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

Reply via email to