This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

problem because of absence of interrupt for "uart tx data register ready"

#include "nrf_delay.h"
#include "nrf_gpio.h"

#define  SETB(x,y)   (x|=(1<<y))     //for o/p
#define  CLRB(x,y)   (x&=(~(1<<y)))  //for o/p
#define  TGLB(x,y)   (x^=(1<<y))     //for o/p
#define  CHECKB(x,y) (x&(1<<y))      //for i/p

#define SERIAL_FLOAT_PRECISION 4

#define SERIAL_BUFFER_SIZE 64


typedef struct
{
  unsigned char buffer[SERIAL_BUFFER_SIZE];
  volatile unsigned int head;
  volatile unsigned int tail;
}ring_buffer;



ring_buffer rx_buffer;
ring_buffer tx_buffer;

void UARTE0_UART0_IRQHandler(void)
{
    unsigned char tx,rx;
    unsigned int i;
    
    if(NRF_UART0->EVENTS_TXDRDY == 1)
    {
        NRF_UART0->EVENTS_TXDRDY=0; 
        
        if (tx_buffer.head == tx_buffer.tail)
        {
            SETB(NRF_UART0->INTENCLR,7);         
        }
        else
        {
            tx = tx_buffer.buffer[tx_buffer.tail];
            tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE;

            NRF_UART0->TXD = tx;
        }

    }

    if(NRF_UART0->EVENTS_RXDRDY == 1)
    {
        NRF_UART0->EVENTS_RXDRDY = 0; 
        
        i = (unsigned int)(rx_buffer.head + 1) % SERIAL_BUFFER_SIZE;

        if(CHECKB(NRF_UART0->ERRORSRC,1)==0)
        {
            rx = NRF_UART0->RXD;
            
            if (i != rx_buffer.tail)
            {
                    rx_buffer.buffer[rx_buffer.head] = rx;
                    rx_buffer.head = i;
            }
        }
        else
        {
            rx = NRF_UART0->RXD;
        }   
        
    }                                   
    
}


void uart_init()
{
   
    NRF_UART0->BAUDRATE = 0x01D7E000;
    //NRF_UART0->CONFIG = 0x00000001;

    NRF_UART0->PSELRTS = 5;
    NRF_UART0->PSELTXD = 6;
    NRF_UART0->PSELCTS = 7;
    NRF_UART0->PSELRXD = 8;
    
    nrf_gpio_cfg_output(6);
    nrf_gpio_cfg_input(8, GPIO_PIN_CNF_PULL_Disabled);

    nrf_gpio_cfg_output(5);
    nrf_gpio_cfg_input(7, GPIO_PIN_CNF_PULL_Disabled);

    
    NRF_UART0->TASKS_STARTTX = 1;
    NRF_UART0->TASKS_STARTRX = 1;
    
    NRF_UART0->ENABLE = 0x00000004;

    NRF_UART0->INTENSET=0x84;
    
    NVIC_EnableIRQ(UARTE0_UART0_IRQn);
}



int serial_available(void)
{
  return (unsigned int)(SERIAL_BUFFER_SIZE + rx_buffer.head - rx_buffer.tail) % SERIAL_BUFFER_SIZE;
}


unsigned char serial_read(void)
{
  unsigned char c;
  
  if (rx_buffer.head == rx_buffer.tail)
  {
    return -1;
  } 
  else 
  {
    c = rx_buffer.buffer[rx_buffer.tail];
    rx_buffer.tail = (unsigned int)(rx_buffer.tail + 1) % SERIAL_BUFFER_SIZE;
    return c;
  }
}


void serial_write(unsigned char c)
{
  int i = (tx_buffer.head + 1) % SERIAL_BUFFER_SIZE;
	
  while (i == tx_buffer.tail){    NRF_P0->OUT^=0x00020000;  }
	
  tx_buffer.buffer[tx_buffer.head] = c;
  tx_buffer.head = i;
	
  SETB(NRF_UART0->INTENSET,7); 
  NRF_UART0->EVENTS_TXDRDY = 0;      

}

void serial_write_string(char *pointer)
{
  while(*pointer!='\0')
  {
    serial_write(*pointer);
    pointer++;
  }
}

int main(void)
{
  NRF_P0->DIR |= 0x000E0000;
  NRF_P0->OUTSET |= 0x000E0000;
  
  uart_init();
  
  unsigned int i=0;

  while(1) 
  {
 
    NRF_P0->OUT^=0x00040000;
    
    //NRF_UART0->TXD = '$';  // after comment out this line, code works normally !!!!
    serial_write_string("Hello World i=");
    serial_no(i++);
    serial_write_string("\n\r");
    
    
    nrf_delay_ms(50);

  }
}

