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
Solved! Go to Solution.
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
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
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
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
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