9 years, 10 months ago.

How can we access the Flash of LPC11u24

How can we access the Flash of LPC11u24 1)Generally 2)Using pointers.

How can we know the amount of flash usable by the user after downloading a .bin file into it.

Is there some way to reserve some space in the available flash for general read/write purposes.

Thanks in advance.

1 Answer

9 years, 10 months ago.

Absolutely you can, you'll need to use In Application Programming calls or IAP calls for short. Start by reserving some flash with this piece of code:

const char userFlashArea[PAGE_COUNT * 256] __attribute__((aligned(256), used)) = {};


A "page" of flash on the LPC11UXX series is 256B, so replace PAGE_COUNT with the number of "pages" you want to reserve. The rest of that line will make sure that the reserved space is "page-aligned", won't be optimized out by the linker, and will be pre-filled with 0x00. At this point you can read from this reserved space using the userFlashArea pointer, but in order to write to it you'll need an IAP driver. There are plenty of these floating around here, but I've attached mine for completeness. It works on the LPC11U2X, LPC11U3X, and LPC11U6X series:

IAP_LPC11UXX.h

#if defined(TARGET_LPC11UXX) | defined(TARGET_LPC11U6X)

#ifndef IAP_LPC11UXX_H
#define IAP_LPC11UXX_H

#include "mbed.h"

//128-bit unique ID struct typedef
struct UID {
    unsigned int word0; /**< Word 0 of 128-bit UID (bits 31 to 0) */
    unsigned int word1; /**< Word 1 of 128-bit UID (bits 63 to 32) */
    unsigned int word2; /**< Word 2 of 128-bit UID (bits 95 to 64) */
    unsigned int word3; /**< Word 3 of 128-bit UID (bits 127 to 96) */
};

//IAP return code enumeration
enum IapReturnCode {
    IAP_CMD_SUCCESS = 0,
    IAP_INVALID_COMMAND,
    IAP_SRC_ADDR_ERROR,
    IAP_DST_ADDR_ERROR,
    IAP_SRC_ADDR_NOT_MAPPED,
    IAP_DST_ADDR_NOT_MAPPED,
    IAP_COUNT_ERROR,
    IAP_INVALID_SECTOR,
    IAP_SECTOR_NOT_BLANK,
    IAP_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION,
    IAP_COMPARE_ERROR,
    IAP_BUSY
};

//Function prototypes
IapReturnCode IAP_PrepareSectors(unsigned int sector_start, unsigned int sector_end);
IapReturnCode IAP_CopyRAMToFlash(void* ram_address, void* flash_address, unsigned int length);
IapReturnCode IAP_EraseSectors(unsigned int sector_start, unsigned int sector_end);
IapReturnCode IAP_BlankCheckSectors(unsigned int sector_start, unsigned int sector_end);
unsigned int IAP_ReadPartID();
unsigned short IAP_ReadBootCodeVersion();
IapReturnCode IAP_Compare(void* address1, void* address2, unsigned int bytes);
void IAP_ReinvokeISP();
UID IAP_ReadUID();
IapReturnCode IAP_ErasePage(unsigned int page_start, unsigned int page_end);
IapReturnCode IAP_WriteEEPROM(unsigned int ee_address, char* buffer, unsigned int length);
IapReturnCode IAP_ReadEEPROM(unsigned int ee_address, char* buffer, unsigned int length);

#endif

#endif


IAP_LPC11UXX.cpp

#if defined(TARGET_LPC11UXX) | defined(TARGET_LPC11U6X)

#include "IAP_LPC11UXX.h"

namespace
{
//This data must be global so it is not read from the stack
unsigned int m_Command[5], m_Result[5];
typedef void (*IAP)(unsigned int [], unsigned int []);
const IAP IAP_Entry = (IAP)0x1FFF1FF1;
}

static inline void _iap_CriticalEntry()
{
    //Disable interrupts
    __disable_irq();

    //Safely perform IAP entry
    IAP_Entry(m_Command, m_Result);

    //Enable interrupts
    __enable_irq();
}

