Help decoding this cryptic FTFE documentation

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

Help decoding this cryptic FTFE documentation

Jump to solution
1,006 Views
paulderocco
Contributor III

I'm using the MK64FN1M0, and looking at the K64 Sub-Family Reference Manual, Rev. 2, January 2014. I want to erase and reprogram the zeroth sector in block 1 of my program flash. I can see how the Erase Flash Sector command works, but I'm trying to figure out if the Program Section command is appropriate, and how to use it if it is. It refers to the "Section Program Buffer", which the Glossary defines as the "Lower quarter of the programming acceleration FlexRAM". Well, I don't have any FlexRAM, just 4KB of "programming acceleration RAM" which is supposedly accessible at 0x14000000. However, 29.4.12.8.1 on page 708 suggests that the latter can be used in lieu of the former. Step 3 begins, "Beginning with the starting address of the programming acceleration RAM (program flash only devices) or Flex RAM (FlexNVM devices), sequenctially write enough data to the RAM to fill an entire flash sector." Subsequent steps say to issue the Program Section command, and then go back and erase the next sector, which I don't have to do since I'm only writing one sector.

However, 29.4.12.8 says that "The section program buffer is limited to the lower quarter of the FlexRAM (byte addresses 0x0000-0x03FF). Data written to the remainder of the FlexRAM is ignored and may be overwritten during Program Section command execution." This is only 1K. I believe FlexRAM is a lot bigger than 4K, so this suggests that the numbers may refer to the programming acceleration RAM instead. But if I can only use the first 1K of that, how do I program an entire sector?

I get the feeling that this documentation is all wrong, and that one of the following three things must be true:

1) I can load the entire 4K of the programming acceleration RAM with what I want to write to the sector, and use one Program Section command to program the sector.

2) I can load the first 1K of the programming acceleration RAM with one quarter of what I want to write to the sector, use the Program Section command to program one quarter of the sector, then repeat that three more times to fill in the whole sector.

3) The Program Section command really is just for FlexNVM parts, and I need to use the Program Phrase command 512 times.

Can anyone tell me which is the case?

Tags (2)
0 Kudos
1 Solution
605 Views
mjbcswitzerland
Specialist V

Paul

The K64 without FlexNVM has 4k acceleration RAM (it is referred to as "programming accelaration RAM" rather than "FlexRAM" but is the same thing).

1. This is not true since only the first (up to) 1k of the acceleration RAM is programmed to flash. The rest "may" be changed during the operation (it is used by the internal programming algorithm for its own work space) and so should therefore not be used for any further data storage.

2. This is correct.

3. The program section command can be used as an alternative to phase programming. However it doesn't need to be used and just phase programming can be used for everything if you prefer.

Phase programming programs 8 bytes at a time and section programming a multiple of this, up to 1k. Section programming is a bit faster to execute though - programming 1k of memory using phrase programming takes typically 9ms whereas doing the same using a single section command takes typiclly 5ms.

In both cases the procedure is repeated using different flash starting addresses if larger amounts of data are to be programmed (and when sector boundaries are encountered).

Both have to start on a phrase programming boundary (128 bit alignment) and the complete section programming area must be within a single 4k Flash sector. Section programming is simply an internal algorithm that is being called to perform multiple phase program operations that are repeated up to 128 times by the Flash controller (like a memcpy() from the start of acceleration RAM to the Flash phrase address specified). The section command specifies the number of phrases to be programmed (1 to 128) whereby 1 would be equivalent to a phrase write so can be used to program a 'burst' of 8, 16, 24, 32 ... 1k bytes at a time.

Regards

Mark

P.S. If not using section programming the 4k acceleration RAM can be used for other purposes (variable storage).

View solution in original post

0 Kudos
4 Replies
605 Views
BitBangerB
Contributor II

I too found that the following instruction makes the documentation ambiguous: "sequentially write enough data to the RAM to fill an entire flash sector".  If only 1/4 of the 4k is usable for section programming then it is not possible to fill it with enough data for an entire 4k sector.  I'm happy to find I am not the only one confused by this.

I will proceed to use phrase programming instead.  Now I am wondering if I can use that 4k of RAM just for a sector buffer so long as I don't use section programming.  Mark has stated this can be done.  Can anybody confirm this?

