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
  • This time, just once toggle as UART event done.

    How can I toggle LED at every UART RX event use the ppi?

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

  • 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.

Reply
  • 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.

Children
No Data
Related