2009-05-28 07:57 AM
Issues programming secondary FLASH when EN_PFQBC is set
2011-05-17 12:54 AM
Hi,
We are seeing a strange issue and were wondering if this is a bug. We are using STR910FAM32 device (Rev G silicon) and programming secondary FLASH by running code in Primary FLASH. When we enable EN_PFQBC bit in SCU_SCR0 register to enable Pre-Fetch Queue/Branch Cache, the Processor randomly hangs sometimes when programming the secondary FLASH. Surprisingly, when we have this bit reset, there are no issues. The processor clocks are set to as follows: MCLK from PLL = 96 MHz RCLK = 96 MHz (RCLK Divider = 1) PCLK = 48 MHz (PCLK Divider = 2) FMICLK = 96 MHz (FMICLK Divider = 1) HCLK = 96 MHz (HCLK Divider = 1) Any assitance would be much appreciated. thanks. regards, Ranjeet2011-05-17 12:54 AM
dude,
there is an errata item about that flaw - yes, to allow reading one bank from another bank, you have to shut off the EN_PFQBC bit. management of the flash is awkward - I have a whole thread in micrium's OS to baby sit the erase. I recommend a mutex to keep threads from trying to access it at the same time. If you want max performance, you should reenable EN_PFQBC when not accessing bank1 memory from bank0 eric krieg erickrieg (at) verizon.net2011-05-17 12:54 AM
Hi Guy,
I was exactelly in your case, In fact, the code which erase and reprogramme MUST be run from the memory and not from the FLASH. Especially at 96Mhz. This code was working FINE with a STR912 running at 96Mhz, with a RTOS Keep me in touch but all information should be here. Regards Damien HOYEN /** ************************************************************************************** * \fn u32 EEPROM_WriteDataInEEPROM_DirectAccess (const void *Address, const u32 DestSectorAddress, const u32 Nbbyte) * \brief This function will write Nbbyte in the bank1 memory, in the sector:DestSectorAddress * This function is not protected, NEVER use it in a multithread software but only EEPROM_WriteDataInEEPROM ************************************************************************************** * ************************************************************************************** * \return Number of byte written ************************************************************************************** */ u32 EEPROM_WriteDataInEEPROM_DirectAccess (const void *Address, const u32 DestSectorAddress, const u32 Nbbyte) { #define SPACE_FOR_RAM_EXEC_SIZE 512 typedef void (*fptr_t)(u32); /* This pointer will be associated to the function : EEPROM_ResetSector */ typedef void (*fptr2_t)(u32,u16); /* This pointer will be associated to the function : EEPROM_Write */ u8 SpaceForRAMexecution[SPACE_FOR_RAM_EXEC_SIZE]; fptr_t RamExecPointer_Fct = (fptr_t)SpaceForRAMexecution; fptr2_t RamExecPointer2_Fct = (fptr2_t)SpaceForRAMexecution; u32 i=0; u16 TempU16; /* Here, we will compare previous value in memory with the new, * if equal, no write necessary */ if (memcmp(Address,(void *)(DestSectorAddress),Nbbyte) == 0) return (Nbbyte); /* According to the Application note AN2540, from ST, page 17/25 * * Try to write data in flash with a CPU frequency > 25 Mhz * must be done from the RAM memory and never from Flash code located inside bank 0 * * WARNING : This code HAVE TO be compiled in ARM, NEVER in Thumb */ /* prevent a wrong compilation option */ #ifdef __thumb__ #error This function HAS to be compiled in ARM mode only, thumb is impossible #endif /* * To avoid a huge usage of stack in this function (Already many byte have been reserved via SpaceForRAMexecution) * Try to avoid to use any function using printf and other vsprintf(...), could be done outside, just after the exit */ FMI_WriteProtectionCmd(DestSectorAddress, DISABLE); /* load memory with code to erase the sector */ memcpy (SpaceForRAMexecution,(void*)EEPROM_ResetSector ,SPACE_FOR_RAM_EXEC_SIZE); /* execute reset of the sector */ taskENTER_CRITICAL (); (*RamExecPointer_Fct)(DestSectorAddress); taskEXIT_CRITICAL (); /* load memory with code to program a 2 bytes */ memcpy (SpaceForRAMexecution,(void*)EEPROM_Write ,SPACE_FOR_RAM_EXEC_SIZE); while(i < Nbbyte) { if (i == (Nbbyte - 1)) { /* last character -> only 1 bit to write*/ TempU16 = (u16)(*((u8*)(Address) + i)); taskENTER_CRITICAL (); (*RamExecPointer2_Fct)((DestSectorAddress + i),TempU16); taskEXIT_CRITICAL (); i = i + 1; } else { /* Normal case */ TempU16 = ((u16)(*((u8*)(Address) + i)) + (((u16) (*((u8*)(Address) + i + 1))) < taskENTER_CRITICAL (); (*RamExecPointer2_Fct) ((DestSectorAddress + i),TempU16); taskEXIT_CRITICAL (); i = i + 2; } } // while(i < Nbbyte) FMI_WriteProtectionCmd(DestSectorAddress, ENABLE); return (i); } static void EEPROM_ResetSector (const u32 DestSectorAddress) { /* * Aftyer checking in the linker file : * The size of this function is (without optimisation and debug): * 164 Bytes * */ #define TIMEOUT 0xFFFFFF vu32 FMI_Bank = FMI_BANK_1; u32 Time_Out = 0; /* Equivalent to FMI_EraseSector(DestSectorAddress); */ /* Write an erase set-up command to the sector */ *(vu16 *)DestSectorAddress = 0x20; /* Write an erase confirm command to the sector */ *(vu16 *)DestSectorAddress = 0xD0; /* Loop until it's finish */ /* Equivalent to Function FMI_WaitForLastOperation(FMI_BANK_1); /* Write a read status register command */ *(vu16 *)(FMI_Bank) = 0x70; /* Wait until operation compeletion */ while((!((*(vu16 *)FMI_Bank) & 0x80))&&(Time_Out < TIMEOUT )) { Time_Out ++; /* Time Out */ } /* Write a read array command */ *(vu16 *)FMI_Bank = 0xFF; } static void EEPROM_Write (const u32 DestAddress, const u16 Value) { /* * Aftyer checking in the linker file : * The size of this function is (without optimisation and debug): * 180 Bytes * */ #define TIMEOUT 0xFFFFFF vu32 FMI_Bank = FMI_BANK_1; u32 Time_Out = 0; /* Write a program command to the sector to be written */ *(vu16 *)(DestAddress & 0xFFFFFFFC) = 0x40; /* Write the halfword to the destination address */ *(vu16 *)DestAddress = Value; /* Loop until it's finish */ /* Equivalent to Function FMI_WaitForLastOperation(FMI_BANK_1); /* Write a read status register command */ *(vu16 *)(FMI_Bank) = 0x70; /* Wait until operation compeletion */ while((!((*(vu16 *)FMI_Bank) & 0x80))&&(Time_Out < TIMEOUT )) { Time_Out ++; /* Time Out */ } /* Write a read array command */ *(vu16 *)FMI_Bank = 0xFF; }2011-05-17 12:54 AM
I had a lot of random crashes related to using bank1 dataflash. I'm not sure I have them all gone. You need to look up the errata app note for the part. There are a lot of things in there they tell you to do. There are a lot of things I changed to lesson the frequency of flash related crashes (I recommend to anyone with a choice to not try to store data in the flash - much easier and faster and more reliable to battery back up the chip to NV the internal ram - or use external EEPROM). I found trying to read the OTP before initing the part can crash it. One of the things the app engineer told me to do slowed up my app way too much. Don't forget to run out of ram if you touch the bank you run out of. I use the following code to init my part:
* FLASH DATA MANAGER This code is for a thread - or at least a process that manages requests to move data to flash. All the code is in bank 1 which starts at 0x100000 The last half of bank 1 starting at 0x110000 is a mirror image of the first half. Memory references to flash as in absolute real addresses - the legal range is from 0x101000 to 0x10FFFF - note, the beginning is unused in case it ever has to be part of a boot prom */ void initFlash(void) { // called on start up to get the flash support code working // char buf[33]; // INT8U os_err; /* Create receive queue (see Note #1a). */ //os_err = OSMutexPost(flashAvlMutex); // make it available - already is available and we are not owner //if (OS_NO_ERR != os_err) { // snprintf(buf, 31, ''InF! %d '', os_err ); // debugSend(buf, DBG_SER1 | DBG_NOW); //} asm ('' MOV R0, #0x40000 \n'' ''MCR P15, 0x1,R0,C15,C1,0\n'' ); SCU_PFQBCCmd(DISABLE); // disables instruction cache to avoid limitation in earlier chips //SCU_AHBPeriphReset(__VIC, ENABLE); /* VIC peripheral is under Reset (disables all interrupts)*/ SCU_AHBPeriphClockConfig(__FMI, ENABLE); SCU_AHBPeriphReset(__FMI, DISABLE); //Ser_WrByte(DEBUG_UART, 'c'); // test // pre 5-15-9FMI_Config(FMI_READ_WAIT_STATE_2, FMI_WRITE_WAIT_STATE_1, FMI_PWD_DISABLE, FMI_LVD_ENABLE, FMI_FREQ_LOW);FMI_FREQ_HIGH FMI_Config(FMI_READ_WAIT_STATE_3, FMI_WRITE_WAIT_STATE_1, FMI_PWD_DISABLE, FMI_LVD_ENABLE, FMI_FREQ_LOW); // below steps avoid a crash before the call to areWeLargeMemoryProc() FMI->BBSR = 0x5; // 1MB for bank FMI->NBBSR = 0x4; // 128k for bank 1 - not used yet FMI->BBADR = 0x00000 ; FMI->NBBADR = 0x100000 >> 2 ; // bank 1 starts right after FMI->CR |= 0x18; /* Enable bank 1 */ FMI_GetStatus(FMI_BANK_1); //Ser_WrByte(DEBUG_UART, 'A'); // test if ((0 == areWeLargeMemoryProc()) ) { FMI->BBSR = 0x4; // 512K for bank FMI->NBBSR = 0x2; // 32k for bank 1 - not used yet FMI->BBADR = 0x00000 ; FMI->NBBADR = 0x100000 >> 2 ; // bank 1 starts a ways after - same for both parts } else { FMI->BBSR = 0x5; // 1MB for bank FMI->NBBSR = 0x4; // 128k for bank 1 - not used yet FMI->BBADR = 0x00000 ; FMI->NBBADR = 0x100000 >> 2 ; // bank 1 starts right after } FMI->CR |= 0x18; /* Enable bank 1 */ // patTheBunny(); should only do while no other thread is alive FMI_GetStatus(FMI_BANK_1); FMI_WaitForLastOperation(FMI_BANK_1); // don't fully know why, but need the fmi routines running out of RAM SCU_PFQBCCmd(ENABLE); // must run fast enough the rest of the time //SCU_AHBPeriphReset(__VIC, DISABLE); /* VIC peripheral is under Reset (disables all interrupts)*/ } I had to add a lot to not hang up my real time application - so I had a layer of semaphores and the app code has a lot of references to PFQBCCmd sprinkled through. It was my goal to make flash drivers that would support run time erase/read/write access to dataflash and upper areas of program flash. I never got the later to work - only the former. What I really wanted to do is split my program memory in half and have the upper half used to download new code over the internet. I admit much of what is in my code is probably superstitious and a result of my flailing trying to avoid the crashes. I made massive changes to the fmi code they give you (it is not to be trusted) - note for example a change to code that reads a location: /******************************************************************************* * Function Name : FMI_ReadWord * Description : Read the correspondent data. * Input : FMI_Address: specifies the needed address. * Output : None * Return : The data contained in the specified address. *******************************************************************************/ __ramfunc u32 FMI_ReadWord(u32 FMI_Address) { u32 result; ramSCU_PFQBCCmd(DISABLE); // disables instruction cache to avoid limitation in earlier chips result = (*(u32*)FMI_Address); ramSCU_PFQBCCmd(ENABLE); // must run fast enough the rest of the time return(result); } make sure to write plenty of code to hammer away at this before consider it working - many crashes I fought were very periodic and the app people weren't too much help. This is one of the more frustrating limitations of the part. Oh, there is some speed place in an on chip register that could be slowed down - you really have to look through the errata sheet and just kind of hack at it. best wishes, Eric krieg erick sapling-inc.com