0 Kudos
606 Views
mjbcswitzerland
Specialist V

Paul

The K64 without FlexNVM has 4k acceleration RAM (it is referred to as "programming accelaration RAM" rather than "FlexRAM" but is the same thing).

1. This is not true since only the first (up to) 1k of the acceleration RAM is programmed to flash. The rest "may" be changed during the operation (it is used by the internal programming algorithm for its own work space) and so should therefore not be used for any further data storage.

2. This is correct.

3. The program section command can be used as an alternative to phase programming. However it doesn't need to be used and just phase programming can be used for everything if you prefer.

Phase programming programs 8 bytes at a time and section programming a multiple of this, up to 1k. Section programming is a bit faster to execute though - programming 1k of memory using phrase programming takes typically 9ms whereas doing the same using a single section command takes typiclly 5ms.

In both cases the procedure is repeated using different flash starting addresses if larger amounts of data are to be programmed (and when sector boundaries are encountered).

Both have to start on a phrase programming boundary (128 bit alignment) and the complete section programming area must be within a single 4k Flash sector. Section programming is simply an internal algorithm that is being called to perform multiple phase program operations that are repeated up to 128 times by the Flash controller (like a memcpy() from the start of acceleration RAM to the Flash phrase address specified). The section command specifies the number of phrases to be programmed (1 to 128) whereby 1 would be equivalent to a phrase write so can be used to program a 'burst' of 8, 16, 24, 32 ... 1k bytes at a time.

Regards

Mark

P.S. If not using section programming the 4k acceleration RAM can be used for other purposes (variable storage).

0 Kudos
605 Views
paulderocco
Contributor III

Thanks for that clear information. Did you have to figure that out from experimenting, or is there better documentation somewhere?

0 Kudos
605 Views
mjbcswitzerland
Specialist V

Paul

If you re-read section 29.4.12.8 (and also observe the error codes that can be returned to the command) you should find that all information is actually there.

On the other hand it always helps to experiment - the sequences can be performed with any debugger (just type in the sequences in the FTFL registers and watch what happens) so if anything is unclear it can be practically verified in a few minutes.

