5. Code Overview
This section provides the code blocks needed to successfully execute this tutorial.
5.1. Header Files
In main.c
file, add the following header files:
#include "ad_sdadc.h"
#include "platform_devices.h"
5.2. Macro Definitions
In config/custom_config_xxx.h
file, add the following macro definitions to enable the SDADC related API:
/*******************************************************
* Peripheral specific config
*/
#define dg_configSDADC_ADAPTER (1)
#define dg_configUSE_HW_SDADC (1)
#define dg_configSDADC_DMA_SUPPORT (0)
In platform_devices.h
file, add the default input source to VBAT:
#define SDADC_INPUT_VBAT
In main.c
file, add the sdadc operation mode macro and os event parameter:
#define USER_SDADC_SYNC_EN 0
#if USER_SDADC_SYNC_EN == 0
__RETAINED static OS_EVENT signal_adc_async;
#endif
5.3. Hardware Initialization
In main.c
file, replace the prvSetupHardware()
routine with the following codes.
static void prvSetupHardware( void )
{
/* Init hardware */
pm_system_init(periph_init);
/* Initialize sdadc IO configuration*/
#ifndef SDADC_INPUT_VBAT
ad_sdadc_io_config(dev_SDADC.id, dev_SDADC.io, AD_IO_CONF_OFF);
#endif
}
In platform_devices.c
file, add IO bus as well as driver configurations for the SDADC device(s) used. These settings will be applied when an application task
attempts to interact with the target analog device.
#include <ad_sdadc.h>
#include "platform_devices.h"
#include "custom_config_eflash.h"
/*
* PLATFORM PERIPHERALS GPIO CONFIGURATION
*****************************************************************************************
*/
#if dg_configSDADC_ADAPTER || dg_configUSE_HW_SDADC
/* SDADC IO */
const ad_sdadc_io_conf_t bus_SDADC = {
.input0 = {
.port = HW_GPIO_PORT_1,
.pin = HW_GPIO_PIN_2,
.on = {HW_GPIO_MODE_INPUT, HW_GPIO_FUNC_ADC, true},
.off = {HW_GPIO_MODE_INPUT, HW_GPIO_FUNC_GPIO, true}
},
.input1 = {
.port = HW_GPIO_PORT_NONE,
.pin = HW_GPIO_PIN_NONE,
.on = {HW_GPIO_MODE_INPUT, HW_GPIO_FUNC_GPIO, true},
.off = {HW_GPIO_MODE_INPUT, HW_GPIO_FUNC_GPIO, true}
},
};
/**
* \brief SDADC configuration
*
*/
/* SDADC driver configurations */
const ad_sdadc_driver_conf_t drv_SDADC = {
.input_mode = HW_SDADC_INPUT_MODE_SINGLE_ENDED,
// .inn = HW_SDADC_IN_ADC0,
#ifndef SDADC_INPUT_VBAT
.inp = HW_SDADC_IN_ADC2_P1_02,
#else
.inp = HW_SDADC_INP_VBAT,
#endif
.continuous = false,
.over_sampling = HW_SDADC_OSR_1024,
.vref_selection = HW_SDADC_VREF_INTERNAL,
.vref_voltage = HW_SDADC_VREF_VOLTAGE_INTERNAL,
#if HW_SDADC_DMA_SUPPORT
.dma_setup = NULL, /**< DMA configuration - NULL to disable */
#endif
.pga_setup = NULL,
};
/* External device/module configurations */
const ad_sdadc_controller_conf_t dev_SDADC = {
.id = HW_SDADC, /* SDADC controller instance */
.io = &bus_SDADC,
.drv = &drv_SDADC
};
#endif /* dg_configSDADC_ADAPTER || dg_configUSE_HW_SDADC */
In platform_devices.h
file, add the following definitions:
#ifndef CONFIG_PLATFORM_DEVICES_H_
#define CONFIG_PLATFORM_DEVICES_H_
#include <ad_sdadc.h>
#ifdef __cplusplus
extern "C" {
#endif
#if dg_configSDADC_ADAPTER || dg_configUSE_HW_SDADC
#define SDADC_INPUT_VBAT
/**
* \brief SDADC device handle
*/
/* List of devices */
extern const ad_sdadc_controller_conf_t dev_SDADC;
#endif /* dg_configSDADC_ADAPTER || dg_configUSE_HW_SDADC */
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_PLATFORM_DEVICES_H_ */
5.4. Task configuration
In static OS_TASK_FUNCTION(system_init, pvParameters)
, modify the stack size of the Template task to 1024 .
And create the signal_adc_async os signal OS_EVENT_CREATE(signal_adc_async);
.
static OS_TASK_FUNCTION(system_init, pvParameters)
{
OS_TASK task_h = NULL;
#if defined CONFIG_RETARGET
extern void retarget_init(void);
#endif
cm_sys_clk_init(sysclk_XTAL32M);
cm_apb_set_clock_divider(apb_div1);
cm_ahb_set_clock_divider(ahb_div1);
cm_lp_clk_init();
/* Prepare the hardware to run this demo. */
prvSetupHardware();
#if defined CONFIG_RETARGET
retarget_init();
#endif
#if USER_SDADC_SYNC_EN == 0
OS_EVENT_CREATE(signal_adc_async);
#endif
pm_set_wakeup_mode(true);
/* Set the desired sleep mode. */
pm_sleep_mode_set(pm_mode_extended_sleep);
/* Start main task here (text menu available via UART1 to control application) */
OS_TASK_CREATE( "Template", /* The text name assigned to the task, for
debug only; not used by the kernel. */
prvTemplateTask, /* The function that implements the task. */
NULL, /* The parameter passed to the task. */
1024, /* The number of bytes to allocate to the
stack of the task. */
mainTEMPLATE_TASK_PRIORITY, /* The priority assigned to the task. */
task_h ); /* The task handle */
OS_ASSERT(task_h);
/* the work of the SysInit task is done */
OS_TASK_DELETE( xHandle );
}
5.5. Operation Code for SDADC Measurements
After main()
, add the following code used for performing SDADC measurements.
#if USER_SDADC_SYNC_EN==0
static void sdadc_user_cb(void *user_data, uint32_t conversions)
{
/* Signal the task that time for resuming has elapsed. */
OS_EVENT_SIGNAL_FROM_ISR(signal_adc_async);
}
#endif
int log_cnt = 1;
/* Perform a SDADC read operation */
static void user_sdadc_reader(const ad_sdadc_controller_conf_t *dev)
{
printf("\n\r***SDADC Demonstration Example***\n\r");
printf(">Log Counts: %d\r\n",log_cnt++);
int error_code;
uint16_t adc_raw_val;
uint16_t voltage_mv;
/* Open the SDADC device */
ad_sdadc_handle_t dev_h = ad_sdadc_open(dev);
#if USER_SDADC_SYNC_EN == 1
/*
* Perform a synchronous SDADC read operation, that is, the task
* is blocking waiting for the operation to finish.
*/
error_code = ad_sdadc_read(dev_h,1, &adc_raw_val);
#else
/*
* Perform an asynchronous SDADC read operation, that is, the task does not
* block waiting for the transaction to finish. Upon operation completion
* callback function is triggered indicating the completion of the SDADC operation
*/
error_code = ad_sdadc_read_async(dev_h, 1, &adc_raw_val, (ad_sdadc_user_cb)sdadc_user_cb, &dev_h);
/*
* In the meantime and while SDADC operations are performed in the background,
* application task can proceed to other operations/calculation. It is essential
* that the new operations do not involve SDADC operations on the already
* occupied block!!!
*/
/*
* Make sure that the current SDADC operation has finished,
* blocking here forever.
*/
OS_EVENT_WAIT(signal_adc_async, OS_EVENT_FOREVER);
#endif
if(error_code){
printf("\n\rUnsuccessful SDADC read operation with error code: %d \n\r",error_code);
}
/* Close the SDADC device */
ad_sdadc_close(dev_h, true);
/* Calculate the voltage in mV*/
voltage_mv = (adc_raw_val>>1) * dev->drv->vref_voltage/0x7fff;
printf("\n\rADC value (raw): 0x%04x \n\r",adc_raw_val>>1);
#ifndef SDADC_INPUT_VBAT
printf("\n\rDetected voltage: %d mV\n\r",voltage_mv);
#else
printf("\n\rDetected voltage: %d mV\n\r",voltage_mv * 4);
#endif
fflush(stdout);
}
In static OS_TASK_FUNCTION(prvTemplateTask, pvParameters)
function, add user_sdadc_reader()
function.
/**
* @brief Template task increases a counter every mainCOUNTER_FREQUENCY_MS ms
*/
static OS_TASK_FUNCTION(prvTemplateTask, pvParameters)
{
OS_TICK_TIME xNextWakeTime;
static uint32_t test_counter=0;
/* Initialise xNextWakeTime - this only needs to be done once. */
xNextWakeTime = OS_GET_TICK_COUNT();
for ( ;; ) {
/* Place this task in the blocked state until it is time to run again.
The block time is specified in ticks, the constant used converts ticks
to ms. While in the Blocked state this task will not consume any CPU
time. */
xNextWakeTime += mainCOUNTER_FREQUENCY_MS;
OS_DELAY_UNTIL(xNextWakeTime);
test_counter++;
if (test_counter % (1000 / OS_TICKS_2_MS(mainCOUNTER_FREQUENCY_MS)) == 0) {
printf("#");
fflush(stdout);
// start sdadc conversion
user_sdadc_reader(&dev_SDADC);
}
}
}