Wakeup From UART

Requirements

This example has been made with GAP9, and EvalKit Board 2.0, and an external UART device. For pads numbers, please refer to the documentation of EvalKit Board version 2.0. Please note that the TX & RTS pads must be Always On so they can be controlled during sleep.

Description

This example shows how to wake up gap9 from light sleep, using an external UART device.

As you can see on this example, we open an UART device, and use it. Then we go into ligt sleep, by asking to be wake up from the external UART device on the RX pin. When receiving a byte on this pin, gap9 will wake up and will be back where we stopped. Before continuing as before, we need to do two things:

  • Setting pads back to their configuration

  • Getting the UART device back (restoring the link to the instance)

Once we do these two steps, we can use our UART again as before.

How to use

As you can see in the upper description, to wake up gap9, a byte must be sent on the RX pin. To do so, use your external UART device, and send a byte through the UART. To finish the example, please send BUFFER_SIZE bytes, at least.

How to run

First, flash the code on the MRAM:

cmake -B build
cmake --build build -t flash

Then, put boot pads to the MRAM configuration, and run your application by pressing the reset button on the EvalKit Board.

Limitations

Be aware that using an UART link to wake up GAP will not prevent to lose some bytes if you send a frame. Only one byte is useful to wake up GAP! During sleep the UART FIFO is not configured and so the bytes, following the first one, will be lost while the FIFO is not configured back.

On the example you can see #define BYTES_LOST to define the number of bytes that are lost at wake up. This define depends of the baudrate.

Code

/*
 * Copyright (c) GreenWaves Technologies 2022
 * All rights reserved.
 */

/*
 * Example wake up from UART on light sleep
 *
 * Please, read the README to get more information on what this example does,
 * and how to use it.
 */

// Global include
#include "pmsis.h"

// DEFINES
#define UART_ID 0
#define BUFFER_SIZE ( 16 * 3 )
#define BYTES_LOST 33 // Bytes lost while RTS is still low. Do not read them. Depend of the baudrate !

#define PAD_UART0_RX  ( PI_PAD_067 ) // CN2 Pin 6
#define PAD_UART0_TX  ( PI_PAD_041 ) // CN3 Pin 8
#define PAD_UART0_RTS ( PI_PAD_042 ) // CN4 Pin 10
#define PAD_UART0_CTS ( PI_PAD_034 ) // CN2 Pin 4

// Global variable
PI_L2 uint8_t buffer[BUFFER_SIZE];


/*
 * Functions
 */

static void setup_fc_pads(void)
{
    pi_pad_function_set(PAD_UART0_CTS, PI_PAD_FUNC0);
    pi_pad_function_set(PAD_UART0_RTS, PI_PAD_FUNC0);

    pi_pad_mux_group_set(PAD_UART0_CTS, PI_PAD_MUX_GROUP_UART0_CTS);
    /* PI_PAD_MUX_GROUP_UART0_CTS is by default on pad 62
     * Changing its function to prevent conflicts
     */
    pi_pad_function_set(PI_PAD_062, PI_PAD_FUNC0);
    pi_pad_mux_group_set(PI_PAD_062, PI_PAD_MUX_GROUP_PWM7);

    pi_pad_mux_group_set(PAD_UART0_RTS, PI_PAD_MUX_GROUP_UART0_RTS);
    /* PI_PAD_MUX_GROUP_UART0_RTS is by default on pad 63
     * Changing its function to prevent conflicts
     */
    pi_pad_function_set(PI_PAD_063, PI_PAD_FUNC0);
    pi_pad_mux_group_set(PI_PAD_063, PI_PAD_MUX_GROUP_PWM7);
}

