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

nRF51822 PCA10001 uart RX interrupt does not trigger

Hello,

I am trying to get the RX interrupt to trigger on the PCA10001 board using the segger debugger as my serial terminal.

My hardware setup consists of a PCA10001 connected to a windows PC and using teraterm pro as my serial terminal program. The program running on the PCA10001 is a BT-LE application implementing a custom profile using the nordic S110 6.0.0 alpha stack.

I have been looking into this problem for a while and after looking at a few demonstration applications, especially the BLE nus example. I am trying to get the same functionality.

Uart transmit works, I can see data from printf's from within the program but characters sent to the device do not arrive.

Here is my current initialization code:

pca10001.h


#define RX_PIN_NUMBER  11
#define TX_PIN_NUMBER  9
#define CTS_PIN_NUMBER 10
#define RTS_PIN_NUMBER 8
#define HWFC           true

main.c


int main(void)
{
	retarget_init();
        ...

retarget.c


void UART0_IRQHandler(void)
{ 

  uart_buffer[uart_buf_head] = simple_uart_get();
	uart_buf_head++;
	if(uart_buf_head > UART_BUF_SIZE)
		uart_buf_head = 0;
		
}

void retarget_init(void)
{
	uart_buf_head = 0;
	uart_buf_tail = 0;

  simple_uart_config(RTS_PIN_NUMBER, TX_PIN_NUMBER, CTS_PIN_NUMBER, RX_PIN_NUMBER, HWFC);
	
	NRF_UART0->INTENSET = UART_INTENSET_RXDRDY_Enabled << UART_INTENSET_RXDRDY_Pos;
	sd_nvic_SetPriority(UART0_IRQn, APP_IRQ_PRIORITY_LOW);
	sd_nvic_EnableIRQ(UART0_IRQn);
}

simple_uart.c


uint8_t simple_uart_get(void)
{
  while (NRF_UART0->EVENTS_RXDRDY != 1)
  {
    // Wait for RXD data to be received
  }
  
  NRF_UART0->EVENTS_RXDRDY = 0;
  return (uint8_t)NRF_UART0->RXD;
}

void simple_uart_config(  uint8_t rts_pin_number,
                          uint8_t txd_pin_number,
                          uint8_t cts_pin_number,
                          uint8_t rxd_pin_number,
                          bool hwfc)
{
  nrf_gpio_cfg_output(txd_pin_number);
  nrf_gpio_cfg_input(rxd_pin_number, NRF_GPIO_PIN_NOPULL);  

  NRF_UART0->PSELTXD = txd_pin_number;
  NRF_UART0->PSELRXD = rxd_pin_number;

  if (hwfc)
  {
    nrf_gpio_cfg_output(rts_pin_number);
    nrf_gpio_cfg_input(cts_pin_number, NRF_GPIO_PIN_NOPULL);
    NRF_UART0->PSELCTS = cts_pin_number;
    NRF_UART0->PSELRTS = rts_pin_number;
    NRF_UART0->CONFIG  = (UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos);
  }

  NRF_UART0->BAUDRATE         = (UART_BAUDRATE_BAUDRATE_Baud115200 << UART_BAUDRATE_BAUDRATE_Pos);
  NRF_UART0->ENABLE           = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos);
  NRF_UART0->TASKS_STARTTX    = 1;
  NRF_UART0->TASKS_STARTRX    = 1;
  NRF_UART0->EVENTS_RXDRDY    = 0;
}

The interrupt routine UART0_IRQHandler does not trigger in the debugger, nor do I see the counters for the circular buffer increment in debug prints.

Can you at first glance see anything that is not correctly setup? Next step is to haul in the oscilloscope to see if the segger can send some characters to the nRF51822.

Thank you in advance for any answers/comments.

Parents
  • After verifying that the characters are really sent by the segger uart chip. I was a bit stumped so I went back to the btle app uart example provided on devzone. After a command by command example I noticed that the only difference was the interrupt initialization:

    Old:

    
    	sd_nvic_SetPriority(UART0_IRQn, APP_IRQ_PRIORITY_LOW);
    	sd_nvic_EnableIRQ(UART0_IRQn);
    
    

    New:

    
    	NVIC_SetPriority(UART0_IRQn, APP_IRQ_PRIORITY_LOW);
            NVIC_EnableIRQ(UART0_IRQn);
    
    

    Changing this did the trick!

    I always assumed that touching peripherals that the softdevice stack uses needed to be done via the sd_$peripheral functions to prevent conflicts. In the btle app uart example this is done. Is my assumption incorrect? Or does this only hold for interrupts used by the softdevice (that you are not supposed to touch)? Any idea what I did wrong?

