hello
I was studying the possibility of receiving data from the UART port.
Now I was asking a question:
MQX seen that there are tasks, so you can run a loop in each task to wait for receivingdata, you must use an interrupt for the UART?
Maurizio Felicioni
Solved! Go to Solution.
Hi Maurizio,
I don't think the issue is to have the UART in POLLED or INTERRUPT mode but more of a system architecture conversation of how you want the two task to access the recieved data.
In general only on task will be able to receive the UART data. Your code needs to either use a synchronization method (semaphore or mutex or glabal variable) or possible one task that will recieve the UART data and then determine who it is for and send that data to a task using message or global variable.
To see how a semaphore can be used for synchronization look at the mqx/examples/hello2 project. It is outputing data to UART and not receiving but the concept is what I want you to see.
There is a lightweight message queue example that might be helpful too in mqx/examples/lwmsgq .
Hope this helps.
Regards,
David
Subtle...I missed that, assuming that it would only hit the num-=i on the first time through
Suppose I'd better go back and put a "blush" smiley on the last post.
Thanks
Just for completeness, here is the eventual triple-buffered rs-232 task.
Seems to work OK.
A pity there wasn't an example - would have saved this thread.
#define BUFFSIZ 512
#define POLLBUFFSIZE 128
char rxbuff[BUFFSIZ]; // receive message buffer. Note only one message at a time allowed.
/*--------------------------------------------------------------------------
MQX Serial Port Listener. Very simple
--- */
void rs232_task
(
uint_32 dummy
)
{
static int rxidx = 0;//index into global message buffer
uint_32 n,i;
char inBuff[POLLBUFFSIZE];
char tmp;
while(1){//sit here forever
_time_delay(10);//polling rate = 10mS - at 115200 could produce 100+ chars?
n = _io_read (stdin, inBuff, POLLBUFFSIZE);
for(i=0;n>0;i++,n--){
tmp = inBuff[i];
tx_byte(tmp);// echo debug
if (CR==tmp){//if CR
rxbuff[rxidx]=0; //replace CR with 0
rxidx=0; //reset buffer pointer
comm_handler(); //parse command
}
else{
rxbuff[rxidx]=inBuff[i];
if (++rxidx>BUFFSIZ) rxidx = BUFFSIZ;//stop overrun.
}
}
}
}
If anybody finds that useful, feel free to borrow it.
Hi,
one thing I have noticed in real communication: There may be partial message or multiple messages
in buffer when io_read() returns.
Example code below handles those cases.
(Not sure if code is bugfree, wrote with Notepad as an example).
~Mark
static int rxidx = 0;//index into global message buffer
uint_32 n;
char inBuff[POLLBUFFSIZE];
uint_32 inCount=0;
uint_16 msgLen;
char *cp;
char tmp;
while(1) //sit here forever
{
_time_delay(10);//polling rate = 10mS - at 115200 could produce 100+ chars?
n = _io_read(stdin, inBuff+inCount, POLLBUFFSIZE-inCount-1);
if (n > 0) // Chars received
{
inCount += n; // Update char count
do {
inBuff[inCount] = '\0'; // End null for strchr
if ((cp = strchr(inBuff, CR) == NULL) // CR received?
{
if (inCount >= POLLBUFFSIZE-1) // No
{
//Too long line without CR
inCount = 0; // Flush buffer
}
}
else // CR received
{
msgLen = cp-inBuff;
comm_handler(inBuff, msgLen); //parse command
memmove(inBuff, cp+1, msgLen+1); // remove handled message
inCount -= msgLen+1;
}
} while (CP != NULL && inCount > 0); // Still data in buffer?
}
}
I have an additional question...
Is it possible to use the MQX interrupt implemenation, and read the status registers at them same time?
I need to know what the status register was for each byte so that I can detect a break condition.
It is important to know where the break condition is.
Is it possible to do this?
Thanks,
Tim
Hi,
Not sure if this kind of solution works:
Save at RX break interrupt the tail index to the new variable RX_BREAK_INDEX.
At read function the RX_BREAK_INDEX is checked.
New code between #if 1 ... #endif below.
Looked also Kinetis datasheet, not sure if the use of UART_S2_LBKDIF_MASK need
some initialization.
file serinprv.h:
----------------
_mqx_uint INPUT_LOW_WATER_MARK;
#if 1//BREAK
_mqx_int RX_BREAK_INDEX; // -1=not set, other value is head index
#endif
} IO_SERIAL_INT_DEVICE_STRUCT, _PTR_ IO_SERIAL_INT_DEVICE_STRUCT_PTR;
file serl_int_kuart.c:
----------------------
void _kuart_int_err_isr()
...
if(stat & UART_S1_FE_MASK) {
++sci_info_ptr->RX_FRAMING_ERRORS;
}
#if 1//BREAK
stat = sci_ptr->S2;
if ((stat & UART_S2_LBKDIF_MASK) != 0) {
sci_ptr->S2 = UART_S2_LBKDIF_MASK; // Clear bit
/* Set current index to break index if not yet set */
if (int_io_dev_ptr->RX_BREAK_INDEX == -1) {
int_io_dev_ptr->RX_BREAK_INDEX = int_io_dev_ptr->IN_QUEUE->TAIL;
}
}
#endif
} /* Endbody */
file serl_int.c:
----------------
_mqx_int _io_serial_int_open()
...
int_io_dev_ptr->COUNT = 1;
#if 1//BREAK
int_io_dev_ptr->RX_BREAK_INDEX = -1;
#endif
return(result);
} /* Endbody */
_mqx_int _io_serial_int_read()
...
while ( i ) {
in_queue = int_io_dev_ptr->IN_QUEUE;
_int_disable();
#if 1//BREAK
if (int_io_dev_ptr->RX_BREAK_INDEX != -1) { // Break received?
if (int_io_dev_ptr->RX_BREAK_INDEX == in_queue->HEAD) { // Now at break location?
if (i == num) { // Characters copied?
num = -99; // NO, RETURN BREAK OCCURENCE
int_io_dev_ptr->RX_BREAK_INDEX = -1; // Remove break mark
_int_enable();
break;
}
else // Some characters copied, return them. Break is returned at next call
{
num -= i;
_int_enable();
break;
}
}
}
#endif
if(flags & IO_SERIAL_NON_BLOCKING) {
if (_CHARQ_SIZE(in_queue) == 0) {
BR,
Mark
Hi Maurizio,
I don't think the issue is to have the UART in POLLED or INTERRUPT mode but more of a system architecture conversation of how you want the two task to access the recieved data.
In general only on task will be able to receive the UART data. Your code needs to either use a synchronization method (semaphore or mutex or glabal variable) or possible one task that will recieve the UART data and then determine who it is for and send that data to a task using message or global variable.
To see how a semaphore can be used for synchronization look at the mqx/examples/hello2 project. It is outputing data to UART and not receiving but the concept is what I want you to see.
There is a lightweight message queue example that might be helpful too in mqx/examples/lwmsgq .
Hope this helps.
Regards,
David
Hmmm.
In a bare-metal system I would have an interrupt handler for the UART, which stores the incoming chars in a buffer, and sets one or more flags.
The flag can be polled whenever the application is ready to cope with the incoming data.
What nice bit of example code shows me how a task can wait for incoming data on the UART? I have looked for this in the MQX examples but haven''t found it yet.
Thanks
You need to define ITTYx (means interrupt):
#define BSPCFG_ENABLE_TTYD 0
#define BSPCFG_ENABLE_ITTYD 1
Change default IO-channel in twrk60n512.h to ittyd:
#if BSPCFG_ENABLE_ITTYD
//#define BSP_DEFAULT_IO_CHANNEL "ttyf:" /* OSJTAG-COM polled mode */
#define BSP_DEFAULT_IO_CHANNEL "ittyd:" /* RS 232 port */
#define BSP_DEFAULT_IO_CHANNEL_DEFINED
#else
#define BSP_DEFAULT_IO_CHANNEL NULL
#endif
#endif
Open uart:
MQX_FILE_PTR uart_device;
uart_device = _io_fopen("ittyd:", (char _PTR_)(IO_SERIAL_RAW_IO|IO_SERIAL_NON_BLOCKING));
Write&read data:
count = _io_write( uart_device, data, len );
readCount = _io_read ( uart_device, data, bufSize);
Change queue-size if larger than 64 needed in user_config.h:
#define BSPCFG_SCI3_QUEUE_SIZE 256 /* sci3=ittyd */
Thanks Mark,
which bit of that is sitting waiting for incoming characters? (I suspect fread...), and what is the task doing in the meantime?
Also, does the device need a mutex for TX use, or is that built into the fwrite?
Hi OldNick,
Here is one way.
pointer fh_ptr;
uint_32 result;
fh_ptr = (pointer)fopen("ittyc:", BSP_DEFAULT_IO_OPEN_MODE);
if (fh_ptr == NULL) {
printf("cannot open file: ittyc\n"); //print to uart0
} else {
printf("\nittyc: Device Handler opened successfully\n"); //print to uart0
fflush(stdout);
}
if(result = fstatus(fh_ptr)) // check uart to see if char is pending
{
printf("Character waiting in UART1\n"); //print to uart0
read(fh_ptr,(pointer)&Z,1); // read 1 char to uart1
printf("Your character in UART1 was %c\n", Z); //print to uart0
}
else
printf("No character waiting in UART1\n"); //print to uart0
Hope this helps.
Regards,
David
DavidS
Sorry to be a bit slow on the uptake here. Your example code looks like "check once then exit".
I don't think
while(1){
if(result = fstatus(fh_ptr)) {
handlecharacter();
}
}
is very elegant.
Anyway, I am reading chapter 5 of MQXIOUG, and not seeing anything that enables a task to "wait on RX"
Nor is fstatus documented in that manual, or anywhere else that I can find in the docs directory.
I reckon there must be something simple in there somewhere? A simple UART example that waits on incoming chars and echoes them back to the terminal would be a great help.
Hi OldNick,
Yes my example checked once (i.e. it is a non-blocking method). It could easily be implemented in a loop as well.
When you do a read with a polling driver, then it will wait for a charater to be entered.
ex: read(fh_ptr,(pointer)bptr++,1); // read 1 char where fh_ptr is returned from fopen(), bptr is pointer to a character buffer, and 1 indicates you are waiting for one charater only.
The fstatus() gets mapped to io_fstatus() from fio.h and is in io_fstatus.c. Sorry that it isn't in UG or RM. We are trying to document everything but not quite there yet.
Interrupt drivers will read the input data as it arrives, place it in a buffer, set a flag so if a task was blocked waiting for data it will awaken.
Hope this helps.
Regards,
David
Ok guys. this is how I have set it up.
in userconfig.h
#define BSPCFG_ENABLE_ITTYA 1//use interrupt version...
in MyBoardk40x256.h
#if BSPCFG_ENABLE_ITTYA
#define BSP_DEFAULT_IO_CHANNEL "ittya:"
#define BSP_DEFAULT_IO_CHANNEL_DEFINED
...
#define BSP_DEFAULT_IO_OPEN_MODE (pointer) ( IO_SERIAL_RAW_IO |IO_SERIAL_NON_BLOCKING)
the tasklist is
const TASK_TEMPLATE_STRUCT MQX_template_list[] =
{
/* Task Index, Function, Stack, Priority, Name, Attributes, Param, Time Slice */
{ HELLO_TASK, hello_task, 1500, 8, "hello", MQX_AUTO_START_TASK, 0, 0 },
{ COMMS_TASK, rs232_task, 1000, 8, "rs232", MQX_AUTO_START_TASK, 0, 0 },
{ 0 }
};
And the rs232-stask is
/* --------------------------------------------------------------------------
MQX task. Very simple
--- */
void rs232_task
(
uint_32 dummy
)
{
static int rxcount = 0;
uint_32 st;
char in;
while(1){//sit here forever
st = status(); //waiting for chars
if (st){
in = getchar();//add char to rxbuff
tx_byte(in);// echo debug
if (CR==in){//if CR
rxbuff[rxcount]=0; //replace CR with 0
comm_handler(); //parse command
rxcount=0; //reset rxcount
}
else{
rxbuff[rxcount]=in;
if (++rxcount>BUFFSIZ) rxcount = BUFFSIZ;//stop overrun.
}
}
}
}
This works quite nicely...except that the hello_task never runs.
Like I said, I need this task to sleep pending an incoming character.
Help?
Hi,
when using nonblocking interrupt method the getchar doesn't block, instead it returns IO_EOF.
_mqx_int _io_fgetc:
...
if ((*dev_ptr->IO_READ)(file_ptr, &tmp, 1) == 1) {
return((_mqx_int)((uchar)tmp));
} else {
return(IO_EOF);
} /* Endif */
You need to add task suspend/wait when this IO_EOF is received.
Serial read function:
_mqx_int _io_serial_int_read:
...
while ( i ) {
in_queue = int_io_dev_ptr->IN_QUEUE;
_int_disable();
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 */
_CHARQ_DEQUEUE(in_queue,c);
Hmmm. Take a while to get my head around that.
I would rather take a step backward and re-frame the original question.
What is the simplest way to get a task to wake up when a character is received on the RS232-port?
e.g. for a task to go to sleep for a while, I call "time_delay()
So to make a task wait for RX-chars, I call ???
Polling the UART takes processor time. But the interrupt driver surely ought to be capable of waking a task?
Thanks again for all the advice.
Not sure, but I think MQX is designed for that purpose by not defining IO_SERIAL_NON_BLOCKING.
But what happens if the baudrate is e.g. 115200, the waiting task is wakened up quite often when receiving data.
I've made in my earlier (non MQX) projects that receive buffer is polled in 10 or 20 ms period.
I've made the polling in MQX in this way:
readCount = _io_read (uart_device, dataBuffer, bufSize);
~Mark
Yep...interrupts about every 90us.
that was going to be my next question...how to move the task-wake from a per-character basis. (Since the driver has a buffer anyway.)
Looks like I am going to be doing the good old 10mS poll->double-buffer->process shuffle (Always assuming I don't get buffer overruns because some other task is munching away and won't give me the processor back.)
Seems crazy that all this stuff gets done for USB and Ethernet stacks, but there is nothing for the ubiquitous UART. (115,200 bits per second is too fast for them, I suppose.)
Do you happen to know what the context-switching time for MQX is, on (say) a Kinetis at 100MHz?
Hi OldNick,
With the UART/SCI in interrupt mode, there is a 64byte buffer defined in the twrk60n512.h in the BSP.
/* TTYA and ITTYA buffer size */
#ifndef BSPCFG_SCI0_QUEUE_SIZE
#define BSPCFG_SCI0_QUEUE_SIZE 64
#endif
It really is only used with the interrupt mode. As a character is received, the interrupt handler will add it to the buffer. If there is a task blocked and waiting for a character, the RTOS will place it in the ready queue and when it is the highest priority task ready to run it will run. Should the task have to wait for awhile as other higher priority tasks are running, the UART/SCI interrupt keeps adding to the buffer.
Hope this helps.
Regards,
David
DavidS,
You wrote
If there is a task blocked and waiting for a character,
I know this sounds silly, but that is the one thing I cannot see how to set up.
Please explain, if I am using the non-blocking interrupt driver,which API layer function call will block the task until one or more characters are available in the ring buffer?
As you saw, I tried status() and getchar() and that was not succesful.
=================
MarkP
I assume that _io_read is non-blocking, and returns 0 if there is nothing in the buffer? Should I have been able to find that out by myself? (Sorry)
Hi TIm,
The MQX IO-Drivers User's Guide describes the _io_read operation. If no characters received, it returns 0.
My first trial with interrupt-mode halted the task, then debugging the code I found the parameter IO_SERIAL_NON_BLOCKING.
In MQX BSP-project there are peripheral drivers source folder (don't remember the exact name because sitting now at my home PC). Studying those polled mode and interrupt mode source files helps to understand the functionality.
~Mark