Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem


Loading

portSTACK - 20-bits

Posted by John W. on July 28, 2007
Hello,

I'm working on a port in which the portSTACK type needs to be 20-bits - has anyone done a port with this being 20-bits wide?
If so - can you elaborate on how you made it work?

Thanks,
John W.

RE: portSTACK - 20-bits

Posted by Richard on July 28, 2007
How does this work then at the processor level? Is the RAM 16bits wide, or 20bits wide?

Regards.

RE: portSTACK - 20-bits

Posted by John W. on July 28, 2007
Richard,

Registers can be used in either 16 or 20-bit mode.

Memory is addressable to 1MB; so addresses can go to 20-bits. RAM is 16-bits wide. Wordsize is 16 bits.

Issue I'm having is using memory above 64K. RAM resides in lower 64. Flash is only located above 64K.

Thanks,
John





RE: portSTACK - 20-bits

Posted by John W. on July 28, 2007
Richard,

I guess I should've said real issue is pushing 20-bit registers on the stack and how to handle in port.c ....

Thanks,
John W.

RE: portSTACK - 20-bits

Posted by Richard on July 28, 2007
The PIC24 does simlar things. Pointers are 16bits, but the address space is 24bits - which makes it seem tricky to point to the start address of a task. Luckily in this case the compiler takes care of it for you through the use of a poitner jump table.

