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
  • Hello,

    Please try to use the UARTperipheral instead (i.e. UARTE — Universal asynchronous receiver/transmitter with EasyDMA) and not UART — Universal asynchronous receiver/transmitter). The legacy UART will only trigger the RXDRDY event after the byte has been moved to the RXD register as noted here in the PS:

    The UART receiver chain implements a FIFO capable of storing six incoming RXD bytes before data is overwritten. Bytes are extracted from this FIFO by reading the RXD register. When a byte is extracted from the FIFO a new byte pending in the FIFO will be moved to the RXD register. The UART will generate an RXDRDY event every time a new byte is moved to the RXD register. (Reception)

  • Hello,

    I studied UART, UARTE's difference. UARTE is added EasyDMA to UART.

    However, I use UART peripheral IRQ, with Timer PPI. Can I use UARTE peripheral IRQ not DMA?

  • 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)
        {}
    }

Related