IapReturnCode IAP_PrepareSectors(unsigned int sector_start, unsigned int sector_end)
{
    //Prepare the command array
    m_Command[0] = 50;
    m_Command[1] = sector_start;             //The start of the sector to be prepared
    m_Command[2] = sector_end;               //The end of the sector to be prepared

    //Invoke critical IAP call...
    _iap_CriticalEntry();

    //Extract the result code
    IapReturnCode ret = (IapReturnCode)m_Result[0];

    //Return the result code
    return ret;
}

IapReturnCode IAP_CopyRAMToFlash(void* ram_address, void* flash_address, unsigned int length)
{
    //Prepare the command array
    m_Command[0] = 51;
    m_Command[1] = (unsigned int)flash_address;     //Flash address where the contents are to be copied (it should be within 256bytes boundary)
    m_Command[2] = (unsigned int)ram_address;       //RAM address to be copied (it should be in word boundary)
    m_Command[3] = length;                          //Number of data to be copied in bytes: 256, 512, 1024, or 4096
    m_Command[4] = SystemCoreClock / 1000;

    //Invoke critical IAP call...
    _iap_CriticalEntry();

    //Extract the result code
    IapReturnCode ret = (IapReturnCode)m_Result[0];

    //Return the result code
    return ret;
}

IapReturnCode IAP_EraseSectors(unsigned int sector_start, unsigned int sector_end)
{
    //Prepare the command array
    m_Command[0] = 52;
    m_Command[1] = sector_start;             //The start of the sector to be erased
    m_Command[2] = sector_end;               //The end of the sector to be erased
    m_Command[3] = SystemCoreClock / 1000;   //System Clock Frequency (CCLK) in kHz

    //Invoke critical IAP call...
    _iap_CriticalEntry();

    //Extract the result code
    IapReturnCode ret = (IapReturnCode)m_Result[0];

    //Return the result code
    return ret;
}

IapReturnCode IAP_BlankCheckSectors(unsigned int sector_start, unsigned int sector_end)
{
    //Prepare the command array
    m_Command[0] = 53;
    m_Command[1] = sector_start;                 //The start of the sector to be checked
    m_Command[2] = sector_end;                   //The end of the sector to be checked

    //Invoke critical IAP call...
    _iap_CriticalEntry();

    //Extract the result code
    IapReturnCode ret = (IapReturnCode)m_Result[0];

    //Return the result code
    return ret;
}

unsigned int IAP_ReadPartID()
{
    //Prepare the command array
    m_Command[0] = 54;

    //Invoke critical IAP call...
    _iap_CriticalEntry();

    //Extract the part ID
    unsigned int ret = m_Result[1];

    //Return the part ID
    return ret;
}

unsigned short IAP_ReadBootCodeVersion()
{
    //Prepare the command array
    m_Command[0] = 55;

    //Invoke critical IAP call...
    _iap_CriticalEntry();

    //Extract the boot code version
    unsigned int ret = (unsigned short)m_Result[1];

    //Return the boot code version
    return ret;
}

IapReturnCode IAP_Compare(void* address1, void* address2, unsigned int bytes)
{
    //Prepare the command array
    m_Command[0] = 56;
    m_Command[1] = (unsigned int)address1;   //Starting flash or RAM address of data bytes to be compared. This address should be a word boundary.
    m_Command[2] = (unsigned int)address2;   //Starting flash or RAM address of data bytes to be compared. This address should be a word boundary.
    m_Command[3] = bytes;                    //Number of bytes to be compared; should be a multiple of 4.

    //Invoke critical IAP call...
    _iap_CriticalEntry();

    //Extract the result code
    IapReturnCode ret = (IapReturnCode)m_Result[0];

    //Return the result code
    return ret;
}

/* This function resets some microcontroller peripherals to reset
 * hardware configuration to ensure that the USB In-System Programming module
 * will work properly. It is normally called from reset and assumes some reset
 * configuration settings for the MCU.
 * Some of the peripheral configurations may be redundant in your specific
 * project.
 */
