2016-10-24 06:36 AM
Hi,
We are using a STM32F030C8T6 and are storing configuration data at the end of flash memory. We carved off 4K of the 64K of flash(via the .ld linker file) for the storage area so our config storage is at address 0x0800F000. The data is stored there correctly when viewed from the debugger. During operation of the system we copy the data into ram, insure that the config CRC's are correct and use the data that is now in ram. The problem that we have is that during normal operation we insure that the ram data matches the original flash data by reading both ram and flash and comparing the bytes. During this process a byte of data that is read from the flash appears as a 0xFF and the compare fails. We are only reading from the flash so there are no writes going on. I have not found/read any reason a flash read could get corrupted so I'm looking for some help. tempByte1 is the data from flash and tempByte2 is the data from ram. The error checking is run at random times during program execution but the failure normally occurs on the first byte read(when i = 0.) The ram byte is correct and the flash byte is showing up as 0xFF. I thought that maybe the tempByte's were getting blasted because of stack space but the error always seems to come from the flash byte read. Are there any issues doing single byte reads from flash? Thanks, John C.uint8_t read_flash_byte(uint8_t *addr_p)
{
return(*(__IO uint8_t *)addr_p);
} // End of write_read_byte()
// Function where error occurs...
uint8_t tempByte1, tempByte2;
uint8_t *ptr1_p, *ptr2_p;
/* Make sure the both flash copies match RAM copy we are using. */
ptr1_p = (uint8_t *)&UL1;
ptr2_p = (uint8_t *)&UL2;
for(i = 0; i <
sizeof
(EE_UL_CRIT_DATA); i++)
{
/* check this byte in Copy1 */
tempByte1
=
read_flash_byte
(ptr1_p++);
tempByte2
=
UsedULData
->Val[i];
if(tempByte2 != tempByte1)
{
/* Flash and Ram are different throw a critical Error */
HandleError();
}
/* check this byte in Copy2 */
tempByte1 = read_flash_byte(ptr2_p++);
if(tempByte2 != tempByte1)
{
/* Flash and Ram are different throw a critical Error */
HandleError();
}
} // End of for loop
2016-10-24 01:00 PM
Hey Clive,
Thanks for the feedback. Here is the source that I've verified fails. You will need a running project(I don't have any demo builds to try this out on.) Also add these to your .ld(linker) file: /* Specify the memory areas */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 60K LOG_AREA (rw) : ORIGIN = 0x0800F000, LENGTH = 4K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K } .flash_array : { PROVIDE_HIDDEN (__flash_array = .); KEEP (*(SORT(.flash_array.*))) KEEP (*(.flash_array*)) PROVIDE_HIDDEN (__flash_array = .); } >LOG_AREA// .h file definitions...
typedef struct
{
uint8_t var1;
uint8_t var2;
uint8_t var3;
uint8_t var4;
uint8_t var5;
uint8_t var6;
uint8_t var7;
uint8_t var8;
uint8_t var9;
uint8_t var10;
uint8_t var11;
uint8_t var12; // App Data
uint8_t var13; // App Data
uint8_t var14; // App Data
uint8_t var15; //App Data
uint8_t var16 : 1; // App Data
uint8_t var17 : 1; // App Data
uint8_t var18 : 1; // App Data
uint8_t var19 : 1; // App Data
} TEST_PARAMS;
typedef union
{
struct
{
uint8_t EepromVer;
TEST_PARAMS Params;
uint16_t crcVal;
};
uint8_t Val[sizeof(TEST_PARAMS) + 3];
} EE_UL_CRIT_DATA2;
// Top of main.c
const uint8_t __attribute__((section (''.flash_array''))) TESTER[sizeof(EE_UL_CRIT_DATA2)] __attribute__((aligned(4))) = UL_SETTINGS;
// Function definitions...
uint8_t read_flash_byte(uint8_t *addr_p)
{
return(*(__IO uint8_t *)addr_p);
} // End of write_read_byte()
void __attribute__((optimize(''O0''))) read_flash(uint32_t addr, uint32_t data, uint32_t size)
{
uint8_t *addr_p, *data_p, *end_p;
addr_p = (uint8_t *)addr;
data_p = (uint8_t *)data;
end_p = (uint8_t *)(addr+size);
while (addr_p <
end_p
)
{
*data_p = *(__IO uint8_t *)addr_p;
data_p++;
addr_p++;
}
} // End of write_flash()
void checkFlash(void)
{
uint8_t *ptr1_p, *ptr2_p;
uint8_t tempByte1, tempByte2;
int16_t i;
/* Make sure the both EEPROM copies match RAM copy we are using. */
ptr1_p = (uint8_t *)&TESTER;
//ptr2_p = (uint8_t *)&UL2;
for(
i
=
0
; i < sizeof(EE_UL_CRIT_DATA2); i++)
{
/* Check this byte in Copy1 */
tempByte1
=
read_flash_byte
(ptr1_p++);
tempByte2
=
TesterData
.Val[i];
//
tempByte2
=
UsedULData
->Val[i];
if(tempByte2 != tempByte1)
{
HandleError();
}
}
}
// Call this before main loop
read_flash((uint32_t)&TESTER, (uint32_t)TesterData.Val, sizeof(EE_UL_CRIT_DATA2));
// Call this in main loop...
checkFlash();
2016-10-24 01:06 PM
Forgot this at top of main.c or .h:
// Top of main.c
#define UL_SETTINGS {8,2,0,0,0,2,0,0,1,1,0,1,0,0,0,0,0,0x42,0x99}
2016-10-24 01:35 PM
What tool chain are you using here? Looks to be GNU/GCC but what version, and command line options?
2016-10-24 01:49 PM
Hey Clive,
It is the Atollic tool chain and I thought it was just a derivative of gcc. Compiler command line: arm-atollic-eabi-gcc -c -mthumb -mcpu=cortex-m0 -std=gnu11 -DUSE_STM32F0_DISCOVERY -DHSI_VALUE=8000000 -DSTM32F030 -DUSE_STDPERIPH_DRIVER -I../src -I..\Libraries\CMSIS\Include -I..\Libraries\CMSIS\Device\ST\STM32F0xx\Include -I..\Libraries\STM32F0xx_StdPeriph_Driver\inc -I..\Utilities\STM32F0-Discovery -O0 -g -Wall -o src\eeprom.o ..\src\eeprom.c Linker command line: arm-atollic-eabi-gcc src\main.o src\eeprom.o Utilities\STM32F0-Discovery\stm32f0_discovery.o Libraries\STM32F0xx_StdPeriph_Driver\src\stm32f0xx_wwdg.o .... -o 70200_ARM_build1.elf -mthumb -mcpu=cortex-m0 -T..\Debug_STM32F030C8_FLASH.ld -Wl,--start-group -lc -lm -Wl,--end-group --specs=nano.specs --specs=nosys.specs -static -Wl,-cref,-u,Reset_Handler -Wl,-Map=ARM_build1.map -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x802016-10-24 07:29 PM
> Before I go down that road let me ask if you know of any issues involving reading flash from a STM32F030 device?
No. > The key for me to post working code would be to remove any company information from > UL1/UL2 data structure. That would take me a small amount of time to do and I'm not > against that, but the main reason I posted was the hope that someone would know of a flash > issue and reply(as I've not seen any flash read issues in my searches.) I understand that, but - as you've said - there is nothing relevant mentioned already, so it's not unlikely it's a programmer error. Please note, that I specifically asked for a minimal but *complete compilable* code. You know you have it when you can copy/paste it without thinking. A minimal but complete command-line and linker script and startup code would be nice - i.e. the whole shebang, zipped up - would be a bonus. And the disassembly, at least of the relevant portions (pointer filling and read). Honestly? I don't need it. I don't even have a 'F030 to try it on. I'm just trying to push *you* to do the unpleasant things which you know you might need to but are reluctant to do. And, who knows, Clive or some of the other smart guys hanging around here might spot something, they often do. Jan PS. One more stupid question: FLASH latency vs system clock?2016-10-25 05:20 AM
Hey Jan,
It is definitely far easier to see incorrect coding. The issue I face on my side is that the code built un-optimized is almost 60K. To pull a piece of it out can be like pulling on a thread where needing one thing can lead to another and another(in this case it was not.) What I was seeing from the debugger(and maybe you could mention to the keepers of this board that putting up 400Kbyte screen shots could be very helpful) was very odd in that a single stack variable was incorrect but the flash that it was read from was ok. I still suspect it is something in the code but I do not do any flash setup/configuration. I am currently clocking at the max 48Mhz and I'm not sure how flash latency would play into something like this(most of the systems I've done in the past run directly out of ram.) Thanks, John C.2016-10-25 05:59 AM
I went through the startup sequence again and noticed a write to the flash before the error occurred. The write occurs several passes of the main loop before the error. I went in and simply had the write function return to the caller without doing anything and the error did not occur. So given the flash write code below, how long after this call do I need to wait before reading the same address again?
Thanks, John C.void __attribute__((optimize(''O0''))) write_flash(uint32_t addr, uint32_t data, uint32_t size)
{
uint32_t *addr_p, *data_p, *end_p;
// Clear the page, erase the page and program the default values...
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
FLASH_ErasePage(FLASH_USER_START_ADDR);
addr_p = (uint32_t *)addr;
data_p = (uint32_t *)data;
end_p = (uint32_t *)(addr+size);
while (addr_p < end_p)
{
FLASH_ProgramWord((uint32_t)addr_p, (uint32_t)*data_p);
addr_p++;
data_p++;
}
FLASH_Lock();
} // End of write_flash()
2016-10-25 07:24 AM
> I am currently clocking at the max 48Mhz and I'm not sure how flash latency would play into something like this
It was one of the many blind shots. Prefetch could be set incorrectly and code run marginally, throwing error/unexpected result upon read from a distinct block. > So given the flash write code below, how long after this call do I need to wait before reading the same address again? Try to switch off/on the prefetch. JW2016-10-25 08:11 AM
Hey Jan,
I've had the pre-fetch off for a couple of days. I think I put it in there when I began seeing the problem as it seemed to be the only configurable I could find for the flash. So unfortunately it is not that(I'm sure in the end it will be something simple I have missed.)FLASH_PrefetchBufferCmd(DISABLE);
2016-10-25 08:50 AM
The flash should have a wait state at 48 MHz
Should be immediately readable after writeShould check the error/status return from commandAssuming everything is aligned, the M0 would Hard Fault other wiseOutput diagnostic data via serial port, ie print out failure address, patternsAvoid debuggerWhat version of GNU/GCC is being used?