So what does the processor do when it stacks 20bit registers into 16bit wide RAM? (I could always read the datasheet but I'm a bit pushed for time). Does it just loose 4bits of the third register byte? The MSP430 has quite a few registers, so this would seem wastefull, but maybe this is not a problem as you get a lot more memory space to play with.

Is your problem then that you cannot declare the stack type as 16bits, as they are in fact 20bits, and you cannot declare the stack type as 32bits, as this gives you a whole byte (plus the 4 bits) too much (sorry for basic questions). Seems a bit tricky.

Regards.

RE: portSTACK - 20-bits

Posted by John W. on July 28, 2007
Richard,

Yes - I can't declare portSTACK as 20-bits wide.

From the datasheet on a push:

The stack pointer (SP) is decremented by two (byte and word
operands) or by four (address-word operand) before the write operation.

From the datasheet for a pop:

The stack pointer SP is incremented by two (byte and
word operands) and by four (address-word operand).

Thanks,
John

RE: portSTACK - 20-bits

Posted by Richard on July 28, 2007
It sounds like it is using 32bits per 20bit value, in which case this would make the stack type unsigned long. You would have to setup the initial stack in port.c using 4bytes per 20bit register.

Regards.

RE: portSTACK - 20-bits

Posted by John W. on July 28, 2007
Richard,

Yes - that's what I'm trying to do now.

I'll let you know how it goes.

Thanks,
John

RE: portSTACK - 20-bits

Posted by John W. on July 28, 2007
Richard,

Looks like everything is OK up until the portRESTORE_CONTEXT when xPortStartScheduler is called - as soon as the reti is called - the app goes into the weeds.
Everything looks ok - the starting addr of the 1st task is where it's supposed to be - but it's 32 bits now vs. 16 (or 20) - maybe that's where things are going wrong...

Regards,
John

RE: portSTACK - 20-bits

Posted by Richard on July 28, 2007
In your debugger, are you able to break in an interrupt routine, then inspect the stack just before a compiler generated reti instruction, so you can inspect the stack to see how the address is stored? You can then copy this. Maybe there is some magic somewhere, as per the PIC24 jump table mentioned previously.

Regards.

RE: portSTACK - 20-bits

Posted by John W. on July 28, 2007
Richard,

One of the issues is in port.c - if everything is made 32-bits - including pxCode and portFLAGS_INT_ENABLED - from the databook
on RETI:

RETI Return from interrupt
Syntax RETI
Operation @SP → SR.15:0 Restore saved status register SR with PC.19:16
SP + 2 → SP
@SP → PC.15:0 Restore saved program counter PC.15:0
SP + 2 → SP House keeping
Description The status register is restored to the value at the beginning of the interrupt
service routine. This includes the four MSBs of the program counter PC.19:16.
The stack pointer is incremented by two afterwards.
The 20-bit PC is restored from PC.19:16 (from same stack location as the
status bits) and PC.15:0. The 20-bit program counter is restored to the value
at the beginning of the interrupt service routine. The program continues at the
address following the last executed instruction when the interrupt was granted.
The stack pointer is incremented by two afterwards.

Looks like 16-bit values are expected - not 32-bit. I did a fix up on this and got a little further down the road - but the app still goes in the weeds.

Since I had the portFLAGS_INT_ENABLED set to be 0x08 - this was stored as 0x00000008 - and after the RETI was done - the 0x0008 was being grabbed by the SR but the
PC was being set to 0x0000; The task's address was after that - stored as 0x0000383E; - but the PC didn't get that far since jumping to weed-land at 0x0000;

I'm going to have to stop for today but I'll be back at it this weekend.

Thanks,
John

RE: portSTACK - 20-bits

Posted by Richard on July 28, 2007
So 4 bits of the program counter are stored in the unused bits of the stack pointer. Looks like you are going to have to do some shifting of values in pxPortInitialiseStack() to get everything in the right place. There is a port that does this already I think (?) but I cannot remember which processor it is.

Can you provide me with a part number or a link to a document that describes the architecture? I've looked at a couple on the TI site but they seem to have 16bit program counters.

Regards.

RE: portSTACK - 20-bits

Posted by John W. on July 28, 2007
Richard,

Yes, I did some shifting at the beginning of xPortInitializeStack() but more needs to be done.

The MPS430 Family is the MSP430FG4XXX - the one's I'm using specifically are the

MSP430FG4618 and
MSP430FG4619

The datasheet can be downloaded from:

http://focus.ti.com/lit/ds/symlink/msp430fg4618.pdf

The UG can be downloaded from:

http://focus.ti.com/lit/ug/slau056f/slau056f.pdf

Chip errata can be downloaded from:

http://focus.ti.com/lit/er/slaz028f/slaz028f.pdf

Main Page for the 'FG4618:

http://focus.ti.com/docs/prod/folders/print/msp430fg4618.html

Thanks!
John


RE: portSTACK - 20-bits

Posted by John W. on July 29, 2007
Richard,

I'm getting to the first vTaskDelayUntil - and when the RETA is executed - it bombs.

It looks like the SP may be off by one word - I just took a closer look in the debugger - and for some reason - this is what it looks like -
there's a popw.m #6,R11 in vPortYield(); - and it looks like where the SP is pointing is SR info - (one word) - then the address of what should be executed - like
what you'd expect in a reti - but in this case it's a RETA - from the datasheet:

* RETA Return from subroutine
Syntax RETA
Operation @SP → PC.15:0 LSBs (15:0) of saved PC to PC.15:0
SP + 2 → SP
@SP → PC.19:16 MSBs (19:16) of saved PC to PC.19:16
SP + 2 → SP
Emulation MOVA @SP+,PC
Description The 20-bit return address information, pushed onto the stack by a CALLA
instruction, is restored to the program counter PC. The program continues at
the address following the subroutine call. The status register bits SR.11:0 are
not affected. This allows the transfer of information with these bits.

So - this is different than RETI - the SR isn't affected - so the PC is picking up what looks like the SR info and then entering weed-land.

But - it looks like the SP is pointing to what would be expected by a RETI vs. a RETA.

At least this is progress...

Thanks,
John W.



RE: portSTACK - 20-bits

Posted by John W. on July 29, 2007
Actually the above is in taskYield() - immediately following the call to vPortYield()...

John

RE: portSTACK - 20-bits

Posted by David Hawks on July 30, 2007
It is interesting to note that the stacking of the address is different between CALLA/RETA and Interrupt/RETI. In the interrupt case PC.15:0 is pushed first, while in the CALLA case PC.15:0 is pushed last.

RE: portSTACK - 20-bits

Posted by John W. on July 30, 2007
Looks like the issue is boiling down to differences in RETI, RETA, and RET.

Regards,
John

RE: portSTACK - 20-bits

Posted by John W. on August 3, 2007
Richard,

After doing the 'shift fix-up' - could that affect the tskTCB down the road? I've looked that this and don't think so - but wanted to see what
you thought.

Thanks,
John

RE: portSTACK - 20-bits

Posted by John W. on August 3, 2007
1st context switch from IDLE to LEDx task is where this is currently dieing...

RE: portSTACK - 20-bits

Posted by Richard on August 3, 2007
I would not have thought so....but

Regards.

RE: portSTACK - 20-bits

Posted by John W. on August 3, 2007
Richard,

Yep - I think ...but may be right here.

I'll revisit this when I get time - or when trying to help others like Penn gives me those 'oh yeah' moments thus causing me to check things out...

Regards,
John W.

RE: portSTACK - 20-bits

Posted by John W. on August 3, 2007
Richard,

I think I may have mentioned this before - I do get 166 ticks on the clock before the <kablam!> happens - so that indicates a lot is working OK.

Regards,
John

RE: portSTACK - 20-bits

Posted by plinder13 on August 8, 2007
I'm not sure where you are at now, but I have a few thoughts - which may just be re-iterating what has been said so far.

Since it is possible for a context switch to occur while the PC is in 20-bit space, the portSAVE_CONTEXT and portRESTORE_CONTEXT macros probably have to handle by default the 20-bit case. This means that all of the push and pops need to be the .A versions so that the 20-bit registers are pushed onto the stack. Since this requires 32-bits per register, this requires twice as much stack space relative to the 16-bit version. This means that the CCE compiler needs to use the mspx core as the msp core does not support the extended instruction set.

In the portYIELD() function, the stack will have to be manipulated to combine the upper 4 bits of the PC with the SR as well as reversing the word order. This will be difficult as it seems that the PC19:16 needs to be shifted to the left and have the SR added to it, without affecting the SR in the process (if you figure this out before me, please post the code), followed by a swap of this location and the location on the stack containing PC15:0. It may end up being easier to push the SR onto the stack, and use portRESTORE_CONTEXT with the RETA instruction (however, this would still require some manipulation for the case of the the portTICK_ISR(), since the stack coming in due to an interrupt is not correct for a RETA instruction).

All of this assumes that portYIELD() is called with a CALLA instruction (not a CALL instruction). This also means that you need to make sure the compiler is using the CALLA instruction when calling portYIELD() so that the stack is as expected. I think the Large Memory Model option in the CCE compiler forces all functions to use CALLA and RETA.

Hope this at least spurs some thoughts. I probably also will be working on a port for CCE as I just had to shift from the F449 to the FG4618 due to a need for RAM.

Penn

RE: portSTACK - 20-bits

Posted by John W. on August 8, 2007
Penn,

I might suggest just using the 'FG4618 in 430 mode for now vs. 430X mode. You will have access to all peripherals save FLASH
above 0xFFFF.

I'm busy working on a C8051 IAR port at the moment so I won't be back on this for a while.

I do have a stable 430-mode port running on the 'FG4618 (IAR).

Regards,
John

RE: portSTACK - 20-bits

Posted by plinder13 on August 8, 2007
I have a port attempted - figured out the assembly code I need. However, when I start the schedular, and step through the taskRESTORE_CONTEXT() macro, it resets when a popx.w r15 instruction executes. The SP seems to be pointing to a valid, even, RAM location. Any ideas?

Penn

RE: portSTACK - 20-bits

Posted by John W. on August 8, 2007
You're not running in 'true' 430X mode (I just made that 'definition' up - so it's somewhat tongue-in-cheek) - but the pop
instruction should be:

