Understand UART, UARTE and getting it to work with PPI

Hi all,

Using UART is confusing for me because I see various implementations in the documentation. There is a Serial library, then there is the UART driver and HAL. The HAL is further divided to UART and UARTE. I read that the difference between UART and UARTE is that the UARTE uses EasyDMA.

I like to try a few things:

1. Use PPI to setup a timer event to trigger a UART TX task. Eg. Send out "Hello" every 1 second.

2. Use PPI to setup a timer event to trigger a UART RX task. Eg. Read from UART every 1 second.

For (1), I have setup the ppi channel as follows:

err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1, nrf_drv_timer_event_address_get(&m_timer1, NRF_TIMER_EVENT_COMPARE0), nrf_drv_uart_task_address_get(&uart_driver_instance, NRF_UART_TASK_STARTTX));

 

In this case, should I be using nrf_uart_task_address_get or nrf_uarte_task_address_get or nrf_drv_uart_task_address_get?

I also noticed that there is a NRF_UART_TASK_STOPTX. Does it mean that I also need to have an event to trigger a stop task? Otherwise, it will never stop transmitting?

How does the UART tx happen? Should I be placing the string in some register or ram address so that when the task is triggered, the string is automatically send from the tx pin? If I am using UARTE, I presume i should initalise the tx buffer with this function nrf_uarte_tx_buffer_set.?

For(2), the ppi channel is setup as follows:

err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1, nrf_drv_timer_event_address_get(&m_timer1, NRF_TIMER_EVENT_COMPARE0), nrf_drv_uart_task_address_get(&uart_driver_instance, NRF_UART_TASK_STARTRX));

Similarly, how does the RX happen? What do I need to configure for the RX data to be stored to memory? How can I access it later when I wake up the CPU? Do I also need another event to stop the RX task?

This is the code that I have now.

#include <stdint.h>

#include "nrf_delay.h"
#include "app_error.h"

#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "nrf_drv_uart.h"


#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#define UART0_USE_EASY_DMA        true
#define UART_EASY_DMA_SUPPORT     1
//#define UART_LEGACY_SUPPORT       1

#define PPI_EXAMPLE_TIMER1_INTERVAL             (1000)  // Timer interval in milliseconds

static const nrf_drv_uart_t uart_driver_instance = NRF_DRV_UART_INSTANCE(UART0_INSTANCE_INDEX);
static const nrf_drv_timer_t m_timer1 = NRF_DRV_TIMER_INSTANCE(1);
static nrf_ppi_channel_t m_ppi_channel1;

static volatile uint32_t m_counter;

/* Timer event handler. Not used since Timer1 is used only for PPI. */
static void empty_timer_handler(nrf_timer_event_t event_type, void * p_context)
{
}

/** @brief Function for initializing the UART peripheral.
*/
static void uart_init(void)
{
    uint32_t err_code = NRF_SUCCESS;
	
		nrf_drv_uart_config_t config = NRF_DRV_UART_DEFAULT_CONFIG;
		config.use_easy_dma = true;
		
		err_code = nrf_drv_uart_init(&uart_driver_instance, &config, NULL);
		APP_ERROR_CHECK(err_code);
	
}
	
/** @brief Function for initializing the PPI peripheral.
*/
static void ppi_init(void)
{
    uint32_t err_code = NRF_SUCCESS;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    /* Configure 1st available PPI channel to start UART RX event on TIMER1 COMPARE[0] match,
     * which is every even number of seconds.
     */
    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel1);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1,
                                          nrf_drv_timer_event_address_get(&m_timer1,
                                                                          NRF_TIMER_EVENT_COMPARE0),
                                          nrf_drv_uart_task_address_get(&uart_driver_instance,
                                                                         NRF_UART_TASK_STARTTX));
    APP_ERROR_CHECK(err_code);

    // Enable both configured PPI channels
    err_code = nrf_drv_ppi_channel_enable(m_ppi_channel1);
    APP_ERROR_CHECK(err_code);
}


/** @brief Function for Timer 1 initialization.
 *  @details Initializes TIMER1 peripheral to generate an event every 1 seconds. The events 
 *           are used to start UART TX or RX via PPI: TIMER1->EVENT_COMPARE[0] triggers UART->TASK_STARTTX/TASK_STARTRX.
 */
static void timer1_init(void)
{
    // Check TIMER1 configuration for details.
    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.frequency = NRF_TIMER_FREQ_31250Hz;
    ret_code_t err_code = nrf_drv_timer_init(&m_timer1, &timer_cfg, empty_timer_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_timer_extended_compare(&m_timer1,
                                   NRF_TIMER_CC_CHANNEL0,
                                   nrf_drv_timer_ms_to_ticks(&m_timer1,
                                                             PPI_EXAMPLE_TIMER1_INTERVAL),
                                   NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                   false);
}


/**
 * @brief Function for application main entry.
 */
int main(void)
{
    uint32_t old_val = 0;
    uint32_t err_code;

    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();

		uart_init();
    ppi_init();
    timer1_init(); // Timer to generate events

    nrf_drv_timer_enable(&m_timer1);

    while (true)
    {
			
    }
}

Thanks in advance!