Hello friends!
I'm trying to make my first custom bootloader but I'm struggling to cope.
I'm using a LPC11U34 and the most similar I've found is the AN10995 which manage a LPC1114 but aren't the same. For example, I can't assign uart to P0.18 and P0.19 pins.
An uart and xmodem for uploading fw would be perfect for my trainning and my application.
Can somebody help me, please?
解決済! 解決策の投稿を見る。
I could modify AN10995 to work with the LPC11Uxx family.
Now, I can upload a new app using xmodem!
However, the application doesn't seem to run. Probably the problem is in the jump from SBL to the app.
Please, see attached files with the custom bootloader for help.
This is the main.c in bootloader:
#include "chip.h"
#include "IAP.h"
#include "crc.h"
#include "xmodem1k.h"
//#include "delay.h"
/* Define flash memory address at which user application is located */
#define APP_START_ADDR 0x00002000UL //0x00001000UL
#define APP_END_ADDR 0x00008000UL
/* Define the flash sectors used by the application */
#define APP_START_SECTOR 2 //1
#define APP_END_SECTOR 7
/* Define location in flash memory that contains the application valid check value */
#define APP_VALID_CHECK_ADDR 0x00007FFCUL
/* Prototypes for functions that re-direct interrupts to handlers specified
in application vector table. Implemented as naked functions as they do not
need to store anything on the stack, they simply change the value of the
program counter. */
void NMI_Handler(void) __attribute__ (( naked ));
void HardFault_Handler(void) __attribute__ (( naked ));
void SVCall_Handler(void) __attribute__ (( naked ));
void PendSV_Handler(void) __attribute__ (( naked ));
void SysTick_Handler(void) __attribute__ (( naked ));
void WAKEUP_IRQHandler(void) __attribute__ (( naked ));
void I2C_IRQHandler(void) __attribute__ (( naked ));
void TIMER16_0_IRQHandler(void) __attribute__ (( naked ));
void TIMER16_1_IRQHandler(void) __attribute__ (( naked ));
void TIMER32_0_IRQHandler(void) __attribute__ (( naked ));
void TIMER32_1_IRQHandler(void) __attribute__ (( naked ));
void SSP_IRQHandler(void) __attribute__ (( naked ));
void UART_IRQHandler(void) __attribute__ (( naked ));
void USB_IRQHandler(void) __attribute__ (( naked ));
void USB_FIQHandler(void) __attribute__ (( naked ));
void ADC_IRQHandler(void) __attribute__ (( naked ));
void WDT_IRQHandler(void) __attribute__ (( naked ));
void BOD_IRQHandler(void) __attribute__ (( naked ));
void FMC_IRQHandler(void) __attribute__ (( naked ));
void PIOINT3_IRQHandler(void) __attribute__ (( naked ));
void PIOINT2_IRQHandler(void) __attribute__ (( naked ));
void PIOINT1_IRQHandler(void) __attribute__ (( naked ));
void PIOINT0_IRQHandler(void) __attribute__ (( naked ));
static void vBootLoader_Task(void);
static uint32_t u32BootLoader_AppPresent(void);
static uint32_t u32Bootloader_WriteCRC(uint16_t u16CRC);
static uint32_t u32BootLoader_ProgramFlash(uint8_t *pu8Data, uint16_t u16Len);
int main(void)
{
char key[16];
SystemCoreClockUpdate();
Chip_GPIO_SetPinDIRInput(LPC_GPIO_PORT, 0, 5); //INPUT
Chip_IOCON_PinMux(LPC_IOCON, 0, 5, IOCON_MODE_PULLUP, FUNC0 );
Chip_GPIO_SetPinDIROutput(LPC_GPIO_PORT, 0, 7); //OUTPUT (Led)
Chip_IOCON_PinMux(LPC_IOCON, 0, 7, IOCON_MODE_INACT, FUNC0 );
Chip_GPIO_WritePortBit(LPC_GPIO_PORT, 0, 7, 0);
if (Chip_GPIO_ReadPortBit(LPC_GPIO_PORT, 0, 5) == 0) // PIO0.5 LOW -> download app
{
Chip_GPIO_WritePortBit(LPC_GPIO_PORT, 0, 7, 0);
/* execute bootloader task that will
obtain a new application and program it to flash.. */
vBootLoader_Task();
/* Above function only returns when new application image has been
successfully programmed into flash. Begin execution of this new
application by resetting the device. */
NVIC_SystemReset();
}
else
{
/* execute app */
Chip_GPIO_WritePortBit(LPC_GPIO_PORT, 0, 7, 1);
//slow jump: switch main clock to IRC --> seen on https://community.nxp.com/t5/LPC-Microcontrollers/LPC1113-302-Secondary-Bootloader-based-on-AN10995/m-p/530513
// LPC_SYSCON->MAINCLKSEL = 0;
// LPC_SYSCON->MAINCLKUEN = 0;
// LPC_SYSCON->MAINCLKUEN = 1;
__disable_irq();
/* NVIC->ICPR[ 0 ] = 0xFFFFFFFF ; //Clear all pending interrupt
NVIC->ICPR[ 1 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 2 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 3 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 4 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 5 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 6 ] = 0xFFFFFFFF ;
NVIC->ICPR[ 7 ] = 0xFFFFFFFF ;
SysTick->CTRL = 0 ; //Disable SysTick and clear its exception pending bit
SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk ;
*/
/* Load main stack pointer with application stack pointer initial value,
stored at first location of application area */
asm volatile("ldr r0, =0x2000"); //=0x1000");
asm volatile("ldr r0, [r0]");
asm volatile("mov sp, r0");
/* Load program counter with application reset vector address, located at
second word of application area. */
asm volatile("ldr r0, =0x2004"); //=0x1004");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
/* User application execution should now start and never return here.... */
}
/* This should never be executed.. */
return 0;
}
static void vBootLoader_Task(void)
{
/* Erase the application flash area so it is ready to be reprogrammed with the new application */
if (u32IAP_PrepareSectors(APP_START_SECTOR, APP_END_SECTOR) == IAP_STA_CMD_SUCCESS)
{
if (u32IAP_EraseSectors(APP_START_SECTOR, APP_END_SECTOR) == IAP_STA_CMD_SUCCESS)
{
uint16_t u16CRC = 0;
/* Start the xmodem client, this function only returns when a
transfer is complete. Pass it pointer to function that will
handle received data packets */
vXmodem1k_Client(&u32BootLoader_ProgramFlash);
/* Programming is now complete, calculate the CRC of the flash image */
u16CRC = u16CRC_Calc16((const uint8_t *)APP_START_ADDR, (APP_END_ADDR - APP_START_ADDR - 4));
/* Write the CRC value into the last 16-bit location of flash, this
will be used to check for a valid application at startup */
(void)u32Bootloader_WriteCRC(u16CRC);
}
}
}
static uint32_t u32Bootloader_WriteCRC(uint16_t u16CRC)
{
uint32_t i;
uint32_t u32Result = 0;
uint32_t a32DummyData[IAP_FLASH_PAGE_SIZE_WORDS];
uint32_t *pu32Mem = (uint32_t *)(APP_END_ADDR - IAP_FLASH_PAGE_SIZE_BYTES);
/* First copy the data that is currently present in the last page of
flash into a temporary buffer */
for (i = 0 ; i < IAP_FLASH_PAGE_SIZE_WORDS; i++)
{
a32DummyData[i] = *pu32Mem++;
}
/* Set the CRC value to be written back */
a32DummyData[IAP_FLASH_PAGE_SIZE_WORDS - 1] = (uint32_t)u16CRC;
if (u32IAP_PrepareSectors(APP_END_SECTOR, APP_END_SECTOR) == IAP_STA_CMD_SUCCESS)
{
/* Now write the data back, only the CRC bits have changed */
if (u32IAP_CopyRAMToFlash((APP_END_ADDR - IAP_FLASH_PAGE_SIZE_BYTES),
(uint32_t)a32DummyData,
IAP_FLASH_PAGE_SIZE_BYTES) == IAP_STA_CMD_SUCCESS)
{
u32Result = 1;
}
}
return (u32Result);
}
static uint32_t u32BootLoader_ProgramFlash(uint8_t *pu8Data, uint16_t u16Len)
{
uint32_t u32Result = 0;
static uint32_t u32NextFlashWriteAddr = APP_START_ADDR;
if ((pu8Data != 0) && (u16Len != 0))
{
/* Prepare the flash application sectors for reprogramming */
if (u32IAP_PrepareSectors(APP_START_SECTOR, APP_END_SECTOR) == IAP_STA_CMD_SUCCESS)
{
/* Ensure that amount of data written to flash is at minimum the
size of a flash page */
if (u16Len < IAP_FLASH_PAGE_SIZE_BYTES)
{
u16Len = IAP_FLASH_PAGE_SIZE_BYTES;
}
/* Write the data to flash */
if (u32IAP_CopyRAMToFlash(u32NextFlashWriteAddr, (uint32_t)pu8Data, u16Len) == IAP_STA_CMD_SUCCESS)
{
/* Check that the write was successful */
if (u32IAP_Compare(u32NextFlashWriteAddr, (uint32_t)pu8Data, u16Len, 0) == IAP_STA_CMD_SUCCESS)
{
/* Write was successful */
u32NextFlashWriteAddr += u16Len;
u32Result = 1;
}
}
}
}
return (u32Result);
}
void NMI_Handler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x2008");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void HardFault_Handler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x200C");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void SVCall_Handler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x202C");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void PendSV_Handler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x2038");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void SysTick_Handler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x203C");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void WAKEUP_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x2040");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void I2C_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x207C");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void TIMER16_0_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x2080");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void TIMER16_1_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x2084");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void TIMER32_0_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x2088");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void TIMER32_1_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x208C");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void SSP_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x2090");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void UART_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x2094");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void USB_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x2098");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void USB_FIQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x209C");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
/****************************************************************************
void ADC_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x20A0");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void WDT_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x20A4");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void BOD_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x20A8");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void FMC_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x20AC");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void PIOINT3_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x20B0");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void PIOINT2_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x20B4");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void PIOINT1_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x20B8");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}
void PIOINT0_IRQHandler(void)
{
/* Re-direct interrupt, get handler address from application vector table */
asm volatile("ldr r0, =0x20BC");
asm volatile("ldr r0, [r0]");
asm volatile("mov pc, r0");
}