Reply
  • After verifying that the characters are really sent by the segger uart chip. I was a bit stumped so I went back to the btle app uart example provided on devzone. After a command by command example I noticed that the only difference was the interrupt initialization:

    Old:

    
    	sd_nvic_SetPriority(UART0_IRQn, APP_IRQ_PRIORITY_LOW);
    	sd_nvic_EnableIRQ(UART0_IRQn);
    
    

    New:

    
    	NVIC_SetPriority(UART0_IRQn, APP_IRQ_PRIORITY_LOW);
            NVIC_EnableIRQ(UART0_IRQn);
    
    

    Changing this did the trick!

    I always assumed that touching peripherals that the softdevice stack uses needed to be done via the sd_$peripheral functions to prevent conflicts. In the btle app uart example this is done. Is my assumption incorrect? Or does this only hold for interrupts used by the softdevice (that you are not supposed to touch)? Any idea what I did wrong?

Children
  • Great that you found the solution on your own! You may have use in reading this for information on the differences between sd_nvic_* and NVIC_: https://devzone.nordicsemi.com/index.php/use-app_gpiote-with-softdevice Note especially that the sd_nvic_ API is only available when the softdevice is enabled.

    In general, you should also always make sure to check error codes on your softdevice call, in which case I guess you would have gotten back NRF_ERROR_SOFTDEVICE_NOT_ENABLED with your original code. :)

  • @Ole Morten

    You are right, these calls where made before enabling the softdevice. Typical case of "user has not read spec" error ;-). Good thing that the softdevice preserves setup NVIC and ISR when being enabled.

    Will be adding the checks from now on with all softdevice functions.

    Thanks!

  • Thank you very much for this post, bart.
    It helped me to resolve issue while receiving data in non-blocking mode.
    In my case, I want to transmit the same data received from UART (ending with '\n' or '\r').
    But some how, my code transmits only 1st byte from the butter and it doesn't generate EVENTS_TXDRDY event.
    Can you help to solve it?

    Other configurations are same except the Flow control. I am not using it.

    UART0_IRQHandler(), simple_uart_put() and simple_uart_get() are as below:

    uint8_t simple_uart_get(void)
    {
        /*
          while (NRF_UART0->EVENTS_RXDRDY != 1)
          {
            // Wait for RXD data to be received
          }
        */
      NRF_UART0->EVENTS_RXDRDY = 0;
      return (uint8_t)NRF_UART0->RXD;
    }
    
    void simple_uart_put(uint8_t data)
    {
        /*
          while (NRF_UART0->EVENTS_TXDRDY != 1)
          {
            // Wait for TXD data to be transmitted
          }
        */  
      NRF_UART0->EVENTS_TXDRDY = 0;
      NRF_UART0->TXD = data;
    }
    
    void UART0_IRQHandler(void)
    { 
    
    	if(NRF_UART0->EVENTS_RXDRDY == 1){
    		uart_buffer[uart_buf_head] = simple_uart_get();
    		uart_buf_head++;
    		if(uart_buffer[uart_buf_head-1] == '\r' || uart_buffer[uart_buf_head-1] == '\n'){
    			NRF_UART0->TASKS_STOPRX = 1;
    			NRF_UART0->TASKS_STARTTX = 1;
    			simple_uart_put(uart_buffer[uart_buf_tail]);
    			uart_buf_tail++;
    		}
    		if(uart_buf_head > UART_BUF_SIZE)
    			uart_buf_head = 0;
    	}
    	
    	if(NRF_UART0->EVENTS_TXDRDY == 1){
    		simple_uart_put(uart_buffer[uart_buf_tail]);
    		uart_buf_tail++;
    		if((uart_buf_tail > UART_BUF_SIZE) || (uart_buf_tail > uart_buf_head)){
    			NRF_UART0->TASKS_STOPTX = 0;
    			uart_buf_head = uart_buf_tail = 0;
    			NRF_UART0->TASKS_STARTRX = 1;
    		}
    	}
    }

Related