3. Implementation

Using the project created in the Clone FreeRTOS retarget Project section, this section demonstrates how to catch the external event and use it in the RTOS.

3.1. Existing Application

The freertos_retarget project demonstrates the scheduling of a timer-based task by sending a character on the UART every second. This behavior is implemented in main.c.

static void prvTemplateTask( void *pvParameters )
{
        OS_TICK_TIME xNextWakeTime;
        static uint32_t test_counter=0;

        /* Initialize 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. */
                vTaskDelayUntil( &xNextWakeTime, mainCOUNTER_FREQUENCY_MS );
                test_counter++;

                if (test_counter % (1000 / OS_TICKS_2_MS(mainCOUNTER_FREQUENCY_MS)) == 0) {
                        printf("#");
                        fflush(stdout);
                }
        }
}

3.2. Configure the GPIO Generating Interruption

On the DA1468x development kits, the button K1 is mapped to the GPIO P1_6. In order to detect an interrupt, it is necessary to configure the GPIO as an input. As the board schematic shows, the button connects the pin to the ground. We will set a pull-up on the pin to be able to detect a falling edge when the button is pressed.

_images/board_schematic.png

Fig. 3 K1 Button Schematic

The configuration should look like:

/* Configure button interrupts */
hw_gpio_configure_pin(HW_GPIO_PORT_1, HW_GPIO_PIN_6, HW_GPIO_MODE_INPUT_PULLUP, HW_GPIO_FUNC_GPIO, 1);

3.3. Set up the Wake-Up Timer

The next step is to initialize the Wake-Up Timer block and configure it to generate an interuption on the falling edge. Then we need to register a callback to handle the interruption, the function will be button_interrupt_cb().

#include "hw_wkup.h"

/* Initialize the Wake-up Timer */
hw_wkup_init(NULL);

/* Configure the Wake-up Timer to interrupt on the falling edge of P1_6 */
hw_wkup_configure_pin(HW_GPIO_PORT_1,HW_GPIO_PIN_6, 1, HW_WKUP_PIN_STATE_LOW);

/* Register callback to handle the event from the GPIO */
hw_wkup_register_interrupt(button_interrupt_cb, 1);

The NULL parameter in hw_wkup_init() resets the wake-up block to its initial state. hw_wkup_configure_pin() configures the GPIO P1_6 to generate the interruption.

3.4. Handle the Interruption

button_interrupt_cb() will be executed in handling mode. In order to defer the handling of the interruption inside the RTOS, we will generate a task notification. The callback also needs to clear the current interruption.

void button_interrupt_cb(void)
{
        hw_wkup_reset_interrupt();
        OS_TASK_NOTIFY_FROM_ISR(task_h, 0x1, OS_NOTIFY_SET_BITS);
}

Note

The task_h handler is declared in the system_init() function and needs to be made global to allow button_interrupt_cb() to use it.

3.5. Using the Notification

The notification can be used by the prvTemplateTask(). We can modify the loop inside the task so that instead of sending a character on regular basis, we wait for the button push notification. Effectively the character will be sent everytime the button is pushed.

for( ;; ) {

             /* Wait for the external interruption notification */
             OS_TASK_NOTIFY_WAIT(0x0, OS_TASK_NOTIFY_ALL_BITS, &ulNotifiedValue, OS_TASK_NOTIFY_FOREVER);

             /* Check the notification is the expected value */
              if(ulNotifiedValue & 0x1){
                      /* Send the character on the UART */
                     printf("#");
                     fflush(stdout);
             }
     }

Eventually the code should look like this:

#include "hw_wkup.h"

void button_interrupt_cb(void)
{
        hw_wkup_reset_interrupt();
        OS_TASK_NOTIFY(task_h, 0x1, OS_NOTIFY_SET_BITS);
}


/**
 * @brief Template task increases a counter every mainCOUNTER_FREQUENCY_MS ms
 */
static void prvTemplateTask( void *pvParameters )
{
        OS_TICK_TIME xNextWakeTime;
        static uint32_t test_counter=0;
        uint32_t ulNotifiedValue;

        /* Configure button interrupts */
        hw_gpio_configure_pin(HW_GPIO_PORT_1,HW_GPIO_PIN_6, HW_GPIO_MODE_INPUT_PULLUP,HW_GPIO_FUNC_GPIO, 1);

        /* Initialize and configure the Wake-up Timer */
        hw_wkup_init(NULL);
        hw_wkup_configure_pin(HW_GPIO_PORT_1,HW_GPIO_PIN_6, 1, HW_WKUP_PIN_STATE_LOW);

        hw_wkup_register_interrupt(button_interrupt_cb, 1);

   for( ;; ) {

                /* Wait for the external interruption notification */
                OS_TASK_NOTIFY_WAIT(0x0, OS_TASK_NOTIFY_ALL_BITS, &ulNotifiedValue,OS_TASK_NOTIFY_FOREVER);

                /* Check the notification is the expected value */
                 if(ulNotifiedValue & 0x1){
                         /* Send the charaacter on the UART */
                        printf("#");
                        fflush(stdout);
                }
        }
}

3.6. Testing

Load the code on the the target development kit and start execution. Open a serial terminal of your choice with the following parameters:

  • 115200 bps
  • 8 bits
  • no flow control
  • 1 stop bit

After each press you should see an additional # character appear in your serial console as shown in Fig. 4.

_images/serial_term.png

Fig. 4 Terminal Interface