I now have a program where I write to flash inside a for-loop. But I'm having an issue I don't understand. Here are two versions of the program. The first version exits the loop and/or crashes during the call to FLASH_writeIntBuffer. The second version completes the for-loop and continues into the while-loop in main
What I expect:
16 pulses on portb.F6 then an eternal pulse train on portc.F0
What I see:
1 pulse on portb.F6 then nothing (but previously the pulse train appeared after a single pulse on portb.F6)
Version 1:
Code: Select all
// External functions placed at absolute addresses to make sure other variables
// don't shift around.
void __CC2DW() org 0x051A;
void KeySequence() org 0x0003;
void FLASH_Write(unsigned, unsigned int*) org 0x005F;
// Blocking out space to keep all other variables in their position while
// stripping down the program
unsigned short spacer1[64] absolute 0x0020; // reduce to 63 and everything works
unsigned short spacer2[12] absolute 0x0066;
// variable still in "use". Have tried reducing this to a single byte.
unsigned int flashRow[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
} absolute 0x0120; // 32 words 14bit values, each takes up two bytes of hex file space
void FLASH_writeIntBuffer(unsigned int buffer, unsigned int address) org 0x114{
FLASH_write(0x1D00, flashRow);
}
void main() org 0x532 {
int rowStart = 0 absolute 0x0060;
// Disable all outputs
GIE_bit = 0;
PEIE_bit = 0;
T0EN_bit = 0;
// For debug output
TRISC.F0 = 0;
PORTC.F0 = 0;
TRISB.F6 = 0;
PORTB.F6 = 0;
for(rowStart = 0; rowStart < 16; rowStart++){
// 1 - a 5 ms pulse on B6
PORTB.F6 = 1; delay_ms(5); PORTB.F6 = 0;
// Writing to a completely different address than what code is at.
FLASH_writeIntBuffer(0, 0x1D00);
// 2 - a 15 ms pulse on B6
PORTB.F6 = 1; delay_ms(15); PORTB.F6 = 0; delay_ms(100);
}
// These are here just to make sure the compiler doesnt remove them
spacer1[0] = 1;
spacer2[0] = 1;
while(1) {
// 3 - a 200 ms pulse train on C0
PORTC.F0 = 1; delay_ms(200);
PORTC.F0 = 0; delay_ms(200);
}
}
Version 2 (comments stripped to compress listing):
Code: Select all
void __CC2DW() org 0x051A;
void KeySequence() org 0x0003;
void FLASH_Write(unsigned, unsigned int*) org 0x005F;
unsigned short spacer1[63] absolute 0x0020; // reduce to 63 and everything works
unsigned short spacer2[12] absolute 0x0066;
unsigned int flashRow[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
} absolute 0x0120;
void FLASH_writeIntBuffer(unsigned int buffer, unsigned int address) org 0x114{
FLASH_write(0x1D00, flashRow);
}
void main() org 0x532 {
int rowStart = 0 absolute 0x0060;
GIE_bit = 0;
PEIE_bit = 0;
T0EN_bit = 0;
TRISC.F0 = 0;
PORTC.F0 = 0;
TRISB.F6 = 0;
PORTB.F6 = 0;
for(rowStart = 0; rowStart < 16; rowStart++){
PORTB.F6 = 1; delay_ms(5); PORTB.F6 = 0;
FLASH_writeIntBuffer(0, 0x1D00);
PORTB.F6 = 1; delay_ms(15); PORTB.F6 = 0; delay_ms(100);
}
spacer1[0] = 1;
spacer2[0] = 1;
while(1) {
PORTC.F0 = 1; delay_ms(200);
PORTC.F0 = 0; delay_ms(200);
}
}
The only difference between them is that in 1), spacer1 takes up 64 bytes and in 2) it takes up 63 bytes. The effect of this is that FLASH_Write_savedINTCON0 moves from 0x00A6 to 0x005F.
Here are the variable placements:
Version 1):
Version 2):
Output
The port output is there so I can see what is going on. Here is the output on my logic probes - not working on top, working at the bottom. The single pulse in the non working version is 5ms which is what we would expect the first pulse in the for-loop to be. The 16 first pulses in the working version are actually double, 5 and 15ms, which is exactly what the code says:
I am at a total loss here. During the process of stripping this down I've seen so much strange (but repeatable) behavior. I had the write within a double loop, and the inner loop would run fine once, then the second time around it would start halfway into the inner loop every time, then continue in main. For some time, with the code very similar to the one above, the loop would exit after the first call to write but CONTINUE in the main loop, which made it quite clear that it isn't just the port output that stops working. Also, moving FLASH_write into main (and removing FLASH_writeIntBuffer) seems to fix things.
For a little more background about the "real" problem - I had a working program but introduced a single global variable and the write loop stopped working.
Details about my setup:
MCU: PIC16F18346
OSC: 32MHz HS crystal oscillator
Project settings:
FEXTOSC External Oscillator mode Selection Bits: -- HS (crystal oscillator above 4MHz)
Power-up default value for COSC bits: -- EXTOSC operating per FEXTOSC bits
Clock Out Enable bit: -- CLKOUT function is disabled
Clock Switch Enable bit: -- Writing to NOSC and NDIV is allowed
Fail-Safe Clock Monitor Enable: -- Fail-Safe Clock Monitor is disabled
Master Clear Enable bit: -- MCLR/VPP pin function is MCLR: Weak pull-up enabled
Power-up Timer Enable bit: -- PWRT disabled
Watchdog Timer Enable bit: -- WDT disabled; SWDTEN is ignored
Low-power BOR enable bit: -- ULPBOR disabled
Brown-out Reset Enable bits: -- Brown-out Reset enabled, SBOREN bit ignored
PPSLOCK bit One-Way Set Enable bit: -- The PPSLOCK bit can be cleared and set only once
Stack Overflow/Underflow Reset Enable bit: -- Stack Overflow or Underflow will cause a Reset
Background Debug: -- Background debugger disabled
User NVM self-write protection bits: -- Write protection off
Low Voltage Programming Enable bit: -- High Voltage on MCLR/VPP must be used for programming.
User NVM Program Memory Code Protection bit: -- User NVM code protection disabled
Data NVM Memory Code Protection bit: -- Data NVM code protection disabled.
Config registers
CONFIG1 : $8007 : 0x0972
CONFIG2 : $8008 : 0x3AE3
CONFIG3 : $8009 : 0x0003
CONFIG4 : $800A : 0x0003
Output settings:
Optimization level: Four