Hi there!
I'm having trouble programming words into the global address space.
Programming / Triggering of write operations shall be done "in the background" by utilising the "Command Status ISR".
First of all I used Processor Expert to generate FLASH1_Init() and added to it from there on.
As soon as FLASH1_Init() completes, the Command Status ISR is called non-stop.
Why is that? Do I need to disable Command Status Complete Interrupts within the ISR?
Now when I skip these ISRs by stepping during Debug, I call enHalFlashInternalWriteWord(), which sadly doesn't work either: When I reach "Schreiben einleiten" to initiate the programming (FSTAT |= FSTAT_CCIF_MASK;), ACCERR is still active, so setting CCIF (which should clear the flag) does nothing. (see attached file or code example)
Input Parameters: 0x7C0000 (Address), 0 (Data).
By the way: How does the Flash-Controller know, how many Words I want to program, starting with the Address?
For example: If I leave FCCOB3-5 empty, would the controller still attempt to write Zeros into the addresses related to FCCOB3-5?
Do I need to consider switching to program execution in RAM?
Is there a far easier way to program internal Flash that I am overlooking?
I tried to understand the "current" AN2720, however it appears to be outdated for S12XE / couldn't get it to work.
This is an excerpt from my code:
/* Moegliche Fehler rücksetzen */
FSTAT |= FSTAT_ACCERR_MASK + FSTAT_FPVIOL_MASK;
/* FCCOB - Register vorbereiten */
/** FCCOB0 */
FCCOBIX = 0u;
FCCOB = ((uint16)(((uint16)EN_P_FLASH_CMD_PROGRAM_P_FLASH) << 8)); /* Schreib-Kommando in FCCOB-MSB schreiben */
FCCOB |= (uint16)(u32ParAddrGlob >> 16); /* Oberste 7 Bit der glob. 23 Bit-Adresse */
/** FCCOB1 */
FCCOBIX = 1u;
FCCOB = (uint16)u32ParAddrGlob; /* Unterste 16 Bit der 23 Bit-Adresse */
/** FCCOB2 */
FCCOBIX = 2u;
FCCOB = u16ParData;
/* Schreiben einleiten */
FSTAT |= FSTAT_CCIF_MASK;
// Warten bis Schreiben abgeschlossen
while(!M_BO_FLASH_CONTROLLER_IDLE);
// Ergebnis stimmt nicht
if((*far_pu16Dest) != u16ParData)
{
enRet = EN_HAL_RET_ERR_FLASH_DATA_INVALID;
}
Thanks for Your time!
Original Attachment has been moved to: Flash_Internal.c.zip
Now it works.
It appears that you cannot put code into paged ram using pragmas.
If you debug, you see that the program changes the PPAGE-register-value to the ram-page number of your paged ram code section, once you reach your "ram function", which is wrong.
So what I did was to declare a part of the unpaged ram as Code-Section.
// PRM-File
RAM = READ_WRITE 0x2000 TO 0x3BFF;
RAM_CODE = READ_WRITE 0x3C00 TO 0x3FFF;
...
CODE_TEST INTO RAM_CODE;
Hi Sacha,
Nice that you work it out by yourself.
Just to leave some notes:
- we cannot read and write Flash from the same block at a time. Therefore during programming of a flash block, the command is usually executed from RAM (or other flash block if there is any)
- For the paged RAM, as it is written in .prm file - when using banked addressing for variable data, make sure to specify the option -D__FAR_DATA on the compiler command line (Alt+F7)
- Here you can download a pack of examples for S12XE device family where you can find CW project for Flash:
LAMA's S12XE unofficial examples
Regards,
iggi
Hey Iggi, thanks for your reply!
These examples are very enlightening. :smileywink:
I already had to activate the compiler command -D__FAR_DATA because of start-up code related warnings.
However, this does not change the behavior (meaning that PPAGE is being changed instead of RPAGE when entering the RAM-function).
This currently does not pose a problem, but in the future I might like to change RAM code to other pages / expand.
First of all:
I got it to work, as long as I don't write into the same block from which the code is executed.
1) I disabled the CCIE in FCNFG, which stopped controller from being locked in an endless CMD-Status-Complete ISR.
2) FSTAT |= FSTAT_ACCERR_MASK + FSTAT_FPVIOL_MASK; was wrong for resetting Error Flags
-> FSTAT = FSTAT_ACCERR_MASK + FSTAT_FPVIOL_MASK; is correct (this way command execution is not triggered)
3) I now understand, that all 4 Words within the FCCOB-Register are written. No way around that.
The huge Problem I now face is this:
How do I get this Write-Function to work if the same Block, from which it is run, is being written to?
I tried to put the Code into RAM, simply by using #pragmas
However, when I get to debugging, the program stops the moment the "RAM-Function" is reached.
The current Test Code looks like this:
#pragma CODE_SEG CODE_TEST
/**
Write Word, Word+1, Word+2, Word+3 into internal Flash starting at global Addr.
@param[in] u32ParAddrGlob - Global Addr (Only even Addr. allowed)
@param[in] u16Data - Data to be written
@retval EN_HAL_RET_OK - Success
@retval EN_HAL_RET_... - Error
*/
EN_HAL_RET enHalFlashInternalWriteWord(uint32 u32ParAddrGlob, uint16 u16ParData)
{
EN_HAL_RET enRet = EN_HAL_RET_OK;
uint16 u16Data = u16ParData;
uint8 u8Ctr;
uint16 *far far_apu16Dest[4];
far_apu16Dest[0] = (uint16 *far)u32ParAddrGlob;
far_apu16Dest[1] = (uint16 *far)(u32ParAddrGlob+2);
far_apu16Dest[2] = (uint16 *far)(u32ParAddrGlob+4);
far_apu16Dest[3] = (uint16 *far)(u32ParAddrGlob+6);
/*|| Guard...*/
if( ( M_BO_ADDR_ODD_U32(u32ParAddrGlob)) /* Ungerade Adresse uebergeben */
/* Ziel-Speicher ist nicht geloescht */
||(!M_BO_FLASH_WORD_ERASED(far_apu16Dest[0]))
||(!M_BO_FLASH_WORD_ERASED(far_apu16Dest[1]))
||(!M_BO_FLASH_WORD_ERASED(far_apu16Dest[2]))
||(!M_BO_FLASH_WORD_ERASED(far_apu16Dest[3]))
||(!M_BO_FLASH_CONTROLLER_IDLE)) /* (Interner)Flashcontroller beschaeftigt */
{
enRet = EN_HAL_RET_ERR_GUARD;
}
/*...Guard ||*/
/*|| Guard OK...*/
else
{
/* Reset possible Flash-Errors */
FSTAT = FSTAT_ACCERR_MASK + FSTAT_FPVIOL_MASK;
/* FCCOB - Reg Preperations */
/** FCCOB0 */
FCCOBIX = 0u;
FCCOB = ((uint16)(((uint16)EN_P_FLASH_CMD_PROGRAM_P_FLASH) << 8)); /* Write Command */
FCCOB |= (uint16)(u32ParAddrGlob >> 16); /* First 7 Bits of global 23 Bit-Addr. */
/** FCCOB1 */
FCCOBIX = 1u;
FCCOB = (uint16)u32ParAddrGlob; /* Lower 16 Bit of 23 Bit Addr. */
/** FCCOB2 */
FCCOBIX = 2u;
FCCOB = u16Data;
u16Data++;
/** FCCOB3 */
FCCOBIX = 3u;
FCCOB = u16Data;
u16Data++;
/** FCCOB4 */
FCCOBIX = 4u;
FCCOB = u16Data;
u16Data++;
/** FCCOB5 */
FCCOBIX = 5u;
FCCOB = u16Data;
/* Initiate Write */
FSTAT = FSTAT_CCIF_MASK;
/* Wait till Write finished */
while(!M_BO_FLASH_CONTROLLER_IDLE);
/* Check Result (Reread) */
for(u8Ctr = 0; u8Ctr < 4u; u8Ctr++)
{
/* Unexpected Value */
if((*(far_apu16Dest[u8Ctr])) != (u16ParData + u8Ctr))
{
enRet = EN_HAL_RET_ERR_FLASH_DATA_INVALID;
}
}
}
/*...Guard OK ||*/
return enRet;
}
#pragma CODE_SEG DEFAULT
///////////////////////////////////////////
.prm File
....
RPAGE_FB = READ_ONLY 0xFB1000 TO 0xFB1FFF;
....
PLACEMENT /* here all predefined and user segments are placed into the SEGMENTS defined above. */
_PRESTART, /* Used in HIWARE format: jump to _Startup at the code start */
STARTUP, /* startup data structures */
ROM_VAR, /* constant variables */
STRINGS, /* string literals */
NON_BANKED, /* runtime routines which must not be banked */
COPY INTO ROM_C000;
DEFAULT_ROM INTO PAGE_FE, PAGE_FC, PAGE_FB, PAGE_FA, PAGE_F9, PAGE_F8, PAGE_F7, PAGE_F6,
PAGE_F5, PAGE_F4, PAGE_F3, PAGE_F2, PAGE_F1, PAGE_F0, PAGE_E7, PAGE_E6,
PAGE_E5, PAGE_E4, PAGE_E3, PAGE_E2, PAGE_E1, PAGE_E0;
DEFAULT_RAM /* all variables, the default RAM location */
INTO RAM;
/*CODE_RAM
INTO RPAGE_FB;*/ /* Im RAM ablaufender Code */
CODE_TEST INTO RPAGE_FB;
END
////////////////////////////////
It seems like it does not make a difference, whether I deklare to Rampage als READ_WRITE or READ_ONLY
RPAGE_FB = READ_WRITE 0xFB1000 TO 0xFB1FFF;