Search code examples
armmicrocontrollerlpcnxp-microcontroller

How to implement bootloader using LPC4330 with SPIFI flash


I am looking into using the NXP LPC4330 microcontroller in a future design and one of the features we need is the ability to update flash in the field using a bootloader. In the past I have done this using the NXP IAP commands, but since the 4330 uses SPIFI flash, IAP is not available.

From what I have gathered, it seems that my bootloader application will need to be executing from RAM and then I can write to flash using the SPIFI library from NXP. My question is this:

Using IAR Embedded Workbench, how can I create a program that will start from flash and then start running via RAM so I can write to the SPIFI chip? I have looked at the example below, but it is unclear how to port it over to the LPC4330. I believe I have the code copied into RAM in the startup code, but not sure how to copy the interrupt vector table to RAM or how to start executing from RAM. https://www.iar.com/support/tech-notes/general/execute-in-ram-after-copying-from-flashrom-v5.20-and-later/


Solution

  • I figured out how this is done. Using the link in the question to get a good idea of the general process.

    This is what the startup file should look like. There is an interrupt vector table in flash, with all interrupt vectors pointing to a dummy handler. Then later on there is an interrupt vector table stored in RAM which is used.

    ;Interrupt vector table in flash, will never be used since VTOR 
    ;(interrupt vector table)will be mapped to RAM on startup
            MODULE  ?cstartup
    
            ;; Forward declaration of sections.
            SECTION CSTACK:DATA:NOROOT(3)
    
            SECTION .intvec:CODE:NOROOT(2)
    
            EXTERN  __iar_program_start 
            EXTERN  SystemInit        
            PUBLIC  __vector_table_RAM
            PUBLIC  __vector_table_0x1c
            PUBLIC  __Vectors
            PUBLIC  __Vectors_End
            PUBLIC  __Vectors_Size
    
            DATA
    
    __vector_table
            DCD     sfe(CSTACK)
            DCD     Reset_Handler
            DCD     NMI_Handler
            DCD     HardFault_Handler
            DCD     MemManage_Handler
            DCD     BusFault_Handler
            DCD     UsageFault_Handler
    __vector_table_0x1c
            DCD     0
            DCD     0
            DCD     0
            DCD     0
            DCD     SVC_Handler
            DCD     DebugMon_Handler
            DCD     0
            DCD     PendSV_Handler
            DCD     SysTick_Handler
    
            ; External Interrupts
            DCD     Dummy_Handler_ROM               ; 16 D/A Converter
            DCD     Dummy_Handler_ROM               ; 17 CortexM0 (LPC43XX ONLY) 
            DCD     Dummy_Handler_ROM               ; 18 General Purpose DMA
            DCD     0                               ; 19 Reserved
            DCD     Dummy_Handler_ROM               ; 20 ORed flash bank A, flash bank B, EEPROM interrupts
            DCD     Dummy_Handler_ROM               ; 21 Ethernet
            DCD     Dummy_Handler_ROM               ; 22 SD/MMC
            DCD     Dummy_Handler_ROM               ; 23 LCD
            DCD     Dummy_Handler_ROM               ; 24 USB0
            DCD     Dummy_Handler_ROM               ; 25 USB1
            DCD     Dummy_Handler_ROM               ; 26 State Configurable Timer
            DCD     Dummy_Handler_ROM               ; 27 Repetitive Interrupt Timer
            DCD     Dummy_Handler_ROM               ; 28 Timer0
            DCD     Dummy_Handler_ROM               ; 29 Timer1
            DCD     Dummy_Handler_ROM               ; 30 Timer2
            DCD     Dummy_Handler_ROM               ; 31 Timer3
            DCD     Dummy_Handler_ROM               ; 32 Motor Control PWM
            DCD     Dummy_Handler_ROM               ; 33 A/D Converter 0
            DCD     Dummy_Handler_ROM               ; 34 I2C0
            DCD     Dummy_Handler_ROM               ; 35 I2C1
            DCD     Dummy_Handler_ROM               ; 36 SPI (LPC43XX ONLY)
            DCD     Dummy_Handler_ROM               ; 37 A/D Converter 1
            DCD     Dummy_Handler_ROM               ; 38 SSP0
            DCD     Dummy_Handler_ROM               ; 39 SSP1
            DCD     Dummy_Handler_ROM               ; 40 UART0
            DCD     Dummy_Handler_ROM               ; 41 UART1
            DCD     Dummy_Handler_ROM               ; 42 UART2
            DCD     Dummy_Handler_ROM               ; 43 UART3
            DCD     Dummy_Handler_ROM               ; 44 I2S0
            DCD     Dummy_Handler_ROM               ; 45 I2S1
            DCD     Dummy_Handler_ROM               ; 46 SPI Flash Interface
            DCD     Dummy_Handler_ROM               ; 47 SGPIO (LPC43XX ONLY)
            DCD     Dummy_Handler_ROM               ; 48 GPIO0
            DCD     Dummy_Handler_ROM               ; 49 GPIO1
            DCD     Dummy_Handler_ROM               ; 50 GPIO2
            DCD     Dummy_Handler_ROM               ; 51 GPIO3
            DCD     Dummy_Handler_ROM               ; 52 GPIO4
            DCD     Dummy_Handler_ROM               ; 53 GPIO5
            DCD     Dummy_Handler_ROM               ; 54 GPIO6
            DCD     Dummy_Handler_ROM               ; 55 GPIO7
            DCD     Dummy_Handler_ROM               ; 56 GINT0
            DCD     Dummy_Handler_ROM               ; 57 GINT1
            DCD     Dummy_Handler_ROM               ; 58 Event Router
            DCD     Dummy_Handler_ROM               ; 59 C_CAN1
            DCD     0
            DCD     Dummy_Handler_ROM               ; 61 ADCHS combined interrupt
            DCD     Dummy_Handler_ROM               ; 62 ATIMER
            DCD     Dummy_Handler_ROM               ; 63 RTC
            DCD     0
            DCD     Dummy_Handler_ROM               ; 65 WDT
            DCD     Dummy_Handler_ROM               ; 66 M0SUB TXEVT
            DCD     Dummy_Handler_ROM               ; 67 C_CAN0
            DCD     Dummy_Handler_ROM               ; 68 QEI
    
    
    
    
    ;Interrupt vector table which will be placed in RAM
            SECTION .vectors_RAM:CODE:ROOT(2)
    
            EXTERN  __iar_program_start 
            EXTERN  SystemInit        
            PUBLIC  __vector_table
            PUBLIC  __vector_table_0x1c
            PUBLIC  __Vectors
            PUBLIC  __Vectors_End
            PUBLIC  __Vectors_Size
    
            DATA
    __vector_table_RAM
            DCD     sfe(CSTACK)
            DCD     Reset_Handler
            DCD     NMI_Handler
            DCD     HardFault_Handler
            DCD     MemManage_Handler
            DCD     BusFault_Handler
            DCD     UsageFault_Handler
            DCD     0
            DCD     0
            DCD     0
            DCD     0
            DCD     SVC_Handler
            DCD     DebugMon_Handler
            DCD     0
            DCD     PendSV_Handler
            DCD     SysTick_Handler
    
            ; External Interrupts
            DCD     DAC_IRQHandler              ; 16 D/A Converter
            DCD     M0APP_IRQHandler            ; 17 CortexM0 (LPC43XX ONLY) 
            DCD     DMA_IRQHandler              ; 18 General Purpose DMA
            DCD     0                           ; 19 Reserved
            DCD     FLASH_EEPROM_IRQHandler     ; 20 ORed flash bank A, flash bank B, EEPROM interrupts
            DCD     ETH_IRQHandler              ; 21 Ethernet
            DCD     SDIO_IRQHandler             ; 22 SD/MMC
            DCD     LCD_IRQHandler              ; 23 LCD
            DCD     USB0_IRQHandler             ; 24 USB0
            DCD     USB1_IRQHandler             ; 25 USB1
            DCD     SCT_IRQHandler              ; 26 State Configurable Timer
            DCD     RIT_IRQHandler              ; 27 Repetitive Interrupt Timer
            DCD     TIMER0_IRQHandler           ; 28 Timer0
            DCD     TIMER1_IRQHandler           ; 29 Timer1
            DCD     TIMER2_IRQHandler           ; 30 Timer2
            DCD     TIMER3_IRQHandler           ; 31 Timer3
            DCD     MCPWM_IRQHandler            ; 32 Motor Control PWM
            DCD     ADC0_IRQHandler             ; 33 A/D Converter 0
            DCD     I2C0_IRQHandler             ; 34 I2C0
            DCD     I2C1_IRQHandler             ; 35 I2C1
            DCD     SPI_IRQHandler              ; 36 SPI (LPC43XX ONLY)
            DCD     ADC1_IRQHandler             ; 37 A/D Converter 1
            DCD     SSP0_IRQHandler             ; 38 SSP0
            DCD     SSP1_IRQHandler             ; 39 SSP1
            DCD     UART0_IRQHandler            ; 40 UART0
            DCD     UART1_IRQHandler            ; 41 UART1
            DCD     UART2_IRQHandler            ; 42 UART2
            DCD     UART3_IRQHandler            ; 43 UART3
            DCD     I2S0_IRQHandler             ; 44 I2S0
            DCD     I2S1_IRQHandler             ; 45 I2S1
            DCD     SPIFI_IRQHandler            ; 46 SPI Flash Interface
            DCD     SGPIO_IRQHandler            ; 47 SGPIO (LPC43XX ONLY)
            DCD     GPIO0_IRQHandler            ; 48 GPIO0
            DCD     GPIO1_IRQHandler            ; 49 GPIO1
            DCD     GPIO2_IRQHandler            ; 50 GPIO2
            DCD     GPIO3_IRQHandler            ; 51 GPIO3
            DCD     GPIO4_IRQHandler            ; 52 GPIO4
            DCD     GPIO5_IRQHandler            ; 53 GPIO5
            DCD     GPIO6_IRQHandler            ; 54 GPIO6
            DCD     GPIO7_IRQHandler            ; 55 GPIO7
            DCD     GINT0_IRQHandler            ; 56 GINT0
            DCD     GINT1_IRQHandler            ; 57 GINT1
            DCD     EVRT_IRQHandler             ; 58 Event Router
            DCD     CAN1_IRQHandler             ; 59 C_CAN1
            DCD     0
            DCD     ADCHS_IRQHandler            ; 61 ADCHS combined interrupt
            DCD     ATIMER_IRQHandler           ; 62 ATIMER
            DCD     RTC_IRQHandler              ; 63 RTC
            DCD     0
            DCD     WDT_IRQHandler              ; 65 WDT
            DCD     M0SUB_IRQHandler            ; 66 M0SUB TXEVT
            DCD     CAN0_IRQHandler             ; 67 C_CAN0
            DCD     QEI_IRQHandler              ; 68 QEI
    __Vectors_End
    
    __Vectors       EQU   __vector_table
    __Vectors_Size  EQU   __Vectors_End - __Vectors
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;
    ;; Default interrupt handlers.
    ;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
            THUMB
    
            PUBWEAK Reset_Handler
            SECTION .text:CODE:REORDER:NOROOT(2)
    Reset_Handler
            LDR     R0, =SystemInit
            BLX     R0
            LDR     R0, =__iar_program_start
            BX      R0
    
            PUBWEAK NMI_Handler
            PUBWEAK HardFault_Handler
            PUBWEAK MemManage_Handler
            PUBWEAK BusFault_Handler
            PUBWEAK UsageFault_Handler
            PUBWEAK SVC_Handler
            PUBWEAK DebugMon_Handler
            PUBWEAK PendSV_Handler
            PUBWEAK SysTick_Handler
            PUBWEAK DAC_IRQHandler
            PUBWEAK M0APP_IRQHandler
            PUBWEAK DMA_IRQHandler
            PUBWEAK FLASH_EEPROM_IRQHandler
            PUBWEAK ETH_IRQHandler
            PUBWEAK SDIO_IRQHandler
            PUBWEAK LCD_IRQHandler
            PUBWEAK USB0_IRQHandler
            PUBWEAK USB1_IRQHandler
            PUBWEAK SCT_IRQHandler
            PUBWEAK RIT_IRQHandler
            PUBWEAK TIMER0_IRQHandler
            PUBWEAK TIMER1_IRQHandler
            PUBWEAK TIMER2_IRQHandler
            PUBWEAK TIMER3_IRQHandler
            PUBWEAK MCPWM_IRQHandler
            PUBWEAK ADC0_IRQHandler
            PUBWEAK I2C0_IRQHandler
            PUBWEAK I2C1_IRQHandler
            PUBWEAK SPI_IRQHandler
            PUBWEAK ADC1_IRQHandler
            PUBWEAK SSP0_IRQHandler
            PUBWEAK SSP1_IRQHandler
            PUBWEAK UART0_IRQHandler
            PUBWEAK UART1_IRQHandler
            PUBWEAK UART2_IRQHandler
            PUBWEAK UART3_IRQHandler
            PUBWEAK I2S0_IRQHandler
            PUBWEAK I2S1_IRQHandler
            PUBWEAK SPIFI_IRQHandler
            PUBWEAK SGPIO_IRQHandler
            PUBWEAK GPIO0_IRQHandler
            PUBWEAK GPIO1_IRQHandler
            PUBWEAK GPIO2_IRQHandler
            PUBWEAK GPIO3_IRQHandler
            PUBWEAK GPIO4_IRQHandler
            PUBWEAK GPIO5_IRQHandler
            PUBWEAK GPIO6_IRQHandler
            PUBWEAK GPIO7_IRQHandler
            PUBWEAK GINT0_IRQHandler
            PUBWEAK GINT1_IRQHandler
            PUBWEAK EVRT_IRQHandler
            PUBWEAK CAN1_IRQHandler
            PUBWEAK ADCHS_IRQHandler
            PUBWEAK ATIMER_IRQHandler
            PUBWEAK RTC_IRQHandler
            PUBWEAK WDT_IRQHandler
            PUBWEAK M0SUB_IRQHandler
            PUBWEAK CAN0_IRQHandler
            PUBWEAK QEI_IRQHandler
            SECTION .text:CODE:REORDER:NOROOT(1)
    NMI_Handler
            B NMI_Handler
    SVC_Handler
            B SVC_Handler
    DebugMon_Handler
            B DebugMon_Handler
    PendSV_Handler
            B PendSV_Handler
    SysTick_Handler
            B SysTick_Handler
    HardFault_Handler
            B HardFault_Handler
    MemManage_Handler
            B MemManage_Handler
    BusFault_Handler
            B BusFault_Handler
    UsageFault_Handler
    DAC_IRQHandler
    M0APP_IRQHandler
    DMA_IRQHandler 
    FLASH_EEPROM_IRQHandler
    ETH_IRQHandler
    SDIO_IRQHandler
    LCD_IRQHandler
    USB0_IRQHandler
    USB1_IRQHandler
    SCT_IRQHandler
    RIT_IRQHandler
    TIMER0_IRQHandler
    TIMER1_IRQHandler
    TIMER2_IRQHandler
    TIMER3_IRQHandler
    MCPWM_IRQHandler
    ADC0_IRQHandler
    I2C0_IRQHandler
    I2C1_IRQHandler
    SPI_IRQHandler
    ADC1_IRQHandler
    SSP0_IRQHandler
    SSP1_IRQHandler
    UART0_IRQHandler
    UART1_IRQHandler
    UART2_IRQHandler
    UART3_IRQHandler
    I2S0_IRQHandler
    I2S1_IRQHandler
    SPIFI_IRQHandler
    SGPIO_IRQHandler
    GPIO0_IRQHandler
    GPIO1_IRQHandler
    GPIO2_IRQHandler
    GPIO3_IRQHandler
    GPIO4_IRQHandler
    GPIO5_IRQHandler
    GPIO6_IRQHandler
    GPIO7_IRQHandler
    GINT0_IRQHandler
    GINT1_IRQHandler
    EVRT_IRQHandler
    CAN1_IRQHandler
    ADCHS_IRQHandler
    ATIMER_IRQHandler
    RTC_IRQHandler
    WDT_IRQHandler
    CAN0_IRQHandler
    M0SUB_IRQHandler
    QEI_IRQHandler
    Default_IRQHandler
            B Default_IRQHandler
    
    /* CRP Section - not needed for flashless devices */
    
    ;;;        SECTION .crp:CODE:ROOT(2)
    ;;;        DATA
    /* Code Read Protection
    NO_ISP  0x4E697370 -  Prevents sampling of pin PIO0_1 for entering ISP mode
    CRP1    0x12345678 - Write to RAM command cannot access RAM below 0x10000300.
                       - Copy RAM to flash command can not write to Sector 0.
                       - Erase command can erase Sector 0 only when all sectors
                         are selected for erase.
                       - Compare command is disabled.
                       - Read Memory command is disabled.
    CRP2    0x87654321 - Read Memory is disabled.
                       - Write to RAM is disabled.
                       - "Go" command is disabled.
                       - Copy RAM to flash is disabled.
                       - Compare is disabled.
    CRP3    0x43218765 - Access to chip via the SWD pins is disabled. ISP entry
                         by pulling PIO0_1 LOW is disabled if a valid user code is
                         present in flash sector 0.
    Caution: If CRP3 is selected, no future factory testing can be
    performed on the device.
    */
    ;;;     DCD 0xFFFFFFFF
    ;;;
    
    ; --------------------
    ; Dummy handler placed in ROM
    
    Dummy_Handler_ROM
                    b       Dummy_Handler_ROM
    
            END
    

    Then the linker file (.icf) needs to be edited to put all of the readonly items in ram (readwrite section) as shown below. The important line is "initialize by copy"

    /*###ICF### Section handled by ICF editor, don't touch! ****/
    /*-Editor annotation file-*/
    /* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
    /*-Specials-*/
    define symbol __ICFEDIT_intvec_start__ = 0x14000000;
    /*-Memory Regions-*/
    define symbol __ICFEDIT_region_ROM_start__ = 0x14000140;
    define symbol __ICFEDIT_region_ROM_end__   = 0x140FFFFF;
    define symbol __ICFEDIT_region_RAM_start__ = 0x10000140;
    define symbol __ICFEDIT_region_RAM_end__   = 0x10007FFF;
    /*-Sizes-*/
    define symbol __ICFEDIT_size_cstack__ = 0x800;
    define symbol __ICFEDIT_size_heap__   = 0x200;
    /**** End of ICF editor section. ###ICF###*/
    
    define symbol RAM_vectors_start = 0x10000000;
    
    define memory mem with size = 4G;
    define region ROM_region   = mem:[from __ICFEDIT_region_ROM_start__   to __ICFEDIT_region_ROM_end__];
    define region RAM_region   = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];
    
    define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };
    define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__     { };
    
    initialize by copy { readonly, readwrite };
    do not initialize  { section .noinit };
    
    place at address mem:__ICFEDIT_intvec_start__ { section .intvec };
    
    place at address mem:RAM_vectors_start { section .vectors_RAM };
    
    place in ROM_region     { readonly };
    place in RAM_region     { readwrite,
                              block CSTACK, block HEAP };
    

    After that, the only thing left to do is remap the interrupt vector table to RAM from ROM. This should be the first thing your application does, before any interrupts are enabled. The code should look like this:

    VTOR = (unsigned int) 0x10000000;