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

UART and FreeRTOS

I have used the UART example up and got it working. So i can send and receive data using it.

However i wanted to modify it so as to run with the current RTOS environment. So i generated a task:

static void tb_uart_task(void* p_params)
{
    uint8_t cr;
    tb_uart_evt_t event = TB_UART_EVT_INVALID;

    while(1)
    {
        //wait forever for an event
        if(xQueueReceive(m_tb_uart_evt_queue, &event, portMAX_DELAY))
        {
            //NRF_LOG_DEBUG("tb_uart_evt: %d\n", event);
            handle_uart_evt(event);
        }
    }
}

static void init_queues(void)
{
    m_tb_uart_evt_queue = xQueueCreate(TB_UART_EVT_QUEUE_LENGTH, sizeof(tb_uart_evt_t));
    if(m_tb_uart_evt_queue==NULL)
    {
        APP_ERROR_CHECK(NRF_ERROR_NO_MEM);
    }
}

void tb_uart_send_event(tb_uart_evt_t evt)
{
    //queue the event
    if(xQueueSendToBack(m_tb_uart_evt_queue,&evt,UART_QUEUE_WAIT_TICKS) == pdFAIL)
    {
        APP_ERROR_CHECK(NRF_ERROR_NO_MEM);
    }
}

static void handle_uart_evt(tb_uart_evt_t evt){

    switch(evt)
    {
        case TB_UART_BYTE_REC:
            uart_putstring("Received\r");
            break;

        case TB_UART_EVT_INVALID:
            break;
        default:
            break;
    }
}

In the task section if i invoke a tb_uart_send_event(TB_UART_BYTE_REC) with a push button input, the system will output "Received" as expected, so the task works. However, i cannot get it to retrieve data from the UART no matter what i attempt to do through the task system. The only way i can get the UART to read upon receiving is to modify the tb_uart_task method. 

static void tb_uart_task(void* p_params)
{
    uint8_t cr;
    tb_uart_evt_t event = TB_UART_EVT_INVALID;

    while(1)
    {
        //wait forever for an event
        while(app_uart_get(&cr) != NRF_SUCCESS);
        while(app_uart_put(cr) != NRF_SUCCESS);

    }
}

ultimately what i would like to be able to do is this:

oid uart_init(void){
    
    uint32_t err_code;
    
    nrf_gpio_cfg_input(RX_PIN, NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_output(TX_PIN);

    uart_received = false;

    APP_UART_FIFO_INIT(&comm_params, 
                        RX_BUF_SIZE,
                        TX_BUF_SIZE,
                        uart_evt_callback,
                        UART_IRQ_PRIORITY,
                        err_code);

}

void uart_evt_callback(app_uart_evt_t * uart_evt)
{   

    switch (uart_evt->evt_type)
    {
        uint8_t cr;

        case APP_UART_DATA: 
            //Data is ready on the UART
            break;
                        
        case APP_UART_DATA_READY:
            //Data is ready on the UART FIFO   
            tb_uart_send_event(TB_UART_BYTE_REC);

            break;
                        
        case APP_UART_TX_EMPTY:
            //Data has been successfully transmitted on the UART
            
            break;
                        
        default:
            break;
    }  
}
static void handle_uart_evt(tb_uart_evt_t evt){
    uint8_t cr;
    uint32_t err_code;
    uint8_t str[50];

    str[0] = '\0';

    switch(evt)
    {
        case TB_UART_BYTE_REC:

            uart_getstring(str, 50);
            uart_putstring(str);
            break;

        case TB_UART_EVT_INVALID:
            break;
        default:
            break;
    }
}

void uart_getstring(char* c, int size){
    int i;
    uint32_t err_code;

    for(i = 0; i < size - 1; i++){
        err_code = app_uart_get(&c[i]);
        if(err_code == NRF_ERROR_NOT_FOUND) break;
        nrf_delay_us(1250);
    }
    c[i] = (char)0;
}

However, when i try and get the UART to receive data from within a task scenario like that it not only fails to receive the byte but seems to freeze the system. Is there something that is special about how tasks operate and the way UART is operate that makes them incompatible in the way i want to use them?

More testing: I tried to go back to test just the callback function. so i modified the following:

int main(void)
{
    uart_init();

    while (true)
    {
        
    }
    
    if(pdPASS != xTaskCreate(tb_uart_task_init,   // Function that implements the task
            "UART_INIT",                         // Text name (for debug only)
            TASK_STACK_SIZE_LARGE,              // Stack size
            NULL,                               // Parameter (not used...)
            3,                                  // Task priority (highestintern_softdevice_events_execute)
            &m_tb_uart_task))                  // Handle
    {
        APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
    }

    /* Activate deep sleep mode */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

    

    /* Start FreeRTOS scheduler */
    vTaskStartScheduler();

    /* should never get here, task scheduler takes over */
    while (true)
    {
        APP_ERROR_HANDLER(NRF_ERROR_FORBIDDEN);
    }
}

static void uart_evt_callback(app_uart_evt_t * uart_evt)
{   
    uint8_t cr;

    switch (uart_evt->evt_type)
    {
        case APP_UART_DATA: 
            //Data is ready on the UART
            break;
                        
        case APP_UART_DATA_READY:
            //Data is ready on the UART FIFO   
            while(app_uart_get(&cr) != NRF_SUCCESS);
            while(app_uart_put(cr) != NRF_SUCCESS);
            break;
                        
        case APP_UART_TX_EMPTY:
            //Data has been successfully transmitted on the UART
            
            break;
                        
        default:
            break;
    }  
}

Just trying to use the callback function does not work. I did move the code to case APP_UART_DATA section and it works once or twice to print the incoming data but ultimately locks up.

My test rig is just sending "T\r" every 5 second from an arduino, and it then outputs to the arduino so i can read the data.

SDK: 12.2

Parents
  • I believe that something is not correctly configured with your uart. If you configured to use FIFO then you will get AA_UART_DATA and not APP_UART_DATA_READY. The driver itself is working in interrupt driven mode, so that should be OK, any data received should have called 

    uart_evt_callback-> tb_uart_send_event(you need to put this all in APP_UART_DATA case and not in APP_UART_DATA_READY if you use fifo) ->xQueueSendToBack-> handle_uart_evt

    I do not see any other complications in this path

Reply
  • I believe that something is not correctly configured with your uart. If you configured to use FIFO then you will get AA_UART_DATA and not APP_UART_DATA_READY. The driver itself is working in interrupt driven mode, so that should be OK, any data received should have called 

    uart_evt_callback-> tb_uart_send_event(you need to put this all in APP_UART_DATA case and not in APP_UART_DATA_READY if you use fifo) ->xQueueSendToBack-> handle_uart_evt

    I do not see any other complications in this path

Children
  • Just to give a heads up it may seem like i do not know what is happening because i am working on someone elses code and there is no reference and i have never used freeRTOS or nRF52 before. So if there is something that you may think is trivial it may not be for me. I can upload files to you. but prefer a more direct method or secure method than posting all over the internet

    I stripped my program down to the bare bones UART only task and got it working. I put all the same code back in and it still worked. so i am kinda of ok but i got another issue

    After 1 minute, the system no longer responds. I saw another post that exhibited same issue was wondering if you knew why this was happening for him and may lead me to know why it is happening to me

    Older Post no resolution

    if I do the only UART task it seems to last longer than 1 minute. but with the BLE enabled it dies after 1 minute. I am trying to search through all the code to determine if there is some BLE timeout since that is what i gather from the older post i linked to. 

    Also they used SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk, however i am having difficulty finding exactly what that is doing or how it works

    Edit: Reviewed the code and it appears i may have same issue as older post. The system boots up and after allotted time, 1 minute, it calls sd_power_system_off(). This causes whole system to go into a stop mode until we hit a button to wake it up.

    Is there a better way to handle a sleep mode where i can wake it up with the UART? 

    Is there a way other than using an input with nrf_gpio_cfg_sense_input() to wake up the system? The system is able to receive a BLE incoming message during this sleep mode and before putting it to sleep they call sd_ble_gap_disconnect(). I am assuming in the code somewhere they have to wake or do something to be able to reconnect with the device before the device sends a message, otherwise it would never get the message. I am looking for this wakeup on BLE action

  • Hi dmleone,

    I think first you should hold on your code and try to understand its internals. I think what you are facing is the problem understanding the code structure and since you are new to FreeRTOS, you have problems understanding the statemachine of your application.

     

    dmleone said:
    Also they used SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk, however i am having difficulty finding exactly what that is doing or how it works

     This is ARM Cortex M4 system control block feature of deep sleep. 

     

    dmleone said:
    Is there a better way to handle a sleep mode where i can wake it up with the UART? 

    If the choice of your system was to make the nRF chip to go to systemoff (not the same as ARM cortext sleep mode), then you need a mechanism to wake it up and waking from GPIO pins sounds reasonable. But if you do not want to go to deepsleep (System off) then using WFE will wake the system on any internal events. 

    I would not be able to suggest you which mode to use, as it entirely depends on your product requirements.

     

    dmleone said:
    Is there a way other than using an input with nrf_gpio_cfg_sense_input() to wake up the system? The system is able to receive a BLE incoming message during this sleep mode and before putting it to sleep they call sd_ble_gap_disconnect(). I am assuming in the code somewhere they have to wake or do something to be able to reconnect with the device before the device sends a message, otherwise it would never get the message. I am looking for this wakeup on BLE action

     When the system wakes up from systemoff (deep sleep) there will be a system reset and if your application is not checking for the reset reason, then the statemachine would always have the same path on the wakeup. This means that your device will again try to attempt to connect as it did before going to sleep.

Related