static void setup_pads(void)
{
    pi_pad_function_set(PAD_UART0_RX, PI_PAD_FUNC0);
    pi_pad_function_set(PAD_UART0_TX, PI_PAD_FUNC0);

    pi_pad_mux_group_set(PAD_UART0_RX, PI_PAD_MUX_GROUP_UART0_RX);
    /* PI_PAD_MUX_GROUP_UART0_RX is available by default on pad 60
     * We need to set another function (with a lower priority) to this pad 60 to
     * prevent conflits
     */
    pi_pad_function_set(PI_PAD_060, PI_PAD_FUNC0);
    pi_pad_mux_group_set(PI_PAD_060, PI_PAD_MUX_GROUP_PWM7);

    pi_pad_mux_group_set(PAD_UART0_TX, PI_PAD_MUX_GROUP_UART0_TX);
    /* PI_PAD_MUX_GROUP_UART0_TX is by default on pad 61
     * Changing its function to prevent conflicts
     */
    pi_pad_function_set(PI_PAD_061, PI_PAD_FUNC0);
    pi_pad_mux_group_set(PI_PAD_061, PI_PAD_MUX_GROUP_PWM7);

    if (CONFIG_EXAMPLE_UART_FC == 1)
        setup_fc_pads();
}

static int8_t light_sleep(pi_device_t *uart)
{
    printf("Going to light sleep\n");

    // Set source for wakeup
    if (pi_uart_ioctl(uart, PI_UART_IOCTL_CHIP_WAKEUP_UART_RX, (void *) PAD_UART0_RX))
    {
        printf("This UART RX pad (%d) can not be configured as a wake up source \
                from uart\n", PAD_UART0_RX);
        return -1;
    }

    // Configure AO pads for sleep
    // TX -> output to high value
    pi_pad_sleep_cfg_set(PAD_UART0_TX, PI_PAD_SLEEP_CFG_OUTPUT_ENABLED | PI_PAD_SLEEP_CFG_OUTPUT_VALUE_1);
    // RTS -> output to low value
    pi_pad_sleep_cfg_set(PAD_UART0_RTS, PI_PAD_SLEEP_CFG_OUTPUT_ENABLED);

    // Force AO pads to their sleep mode configuration to force RTS pad to 0
    pi_pad_sleep_cfg_force(1);

    // Set sleep mode and go to sleep
    pi_pmu_domain_state_change(PI_PMU_DOMAIN_CHIP, PI_PMU_DOMAIN_STATE_LIGHT_SLEEP, 0);

    /*
     * At wake up we will fall back here
     */
    printf("Back from light sleep\n");

    return 0;
}

/*
 * Main function
 * Returned values:
 *  0 = Success
 * -1 = Error in configuration
 * -2 = Error with light sleep
 */
int main(void)
{
    printf("\n*** Entering main controller ***\n\n");

    printf("*** Example wake up from UART ***\n");

    // Before using uart, pads must be set properly
    setup_pads();

    // Configuring UART and oppening it
    pi_device_t uart;
    struct pi_uart_conf conf;

    pi_uart_conf_init(&conf);
    conf.baudrate_bps  = CONFIG_EXAMPLE_UART_BPS;
    conf.enable_tx     = 1;
    conf.enable_rx     = 1;
    conf.uart_id       = UART_ID;
    conf.use_ctrl_flow = CONFIG_EXAMPLE_UART_FC;
    conf.rts_pad       = PAD_UART0_RTS;
    conf.use_fast_clk  = 1;
    pi_open_from_conf(&uart, &conf);

    if (pi_uart_open(&uart))
    {
        printf("ERROR - Failed to open uart\n");
        return -1;
    }

    // Using UART
    for (uint8_t i = 0; i < BUFFER_SIZE; i++)
    {
        buffer[i] = i;
    }
    pi_uart_write(&uart, buffer, BUFFER_SIZE);
    /*
     * Here you should have received "buffer" data on your external UART
     * device.
     */
    memset(buffer, '\0', BUFFER_SIZE);

    // Going to light sleep
    if (light_sleep(&uart))
    {
        return -2;
    }

    /*
     * After light sleep we need to do two things:
     * - Setting pads back to their configuration
     * - Gettting UART device back
     */
    setup_pads();
    pi_uart_ioctl(&uart, PI_UART_IOCTL_DEVICE_GET, (void *) UART_ID);

    /*
     * Then we can continue our app
     */

    // Get data on UART
    pi_uart_read(&uart, buffer, BUFFER_SIZE-BYTES_LOST);
    printf("Received: %s\n", buffer);

    // END
    printf("END of the example\n");
    return 0;
}