CW MobileGT - Blocking Serial Read() Call Doesn't Cause Task To Block?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

CW MobileGT - Blocking Serial Read() Call Doesn't Cause Task To Block?

Jump to solution
1,129 Views
Tim562
Senior Contributor I

Hi All, I have a task created to receive data on a serial port that calls read() in an endless loop and stores any received data in a buffer for later processing. The problem is, even though the read() call is blocking, when it blocks while waiting for data, the task that called it doesn't block and return me to the main task.

 

 

Here's the task list template with the two tasks defined

TASK_TEMPLATE_STRUCT MQX_template_list[] = {   /* Task number, Entry point, Stack, Pri, String,    Auto? */  {MAIN_TASK,     Main_task,   3000,  10,  "main",    MQX_AUTO_START_TASK},  {SERIALRX_TASK, MAIN_SerialRxTask, 3000, 9, "serx", 0},  {            0,         0,      0,   0,          0,0}};

 

Here, the main task creates a task to receive serial data (then goes on to waste time in a loop)

void Main_task(uint_32 initial_data)    {    _task_id tiNewTaskID;    uint_32 iWasteTime;    tiNewTaskID = _task_create(0, SERIALRX_TASK, 0);    if(tiNewTaskID == MQX_NULL_TASK_ID)        _time_delay(1);    iWasteTime = 0;    while(1)        {        iWasteTime++;        if(iWasteTime >= 100)            iWasteTime = 0;        }    _mqx_exit(0);    }

 

  

The serialRx task runs, and read() blocks until data is received but MQX doesn't ever return back to the main task (main and this task are the only 2 tasks). I've done a similar thing with RTCS with blocking calls in a task to read IP data and when the recv() function is blocked waiting for data, MQX blocks the task to let other tasks run, any idea why not here? I've tried various priority levels for the two tasks (doesn't seem to make a difference).

void MAIN_SerialRxTask(uint_32 initial_data)    {    int_32 iCount;    uint_32 baud=57600;    unsigned char data_buffer[2048];    FILE_PTR serial_fd =  fopen("ttyj:", IO_SERIAL_RAW_IO);    ioctl(serial_fd, IO_IOCTL_SERIAL_SET_BAUD, &baud);    while(1)        {        //Function blocks but doesn't cause MQX to return to main task        iCount = read(serial_fd, data_buffer, 1);        if(iCount == IO_ERROR)    //Error check            break;        //Write the recvd data back out the same port        write(serial_fd, data_buffer, iCount);           }    fclose(serial_fd);    return;    }

 

 

I had thought that when a task called a blocking function (and that function blocked) that the task would block until the function was ready to go again. Do I have that wrong? Is there something specific about the read() function that won't let the task block? Perhaps there's a better way of setting up a task to receive incoming serial data that will be processed in another task? The serial port is operating in polled (verses interrupt) mode and it works properly, I just can't figure out why the task doesn't block when the read() function does.

 

The code is running on MQX 3.7 and the Tower MPC5125 board also using the Tower Serial Module. Thanks in advance for any suggestions or advice.

 

~Tim

 

 

 

 

 

 

 

 

 

 

 

0 Kudos
1 Solution
543 Views
MarkP_
Contributor V

Hi Tim,

Been working with uarts in my project, noticed that the polled mode receive simply polls the uart in loop.

This method is unusable, blocks lower priority tasks from running.

 

char _kuart_polled_getc

   /* Wait while buffer is empty */
   while (!(sci_ptr->S1 & UART_S1_RDRF_MASK)) {
      /* Wait while buffer is empty */
   } /* Endwhile */
   io_info_ptr->RX_CHARS++;


Better to use interrupt method.

_mqx_int _io_serial_int_read:

      if(flags & IO_SERIAL_NON_BLOCKING) {
          if (_CHARQ_SIZE(in_queue) == 0) {
              num -= i;
              _int_enable();
              break;
          } /* Endif */
      } else {
          while (_CHARQ_SIZE(in_queue) == 0) {
             _taskq_suspend(int_io_dev_ptr->IN_WAITING_TASKS);
          } /* Endwhile */ 
      } /* Endif */

I've been using uart in nonblocking mode:

FILE_PTR serial_fd =  fopen("ittyj:",(char _PTR_)(IO_SERIAL_RAW_IO|IO_SERIAL_NON_BLOCKING);

~Mark

View solution in original post

0 Kudos
4 Replies
544 Views
MarkP_
Contributor V

Hi Tim,

Been working with uarts in my project, noticed that the polled mode receive simply polls the uart in loop.

This method is unusable, blocks lower priority tasks from running.

 

char _kuart_polled_getc

   /* Wait while buffer is empty */
   while (!(sci_ptr->S1 & UART_S1_RDRF_MASK)) {
      /* Wait while buffer is empty */
   } /* Endwhile */
   io_info_ptr->RX_CHARS++;


Better to use interrupt method.

_mqx_int _io_serial_int_read:

      if(flags & IO_SERIAL_NON_BLOCKING) {
          if (_CHARQ_SIZE(in_queue) == 0) {
              num -= i;
              _int_enable();
              break;
          } /* Endif */
      } else {
          while (_CHARQ_SIZE(in_queue) == 0) {
             _taskq_suspend(int_io_dev_ptr->IN_WAITING_TASKS);
          } /* Endwhile */ 
      } /* Endif */

I've been using uart in nonblocking mode:

FILE_PTR serial_fd =  fopen("ittyj:",(char _PTR_)(IO_SERIAL_RAW_IO|IO_SERIAL_NON_BLOCKING);

~Mark

0 Kudos
543 Views
Tim562
Senior Contributor I

Hi Mark,

 

    Thanks for your reply. I tried opening the serial device in interrupt mode as you suggested and now, when the call to read() blocks while waiting for data, the task I created to service the serial port blocks as well so other tasks can run! Thanks for your advice, I appreciate it. Have a great day.

 

Best Regards,

Tim

0 Kudos
543 Views
MarkP_
Contributor V

Hi Tim,

one more thing, if you are using the same port as default serial port you need to add to user_config.h:

#define BSP_DEFAULT_IO_OPEN_MODE ((pointer)(IO_SERIAL_RAW_IO|IO_SERIAL_NON_BLOCKING))

 

This overrides the default open-mode defined twrk60n512.h:

#ifndef BSP_DEFAULT_IO_OPEN_MODE
    #define BSP_DEFAULT_IO_OPEN_MODE  (pointer) (IO_SERIAL_XON_XOFF | IO_SERIAL_TRANSLATION | IO_SERIAL_ECHO)
#endif

Default port definition also in this file:

#define BSP_DEFAULT_IO_CHANNEL "ittyf:"    /* OSJTAG-COM   polled mode   */


You can use printf directly to this default channel for debug etc. printouts.

~Mark

0 Kudos
543 Views
Tim562
Senior Contributor I

Thanks Mark, that's helpful. Been an embedded developer for almost 20 years but new to RTOS/MQX so figuring out how to do things within the framework of the OS can be a bit of a challenge. I see you've replied to my other question about how to set up a task (or tasks) to transmit as well as receive. Don't quite understand your answer yet but I'm working on it. Thanks again.

 

~Tim

0 Kudos