Re-invoke USB bootloader on LPC11U68

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

Re-invoke USB bootloader on LPC11U68

1,366 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by neilt6 on Mon May 26 17:03:10 MST 2014
Hey guys, I've been using the following code to re-invoke the USB bootloader on the LPC11U35 QuickStart Board, but it doesn't work on the LPC11U68. I originally thought *((unsigned int *)(0x10000054)) = 0x0; and __set_MSP(*((unsigned int *)0x00000000)); might be the problem, but removing them makes no difference on the LPC11U35, and still doesn't work on the LPC11U68. Anybody have any ideas? It seems to be resetting instead of running the bootloader.

/* 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;
 
    //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
    while(1);
}
Labels (1)
0 Kudos
12 Replies

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by neilt6 on Mon Jun 09 08:06:28 MST 2014
Good news everyone, some of the guys over at mbed solved it! It turns out that as soon as an interrupt is used in the mbed library, VTOR gets remapped to the bottom of the SRAM. Calling SCB->VTOR = 0; restores it to reset default and now ReinvokeISP works!
0 Kudos

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by neilt6 on Mon Jun 09 07:46:47 MST 2014

Quote: neilt6

Quote: xianghuiwang
Hi, neilt6,

Using the same IAP_ReinvokeISP code as you, I am able to enter USP_ISP mode when the USB cable is connected to the target side with the 11u68 xpresso board.
Connecting to the link side does not work for me.
Please compare your jumper setup and board in general with mine as attached.

regards,


Interesting... I'm pretty sure mine is configured the same way, but I won't be able I check it until Monday.


I just checked my jumper configuration, and it is indeed the same as yours... Very strange that we're getting different results, has there been a bootloader update?
0 Kudos

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by neilt6 on Sat Jun 07 17:23:53 MST 2014

Quote: xianghuiwang
Hi, neilt6,

Using the same IAP_ReinvokeISP code as you, I am able to enter USP_ISP mode when the USB cable is connected to the target side with the 11u68 xpresso board.
Connecting to the link side does not work for me.
Please compare your jumper setup and board in general with mine as attached.

regards,


Interesting... I'm pretty sure mine is configured the same way, but I won't be able I check it until Monday.
0 Kudos

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by xianghuiwang on Thu Jun 05 13:33:42 MST 2014
Hi, neilt6,

Using the same IAP_ReinvokeISP code as you, I am able to enter USP_ISP mode when the USB cable is connected to the target side with the 11u68 xpresso board.
Connecting to the link side does not work for me.
Please compare your jumper setup and board in general with mine as attached.

regards,
0 Kudos

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by neilt6 on Wed Jun 04 21:15:26 MST 2014

Quote: xianghuiwang
Hi, neilt6,
Could you upload the "blank - simple" project? I will try it on my xpresso board.


Sure, here's the mbed project. I haven't tried it on LPCXpresso since I do all of my development on mbed, but I would imagine the development environment has nothing to do with it, especially since the attached IAP code works just fine on my LPC11U35.

[u]main.cpp[/u]
#include "mbed.h"
#include "IAP_LPC11UXX.h"

DigitalOut led1(LED1, 1);

int main()
{
    led1 = !led1;
    wait(0.5);
    led1 = !led1;
    wait(0.5);
    led1 = !led1;
    wait(0.5);

    IAP_ReinvokeISP();
}


[u]IAP_LPC11UXX.h[/u]
#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


[u]IAP_LPC11UXX.cpp[/u]
#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;

    //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);
}

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;
}
0 Kudos

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by xianghuiwang on Wed Jun 04 16:33:00 MST 2014
Hi, neilt6,
Could you upload the "blank - simple" project? I will try it on my xpresso board.
0 Kudos

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by neilt6 on Wed Jun 04 13:05:05 MST 2014

Quote: dztang
When the reinvoke_ISP is called, it will sample the VBUS pin, if it's high, it will go to USB ISP, otherwise, it will go to UART ISP mode.
So, only the GPIO clock needs to be turned on first before reinvoke_ISP is called.

I am puzzled why you got a reset. Inside USB ISP mode, the XTAL instead of IRC must be used, if there are any jumper setting, you need to connect to
the XTAL pin on P2.0 and P2.1 first.

That's why I asked you to verify if UART ISP works or not when reinvoke_ISP is called. If it does, connect the USB cable with the host, and also make
sure XTALs are installed.


Ok, I just tried calling ReinvokeISP with USB connected to the LPC-Link connector instead of the target connector (leaving VBUS disconnected), and the UART ISP mode indeed works. However, calling it while connected to the target connector simply resets. I checked the LPCXpresso11U68 schematic, and XTAL is connected. Also, the USB bootloader works if I hold down the ISP button and plug in/reset, so the wiring is correct.

Up until now I've been testing this in a project that (among other things) uses USB. To make matters more interesting, I tried moving the IAP code to a blank project that just calls ReinvokeISP after a 1 second timeout. Low and behold the call actually goes somewhere and the micro doesn't reset. It still doesn't work though, it just shows up as an unrecognized device after several seconds...
0 Kudos

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dztang on Wed Jun 04 09:41:50 MST 2014
When the reinvoke_ISP is called, it will sample the VBUS pin, if it's high, it will go to USB ISP, otherwise, it will go to UART ISP mode.
So, only the GPIO clock needs to be turned on first before reinvoke_ISP is called.

I am puzzled why you got a reset. Inside USB ISP mode, the XTAL instead of IRC must be used, if there are any jumper setting, you need to connect to
the XTAL pin on P2.0 and P2.1 first.

That's why I asked you to verify if UART ISP works or not when reinvoke_ISP is called. If it does, connect the USB cable with the host, and also make
sure XTALs are installed.

 


0 Kudos

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by neilt6 on Tue Jun 03 09:00:10 MST 2014
Anyone? I'm kind of hoping to use this chip in a production product here...
0 Kudos

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by neilt6 on Wed May 28 15:35:33 MST 2014

Quote: dztang
Check if you are in the UART ISP mode or not. If so, please check the H/W: the USB must be connected to the host, USB VBUS must be high, the SoftConnect
pin must control the pull-up on D+ line.

If you are in neither USB nor UART ISP mode, then, something is wrong when you make this IAP call.


I'm trying this on the LPCXpresso11U68 development board, and the bootloader works if I use the ISP button so I would assume it's wired correctly. When I make the IAP call it's resetting instead of running the bootloader. I know this because it will run the bootloader if I hold down the ISP button while making the IAP call, it might as well be NVIC_SystemReset().
0 Kudos

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by dztang on Wed May 28 10:26:49 MST 2014
Check if you are in the UART ISP mode or not. If so, please check the H/W: the USB must be connected to the host, USB VBUS must be high, the SoftConnect
pin must control the pull-up on D+ line.

If you are in neither USB nor UART ISP mode, then, something is wrong when you make this IAP call.

0 Kudos

950 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by neilt6 on Wed May 28 08:17:22 MST 2014
*sigh* Sometimes I wonder why I bother asking questions on this site...
0 Kudos