How can I implement UART RX PPI with GPIO?

Hi, I use nRF52840, with SDK 15.3.0

I would like to toggle LED every time receive 1 byte to UART.

So I wrote down the code.

static void ppi_init()
{
uint32_t err_code;

uint32_t uart_event_addr;
uint32_t gpio_task_addr;

nrf_ppi_channel_t ppi_channel_uart_gpio_toggle;

err_code = nrf_drv_ppi_init();
if((err_code != 0) && (err_code != NRF_ERROR_MODULE_ALREADY_INITIALIZED))
{
APP_ERROR_CHECK(err_code);
}

nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);

err_code = nrf_drv_gpiote_out_init(LED_pin, &config);
APP_ERROR_CHECK(err_code);

err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_uart_gpio_toggle);
APP_ERROR_CHECK(err_code);

uart_event_addr = nrfx_uart_event_address_get(&uart1_inst, NRF_UART_TASK_STARTRX);
gpio_task_addr = nrfx_gpiote_out_task_addr_get(LED_pin);

err_code = nrfx_ppi_channel_assign(ppi_channel_uart_gpio_toggle, uart_event_addr, gpio_task_addr);
APP_ERROR_CHECK(err_code);

err_code = nrf_drv_ppi_channel_enable(ppi_channel_uart_gpio_toggle);
APP_ERROR_CHECK(err_code);

nrf_drv_gpiote_out_task_enable(LED_pin);

}

Thanks in advance!

Parents Reply Children
  • DMA is mandatory with UARTE, but that does not mean you will not get an interrupt. You can set the DMA receive buffer to '1' byte if you want the uarte driver callback to be called for every received byte.

  • Hello,

    Would you mind sharing the rest of the UART related code? I am not sure I understand exactly how you have configured it now, or why you only get the first RX byte event.

  • Hello,

    Here the related UART code initial part, IRQ handler, main

    void UART_dataHandler(void)
    {
        static uint8_t databuff;
        printf("%x\r\n", databuff);
    }
    
    void UART_idleHandler(void)
    {
    }
    /*    UART ISR    */
    void UART_IRQ_handler(const nrfx_uart_event_t * p_event, void * p_context)
    {
        switch(p_event -> type)
        {
            case NRFX_UART_EVT_RX_DONE:
                UART_dataHandler();
                break;
            case NRFX_UART_EVT_TX_DONE:
                break;
            case NRFX_UART_EVT_ERROR:
                NRF_LOG_INFO("INVALID_IRQ\r\n");
                UART_idleHandler();
                break;
        }
    }
    
    void uart1_init(void)
    {
        uint32_t err_code;
    
        nrfx_uart_config_t uart1_config = {TX_PIN,
                                           RX_PIN,
                                           CTS_PIN,
                                           RTS_PIN,
                                           NULL,
                                           NRF_UART_HWFC_DISABLED,
                                           NRF_UART_PARITY_EXCLUDED,
                                           UART_BR_115200,
                                           6};
    
        nrfx_uart_init(&uart1_inst, &uart1_config, UART_IRQ_handler);
        nrf_uart_int_enable(NRF_UART0, NRF_UART_INT_MASK_ERROR | NRF_UART_INT_MASK_RXDRDY);
        nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_ERROR | NRF_UART_EVENT_RXDRDY);
        //nrf_uart_task_trigger(NRF_UART0, NRF_UART_TASK_STARTRX);
    }
    
    static void ppi_init()
    {
            uint32_t err_code;
    
            uint32_t uart_event_addr;
            uint32_t gpio_task_addr;
            
            nrf_ppi_channel_t ppi_channel_uart_gpio_toggle;
    
            err_code = nrf_drv_ppi_init();
            if((err_code != 0) && (err_code != NRF_ERROR_MODULE_ALREADY_INITIALIZED))
            {
                APP_ERROR_CHECK(err_code);
            }
    
            nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);
    
            err_code = nrfx_gpiote_out_init(LED_1, &config);
            APP_ERROR_CHECK(err_code);
    
            err_code = nrfx_ppi_channel_alloc(&ppi_channel_uart_gpio_toggle);
            APP_ERROR_CHECK(err_code);
    
            uart_event_addr = nrfx_uart_event_address_get(&uart1_inst, NRF_UART_EVENT_RXDRDY);
            gpio_task_addr = nrfx_gpiote_out_task_addr_get(LED_1);
            
            err_code = nrfx_ppi_channel_assign(ppi_channel_uart_gpio_toggle, uart_event_addr, gpio_task_addr);
            APP_ERROR_CHECK(err_code);
    
            err_code = nrfx_ppi_channel_enable(ppi_channel_uart_gpio_toggle);
            APP_ERROR_CHECK(err_code);
    
            nrfx_gpiote_out_task_enable(LED_1);
    }
    
    int main(void)
    {
        uart1_init();
        
        ppi_init();
        nrfx_uart_rx_enable(&uart1_inst);
        
        while(1)
        {}
    }

  • Hello,

    I see the problem now. To enable reception you have to provide the driver with a application buffer to hold store the received bytes. You also have to repeat this after receiving the NRFX_UART_EVT_RX_DONE event.

    Like this:

    static uint8_t m_rx_buffer[1];
    
    void UART_dataHandler(void)
    {
        ...
        nrfx_uart_rx(&uart1_inst, m_rx_buffer, sizeof(m_rx_buffer));
    }
    
    int main(void)
    {
        uart1_init();
        
        ppi_init();
        nrfx_uart_rx(&uart1_inst, m_rx_buffer, sizeof(m_rx_buffer));
        
        while(1)
        {}
    }

    You may also refer to the app_uart library implementation used by ble_app_uart to see how the driver APIs are used there.

Related