6. Code Overview

This section provides the code blocks needed to successfully execute this tutorial.

6.1. Header Files

In main.c, add the following header files:

#include "hw_wkup.h"

#include "ad_nvparam.h"
#include "ad_nvms.h"
#include <platform_nvparam.h>

6.2. System Init Code

In main.c, replace system_init() with the following code:

/* OS signals used for synchronizing OS tasks */
static OS_EVENT signal_flash;

/* Flash memory application task - Function prototype */
static void prvFlashTask( void *pvParameters );


/* Flash memory application task priority */
#define mainFLASH_TASK_PRIORITY     ( OS_TASK_PRIORITY_NORMAL )

/* Flag for selecting Flash memory operation */
volatile static bool flash_state = 0;


static void system_init( void *pvParameters )
{
        OS_TASK task_h  = NULL;
        OS_TASK flash_h = NULL;

#if defined CONFIG_RETARGET
        extern void retarget_init(void);
#endif

        /* Prepare clocks. Note: cm_cpu_clk_set() and cm_sys_clk_set() can only be called
         * from a task since they will suspend the task until the XTAL16M has settled and,
         * maybe, the PLL is locked.
         */
        cm_sys_clk_init(sysclk_XTAL16M);
        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();

        /* init resources */
        resource_init();

#if defined CONFIG_RETARGET
        retarget_init();
#endif

        /* Initialize the OS event signal */
        OS_EVENT_CREATE(signal_flash);

        /* Set the desired sleep mode. */
        pm_set_sleep_mode(pm_mode_extended_sleep);


        /* Start main task here */
        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 */
                        200 * OS_STACK_WORD_SIZE,       /* 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);

        /* Suspend task execution */
        OS_TASK_SUSPEND(task_h);

        /*
         * Task responsible for flash memory operations.
         */
        OS_TASK_CREATE( "FLash",                        /* The text name assigned to the
                                                           task, for debug only; not used
                                                           by the kernel. */
                        prvFlashTask,                   /* The function that implements
                                                           the task. */
                        (void *)flash_h,                /* The parameter passed to the
                                                           task. */
                        200 * OS_STACK_WORD_SIZE,       /* The number of bytes to allocate
                                                           to the stack of the task. */
                        mainFLASH_TASK_PRIORITY,        /* The priority assigned to the
                                                           task. */
                        flash_h );                      /* The task handle */
        OS_ASSERT(flash_h);


        /* The work of the SysInit task is complete */
        OS_TASK_DELETE( xHandle );
}

In main(), slightly modify the task creation of system_init(). The stack size should be increased, for instance to 500 bytes. The following code snippet shows how it should look like:

status = OS_TASK_CREATE("SysInit",

                system_init,
                ( void * ) 0,
                500,              /* Modified code line! */

                OS_TASK_PRIORITY_HIGHEST,
                xHandle );

6.3. Wake-Up Timer Code

In main.c (after system_init()), add the following code for handling external events via the wake-up controller:

/*
 * Callback function to be called after an external event is generated,
 * that is, after K1 button on the Pro DevKit is pressed.
 */
void wkup_cb(void)
{
        /*
         * This function must be called by any user-specified
         * interrupt callback, to clear the interrupt flag.
         */
        hw_wkup_reset_interrupt();

        /*
         * Toggle flash status.
         */
        flash_state ^= 1;

        /*
         * Time for resuming [prvFlashTask] task has elapsed.
         */
        OS_EVENT_SIGNAL_FROM_ISR(signal_flash);
}

/*
 * Function which makes all the necessary initializations for the
 * wake-up controller
 */
static void init_wkup(void)
{
        /*
         * This function must be called first and is responsible
         * for the initialization of the hardware block.
         */
        hw_wkup_init(NULL);

        /*
         * Configure the pin(s) that can trigger the device to wake up while
         * in sleep mode. The last input parameter determines the triggering
         * edge of the pulse (event)
         */
        hw_wkup_configure_pin(HW_GPIO_PORT_1, HW_GPIO_PIN_6, true,
                                                      HW_WKUP_PIN_STATE_LOW);

        /*
         * This function defines a delay between the moment at which
         * a trigger event is present and the moment at which the controller
         * takes this event into consideration. Setting debounce time to [0]
         * hardware debouncing mechanism is disabled. Maximum debounce time is 63 ms.
         */
        hw_wkup_set_debounce_time(10);

// Check if the chip is either DA14680 or 81
#if dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_A

        /*
         * Set threshold for event counter. Interrupt is generated after
         * the event counter reaches the configured value. This function
         * is only supported in DA14680/1 chips.
         */
        hw_wkup_set_counter_threshold(1);
#endif

        /* Register interrupt handler */
        hw_wkup_register_interrupt(wkup_cb, 1);
}

