Bluetooth Low Energy (LE) and Drivers#
Texas Instruments
2 - 3 hours read
Introduction#
This module covers the basics of how to build a project that involves using TI developed driver functionalities
on top of the basic_ble project. We will discuss the recommended approach on how to
add these drivers in the SDK to create your own custom application.
The lab activities will walk you through how to use drivers like GPIO, ADC, LGPTimer, Systerm Timer, and Real Time Clock (RTC) while also enabling Bluetooth Low Energy to transmit data from a peripheral device configured as a server. First we will learn how to set the drivers to work correctly and then we will learn how to use them with Bluetooth LE functionalities.
It is recommended to have the TI Drivers API Reference section of the TI BLE5-Stack User’s Guide alongside this lab for details and further information.
Prerequisites#
Hardware#
For this lab, you need one Bluetooth-enabled development board. Supported devices are:
Software and Tools for Development#
SIMPLELINK-LOWPOWER-F3-SDK Software Development Kit (SDK)
Code Composer Studio CCS / CCS Cloud or IAR
See Dependencies section of SDK release notes for required version.
Download TI SimpleLink™ Connect App#
Warning
TI SimpleLink™ Connect app does not get automatically updated. You need to update the app in your OS app store manually.
Find the TI SimpleLink™ Connect App on both OS Android and iOS.
Why is it important to execute from BLE task context?#
Processes that run on interrupt routines or RTOS tasks will be able to invoke specific functions and access variables from their own context (stack for instance). Therefore, if we want to do Bluetooth LE operations we first need to change the context to the correct one.
BLEAppUtil_invokeFunctionNoData() is used for this purpose,
particularly when dealing with callbacks or handlers that do not require any data to be passed to them,
BLEAppUtil_invokeFunction() is used otherwise. This utility function is typically part of a BLE software
stack or library, and it simplifies the invocation of specific functions within the BLE application framework.
Please see below for each driver how this function is being used.
Note
If BLEstack functions are called from a different context then the application might go into ICall_abort().
GPIO#
General Purpose Input/Output (GPIO) is a set of pins in the MCU, used to interact with peripherals
on a bidirectional way depending on their configuration, either as an input or output pin. The GPIO
driver module allows you to manage General Purpose I/O pins via a series of APIs. GPIO pin behavior
is usually configured statically, but can also be configured or reconfigured at runtime. We will
approach this in next steps. For further information please refer to the GPIO API detailed description
located inside the TI Drivers API Reference Section of TI BLE5-Stack User’s Guide.
First, lets make sure we have configured our GPIO as required. The following example demonstrates how to configure a GPIO pin to generate an interrupt and how to toggle a LED on and off within the registered interrupt callback function. Please consider the following:
Pin configuration is handled within SysConfig for this example as shown below. Go to SysConfig → TI DRIVERS → GPIO → Add a new GPIO and configure as following. In this example we are only configuring the GPIO pin (
DIO01in this example) and its defined referenced name, the rest (Mode, Pull, Interrupt, etc) will be configured inside the code for explanatory purposes but can be configured using SysConfig as well.
GPIO Configuration in SysConfig#
Note
In this example we are selecting GPIO pins that are not the Buttons. This is intentional to showcase that any GPIO pin can be configured as explained and can be used for any other applications.
Inside the
appMain(void)function in theapp_main.cfile, include the following lines to configure the GPIO pin you have setup in SysConfig. Here we are configuring theCONFIG_GPIO_0pin as Input with Pull Down mode (GPIO_CFG_IN_PD), and enabling an interrupt (GPIO_CFG_INT_ENABLE) to be triggered at rising edge (GPIO_CFG_IN_INT_RISING). Lastly, we configure the interrupt and its callback function (gpioButton0Fxn).GPIO configuration#// Driver header file #include <ti/drivers/GPIO.h> // TI Drivers Configuration #include "ti_drivers_config.h" void gpioButton0Fxn(uint_least8_t index) { // Toggle the LED GPIO_toggle(CONFIG_GPIO_LED_RED); } void appMain(void) { // One-time init of GPIO driver GPIO_init(); // Configure a button pin as input and configure its interrupt // Passing INT_ENABLE means you do not need to also call GPIO_enableInt() GPIO_setConfig(CONFIG_GPIO_0, GPIO_CFG_IN_PD | GPIO_CFG_IN_INT_RISING | GPIO_CFG_INT_ENABLE); GPIO_setCallback(CONFIG_GPIO_0, gpioButton0Fxn); // Call the BLEAppUtil module init function BLEAppUtil_init(&criticalErrorHandler, &App_StackInitDoneHandler, &appMainParams, &appMainPeriCentParams); }
Build and flash the code. Test your solution by inputting a high voltage (3.3v) into the configured GPIO pin. The Red LED should toggle.
Second, now that we know that our GPIO interrupt is set correctly, lets do some Bluetooth LE stuff!
In this example, we will trigger a notification from a specific characteristic of our basic_ble project. Notifications
are important mechanisms for fast and asynchronous transmission of data from the server-side to the central.
For the implementation, please consider the following:
Inside the
Profilesfolder, open theapp_simple_gatt.cfile and add a new function that will send a notification. Due to the fact that we are using the GATT table defined in thebasic_bleproject, we will use the Characteristic 4 (handle number 46 -HANDLE_CHAR_4) that is configured to send notifications.extern uint8 value_gpio_level; #define HANDLE_CHAR_4 46 void NotifyTrigger() { uint8_t status; attHandleValueNoti_t noti; uint8_t len = 1; noti.pValue = GATT_bm_alloc(0, ATT_HANDLE_VALUE_NOTI, len, NULL); if (noti.pValue != NULL) { noti.handle = HANDLE_CHAR_4; noti.len = len; memcpy(noti.pValue, &value_gpio_level, len); // Send notification status = GATT_Notification(0, ¬i, FALSE); if (status != SUCCESS) { GATT_bm_free((gattMsg_t *)¬i, ATT_HANDLE_VALUE_NOTI); } } else { status = bleMemAllocError; } }
Inside the callback function (
gpioButton0Fxn)app_main.c, we will invoke the new function we have created but within the BLEstack context. The function BLEAppUtil_invokeFunctionNoData() is especially important to achieve this. To make it more interesting, we will transmit a dynamic valuevalue_gpio_level. This value will be updated by reading the left button (CONFIG_GPIO_BUTTON_0_INPUT) GPIO digital level. This button is already configured in SysConfig by default in thebasic_bleproject, therefore there is no need to declare something else.uint8 value_gpio_level = 0; void gpioButton0Fxn(uint_least8_t index) { // Toggle the LED GPIO_toggle(CONFIG_GPIO_LED_RED); value_gpio_level = GPIO_read(CONFIG_GPIO_BUTTON_0_INPUT); BLEAppUtil_invokeFunctionNoData(NotifyTrigger); }
Build the project and flash the device.
To verify your implementation you will need a central device where you can see the notification being received. We suggest using the SimpleLink™ Connect Mobile Application. If you are new to the mobile application, please visit our lab on TI SimpleLink™ Connect App.
Establish a connection between the device and the mobile application and go inside
TI Simple Peripheral Service. Search forCharacteristic 4and click onEnable(this option will enable the central to receive notifications). If you generate an interrupt (by inputting a high voltage (3.3v) into the configured GPIO pin) you should see a01(logic level HIGH) value displayed. This makes sense considering the button is configured with Pull-Up mode. On the contrary, if you press the left button, you should see a00(logic level HIGH) value displayed.
Congrats! You have been able to send information through Bluetooth LE triggered using a GPIO interrupt.
TIMERS#
LGPTIMER#
The General Purpose Timer (LGPT) LGPT is often used for high accuracy measurement, timer comparison, DMA triggering, PWM, etc.
The LGPTimer driver allows for asynchronous callbacks after a certain amount of time has elapsed. The LGPT peripherals support
different timer counter widths depending on the peripheral instance number (LGPT0, LGPT1, LGPT2, LGPT3).
The timer counter clock is sourced from the internal prescaler stage which has the high frequency clock (CLKSVT) as input and
is only available in Active or Idle mode. The prescaler can be configured to divide the input system clock,
effectively extending the maximal time interval for the timer counter while reducing the timer resolution.
For further information please refer to the LGPTimerLPF3 API detailed description located inside the TI Drivers API Reference
Section of TI BLE5-Stack User’s Guide.
First, lets make sure we have configured our LGPTimer as required. The following example demonstrates how to configure a LGPT timer to generate an interrupt approximately every 2.5 seconds and how to toggle a LED on and off within the registered interrupt callback function. Please consider the following:
LGPT configuration is handled within SysConfig for this example as shown below. Go to SysConfig → TI DRIVERS → LGPTimer → Add a new LGPTimer and configure as following. In this example we using the
LGPT3as it allows for the longest bit-counter.
GPIO Configuration in SysConfig#
Note
In this example we are selecting LGPTimer…
Inside the
appMain(void)function in theapp_main.cfile, include the following lines to configure the LGPTimer you have setup in SysConfig. Here we are configuring theCONFIG_LGPTIMER_0timer with a clock source prescaled by 256 (params.prescalerDiv) and a counter (counterTarget) set to count up to 4800000 before triggering. If we do the math, the Timer will trigger everycounterTarget÷sourceclock frequency (48 MHz)÷prescalerDiv. In addition, we set the software callback routine that will be called upon the timer interrupt.GPIO configuration##include <ti/drivers/timer/LGPTimerLPF3.h> extern void NotifyTrigger(); void timerCallback(LGPTimerLPF3_Handle lgptHandle, LGPTimerLPF3_IntMask interruptMask) { // interrupt callback code goes here. Minimize processing in interrupt. GPIO_toggle(CONFIG_GPIO_LED_RED); } void appMain(void) { LGPTimerLPF3_Handle lgptHandle; LGPTimerLPF3_Params params; uint32_t counterTarget; // Initialize parameters and assign callback function to be used LGPTimerLPF3_Params_init(¶ms); params.hwiCallbackFxn = timerCallback; params.prescalerDiv = 256; // Open driver lgptHandle = LGPTimerLPF3_open(0, ¶ms); // Set counter target counterTarget = 4800000 - 1; // 2560 ms with a system clock of 48 MHz LGPTimerLPF3_setInitialCounterTarget(lgptHandle, counterTarget, true); // Enable counter target interrupt LGPTimerLPF3_enableInterrupt(lgptHandle, LGPTimerLPF3_INT_TGT); // Start counter in count-up-periodic mode LGPTimerLPF3_start(lgptHandle, LGPTimerLPF3_CTL_MODE_UP_PER); // Call the BLEAppUtil module init function BLEAppUtil_init(&criticalErrorHandler, &App_StackInitDoneHandler, &appMainParams, &appMainPeriCentParams); }
Build and flash the code. You should be able to see the Red LED toggling every 2.5 seconds approximately.
Second, now that we know that our LGPTimer interrupt is set correctly, lets do some Bluetooth LE stuff!
In this example, we will trigger a notification from a specific characteristic of our basic_ble project. Please consider
the following:
Inside the
Profilesfolder, open theapp_simple_gatt.cfile and add a new function that will send a notification. Due to the fact that we are using the GATT table defined in thebasic_bleproject, we will use the Characteristic 4 (handle number 46 -HANDLE_CHAR_4) that is configured to send notifications.extern uint8 value_gpio_level; #define HANDLE_CHAR_4 46 void NotifyTrigger() { uint8_t status; attHandleValueNoti_t noti; uint8_t len = 1; noti.pValue = GATT_bm_alloc(0, ATT_HANDLE_VALUE_NOTI, len, NULL); if (noti.pValue != NULL) { noti.handle = HANDLE_CHAR_4; noti.len = len; memcpy(noti.pValue, &value_gpio_level, len); // Send notification status = GATT_Notification(0, ¬i, FALSE); if (status != SUCCESS) { GATT_bm_free((gattMsg_t *)¬i, ATT_HANDLE_VALUE_NOTI); } } else { status = bleMemAllocError; } }
Inside the callback function (
timerCallback)app_main.c, we will invoke the new function we have created but within the BLEstack context. The function BLEAppUtil_invokeFunctionNoData() is especially important to achieve this. To make it more interesting, we will make transmit a dynamic valuevalue_gpio_level. This value will be updated by reading the left button (CONFIG_GPIO_BUTTON_0_INPUT) GPIO digital level. This button is already configured in SysConfig by default in thebasic_bleproject, therefore there is no need to declare something else.uint8 value_gpio_level = 0; void timerCallback(uint_least8_t index) { // Toggle the LED GPIO_toggle(CONFIG_GPIO_LED_RED); value_gpio_level = GPIO_read(CONFIG_GPIO_BUTTON_0_INPUT); BLEAppUtil_invokeFunctionNoData(NotifyTrigger); }
Build the project and flash the device.
To verify your implementation you will need a central device where you can see the notification being received. We suggest using the SimpleLink™ Connect Mobile Application. If you are new to the mobile application, please visit our lab on TI SimpleLink™ Connect App.
Establish a connection between the device and the mobile application and go inside
TI Simple Peripheral Service. Search forCharacteristic 4and click onEnable(this option will enable the central to receive notifications). You should be able to see the logic level of the button GPIO displayed and updated every 2.5 seconds approximately.
Congrats! You have been able to send information through Bluetooth LE triggered using a LGPTimer interrupt.
System Timer (SYSTIM)#
SYSTIM has 5 channels from which 4 channels are reserved by system software and radio operation. Different to the LGPTimer, the SYSTIM is available in Active mode, Idle mode, and Standby mode and it is synchronized to RTC in hardware.
In general, it is recommended to use ClockP Module if users want to realize the functionality provided by SYSTIM.
The ClockP module, uses the available SYSTIM channel with 1 us resolution and is synchronized with the RTC.
Among other things such as allowing us to get current timestamp and get CPU clock frequency, ClockP can be
used to create a periodic timer to trigger periodic tasks. For further information please refer to the ClockP
API detailed description located inside the TI Drivers API Reference Section of TI BLE5-Stack User’s Guide.
Note
The main difference between using ClockP over LGPTimer is that the first one runs on the System Timer which is capable of running in the background, even when the device is in standby while the LGPTimer runs in active mode.
We will modify the LGPTimer example to use the ClockP module instead. Inside the
appMain(void)function in theapp_main.cfile, include the following lines to configure the ClockP module instead of the LGPTimer. Here we are configuring theclockTicksto 5000 ms by settingTIME_UNITto 5000 and theCLOCK_UNITS_MSto 1000 based on the valueconfigTICK_RATE_HZdefined insideFreeRTOSConfig.hwhich is also 1000. In addition, we setup the callback routineclockHandlerthat will be triggered when the number of ticks (set inClockP_setTimeout()) have reached the same value asclockTicks, and theperiodto 0 (one-shot timer) as theClockP_start()function is being called constantly from the callback.ClockP configuration##include <ti/drivers/dpl/ClockP.h> static ClockP_Struct clkStruct; ClockP_Handle clkHandle; ClockP_Params clockpParams; #define TIME_UNIT 5000 #define CLOCK_UNITS_MS 1000 extern void NotifyTrigger(); uint8 value_gpio_level = 0; static void clockHandler(void) { GPIO_toggle(CONFIG_GPIO_LED_RED); value_gpio_level = GPIO_read(CONFIG_GPIO_BUTTON_0_INPUT); if(!ClockP_isActive(clkHandle)) { int32_t clockTicks = TIME_UNIT * (CLOCK_UNITS_MS); ClockP_setTimeout(clkHandle, clockTicks); ClockP_start(clkHandle); } BLEAppUtil_invokeFunctionNoData(NotifyTrigger); } void appMain(void) { ClockP_Params_init(&clockpParams); uint32_t clockTicks = TIME_UNIT * (CLOCK_UNITS_MS); clockpParams.period = 0; // set to use one-shot timer clockpParams.startFlag = true; clockpParams.arg = (uintptr_t)clockHandler; // Initialize clock instance. clkHandle = ClockP_construct(&clkStruct, (void *)BLEAppUtil_invokeFunctionNoData, clockTicks, &clockpParams); // Call the BLEAppUtil module init function BLEAppUtil_init(&criticalErrorHandler, &App_StackInitDoneHandler, &appMainParams, &appMainPeriCentParams); }
Note
Another way of generating a periodic time trigger is to set the clockpParams.period to the value of clockTicks.
This way, it will not be necessary to re-start the ClockP counter by calling ClockP_setTimeout and ClockP_start
inside the callback every time.
Build the project and flash the device.
To verify your implementation you will need a central device where you can see the notification being received. We suggest using the SimpleLink™ Connect Mobile Application. If you are new to the mobile application, please visit our lab on TI SimpleLink™ Connect App.
Establish a connection between the device and the mobile application and go inside
TI Simple Peripheral Service. Search forCharacteristic 4and click onEnable(this option will enable the central to receive notifications). You should be able to see the logic level of the button GPIO displayed and updated every 5 seconds approximately.
Congrats! You have been able to send information through Bluetooth LE triggered using the ClockP module.
Real Time Clock (RTC)#
The RTC is a 67-bit, 2-channel timer running on the Low Frequency Clock. The RTC is active in stanby and
active power states. We will learn how to fetch the timestamp by directly reading from the RTC registers.
You can find more information about these registers (TIME8U and TIME524M) inside the
TI CC2340R5 - Technical Reference Manual in Chapter 12.
RTC.TIME8U has a range of approximately 9.5 hours with an LSB representing 8 microseconds.
RTC.TIME524M has a range of approximately 71.4 years with an LSB representing 524 milliseconds.
The main reason from reading the RTC registers directly is to use the TIME524M if a longer range of time is needed.
We will also use this opportunity to show how to transmit data through Bluetooth LE advertisement report, and therefore without the need to establish a connection.
Go to
app_peripheral.cand add a new event calledBLEAPPUTIL_ADV_ENDto theperipheralAdvHandler. This will allow us to receive an event from the BLEstack everytime an advertisement is finished.Adding new event to peripheralAdvHandler#BLEAppUtil_EventHandler_t peripheralAdvHandler = { .handlerType = BLEAPPUTIL_GAP_ADV_TYPE, .pEventHandler = Peripheral_AdvEventHandler, .eventMask = BLEAPPUTIL_ADV_START_AFTER_ENABLE | BLEAPPUTIL_ADV_END_AFTER_DISABLE | BLEAPPUTIL_ADV_END };
Still in
app_peripheral.c, collect the time when the first advertisement is first enabled by using theBLEAPPUTIL_ADV_START_AFTER_ENABLEcaseevent inside thePeripheral_AdvEventHandler()function.Fetch RTC Timestamp after Advertisement is first enabled#case BLEAPPUTIL_ADV_START_AFTER_ENABLE: { // Read the TIME8U register. RTC_cnt_8U = HWREG(RTC_BASE + RTC_O_TIME8U) & 0xFFFFFFFF; // Read the TIME524M register. RTC_cnt_524M = HWREG(RTC_BASE + RTC_O_TIME524M) & 0xFFFFFFFF; // Both registers (524M and 8U) are latched from the same RTC register, but this happen between 1-2 clock cycles apart. // The two registers have some shared bits, and the loop assumes that if the shared bits are equal, // then the values read from 524M and 8U are synchronized (values latched at same clock cycle). while ((RTC_cnt_524M & 0xFFFF) != (RTC_cnt_8U >> 16) & 0xFFFF) { RTC_cnt_8U = HWREG(RTC_BASE + RTC_O_TIME8U); RTC_cnt_524M = HWREG(RTC_BASE + RTC_O_TIME524M); } // Calculate the RTC time in mili seconds. RTCTime_msec = (RTC_cnt_524M * 524) + (RTC_cnt_8U & 0xFFFF)*8/1000; timestamp_when_start_adv = (uint32_t)RTCTime_msec/1000; break; }
In addition, add the new
casescenario inside thePeripheral_AdvEventHandler()function to change the advertisement report data after everySKIP_ADVadvertisements (BLEAPPUTIL_ADV_END). Therefore the time in between transmitting a timestamp will be calculated asadvertisement_interval (ms) x SKIP_ADVseconds. In addition, we fetch the RTC ticks timestamp (timestamp_when_adv) and calculate the overall timestamp (rtc_overall) which is:timestamp_when_start_adv-timestamp_when_end_adv.Fetch RTC Timestamp after every Advertisement#case BLEAPPUTIL_ADV_END: { update_rtc++; if(update_rtc > SKIP_ADV){ // This function will automatically disable advertising for all advertising handles // that use this buffer and allows to update the contents of a data buffer that is // currently being used by multiple advertising sets. GapAdv_prepareLoadByBuffer(advData1, FALSE); RTC_cnt_8U = HWREG(RTC_BASE + RTC_O_TIME8U) & 0xFFFFFFFF; RTC_cnt_524M = HWREG(RTC_BASE + RTC_O_TIME524M) & 0xFFFFFFFF; while ((RTC_cnt_524M & 0xFFFF) != (RTC_cnt_8U >> 16) & 0xFFFF) { RTC_cnt_8U = HWREG(RTC_BASE + RTC_O_TIME8U); RTC_cnt_524M = HWREG(RTC_BASE + RTC_O_TIME524M); } RTCTime_msec = (RTC_cnt_524M * 524) + (RTC_cnt_8U & 0xFFFF)*8/1000; timestamp_when_end_adv = (uint32_t)RTCTime_msec/1000; rtc_overall = (timestamp_when_start_adv - timestamp_when_end_adv); // Each of the advertisement report fields is 1-byte long, therefore // we need to segment the data accordingly. advData1[11] = (rtc_overall & 0xFF000000)>>24; advData1[12] = ((rtc_overall & 0x00FF0000)>>16); advData1[13] = ((rtc_overall & 0x0000FF00)>>8); advData1[14] = ((rtc_overall & 0x000000FF)); // The function will automatically re-enable advertising for all handles that use this buffer. // Consider the size of the advertisement report (which is 15 in this example). GapAdv_loadByBuffer(15, advData1); update_rtc = 0; } break; }
Note
Please take into account that the advertisement report structure may be different depending on your configuration.
You can take a look at the advData1 structure inside SysConfig → Show Generated Files (< >
symbol on upper right corner) → ti_ble_config.c and search for advData1[].
The field we can use to add this information (timestamp in our example) is the Additional Data section.
Make sure to create an advertisement structure that already accounts for the amount of data you will input
inside the Additional Data as you will need to modify the already existing memory addresses.
Please take a look at the BLE Scanning and Advertising lab for further reference on this.
Make sure to declare the required libraries, variables and definitions.
RTC configuration##include <ti/drivers/dpl/ClockP.h> #include <ti/drivers/GPIO.h> uint32_t timestamp_when_adv = 0; extern uint32_t timestamp_when_connect; uint32_t rtc_overall = 0; char update_rtc = 0; uint8 RTC_master; #define SKIP_ADV 10 // RTC Lower Time Slice #define RTC_O_TIME8U 0x00000018U // TIME8U register address. // RTC Upper Time Slice #define RTC_O_TIME524M 0x0000001CU // TIME524M register address. uint64_t RTC_cnt_524M; uint64_t RTC_cnt_8U; uint64_t RTCTime_msec = 0;
Build the project and flash the device.
To verify your implementation you will need a central device where you can receive and parse the advertisement report. We suggest visiting our lab on BLE Scanning and Advertising.
Establish a connection between the device and the mobile application and go inside
TI Simple Peripheral Service. Search forCharacteristic 4and click onEnable(this option will enable the central to receive notifications). You should be able to see the logic level of the button GPIO displayed and updated every 5 seconds approximately.
Congrats! You have been able to send RTC timestamp information through Bluetooth LE advertisement packets. Remember that a similar approach can be used to transmit data coming from other sources.
Note
As you have seen, we have transmitted data as part of the advertisement report, therefore without the need of establishing a connection. In the same way, you can transmit data using the other drivers we have seen so far by using this method. However, as you can expect, there are limitations and considerations to take into account, some of them are: limited payload (max 33 bytes of advertisement report data and 252 with Advertisement Extension) and no data encryption (only supported through connection followed by pairing/bonding).
ADC#
The Analog to Digital Conversion (ADC) driver supports sampling and converting raw values into microvolts. The next example will use the LGPTimer configured previously in order to trigger an ADC conversion. However, you can use the ClockP as well.
We will replace a simple GPIO read with a value coming from the ADC!
For further information please refer to the ADC API detailed description located inside the TI Drivers API Reference Section of TI BLE5-Stack User’s Guide.
ADC configuration is handled within SysConfig for this example as shown below. Go to SysConfig → TI DRIVERS → ADC → Add a new ADC instance and configure as following.
ADC Configuration in SysConfig#
Inside the
appMain(void)function in theapp_main.cfile, add the following lines to configure the ADC you have setup in SysConfig and modify the timer callback to read the ADC value. You would have to change the variablevalue_gpio_leveltype touint16_tas this is required by the ADC if configured for 12-bits sample.ADC configuration##include <ti/drivers/timer/LGPTimerLPF3.h> #include <ti/drivers/ADC.h> ADC_Params ADCparams; ADC_Handle adcHandle; extern uint16_t value_gpio_level; void timerCallback(LGPTimerLPF3_Handle lgptHandle, LGPTimerLPF3_IntMask interruptMask) { // interrupt callback code goes here. Minimize processing in interrupt. GPIO_toggle(CONFIG_GPIO_LED_RED); ADC_convert(adcHandle, &value_gpio_level); BLEAppUtil_invokeFunctionNoData(NotifyTrigger); } void appMain(void) { //...Timer Config...// // One-time init of ADC driver ADC_init(); // initialize optional ADC parameters ADC_Params_init(&ADCparams); ADCparams.isProtected = true; // Open ADC channels for usage adcHandle = ADC_open(CONFIG_ADC_0, &ADCparams); // Call the BLEAppUtil module init function BLEAppUtil_init(&criticalErrorHandler, &App_StackInitDoneHandler, &appMainParams, &appMainPeriCentParams); }
Build the project and flash the device.
To verify your implementation you will need a central device where you can see the notification being received. We suggest using the SimpleLink™ Connect Mobile Application. If you are new to the mobile application, please visit our lab on TI SimpleLink™ Connect App.
Establish a connection between the device and the mobile application and go inside
TI Simple Peripheral Service. Search forCharacteristic 4and click onEnable(this option will enable the central to receive notifications). You should be able to see the ADC value displayed. If the application is configured to display in decimal format, you should be able to see 0 when ADC pin (DIO07) connected to GND and 255 when connected to 3.3 volts.
References#
TI CC2340R5 - Technical Reference Manual
Bluetooth Core Specification Version 5.3