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);
                }
        }
}