popx.a r15
....

If 430 & 430X modes get mixed - you get bits 'lurking' in the upper 4 positions - and end up with a situation that doesn't
work - which sounds like what is happening.

You may have to some assembler to get this to work - look at the Rowley MSP430 port for some starting ideas or look at the
MSP430 ports on my site.

I don't think you will have 100% control on when the compiler decides to use CALL vs. CALLA - which could lead to the above -
which is why you may need to convert some routines to assembler.

HTH,
John W.


RE: portSTACK - 20-bits

Posted by John W. on August 8, 2007
Maybe a way to 'fix' this is to issue CLR instructions at the appropriate time - would be useful if TI had supplied a
'CLEAR MULTIPLE' command - i.e. - CLRM.A command.

This in fact may be a way to fix the problem.

The 20 vs. 16 bit issue is particularly ugly if the PC gets corrupted in 16 vs. 20-bit mode - meaning the upper 4 bits are set when the PC is restored to a 'near' address making the PC happily jump into weedland - somewhere > 0x10000 (running in 430 mode).
20-bit push occurring when a 16-bit should've occurred - or 20-bit pop occuring where 16-bit should've occurred - or vice-versa.

Regards,
John W.

RE: portSTACK - 20-bits

Posted by plinder13 on August 8, 2007
From what I understand, it is ok to "mix" popx.w and popx.a. I believe that when popx.w Rn is used, it automatically clears bits 19:16 of Rn while placing the word on the stack into 15:0, and decrements the stack pointer by 2. I am stepping through the code and the stack pointer is in RAM - the upper 4 bits of the SP are clear - right before the "popx.w R15" sends my debugger into the weeds. Issuing a popx.w R15 command shouldn't affect either the SP or the PC, so I am confused why stepping into this instruction is causing my debugger to go into the weeds. I will change it to a popx.a instruction just for a test to see if it improves my situation (knowing I will have to change the corresponding pushx.w instruction to pushx.a as well). I suspect that there is something else going on that I am missing and the debugger is not showing me good information.

