I'm using Salvo Pro for a product that has multiple AVR's communicating over an I2C bus. The documentation for Salvo is excellent and the tutorials very helpful.
This is the first Cooperative RTOS that I've used and it has taken me awhile to readjust my thinking on how to structure a solution without the use of preemption.
It has also taken me awhile to get my head wrapped around the fact that I can not invoke an OS service that would block in a function that was called from a task. Any OS service that returns control to the scheduler must be called only from within a task itself. However, I do understand the reason for this.
Here'a an example. I've written several functions to control the character LCD. One of these functions clear the display. Since the clear operation takes up to 1.6mS, my first thought was to call to OS_Delay() with a 1 tick delay in the LCD_Clear function itself. But this is not permitted. So, I have to have the OS_Delay() call in the task after the call to LCD_Clear(). This makes it a bit more of a challenge to isolate the low-level code from the application code.
My solution was to wrap up all of the LCD control functions into a single task that waits on a message queue. My application code creates a message with the appropriate arguments and (after obtaining a lock on the LCD) passes this message (a pointer to a struct of type lcd-control) to the lcd control task. All low-level LCD operations are handled in this lcd control task. I do have higher level operations such as LCD_Printf() that I call from a task in the application. These higher-level functions handle the work of creating and sending the message to the lcd control task.
Overall, I find Salvo to be a solid RTOS for use with the AVR. I also like the fact that it is avalable for other processor platforms.
What RTOS are you using on the AVR?
Does anyone else have experience with Salvo?