K64 Writing Flash - the last 8 byte missing

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

K64 Writing Flash - the last 8 byte missing

1,033 Views
MarcoGiammarini
Contributor III

Hello to everyone,

I wrote a small routine to write data into flash memory.  When I try to write an array of 24 byte, the last 8 byte doesn't write and I don't understand why! There is some error in my code?

Regards

Marco

static System_Errors Flash_sequenceCommand (Flash_DeviceHandle dev)
{
    // check CCIF bit of the flash status register
    // wait until CCIF bit is set
    while(0 == (FTFE_FSTAT_REG(dev->regMap) && FTFE_FSTAT_CCIF_MASK));

    // Clear RDCOLLERR, ACCERR and FPVIOL flag into status register
    FTFE_FSTAT_REG(dev->regMap) = FTFE_FSTAT_RDCOLERR_MASK |
                                  FTFE_FSTAT_ACCERR_MASK |
                                  FTFE_FSTAT_FPVIOL_MASK;

    FTFE_FCCOB0_REG(dev->regMap) = dev->commandArray[0];
    FTFE_FCCOB1_REG(dev->regMap) = dev->commandArray[1];
    FTFE_FCCOB2_REG(dev->regMap) = dev->commandArray[2];
    FTFE_FCCOB3_REG(dev->regMap) = dev->commandArray[3];
    FTFE_FCCOB4_REG(dev->regMap) = dev->commandArray[4];
    FTFE_FCCOB5_REG(dev->regMap) = dev->commandArray[5];
    FTFE_FCCOB6_REG(dev->regMap) = dev->commandArray[6];
    FTFE_FCCOB7_REG(dev->regMap) = dev->commandArray[7];
    FTFE_FCCOB8_REG(dev->regMap) = dev->commandArray[8];
    FTFE_FCCOB9_REG(dev->regMap) = dev->commandArray[9];
    FTFE_FCCOBA_REG(dev->regMap) = dev->commandArray[10];
    FTFE_FCCOBB_REG(dev->regMap) = dev->commandArray[11];

    // Clear CCIF flag into status register
    FTFE_FSTAT_REG(dev->regMap) |= FTFE_FSTAT_CCIF_MASK;

    if (FTFE_FSTAT_REG(dev->regMap) & FTFE_FSTAT_ACCERR_MASK)
        return ERRORS_FLASH_ACCESS;
    else if (FTFE_FSTAT_REG(dev->regMap) & FTFE_FSTAT_RDCOLERR_MASK)
        return ERRORS_FLASH_ACCESS;
    else if (FTFE_FSTAT_REG(dev->regMap) & FTFE_FSTAT_FPVIOL_MASK)
        return ERRORS_FLASH_PROTECTION_VIOLATION;
    else
        return ERRORS_NO_ERROR;
}

static System_Errors Flash_writeLongWord (Flash_DeviceHandle dev, uint32_t address, uint8_t* data)
{
    dev->commandArray[0] = FTFx_PROGRAM_PHRASE;
    dev->commandArray[1] = FLASH_GET_BIT_16_23(address);
    dev->commandArray[2] = FLASH_GET_BIT_8_15(address);
    dev->commandArray[3] = FLASH_GET_BIT_0_7(address);
    dev->commandArray[4] = FLASH_READ8((data + 3));
    dev->commandArray[5] = FLASH_READ8((data + 2));
    dev->commandArray[6] = FLASH_READ8((data + 1));
    dev->commandArray[7] = FLASH_READ8((data + 0));
    dev->commandArray[8] = FLASH_READ8((data + 7));
    dev->commandArray[9] = FLASH_READ8((data + 6));
    dev->commandArray[10] = FLASH_READ8((data + 5));
    dev->commandArray[11] = FLASH_READ8((data + 4));

    return Flash_sequenceCommand(dev);
}

