I think I'm far enough along for a useful progress report, but there are still a few problems to solve before I'm done. I've been talking to an apps engineer at Microchip also, so some of this comes from him:
Instead of #pragma psect, the help file prefers __section() for each function, constant, and variable that will be linked explicitly. I knew this from the start, but I couldn't make it work for a while. The help file uses a simpler example to suggest that I do it like this:
- Code: Select all
const unsigned char __section("USBConst") string1[] = "foo";
const unsigned char __section("USBConst") string2[] = "bar";
const unsigned char *const __section("USBConst") string_table[] = {string1, string2};
Except it didn't like string_table. If I took out the __section() on that line only, it would work. If I rearrange it like this, it's happy:
- Code: Select all
__section("USBConst") const unsigned char string1[] = "foo";
__section("USBConst") const unsigned char string2[] = "bar";
__section("USBConst") const unsigned char *const string_table[] = {string1, string2};
Except that doesn't work with anonymous structures. The first way does though, so I can mix and match to make all of them work.
I also found that you can use a negative address for the linker options to specify an ending address. Actually, this is one past the end, or the first address that you don't want to use. You can then, in theory, place psects consecutively before it so that all of them are packed together next to that maximum address. But it seems to have some trouble doing that:
- Code: Select all
Linker:
-L-pUSBCode=-1FFEh,USBCode_split_1,USBCode_split_2,USBConst -L-pApplicationISR=0220h
- Code: Select all
Output:
:0: warning: (596) segment "USBCode" (3DC2-3FFB) overlaps segment "USBCode_split_1" (3727-3EDE)
:0: warning: (596) segment "USBCode_split_1" (3727-3EDE) overlaps segment "USBCode_split_2" (3129-3B02)
:0: warning: (596) segment "USBCode_split_2" (3129-3B02) overlaps segment "USBConst" (35A3-3712)
The USBCode_split_# psects were created automatically because I probably assigned more stuff to USBCode than would fit. I didn't know this at first, so I only told the linker about USBCode, and so I still had stuff in the wrong place because I didn't tell it about these extra automatic psects. (in fact, I still have stuff in the wrong place because they clobber each other, but at least it's trying now
)
If you want to have an assembly file in a C project, it MUST have the extension .as. The help file is wrong in saying that it must be .s, and the MPLAB X IDE offers a choice of .s, .as (Edit: .as is actually not offered), or .asm with no explanation of the difference.
Once I figured that out, it would find the .inc header file that I included from the .as assembly file, but it found syntax errors all over it. (this is an unmodified, stock header file that came with the toolchain
) After trying a few things there, I gave up, scrapped the includes, and defined my own registers and macros in the .as file itself. That worked. Don't forget to leave some handles for the linker to pick up.
So the remaining problems are:
- How to keep a consecutive series of psects that are placed with a negative address from running over each other?
- How to use wildcards in linker options, if they're supported at all, so that one label can collect the original and all of the splits without wasting space like I think a class would?
- How to guarantee that the lower end of the series is padded down to the start of a 32-word row of flash?
I want to end up with at least one of my constants at the start of the lowest row so that I can distinguish a new image of upper memory from an ISR that would normally be there. I figure that the retlw instruction that comes free with every constant should do the job nicely.
According to the overall architecture of the project, interrupts are disabled before clobbering the ISR and not reenabled until the new ISR is present and verified.