Where I have been for the last week or so, on another barefoot journey across a LEGO pile with MPLAB and XC8
compiler. Bottom line, beware of C compilers claiming
improved performance.
My very small Light Controller was depending on the 256 bytes in the
EEPROM for config and script storage. After config storage, that
left about 220 bytes for the scripting. But each LED takes 5 bytes
to describe the time, command, state, features and PWM setting. So
a single time slot with all 6 LEDs changing can take 30 bytes. Thus
in 7 time slots all the memory can be used. I had over 4K left in
flash, so I decided to move the scripting there. I had done this in
one of the PIC32s that did not have EEPROM.
And the fun begins. Harmony in the PIC32 had libraries for doing
this, it was fairly easy. I had written a boot loader for an older
PIC, so this cant be that hard. Well after 3 days on and off trying
to make this work, I decided to change course. Brand new MPLAB
project with only the FLASH writing routines and using the MPLAB
Code Configurator to generate the FLASH routines. Their routines
were essentially the same as what I wrote. I could not see any
difference that would make it work over what I had done.
But this did not work either. I spent a huge amount of time trying
to debug this with no change. Then I spent a day reading every
FLASH routine posting I could find. 90%+ were using the MCC
routines I had generated. Most problems were related to other
things that I had already implemented. Then I finally found one
post where the person could not get FLASH to work. Microchip told
him to change compilers. There was an issue in 2.35
and that 2.36 fixed that. Well 2.36 was a transitory release and I
had a choice between 2.40 and 2.41. Knowing that x.x0 and x.x5 is
Microchips release schedule and any other numbers are bug fixes, I
went with 2.41. And what do you know, the dedicated program started
writing to the FLASH.
Could it be that simple, of course not. Compiled the Light
Controller and it still failed. Now to be fair I had slightly
rearranged the MCC generated code to fit my overall structure. So I
went back to the dedicated program and pointed all the FLASH
routines at my revised code. Also renamed all the FLASH routines
in this dedicated program directory so there was no way they would
be included. And it works just fine. I then made sure the
configuration bits were the same in both programs. The last thing I
did was copy the oscillator startup code from the Light Controller
to the dedicated program. Still works.
Startup code, project properties, compiler settings were the first
things to look at and these were all the same. Something in the
startup code? I cut out the test routine of the dedicated program
and placed it as far in the front as possible. Still would not
work. At this point almost a week has gone by and I am getting no
where. I have been taking breaks to work on other things, one to
clear my mind and two to have some sense of progress.
At some point I remembered some quirky things I had read about
EEPROM unlock sequence. Back to the dedicated program to trace through the assembly
code to see how that worked. The unlock sequence is 0x55 then 0xAA
then set the write bit. The green is the C code and the rest is
assembly. Nothing exciting here, what I would expect.
Then to trace through the Light Controller. Both are using the
exact same code base, there is no difference, no #ifdef, no changes
at all. There are two differences, either of which could cause a
problem. Line #187, the BANK command. Why is that there, that
should have been before the sequence started. Then the real problem
is Line #193, another BANK command and inserted just before the
write bit. My understanding is that the unlock sequence is timed
and set for exactly 5 instructions. At a minimum, setting the write
bit has to be the next instruction after loading 0xAA.
After some more reading I came up with this
assembly code sequence for the unlock. The C code using inline
assembly is in green. As you can see the generated instructions are
exactly 5 instructions long and it works as expected.
So after a week of messing around with this, it finally works. I
will probably go back and replace the unlock sequence elsewhere with
this assembly version, just to make sure that somewhere in the
future the compiler doesn't change it's mind and change the C code.