In the uTasker project there is a Flash driver that automatically switches between phrase and section programming depending on flash alignment, boundary locations etc. (when allowed - see #if defined USE_SECTION_PROGRAMMING below).

There is however a disadvantage with section programming that I didn't mention in the previous post; while programming 1k using phrase writes may take twice as long as a section write it is being split into 128 write operations lasting typically 70us each. Usually interrupts are blocked during each phrase write operation since the Flash can't be used for code execution (Flash program routines always execute from RAM). This means that between each phrase programming duration interrupts can be handled and so it is still possible to receive data streams (for example 57600kBaud UART streams in parallel without overruns - assuming interrupt driven and not DMA driven). When programming 1k with the section command the interrupt will be blocked typically 5ms long and so communication streams using interrupts that need to be received in parallel with flash writing will start to fail (overruns) even at low data rates unless additional interrupt handling is also run in RAM.

As reference, the write routine (not showing the actual command interface, which is in fnFlashNow() and controls blocking interrupts and execution from RAM where needed - it also simulates the internal Flash operation to allow incorrect use to be detected before moving to target level debugging) is show below. This allows writing any size of data (1 byte to max. possible) and also allows operation on any K, KE or KL part (adapts itself to write sizes and flash granularity etc. note that some K parts can write up to 2k of data in a single section write command). It has a local phrase buffer allowing users to write part phrases so that the flash programming rules are not 'fully' exposed at the higher level.

Regards

Mark

static int fnWriteInternalFlash(unsigned long ulFlashAddress, unsigned char *ucData, MAX_FILE_LENGTH Length)

{

    static unsigned char *ptrOpenBuffer = 0;

    unsigned char *ptrFlashBuffer;

    unsigned long ulBufferOffset;

    MAX_FILE_LENGTH BufferCopyLength;

    if (ucData == 0) { // close an open buffer

        ulBufferOffset = ((CAST_POINTER_ARITHMETIC)ptrOpenBuffer & (FLASH_ROW_SIZE - 1));

        if (ulBufferOffset == 0) {

            return 0; // no open buffer so nothing to do

        }

        ulBufferOffset = FLASH_ROW_SIZE; // cause the open buffer to be saved without copying any input data

        ptrOpenBuffer = (unsigned char *)((CAST_POINTER_ARITHMETIC)ptrOpenBuffer & ~(FLASH_ROW_SIZE - 1));

    }

    else {

        ptrOpenBuffer = (unsigned char *)(ulFlashAddress & ~(FLASH_ROW_SIZE - 1)); // set to start of long word or phrase that the address is in

        ulBufferOffset = (ulFlashAddress & (FLASH_ROW_SIZE - 1)); // offset in the long word or phrase

    }

    do { // handle each byte to be programmed

        #if defined USE_SECTION_PROGRAMMING

        if (ulBufferOffset == 0) { // if the data start is aligned there is a possibility of using accelerated section programming

            MAX_FILE_LENGTH SectionLength = (Length & ~(FLASH_ROW_SIZE - 1)); // round down to full long words/phrases

            if (SectionLength > (FLASH_ROW_SIZE * 2)) { // from 2 long words or phrases

                unsigned char *ptrEnd = (unsigned char *)((CAST_POINTER_ARITHMETIC)ptrOpenBuffer & ~(FLASH_GRANULARITY - 1));

                ptrEnd += FLASH_GRANULARITY; // pointer to the next flash sector

                if ((ptrOpenBuffer + SectionLength) >= ptrEnd) { // end of write is past a sector boundary

                    SectionLength = (ptrEnd - ptrOpenBuffer); // limit

                }

                if (SectionLength > (FLASH_ROW_SIZE * 2)) { // if still at least 2 long words or phrases to make section write worthwhile

                    if (SectionLength > FLEXRAM_MAX_SECTION_COPY_SIZE) {

                        SectionLength = FLEXRAM_MAX_SECTION_COPY_SIZE;

                    }

                    uMemcpy((void *)FLEXRAM_START_ADDRESS, ucData, SectionLength); // copy the data to the accelerator RAM

                    ulFlashRow[0] = (SectionLength/FLASH_ROW_SIZE); // the number of long words/phrases to be written to the section

                    if ((fnFlashNow(FCMD_PROGRAM_SECTOR, (unsigned long *)ptrOpenBuffer, &ulFlashRow[0])) != 0) { // write section

                        return 1; // error

                    }

                    ptrOpenBuffer += SectionLength;

                    Length -= SectionLength;

                    ucData += SectionLength;

                    if (Length == 0) {

                        return 0;

                    }

                    continue;

                }

            }

        }

        #endif

        BufferCopyLength = (FLASH_ROW_SIZE - ulBufferOffset); // remaining buffer space to end of present backup buffer

        if (BufferCopyLength > Length) { // limit in case the amount of bytes to be programmed is less than the long word or phrase involved

            BufferCopyLength = Length;

        }

        ptrFlashBuffer = (unsigned char *)ulFlashRow + ulBufferOffset; // pointer set in FLASH row backup buffer

        uMemcpy(ptrFlashBuffer, ucData, BufferCopyLength); // copy the input data to the FLASH row backup buffer

        ucData += BufferCopyLength;

        Length -= BufferCopyLength; // remaining data length

        ptrFlashBuffer += BufferCopyLength; // next copy location

        if (ptrFlashBuffer >= ((unsigned char *)ulFlashRow + FLASH_ROW_SIZE)) { // a complete backup buffer is ready to be copied to FLASH

            ptrFlashBuffer = (unsigned char *)ulFlashRow; // set pointer to start of FLASH row backup buffer

            ulBufferOffset = 0;

            if ((fnFlashNow(FCMD_PROGRAM, (unsigned long *)ptrOpenBuffer, &ulFlashRow[0])) != 0) { // write long word/phrase

                return 1; // error

            }

            ptrOpenBuffer += FLASH_ROW_SIZE;

            uMemset(ulFlashRow, 0xff, FLASH_ROW_SIZE); // flush the intermediate buffer

        }

        else { // incomplete buffer collected

            ptrOpenBuffer += BufferCopyLength;

        }

    } while (Length != 0);

    return 0;

}

0 Kudos