void IAP_ReinvokeISP()
{
    //Make sure USB clock is turned on before calling ISP
    //LPC_SYSCON->SYSAHBCLKCTRL |= 0x04000;

    //Make sure 32-bit Timer 1 is turned on before calling ISP
    //LPC_SYSCON->SYSAHBCLKCTRL |= 0x00400;

    //Make sure GPIO clock is turned on before calling ISP
    LPC_SYSCON->SYSAHBCLKCTRL |= 0x00040;

    //Make sure IO configuration clock is turned on before calling ISP
    //LPC_SYSCON->SYSAHBCLKCTRL |= 0x10000;

#if defined(TARGET_LPC11U6X)
    //Set the vector table offset to address 0
    SCB->VTOR = 0;
#endif

    //Make sure AHB clock divider is 1:1
    LPC_SYSCON->SYSAHBCLKDIV = 1;

    //Prepare the command array
    m_Command[0] = 57;

    //Initialize the storage state machine
    //*((unsigned int*)(0x10000054)) = 0x0;

    //Set stack pointer to ROM value (reset default)
    //This must be the last piece of code executed before calling ISP,
    //because most C expressions and function returns will fail after the stack pointer is changed.
    //__set_MSP(*((unsigned int*)0x00000000));

    //Invoke IAP call...
    IAP_Entry(m_Command, m_Result);

    //Shouldn't return
}

UID IAP_ReadUID()
{
    //Prepare the command array
    m_Command[0] = 58;

    //Invoke critical IAP call...
    _iap_CriticalEntry();

    //Extract the UID
    UID ret = {
        m_Result[1],
        m_Result[2],
        m_Result[3],
        m_Result[4]
    };

    //Return the UID
    return ret;
}

IapReturnCode IAP_ErasePage(unsigned int page_start, unsigned int page_end)
{
    //Prepare the command array
    m_Command[0] = 59;
    m_Command[1] = page_start;               //The start of the page to be erased
    m_Command[2] = page_end;                 //The end of the page to be erased
    m_Command[3] = SystemCoreClock / 1000;   //System Clock Frequency (CCLK) in kHz

    //Invoke critical IAP call...
    _iap_CriticalEntry();

    //Extract the result code
    IapReturnCode ret = (IapReturnCode)m_Result[0];

    //Return the result code
    return ret;
}

IapReturnCode IAP_WriteEEPROM(unsigned int ee_address, char* buffer, unsigned int length)
{
    //Prepare the command array
    m_Command[0] = 61;
    m_Command[1] = ee_address;               //EEPROM address (byte, half-word or word aligned)
    m_Command[2] = (unsigned int)buffer;     //RAM address (byte, half-word or word aligned)
    m_Command[3] = length;                   //Number of bytes to be written (byte, half-word writes are ok)
    m_Command[4] = SystemCoreClock / 1000;   //System Clock Frequency (CCLK) in kHz

    //Invoke critical IAP call...
    _iap_CriticalEntry();

    //Extract the result code
    IapReturnCode ret = (IapReturnCode)m_Result[0];

    //Return the result code
    return ret;
}

IapReturnCode IAP_ReadEEPROM(unsigned int ee_address, char* buffer, unsigned int length)
{
    //Prepare the command array
    m_Command[0] = 62;
    m_Command[1] = ee_address;               //EEPROM address (byte, half-word or word aligned)
    m_Command[2] = (unsigned int)buffer;     //RAM address (byte, half-word or word aligned)
    m_Command[3] = length;                   //Number of bytes to be read (byte, half-word reads are ok)
    m_Command[4] = SystemCoreClock / 1000;   //System Clock Frequency (CCLK) in kHz

    //Invoke critical IAP call...
    _iap_CriticalEntry();

    //Extract the result code
    IapReturnCode ret = (IapReturnCode)m_Result[0];
    
    //Return the result code
    return ret;
}

#endif


Now comes the fun part, you can use the IAP driver to erase and program the pages you reserved with userFlashArea. I've attached some example functions that work on the LPC11U35, but the LPC11U24 doesn't support the page-erase command, so you'll have to modify them to erase a sector at a time:

bool EraseFlash(const char* flashAddr, unsigned int length)
{
    IapReturnCode ret;

    //Prepare the sector range
    ret = IAP_PrepareSectors((unsigned int)flashAddr >> 12, ((unsigned int)flashAddr + length - 1) >> 12);
    if (ret != IAP_CMD_SUCCESS)
        return false;

    //Erase the specified pages
    ret = IAP_ErasePage((unsigned int)flashAddr >> 8, ((unsigned int)flashAddr + length - 1) >> 8);
    if (ret != IAP_CMD_SUCCESS)
        return false;

    //No errors!
    return true;
}

