MCF52259 Internal flash problems/errors

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MCF52259 Internal flash problems/errors

Jump to solution
3,450 Views
FridgeFreezer
Senior Contributor I

Me again! (don't worry, project is nearly finished then I'll go away for a bit :smileywink:)

 

I'm having some weird issues using the Freescale-supplied CFM erase/program routines as seen in their MCF52259 USB Bootloader application note supplied with the M52259EVB / DEMOMCU boards.

 

I'm using CW7.2.2 (just found the 7.2.1/7.2.2 patches today!), micro is MCF52259 on our own board, running direct from 48MHz crystal (no PLL) as per the EVB.

 

I've narrowed the issue down to errors in the flash after programming, which may be down to the CFMCLKD value, or maybe something else stupid that I've done...

 

We can erase, blank check, program & verify the device(s) via the BDM pod with no issues (in other words, the device is working OK & not damaged).

 

Using a tweaked version of the Freescale USB bootloader (we load from SPI Flash rather than USB, the but the CFM routines are untouched) we can erase the internal flash OK, but when we program it it doesn't always work - we get stray bits which are unprogrammed. Running a debug routine where we erase the flash & then prgram all zeros gives us a result that looks like the attached picture.

 

Something that has caused some confusion (I'm easily confused) is the CFMCLKD value, as also seen here:

https://community.freescale.com/message/41160#41160

The original Freescale routine, which states it's for a "clock" of 24MHz (Fsys = 48MHz == BUSCLK of 24MHz), uses PRDIV8 & a CLKDIV value of 0x0F, which by my calculations yeilds an FCLK of 187.5kHz (24000/8/(15+1)), so this is what I'm using.

 

If we just erase the fash & then do a series of single 32-bit word writes, filling the flash with 0x00000000, we get random bits which are not set to 0. If we read it back, we read back different values, for example:

ptr = 0x00004000 // Flash address to read, should read back 0x00a = *ptr;b = *ptr;c = *ptr;d = *ptr;

 

Will give a result something like:

a = 0x08

b = 0x48

c = 0x08

d = 0x08

And reading the address 0x00004000 with the BDM pod will read back 0x08. Sometimes one or more of the results read back will be correct (although the BDM pod usually agrees with the "wrong" one, maybe because it reads the data more slowly?)

 

All help gratefully received as ever!

Labels (1)
0 Kudos
Reply
1 Solution
1,202 Views
FridgeFreezer
Senior Contributor I

Well it looks like I've found the problem, the CFMCLKD register is write ONCE only, so you can't set it up like this:

 

MCF_CFM_CFMCLKD = MCF_CFM_CFMCLKD_PRDIV8; // Set div8MCF_CFM_CFMCLKD |= 0x10; // Set divider

 You have to set it up like this:

 

MCF_CFM_CFMCLKD = (MCF_CFM_CFMCLKD_PRDIV8 | 0x10);

 Now that's done, it all works beautifully!

 

I'm going to lay down in a darkened room now...

View solution in original post

0 Kudos
Reply
9 Replies
1,202 Views
FridgeFreezer
Senior Contributor I

I've just tried the (slightly naughty) experiment of writing the flash twice, across a page-size area, so:

// *bufp points to an array of 2048 bytes, all zero// call flash programtemp = (unsigned char) Flash_Prog(address, bufp, (i >> 2));// call flash program again (go over it with a thicker pencil)temp = (unsigned char) Flash_Prog(address, bufp, (i >> 2));

 On the first pass, we have the "usual" random bit errors maybe 40-100 bytes apart, after the 2nd pass all bytes are correctly written to zero. I know this is bad for the flash but I think it proves something about what's going on here...

 

The boss (who has a better maths brain) has been over Freescale's calcs in the data sheet, as well as you guys' version

https://community.freescale.com/message/41160#41160 and belives that our prescaler should actually be 16 (but could also be 17 or 18) as the +1/-1 part of the calculations seems to be wrong. We've tried 15, 16 and 17 but none of them seem to make very much difference, the errors reduce if we go a bit slower (using 17 at the moment).

 

I've also tried writing 0x11, which is placing less stress on the flash than writing all zeros, and that is a lot more reliable (although it still gives random bit errors).

0 Kudos
Reply
1,202 Views
FridgeFreezer
Senior Contributor I

The fun continues, I think I've spotted a bug in Freescale's own code:

 

uint8 Flash_Cmd(uint8 Cmd){      MCF_CFM_CFMCMD = Cmd;      MCF_CFM_CFMUSTAT = 0x80;     // launch command        if(MCF_CFM_CFMUSTAT&0x30)    {      return 0xFF;    }        // *** This is pointless as it's just while(!0x80) ***    while(!MCF_CFM_CFMUSTAT_CCIF){}      return 0x01;  }

 It's either a bug, pointless code, or some sort of super coding kung-fu that us mere mortals can't understand :smileyindifferent:

0 Kudos
Reply
1,202 Views
TomE
Specialist II

Not waiting for the command to finish (and then sending the next one) could explain your problem.

 

Search for "MCF_CFM_CFMUSTAT_CCIF" in this forum (and using Google elsewhere) to get other examples.

 

The above weird code waiting on a constant MIGHT be a "leftover" if all the code that calls this function has the "wait" code in it (like some of the samples my search found).

 


Compare the code with the flowcharts in the manual. They look pretty good. Maybe...

 

Check all your power supplies during the programming operations, just in case the current consumption goes up. There's no documentation on "current during program/erase" that I can find.

 

Tom

 

0 Kudos
Reply
1,202 Views
FridgeFreezer
Senior Contributor I

Thanks Tom,

You're right, the parent function contains the wait for CCIF/CBEIF:

void EraseFlash(void)
{
    volatile uint32 addr;
    unsigned char temp;
   
    // erase each page of flash
    for(addr=MIN_FLASH1_ADDRESS;addr<=MAX_FLASH1_ADDRESS;addr+=FLASH_PAGE_SIZE) {
        if(addr > FLASH_PROTECTED_ADDRESS)
        {
            while(!(MCF_CFM_CFMUSTAT & MCF_CFM_CFMUSTAT_CBEIF))
            {
                nop();// wait for CFM to be ready for new command
            }
           
            // OK go
            temp = (uint8) Flash_Erase(addr + FLASH_ADDR_OFFSET); // Calls FlashCmd()
            if(gFlashError == temp)
            {
                // Error Erasing Flash
                BootloaderStatus = BootloaderFlashError;
                return;
            }
        }
    }
    // Wait for all cmds to finish before returning
    while(!(MCF_CFM_CFMUSTAT & MCF_CFM_CFMUSTAT_CCIF));    // wait for CFM to completely finish

}

We've monitored the current consumption and it doesn't seem to change with flash erase/program operations although we will re-check more closely.

0 Kudos
Reply
1,202 Views
FridgeFreezer
Senior Contributor I

One thing that I have just noticed - the freescale code runs FlashCmd() from RAM but because it doesn't contain any wait polling, it will immediately return to the calling function and run from flash while the flash operation is still executing, which I thought was a no-no :smileysurprised: I think the Freescale code has been hacked about a bit...

 

I've also just been reading through https://community.freescale.com/message/18463#18463 which is for the MCF5223x, and the CLKDIV formula appears to use the OSCCLK without the divide-by-two that is used in the 52259 examples, despite the core being exactly the same (M52235RM.pdf has the same clock block diagram as M52259), which throws up questions about the clock divider maths...

 

static void fnConfigFlash(void) // M5223x example from mjbcswitzerland{CFMUSTAT = (ACCERR | PVIOL); // clear error flagsif (CFMCLKD & DIVLD) return; // already configured// before erasing or writing FLASH, the clock must be configured correctly// we want to be in the 150kHz..200kHz range but as fast as possible// This works for oscillator clocks greater than 12.8MhzCFMCLKD = (PRDIV8 | (unsigned char)((OSCCLK/200000/8))); // warning - If in doubt, best check that it is in range before using - errors can destroy FLASH!!!}

0 Kudos
Reply
1,202 Views
FridgeFreezer
Senior Contributor I

...just found *another* bug in Freescale's code, they go to the trouble of copying code to RAM but then completely fail to run it and just execute from flash, for example:

 

// sector erase (2k bytes)uint8 Flash_Erase(uint32 addr){    FnCmdInRam = (void*)((uint32)&CmdInRam); // Create alias function in RAM    CmdInRam = *(CmdInRam_t *)(Flash_Cmd);  // Copy Flash_Cmd to function in ram    MCF_CFM_CFMUSTAT = 0x30;                 *(uint32 *)addr = 0x55; // Write dummy data to address        return(Flash_Cmd(0x40));    // Should be return(FnCmdInRam(0x40));}

 

This is getting to be a flipping joke - depending whose documentation or code you read the clock divisor can be a factor of two wrong (M5223x example), you can execute from FLASH (CPUStick example or Freescale's dodgy code) or must execute from RAM (uTasker & Freescale's advice), you wait for CCIF or just CBEIF... ARGH!

 

Someone must have some working code for the M52259 CFM somewhere...

0 Kudos
Reply
1,203 Views
FridgeFreezer
Senior Contributor I

Well it looks like I've found the problem, the CFMCLKD register is write ONCE only, so you can't set it up like this:

 

MCF_CFM_CFMCLKD = MCF_CFM_CFMCLKD_PRDIV8; // Set div8MCF_CFM_CFMCLKD |= 0x10; // Set divider

 You have to set it up like this:

 

MCF_CFM_CFMCLKD = (MCF_CFM_CFMCLKD_PRDIV8 | 0x10);

 Now that's done, it all works beautifully!

 

I'm going to lay down in a darkened room now...

0 Kudos
Reply
1,202 Views
TomE
Specialist II

Not exactly obvious, is it. Sandwiched between "Figure 18-5" and "Table 18-5" is the one line:

 

All CFMCLKD register bits are readable, while bits [6:0] write once and bit 7 is not writable.

That explains why the register has a "DIVLD" bit, and why the code I've been reading only writes to the register if DIVLD isn't set.

 

It would have been a lot friendlier if the sample code tested that bit, and if already set checked the divider value and then printed an ERROR MESSAGE if it couldn't set it to the right value, or perhaps had a COMMENT on it saying what it was doing and why.

 

Concerning the "execute from RAM or execute from FLASH", my previous reading of this forum indicates that some chips can program FLASH "while they're running in it" as the hardware either has multiple FLASH banks or can lock the CPU out while the FLASH opoerations are proceeding. Other chips can't do that and require the burning code to run from RAM. "Generic code" (to run on more than one of them) should support both methods, or be as "general purpose" as possible (meaning "run in RAM"). That may explain, but not excuse, the "leftover" bits you're seeing in the sample code.

 

Tom

 

 

0 Kudos
Reply
1,202 Views
FridgeFreezer
Senior Contributor I

I'm glad you didn't reply with "well of course it's write-once you idiot!" :smileyvery-happy:

 

The example page in the manual also neatly skips over the issue:

For example, if the bus frequency is 33 MHz, CFMCLKD[DIV] should be set to 0x14 and bit PRDIV8 set to 1.

 Which sounds like you can do

CFMCLKD = 0x14;CFMCLKD |= PRDIV8;

 What did throw me is how reliably the thing operated at what I assume must have been about 15x the recommended speed! We were seeing errors in the order of one or two bytes per kb of data written, I'd expect it to hardly manage to write anything at all racing away at ~3MHz instead of 200KHz :smileysurprised:

 

It would be nice if the device manual explicitly stated what you can & can't do with regard to running from flash whilst programming flash, they do leave it a bit open to interpretation.

0 Kudos
Reply