/NRF_UART0->TXD = '$'; // after comment out this line, code works normally !!!! When I comment out this line from main function only then code prints "Hello World" on serial terminal.

This is arduino logic. I think due to unavailability of interrupt for "uart tx data register ready" it is behaving like this. I have implement same logic on STM32F407 & there it works smoothly.

Parents
  • So from the UARTE Transmission chapter in the PS we have that:

    When all bytes in the TXD buffer, as specified in the TXD.MAXCNT register, have been transmitted, the UARTE transmission will end automatically and an ENDTX event will be generated.

    A UARTE transmission sequence is stopped by triggering the STOPTX task, a TXSTOPPED event will be generated when the UARTE transmitter has stopped.

    So if you look at how this is handled by the UART(E) driver in SDK, you can see that after we trigger the TASKS_STARTTX, we are checking and waiting for the either the ENDTX event or the TXSTOPPED to be triggered, before we continue. This is how we do it in the SDK, in the function nrf_drv_uart_tx_for_uarte():

    __STATIC_INLINE ret_code_t nrf_drv_uart_tx_for_uarte(const nrf_drv_uart_t * p_instance)
    {
        uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
        ret_code_t err_code = NRF_SUCCESS;
    
        nrf_uarte_event_clear(p_instance->reg.p_uarte, NRF_UARTE_EVENT_ENDTX);
        nrf_uarte_event_clear(p_instance->reg.p_uarte, NRF_UARTE_EVENT_TXSTOPPED);
        nrf_uarte_tx_buffer_set(p_instance->reg.p_uarte, p_cb->p_tx_buffer, p_cb->tx_buffer_length);
        nrf_uarte_task_trigger(p_instance->reg.p_uarte, NRF_UARTE_TASK_STARTTX);
    
        if (p_cb->handler == NULL)
        {
            bool endtx;
            bool txstopped;
            do
            {
                endtx     = nrf_uarte_event_check(p_instance->reg.p_uarte, NRF_UARTE_EVENT_ENDTX);
                txstopped = nrf_uarte_event_check(p_instance->reg.p_uarte, NRF_UARTE_EVENT_TXSTOPPED);
            }
            while ((!endtx) && (!txstopped));
    
            if (txstopped)
            {
                err_code = NRF_ERROR_FORBIDDEN;
            }
            p_cb->tx_buffer_length = 0;
        }
        return err_code;
    }
    
Reply
  • So from the UARTE Transmission chapter in the PS we have that:

    When all bytes in the TXD buffer, as specified in the TXD.MAXCNT register, have been transmitted, the UARTE transmission will end automatically and an ENDTX event will be generated.

    A UARTE transmission sequence is stopped by triggering the STOPTX task, a TXSTOPPED event will be generated when the UARTE transmitter has stopped.

    So if you look at how this is handled by the UART(E) driver in SDK, you can see that after we trigger the TASKS_STARTTX, we are checking and waiting for the either the ENDTX event or the TXSTOPPED to be triggered, before we continue. This is how we do it in the SDK, in the function nrf_drv_uart_tx_for_uarte():

    __STATIC_INLINE ret_code_t nrf_drv_uart_tx_for_uarte(const nrf_drv_uart_t * p_instance)
    {
        uart_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
        ret_code_t err_code = NRF_SUCCESS;
    
        nrf_uarte_event_clear(p_instance->reg.p_uarte, NRF_UARTE_EVENT_ENDTX);
        nrf_uarte_event_clear(p_instance->reg.p_uarte, NRF_UARTE_EVENT_TXSTOPPED);
        nrf_uarte_tx_buffer_set(p_instance->reg.p_uarte, p_cb->p_tx_buffer, p_cb->tx_buffer_length);
        nrf_uarte_task_trigger(p_instance->reg.p_uarte, NRF_UARTE_TASK_STARTTX);
    
        if (p_cb->handler == NULL)
        {
            bool endtx;
            bool txstopped;
            do
            {
                endtx     = nrf_uarte_event_check(p_instance->reg.p_uarte, NRF_UARTE_EVENT_ENDTX);
                txstopped = nrf_uarte_event_check(p_instance->reg.p_uarte, NRF_UARTE_EVENT_TXSTOPPED);
            }
            while ((!endtx) && (!txstopped));
    
            if (txstopped)
            {
                err_code = NRF_ERROR_FORBIDDEN;
            }
            p_cb->tx_buffer_length = 0;
        }
        return err_code;
    }
    
Children
No Data
Related