bool WriteFlash(const char* flashAddr, char* data, unsigned int length)
{
    IapReturnCode ret;

    //Calculate the sector numbers
    unsigned int startSectorNum = (unsigned int)flashAddr >> 12;
    unsigned int endSectorNum = ((unsigned int)flashAddr + length - 1) >> 12;

    //Make sure the sector range is blank
    ret = IAP_BlankCheckSectors(startSectorNum, endSectorNum);
    if (ret == IAP_SECTOR_NOT_BLANK)
        HAL_EraseFlash(flashAddr, length);
    else if (ret != IAP_CMD_SUCCESS)
        return false;

    //Prepare the sector range
    ret = IAP_PrepareSectors(startSectorNum, endSectorNum);
    if (ret != IAP_CMD_SUCCESS)
        return false;

    //Write all of the data in one shot
    ret = IAP_CopyRAMToFlash((void*)data, (void*)flashAddr, length);
    if (ret != IAP_CMD_SUCCESS)
        return false;

    //No errors!
    return true;
}


P.S. The User Manual for the LPC11UXX series mentions that the flash programming IAP commands will trample on the top 32B of RAM, which is used by the stack. Now, many people here (myself included) have used IAP with no ill effect, but be warned. The mbed library does not reserved this space, so there's every possibility that IAP could corrupt the stack and cause your program to crash.

Thanks for the reply @Neil Thiessen .

Does The Local file system actually write to the 32kb flash . If so is there some way to access it using pointers. If not so then where will it store it and how to access it ? What are the memory addresses ?

Here is the code which I wrote but was not working fine!

  1. include "mbed.h"
  2. include "SDFileSystem.h"

Serial pc(USBTX,USBRX);

SDFileSystem sd(p5, p6, p7, p8, "sd"); the pinout on the mbed Cool Components workshop board

int main() {

pc.printf("Hello\n"); char* bae = (char*)(0x07000); char* cdms = (char*)(0x07004); char* eps = (char*)(0x07008); char* pl = (char*)(0x0700c); storeddata();

  • bae = '0';
  • cdms = '9';
  • eps = '3';
  • pl = '4'; pc.printf("Making a directory\n"); mkdir("/sd/13_06_2014", 0777); pc.printf("Directory with today's Date made successfully\n"); pc.printf("Making txt files for Bae,CDMS,EPS,PL\n");

FILE *fbae = fopen("/sd/13_06_2014/bae.txt", "w"); fprintf(fbae,"%c",*bae); pc.printf("%c\n",*bae); fclose(fbae); FILE *fcdms = fopen("/sd/13_06_2014/cdms.txt", "w"); fprintf(fcdms,"%c",*cdms); fclose(fcdms); FILE *feps = fopen("/sd/13_06_2014/eps.txt", "w"); fprintf(feps,"%c",*eps); fclose(feps); FILE *fpl = fopen("/sd/13_06_2014/pl.txt", "w"); fprintf(fpl,"%c",*pl); pc.printf("Fopen successful\n"); fclose(fpl);

/*fwrite( bae,1,sizeof(bae),fbae); fwrite( cdms,1,sizeof(cdms),fcdms); fwrite( eps,1,sizeof(eps),feps); fwrite( pl,1,sizeof(pl),fpl);*/

pc.printf("Data to corresponding files written and closed properly!\nBye\n"); }

It was given in the data sheet that the memory adresses from 0x0000 to 0x7fff can be accessed any way , but that is not possible !!

posted by saiteja dommeti 24 Jun 2014

Unfortunately, LocalFileSystem uses semihosting to access the mbed interface chip's 2MB flash chip that it uses to store binaries. There's no way to access that data using pointers, but any files you create there will show up on the MBED disk on your computer when your program exits.

posted by Neil Thiessen 24 Jun 2014

@Neil Thiessen Thanks again for the quick response . I was worried about the above pasted code by me can u please spot the errors and tell me the changes that I can make .

posted by saiteja dommeti 24 Jun 2014

I'm not sure without being able to test it myself, and unfortunately I no longer have access to an SD card breakout to try it with. Have you tried using a different card?

posted by Neil Thiessen 24 Jun 2014