I am implementing a uart communication, where i have various functions and/or tasks which may want to perform transmission using uart. Hence prior to new transmission on uart, i want to ensure that the resource (uart) is not already in use. this can be achieved by a binary semaphore whose value can be checked prior to new transmissions. But keil RTOS doesnt have sem_getvalue, in absence of which i am unable to think of any way of implementation.
one way around is to have a global flag. But currently trying to use any idea by which i can avoid using a global flag. In case of no other way, will have to use global flag.
any suggestions?
Thinking of implementing my own semaphore management routines. :P
You don't want to use a global flag but a global semaphore is ok?
So - create an accessor function that uses a static flag and a critical section. Call it to allocate the UART and check the return value if you got the UART allocated or if it was busy. You could potentially have your code send events too, to let threads wait for the availability of the UART.
Thank you for the view. was Helpful. but, i m still doubtful, why keil doesnt have a function equivalent to sem_getvalue.
os_evt_wait_or(CHECK_EVENT_FLAGS, INFINITE_TIME); //Wait for an Event to occur rx_event = os_evt_get(); if(!CurTxflg) //Check if any transmission is going on currently switch(rx_event) { case EVENT_TXCMD: os_mbx_wait(&MailTxBuf, &ptx, 0xFFFF); //Wait for the Transmission Data strcpy(DISPLAY_PORT_TXBUF, ptx); CurTxflg = 1; UTILS_AppendLRC(DISPLAY_PORT_TXBUF, UTILS_CalcLRC(DISPLAY_PORT_TXBUF)); UART_SendByte(DISPLAY_PORT_UART, *DISPLAY_PORT_TXBUF); break; case EVENT_COMPLETE: CurTxflg = 0; break; }
The uart interrupt task will generate "EVENT_COMPLETE" and the other tasks and/or functions that want to send data will generate the "EVENT_TXCMD".
suppose a task generates an event "EVENT_TXCMD", when the current transmission is still not complete,
os_evt_set (EVENT_TXCMD,TID_TxDisplay); os_mbx_send(&MailTxBuf, (void*)&pbuf, 0xFFFF);
then will the event be logged and hence executed by the task after completion of the transmission indicated by
isr_evt_set (EVENT_COMPLETE,TID_TxDisplay);
Note that you have code that does the following:
if (!CurTxflg) { //Check if any transmission is going on currently switch(rx_event) { case EVENT_TXCMD: ... CurTxflg = 1;
You have no critical section that makes sure that not another thread also tries to look at CurTxflg and then decide that the UART is free to use.
This is actually the new implemented code, which i wrote as a way around, in absence of sem_getvalue(). and i am sry. that doesnt work as the uart interrupt cant clear the CurTxflg. hence the implementation changes to:
switch(rx_event) { case EVENT_TXCMD: if(!CurTxflg) //Check if any transmission is going on currently { os_mbx_wait(&MailTxBuf, &ptx, 0xFFFF); //Wait for the Transmission Data strcpy(DISPLAY_PORT_TXBUF, (uint8_t*)ptx); CurTxflg = 1; UTILS_AppendLRC(DISPLAY_PORT_TXBUF, UTILS_CalcLRC(DISPLAY_PORT_TXBUF)); UART_SendByte(DISPLAY_PORT_UART, *DISPLAY_PORT_TXBUF); } break; case EVENT_COMPLETE: CurTxflg = 0; break; }
Note that you have never described exactly in what way the UART is shared.
If the goal is just to make sure that printouts from different tasks doesn't get intermixed, then you have many other options available.
One potential way: - let the UART ISR consume data from a single transmit buffer. - have multiple threads that want to print generate their output into individual, static buffers. - have the printing threads send mail with the individual prints. - let a common master thread wait for mails, pick up a mail, wait until the transmit buffer has enough free space to hold the mailed text - use some signalling to report back to the sender thread that the thread-specific send buffer has been consumed so it is free to generate and send a new mail with more UART data.
Then you get a situation where multiple printouts never have the individual characters interleaved.
And you have a way of sharing the use of the UART - the order of the mails will control the order data gets sent to the UART. So no printing thread will lock the UART indefinitely and starve other prints.
Note also that the isr_xxx() functions allows the UART transmit ISR to look for a new mail if running out of serial data. So the UART could run with no global transmit buffer - it picks up the data directly from the mail-supplied buffer before releasing the mail and looking for next mail. Having the ISR directly picking up any mails will require that you have some other code to kick-start the UART transmit interrupt after the interrupt have run out of data to send and had to deactivate the UART TX interrupt. So you might need something like:
os_mbx_send(...); if (!uart_running) kickstart_uart(); // enable UART TX interrupt to have the ISR start consuming mails again.
But keil RTOS doesnt have sem_getvalue, in absence of which i am unable to think of any way of implementation.
I'm afraid you're attacking the wrong end of the problem there. The fact you believe you need a sem_getvalue() function indicates that your understanding of the purpose and meaning of semaphores is probably flawed. A semaphore is the wrong tool for that job.
If you don't want to block in case of a failed access, you shouldn't be using a semaphore in the first place. You should be using other services provided by the RTOS, e.g. message passing.
Let me just explain you what i am trying to achieve. (this is a communication protocol & its big and has to be robust. kindly bare the patience).
1. The ARM controller is acting as Slave to another controller. so it has to respond and take action to the master's commands. The master sends commands over uart. Hence, on receiving strings on uart, the data is processed to check what action is to be taken. some bytes in the string indicate the command to be executed. (all that is taken care of pretty-well).
2. all the commands have different individual functions. hence any function may be executed. when a function completes the execution, it responds to master by sending some data via uart.
3. Meanwhile, it may so happen that, while the function is being executed, the master may send a command to check the status of the execution. the status strings have not more than 10-15 bytes.
how i have implemented? one task (rx_task) continuously monitors the reception on uart by waiting for a mail from uart rx interrupt. on checking the command & data (sometimes there may be some data which requires processing), another task (exe_task) is invoked by an event. rx_task sets a static flag exe_cmd_flg. the exe_task calls a function depending upon the rx command. at the end of execution, the processed data is loaded into a buffer which is passed via mail to tx_task.
meanwhile, if chk_status command is received on the uart, and if exe_cmd_flg is set, then a function loads its static buffer & passes it via mail to tx_task. tx_task starts transmission & sets curtxflg.
now my idea of using semaphore & its application.... If you don't want to block in case of a failed access, you shouldn't be using a semaphore in the first place. I wanted the execution function (any function may be executing), to check if the transmission is already under progress or not (this transmission may be the reply for the check status - which is asynchronous event). if transmission is in progress, then wait untill the transmission is completed and then send the data (which can be done with help of a semaphore).
no in absence of sem_getvalues(), i hav implemented the below code for tx_task & want to clear the doubt if this implementation work in case if the following case occurs...
reply to chk_status command is being sent on uart. a function sends an event "event_txcmd" & then a msg box (obviously it wont be executed as curtxflg = 1) after completion of transmission, uart tx_interrupt will send event_complete, which will clear the curtxflg. will the previously sent event, event_txcmd be executed now. if not, then kindly suggest some alternate way.
in case my explanation of the situation is not proper enough, kindly let me know. Thanking you for all your time & patience. :)
No - I really do not understand the complications.
why not:
while forever { wait for mail kick-start UART with first character in mail wait for event from UART interrupt that UART transmit buffer has been fully consumed release mail buffer }
And a worker task:
while forever { wait for work perform work wait for free mail buffer send mail with result }
Receive task:
while forever { wait for uart data process uart data if forming command if poll command wait for free mail buffer send mail will poll result else inform worker thread what to do }
Whatever happens, your master processor must be bright enough to not send jobs or ask status requests faster than what the UART channel is able to send back responses or one or more of your threads in the slave processor will not be able to start with the next job because it is still waiting for a mail to use to report the previous result.
if transmission is in progress, then wait untill the transmission is completed and then send the data (which can be done with help of a semaphore).
Yes. But it appears you really have no idea how that's supposed to be done with the help of a semaphore.
I'm afraid I have to recommend that you stop what you're doing, right here and now, and go back to the fundamentals. Pick up a textbook. Really learn what a semaphore is, and what it does. Learn what P() and V() are, and why these are enough to do what a semaphor is meant to do. Only then does it make any sense for you to continue with the task at hand.
Whatever happens, your master processor must be bright enough to not send jobs or ask status requests faster than what the UART channel is able to send back responses... this is one of the problem....the master cant be smarter enough as different task at the slave take different amount of time. Though there is some pretty decent amount of delay that master will wait for (100ms or so) before sending a new command or the poll, but there is no estimation of this time period.
But it appears you really have no idea how that's supposed to be done with the help of a semaphore... kindly elaborate how its can be done
learn what a semaphore is, and what it does. suggest some good links or articles that may be noteworthy :)
before sending a new command or the poll, in absence of reply from slave...