MCF51QE Flash and Interrupts

cancel
Showing results for 
Search instead for 
Did you mean: 

MCF51QE Flash and Interrupts

1,813 Views
sebasira
Senior Contributor I

Hello!

 

I've an application that communicates via SCI @57600bps and writes permanent data in FLASH. It uses a MCF51QE128 running at 25MHz.

I'm using routines from AN3942.

 

In that document, where it talks about implementation, in the example:

 

void main(void) {   Clock_init();        // initialization of  clock source on JM128   Flash_Clock_Init();  // initialization of  flash clock frequency   length_data = 10;    // the length of the data is 10 bytes   adress = 0x2000;     // the source data will program to this address   DisableInterrupts;    FlashErase(address);  // erase function    FlashProg(address, source_data, length_data); //program function   EnableInterrupts; }

 

Before calling FlashErase and FlashProg, interrupts are disabled. I meassure the time, and Erase takes 20mseg. The problem is that this time is sometimes too much for the SCI communication and I lose some characters.

 

I'm not using any kind of flow control. I guess maybe that's what I should do.

 

The question is: Does Interrupts MUST be disable? Or can I disable them anywhere else inside FlashErase/Prog so the time that they are disabled is smaller?

 

 

Thanks in advance!

Labels (1)
13 Replies

1,128 Views
TomE
Specialist I

> Before calling FlashErase and FlashProg, interrupts are disabled

Interrupts are disabled so that your code can't do anything that the Flash programming can't handle. It is a "sledgehammer" approach that works, but has its downsides as you've found.

You need to know in more details exactly what the Flash programming can tolerate and what it can't. Then you can' change it and your code to work together.

if the Vectors are in FLASH then they aren't available to the CPU while it is working on the FLASH. But you can move the vectors to RAM and be able to take interrupts.

If the interrupt service routines are in FLASH, then likewise, they can't be executed.

If the FLASH programming has some critical software timings, then you need to know what they are and write your code to guarantee not to cause problems.

So before entry to the FLASH programming, copy the Vectors to RAM, point the CPU at them, copy your SCI interrupt service routine to RAM (and change the vector to point to it), set the SCI to interrupt at IPL6 (or 7), make sure that's the only interrupting device that high and have the FLASH programming enable that level.

But there's a WAY simpler solution available.

There should only be a few places in the FLASH burning code where it is wasting time, waiting for a FLASH operation to complete. "Hook" those loops. They're polling the FLASH. Have them poll the SCI receiver at the same time, and put any received characters into a RAM-based buffer for handling after the FLASH burning has finished. That way you won't lose any messages.

Tom

1,128 Views
sebasira
Senior Contributor I

Hi Tom!

It's an interesting solution. And a very usefull information. I always believe that interrupts must be disabled because of strict timming of the flash erase/prog internal procedure.

Thanks for your reply!

But for now, I guess I'll attach to peridically query the GPRS status.

SebaS

0 Kudos

1,128 Views
TomE
Specialist I

> I always believe that interrupts must be disabled because of strict timming

> of the flash erase/prog internal procedure.

FLASH (and EPROM) from 20 years ago was like that, where the program had to worry about the timing. I doubt if this FLASH is like that.

Time for me to look at the Reference Manual to see what sort of FLASH this is.

4.4.1 Features

Features of the flash memory include:

• Automated program and erase algorithm

From reading this chapter it is only necessary to write a command (Erase Verify, Program, Burst Program, Sector Erase, Mass Erase) to FCMD and then poll FSTAT while waiting for the command to complete.


So there are no timing restrictions at all.


There are SEQUENCE restrictions. Section "4.5.1.2 Command Write Sequence" details the command order, and the writes (to the FLASH and the command register) can't be interrupted by anything that would wreck the sequence. But you only need to disable interrupts around that (short) sequence to guarantee that.


The reason that interrupts are disabled for a long time is that the FLASH can't be READ while it is being programmed or erased. Section "4.4 Flash" states "It is not possible to read from a flash block while any command is executing on that specific flash block".

If the Vector Area is in FLASH it can't be accessed, so you can't allow any interrupts that would try to read a vector. If the code for the interrupt service routine is in FLASH it can't be read/executed either.

Luckily you have an extremely simple requirement - don't miss incoming characters on a serial port. So all you have to do is poll the serial port while polling FSTAT and copy and characters to a temporary buffer.

Tom


1,128 Views
sebasira
Senior Contributor I

I think now I've learn a little bit more about FLASH and clear some doubts. I never realize that "It is not possible to read from a flash block while any command is executing on that specific flash block" means that code can not be executed (because execution needs reading), I always think of it as "my application reading a value"

Looking at AN3942's Source Code, I guess here is where I should be polling SCI data register, right? (I mean inside loop_1)

/********************** ERASE SUBROUTINE **************************/

/*** THIS PART OF SOURCE CODE MUST RUNNING IN RAM ***/

SpSub:

        move.b  #mFSTAT_FCBEF,d1       /*   Clear  FCBEF 0x80             */

        move.b  d1,(FSTAT)                      /*   Write: FSTAT register         */

loop_1:

        move.l  #FSTAT,a4                       /* Read: FSTAT register            */

        move.b  (a4),d2

        moveq   #0,d1         

        move.b  d2,d1                              /* FCCF Set? */

        andi.l  #0x40,d1      

        beq.s   loop_1

SpSubEnd:

        rts

0 Kudos

1,128 Views
TomE
Specialist I

> I guess here is where I should be polling SCI data register, right?

Yes. It is a pain that code is in assembly, unless all of your other code is as well.

That isn't the worst assembly code I've ever seen, but it comes close.  It directly writes to (FSTAT), and then it loads that register's address into a register INSIDE THE LOOP. It should do one or the other, and not reload inside the loop, or clear "d1" inside the loop. This is a "polling loop" so it doesn't have to be fast, but is bad practice and ugly-ugly-ugly. Why is it loading a byte, copying to a different register, clearing the upper 24 bits when the "AND" is only testing one bit anyway? Half of the instructions in that loop are redundant.

The function doesn't clear the error bits and it isn't testing the error bits either. If those checks aren't done anywhere else in the code then it would be very easy to have it lock up if called with a bad address, and not tell you why, or lock up and silently fail until the CPU has been reset. Not a good programming example.

Another problem with trying to add your code (to read and stash SCI bytes) is that you don't know what registers the callers to that function are using and what registers that function is allowed to use. i\It is essential programming practice to document the register calling and preservation conventions in use. This code doesn't do that anywhere I can see (and I've downloaded the entire ZIP archive and looked)l, so you're going to have to reverse-engineer the lot to make sure you're not clobbering anything, or you'll have to save all registers somewhere to make sure you don't accidentally corrupt something a caller is using.

You need to poll and read bytes into a buffer. You have to keep track of buffer pointers, or indexes and counts. This is fairly simple in C but tricky in assembly. Then you have to share the common buffer and index between this code and your mainline (easy if your code is assembly, a bit trickier if you're using C).

If you haven't written ColdFire assembly before, watch out, there are some traps. A byte read to a register doesn't zero or sign extend to the upper bits. That's why that code above is clearing d1 (but doesn't need to). The M68k on which it was based was more symmetric (with respect to byte/word/long ops) but the ColdFire instructions are 32 bits mainly. Watch out for the differences between Address and Data registers.

Good luck.

Tom

0 Kudos

1,128 Views
sebasira
Senior Contributor I

> Half of the instructions in that loop are redundant

You're right, I haven't check ir before...

About error bits, I already check them outside this, to ensure the operation was properly executed.

> Another problem with trying to add your code (to read and stash SCI bytes) is that you don't know what registers the callers to that function are using and what registers that function is allowed to use

About that, it's a mess!!! Because it came from another functions also in asm (from AN3942). And I would need to do this both in ERASE and BURST PROG. So, maybe if I save all the registers, then it wouldn't be a problem. The only thing I would be wasting is time. And a little stack.

>You need to poll and read bytes into a buffer. You have to keep track of buffer pointers, or indexes and counts. This is fairly simple in C but tricky in assembly. Then you have to share the common buffer and index between this code and your mainline (easy if your code is assembly, a bit trickier if you're using C).

Why couldn't I call the same function as the SCI Rx ISR? There I handle the pointers and the buffers and it do it correctly. I'm programming in C. The only code in ASM is the one from AN3942.

>If you haven't written ColdFire assembly before, watch out, there are some traps

I'm used to the ASM of HC08 and HCS12... I don't understand the one from ColdFire, but also I've never try to...

Thanks Tom!!! Best Regards!

SebaS

0 Kudos

1,128 Views
TomE
Specialist I

> And I would need to do this both in ERASE and BURST PROG.

You can't make the Erases faster. You CAN make the "Burst Program" faster, by limiting the burst length called from your program, or by programming a "big burst" as a series of smaller "burst" calls from your code, with the interrupts enabled between the bursts (to let the SCI interrupts run).

> Why couldn't I call the same function as the SCI Rx ISR?

Because if that code is in FLASH, then  "It is not possible to read from a flash block while any command is executing on that specific flash block".

You could do that AS LONG AS the all of the SCI interrupt service routine code (and any functions it calls and any fixed data structures it uses) is in RAM and not in FLASH, or you have moved a copy of that function into RAM somehow and call it there.

I prefer to use micros with lots of FLASH and RAM and copy all the code from FLASH to RAM and execute from there. That gets around all these problems. In these CPUs reading RAM is usually a lot faster than reading FLASH too. My last project has 32M of FLASH and 16M of RAM. My current project has 512M of RAM. I've been lucky enough to be on projects that need this much RAM and can't fit into a single-chip solution like you're working with.


> I don't understand the one from ColdFire, but also I've never try to...

Maybe you don't have to. Write a simple function  IN C that polls the SCI status register and reads the character into a buffer and then compile it with the Optimization set LOW (so the code it generates is easier to understand and less tricky). Get your Development Environment to show you the generated assembly for that function and then use THAT as the source assembly code you then copy into ERASE polling loop. Leave the original C code as comments in that assembly to help with understanding it.

Tom

0 Kudos

1,128 Views
TurboBob
Contributor IV

A couple questions first,   How much data are you trying to receive,  and over what period of time?   You are receiving at 57K baud,  but are there any gaps in the data,  what rate is the data arriving?

The erase generally takes a lot longer than the write,  depending on how much data you are dealing with it may be possible to erase the section of flash at start up and just write data as its received.  A burst write might help you write several bytes quickly.  I believe you could narrow the timing of the interrupt disable,  but the erase will still be too long.

The erase function clears a large section,  you don't erase a byte at a time with flash.

It might be better (assuming the data is small) to save it in RAM and store to flash at powerdown.  (I'm not sure what stage of development you are at)

worst case,  a serial eeprom might be the best solution.

Bob

0 Kudos

1,128 Views
sebasira
Senior Contributor I

Hi Bob!

Thanls for your input! As I read your post I realize how poor was my explanation. Im using the SCI to communicate with a GSM/GPRS module with AT Commands. Data rate is not high, usually is on stand-by. And when a write to Flash is request no more than 20bytes are written.

I don't know if your familiar with AT Commands, there URC (unsolicited result codes) that the modem may issue anytime and if it coincide with a write to Flash, then that URC is lost. The problem is that I can't predict when a URC may arrive.

Your idea of writting at power down could work with some data, but there another one such as configuration and so that are retrieved from Flash. Changing all of it would be a headache. Now we're at testing stage.

This problem does not ocurr often because of it nature; but when it does, it's a pain. Let say, for example that I miss the URC for a "new SMS receive", then unless I constantly check on it, I wouldn't notice.

As said before, I was thinking on using flow control, but I beleive I'm missing something here. It's actually a very basic application, that only recieve data from GSM/GPRS and store some in Flash. I think maybe there's a simpler solution.

Also, now that I think about it, I could speed up the SCI to 115200bps and prevent Flash writes when receiving. This will lower the probability of a write request in the exact moment an URC is issued.

What do you think?

Sebastian M. Irazabal

Rosario, Argentina

0 Kudos

1,128 Views
TurboBob
Contributor IV

I would try a couple things.

1,  just reducing the chance of an error is not the same as fixing it.

2,  if you erase a section of flash at startup,  then you only have to write.

3,  if you reduce the baud rate,  then you will have longer time to write.

4,  you will eventually miss a URC,   Assume that you will miss them and design the software to check for

it often and ensure no data is ever lost. 

5,  or save all the data to RAM,  write to flash at power-off.  this requires detecting power-off and having enough time to complete the write before the CPU shuts off.  This is not my favorite solution as it relies on things that are difficult to test in production.

Bob

1,128 Views
sebasira
Senior Contributor I

About what you suggest:

1. You're totally right

2. Erasing at startup would only reduce time for the first write, the next one would need to re-erase, and so on.

3. Also think about it, but for example at 9600bps, a character would take about 900usec, and 20msec is still a lot. May reducing it even more.

4. I think this may be the best choice. The things that the URC reports can be checked (unread SMS, connection status, registration status, etc)

5. I think this method would not apply to application, because of it requierements.

So, returning to the original question... flash erase time or the time interrupts are disabled can not be reduce?

Thanks for your help!

0 Kudos

1,128 Views
TurboBob
Contributor IV

ok,  we are making progress.  how often do you need to write data?

Just be aware of wearing out the flash.

There is really no way to shorten the interrupt blocking time,  the delay for erase is the big one.

It seems that just checking the GPS status after you perform a flash operation (or just periodically) is the simplest/best solution.

Bob

1,128 Views
sebasira
Senior Contributor I

Well, if it is impossible to reduce IRQ disabled time, then I guess the best aproach would be to check periodically for those status.

In addition, it would make the system more roboust.

Thanks for helping me and clearing my mind

SebaS

0 Kudos