System_Errors Flash_writeBuffer (Flash_DeviceHandle dev, uint8_t *buffer, uint32_t size)
{
    System_Errors error = ERRORS_NO_ERROR;
    uint32_t addr = dev->userStartAddr;

    while (size > 0x00U)
    {
        error = Flash_writeLongWord(dev,addr,buffer);

        if (error != ERRORS_NO_ERROR)
            return error;

        addr += dev->blockSize;
        size -= dev->blockSize;
        buffer += dev->blockSize;
    }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

System_Errors Flash_init (Flash_DeviceHandle dev, uint8_t sectorNumbers)
{
    if (dev->isInit == TRUE) return ERRORS_FLASH_JUST_INIT;

    // Save memory address
    dev->startAddr = FSL_FEATURE_FLASH_PFLASH_START_ADDRESS;
    dev->flashSize = FSL_FEATURE_FLASH_PFLASH_BLOCK_SIZE * FSL_FEATURE_FLASH_PFLASH_BLOCK_COUNT;
    dev->sectorSize = FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE;

    dev->userStartAddr = dev->startAddr + dev->flashSize - (dev->sectorSize * sectorNumbers);
    dev->userStopAddr = dev->startAddr + dev->flashSize;

    dev->blockSize = FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE;

    // Init command array to 0x00
    for (uint8_t i = 0; i < 12; ++i)
        dev->commandArray[i] = 0x00;

    return ERRORS_NO_ERROR;
}
Labels (1)
Tags (2)
0 Kudos
5 Replies

735 Views
mjbcswitzerland
Specialist V

Marco

I think that you need to show the code that is trying to write the 24 bytes of data.
If some phrase writes are operating your Flash driver is probably Ok but the error is in the application's use of it.

Regards

Mark

P.S. I have also attached the Flash driver from the uTasker project as reference (it is compatible with all flash implementations - long word, phrase, KE/KEA parts etc.).


Kinetis: http://www.utasker.com/kinetis.html
Kinetis K64:
- http://www.utasker.com/kinetis/FRDM-K64F.html
- http://www.utasker.com/kinetis/TWR-K64F120M.html
- http://www.utasker.com/kinetis/TEENSY_3.5.html
- http://www.utasker.com/kinetis/Hexiwear-K64F.html
Flash interface: http://www.utasker.com/docs/uTasker/uTaskerFileSystem_3.PDF


Free Open Source solution: https://github.com/uTasker/uTasker-Kinetis
Working project in 15 minutes video: https://youtu.be/K8ScSgpgQ6M

Professional Kinetis support, one-on-one training and complete fast-track project solutions: http://www.utasker.com/support.html

0 Kudos

735 Views
MarcoGiammarini
Contributor III

Hello Mark,

the code that I use is:

typedef struct
{
    uint8_t net_macAddr[6];
    uint8_t net_ipAddr[4];
    uint8_t net_subMask[4];
    uint8_t net_gwAddr[4];
    uint8_t dump[6];
} App_Memory;

#define APP_MEMORYSIZE_UINT8     (8*(1+(sizeof(App_Memory)-1)/8))
#define APP_MEMORYSIZE_UINT16    (APP_MEMORYSIZE_UINT8/2)

union
{
    uint8_t    buffer8[APP_MEMORYSIZE_UINT8];
    uint16_t   buffer16[APP_MEMORYSIZE_UINT16];
    App_Memory data;
} App_MemoryImage;

void App_setMemory (bool restore)
{
    // Init the flash memory...
    Flash_init(OB_FLASH0,1);

    if (restore || (Flash_readLocation(OB_FLASH0,0) == 0xFFFF))
    {
        App_MemoryImage.data.net_macAddr[0] = 0x00;//0x00,0xCF,0x52,0x35,0x00,0x01
        App_MemoryImage.data.net_macAddr[1] = 0xCF;
        App_MemoryImage.data.net_macAddr[2] = 0x52;
        App_MemoryImage.data.net_macAddr[3] = 0x35;
        App_MemoryImage.data.net_macAddr[4] = 0x00;
        App_MemoryImage.data.net_macAddr[5] = 0x01;
        App_MemoryImage.data.net_ipAddr[0] = 192;
        App_MemoryImage.data.net_ipAddr[1] = 168;
        App_MemoryImage.data.net_ipAddr[2] = 1;
        App_MemoryImage.data.net_ipAddr[3] = 6;
        App_MemoryImage.data.net_subMask[0] = 255;
        App_MemoryImage.data.net_subMask[1] = 255;
        App_MemoryImage.data.net_subMask[2] = 255;
        App_MemoryImage.data.net_subMask[3] = 0;
        App_MemoryImage.data.net_gwAddr[0] = 192;
        App_MemoryImage.data.net_gwAddr[1] = 168;
        App_MemoryImage.data.net_gwAddr[2] = 1;
        App_MemoryImage.data.net_gwAddr[3] = 100;

        App_writeMemory2Flash();
    }
    else
    {
        for (uint16_t i = 0; i < APP_MEMORYSIZE_UINT16; ++i)
        {
            App_MemoryImage.buffer16[i] = Flash_readLocation(OB_FLASH0,i);
        }
    }
}

static System_Errors App_writeMemory2Flash(void)
{
    uint8_t* dataPtr = App_MemoryImage.buffer8;
    System_Errors error = 0;

    __disable_irq();

    error = Flash_EraseSector(OB_FLASH0,0);
    if (error != ERRORS_NO_ERROR) return error;

    error = Flash_writeBuffer(OB_FLASH0,dataPtr,APP_MEMORYSIZE_UINT8);

    __enable_irq();

    return error;
}

If I put a dump array of 14 elements I can find in memory all 24 byte.

Regards

Marco

0 Kudos

735 Views
mjbcswitzerland
Specialist V

Hi Marco

I don't see the actual problem/error but I find that the code is rather difficult to understand (and verify) due to the fact that you have written it in a way that demands that the user pass the exact number of bytes to program, rounded to the the programming size, rather than doing it in a generic manner that allows the user to not need to know this information and thus avoid potential mistakes).

This, for example, is over-complicated and dangerous:

#define APP_MEMORYSIZE_UINT8     (8*(1+(sizeof(App_Memory)-1)/8))

since if you change your App_Memory size it will cause one more or one less phrase write to be made. A one-off error will lose you 8 bytes or not, which is similar to the issue that you have since if you increase App_Memory size with dummy bytes it indeed solves your issue. When I calculate the value in my head it seems to be OK, but it is a bit cryptic and begs for errors to be made.

If someone were to pass a non power of 8 length to your Flash_writeBuffer() routine it would also hang, so my advice is to allow the user to simply pass the same of the data to be written and you can pad and dangling bytes to the programming size and thus avoid such risks. or to 4 bytes if you use the same code on a device with long-word programming instead (portability).

In addition, I would protect just the low level writes and erase form interrupt rather than the complete loops - this will avoid clocking other interrupt driver services for unnecessary long times during such use.

I expect that if you clean up the method so that it automatically handles/manages the HW restrictions in the low level code you will probably find that such problems automatically disappear to and also don't come back later when you change something using it.

Regards

Mark

 
0 Kudos

735 Views
MarcoGiammarini
Contributor III

Hi Mark,

thank you for your reply and for suggetions. I tried to simplify the code, with no buffer rounded to programming size, but the result is the same. Furthermore, during debugging, when I launch the debug, the debugger go in RESET handler, I push play again and the session start (this behaviour happen in the same way before the last change).

I don't know why!!!

System_Errors Flash_writeBuffer (Flash_DeviceHandle dev, uint8_t *buffer, uint32_t size)
{
    System_Errors error = ERRORS_NO_ERROR;
    uint32_t addr = dev->userStartAddr;
    uint8_t sendBuffer[FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE];
    uint8_t tempSize = 0;

    while (size > 0x00U)
    {
        dev->commandArray[0] = FTFx_PROGRAM_PHRASE;
        dev->commandArray[1] = FLASH_GET_BIT_16_23(addr);
        dev->commandArray[2] = FLASH_GET_BIT_8_15(addr);
        dev->commandArray[3] = FLASH_GET_BIT_0_7(addr);

        if (size < dev->blockSize) tempSize = size;
        else tempSize = dev->blockSize;

        for (uint8_t i = 0; i < tempSize; i++)
            sendBuffer[i] = *(buffer + i);

        for (uint8_t i = tempSize; i < dev->blockSize; i++)
            sendBuffer[i] = 0;

        dev->commandArray[4] = FLASH_READ8((sendBuffer + 3));
        dev->commandArray[5] = FLASH_READ8((sendBuffer + 2));
        dev->commandArray[6] = FLASH_READ8((sendBuffer + 1));
        dev->commandArray[7] = FLASH_READ8((sendBuffer + 0));
        dev->commandArray[8] = FLASH_READ8((sendBuffer + 7));
        dev->commandArray[9] = FLASH_READ8((sendBuffer + 6));
        dev->commandArray[10] = FLASH_READ8((sendBuffer + 5));
        dev->commandArray[11] = FLASH_READ8((sendBuffer + 4));

        error = Flash_sequenceCommand(dev);

        if (error != ERRORS_NO_ERROR)
            return error;

        addr += tempSize;
        size -= tempSize;
        buffer += tempSize;
    }
}

I put the interrupt disable/enable inside Flash_sequenceCommand() function.

Regards

Marco

0 Kudos

735 Views
mjbcswitzerland
Specialist V


Hi Marco

If you need this for  professional work you can request remote desktop support to solve it at the support link in a previous post.
Otherwise you could copy the interface in the file that I posted (it does phrase buffer management).
For full analysis just download the uTasker project and run it in VisualStudio (free community edition is adequate) since it will simulate the internal flash and you can see the flashing routines in operation. Note also that it has integrated TCP/IP stack which uses the Flash as a (fail-safe) parameter system (including IP setting; MAC can be in the same area or in OTP area) so you could just copy the complete solution if you need to save time.

Regards

Mark

0 Kudos