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