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

Reply via email to