Penn

RE: portSTACK - 20-bits

Posted by plinder13 on August 8, 2007
BTW, I think the CCE compiler uses strictly CALLA and RETA when using the mspx core.

RE: portSTACK - 20-bits

Posted by John W. on August 9, 2007
Wouldn't count on it. If you're operating in the lower 64 - then CALL's work fine. I would think a 'short' call would only
use CALL's. I wouldn't trust any compiler until I looked at 100% of the assembly in this case.

RE: portSTACK - 20-bits

Posted by plinder13 on August 9, 2007
CCE says that to mix assembler and C, always use CALLA and RETA in the assembler. This implies that all the functions use this, as otherwise a C function could be called from assembler with a CALLA that returned with a RET.

I figured out my bug - I was writing to an undefined are of the SFRs - pointer issue. The debugger was masking it as it is slow and awkward with the MSP430X.

Here are some snippets of my port. Note that the portSTACK_TYPE should be portSTACK_SHORT as in other MSP430 ports, even though some function pointers are 20-bits. This works because all stack pointers are in RAM and are 16-bit.

#define portSAVE_CONTEXT()\
asm (" pushm.a#12,r15");\
asm(" movx.wusCriticalNesting,r15");\
asm (" pushx.wr15");\
asm ( " movx.wpxCurrentTCB,r12");\
asm ( " movx.wr1,0(r12)");

#define portRESTORE_CONTEXT()\
asm (" movx.wpxCurrentTCB, r12");\
asm(" movx.w0(r12),r1");\
asm(" popx.wr15");\
asm(" movx.wr15,usCriticalNesting");\
asm(" popm.a#12,r15");\
asm (" reti");

void vPortYield( void )
{
/* We want the stack of the task being saved to look exactly as if the task
was saved during a pre-emptive RTOS tick ISR. Before calling an ISR the
msp430 places the status register onto the stack. As this is a function
call and not an ISR we have to do this manually. */
asm ( " pushx.w r2" );
_DINT();
/* Make stack look like we entered form an ISR instead of a CALLA */
asm ( " bicx.w #0xF000,0(r1)");
asm ( " swpbx.w+4(r1)");
asm ( " rlax.w+4(r1)");
asm ( " rlax.w+4(r1)");
asm ( " rlax.w+4(r1)");
asm ( " rlax.w+4(r1)");
asm ( " addx.w +4(r1),0(r1)");
asm ( " movx.w +2(r1),+4(r1)");
asm ( " movx.w 0(r1),+2(r1)" );
asm ( " incdx.ar1");
...

The pushm.x #n,Rx instruction and corresponding popm.x instruction, while placing n registers on the stack with one instruction, place the registers on the stack in the opposite order of pushing and popping one at a time. Therefore, the pxPortInitialiseStack function needs to account for this and reverse the R4 to R15 initialization values.

portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
{
/*
Place a few bytes of known values on the bottom of the stack.
This is just useful for debugging and can be included if required.

*pxTopOfStack = ( portSTACK_TYPE ) 0x1111;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x2222;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x3333;
pxTopOfStack--;
*/

/* The msp430 automatically pushes the PC then SR onto the stack before
executing an ISR. We want the stack to look just as if this has happened
so place a pointer to the start of the task on the stack first - followed
by the flags we want the task to use when it starts up. */
*pxTopOfStack = ( portSTACK_TYPE ) pxCode;
pxTopOfStack--;
*pxTopOfStack = ((( portSTACK_TYPE )((((unsigned long)(pxCode)) >>4) & (0x0000F000))) | portFLAGS_INT_ENABLED);
//*pxTopOfStack = portFLAGS_INT_ENABLED;
pxTopOfStack--;

/* Next the general purpose registers. */
/* When the task starts is will expect to find the function parameter in
R15. */
*pxTopOfStack = (portSTACK_TYPE) ((((unsigned long)pvParameters)>>16) & (0x0000000F));
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) pvParameters;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x000e;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0xeeee;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x000d;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0xdddd;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x000c;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0xcccc;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x000b;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0xbbbb;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x000a;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0xaaaa;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0009;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x9999;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0008;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x8888;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0007;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x7777;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0006;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x6666;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0005;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x5555;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0004;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x4444;
pxTopOfStack--;

/* The code generated by the mspgcc compiler does not maintain separate
stack and frame pointers. The portENTER_CRITICAL macro cannot therefore
use the stack as per other ports. Instead a variable is used to keep
track of the critical section nesting. This variable has to be stored
as part of the task context and is initially set to zero. */
*pxTopOfStack = ( portSTACK_TYPE ) portNO_CRITICAL_SECTION_NESTING;

/* Return a pointer to the top of the stack we have generated so this can
be stored in the task control block for the task. */
return pxTopOfStack;
}

