Hi Sergio I would suggest to look at existing OS for small embedded systems like Nut/OS or FreeRTOS. The latter even has a port for MSP430 and all of those need to solve the "Context switch problem". The uC/OS book is also a very good introduction into that topic.
Best Matthias On 07.12.2011, at 11:56, Sergio Campamá wrote: > Thanks for the tips Wayne! > > Talking about the context switch problem, could I obtain the registers in C > code? What I was thinking was not doing the context save into other stacks, > but into C structs, preallocated on compile time (this would limit the amount > of simultaneous context switching). And use the same stack pointer for the > new tasks… > > Best regards, > --------------------------------------- > Sergio Campamá > sergiocamp...@gmail.com > > > > > On Dec 7, 2011, at 12:13 AM, Wayne Uroda wrote: > >> When an interrupt is generated, the hardware pushes the PC and then the SR >> onto the stack. The hardware then clears the SR and loads PC with the >> appropriate interrupt address. >> >> In MSPGCC, the first thing the compiler does on entry to an interrupt >> routine is push any registers clobbered during the interrupt routine to the >> stack. Then the interrupt work is done, then the registers are popped in the >> reverse order, then the RETI instruction causes the machine to pop back the >> SR and then the original PC is popped. >> >> So if you want to do a context switch in your interrupt routine, you should >> push ALL the registers to the stack as you have indicated. You will have to >> break out some assembly code to do this. You will also (I'm guessing) need >> to stop GCC from generating the interrupt related pushes and pops. Probably >> best to write this whole interrupt handler in assembly so you can be sure >> what is going on. >> >> So, you will need to do the following (Note that R0 to R3 are PC, SP, SR, >> and CG respectively) (this code surely doesn't work verbatim, it is just an >> example) >> >> /* start of ISR */ >> /* first save all the general purpose registers to the stack */ >> push r15 >> push r14 >> ... repeat >> push r5 >> push r4 >> >> /* now we can do a context switch by swapping the SP with another VALID >> context */ >> /* first back up the old SP to some address, then load in the new SP */ >> /* choosing the new context can be simple or complex, this depends on the >> type of scheduler you wish to use */ >> mov r1, &oldSP >> mov &newSP, r1 >> >> /* should clear whatever interrupt flag got us to this ISR in the first >> place */ >> TODO >> >> /* now we are operating in the new context, we should restore all registers >> and return from the interrupt */ >> pop r4 >> pop r5 >> ... repeat >> pop r14 >> pop r15 >> reti >> /* end of ISR */ >> >> This means that your new context has its own stack, so make sure that each >> context (stack) is big enough for all the functions that they need to >> execute between task switching. >> Note where I say "VALID context" - this must be a stack which already has >> registers r4 to r15 as well as the SR and PC to return to - otherwise you >> will get stack underrun when you execute the 12 pops and then the machine >> executes the 2 pops (SR and PC). >> >> The smallest possible size a context could be is then 14 words or 28 bytes, >> but this doesn't leave any room for the stack to grow during your actual >> function. >> >> If you want to perform only one function in this other context, maybe >> looking into nested interrupts would be better, as this scheme above will >> probably take a fair bit of effort to get working. >> >> There are plenty of free RTOS around on the internet, I have not used any on >> the MSP430 though, but they would have done this work already. >> >> As for link scripts, start with the GNU LD manual. Also look at the existing >> link scripts under the 'ldscripts' directory in your mspgcc installation. >> >> Your example of a system which uses a function which can be replaced >> on-the-fly (in flash I assume) could be archived by reserving a block of RAM >> (just a global array for example, word aligned), and at startup copy your >> function into this block. Then if the system receives a new function it can >> overwrite the old function in ram and execute it. The functions should share >> the same return type and parameters as you say, to make calling it from C >> easy (call it through a function pointer). >> >> Of course if you want it to be stored through a reset then yes, you will >> need flash, and yes you probably will need to write your own linker script >> to put the function at a known address and keep other functions out of its >> area. Keep in mind the smallest memory you can erase is a segment so you >> probably will want to put a whole segment (or multiple segments) aside for >> your loadable module. >> >> - Wayne >> >> -----Original Message----- >> From: Sergio Campamá [mailto:sergiocamp...@gmail.com] On Behalf Of Sergio >> Campamá >> Sent: Wednesday, 7 December 2011 12:34 PM >> To: Wayne Uroda >> Cc: Peter Bigot; mspgcc-users@lists.sourceforge.net >> Subject: Re: [Mspgcc-users] Enter LPM4 without missing the wakeup interrupt >> >> Hey, maybe I'm straying a bit from the conversation, but >> >> 1. Is there a way to obtain (and set) the registers? I want to try a feature >> where I create preemptive "threads", in which after certain interrupts, I >> will save the current context (registers) and the instruction line I was >> executing (which is already in the registers, the PC), and start executing >> from another address.. And when I'm done with that, reload the PC and all >> the other registers and resume working on that "thread"... I'm guessing that >> 8 * 16 = 128 bytes would be the least memory I would need for each context >> save. Is it not? >> >> 2. Where can I find tutorials or more info to read about custom linking >> scripts? I also want to try a feature where I have a base system setup and a >> special memory area reserved for a module, and when the base system receives >> a new module (with a flash memory proxy or whatever), it replaces the old >> one... I'm assuming the entry point for that module would have to be the >> same function name and the same memory address (is it not?) >> >> Best regards, >> --------------------------------------- >> Sergio Campamá >> sergiocamp...@gmail.com >> >> >> >> >> On Dec 6, 2011, at 11:10 PM, Wayne Uroda wrote: >> >>> Thanks. That is what I expected the wakeup keyword did so I am happy with >>> using it. >>> >>> I personally only use the critical and wakeup keywords. Of course putting >>> dint and eint calls at the start and end of the function is easy, but I >>> prefer critical as it saves the current state of GIE on the stack and pops >>> it on exit (whereas hand coding dint eint will always leave your function >>> with interrupts enabled). >>> >>> There is probably some easy macro I don't know about to push and then pop >>> the status register but if you push and then forget to pop I imagine you >>> might rip your hair out for a while trying to work out what is going on :) >>> >>> Our platform is fully hand coded from the ground up (custom C startup, >>> custom linker scripts, custom ELF based tools) to allow for custom >>> bootloader / firmware loading. So the critical and wakeup keywords will be >>> the least of somebody's worries should they ever need to port the code to >>> IAR ;) >>> >>> - Wayne >>> >>> -----Original Message----- >>> From: pabi...@gmail.com [mailto:pabi...@gmail.com] On Behalf Of Peter Bigot >>> Sent: Wednesday, 7 December 2011 11:59 AM >>> To: Wayne Uroda >>> Cc: mspgcc-users@lists.sourceforge.net >>> Subject: Re: [Mspgcc-users] Enter LPM4 without missing the wakeup interrupt >>> >>> On Tue, Dec 6, 2011 at 5:53 PM, Wayne Uroda <wayne.ur...@grabba.com> wrote: >>>> Thanks for the discussion - I apologise for my code sample having flaws, >>>> it isn't production code just something I threw together to illustrate the >>>> point. In my case I am only interested in the level of the pin (sleep when >>>> it is low, awake when it is high) and so I am not concerned with missing >>>> edges other than the critical edge which brings me out of LPM4. I am aware >>>> that I still need to be careful of the order in which I enable the >>>> interrupt/clear the ifg and disable interrupts before finally checking the >>>> level of the pin and entering LPM4 if appropriate. >>>> >>>> One thing that I have never done is use the on_exit macro - I use the >>>> wakeup keyword instead - I'm guessing there are potential problems with >>>> the wakeup keyword? >>> >>> The wakeup function attribute in mspgcc is equivalent to having >>> "bic_status_register_on_exit(0xF0)" in your interrupt handler (and >>> LPM4_bits is 0xF0). There's nothing intrinsically wrong with it >>> except that it's opaque, and will only do exactly that operation, so >>> you couldn't (for example) clear GIE on exit using it. >>> >>> Personally I never remember what "signal", "wakeup", "reentrant", and >>> "critical" as function attributes mean exactly, and if I encounter >>> them I have to go read the compiler source to remind me what they do. >>> As far as I know they're also specific to mspgcc, so people who use >>> IAR or CCS won't understand what you're doing either. >>> >>> Peter >>> >>>> >>>> - Wayne >>>> >>>> -----Original Message----- >>>> From: JMGross [mailto:msp...@grossibaer.de] >>>> Sent: Wednesday, 7 December 2011 12:47 AM >>>> To: MSPGCC mailing list, >>>> Subject: Re: [Mspgcc-users] Enter LPM4 without missing the wakeup interrupt >>>> >>>> >>>> Hello Wayne, >>>> >>>> you correctly detected a possible problem in your code, which from my >>>> experience really is an exception. Most 'coders' don't >>>> care for realtime influences and then wonder why the code doesn't work (or >>>> use a watchdog do reset the CPU when the code >>>> unexpectedly 'hangs'. >>>> >>>> A generic solution to your problem has already beenb pinted out. Set LPM >>>> and GIE in the same instruction. >>>> Both, the LPM bits as well as GIE are located in the status register, so >>>> it comes down to an atomic operation: >>>> BIS #(LPM4|GIE), R2 >>>> >>>> In this case, if an interrupt happened before GIE is set and LMP is >>>> entered, the following will happen: >>>> GIE/LPM is set. >>>> LMP is exited, since an ISR is pending. (I'm not sure whether the DCO/XT >>>> wakeup time does apply in this case) >>>> the instruction after the BIS is executed (it aslready had been fetched >>>> before the BIS was executed, hence the usual NOP after an LPM entry) >>>> the status register including the GIE and LPM bits is stored on the stack >>>> GIE ans LPM bits are cleared >>>> the ISR is executed. >>>> >>>> If the ISR doesn't manipulate the stored status register copy on the >>>> stack, then when exiting the ISR, teh SR is restord and LPM/GIE are >>>> in effect again. >>>> >>>> So if you clear the LPM bits inside the ISR (using the proper 'on_exit' >>>> macro!), MSP won't return to LPM. >>>> >>>> However, your code example has several more flaws. >>>> - When your ISR does not clear the IFG bit for th einterrupt, the ISR will >>>> be re-entered as soon as it exits. >>>> If it does, the port1.ifg.pin1=0 assignment will clear a possible next >>>> interrupt, and you'll miss it. >>>> - you enable porti.ie.pin1 in every loop. It stays enabled (unless the ISR >>>> disables it) and interrupts may >>>> happen all the time (or after this point) independently of LPM4. You >>>> should clear GIE on exit of the ISR too, >>>> so when main is awakened, no further interrupts are handled unless you >>>> want them again. >>>> - you check for port1.in-.pin1. But even if an interrupt happened, P1.1 >>>> might have gone low again in the meantime. >>>> It's better to set a global flag inside the ISR (don't forget to mark it >>>> volatile) and check this. >>>> - depending on the compiler capabilities, the use of bitfields may result >>>> in less efficient code. >>>> That's one reason why bitfields for the many registers (especially ports) >>>> have been removed from the 'official' >>>> header files. Especially since every bit operation is a RMW >>>> (read-modify-write) operation on the whole register >>>> (which may have side-effects that are easily missed when one jus tlooks on >>>> the bit oepration). >>>> Also, since the registers are 'volatile', manipulation of multiple bits in >>>> the same register results in multiple >>>> RMW operations. Due to the volatile nature of the registers, the compiler >>>> is not allowed to group them. >>>> (the sequential access might be intentional). >>>> >>>> If you want to implement a debounce feature, a typical way to do it is to >>>> start a timer inside the port ISR >>>> and disable port interrupts (PxIE=0). >>>> When the timer expires, the tiemr ISR will check for the current port pin >>>> state, re-enable port interrupts and >>>> depending on the port pin state will set a global flag and end LPM. >>>> It gets a bit more tricky if you have multiple interrupt pins, but there >>>> have been implementations discussed >>>> and posted in the 'official' MSP forum: e2e.ti.com. >>>> >>>> JMGross >>>> >>>> >>>> ----- Ursprüngliche Nachricht ----- >>>> Von: Wayne Uroda >>>> An: mspgcc-users@lists.sourceforge.net >>>> Gesendet am: 06 Dez 2011 00:40:59 >>>> Betreff: [Mspgcc-users] Enter LPM4 without missing the wakeup interrupt >>>> >>>> I have a question which isn't technically related to MSPGCC (more of a >>>> msp430 question) but I thought one of you smart people >>>> might know. >>>> >>>> Imagine the following scenario: >>>> >>>> /* 1*/ while (1) >>>> /* 2*/ { >>>> /* 3*/ if (!port1.in.pin1) >>>> /* 4*/ { >>>> /* 5*/ // Enable interrupt (rising edge) for pin 1.1 >>>> /* 6*/ port1.ies.pin1 = 0; >>>> /* 7*/ port1.ifg.pin1 = 0; >>>> /* 8*/ port1.ie.pin1 = 1; >>>> /* 9*/ >>>> /*10*/ // Enter sleep mode, but only if the pin is still >>>> not high >>>> /*11*/ if (!port1.in.pin1) >>>> /*12*/ { >>>> /*13*/ LPM4(); >>>> /*14*/ } >>>> /*15*/ } >>>> /*16*/ >>>> /*17*/ // Awake >>>> /*18*/ // Do real work here >>>> /*19*/ } >>>> >>>> The ISR for port1 interrupt just wakes up the processor from LPM4 and >>>> clears the IFG for pin 1.1. >>>> >>>> The problem I see is that there is a small window (between the execution >>>> of line 11 and line 13) where pin1.1 can go high, have >>>> the ISR handled and the IFG cleared, and then the system can incorrectly >>>> go into LPM4 even though pin1.1 is high. >>>> >>>> My thoughts are that the only way around this is to avoid using LPM4 and >>>> poll the state of pin 1.1, which is what I have done in >>>> previous designs. As far as I know there is no way to atomically enter >>>> LPM4 and enable interrupts so that the pending pin1.1 >>>> IFG can be handled AFTER entering LPM4, thus bringing the system out of >>>> LPM4. >>>> >>>> Has anybody come up against this? Is using LPM3 the best/only workaround? >>>> >>>> I am using 1 family chips, MSP430F148 in particular. >>>> >>>> Thanks, >>>> >>>> - Wayne >>>> >>>> ------------------------------------------------------------------------------ >>>> All the data continuously generated in your IT infrastructure >>>> contains a definitive record of customers, application performance, >>>> security threats, fraudulent activity, and more. Splunk takes this >>>> data and makes sense of it. IT sense. And common sense. >>>> http://p.sf.net/sfu/splunk-novd2d >>>> _______________________________________________ >>>> Mspgcc-users mailing list >>>> Mspgcc-users@lists.sourceforge.net >>>> https://lists.sourceforge.net/lists/listinfo/mspgcc-users >>>> >>>> >>>> ------------------------------------------------------------------------------ >>>> Cloud Services Checklist: Pricing and Packaging Optimization >>>> This white paper is intended to serve as a reference, checklist and point >>>> of >>>> discussion for anyone considering optimizing the pricing and packaging >>>> model >>>> of a cloud services business. Read Now! >>>> http://www.accelacomm.com/jaw/sfnl/114/51491232/ >>>> _______________________________________________ >>>> Mspgcc-users mailing list >>>> Mspgcc-users@lists.sourceforge.net >>>> https://lists.sourceforge.net/lists/listinfo/mspgcc-users >>>> >>>> ------------------------------------------------------------------------------ >>>> Cloud Services Checklist: Pricing and Packaging Optimization >>>> This white paper is intended to serve as a reference, checklist and point >>>> of >>>> discussion for anyone considering optimizing the pricing and packaging >>>> model >>>> of a cloud services business. Read Now! >>>> http://www.accelacomm.com/jaw/sfnl/114/51491232/ >>>> _______________________________________________ >>>> Mspgcc-users mailing list >>>> Mspgcc-users@lists.sourceforge.net >>>> https://lists.sourceforge.net/lists/listinfo/mspgcc-users >>> >>> ------------------------------------------------------------------------------ >>> Cloud Services Checklist: Pricing and Packaging Optimization >>> This white paper is intended to serve as a reference, checklist and point of >>> discussion for anyone considering optimizing the pricing and packaging model >>> of a cloud services business. Read Now! >>> http://www.accelacomm.com/jaw/sfnl/114/51491232/ >>> _______________________________________________ >>> Mspgcc-users mailing list >>> Mspgcc-users@lists.sourceforge.net >>> https://lists.sourceforge.net/lists/listinfo/mspgcc-users >> > > > ------------------------------------------------------------------------------ > Cloud Services Checklist: Pricing and Packaging Optimization > This white paper is intended to serve as a reference, checklist and point of > discussion for anyone considering optimizing the pricing and packaging model > of a cloud services business. Read Now! > http://www.accelacomm.com/jaw/sfnl/114/51491232/ > _______________________________________________ > Mspgcc-users mailing list > Mspgcc-users@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/mspgcc-users ------------------------------------------------------------------------------ Cloud Services Checklist: Pricing and Packaging Optimization This white paper is intended to serve as a reference, checklist and point of discussion for anyone considering optimizing the pricing and packaging model of a cloud services business. Read Now! http://www.accelacomm.com/jaw/sfnl/114/51491232/ _______________________________________________ Mspgcc-users mailing list Mspgcc-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mspgcc-users