## ## ## # ## ####### ##### ## ##
_ _ | | | | | |_| | | _ | | | | | \_| |_/
____ | _ \ | | | | | |_| | |____/
### ## ## ## ## ## ####
_ _ ( ) ( ) | | | | | | | | | \_/ | `\___/'
IMPORTANT: enter the case-INsensitive alphabetic (no numbers) code AND WRITE SOME SHORT summary of changes (below) if you are saving changes. (not required for previewing changes). Wiki-spamming is not tolerated, will be removed, so it does NOT even show up in history. Spammers go away now. Visit Preferences to set your user name Summary of change: '''Developer info to improve scheduler''' When * we move some high priority trigger-data processing to userspace * move some tables from SRAM to EEPROM (to free space for MMC logging and networking), where there are limits of when it can be accessed for read (not during EPPROM write). ** the EEPROM write (if there is a demand) can only start right after all necessary variables for fuel VE/lambda/ign calc had been cached in SRAM (seach_table result and 2x2 grid of each table). ** Also, the above cached table-data cannot be updated during EEPROM write (new calc would be possible nevertheless, with some boundary-check consideration ; but easier to avoid it, and only recalc new injPW from changed MAP if it's absolutely needed within 8.5 msec; many competition controllers cannot even finish a full calc within that period) ** when these userspace calcs are allowed (not in EEPROM write and at least 4 msec passed since last) they can be medium priority * implement more convenience features the simple scheduler used now (mainloop) must be improved so latency of some high-priority actions is improved. See the priority ideas on GenBoard/UnderDevelopment/FirmWare Even though it is relatively simple, it's a good idea to model it in JAVA first (see ''package org.vemsgroup.firmware.scheduler'' in JTune CVS) to verify operation (and maybe tune some variables). Similar scheduler is implemented in most real-time operating systems. See task-states on an [http://www.on-time.com/index.html?page=rtpeg32.htm an x86 RTOS]. However we don't need preemptive multitasking. Cooperative is fine. So no need for separate stack for each process. When the process returns, it's stack is back to normal anyway. Timing sensitive tasks must be done in interrupt or high-priority process. A nice OS with non-preemptive multitasking running on the atmega16 (gpl and compilable with avr-gcc) can be found here [http://www.ethernut.de/en/software.html ethernut.de] ---- I created a very simple scheduler: (some stuff like interrupt management is left out) <code> void scheduler_run(void) { for(;;) { func = schedule_list[current_sched]; schedule_list[current_sched] = NULL; current_sched++; if(func) { func(); } if(current_sched == Last_Prio) { scheduler_sleep(); } } </code> I've decided to instead of having 4 different queues I just have one huge. Every 'task' has an entry in a large enum, where being first means having more priority. While this would be very convenient, since it is already implemented (for slightly different purpose) in lcd.c find_dirty(), unfortunately this is not suitable, because it results in "starvation". Ok, I think I know what you're worried about; two (or more) tasks that run everytime without ever sleeping (calling add_schedule everytime it ends in my implementation). Using queue seperation and round-robin you assert that every task would be called, while in my implementation the higher priority task would always starve the lower one. But is this really a problem? Do we have any functions that absolutely needs to be called 100 times more often than the primary_trigger? From userspace? scheduler_sleep() is putting the AVR to sleep. I think this is very dangerous, this is the easiest to get wrong. For battery powered systems it's worth it, but v3 consumes appr. 100 mA so we cannot save significant power. Any IO or interrupt (eg. handler2k) will wake AVR up from sleep. On the emulator this will probably be a semaphore. <code> void scheduler_add(prio_t prio, func_t function) { if(current_sched > prio) current_sched = prio; schedule_list[prio] = function; scheduler_wakeup(); } </code> This function can both be called from interrupt context or from userspace (if one task wants to run another). scheduler_wakeup() is a NOP on AVR. Emulator will signal the semaphore. Any task may re-schedule itself either by calling scheduler_add itself, or using the eventqueue to schedule itself sometimes in the future. ''Can I use the existing eventqueue for this?'' We only set schedule flags from interrupt/eventqueue when we are there for other reason (eg. trigger, or action). Otherwise userspace actions should not use interrupt for this. However if you feel uncomfortable to do many false comparisons (like softelapsed does), a second heap maintained from userspace is perfect. Just like eventqueue, but separate heap and actions from it are only executed when the scheduler thinks right (not asynchronously): * not delaying any high priority task * and no race/locking issues. Resolution can be any. Proposed: 1 msec and 16 bit keys on AVR (32 bit on ARM) Dispatcher actions are also independent. 16 bit is perfect, no need to spare clocks by using 8 bit values. Optional: Add document to category: Wiki formatting: * is Bullet list ** Bullet list subentry ... '''Bold''', ---- is horizontal ruler, <code> preformatted text... </code> See wiki editing HELP for tables and other formatting tips and tricks.