Has anyone attempted to port this XBee/AVR wirless bootloader (http://www.sparkfun.com/commerce/tutori … als_id=122) to LPC21xx?
Would it be much of a stretch to implement this wireless bootloader with nRF24AP1 transeivers instead of xbee?
Has anyone attempted to port this XBee/AVR wirless bootloader (http://www.sparkfun.com/commerce/tutori … als_id=122) to LPC21xx?
Would it be much of a stretch to implement this wireless bootloader with nRF24AP1 transeivers instead of xbee?
I have some code that can do this via the BOOT ROM IAP on a LPC2103… If you can give me a little more to go on?
What I did is take the code from NXP there is a secondary bootloader example on their web site. I took that code and did a wrapper to allow to flash, jump to user code etc via the UART that is not supported by the internal boot rom… To make it easier, just have your app reboot the the boot rom… and do all of the commands
On the LPC21xx secondary boot loader… Did you work out (can you share) the intricate details on how to setup the flash addresses for the boot and app? If I understand, the secondary bootloader on a 21xx origins at address 0 so it runs after reset. It uses one or more sectors of flash.
But all application programs must be compiled to origin at the sector following the secondary boot.
With IAR, there are “icf” files and a graphical editor to setup this.
Also, one has to work out how the secondary bootloader knows if it has no new boot to do, and just jump to the app. There’s also some issues about how the app’s coded is checksummed or some such.
I’m starting into this.
For a simple wireless boot, I’d just connect a wireless serial port extension device to UART0 and use the factory bootloader, if you can work out how the jumpers and DTR bit would work. E.g., you could use a Digi XBee with the wireless serial cable replacement firmware mode.
I’m using a LPC2103, so only have 8K or RAM and 32K of flash.
I don’t use any interrupts in either the boot loader or the user application. So it makes it a little easier. I’m using codesourcery arm tool set. I will post each LD file at the end of the email.
For the boot loader I use file on this web page ie XMODEM http://www.nxp.com/#/pip/pip=[pip=LPC2109_2119_2129]|pp=[t=pip,i=LPC2109_2119_2129]
So the bootloader is at 0-2K, the user app is 2K+64 to the end of flash. The 64 bytes is a header. ie string 32 bytes ie product name etc, some junk, an unsigned int version, unsigned length, unsigned crc;
This allows the boot loader to check if there is a valid image. Hence the Length and CRC. I use a simple CRC16 that XMODEM uses, so no extra code…
So, the boot loader does the init at the reset vector, then goes to main, does a app check, if the app is there jump to 64+2k… and starts running the user, app. At this time you can relocate the vector to RAM. But I chose not to at this time, but can do it later. I use protothreads for a simple tasking threading…
The trick was the app startup, I re-use the startup code, but relocate it to 2K+32. see below:
/* identify the Entry Point */
OUTPUT_FORMAT(“elf32-littlearm”, “elf32-littlearm”, “elf32-littlearm”)
OUTPUT_ARCH(arm)
STARTUP(crt.o)
GROUP(-lgcc -lc)
ENTRY(_vectors)
/* specify the LPC2103 memory areas */
MEMORY
{
flash : ORIGIN = 8K+64, LENGTH = 24K-64 /* FLASH ROM */
ram_isp_low(A) : ORIGIN = 0x40000040, LENGTH = 224 /* variables used by Philips ISP bootloader */
ram : ORIGIN = 0x40000120, LENGTH = 7872 /* free RAM area */
ram_isp_high(A) : ORIGIN = 0x40001FE0, LENGTH = 32 /* variables used by Philips ISP bootloader */
}
/* define a global symbol _stack_end */
_stack_end = 0x40001FDC;
/* now define the output sections */
SECTIONS
{
. = 0; /* set location counter to address zero */
startup : { (.startup)} >flash / the startup code goes into FLASH */
.text : /* collect all sections that should go into FLASH after startup */
{
(.text) / all .text sections (code) */
(.rodata) / all .rodata sections (constants, strings, etc.) */
(.rodata) /* all .rodata* sections (constants, strings, etc.) */
(.glue_7) / all .glue_7 sections (no idea what these are) */
(.glue_7t) / all .glue_7t sections (no idea what these are) */
_etext = .; /* define a global symbol _etext just after the last code byte */
} >flash /* put all the above into FLASH */
.data : /* collect all initialized .data sections that go into RAM */
{
_data = .; /* create a global symbol marking the start of the .data section */
(.data) / all .data sections */
_edata = .; /* define a global symbol marking the end of the .data section */
} >ram AT >flash /* put all the above into RAM (but load the LMA copy into FLASH) */
.bss : /* collect all uninitialized .bss sections that go into RAM */
{
_bss_start = .; /* define a global symbol marking the start of the .bss section */
(.bss) / all .bss sections */
} >ram /* put all the above in RAM (it will be cleared in the startup code */
. = ALIGN(4); /* advance location counter to the next 32-bit boundary */
_bss_end = . ; /* define a global symbol marking the end of the .bss section */
}
_end = .; /* define a global symbol marking the end of application RAM */
Here is the startup code… for the user app.
.equ Mode_USR, 0x10
.equ Mode_FIQ, 0x11
.equ Mode_IRQ, 0x12
.equ Mode_SVC, 0x13
.equ Mode_ABT, 0x17
.equ Mode_UND, 0x1B
.equ Mode_SYS, 0x1F
.equ I_Bit, 0x80 /* when I bit is set, IRQ is disabled */
.equ F_Bit, 0x40 /* when F bit is set, FIQ is disabled */
/*
// Stack Configuration
// Top of Stack Address <0x0-0xFFFFFFFF>
// Stack Sizes (in Bytes)
// Undefined Mode <0x0-0xFFFFFFFF>
// Supervisor Mode <0x0-0xFFFFFFFF>
// Abort Mode <0x0-0xFFFFFFFF>
// Fast Interrupt Mode <0x0-0xFFFFFFFF>
// Interrupt Mode <0x0-0xFFFFFFFF>
// User/System Mode <0x0-0xFFFFFFFF>
//
//
*/
.equ Top_Stack, 0x40004000
.equ UND_Stack_Size, 0x00000004
.equ SVC_Stack_Size, 0x00000004
.equ ABT_Stack_Size, 0x00000004
.equ FIQ_Stack_Size, 0x00000004
.equ IRQ_Stack_Size, 0x00000080
.equ USR_Stack_Size, 0x00000400
.equ PLL_BASE, 0xE01FC080 /* PLL Base Address */
.equ PLLCON_OFS, 0x00 /* PLL Control Offset*/
.equ PLLCFG_OFS, 0x04 /* PLL Configuration Offset */
.equ PLLSTAT_OFS, 0x08 /* PLL Status Offset */
.equ PLLFEED_OFS, 0x0C /* PLL Feed Offset */
.equ PLLCON_PLLE, (1<<0) /* PLL Enable */
.equ PLLCON_PLLC, (1<<1) /* PLL Connect */
.equ PLLCFG_MSEL, (0x1F<<0) /* PLL Multiplier */
.equ PLLCFG_PSEL, (0x03<<5) /* PLL Divider */
.equ PLLSTAT_PLOCK, (1<<10) /* PLL Lock Status */
/*
// PLL Setup
// <o1.0…4> MSEL: PLL Multiplier Selection
// <1-32><#-1>
// M Value
// <o1.5…6> PSEL: PLL Divider Selection
// <0=> 1 <1=> 2 <2=> 4 <3=> 8
// P Value
//
*/
.equ PLL_SETUP, 1
.equ PLLCFG_Val, 0x00000024
.equ MAM_BASE, 0xE01FC000 /* MAM Base Address */
.equ MAMCR_OFS, 0x00 /* MAM Control Offset*/
.equ MAMTIM_OFS, 0x04 /* MAM Timing Offset */
/*
// MAM Setup
// <o1.0…1> MAM Control
// <0=> Disabled
// <1=> Partially Enabled
// <2=> Fully Enabled
// Mode
// <o2.0…2> MAM Timing
// <0=> Reserved <1=> 1 <2=> 2 <3=> 3
// <4=> 4 <5=> 5 <6=> 6 <7=> 7
// Fetch Cycles
//
*/
.equ MAM_SETUP, 1
.equ MAMCR_Val, 0x00000002
.equ MAMTIM_Val, 0x00000004
.text
.arm
.global _startup
.func _startup
_startup:
Vectors: LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP /* Reserved Vector */
LDR PC, IRQ_Addr
LDR PC, FIQ_Addr
Reset_Addr: .word Reset_Handler
Undef_Addr: .word Undef_Handler
SWI_Addr: .word SWI_Handler
PAbt_Addr: .word PAbt_Handler
DAbt_Addr: .word DAbt_Handler
.word 0 /* Reserved Address */
IRQ_Addr: .word IRQ_Handler
FIQ_Addr: .word FIQ_Handler
Undef_Handler: B Undef_Handler
SWI_Handler: B SWI_Handler
PAbt_Handler: B PAbt_Handler
DAbt_Handler: B DAbt_Handler
IRQ_Handler: B IRQ_Handler
FIQ_Handler: B FIQ_Handler
Reset_Handler:
.if PLL_SETUP
LDR R0, =PLL_BASE
MOV R1, #0xAA
MOV R2, #0x55
MOV R3, #PLLCFG_Val
STR R3, [R0, #PLLCFG_OFS]
MOV R3, #PLLCON_PLLE
STR R3, [R0, #PLLCON_OFS]
STR R1, [R0, #PLLFEED_OFS]
STR R2, [R0, #PLLFEED_OFS]
PLL_Loop: LDR R3, [R0, #PLLSTAT_OFS]
ANDS R3, R3, #PLLSTAT_PLOCK
BEQ PLL_Loop
MOV R3, #(PLLCON_PLLE | PLLCON_PLLC)
STR R3, [R0, #PLLCON_OFS]
STR R1, [R0, #PLLFEED_OFS]
STR R2, [R0, #PLLFEED_OFS]
.endif
.if MAM_SETUP
LDR R0, =MAM_BASE
MOV R1, #MAMTIM_Val
STR R1, [R0, #MAMTIM_OFS]
MOV R1, #MAMCR_Val
STR R1, [R0, #MAMCR_OFS]
.endif
LDR R0, =Top_Stack
MSR CPSR_c, #Mode_UND|I_Bit|F_Bit
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
MSR CPSR_c, #Mode_ABT|I_Bit|F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
MSR CPSR_c, #Mode_FIQ|I_Bit|F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
MSR CPSR_c, #Mode_IRQ|I_Bit|F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
MSR CPSR_c, #Mode_SVC|I_Bit|F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
MSR CPSR_c, #Mode_USR
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
LDR R1, =_etext
LDR R2, =_data
LDR R3, =_edata
LoopRel: CMP R2, R3
LDRLO R0, [R1], #4
STRLO R0, [R2], #4
BLO LoopRel
MOV R0, #0
LDR R1, =bss_start
LDR R2, =bss_end
LoopZI: CMP R1, R2
STRLO R0, [R1], #4
BLO LoopZI
ADR LR, __main_exit
LDR R0, =main
BX R0
__main_exit: B __main_exit
.size _startup, . - _startup
.endfunc
.end
Does this help?
Well since you are using UART0, you don’t need all of the crap I did. Our problem was we have to use UART1 due to RTS/CTS must be used for buffer control… So the boot ROM only helped doing the erase and program.
So you really don’t need a boot loader at all, just a way to call into the boot ROM and start the serial protocol up to start the erase and program. Does this make sense?
processcommand( int cmd)
{
switch(cmd)
{
case PROGRAM_FLASH:
//turn off interrupts etc
// may have to setup the PLL to the default
REBOOT_USING_IAP(); /* This will cause the boot loader to start, and then you have to use the bootloader API to erase the sectors etc.
** This code does not return…
*/
break;
}
}
Yes, use the DTR to set the pin to boot into the boot ROM after reset, there is a pin on the chip it is low (Have to look at the data sheet) at boot it forces the BOOT ROM to execute, even if you have a valid app in flash.
For example
void processComand(int cmd)
{
switch(cmd)
{
case RESETPROCESSOR:
use_WDT_or_something to reset the processor(); // make sure the DTR is configure to boot into the boot rom on RESET…
break;
}
Do you see what I mean?
If you want to talk offline post me a private message
thanks… reading, understanding.