|
CapTIvate™ Technology Guide
v1.00.20.00
|
The CapTIvate™ Capacitive Touch Software Library provides everything needed to support self and mutual capacitive sensors to help shorten the application development process.
The software library is a comprehensive collection of functions for touch, communications and sensor management features. Touch functions range from advanced sensor processing for buttons, sliders and wheels to "bare-metal" functions allowing direct access to the CapTIvate™ peripheral. Communication functions for I2C and UART serial drivers, and a communications protocol, enable the MSP430FR26xx\25xx microcontroller to send sensor data to the CapTIvate™ Design Center during the sensor development process. A library manager simplifies sensor measurement, calibration and communication activities.
Benefits of using the CapTIvate™ Library
The components illustrated below are provided pre-compiled as captivate.lib for Texas Instruments Code Composer Studio (CCS) and captivate.r43 for IAR Embedded Workbench. The CapTIvate™ Software Library API provides the interface to the library functions. Source code for these pre-compiled components are not provided.
Some library components are provided as source code, allowing flexibility in the system configuration during the application development cycle.
The library components illustrated below are pre-programmed into ROM on MSP430FR26xx\25xx microcontrollers with CapTIvate™ Technology. Library components in ROM, rather than FRAM, allows more program memory space for the application.
The CapTIvate™ Library utilizes functions in ROM when using the MSP430FR26xx/25xx family. The ROM size is10.2kB.
All applications using CapTIvate™ Touch Technology require a small base amount of FRAM code memory to call into the ROM library. This code size is not dependent on the type or number of sensors in the system. The code size does vary when using the UART or I2C drivers that are needed during the development process to communicate with the CapTIvate™ Design Center.
Data memory is variable and grows based on the number and type of sensor in the application.
With FRAM technology, data RAM memory can easily be relocated to FRAM. This may be a consideration in applications with larger number of sensors that require more data space than the available amount of device RAM memory. Below is a simple modification to the MCU's linker command file that will place the .data section for the sensor objects (defined in CAPT_UserConfig.c) into FRAM.
The pre-compiled library components are compiled using small code and small data memory.
The CapTIvate™ file structure is shown below. Note, Bold Files indicate those components that are not provided in the pre-compiled library, but are provided as library source code.
The MSP430FR2xx family software library API guide is provided as a separate document.
Jump to the Software Library API Guide...
The software library is designed to provide a bridge between the user's application and the CapTIvate™ peripheral. At a minimum, an application only needs to interface with the upper most Advanced layer in the library.
The Advanced layer functions provide button, slider and wheel functionality. Results from the touch layer are processed for each sensor type, depending on the type of sensors in the application. The advanced layer updates the application layer through user defined callback functions. See Callback section for details.
The Touch layer functions perform processing and filtering of raw sensor data, as well as debounce and threshold detection. Results are provided to the components in the advanced layer.
The HAL (hardware abstraction layer) software functions can directly access and manipulate the CapTIvate™ analog and hardware state machine. In a typical touch application, it is not necessary to call the HAL functions directly from the application. Rather, HAL functions are called from the higher level layers in the library or from the library manager during initialization.
To help abstract the sensor management and timing, three high level functions, typically called from within an application's main() function, are part of the library's "library sensor manager" which is responsible for managing the execution of the lower level library functions. These functions are:
Using only these three functions, it is possible to assemble a basic sensor measurement framework that provides sensor initialization, sensor calibration and sensor updates. The CapTIvate™ Design Center generates example code projects that show the use of these functions.
The CapTIvate™ software library is provided with every MSP430FR26xx\25xx source code project created by the CapTIvate™ Design Center. The recommended process for creating new projects is described in the capacitive touch design process. It is also recommended to use ROM library functions vs. the pre-compilied library functions to minimize the FRAM memory footprint.
Calling library functions directly from the MSP430FRxx microcontroller ROM requires the use of two header files that are provided with the library, rom_captivate.h and rom_map_captivate.h. These header files provide a mapping between functions in the software library function and the same function located in device ROM. Use the function call technique described in the following example to simplify the procedure.
Example:
Assume the captivate.lib has been added to the project and header files rom_captivate.h and map_rom_captivate.h are included in the source file where the library function call will be made. To call the library function "foo()", it is recommended to make an implicit ROM call MAP_foo(). The complier parses through the rom_map_captivate.h file to determine if the function resides in ROM, and if it does, will make the ROM call. If this function does not exist in ROM then the compiler will make a call to the pre-compiled library version.
It is possible to explicitly call the function "foo()" from the pre-compiled library using foo(). The linker will pull this function from the pre-compiled library during the link process, adding the function to FRAM program memory. To explicitly call the function "foo()" from ROM, use ROM_foo(). This will force the compiler to make a call to ROM, with no impact on FRAM program memory.
The CapTIvate™ library is provided as a pre-compiled library in addition to some user configurable source files. The pre-compiled library file and source files can be added to the IDE project or used with a command line make file. During the link process, any non-ROM functions called by the application will be extracted from the library.
Example:
If the application references a library function foo(), then this function is extracted from the pre-compiled library and placed into FRAM program memory by the linker.
If, however, the application references the library function as MAP_foo() or ROM_foo(), the function is resolved by the linker to ROM using the map_rom_captivate.h file.
Callbacks provide a mechanism for the application to be notified when a sensor has been updated. The application must first register its "callback" function for each sensor before it can receive updates. When the callback is executed, the application can query the sensor's data structure to determine the status of the sensor.
A library function CAPT_registerCallback() provides the registration.
Example
Registering the application's callback function named "my_button_callback" to the sensor BTN0000.
Once an application's callback function is registered, the callback is executed each time the corresponding sensor is scanned and processed, regardless if a proximity or touch detection has occurred. Inside the user callback, the application can perform any required sensor data and status post-processing. In a typical button application, this is where the application will check for a proximity, touch detection or slider/wheel position.
Example
Here is a typical callback example for a button that checks both when a touch is detected and a release.
Here is a callback example for a proximity sensor.
In addition to proximity and touch status, sliders and wheels also provide position status. Here is a typical callback example for a slider or wheel that checks a sensor's position.
The CapTIvate™ Touch Library includes a communications module for connecting CapTIvate™ MCUs to the outside world. This section discusses the architecture, features, and specification for that communications module, as well as how it may be used in a variety of applications from development to production.
This section assumes that the reader is familiar with the following:
Designing a capacitive touch interface is an iterative process. Every sensor in the system must be individually tuned and optimized to achieve the desired sensitivity and "feel." Having the ability to communicate in real-time between a PC GUI and the target MCU drastically reduces the amount of time needed to tune an interface, and can provide better tuning results as the features incorporated into the CapTIvate™ peripheral can quickly and easily be exercised to determine the best configuration.
Following the design and tuning phase, a capacitive touch microcontroller takes on one of two roles in a system. It may be a dedicated human-machine interface (HMI) that only serves to resolve a capacitive touch panel into usable information (like touch/no touch, or a slider position), or it may double as a host processor, integrating other functionality such as monitoring sensors or controlling other functions in the system. In the first case (the dedicated HMI case), the controller will almost always require a way to communicate the status of the interface to some other host, which may be another MCU or an MPU. This interface could be as simple as a GPIO that gets set when a button is pressed, or as complex as a full I2C protocol with addressable parameters.
The CapTIvate™ Software Library communications module provides a single solution to the two needs above. The communications module is a layered set of firmware with a simple top-level API, designed to link a CapTIvate™ MCU to the CapTIvate™ Design Center PC GUI or to a host processor of some kind via a standard, common serial interface.
In a capacitive touch application the MCU is responsible for measuring capacitive sensors, processing the measurement to interpret some kind of result, and transmitting that result either to the application locally or to a host processor. The communications layer provides the "transmission" part of the equation. The diagram below portrays how the communications module fits in with the rest of the firmware in a typical CapTIvate™ application.
The CapTIvate™ communications module is layered and contains several standalone features that are interlinked together. These features are introduced below. To use the communications module, it is only necessary to set up the configuration file and call the top-level APIs.
The communications module contains 4 layers. In order of decreasing abstraction, they are:
The CapTIvate™ interface layer is the top-level communication layer. It provides the top-level function calls that are used by the application, and serves to marry together the protocol layer (which handles packet generation and interpretation) with the serial driver (which actually moves the data in and out of the microcontroller). The functionality provided is covered in this section below. All application access to the communications module should be through the interface layer.
The communications module must be initialized at startup by the application via a call to CAPT_initCommInterface(). This top-level init function handles opening the selected serial driver, as well as initializing any queues/buffers that are needed for communication.
| Description | Declaration |
|---|---|
| Init the Communications Module | extern void CAPT_initCommInterface(tCaptivateApplication *pApp) |
Incoming raw data from a host is buffered by the serial driver to be serviced when the application is available to do so. The application must periodically call CAPT_checkForInboundPacket() to check to see if any packets have been received from the host. This top-level function will check for packets in the receive queue of the serial driver, and if any packets are found, they will be processed according to their type. Typically, this function is called in a background loop when the application is available. Note that the serial drivers will exit active from sleep if a data is arriving from the host, which can be used as a mechanism to wake up the background loop to call this function.
The CAPT_checkForRecalibrationRequest() function should also be called periodically to see if any of the packets received and handled by CAPT_checkForInboundPacket() require the application to re-calibrate the user interface. An example of this would be if a packet was received that changed the conversion count, requiring a re-calibration of the sensors in the system.
| Description | Declaration |
|---|---|
| Check for an Inbound Packet, and Process It | extern bool CAPT_checkForInboundPacket(void) |
| Check for a Re-calibration Request | extern bool CAPT_checkForRecalibrationRequest(void) |
The interface layer provides 3 top-level constructs for transmitting data to the host. The three functions below handle generation of the appropriate packet, management of the transmit ping/pong buffers, and transmission over the serial interface. If the serial peripheral is available (not busy) these calls are non-blocking, and the packets that are generated are transmitted to the host via interrupt service routines in the serial driver.
| Description | Declaration |
|---|---|
| Write Element Data | extern bool CAPT_writeElementData(uint8_t ui8SensorID) |
| Write Sensor Data | extern bool CAPT_writeSensorData(uint8_t ui8SensorID) |
| Write General Purpose Data | extern bool CAPT_writeGeneralPurposeData(uint16_t *pData, uint8_t ui8Cnt) |
The compile-time configuration options are set in the CAPT_CommConfig.h file. The available compile-time options are described below.
| Parameter | File | Valid Values |
|---|---|---|
| CAPT_INTERFACE | CAPT_UserConfig.h | __CAPT_NO_INTERFACE__, CAPT_UART_INTERFACE, CAPT_BULKI2C_INTERFACE, CAPT_REGISTERI2C_INTERFACE |
CAPT_INTERFACE, unlike the remaining definitions, is located in the User Config file (CAPT_UserConfig.h). It selects the interface that the communications module should be built for. If the communication module should be excluded from the build, then CAPT_NO_INTERFACE should be set. Otherwise, the desired communication mode should be set.
NOTE: This value is automatically populated in the CAPT_UserConfig.h file by the Design Center during source code generation.
| Parameter | File | Valid Values |
|---|---|---|
| CAPT_TRANSMIT_BUFFER_SIZE | CAPT_CommConfig.h | Unsigned Integer |
CAPT_TRANSMIT_BUFFER_SIZE defines the size of the transmit buffer. Note that 2x this size will be allocated, since ping-pong buffering is used. This size should also be at least 2x the size of the largest packet, to allow for byte stuffing.
| Parameter | File | Valid Values |
|---|---|---|
| CAPT_QUEUE_BUFFER_SIZE | CAPT_CommConfig.h | Unsigned Integer |
CAPT_QUEUE_BUFFER_SIZE defines the size of the receive queue. This is the queue that the serial driver uses to buffer received data until the data is processed by a call to CAPT_checkForInboundPacket(). If it seems like packets are being dropped, a good first step is to increase the size of this buffer.
| Parameter | File | Valid Values |
|---|---|---|
| CAPT_I2C_RECEIVE_BUFFER_SIZE | CAPT_CommConfig.h | Unsigned Integer |
CAPT_I2C_RECEIVE_BUFFER_SIZE defines the size of the receive buffer used by the I2C Slave driver, if that driver is selected. This buffer size should be at least as large as the maximum length I2C bus write transaction that is expected.
| Parameter | File | Valid Values |
|---|---|---|
| CAPT_I2C_REGISTER_RW_BUFFER_SIZE | CAPT_CommConfig.h | Unsigned Integer |
CAPT_I2C_REGISTER_RW_BUFFER_SIZE defines the size of the buffer used by the I2C Slave driver when the communication interface is configured in register I2C mode. This buffer size should be at least as large as the maximum length I2C bus transaction that is expected.
The CapTIvate™ protocol is a communications specification for sending capacitive touch specific data. It enables MSP430 Captivate-equipped microcontrollers to communicate with design, debug, and tuning tools on host PCs. In addition to this function, it can also provide a mechanism for interfacing a Captivate MCU to another host MCU or SoC in the context of a larger system. This guide discusses the details of the protocol itself: packet types and packet structure.
The Captivate protocol is a packet-based serial messaging protocol. It includes provisions for passing real-time capacitive measurement data from a Captivate target MCU to another processor, as well as provisions for tuning parameter read and write.
The various use cases for the protocol are described below.
The Captivate protocol supports five packet types: sensor packets, cycle packets, parameter packets, general purpose packets, and trackpad packets. In a capacitive touch system, there are two endpoints in the communication link: the target MCU itself, and the host. The host might be a PC tool or some kind of embedded processor. Sensor packets, cycle packets, general purpose packets, and trackpad packets carry information about the current state of the touch panel being driven by the target MCU. These packets are UNIDIRECTIONAL, and only travel from the target to the host. Parameter packets are BIDIRECTIONAL, and may travel from the target to the host or from the host to the target.
Sensor packets are unidirectional packets from the Captivate MCU to the host. They provide information about the current state of a sensor. Sensor state information includes things like dominant button, slider or wheel position, sensor global proximity state, and sensor global touch/previous touch state.
Cycle packets are unidirectional packets from the Captivate MCU to the host. They provide low level element information, such as element touch status, element proximity status, element count, and element long term average for all of the elements within a cycle. These packets are typically used in the tuning phase, where it is desirable to have real-time views of count and long term average for setting thresholds and tuning filters.
Trackpad packets are unidirectional packets from trackpad MCUs to the host. They provide the X and Y coordinates of touches on the trackpad.
General purpose packets are unidirectional packets from a Captivate MCU to the host. They serve as a generic container to send any information that can be formatted as a 16-bit unsigned integer. This channel can serve as a debug tool for sending any kind of information that doesn't fit into any of the other packet types. Up to 29 integers (58 bytes) may be sent in a single packet.
Parameter packets are bi-directional packets between a host and the Captivate MCU. Parameter packets allow for the host to adjust a tuning parameter on the target at runtime. For example, the touch threshold for an element or the resolution of a slider could be adjusted by sending the appropriate parameter command. Parameters can be read or written. Parameter reads and writes from a host to a target MCU always result in a read-back of the most current value (the value after the write, in the case of a write).
The packet types discussed above are transmitted via a serial interface of some kind between the target and the host. Full-duplex UART is the typical interface. To provide reliable and accurate packet transmission, a set of transmission rules is applied to all packets when being transmitted. These rules are discussed in the HID Bridge Packet Mode section.
The following functions aid in applying transmission rules:
| Description | Declaration |
|---|---|
| Stuff Sync Bytes in a Packet | extern uint16_t CAPT_stuffSyncBytes(uint8_t *pBuffer, uint16_t ui16Length) |
| Verify a Checksum | extern bool CAPT_verifyChecksum(const uint8_t *pBuffer, const uint16_t ui16Length, const uint16_t ui16Checksum) |
| Get a Checksum | extern uint16_t CAPT_getChecksum(const uint8_t *pBuffer, const uint16_t ui16Length) |
| Identify and Frame a Packet in a Receive Data Queue | extern bool CAPT_processReceivedData(tByteQueue *pReceiveQueue, tParameterPacket *pPacket, tTLProtocolProcessingVariables *pVariables) |
Sensor packets have a fixed length of 6 bytes. There are two control bytes and four data payload bytes.
| Sensor Type | Byte 0 | Byte 1 | Byte 2 | Byte 3 |
|---|---|---|---|---|
| Button Group | Dominant Element (256 elements max) | Previous Dominant Element (256 elements max) | Reserved | Sensor Status |
| Slider | Slider Position (Lower 8 bits of 16 bits) | Slider Position (Upper 8 bits of 16 bits) | Reserved | Sensor Status |
| Wheel | Wheel Position (Lower 8 bits of 16 bits) | Wheel Position (Upper 8 bits of 16 bits) | Reserved | Sensor Status |
| Proximity | Reserved | Reserved | Reserved | Sensor Status |
| Trackpad | Reserved | Reserved | Reserved | Sensor Status |
The sensor status byte, included in button group, slider, and wheel sensor packets, provides additional data about the state of the sensor that is often meaningful. The status flags are all boolean flags, and are assigned to bit positions as follows:
| Bit Mask (Position) | Sensor Status Flag |
|---|---|
| Bit 0 (01h) | Global Sensor Touch Flag |
| Bit 1 (02h) | Global Sensor Previous Touch Flag |
| Bit 2 (04h) | Global Sensor Proximity Flag |
| Bit 3 (08h) | Global Sensor Detect Flag (Prox Detect Pre-Debounce) |
| Bit 4 (10h) | Global Sensor Negative Touch Flag (Reverse Touch) |
| Bit 5 (20h) | Global Sensor Noise State |
| Bit 6 (40h) | Global Sensor Max Count Error Flag |
| Bit 7 (80h) | Global Sensor Calibration Error Flag |
NOTE: For slider / wheel sensors, the 16 position bits in the data payload will contain the valid slider or wheel position when the global sensor touch flag is true on that sensor. If there is not a global touch detection, the 16 position bits will all be set high (0xFFFF for the slider/wheel position value).
NOTE: Reserved fields are still transmitted, but do not contain any meaningful data. Do not use or rely on any data transmitted in a reserved field.
Sensor packets are generated via a call into the protocol layer. The CAPT_getSensorPacket() function looks up the sensor at index ui8SensorID in the array sensorArray, and stores the generated packet in the buffer space pointed to by pBuffer. The length of the packet is returned by the function.
| Description | Declaration |
|---|---|
| Get a Sensor Packet | extern uint16_t CAPT_getSensorPacket(tSensor **sensorArray, uint8_t ui8SensorID, uint8_t *pBuffer) |
Cycle packets have a variable length which is dependent upon the number of elements within the cycle. There are always 3 control bytes and 3 state bytes. In addition to those 6 bytes, there are 4 bytes per element in the cycle.
Cycle packets are generated via a call into the protocol layer. The CAPT_getCyclePacket() function looks up the cycle at index ui8Cycle in the sensor at index ui8SensorID in the array sensorArray, and stores the generated packet in the buffer space pointed to by pBuffer. The length of the packet is returned by the function.
| Description | Declaration |
|---|---|
| Get a Cycle Packet | extern uint16_t CAPT_getCyclePacket(tSensor **sensorArray, uint8_t ui8SensorID, uint8_t ui8Cycle, uint8_t *pBuffer); |
Trackpad packets have a variable length which is dependent upon the maximum number of simultaneous touches supported by the trackpad device. There are 3 control bytes. Following the control bytes, there is a trackpad gesture byte for indicating the detection of a gesture and what the gesture was. For each simultaneous touch the trackpad device supports, 4 additional payload bytes are added to the packet. The packet format can be seen below.
| **Value** | Gesture |
|---|---|
| 00h | Wake on Proximity Detection |
| 01h | Reserved |
| 02h | Single Touch Single Tap |
| 03h | Single Touch Double Tap |
| 04h | Two Touch Single Tap |
| 05h | Two Touch Double Tap |
| 06h | Tap and Hold |
| 07h | Two Touch Tap and Hold |
| 08h | Swipe Left |
| 09h | Swipe Right |
| 0Ah | Swipe Up |
| 0Bh | Swipe Down |
| 0Ch-FEh | Reserved |
| FFh | No Gesture Detected |
NOTE: Trackpad packets only pertain to dedicated trackpad devices.
General purpose packets are unique in that they simply serve as a data streaming mechanism for any data an application wishes to send. Data is sent as an array of 16-bit unsigned integers. General purpose packets have variable length that is dependent upon the number of integers being sent. There are always 2 control bytes. Following the control bytes is the data payload (up to 29 entries), with 2 bytes (16 bits) per entry.
General purpose packets are generated via a call into the protocol layer. The CAPT_getGeneralPurposePacket() function generates a packet for the data array of length ui8Cnt pointed to by pData, and stores the generated packet in the buffer space pointed to by pBuffer.
| Description | Declaration |
|---|---|
| Get a General Purpose Packet | extern uint16_t CAPT_getGeneralPurposePacket(uint16_t *pData, uint8_t ui8Cnt, uint8_t *pBuffer) |
Parameter packets have a fixed length of 7 bytes. There are 3 control bytes and 4 data payload bytes. The packet format can be seen below.
The protocol layer provides several functions for framing and interpreting parameter packets. Placing a call into CAPT_processReceivedData() causes the protocol layer to search for potential packets in a datastream that has been queued up by a serial driver. Once a valid packed has been framed, the parameter may be accessed and updated/read via calls to CAPT_accessSensorParameter() and CAPT_accessSpecialSensorParameter().
| Description | Declaration |
|---|---|
| Access a Sensor Parameter | extern tTLParameterAccessResult CAPT_accessSensorParameter(tSensor **sensorArray, tParameterPacket *pPacket) |
| Access a Special Sensor Parameter | extern tTLParameterAccessResult CAPT_accessSpecialSensorParameter(tSensor **sensorArray, tParameterPacket *pPacket) |
| Identify and Frame a Packet in a Receive Data Queue | extern bool CAPT_processReceivedData(tByteQueue *pReceiveQueue, tParameterPacket *pPacket, tTLProtocolProcessingVariables *pVariables) |
| Verify a Checksum | extern bool CAPT_verifyChecksum(const uint8_t *pBuffer, const uint16_t ui16Length, const uint16_t ui16Checksum) |
The available parameters that can be adjusted through the use of parameter packets are listed below.
| Parameter Name | Byte 0: CMD | Byte 1: RW | Byte 2: ID | Byte 3 | Byte 4 | Byte 5 | Byte 6 | MCU Task | SW Containing Structure | SW Containing Variable |
|---|---|---|---|---|---|---|---|---|---|---|
| Conversion Gain | 80 | RW | Sensor ID | Don't Care | Don't Care | ATI Base Lower Byte | ATI Base Upper Byte | Re-Cal | tSensor | ui16ConversionGain |
| Conversion Count | 81 | RW | Sensor ID | Don't Care | Don't Care | ATI Target Lower Byte | ATI Target Upper Byte | Re-Cal | tSensor | ui16ConversionCount |
| Prox Threshold | 82 | RW | Sensor ID | Don't Care | Don't Care | Prox Threshold Lower Byte | Prox Threshold Upper Byte | NA | tSensor | ui16ProxThreshold |
| Prox Debounce-In Threshold | 84 | RW | Sensor ID | Don't Care | Don't Care | Prox Db In | Don't Care | NA | tSensor | ProxDbThreshold .DbUp |
| Prox Debounce-Out Threshold | 85 | RW | Sensor ID | Don't Care | Don't Care | Prox Db Out | Don't Care | NA | tSensor | ProxDbThreshold .DbDown |
| Touch Debounce-In Threshold | 86 | RW | Sensor ID | Don't Care | Don't Care | Touch Db In | Don't Care | NA | tSensor | TouchDbThreshold .DbUp |
| Touch Debounce-Out Threshold | 87 | RW | Sensor ID | Don't Care | Don't Care | Touch Db Out | Don't Care | NA | tSensor | TouchDbThreshold .DbDown |
| Sensor Timeout Threshold | 88 | RW | Sensor ID | Don't Care | Don't Care | Sensor Timeout Lower Byte | Sensor Timeout Upper Byte | NA | tSensor | ui16TimeoutThreshold |
| Count Filter Enable | 89 | RW | Sensor ID | Don't Care | Don't Care | Count Filter Enable bit | Don't Care | NA | tSensor | bCountFilterSelect |
| Count Filter Beta | 8A | RW | Sensor ID | Don't Care | Don't Care | Count Filter Beta | Don't Care | NA | tSensor | ui8CntBeta |
| LTA Filter Beta | 8B | RW | Sensor ID | Don't Care | Don't Care | LTA Filter Beta | Don't Care | NA | tSensor | ui8LTABeta |
| Halt LTA Filter Immediately | 8C | RW | Sensor ID | Don't Care | Don't Care | LTA Filter Halt | Don't Care | NA | tSensor | bSensorHalt |
| Runtime Re-Calibration Enable | 8D | RW | Sensor ID | Don't Care | Don't Care | Runtime Re-Cal Enable | Don't Care | NA | tSensor | bReCalibrateEnable |
| Force Re-Calibrate | 8E | N/A | Sensor ID | Don't Care | Don't Care | Don't Care | Don't Care | Re-Cal | tSensor | N/A |
| Bias Current | 8F | RW | Sensor ID | Don't Care | Don't Care | Bias Current | Don't Care | Re-Cal | tSensor | ui8BiasControl |
| Sample Capacitor Discharge | 95 | RW | Sensor ID | Don't Care | Don't Care | Cs Discharge | Don't Care | Re-Cal | tSensor | bCsDischarge |
| Modulation Enable | 96 | RW | Sensor ID | Don't Care | Don't Care | Mod Enable | Don't Care | Re-Cal | tSensor | bModEnable |
| Frequency Divider | 97 | RW | Sensor ID | Don't Care | Don't Care | Freq Div | Don't Care | Re-Cal | tSensor | ui8FreqDiv |
| Charge/Hold Phase Length | 98 | RW | Sensor ID | Don't Care | Don't Care | Charge Length | Don't Care | Re-Cal | tSensor | ui8ChargeLength |
| Transfer/Sample Phase Length | 99 | RW | Sensor ID | Don't Care | Don't Care | Transfer Length | Don't Care | Re-Cal | tSensor | ui8TransferLength |
| Error Threshold | 9A | RW | Sensor ID | Don't Care | Don't Care | Error Threshold Lower Byte | Error Threshold Upper Byte | NA | tSensor | ui16ErrorThreshold |
| Negative Touch Threshold | 9B | RW | Sensor ID | Don't Care | Don't Care | Negative Touch Threshold Lower Byte | Negative Touch Threshold Upper Byte | NA | tSensor | ui16NegativeTouchThreshold |
| Idle State | 9C | RW | Sensor ID | Don't Care | Don't Care | Idle State | Don't Care | NA | tSensor | bIdleState |
| Input Sync | 9D | RW | Sensor ID | Don't Care | Don't Care | Input Sync | Don't Care | NA | tSensor | ui8InputSyncControl |
| Timer Sync | 9E | RW | Sensor ID | Don't Care | Don't Care | Timer Sync | Don't Care | NA | tSensor | bTimerSyncControl |
| Automatic Power-Down Enable | 9F | RW | Sensor ID | Don't Care | Don't Care | Power Down Control | Don't Care | NA | tSensor | bLpmControl |
| Halt LTA on Sensor Prox or Touch | A0 | RW | Sensor ID | Don't Care | Don't Care | Sensor Prox/Touch Halt | Don't Care | NA | tSensor | bPTSensorHalt |
| Halt LTA on Element Prox or Touch | A1 | RW | Sensor ID | Don't Care | Don't Care | Element Prox/Touch Halt | Don't Care | NA | tSensor | bPTElementHalt |
| Parameter Name | Byte 0: CMD | Byte 1: RW | Byte 2: ID | Byte 3 | Byte 4 | Byte 5 | Byte 6 | MCU Task | SW Containing Structure | SW Containing Variable |
|---|---|---|---|---|---|---|---|---|---|---|
| Touch Threshold | 83 | RW | Sensor ID | Cycle # (relative to sensor) | Lower 4 Bits: Element # (relative to cycle) | Touch Threshold | Don't Care | NA | tElement | ui8TouchThreshold [Element #] |
| Coarse Gain Ratio | A2 | R | Sensor ID | Cycle # (relative to sensor) | [UPPER 4 Bits: Frequency #] [ LOWER 4 Bits: Element # relative to cycle] | Coarse Gain | Don't Care | NA | tCaptivateElementTuning | ui8GainRatioCoarse |
| Fine Gain Ratio | A3 | R | Sensor ID | Cycle # (relative to sensor) | [UPPER 4 Bits: Frequency #] [ LOWER 4 Bits: Element # relative to cycle] | Fine Gain | Don't Care | NA | tCaptivateElementTuning | ui8GainRatioFine |
| Parasitic Offset Scale | D0 | R | Sensor ID | Cycle # (relative to sensor) | [UPPER 4 Bits: Frequency #] [ LOWER 4 Bits: Element # relative to cycle] | Offset Scale (2 bit selection) | Don't Care | NA | tCaptivateElementTuning | ui16OffsetTap Upper Byte |
| Parasitic Offset Level | D1 | R | Sensor ID | Cycle # (relative to sensor) | [UPPER 4 Bits: Frequency #] [ LOWER 4 Bits: Element # relative to cycle] | Offset Level (8 bit selection) | Don't Care | NA | tCaptivateElementTuning | ui16OffsetTap Lower Byte |
| Parameter Name | Byte 0: CMD | Byte 1: RW | Byte 2: ID | Byte 3 | Byte 4 | Byte 5 | Byte 6 | MCU Task | SW Containing Structure | SW Containing Variable |
|---|---|---|---|---|---|---|---|---|---|---|
| Slider/Wheel Position Filter Enable | 90 | RW | Sensor ID | Don't Care | Don't Care | Slider Filter Enable bit | Don't Care | NA | tSliderSensorParams | SliderFilterEnable |
| Slider/Wheel Position Filter Beta | 91 | RW | Sensor ID | Don't Care | Don't Care | Slider Filter Beta | Don't Care | NA | tSliderSensorParams | SliderBeta |
| Desired Slider/Wheel Resolution | 92 | RW | Sensor ID | Don't Care | Don't Care | Slider Resolution Lower Byte | Slider Resolution Upper Byte | NA | tSliderSensorParams | ui16Resolution |
| Slider Lower Trim | 93 | RW | Sensor ID | Don't Care | Don't Care | Slider Lower Trim Lower Byte | Slider Lower Trim Upper Byte | NA | tSliderSensorParams | SliderLower |
| Slider Upper Trim | 94 | RW | Sensor ID | Don't Care | Don't Care | Slider Upper Trim Lower Byte | Slider Upper Trim Upper Byte | NA | tSliderSensorParams | SliderUpper |
| Parameter Name | Byte 0: CMD | Byte 1: RW | Byte 2: ID | Byte 3 | Byte 4 | Byte 5 | Byte 6 | MCU Task | SW Containing Structure | SW Containing Variable |
|---|---|---|---|---|---|---|---|---|---|---|
| Element Data Transmit Enable | C0 | RW | Don't Care | Don't Care | Don't Care | Element Transmit Enable | Don't Care | NA | tCaptivateApplication | bElementDataTxEnable |
| Sensor Data Transmit Enable | C1 | RW | Don't Care | Don't Care | Don't Care | Sensor Transmit Enable | Don't Care | NA | tCaptivateApplication | bSensorDataTxEnable |
| Active Mode Scan Rate (ms) | C2 | RW | Don't Care | Don't Care | Don't Care | Active Report Period (ms) Lower Byte | Active Report Period (ms) Upper Byte | NA | tCaptivateApplication | ui16ActiveModeScanPeriod |
| Wake-on-Prox Mode Scan Rate (ms) | C3 | RW | Don't Care | Don't Care | Don't Care | WoP Report Period (ms) Lower Byte | WoP Report Period (ms) Upper Byte | NA | tCaptivateApplication | ui16WakeOnProxModeScanPeriod |
| Wakeup Interval | C4 | RW | Don't Care | Don't Care | Don't Care | Wakeup Interval | Don't Care | NA | tCaptivateApplication | ui8WakeupInterval |
| Inactivity Timeout | C5 | RW | Don't Care | Don't Care | Don't Care | Timeout Lower Byte | Timeout Upper Byte | NA | tCaptivateApplication | ui16InactivityTimeout |
The MSP430 eUSCI_A UART Driver provides a simple UART API to MSP430 applications, enabling interrupt-driven transmit and receive operations as well as error handling. This section provides an overview of the driver's features, architecture, and API. This document assumes that the reader is familiar with the MSP430 MCU architecture, as well as embedded C programming concepts.
This document should be used with the following additional supporting documentation. The MSP430 Driver Library API is not specific to this driver, and has its own documentation.
The eUSCI_A UART Driver enables developers to quickly get up and running with UART communication via an API that is similar to one used on a PC. The API provides simple functions such as UART_openPort() and UART_transmitBuffer(), and it allows the developer to register event handlers for received data and error conditions. To enable portability, the driver is built upon the MSP430 DriverLib register abstraction. This driver has been designed to work with MSP430 DriverLib build 1.90.00.00 and greater. Like any other serial interface, UART has benefits and drawbacks. Whether or not it is the best choice for an embedded interface depends on a number of factors. The benefits and drawbacks of UART are discussed below.
UART Benefits
UART Drawbacks
The key features implemented in the UART driver are listed below.
The UART driver is provided in source code. The driver consists of three source files:
The UART driver requires the following hardware resources:
The UART driver API is composed of functions and data types. The sections below describe how to configure the UART driver and use it to perform transmit and receive operations. The UART driver employs a basic software state machine to manage operations. The three driver states and their interconnection are shown in the diagram below.
The UART driver has compile-time options as well as run-time configurable options. Certain things must be known at compile-time, such as which eUSCI_A peripheral instance is associated with the driver. Other options, such as baud rate, may be controlled at runtime.
The compile-time configuration options are set in the UART_Definitions.h file. The available compile-time options are described below.
| Parameter | File | Valid Values |
|---|---|---|
| UART__ENABLE | UART_Definitions.h | true, false |
The UART Enable compile-time option selects whether the UART Driver is enabled or disabled. This provides a mechanism to exclude the driver from the compilation process. To include the driver, define UART__ENABLE as true. Else, define it as false.
| Parameter | File | Valid Values |
|---|---|---|
| UART__EUSCI_A_PERIPHERAL | UART_Definitions.h | EUSCI_A0_BASE, EUSCI_A1_BASE |
The UART eUSCI_A peripheral selection allows easy selection of which eUSCI_A instance to associate with the UART driver. This provides flexibility during design if a pin-mux change is necessary. A valid base address must be provided.When a eUSCI_A peripheral selection is made, the UART driver ISR address is linked to the appropriate eUSCI interrupt vector automatically. If an invalid address is selected, a compiler error is thrown.
| Parameter | File | Valid Values |
|---|---|---|
| UART__LPMx_bits | UART_Definitions.h | 0, LPM0_bits, LPM1_bits, LPM2_bits, LPM3_bits |
UART communications is often performed in a low power mode. The UART LPM Mode configuration is used in three ways, as described below.
The UART driver has compile-time options as well as run-time configurable options. The runtime configuration options are specified by populating a tUARTPort structure in the application, and passing this structure to the driver when opening the driver. A tUARTPort structure is required when opening the UART driver. The tUARTPort structure must be available in memory whenever the driver is open. This is a result of the fact that the UART driver references this structure at runtime to find the callback functions for receive handling and error handling. However, the driver does not modify the data in the structure at any time, and as such, the structure may be placed in a read-only memory section (such as C const memory). These parameters are considered runtime adjustable because the parameters may be modified by the application if the UART driver is closed first, then re-opened. For example, the application may change the UART baud rate by closing the port, changing the baud rate options on the tUARTPort structure, and re-opening the port. Note that the .peripheralParameters member of the tUARTPort structure is a EUSCI_A_UART_initParam structure from the MSP430 Driver Library.
| Member | Description | Valid Values |
|---|---|---|
| bool (*pbReceiveCallback)(uint8_t) | pbReceiveCallback is a function pointer that may point to a receive event handler. If no receive handling is required, initialize this member to 0 (null). | Null, or a valid function address. |
| bool (*pbErrorCallback)(uint8_t) | pbErrorCallback is a function pointer that may point to an error event handler. If no error handling is required, initialize this member to 0 (null). | Null, or a valid function address. |
| .peripheralParameters.selectClockSource | This member specifies the clock source for the eUSCI_A peripheral. | EUSCI_A_UART_CLOCKSOURCE_SMCLK, EUSCI_A_UART_CLOCKSOURCE_ACLK |
| .peripheralParameters.clockPrescalar | This member specifies the eUSCI_A clock prescalar. This affects the baud rate. | 0-65535 |
| .peripheralParameters.firstModReg | This member specifies the eUSCI_A first stage modulation. This affects the baud rate. | 0-15 |
| .peripheralParameters.secondModReg | This member specifies the eUSCI_A second stage modulation. This affects the baud rate. | 0-255 |
| .peripheralParameters.parity | This member specifies the UART parity mode. | EUSCI_A_UART_NO_PARITY, EUSCI_A_UART_ODD_PARITY, EUSCI_A_UART_EVEN_PARITY |
| .peripheralParameters.msborLsbFirst | This member specifies the transmission bit order. | EUSCI_A_UART_LSB_FIRST, EUSCI_A_UART_MSB_FIRST |
| .peripheralParameters.numberofStopBits | This member specifies the number of stop bits. | EUSCI_A_UART_ONE_STOP_BIT, EUSCI_A_UART_TWO_STOP_BITS |
| .peripheralParameters.uartMode | This member specifies the UART mode. | EUSCI_A_UART_MODE, EUSCI_A_UART_IDLE_LINE_MULTI_PROCESSOR_MODE, EUSCI_A_UART_ADDRESS_BIT_MULTI_PROCESSOR_MODE, EUSCI_A_UART_AUTOMATIC_BAUDRATE_DETECTION_MODE |
| .peripheralParameters.overSampling | This member specifies whether UART oversampling is enabled. | EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION, EUSCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION |
Opening and closing of the UART driver is accomplished through the following function calls:
| Description | Declaration |
|---|---|
| Open the UART Port | extern void UART_openPort(const tUARTPort *pPort) |
| Close the UART Port | extern void UART_closePort(void) |
The UART driver is opened and initialized by a call to UART_openPort(), which is passed a completed tUARTPort structure. The tUARTPort structure must be populated by the application. It may be placed in read-only memory, as the UART API does not modify the structure at any time; rather, it only references it. It is important that the structure be left in memory at the address given when UART_openPort() is called, as the UART API will reference this structure to access callback functions when the port is open. If the memory must be freed, first close the UART port with a call to UART_closePort().
A call to UART_closePort() will disable the UART port and its associated eUSCI_A peripheral, halting all Rx/Tx interrupt activity. After the port is closed, the event handlers will no longer be called, and the tUARTPort structure memory may be released to the application.
Data transmission is accomplished through the following function calls:
| Description | Declaration |
|---|---|
| Transmit a Buffer | extern void UART_transmitBuffer(const uint8_t *pBuffer, uint16_t ui16Length) |
| Transmit a Byte | extern void UART_transmitByteImmediately(uint8_t ui8Data) |
| Get Port Status | extern uint8_t UART_getPortStatus(void) |
Transmit operations are interrupt driven. To initiate a transmission after opening the UART port, make a call to UART_transmitBuffer(). This function is simply passed a pointer to the buffer to transmit, and the length of the buffer to transmit (specified in bytes). If the eUSCI_A peripheral is available, transmission will begin immediately and the function will return. If the peripheral is still busy sending a previous transmission, it will block (in a low power mode, if specified in UART_Definitions.h) until the previous transmission is complete.
The transmit operation uses the buffer memory that was pointed to in the UART_transmitBuffer() function - it does not perform a data copy in the name of efficiency. As such, that memory must not be modified during the transmission, or the transmission will be invalid. To detect when transmission has completed and the memory is again available, it is possible to check the UART port status via a call to UART_getPortStatus(). If an application will be re-using buffer space, it is best to employ a ping-pong buffer strategy so that a new packet may be assembled while a previous packet is being sent.
A call to UART_getPortStatus() returns one of the values enumerated by tUARTStates. The options are described below.
| Port Status Option | Description |
|---|---|
| eUARTIsClosed | The UART driver is not currently open, and is neither receiving nor transmitting data. |
| eUARTIsIdle | The UART driver is currently open, but is not in the process of transmitting a buffer. |
| eUARTIsTransmitting | The UART driver is currently open, and is in the process of transmitting a buffer. |
If only a single byte is going to be sent, it is possible to send it immediately via the UART_transmitByteImmediately() function. This function sends a single byte as soon as the eUSCI_A peripheral transmit buffer is available. It will block until the buffer is available. If a transmission started by a call to UART_transmitBuffer() is in progress, this transfer may finish first as it is interrupt-driven. The UART_transmitByteImmediately() function is mainly available to be used in terminal emulator applications, where sent ASCII characters are echoed back to be visible to the user.
Received data is passed to the application through the use of the receive callback. The UART driver will call a user-defined function every time a new byte is received from the UART peripheral, passing that byte to the receive callback. It is then up to the application to decide how to handle the data. It is recommended to use a ring-buffer FIFO queue to handle buffering incoming data. The data may then be extracted and processed in a background process. The receive event handler is called from the UART ISR in the UART driver, and as such, the event handler should be kept as short as possible. It is recommended to follow the same practice used to write ISR's when writing event handlers.
The receive callback function is linked to the driver by placing its address in the pbReceiveCallback member of the tUARTPort structure. If the application does not wish to listen for receive events, the receive callback pointer in the tUARTPort structure may be initialized to null. Receive operations are performed entirely out of the ISR. The receive operation ISR flow is shown below. Errors are checked for whenever a receive interrupt is serviced.
The UART driver employs basic UART error detection to alert the application when something has gone wrong. The two errors detected by the driver are:
The MSP430 eUSCI_B I2C slave driver provides a simple I2C slave API to MSP430 applications, enabling interrupt-driven I2C read/write operations as well as bus timeout detection and driver error handling. This User's Guide provides an overview of the driver's features, architecture, and API. This document assumes that the reader is familiar with MSP430 MCU architecture, as well as embedded C programming concepts and basic I2C principles. Note: From this point forward, the I2C slave driver will simply be referred to as "the driver."
This guide should be used with the following additional supporting documentation. The MSP430 Driver Library API is not specific to this driver, and has its own documentation.
The driver enables quick development of MSP430 applications where the MSP430 itself is a slave device to some other master in a larger embedded system. This is a common application, as MSP430 microcontrollers are often a secondary MCU to a larger host MCU or host MPU.
The driver is structured to be flexible, enabling many different applications. It is capable of providing a register-file interface to a host processor, similar to a sensor or an EEPROM. It may also be used as a bulk-transfer interface to a host.
The key features provided by the driver are listed below.
The driver is provided in C source code. It consists of 3 base driver source files, plus an additional 3 source files related to the I2C timeout detection feature (which is a compile-time option).
Base Driver:
Function Timer (used for I2C timeout detection):
The I2CSlave_Definitions.h and FunctionTimer_Definitions.h files contain the compile-time options for each component.
The driver requires the following MCU hardware resources:
Base Driver:
Slave Request Feature (Optional):
Timeout Feature (Optional):
The driver operation is based upon a software state machine that keeps track of the current driver state. There are four possible states: closed, idle, read, and write. Since the driver implements an I2C slave, it is important to be clear on the naming conventions for read and write. An I2C bus write is a receive operation from the perspective of an I2C slave, as the bus master is writing to the slave. Similarly, an I2C bus read is a transmit operation from the perspective of the slave. The state machine implemented by the driver is depicted below.
As shown, state changes between idle, read, and write are controlled solely by the I2C bus master. It is possible for the slave to close the driver at any time, however.
The driver enters the "write" state (eI2CSlaveIsBeingWrittenTo) whenever the bus master sends a start or restart condition to the driver's 7-bit I2C address with the R/_W bit cleared. In this state, the driver is receiving data. Data is received into the buffer memory that was specified by the user when the driver was opened. If the bus master attempts to write data beyond the length of the receive buffer, the data is ignored and an error callback alerts the application. The write state is cleared when a stop condition or a restart condition is issued. When this happens, the driver calls a user-specified callback function for the received data to be handled.
The driver enters the "read" state (eI2CSlaveIsBeingRead) whenever the bus master sends a start or restart condition to the driver's 7-bit I2C address with the R/_W bit set. In this state, the driver is transmitting data to the master by loading data from the latest transmit buffer memory that was linked to the driver. Note that the buffer memory must have been pre-loaded before the read state was entered. If the bus master attempts to read data before any buffer was specified or if it attempts to read out more data than was made available in the buffer, the driver will clock out an invalid byte, which may be specified as a compile-time option. The read state is cleared when a stop condition or a restart condition is issued. When this happens, the driver wakes the CPU from any low power modes in case it was pending on the completion of a read operation.
The driver provides a mechanism for alerting the bus master that it wishes to communicate. This is helpful in many applications, as the slave has no way to initiate communication on the I2C bus. The slave request feature is implemented as an open-drain request line. The request line may be any digital IO on the MCU. The request line should be pulled up to VCC via a pull-up resistor, just like an I2C bus line. The driver controls whether the request line IO is left tri-stated (Hi-Z), or whether it is pulled to a logic low (sinking current to ground through the pullup resistor and the digital IO). The driver API contains a function for "pulling" the request line, which waits for a I2C bus response from the master (or a timeout) before returning.
The driver provides a timeout mechanism for preventing application lock-ups. To enable timeouts in a low-power way, a dedicated hardware timer is used to set limits on how long specific driver operations may take. The operations that may have timeouts placed on them are:
The timeout feature is implemented by the Function Timer module, which is a completely independent software module. As transaction monitoring may be a part of the application layer (perhaps with a standard watchdog timer), the timeout feature may be excluded completely at compile time. The Function Timer module essentially calls a predefined function in the foreground after a defined delay in timer cycles. That function can then take actions such as cancelling a slave request or resetting the driver.
The compile-time configuration options are set in the I2CSlave_Definitions.h and FunctionTimer_Definitions.h files. These options are described below.
| Parameter | File | Valid Values |
|---|---|---|
| I2CSLAVE__ENABLE | I2CSlave_Definitions.h | true, false |
The I2C Slave Enable compile-time option selects whether the driver is enabled or disabled. This provides a mechanism to exclude the driver from the compilation process. To include the driver, define I2CSlave__ENABLE as true. Else, define it as false.
| Parameter | File | Valid Values |
|---|---|---|
| I2CSLAVE__EUSCI_B_PERIPHERAL | I2CSlave_Definitions.h | EUSCI_B0_BASE |
The I2C eUSCI_B peripheral selection allows easy selection of which eUSCI_B instance to associate with the I2C driver. This provides flexibility during design if a pin-mux change is necessary. A valid base address must be provided.
| Parameter | File | Valid Values |
|---|---|---|
| I2CSLAVE__ADDRESS | I2CSlave_Definitions.h | 0x00 to 0x7F |
The I2C slave address specifies the 7-bit I2C bus address associated with this device.
| Parameter | File | Valid Values |
|---|---|---|
| I2CSLAVE__LPMx_bits | I2CSlave_Definitions.h | LPM0_bits, LPM1_bits, LPM2_bits, LPM3_bits, LPM4_bits |
I2C communication may be performed in a low power mode. No clocks need to be enabled on the MSP430 to send or receive bytes on a eUSCI_B peripheral when in I2C slave mode. This is a benefit of the bit clock being provided by the bus master. The I2C Slave LPM mode control is used in the following ways.
| Parameter | File | Valid Values |
|---|---|---|
| I2CSLAVE__INVALID_BYTE | I2CSlave_Definitions.h | 0x00 to 0xFF |
The invalid byte specifies the byte that is transmitted to the master (during an I2C read) if the master attempts to read beyond the length of the transmit buffer provided to the driver.
| Parameter | File | Valid Values |
|---|---|---|
| I2CSLAVE__TIMEOUT_ENABLE | I2CSlave_Definitions.h | true, false |
The slave timeout enable controls whether the timeout feature of the driver is included. The timeout feature provides the ability to set a maximum amount of time a certain I2C slave task may take before it fails. The two tasks that may be monitored with a timeout is the I2C slave request and any I2C transaction. Note that enabling the timeout feature requires the inclusion of the FunctionTimer source files, a Timer_A instance, and additional memory.
| Parameter | File | Valid Values |
|---|---|---|
| I2CSLAVE__REQ_TIMEOUT_CYCLES | I2CSlave_Definitions.h | 0x0000 - 0xFFFF |
The I2C slave request timeout cycles specifies the timeout period for the I2C request timeout, in units of the function timer clock period. This is the amount of time the driver will wait after pulling the slave request line low before the transaction fails out. The bus master must respond to the slave request within this amount of time.
| Parameter | File | Valid Values |
|---|---|---|
| I2CSLAVE__TXFR_TIMEOUT_CYCLES | I2CSlave_Definitions.h | 0x0000 - 0xFFFF |
The I2C slave transfer timeout cycles specifies the timeout period for any I2C transaction, in units of the function timer clock period. I2C transactions are timed from start condition to stop condition, or start condition to re-start condition.
| Parameter | File | Valid Values |
|---|---|---|
| I2CSLAVE__REQ_ENABLE | I2CSlave_Definitions.h | true, false |
The request enable controls whether the I2C request line feature is included in the driver build. The I2C request line provides a mechanism for the slave to signal the master that it would like to communicate.
| Parameter | File | Valid Values |
|---|---|---|
| I2CSLAVE__REQ_POUT | I2CSlave_Definitions.h | PxOUT |
| I2CSLAVE__REQ_PDIR | I2CSlave_Definitions.h | PxDIR |
| I2CSLAVE__REQ_MASK | I2CSlave_Definitions.h | BIT0 - BIT7 |
The I2C slave request line is defined by three values- the port output register, the port direction register, and the pin mask. These do not need to be defined if the slave request enable is set to false.
| Parameter | File | Valid Values |
|---|---|---|
| FUNCTIONTIMER__ENABLE | FunctionTimer_Definitions.h | true, false |
The function timer enable controls whether the function timer is included in the driver build. If the I2C slave timeout feature is not used, memory is conserved when the function timer is disabled (set to false).
| Parameter | File | Valid Values |
|---|---|---|
| FUNCTIONTIMER__PERIPHERAL | FunctionTimer_Definitions.h | TIMER_A0_BASE, TIMER_A1_BASE, TIMER_A2_BASE, TIMER_A3_BASE |
The function timer peripheral stores the base address of the Timer_A instance that should be associated with the function timer. This instance must have at least two capture compare units (CCR0 an CCR1).
| Parameter | File | Valid Values |
|---|---|---|
| FUNCTIONTIMER__CLOCK | FunctionTimer_Definitions.h | TASSEL__SMCLK, TASSEL__ACLK |
The function timer clock determines the resolution of the function timer, as well as the maximum delay. Sources include SMCLK and ACLK. Note that if the clock source is changed, the effective function timer delay may change.
| Parameter | File | Valid Values |
|---|---|---|
| FUNCTIONTIMER__DIVIDER | FunctionTimer_Definitions.h | ID__1, ID__2, ID__4, ID__8 |
The function timer clock divider divides down the source clock (which was specified above). Note that if the clock divider is changed, the effective function timer delay may change.
| Parameter | File | Valid Values |
|---|---|---|
| FUNCTIONTIMER__EXDIVIDER | FunctionTimer_Definitions.h | TAIDEX_0 to TAIDEX_7 |
The function timer extended divider allows an additional second divider to be added in series with the standard divider. Note that if the extended clock divider is changed, the effective function timer delay may change.
| Parameter | File | Valid Values |
|---|---|---|
| FUNCTIONTIMER__LPM_CLEAR | FunctionTimer_Definitions.h | LPM0_bits, LPM1_bits, LPM2_bits, LPM3_bits, LPM4_bits |
The function timer LPM clear controls which LPM bits are cleared upon exit from a function called in the foreground by the function timer. This should be set to enable CPU wake-up after a timeout event. The function timer feature will never use these bits to enter into a low power mode- it will only use them to exit.
The driver's runtime configuration options are specified by populating a tI2CSlavePort structure in the application, and passing this structure to the driver when opening the driver. The tI2CSlavePort structures are discussed below.
| Member | Description | Valid Values |
|---|---|---|
| bool (*pbReceiveCallback)(uint16_t) | pbReceiveCallback is a function pointer that may point to a receive event handler in the application. If no receive handling is required, initialize this member to 0 (null). | Null, or a valid function address. |
| void (*pvErrorCallback)(uint8_t) | pvErrorCallback is a function pointer that may point to an error event handler in the application. If no error handling is required, initialize this member to 0 (null). | Null, or a valid function address |
| ui16ReceiveBufferSize | This member stores the size of the receive buffer pointed to by pReceiveBuffer. | 0x00 to 0xFF |
| pReceiveBuffer | This member is a pointer to the I2C receive buffer. | A valid pointer |
| bSendReadLengthFirst | When set to true, this flag configures the driver to always load the length of the transmit buffer as the first data byte read by the bus master. This is useful when variable length bulk packets are being read out by the master, and the master needs to know how many bytes to read from the slave. | true, false |
If the timeout feature is included in the driver build, a function timer run-time configuration also happens- but it is handled automatically by the driver when the I2C port is opened. The function timer runtime configuration structure (tFunctionTimer) is outlined below for completeness, but application does not need to know any of the function timer details.
| Member | Description | Valid Values |
|---|---|---|
| ui16FunctionDelay_A | This member specifies the length of the delay (in timer clock cycles) before function A is called. | 0x0000 to 0xFFFF |
| bool (*pbFunction_A)(void) | pbFunction_A is a function pointer to function A. | A valid function pointer, else null. |
| ui16FunctionDelay_B | This member specifies the length of the delay (in timer clock cycles) before function B is called. | 0x0000 to 0xFFFF |
| bool (*pbFunction_B)(void) | pbFunction_B is a function pointer to function B. | A valid function pointer, else null. |
Opening and closing of the I2C slave driver is accomplished through the following function calls:
| Description | Declaration |
|---|---|
| Open the I2C Slave Port | extern void I2CSlave_openPort(const tI2CSlavePort *pPort) |
| Close the I2C Slave Port | extern void I2CSlave_closePort(void) |
The driver is initialized and made ready for use by placing a call to I2CSlave_openPort(), which is passed a completed tI2CSlavePort structure. The tI2CSlavePort structure must be populated by the application. This structure is not modified by the driver at any time, and as such, it may be placed in read-only memory such as a C const memory section. It is important that the structure be left in memory at the original address that is passed to I2CSlave_openPort(), as the driver will reference this structure to access callback functions when the port is open. If the memory must be freed, first close the driver with a call to I2CSlave_closePort(). A call to I2CSlave_closePort() will disable the driver and its associated eUSCI_B peripheral, halting all I2C slave activity. If the timeout feature was included in the build, I2C_closePort() disables the function timer module that drives the timeout feature. After the port is closed, the event handlers will no longer be called and the tI2CSlave structure memory may be released to the application.
Data transmission is accomplished through the following function calls:
| Description | Declaration |
|---|---|
| Set Transmit Buffer | extern void I2CSlave_setTransmitBuffer(uint8_t *pBuffer, uint16_t ui16Length) |
| Set Request Flag | extern void I2CSlave_setRequestFlag(void) |
| Get Port Status | extern uint8_t I2CSlave_getPortStatus(void) |
An I2C slave cannot push data out onto the bus on its own- rather, a master must address the slave and clock out the data. Therefore, the data buffer must be made available to the driver before the bus master attempts to read it. The application may pass a pointer and a length (in bytes) to the I2CSlave_setTransmitBuffer() function. This function will block if a current transaction is in progress, and will return when the transmit buffer pointer and length have been updated. If no transmit buffer is provided and the bus master attempts to read from the slave, it will read out the invalid character (a compile-time option).
The I2CSlave_setTransmitBuffer() function does not perform a copy of the buffer- rather, it just stores its location and length. This is very valuable for "register" applications, where the application just updates the buffer, and I2CSlave_setTransmitBuffer() only needs to be called once during initialization. Repeated reads from the bus master will re-read the same buffer until I2CSlave_setTransmitBuffer() is called again. On the flipside, it is important that the application does not overwrite the transmit buffer space until transmission is complete.
If the slave request feature is enabled, the master may be signaled by calling the I2CSlave_setRequestFlag() function. This function immediately pulls the request line, then waits for the master to begin performing a read operation before it returns (or times out).
The driver state may be obtained by the application at any time by calling I2CSlave_getPortStatus(). This function returns the current I2C Slave state. The possible states are enumerated by tI2CSlaveStates. The possible enumerations are listed below.
| Port Status Option | Description |
|---|---|
| eI2CSlaveIsClosed | The driver is closed. All functions besides I2CSlave_openPort() and I2CSlave_getPortStatus() are invalid. |
| eI2CSlaveIsIdle | The driver is open, but no I2C transactions are currently in progress. |
| eI2CSlaveIsBeingRead | The driver is open and the bus master is reading data. The driver loads data from the transmit buffer until all data has been sent, then it loads the invalid byte. |
| eI2CSlaveIsBeingWrittenTo | The driver is open and the bus master is writing data. The written data is placed into the receive buffer if there is space. At the end of this state, the receive callback in the application is called. |
The bus master may start a write operation at any time. The driver will buffer incoming data into the receive buffer. When the transaction is complete, the application receive callback is called. The callback is passed the size of the data received from the master (in bytes). Since it is called from the driver interrupt service routine, no other interrupts will be processed and the eUSCI_B may be stretching the bus clock line until the driver returns from the receive callback. This provides the callback function the opportunity to process any received data and update the transmit buffer before the master may continue with communication.
The driver provides an error callback to alert the application if there is a problem with the driver. The error callback, when called, passes a value indicating the error that occurred. The possible errors are listed below.
| Error Code | Description |
|---|---|
| eI2CSlaveTransmitRequestTimeout | This code indicates that a slave request to the bus master was not serviced within the timeout window, and the request timed out. |
| eI2CSlaveTransactionTimeout | This code indicates that an I2C transaction was taking longer than the timeout window, and the transaction timed out. This error also results in a driver reset. |
| eI2CSlaveReceiveBufferFull | This code indicates that the receive buffer was full during the last read transaction, and data from the bus master was lost. |
| eI2CSlaveWasReadBeyondTransmitBuffer | This code indicates that the bus master attempted to read data from the slave beyond the valid transmit buffer length (indicating the master was reading invalid bytes). |
The CapTIvate™ Touch Library includes an EMC module in the advanced layer. This module provides processing plug-ins to the touch layer to enhance the robustness of a system in the presence of noise.
While the CapTIvate™ peripheral provides a significant feature set for dealing with electromagnetic compatibility issues on its own, some amount of digital signal processing is still required to process the raw data into usable values. The EMC module in the CapTIvate™ Software Library fills that need.
The EMC module provides configurable algorithms to the base touch layer of the software library.
The EMC module provides the following feature set:
When using the CapTIvate™ Software Library, the EMC module functions are not called by the application. Rather, noise immunity is enabled for a user configuration at a top level. When noise immunity is enabled in the library for a design, several base library functions for calibration and sensor measurement are replaced with EMC versions of the same functions. Those functions utilize the processing algorithms provided by this layer to add a level of robustness to a design.
It is best to enable noise immunity via the CapTIvate™ Design Center. The controller customizer has a compile-time option for noise immunity. Selecting this option sets the CAPT_CONDUCTED_NOISE_IMMUNITY_ENABLE compile-time definition in the CAPT_UserConfig.h file to true when source code is generated.
When the compile-time option is set, the manager layer will make calls to EMC versions of functions rather than the standard versions. Below is a mapping of which functions are replaced:
| Description | Standard Function | EMC Function |
|---|---|---|
| Calibrate a Sensor | CAPT_calibrateSensor() | CAPT_calibrateSensorWithEMC() |
| Update a Sensor | CAPT_updateSensor() | CAPT_updateSensorWithEMC() |
These top level functions are called by the application via abstractions in CAPT_Manager.
| Description | Standard Function | EMC Function |
|---|---|---|
| Process a Cycle | CAPT_processFSMCycle() | CAPT_processCycleWithEMC() |
| Update Prox/Touch Status | CAPT_updateProx, CAPT_updateTouch | CAPT_updateSelfElementProxTouchWithEMC(), CAPT_updateProjElementProxTouchWithEMC() |
These functions are called inside the touch layer, and are not directly called by the application.
The EMC Module is configured through the tEMCConfig structure. The EMC layer only reads from this structure, so the configuration may be kept in non-volatile read-only memory if desired. A default configuration is provided in the CAPT_UserConfig module as shown below:
The default values were selected by bench characterization and have proven effective for several different sensing panels. However, for certain applications and/or certain noise environments, it may be necessary to adjust some of the parameters. To implement a custom configuration, simply create a new tEMCConfig structure with the desired values, and pass it's address to CAPT_loadEMCConfig(). Note that the CapTIvate™ starter project makes this call in CAPT_initUI() in CAPT_Manager. You may either override this call be calling the function again after CAPT_initUI() is called, or you may edit CAPT_initUI() directly.
The configuration structure has the following parameters:
| Member | Description | Default Value | Valid Values |
|---|---|---|---|
| bEnableDynamicThresholdAdjustment | Enable or disable dynamic threshold adjustment. Note that dynamic threshold adjustment only applies to self capacitance sensors in either case. | true | true, false |
| bDynamicThresholdAdjustmentIsGlobal | Enable global dynamic threshold adjustment. When true, a global noise level that is representative of the highest noise level seen in the system is tracked. When the adjusted threshold is calculated for each element, if the global noise is greater than an individual element's noise, then the global value will be used to determine the threshold adjustment. | true | true, false |
| ui16CalibrationNoiseLimit | During calibration, the noise limit is the maximum absolute noise allowed at a given frequency for any element in a sensor before the calibration values for that frequency are deemed invalid. Once a frequency is invalidated, its calibration values will be sourced from the closest valid frequency. If all 4 frequencies are noisy during calibration, the calibration error bit is set. | 10 | 8191 |
| ui8CalibrationTestSampleSize | During calibration, the number of test samples that are taken for each element at each frequency. The peak-to-peak spread of the test set is compared against the ui16CalibrationNoiseLimit to determine if the calibration is valid. | 8 | 255 |
| ui8NoiseThreshold | The relative (% of the LTA with 0%=0 and 100%=128) value that specifies at what element noise level the bNoiseDetected bit in the element structure (and the bSensorNoiseState bit in the parent sensor structure) are set. | 20 | 0-128 |
| ui8MaxRelThreshAdj | The relative (% of the LTA with 0%=0 and 100%=128) value that specifies the maximum threshold after adjustment. This may be used to place a cap on how much adjustment may be applied. | 76 | 0-128 |
| ui8NoiseLevelFilterEntryThresh | If the noise level is increasing (low to high vector) and the new noise sample is below this value, the global and local value filters will be disabled to allow for rapid tracking. A value of '0' keeps the filters enabled at all times. | 32 | 0-128 |
| ui8NoiseLevelFilterExitThresh | If the noise level is decreasing (high to low vector) and the new noise sample is below this value, the global and local value filters will be disabled to allow for rapid tracking. A value of '0' keeps the filters enabled at all times. | 0 | 0-128 |
| ui8LocalNoiseLevelFilterDown | The filter beta applied to the local (element) filtered noise value when the new noise sample is lower than the filtered noise value. | 5 | 0-15 |
| ui8LocalNoiseLevelFilterUp | The filter beta applied to the local (element) filtered noise value when the new noise sample is higher than the filtered noise value. | 1 | 0-15 |
| ui8GlobalNoiseLevelFilterDown | The filter beta applied to the global filtered noise value when the new noise sample is lower than the filtered noise value. | 5 | 0-15 |
| ui8GlobalNoiseLevelFilterUp | The filter beta applied to the global filtered noise value when the new noise sample is higher than the filtered noise value. | 1 | 0-15 |
| coeffA | The 'A' coefficient in the dynamic threshold adjustment algorithm calculation. | 0.0065 | 0-0.999999999 |
| coeffB | The 'B' coefficient in the dynamic threshold adjustment algorithm calculation. | 0.0100 | 0-0.999999999 |
The multi frequency processing algorithm is implemented in the CAPT_resolveMultiFreqSet() function. When noise immunity is enabled, each element is measured at four different conversion frequencies to gather more data in the presence of noise. The algorithm is then applied to the four raw measurements. The output of the algorithm is a single, composite measurement and a noise level. The composite measurement is then used by the higher levels of the library just like a raw sample normally would. The noise level is used to update each element's filtered noise level.
The dynamic threshold adjustment (DTA) algorithm is implemented in the CAPT_computeRelativeNoiseComp() function. The algorithm calculates threshold adjustments based on the amount of noise seen in a history of measurements. It relies on a filtered relative noise value as an input, and it calculates the corresponding threshold adjustment to be applied for proximity and touch detection. The threshold adjustment is calculated based on a polynomial model as shown below, where 'x' is the relative noise value and 'y' is the corresponding relative threshold adjustment. The polynomial allows for greater adjustment at higher noise levels.
This formula with the default values provides the adjustment curve shown below. A linear (A=0; B=0.5) curve is also shown for reference.