Penn

RE: portSTACK - 20-bits

Posted by John W. on August 9, 2007
Penn,

Looks like you have solved this - great job!

As long as a vPortYield will always occur during a CALLA/RETA frame - this should always work. I wasn't 100% sure this could be relied upon since I wasn't sure the compiler wouldn't 'mix' CALL and CALLA frames.

I will code up a test and try to force calls with function pointers > 0x10000 to be yielded to make sure this works in all instances.

Thanks!
John W.

RE: portSTACK - 20-bits

Posted by plinder13 on August 9, 2007
I'll try to remember to send you my port.c and portmacro.h tomorrow when I get back to work.

Penn

RE: portSTACK - 20-bits

Posted by John W. on August 10, 2007
Penn,

OK - please do that.

I just tried this - plus I tried some ideas I had -

definitely got the system running with some tasks running - but -

I have a RX_IRQ that caused the system to crash only after a few times of it being used - so evidently there's still some work to do.

This is good progress though.

Thanks,
John W.

RE: portSTACK - 20-bits

Posted by plinder13 on August 10, 2007
How many times is your TICK running before it crashes (ie, is it crashing on the first tick or have you concluded it is definately related to the RX_IRQ)?


RE: portSTACK - 20-bits

Posted by John W. on August 10, 2007
Penn,

As I mentioned - several tasks are actively running - LED's blinking, several IRQ's running, etc. The xTickCount counter has rolled many times before this happens.

Please check this if you would on your end with a serial ISR maybe doing something simple like copying received chars and just echoing them back out.

The same code I have runs fine in 430 mode - so the error is more than likely related to the port (430X).

Are you able to run the demo code in 430X mode - including the Serial ISR demo, with no problem?

Thanks,
John


RE: portSTACK - 20-bits

Posted by plinder13 on August 10, 2007
I have not tried the demo code as I have my own hardware and software - a completely different application.

I have TIMERB interrupts going - they are yielding and resuming tasks. I also have a simple serial ISR that collects data and places into a buffer - but I haven't tried it yet as I am waiting on some other hardware.

Could you send me or post a copy of your serial ISR so I can take a quick look at it?

Also, the stack size needs to increase when using the 430X because the full 20-bits of the registers are saved on the stack (consuming 4-bytes) instead of just the lower 16-bits. Perhaps your ISR is interrupting a task that is near the end of the stack.

Penn

RE: portSTACK - 20-bits

Posted by John W. on February 14, 2008
Penn, et. al,

I have the IAR (4.10D) port running on the TI MSP430(X) Experimeter Board - using the latest posted v.4.7.1 FreeRTOS 'core' code.
There are a few differences with my board(s) - I have the '4619 on my board(s) vs. the '4618 - and I'm using an 8MHz clk (X1)
on my board(s).

I have the LED demo running - LED's 1, 2, and 4 - and I have the Com Test Running - 115.2KB - running out of the 9-Pin DB-9
(RS-232) port.

If anyone is interested in the port - you can send me an e-mail and/or download it from my web-site. I will try to post it soon -
so be patient if you want to download it from my site.

The port seems to be stable so far - I want to thank Penn for his dialogue and suggestions on this port.

Regards,
John C. Westmoreland
www.WestmorelandEngineering.com
john at westmorelandengineering dot com


[ Back to the top ]    [ About FreeRTOS ]    [ Privacy ]    [ Sitemap ]    [ ]


Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

NXP tweet showing LPC5500 (ARMv8-M Cortex-M33) running FreeRTOS.

Meet Richard Barry and learn about running FreeRTOS on RISC-V at FOSDEM 2019

Version 10.1.1 of the FreeRTOS kernel is available for immediate download. MIT licensed.

View a recording of the "OTA Update Security and Reliability" webinar, presented by TI and AWS.


Careers

FreeRTOS and other embedded software careers at AWS.



FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Espressif ESP32

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Renesas

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS

Xilinx Microblaze and Zynq partner