6.4. Hardware Initialization

In main.c, replace both periph_init() and prvSetupHardware() with the following code to configure pins after a power-up/wake-up cycle. Please note that every time the system enters sleep, it loses all its pin configurations.

/**
 * @brief Initialize the peripherals domain after power-up
 *
 */
static void periph_init(void)
{
#       if dg_configBLACK_ORCA_MB_REV == BLACK_ORCA_MB_REV_D
#               define UART_TX_PORT    HW_GPIO_PORT_1
#               define UART_TX_PIN     HW_GPIO_PIN_3
#               define UART_RX_PORT    HW_GPIO_PORT_2
#               define UART_RX_PIN     HW_GPIO_PIN_3
#       else
#               error "Unknown value for dg_configBLACK_ORCA_MB_REV!"
#       endif


        hw_gpio_set_pin_function(UART_TX_PORT, UART_TX_PIN, HW_GPIO_MODE_OUTPUT,
                        HW_GPIO_FUNC_UART_TX);
        hw_gpio_set_pin_function(UART_RX_PORT, UART_RX_PIN, HW_GPIO_MODE_INPUT,
                        HW_GPIO_FUNC_UART_RX);

        /* This pin drives the D2 Led on the Pro DevKit (for debugging purposes) */
        hw_gpio_set_pin_function(HW_GPIO_PORT_1, HW_GPIO_PIN_5,
                                          HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_GPIO);
}

/**
  * @brief Hardware Initialization
  */
 static void prvSetupHardware( void )
 {
        /* Init hardware */
        pm_system_init(periph_init);
        init_wkup();
 }

6.5. Flash Task Code

Code snippet of the prvFlashTask task responsible for interacting with the externally connected flash memory of the system. In main.c, add the following code (for instance, after system_init()):

/*
 * Task responsible for interacting with the externally
 * connected flash memory of the system.
 */
