> I think you're missing the bigger picture here. A short busy-wait > isn't going to have much effect on a PIC application, whether it's > Salvo-based or not. In either case, interrupts can still proceed, and > the rest of the application is "held up" while the busy-wait occurs. > This would be the case in any superloop application, in any > cooperative RTOS, and also in a preemptive RTOS with preemption > (temporarily) disabled -- makes no difference. This is not related to the point you are trying to make in this paragraph, but you keep characterising the non-RTOS option as a very stupidly written "superloop". There are more intelligent designs than what you describe that are easy to do and certainly don't require buying an RTOS. Most forground "threads" can be handled very nicely by an an event loop, since most of the time things are event driven. I usually have my foreground code enter an endless loop for main system operation. It checks all the events that could require service, and jumps to an event routine if one does. One of the difference from what you describe is that event routines jump back to the start of the event loop when done. This provides some event priority, which is often useful. Most event routines are short. If handling one "event" requires waiting for something else to happen, then you just think of this as two events. A common example of this is reading the A/D. One event starts the conversion, and another event fires when the conversion is complete. This is really very easy to do with a little thinking about the design. You can see an example of such an A/D handler in HAL_AD.ASPIC at http://www.embedinc.com/pic/hal.htm. The event loop is in the HAL_MAIN.ASPIC module. One exception to the above scheme that comes up regularly is handling a command input stream from the UART or something while continuing all the other foreground processing. This looks the same to the event loop, because the event is that an input character is available to be processed. However, since a command processor is often highly state driven, the event model would be too cumbersome because there would be a large number of possible events, depending on where you are in the command processing sequence. To get around this, I create a macro that fakes a call to "get" the next input byte. It really saves the program address immediately following the macro call and returns to the event loop. The event handler for dealing with a new input byte gets this address and jumps to immediately following the macro, thereby "returning" with the next byte. You could say this is essentially a cooperative thread of an RTOS, but this is so simple to do yourself it hardly justifies purchasing one. In case anyone doesn't believe this, I have provided the source code below. It is exactly 42 lines long if you eliminate the 111 comment and blank lines. Big deal. ; *************************************************************** ; * Copyright (c) 2001, Embed Inc (http://www.embedinc.com) * ; * * ; * Permission to copy this file is granted as long as this * ; * copyright notice is included in its entirety at the * ; * beginning of the file, whether the file is copied in whole * ; * or in part and regardless of whether other information is * ; * added to the copy. * ; * * ; * The contents of this file may be used in any way, * ; * commercial or otherwise. This file is provided "as is", * ; * and Embed Inc makes no claims of suitability for a * ; * particular purpose nor assumes any liability resulting from * ; * its use. * ; *************************************************************** ; ; ;*********************************************************************** ; ; Configuration constants. ; nsave equ 5 ;num regs saved accross GETBYTE, starts with REG1 lbank equ 1 ;register bank for the local state of this module ; ; Derived constants. ; lbankadr equ bankadr(lbank) ;address within local state register bank ; ;*********************************************************************** ; ; Local state. ; if lbank != gbank .bank#v(lbank) udata endif injump res 2 ;where to jump on next input byte saveregs res nsave ;save area for registers accross GETBYTE invocations .cmd code ; ;*********************************************************************** ; ; Macro GETBYTE ; ; The code in this module gets run whenever a new input byte is available. ; This macro makes it appear as if the code in this module is a separate ; thread that goes and gets the next input byte. It saves a restart address, ; then returns to the main event loop. When CMD_BYTE gets envoked the next ; time, it resumes execution at the restart address. ; ; This macro therefore appears like a subroutine call that returns with ; the next input byte in REG0. The register bank assumptions must be ; correct when this macro is used. ; ; From the caller's point of view, REG0 is returned with the new input ; byte, REG1 - REG are preserved, and the remaining registers are ; trashed. ; getbyte macro local restart ; ; Set the address at which to restart next time. This is the address ; immediately after this macro. ; dbankif lbankadr movlw low restart ;save where to restart next time movwf injump+0 movlw high restart goto getbyte2 ;to non-replicated code to do the rest ; ; Set the assembler state to indicate the register bank settings. ; The settings are a function of the code in CMD_BYTE that jumps to the ; restart address. ; restart ;end up here next time CMD_BYTE is envoked dbankis lbankadr ;direct register set for access to local state ibank? ;indirect bank setting is unknown endm ; ;********** ; ; This section of code is only run implicitly from the GETBYTE macro. ; There is only one copy of this code at a fixed location, whereas ; the GETBYTE code is replicated for every use of the macro. This code ; is jumped to from GETBYTE to perform as much of the GETBYTE operation ; as possible that is not unique to each individual invocation of GETBYTE. ; This reduces redundant code which would otherwise be produced for each ; GETBYTE invocation. ; getbyte2 ; ; The low byte of the restart address has already been saved in INJUMP+0, ; and the high byte is in W. Now save the high byte into INJUMP+1. ; The direct register bank is set for access to the local state. ; dbankis lbankadr movwf injump+1 ; ; Save some of the registers locally. These will be restored when ; CMD_BYTE is run next before it jumps to the restart address. ; dbankif lbankadr copyn saveregs, reg1, nsave ;save the preserved registers gjump loop_main ;back to the main event loop ; ;*********************************************************************** ; ; Subroutine CMD_INIT ; ; Initialize the state managed by this module. ; glbsub cmd_init, noregs dbankif lbankadr movlw low cmd_start ;init to where to start processing next in byte movwf injump+0 movlw high cmd_start movwf injump+1 leaverest ; ;*********************************************************************** ; ; Routine CMD_BYTE ; ; This routine is jumped to from the main event loop when there is an ; input byte available from UART_GET. ; glbent cmd_byte gcall uart_get ;get the input byte into REG0 ; ; Restore the registers that are preserved accross invocations of the ; GETBYTE macro. ; dbankif lbankadr copyn reg1, saveregs, nsave ;restore the preserved registers ; ; Jump to the restart address. The restart address was saved by GETBYTE ; before it jumped back to the main event loop. ; dbankif lbankadr movf injump+1, w ;get restart address high byte movwf pclath ;set jump address high byte movf injump+0, w ;get restart address low byte movwf pcl ;jump to the restart address ; ; The restart address is jumped to with the direct register bank set for ; access to the local state. The indirect register bank setting is unknown. ; ******************************************************************** Olin Lathrop, embedded systems consultant in Littleton Massachusetts (978) 742-9014, olin@embedinc.com, http://www.embedinc.com -- http://www.piclist.com hint: PICList Posts must start with ONE topic: [PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads