It is based on HelloWorld example. It has two interrupts and two
tasks. One task is led "Hello world" blink, other is UART loopback. I
have one receive and one send interrupt.
For testing I use Teraterm on USB/RS232 transceiver. I send FemtoOS
Readme file over RS232 connection on different baudrares.
UART is initialised correctly. If I use only receive interrupt
(modified of course) i can do 38.4k and it is max for 8000000 Hz
crystal.
If i use pooling ( void UART_loopback_pool(void) ) I can do 19.2.
But I believe that using blocking on queue can do more. So begin problems:
1. I can not use taskQueuReadRequestOnName(UARTRx,8) or any other
number except 0. I get puntime error like this:
Error 0x12: errSlotTypeMismatch Slot used outside its definition.
Calling API: 0x27
Task: 1
I can not find problem. Do not know what to do
2. If i do not use:
for (count=0; count<8; count++)
and use
taskQueuReadRequestOnName(UARTRx,0)
inside void UART_loopback_sync(void) i can do only 9600 baudrate. It
has something to do with 1ms tick. Please explain context switch
timing.
3. So I want to use burst data: I wait for 8 byte, obtain lock,
disable context switch… But taskQueuReadRequestOnName(UARTRx,8) will
not work? What am I doing wrong?
4. Try to give Write task more time by raising priority on 3 (or
higher) but then Display task will not run? Why?
5. Also I can not compile for Compact only standard. Why?
Any other opinion on sync, performance, code, anything… would be helpful.
App is not even begin to be polished but works.
Best regards
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
1. I can not use taskQueuReadRequestOnName(UARTRx,8) or …
This is a bug, the checking mechanism thinks you made a
mistake in using the call, but you did not. I have
corrected (but not tested yet) it in the nightly build: http://www.femtoos.org/MainCode.zip
Just take the femtoos_core.c file from the nightly and replace
your version.
Workaround in current version: set 'cfgCheckMethodUse' to 'cfgFalse'.
Of course, then you loose other checking facilities as well.
Short explanation: An OS switches tasks every 1ms (but you can
change this). Anything you want to do that takes longer will
be interrupted, for an other task. If you have two tasks,
the communication task will be activated every other millisecond.
This is devastating for time critical communication protocols.
(See below for a solution)
Please note the context switching in FemtoOS is more complex,
since it allows for unequal time slices, but the basics are
the same.
3. So I want to use burst data …
Try this with the correct version or with the work around.
4. Try to give Write task more time …
This is not the correct approach. If you give a task which
has a 100% load the highest priority it will starve all
other tasks with lower priorities. This is expected behavior.
High priority tasks should delay often. But this is not what you
want.
So how do you approach this problem? There are several 'solutions'.
(btw, this is a problem in every OS.)
1) Make communication fully interrupt driven. This implies that
every time a new byte must be written (standard avr has no dma)
an interrupt occurs, and you must prepare a new byte. At 38.4 Kbaud,
this is every 200us. A lot for a system running at 16MHz, and it
will significantly increase the overhead, since each context switch
costs a lot of instructions.
2) Make a communication task at highest priority (as you did)
so it has full control, but do not forget to stop it when
communication is done. Disadvantage: all other tasks stop when
the communication is running.
5. Also I can not compile for Compact only standard. Why?
'Compact code' is for highly optimized code, forget about it until
you have a good grasp of this OS. Then have a look at the demo's in
detail. You will see that this kind of optimization requires detailed
research about the registers used per task and stack depth analysis.
regards
Ruud
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
First thing first:
Last few days I have trouble connecting to your website. ?
Now, when I am writing this there is no connection.
Second:
2) Make a communication task at highest priority (as you did)
so it has full control, but do not forget to stop it when
communication is done. Disadvantage: all other tasks stop when
the communication is running.
At *1*: I ask for UARTRx queue: If there is 8 bytes i go further and with taskEnterSwitchCritical() I process all 8 byte without interruption and at *3* I let system work normal. If tick comes processing will be switched to other task on the same priority. I release queue and go for other 8 bytes. If I have continuous stream of data I will be locked here. But If there is not 8 byte taskQueuReadRequestOnName(UARTRx,8) will block execution of current task and tell scheduler to suspend current task and let some other task do what it has to do. When 8byte are ready UART task will be ready and wait for next tick to start running. This should give some time for other task to do something (will they have enough time is another question). If UART is not active (no data flow) UART task will be blocked indefinitely and other tasks on other priorities will go on running with all the time in the world.
So I ask if this is OK. Or I did not understand how queue synchronization is done?
This is not what real communication will do. I will not have continuous stream of data that will block everything:
Highest priority: control system that will keep real (mechanical, electrical..) world in stability and control. This would work in equidistant times (10 to 20 ms) and will be fairly quick.
Lower priority: communication level with commands coming at random (sparse) times and data acquisition at equidistant times.
Lowest: all other tasks
So question is: Is taskQueuReadRequestOnName(UARTRx,dataLength) blocking task in the way that it will immediately release processor and let other tasks run.
As I can not download your code, could you email me femtoos_core.c. I will try the workaround in the meanwhile.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Tried workaround. Compiles and runs without error.
But… If I use taskQueuReadRequestOnName(UARTRx,0) program runs and I get UART loop-back working correctly. At 19200 baudrate all characters loopback. At 38400 some characters are lost.
But if I put taskQueuReadRequestOnName(UARTRx,8) or any other char count program get stacked at this place and nothing happens inside UART processing task. Second task runs as expected regardless of priority of the given tasks (no matter if UART task is higher priority).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Last few days I have trouble connecting to your website. ?
Hmmm, i did not notice any downtime, and i call my server every
five minutes. Could be the somewhere in the connection.
I also saw some intensive attacks on my server, maybe
that interfered with the normal httpd operations. Lets
hope this problem disappears by itself. If it remains, (i.e.
is still there in a couple of days) let me know, i will start
complaining at the data center.
Your code:
This setup is ok. Indeed the taskQueuReadRequestOnName(UARTRx,8)
should block until 8 bytes have arrived. If you put 0, the task
would run at 100% load, so it starves other lower priority tasks.
The disadvantage of putting 8 is of course that you can only send
data in multiples of 8 bytes before processing begins. If you loose
sync on the 8 byte boundary this may severely hamper the communication.
Or you put in a 1, so it at least blocks until one character has
arrived, but then the overhead per byte is still high, or you
put in 8 or so with a 'timeout'. If you make sure you always pad
your data with 8 bytes, you can throw away the last bytes, at a
timeout.
The fact that it does not work at all when you put in any other
number than 0 i do not understand yet. You said that it blocks on
the taskQueuReadRequestOnName(UARTRx,8) instruction itself. Have
you verified that, in other words, you are sure it does not block in
the part "// some code goes here" ? This makes a difference when
looking for the cause.
You make use of taskEnterSwitchCritical() and states that it blocks
interrupts, but this is not true. It prohibits task switches,
but still allows for the tick interrupts to come, and thus for
the tick counter to increase and the tick hooks to be punctual.
This may be the reason for your loss of characters at the highest speed.
You can also try taskEnterTickCritical(). This makes sure
there are no tick interrupts any more, but still allows for
other interrupts. Of course, time spend in between tick critical
code must be minimal, and you should never block inside such
a critical sections. If you do => system hangs.
See http://www.femtoos.org/code_api.html#0416 http://www.femtoos.org/code_api.html#0419
OK i still do not understand why any other number than 8
causes a permanent block. Can you post the code of the
block "// some code goes here". [I have it in the zip, but
do not know for sure if you did not modify it]. I have
for (count=0; count<8; count++)
{
RXdata = genQueuReadOnName(UARTRx);
I will answer your last post in next y post but first this:
1 Queue example from FemtoOS unchanged original state compiles and runs as described. I checked. It uses same queue functions as I do. So just put some char on queue and read it later. Only difference is that i use interrupts.
2. Reading from UARTRx is blocking. Reading code I use now is:
As you can see ISR is displaying number of characters ready to be read from queue.
4. Results are as follows:
- if I use taskQueuReadRequestOnName(UARTRx,0) at 19200 baudrate no more then 3 characters are in queue at anytime and all characters are looped back. No characters are lost. At 38400 queue gets filled to max of 30 chars (size of queue) and some characters are lost (approximately every other) but UART loopback is working.
-if I use taskQueuReadRequestOnName(UARTRx,5) queue gets filled to maximum and no characters are looped back. I tried keyboard input of characters and all is the same, no characters are looped back. All characters are received and put to queue but never read from it? I also tried peeking into queue and reading from queue inside ISR and putting chars on ledPort and all is OK. Queue is filling.
5. Please consider that I might be doing something stupid in coding or configuration.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Also all other writing to devLedPORT is disabled (except these two) and program never get to devLedPORT = ~0xaa when blocking count is more then 0. also when sending stream of data I see these two values together on leds, as change is too fast for leds to switch off. And again data flows.
This is now no problem of performance. The problem is that I can not block on queue, or to be correct task blocks indefinitely.
I could use event in ISR and dedicated task in high priority but it does not solve the problem. May me the queue synchronization would work when only queues are involved in filling/reading queue. May be using ISR is problem.
Or again I am doing something stupid. Would not be the first time :-))
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
OK i still do not understand why any other number than 8
causes a permanent block.
Sorry for misunderstanding: any other number than 0 causes permanent block. It has nothing to do with number 8. You can pick any number you like. I tried.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I understood your points in your last two post fully. I think there is a "flaw" in my design. You said "Only difference is that i use interrupts". This triggered my suspicion. It looks like the block is erroneously not released when the characters are added in a ISR. But this is not the case. The problem is, that in my design, taskQueuReadRequest / taskQueuRelease form a pair. So, only after a formal release other requests are reexamined. There where reasons for that, which i shall not discuss now (**). But in an ISR you cannot use those calls, so, although you can read/write a queue, you cannot use it to deblock any blocking calls right now. Your design was so natural i forgot all about this limitation. My apologies.
The question is, how to repair this? It seems logical to add deblocking code to genQueuWrite, but it is not the correct solution. I could add a new call specially for inside an ISR, that you may call to force such a check. But this would still require you to call it after the addition of every byte, which really adds much more overhead at the point it hinders you most. It would certainly slow down communication. So I have to think about it.
For you, the best way would be to simply add a time out, with a wait time low enough prohibiting the queue from overflowing.
Thus, if your queue is 30 bytes, keep some margin, and set the limit to 24 bytes. To fill these at max speed you need 8x24/38400 = 0.005, so 5 ms. (you can even make this dynamic, dependant on your communication speed) In fact, you are using a spinlock. Now you get something like (untested)
void UART_loopback_sync(void)
{ Tchar RXdata = 0;
Tuint08 count = 0;
/* wait until at least 8 characters have arrived, make sure that
* you do not wait more than 5ms, so that there never more than
* 24 bytes in the queue. Note that this loop is relatively fast,
* this task will not produce much overhead, when no characters are
* arriving. */
while (!taskQueuReadRequestOnName(UARTRx,8,5));
/* now read 8 characters */
for (count=0; count<8; count++)
{ RXdata = genQueuReadOnName(UARTRx);
/* actually, this if is not needed, you know that there must be a valid character. */
if (RXdata)
{ genQueuWriteOnName(UARTTx,RXdata);
UCSRB |= (1 << UDRIE); } }
taskQueuReleaseOnName(UARTRx); }
Please note that in between a taskQueuReadRequest / taskQueuRelease pair characters may still arrive and are added to the read queue. This is perfectly ok.
I am curious if this works.
Ruud.
(**) One of them is that adding that to the genQueuWrite/genQueuRead routines would not keep them short,as required in ISR environment. Others have to do with the internal design. Allowing it would require extra checks and protection routines and thus further bloating the OS.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Added: while (!taskQueuReadRequestOnName(UARTRx,8,5));
and get compile error:
../src/FOS_driver_UART.c:79:47: error: macro "taskQueuReadRequestOnName" passed 3 arguments, but takes just 2
API claims that there is call to taskQueuReadRequestOnName with 3 arguments. Queue example project from OS uses macro with 3 arguments and compiles with no problem.
Or again I am doing something stupid. Would not be the first time :-))
I checked OS files in both src dirs and they are identical. Only thing that is different are config files. and of course project files.
Again it must be me. Is there a config situation to include only macro with 2 and not 3 arguments.
It must be me doing crazy things.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Or again I am doing something stupid. Would not be the first time :-))
This time, i must admit it ;-)
Any (well most) functionality you want to use you must activate in the configuration file. Of course, i could have added all functionality in the kernel by default, but that would bloat the OS with stuff you may never need. I agree, that Femto OS is a little rough in this aspect., thats the price to be paid for very small systems. Thus in any case, you have to activate:
#define cfgUseTimeout cfgTrue
And the task must have delay capabilities, but i think you have already set capabilities to all (cfgCapAll) http://www.femtoos.org/code_config.html#1830
If you get an compiler error, have a look at the warnings too. Often, my checking system reports misuse and inconsistent use of configuration settings. Never ignore warnings! In my opinion, a program should compile without warnings.
One other remark.
I saw you configured
#define cfgUseSynchronization cfgSyncSingleSlot
This is fine as long as you are not occupy more than one slot per task at the same time. In the code however i saw that you use two when requesting the write and read queue. (Writing to the queue does not require a slot, but reserving it for yourself does)
// requesting the first slot
taskQueuReadRequestOnName(UARTRx,8);
taskEnterSwitchCritical();
for (count=0; count<8; count++)
{
RXdata = genQueuReadOnName(UARTRx);
if (RXdata)
{
// requesting the second slot, if you include the statement below
taskQueuWriteRequestOnName(UARTTx,8);
genQueuWriteOnName(UARTTx,RXdata);
UCSRB |= (1 << UDRIE);
taskQueuReleaseOnName(UARTTx);
}
}
taskExitSwitchCritical();
taskQueuReleaseOnName(UARTRx);
#define cfgUseSynchronization cfgSyncSingleBlock
...
#define SlotSize_Write 2
#define SlotSize_Display 0
// i saw that the display task does not use locking at all
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
One last remark. It is not obligatory to use the taskQueuReadRequestOnName/taskQueuReleaseOnName pair. You can perfectly read from a queue as long as you know you are the only one at the time manipulating it. And this is true, if you only add characters in an ISR. Thus, it is much easier to use the event system of Femto OS to activate the reading task. I will post an example later.
I started UART driver in order to have some feedback and insight what is going on inside MCU during execution of OS and to use functions inside Shell application to check for performance. Also I need it do do some data collection for further PC processing.
To start most natural thing was to make "digital parrot" that will repeat all i send to it. When I got loopback I wanted to see how fast can communication be in order to use most efficient way. It is not my intension to have continuous stream of data flowing in and out at all times. For now it is only convenient way to test the overall setup. Ultimately I hope to have kind of putchar/getchar, puts/gets paits and pipe functionality (as in shell example and everywhere I look in other applications).
So the idea is following: I use queues as data buffers and synchronization mechanism to achieve asynchronous data flow in/out. Data processing task is inactive until there is enough data communication. Only at this point task is activated and data is processed. When all available data is processed task is suspended again.
In order to have this work "naturally" writing and reading queue must block.
Reading and writing communication hardware can be done in 2 way: in one way ISR will read and write to queue, in other ISR will will fire an event what will wake task to do actual read/write.
But now I see problem: if ISR is used we have problems described before. If event and task is used I see similar problem:
Proposed solution with while (!taskQueuReadRequestOnName(UARTRx,8,5)); is, in my opinion, just a better pooling: instead of pooling all the time, queue is pooled (effectively) every 5ms ant this is not "wait for enough data and only then begin processing" strategy. Timeout here is used, in my opinion, to have time critical notification in case of communication troubles.
The way I see things solution is:
taskQueuReadRequestOnName(UARTRx,8);
while (allDataIsProcessed)
{
RXdata = genQueuReadOnName(UARTRx);
processData(RXdata);
}
taskQueuReleaseOnName(UARTRx);
This is not working for me when writing to queue inside ISR, for reasons described before.
How will this work in case of event and task writing to queue: ISR fires an event that will wake a high priority task to write queue using genQueuWriteOnName(UARTRx,UDR);. Question is: if this function is used inside task does it have to be inside
taskQueuWriteRequest / taskQueuRelease to have correct reading synchronization? If this is a case then there could be problem if queue if full. Then no data would be read from UDR until there is empty place inside queue. This, on the other hand, could be solved by requesting 0 byte for writing inside taskQueuWriteRequest.
But there is even bigger problem:
Page 152 of Atmega16 manual:
When interrupt-driven data
transmission is used, the Data Register Empty Interrupt routine must either write new data to
UDR in order to clear UDRE or disable the Data Register empty Interrupt, otherwise a new interrupt
will occur once the interrupt routine terminates.
Page 156 of Atmega manual:
When interrupt-driven data reception is used, the receive complete routine
must read the received data from UDR in order to clear the RXC Flag, otherwise a new interrupt
will occur once the interrupt routine terminates.
So using ISR to fire event also requires reading UDR in order to stop repeating interrupts , having global variable to store data.
Than this global variable is to be stored in queue inside high priority task.
So, any solution I see is not optimal in any way.
I do not know what to do!
Help!?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
We discussed this before. There is no GPIO on this device. The device architecture is ancient. Choose an other device, or choose a register you do not need. It must be in the lower IO (<0x20) region.
I will react to your other points later on, but i believe the event system is just the solution to your problems. Untested:
Of course, it also possible to use the interrupt (with isr) solely to wake a high priority task, which fully handles the incoming bytes. This is polling, but guarantees maximum throughput. In that case, the ISR looks (note the absent isrEnter/isrExit!)
And handle everything else in the task. Now rereading your post, i see you must disable the interrupts manually also. Please add this in the ISR, and enable them again in the high priority task once communication is over. I do not have the time right now to come with some working code examples, but i don't think its to difficult.
Question is: if this function is used inside task does it have to be inside
taskQueuWriteRequest / taskQueuRelease to have correct reading synchronization?
No, as i explained earlier, this calls are only to needed if you want exclusive access to your queue. This is not needed if you have only one task reading and one task writing. (If you have more tasks writing for example, you need this to make sure the messages are not mixed). With genQueuReadableOnName(UARTRx) you can test if there are bytes ready to be processed.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This should work like this: ISR reads character, writes queue and fires event. Task blocks on event and waits for first char to arrive.
But…
If I uncomment in ISR
//devLedPORT = ~count++
and comment corresponding instruction in UART_loopback_sync I can see on led port count incrementing on every new character. And this is correct. So event is fired only when new character arrives. At least this is what I think.
But if I run this code as shown above, as soon as program is loaded strange things begin: leds on devLedPORT flash like crazy and in PC terminal application I get tons of garbage.
To me this is indication that task is not blocking on event for some reason and just loops and loops on indefinitely.
Help!?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
If I use your code with addition of counter inside task same thing happens. Leds flash like crazy just after I download hex without any UART communication started. If characters are send to MCU they are looped back.
May be the problem with TWDR register I used? Will check.
No. If I use SPDR the same thing happens.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
To me this is indication that task is not blocking on event for some reason and just loops and loops on indefinitely.
This conclusion seems valid
May be the problem with TWDR register I used? Will check.
No. If I use SPDR the same thing happens.
I am not sure this is conclusive. Reading or writing those registers activates further events in the mcu. I would take a free port (just for the moment). If you define them as output, you can even see what is happening on the outside. If this helps, we need to find an other register that is free. Let me know.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It pays to "Clean project" command from time to time.
Indeed, you learned it the hard way :-(. Anyway, nice you tackled the problem! BTW, i always clean before compile, and this is my practice for so long now, that i had forgotten about the effects it may give when you don't. Programs are so small that the extra compile time does not outweighs the time spend searching for strange bugs!
Can do 19200 baud continuous stream data and 38400 baud keyboard data.
So it seems that 38400Kbd, which requires a guaranteed response time of 200us/char is just too much. I am a little surprised, but maybe you can get some extra speed if you deactivate all QA check functions. Thus, set all cgfCheck…. definitions to cfgFalse. The other thing you can do is to use the register compression facility. But be prepared to suffer, since this is the last optimization step to be taken, and may quickly result in the program going haywire. So this is only the last resort.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello all,
I must ask you again as last resort for some assistance because I hit the wall.
After few weeks I return to UART app. Attached you will find it. Link to .zip project file is:
https://docs.google.com/leaf?id=0B_OgQY_eYlI7N2Y5YTIzZjQtY2I3YS00MzZmLWEzZGUtYTVmYjcxNDg3ZTNk&hl=en
It is based on HelloWorld example. It has two interrupts and two
tasks. One task is led "Hello world" blink, other is UART loopback. I
have one receive and one send interrupt.
For testing I use Teraterm on USB/RS232 transceiver. I send FemtoOS
Readme file over RS232 connection on different baudrares.
UART is initialised correctly. If I use only receive interrupt
(modified of course) i can do 38.4k and it is max for 8000000 Hz
crystal.
If i use pooling ( void UART_loopback_pool(void) ) I can do 19.2.
But I believe that using blocking on queue can do more. So begin problems:
1. I can not use taskQueuReadRequestOnName(UARTRx,8) or any other
number except 0. I get puntime error like this:
Error 0x12: errSlotTypeMismatch Slot used outside its definition.
Calling API: 0x27
Task: 1
I can not find problem. Do not know what to do
2. If i do not use:
for (count=0; count<8; count++)
and use
taskQueuReadRequestOnName(UARTRx,0)
inside void UART_loopback_sync(void) i can do only 9600 baudrate. It
has something to do with 1ms tick. Please explain context switch
timing.
3. So I want to use burst data: I wait for 8 byte, obtain lock,
disable context switch… But taskQueuReadRequestOnName(UARTRx,8) will
not work? What am I doing wrong?
4. Try to give Write task more time by raising priority on 3 (or
higher) but then Display task will not run? Why?
5. Also I can not compile for Compact only standard. Why?
Any other opinion on sync, performance, code, anything… would be helpful.
App is not even begin to be polished but works.
Best regards
This is a bug, the checking mechanism thinks you made a
mistake in using the call, but you did not. I have
corrected (but not tested yet) it in the nightly build:
http://www.femtoos.org/MainCode.zip
Just take the femtoos_core.c file from the nightly and replace
your version.
Workaround in current version: set 'cfgCheckMethodUse' to 'cfgFalse'.
Of course, then you loose other checking facilities as well.
Full explanation of the context switch would take to much time,
There is an article in Elektor, (but it is not free)
http://www.elektor.com/magazines/2010/february/femto-os.1222123.lynkx?tab=3
You can also have a look at (the larger) brother freeRTOS:
http://www.freertos.org/implementation/a00002.html
which explains the concept quite well.
Short explanation: An OS switches tasks every 1ms (but you can
change this). Anything you want to do that takes longer will
be interrupted, for an other task. If you have two tasks,
the communication task will be activated every other millisecond.
This is devastating for time critical communication protocols.
(See below for a solution)
Please note the context switching in FemtoOS is more complex,
since it allows for unequal time slices, but the basics are
the same.
Try this with the correct version or with the work around.
This is not the correct approach. If you give a task which
has a 100% load the highest priority it will starve all
other tasks with lower priorities. This is expected behavior.
High priority tasks should delay often. But this is not what you
want.
So how do you approach this problem? There are several 'solutions'.
(btw, this is a problem in every OS.)
1) Make communication fully interrupt driven. This implies that
every time a new byte must be written (standard avr has no dma)
an interrupt occurs, and you must prepare a new byte. At 38.4 Kbaud,
this is every 200us. A lot for a system running at 16MHz, and it
will significantly increase the overhead, since each context switch
costs a lot of instructions.
2) Make a communication task at highest priority (as you did)
so it has full control, but do not forget to stop it when
communication is done. Disadvantage: all other tasks stop when
the communication is running.
3) Elongate the time slice to 10ms or so, and make the task
quickly relinquish control when no communication is needed.
In 10 ms you can transfer 48 bytes. If you can organize
your communication in blocks of 48 bytes (or less), you'r fine.
In FemtoOS it is possible to give one task a longer time slice
than others, specially for this purpose:
http://www.femtoos.org/code_config.html#1401
http://www.femtoos.org/code_config.html#1804
http://www.femtoos.org/code_config.html#1109
Have a look at the following discussion too:
https://sourceforge.net/projects/femtoos/forums/forum/789278/topic/3565410
'Compact code' is for highly optimized code, forget about it until
you have a good grasp of this OS. Then have a look at the demo's in
detail. You will see that this kind of optimization requires detailed
research about the registers used per task and stack depth analysis.
regards
Ruud
First thing first:
Last few days I have trouble connecting to your website. ?
Now, when I am writing this there is no connection.
Second:
I thought I did so by using:
At *1*: I ask for UARTRx queue: If there is 8 bytes i go further and with taskEnterSwitchCritical() I process all 8 byte without interruption and at *3* I let system work normal. If tick comes processing will be switched to other task on the same priority. I release queue and go for other 8 bytes. If I have continuous stream of data I will be locked here. But If there is not 8 byte taskQueuReadRequestOnName(UARTRx,8) will block execution of current task and tell scheduler to suspend current task and let some other task do what it has to do. When 8byte are ready UART task will be ready and wait for next tick to start running. This should give some time for other task to do something (will they have enough time is another question). If UART is not active (no data flow) UART task will be blocked indefinitely and other tasks on other priorities will go on running with all the time in the world.
So I ask if this is OK. Or I did not understand how queue synchronization is done?
This is not what real communication will do. I will not have continuous stream of data that will block everything:
Highest priority: control system that will keep real (mechanical, electrical..) world in stability and control. This would work in equidistant times (10 to 20 ms) and will be fairly quick.
Lower priority: communication level with commands coming at random (sparse) times and data acquisition at equidistant times.
Lowest: all other tasks
So question is: Is taskQueuReadRequestOnName(UARTRx,dataLength) blocking task in the way that it will immediately release processor and let other tasks run.
As I can not download your code, could you email me femtoos_core.c. I will try the workaround in the meanwhile.
Tried workaround. Compiles and runs without error.
But… If I use taskQueuReadRequestOnName(UARTRx,0) program runs and I get UART loop-back working correctly. At 19200 baudrate all characters loopback. At 38400 some characters are lost.
But if I put taskQueuReadRequestOnName(UARTRx,8) or any other char count program get stacked at this place and nothing happens inside UART processing task. Second task runs as expected regardless of priority of the given tasks (no matter if UART task is higher priority).
Hmmm, i did not notice any downtime, and i call my server every
five minutes. Could be the somewhere in the connection.
I also saw some intensive attacks on my server, maybe
that interfered with the normal httpd operations. Lets
hope this problem disappears by itself. If it remains, (i.e.
is still there in a couple of days) let me know, i will start
complaining at the data center.
This setup is ok. Indeed the taskQueuReadRequestOnName(UARTRx,8)
should block until 8 bytes have arrived. If you put 0, the task
would run at 100% load, so it starves other lower priority tasks.
The disadvantage of putting 8 is of course that you can only send
data in multiples of 8 bytes before processing begins. If you loose
sync on the 8 byte boundary this may severely hamper the communication.
Or you put in a 1, so it at least blocks until one character has
arrived, but then the overhead per byte is still high, or you
put in 8 or so with a 'timeout'. If you make sure you always pad
your data with 8 bytes, you can throw away the last bytes, at a
timeout.
The fact that it does not work at all when you put in any other
number than 0 i do not understand yet. You said that it blocks on
the taskQueuReadRequestOnName(UARTRx,8) instruction itself. Have
you verified that, in other words, you are sure it does not block in
the part "// some code goes here" ? This makes a difference when
looking for the cause.
You make use of taskEnterSwitchCritical() and states that it blocks
interrupts, but this is not true. It prohibits task switches,
but still allows for the tick interrupts to come, and thus for
the tick counter to increase and the tick hooks to be punctual.
This may be the reason for your loss of characters at the highest speed.
You can also try taskEnterTickCritical(). This makes sure
there are no tick interrupts any more, but still allows for
other interrupts. Of course, time spend in between tick critical
code must be minimal, and you should never block inside such
a critical sections. If you do => system hangs.
See
http://www.femtoos.org/code_api.html#0416
http://www.femtoos.org/code_api.html#0419
OK i still do not understand why any other number than 8
causes a permanent block. Can you post the code of the
block "// some code goes here". [I have it in the zip, but
do not know for sure if you did not modify it]. I have
for (count=0; count<8; count++)
{
RXdata = genQueuReadOnName(UARTRx);
I will answer your last post in next y post but first this:
1 Queue example from FemtoOS unchanged original state compiles and runs as described. I checked. It uses same queue functions as I do. So just put some char on queue and read it later. Only difference is that i use interrupts.
2. Reading from UARTRx is blocking. Reading code I use now is:
I can use any number of characters for blocking and the result is the same. You can see I commented out some code just to be sure.
3. For writing I use modified ISR:
As you can see ISR is displaying number of characters ready to be read from queue.
4. Results are as follows:
- if I use taskQueuReadRequestOnName(UARTRx,0) at 19200 baudrate no more then 3 characters are in queue at anytime and all characters are looped back. No characters are lost. At 38400 queue gets filled to max of 30 chars (size of queue) and some characters are lost (approximately every other) but UART loopback is working.
-if I use taskQueuReadRequestOnName(UARTRx,5) queue gets filled to maximum and no characters are looped back. I tried keyboard input of characters and all is the same, no characters are looped back. All characters are received and put to queue but never read from it? I also tried peeking into queue and reading from queue inside ISR and putting chars on ledPort and all is OK. Queue is filling.
5. Please consider that I might be doing something stupid in coding or configuration.
In my previous post you can notice that I am not using critical section protection, just to be sure also you can notice this arangement:
Also all other writing to devLedPORT is disabled (except these two) and program never get to devLedPORT = ~0xaa when blocking count is more then 0. also when sending stream of data I see these two values together on leds, as change is too fast for leds to switch off. And again data flows.
This is now no problem of performance. The problem is that I can not block on queue, or to be correct task blocks indefinitely.
I could use event in ISR and dedicated task in high priority but it does not solve the problem. May me the queue synchronization would work when only queues are involved in filling/reading queue. May be using ISR is problem.
Or again I am doing something stupid. Would not be the first time :-))
devlaam wrote:
Sorry for misunderstanding: any other number than 0 causes permanent block. It has nothing to do with number 8. You can pick any number you like. I tried.
I understood your points in your last two post fully. I think there is a "flaw" in my design. You said "Only difference is that i use interrupts". This triggered my suspicion. It looks like the block is erroneously not released when the characters are added in a ISR. But this is not the case. The problem is, that in my design, taskQueuReadRequest / taskQueuRelease form a pair. So, only after a formal release other requests are reexamined. There where reasons for that, which i shall not discuss now (**). But in an ISR you cannot use those calls, so, although you can read/write a queue, you cannot use it to deblock any blocking calls right now. Your design was so natural i forgot all about this limitation. My apologies.
The question is, how to repair this? It seems logical to add deblocking code to genQueuWrite, but it is not the correct solution. I could add a new call specially for inside an ISR, that you may call to force such a check. But this would still require you to call it after the addition of every byte, which really adds much more overhead at the point it hinders you most. It would certainly slow down communication. So I have to think about it.
For you, the best way would be to simply add a time out, with a wait time low enough prohibiting the queue from overflowing.
Thus, if your queue is 30 bytes, keep some margin, and set the limit to 24 bytes. To fill these at max speed you need 8x24/38400 = 0.005, so 5 ms. (you can even make this dynamic, dependant on your communication speed) In fact, you are using a spinlock. Now you get something like (untested)
Please note that in between a taskQueuReadRequest / taskQueuRelease pair characters may still arrive and are added to the read queue. This is perfectly ok.
I am curious if this works.
Ruud.
(**) One of them is that adding that to the genQueuWrite/genQueuRead routines would not keep them short,as required in ISR environment. Others have to do with the internal design. Allowing it would require extra checks and protection routines and thus further bloating the OS.
This forum sucks. I tried three times to codify the code, but the forum engine simply deletes the first 'code' statement.
First things first:
Added: while (!taskQueuReadRequestOnName(UARTRx,8,5));
and get compile error:
../src/FOS_driver_UART.c:79:47: error: macro "taskQueuReadRequestOnName" passed 3 arguments, but takes just 2
API claims that there is call to taskQueuReadRequestOnName with 3 arguments. Queue example project from OS uses macro with 3 arguments and compiles with no problem.
Or again I am doing something stupid. Would not be the first time :-))
I checked OS files in both src dirs and they are identical. Only thing that is different are config files. and of course project files.
Again it must be me. Is there a config situation to include only macro with 2 and not 3 arguments.
It must be me doing crazy things.
This time, i must admit it ;-)
Any (well most) functionality you want to use you must activate in the configuration file. Of course, i could have added all functionality in the kernel by default, but that would bloat the OS with stuff you may never need. I agree, that Femto OS is a little rough in this aspect., thats the price to be paid for very small systems. Thus in any case, you have to activate:
And the task must have delay capabilities, but i think you have already set capabilities to all (cfgCapAll)
http://www.femtoos.org/code_config.html#1830
If you get an compiler error, have a look at the warnings too. Often, my checking system reports misuse and inconsistent use of configuration settings. Never ignore warnings! In my opinion, a program should compile without warnings.
One other remark.
I saw you configured
This is fine as long as you are not occupy more than one slot per task at the same time. In the code however i saw that you use two when requesting the write and read queue. (Writing to the queue does not require a slot, but reserving it for yourself does)
please see the discussion on
http://www.femtoos.org/code_config.html#1404
Then you need
One last remark. It is not obligatory to use the taskQueuReadRequestOnName/taskQueuReleaseOnName pair. You can perfectly read from a queue as long as you know you are the only one at the time manipulating it. And this is true, if you only add characters in an ISR. Thus, it is much easier to use the event system of Femto OS to activate the reading task. I will post an example later.
You can have look here:
http://www.femtoos.org/code_config.html#1420
http://www.femtoos.org/code_config.html#1765
http://www.femtoos.org/code_config.html#1765
http://www.femtoos.org/code_config.html#1752
At this point I must ask for a help/opinion:
Lets put beginning and end together:
I started UART driver in order to have some feedback and insight what is going on inside MCU during execution of OS and to use functions inside Shell application to check for performance. Also I need it do do some data collection for further PC processing.
To start most natural thing was to make "digital parrot" that will repeat all i send to it. When I got loopback I wanted to see how fast can communication be in order to use most efficient way. It is not my intension to have continuous stream of data flowing in and out at all times. For now it is only convenient way to test the overall setup. Ultimately I hope to have kind of putchar/getchar, puts/gets paits and pipe functionality (as in shell example and everywhere I look in other applications).
So the idea is following: I use queues as data buffers and synchronization mechanism to achieve asynchronous data flow in/out. Data processing task is inactive until there is enough data communication. Only at this point task is activated and data is processed. When all available data is processed task is suspended again.
In order to have this work "naturally" writing and reading queue must block.
Reading and writing communication hardware can be done in 2 way: in one way ISR will read and write to queue, in other ISR will will fire an event what will wake task to do actual read/write.
But now I see problem: if ISR is used we have problems described before. If event and task is used I see similar problem:
Proposed solution with while (!taskQueuReadRequestOnName(UARTRx,8,5)); is, in my opinion, just a better pooling: instead of pooling all the time, queue is pooled (effectively) every 5ms ant this is not "wait for enough data and only then begin processing" strategy. Timeout here is used, in my opinion, to have time critical notification in case of communication troubles.
The way I see things solution is:
This is not working for me when writing to queue inside ISR, for reasons described before.
How will this work in case of event and task writing to queue: ISR fires an event that will wake a high priority task to write queue using genQueuWriteOnName(UARTRx,UDR);. Question is: if this function is used inside task does it have to be inside
taskQueuWriteRequest / taskQueuRelease to have correct reading synchronization? If this is a case then there could be problem if queue if full. Then no data would be read from UDR until there is empty place inside queue. This, on the other hand, could be solved by requesting 0 byte for writing inside taskQueuWriteRequest.
But there is even bigger problem:
Page 152 of Atmega16 manual:
Page 156 of Atmega manual:
So using ISR to fire event also requires reading UDR in order to stop repeating interrupts , having global variable to store data.
Than this global variable is to be stored in queue inside high priority task.
So, any solution I see is not optimal in any way.
I do not know what to do!
Help!?
Crazy:
femtoos_ATMega32A.asm:
#define devAuxEventReg UBRRL
And I need this for events and UART too.
We discussed this before. There is no GPIO on this device. The device architecture is ancient. Choose an other device, or choose a register you do not need. It must be in the lower IO (<0x20) region.
I will react to your other points later on, but i believe the event system is just the solution to your problems. Untested:
And in the configfile on the appropiate places:
Of course, it also possible to use the interrupt (with isr) solely to wake a high priority task, which fully handles the incoming bytes. This is polling, but guarantees maximum throughput. In that case, the ISR looks (note the absent isrEnter/isrExit!)
And handle everything else in the task. Now rereading your post, i see you must disable the interrupts manually also. Please add this in the ISR, and enable them again in the high priority task once communication is over. I do not have the time right now to come with some working code examples, but i don't think its to difficult.
No, as i explained earlier, this calls are only to needed if you want exclusive access to your queue. This is not needed if you have only one task reading and one task writing. (If you have more tasks writing for example, you need this to make sure the messages are not mixed). With genQueuReadableOnName(UARTRx) you can test if there are bytes ready to be processed.
Again; I have been busy and worked some code my self like this:
Note count1 in genQueuWriteOnName.
Also:
In config_application.h:
This should work like this: ISR reads character, writes queue and fires event. Task blocks on event and waits for first char to arrive.
But…
If I uncomment in ISR
and comment corresponding instruction in UART_loopback_sync I can see on led port count incrementing on every new character. And this is correct. So event is fired only when new character arrives. At least this is what I think.
But if I run this code as shown above, as soon as program is loaded strange things begin: leds on devLedPORT flash like crazy and in PC terminal application I get tons of garbage.
To me this is indication that task is not blocking on event for some reason and just loops and loops on indefinitely.
Help!?
If I use your code with addition of counter inside task same thing happens. Leds flash like crazy just after I download hex without any UART communication started. If characters are send to MCU they are looped back.
May be the problem with TWDR register I used? Will check.
No. If I use SPDR the same thing happens.
This conclusion seems valid
I am not sure this is conclusive. Reading or writing those registers activates further events in the mcu. I would take a free port (just for the moment). If you define them as output, you can even see what is happening on the outside. If this helps, we need to find an other register that is free. Let me know.
Tested:
The same situation:
On devLedPORT leds are flashing. On PORTC no leds are on.
When stream data is sent over UART at 19200 baud no led again is set. I would expect that at least one should change state when event is fired.
Have you set cfgUseEvents to cfgTrue (in configfile)?
Never mind, you stated you did.
Please always have in mind that it might be me doing something stupid. I do not have too mush coding experience.
Solved problem with events and ISR.
It pays to "Clean project" command from time to time.
System works as intended. Cad do 19200 baud continuous stream data and 38400 baud keyboard data.
Will have some finished code soon.
Best regards.
Indeed, you learned it the hard way :-(. Anyway, nice you tackled the problem! BTW, i always clean before compile, and this is my practice for so long now, that i had forgotten about the effects it may give when you don't. Programs are so small that the extra compile time does not outweighs the time spend searching for strange bugs!
So it seems that 38400Kbd, which requires a guaranteed response time of 200us/char is just too much. I am a little surprised, but maybe you can get some extra speed if you deactivate all QA check functions. Thus, set all cgfCheck…. definitions to cfgFalse. The other thing you can do is to use the register compression facility. But be prepared to suffer, since this is the last optimization step to be taken, and may quickly result in the program going haywire. So this is only the last resort.