static void prvFlashTask( void *pvParameters )
{

        uint16_t wd_param_bytes = 0;

        uint16_t wd_log_bytes = 0;
        uint16_t rd_log_bytes = 0;


        /*
         * Data to be written during a write access to
         * [NVMS_PARAM_PART] partition entry.
         */
         uint8_t bd_address_nvparam_wd[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00};

        /*
         * Buffer used for storing data during a read access to
         * [NVMS_LOG_PART] partition entry.
         */
        char log_value_rd[25];

        /*
         * Data to be written during a write access to
         * [NVMS_LOG_PART] partition entry.
         */
        char log_value_1_wd[] = "BD address validated!";
        char log_value_2_wd[] = "BD address invalidated!";

        /*
         * Handler for accessing [NVMS_PARAM_PART] partition entry.
         */
        nvparam_t param;

        /*
         * Handler for accessing [NVMS_LOG_PART]  partition entry.
         */
        nvms_t nvms_var;

        /*
         * Flash adapter initialization should be done once at the beginning. Alternatively,
         * this function could be called during system initialization in system_init().
         */
        ad_nvms_init();

        /*
         * Before accessing a partition entry, you should first open it.
         */
        nvms_var = ad_nvms_open(NVMS_LOG_PART);

        for (;;) {

                       /*
                        * Suspend task execution - As soon as WKUP callback function
                        * is triggered the task resumes its execution.
                        */
                       OS_EVENT_WAIT(signal_flash, OS_EVENT_FOREVER);

                       /*
                        * Turn on LED D2 on Pro DevKit indicating the
                        * beginning of a process.
                        */
                       hw_gpio_set_active(HW_GPIO_PORT_1, HW_GPIO_PIN_5);

                        /*
                         * Before accessing a partition entry, you should first open it.
                         */
                        param = ad_nvparam_open("ble_platform");

                        // Validate the BD address
                        if (flash_state == 1) {

                                /*
                                 * Validate the validity flag of BD address entry
                                 * (7th byte)
                                 */
                                memset(bd_address_nvparam_wd + 6, 0x00, 1);

                                /*
                                 * Attempt a write access to [NVMS_PARAM_PART]
                                 * partition entry to write the BD address
                                 * field value.
                                 *
                                 * The function returns the actual number of written data.
                                 */
                                wd_param_bytes = ad_nvparam_write(param,
                                            TAG_BLE_PLATFORM_BD_ADDRESS, sizeof(bd_address_nvparam_wd),
                                                     bd_address_nvparam_wd);

                                OS_ASSERT(wd_param_bytes != 0);


                                /*
                                 * Attempt a write access to [NVMS_LOG_PART] partition
                                 * entry to log the status of the previously written BD
                                 * address (validated/invalidated)
                                 *
                                 * The function returns the actual number of written data.
                                 */
                                wd_log_bytes = ad_nvms_write(nvms_var, 0,
                                                 (uint8_t *)log_value_1_wd, sizeof(log_value_1_wd));

                                OS_ASSERT(wd_log_bytes != 0);


                                // ------------------ Read operations -------------------

                                memset(log_value_rd, 0x20, sizeof(log_value_rd));

                                /*
                                 * Attempt a read access to [NVMS_LOG_PART] partition
                                 * entry to read the current status of BD address
                                 * (validated/invalidated).
                                 *
                                 * The function returns the actual number of read data.
                                 */
                                rd_log_bytes = ad_nvms_read(nvms_var, 0,
                                                  (uint8_t *)log_value_rd, sizeof(log_value_rd));

                                OS_ASSERT(rd_log_bytes != 0);


                                /*
                                 * Print the log status on the serial console.
                                 */
                                printf("\nLog entry: %s\n\r", log_value_rd);

                        // Invalidate the BD address
                        } else if (flash_state == 0) {

                                /*
                                 * Invalidate the validity flag of BD address entry
                                 * (7th byte)
                                 */
                                memset(bd_address_nvparam_wd + 6, 0xFF, 1);

                                /*
                                 * Attempt a write access to [NVMS_PARAM_PART]
                                 * partition entry to write the BD address
                                 * field value.
                                 *
                                 * The function returns the actual number of written data.
                                 */
                                wd_param_bytes = ad_nvparam_write(param,
                                              TAG_BLE_PLATFORM_BD_ADDRESS, sizeof(bd_address_nvparam_wd),
                                                            bd_address_nvparam_wd);

                                OS_ASSERT(wd_param_bytes != 0);

                                /*
                                 * Attempt a write access to [NVMS_LOG_PART]
                                 * partition entry to log the status of the previously
                                 * written BD address (validated/invalidated)
                                 *
                                 * The function returns the actual number of written data.
                                 */
                                wd_log_bytes = ad_nvms_write(nvms_var, 0,
                                              (uint8_t *)log_value_2_wd, sizeof(log_value_2_wd));

                                OS_ASSERT(wd_log_bytes != 0);


                                // ----------------- Read operations ------------------

                                memset(log_value_rd, 0x20, sizeof(log_value_rd));

                                /*
                                 * Attempt a read access to [NVMS_LOG_PART] partition
                                 * entry to read the current status of BD address
                                 * (validated/invalidated).
                                 *
                                 * The function returns the actual number of read data.
                                 */
                                rd_log_bytes = ad_nvms_read(nvms_var, 0,
                                                 (uint8_t *)log_value_rd, sizeof(log_value_rd));

                                OS_ASSERT(rd_log_bytes != 0);

                                /*
                                 * Print the log status on the serial console
                                 */
                                printf("\nLog entry: %s\n\r", log_value_rd);

                        }


                 /* Close the already opened adapter */
                 ad_nvparam_close(param);

                /*
                 * Turn off LED D2 on Pro DevKit indicating the end of
                 * a process.
                 */
                hw_gpio_set_inactive(HW_GPIO_PORT_1, HW_GPIO_PIN_5);


        } // end of for loop
} // end of task

6.6. Macro Definitions

In config/custom_config_qspi.h, add/modify the following macro definitions:

#define dg_configFLASH_ADAPTER                  (1)
#define dg_configNVMS_ADAPTER                   (1)

/*
 * Additional mechanism for accessing the [NVMS_PARAM_PART] partition entry.
 */
#define dg_configNVPARAM_ADAPTER                (1)