├── .gitignore ├── .gitmodules ├── README.md ├── conf └── openocd │ ├── flash.cfg │ ├── gdb.cfg │ └── interface │ ├── olimex-arm-usb-ocd-custom.cfg │ └── olimex-arm-usb-ocd-h-custom.cfg ├── example ├── .gdbinit ├── .gitignore ├── LPC1768.ld ├── Makefile ├── README.mkd ├── Timer │ ├── timer.c │ └── timer.h ├── gdb.cfg ├── main.c └── startup.c ├── script └── bootstrap.sh └── src ├── .gdbinit ├── .gitignore ├── LPC1768.ld ├── Makefile ├── blockdev_flash.c ├── disk.h ├── diskimage.c ├── log.c ├── log.h ├── main.c ├── msc_scsi.c ├── msc_usb_start.c ├── sbl_config.h ├── sbl_iap.c ├── sbl_iap.h └── startup.c /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .project 3 | .cproject 4 | *.bin 5 | *.elf 6 | *.map 7 | *.o 8 | dependencies 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/CDL"] 2 | path = src/CDL 3 | url = https://github.com/openxc/nxp-cdl 4 | [submodule "src/lpcusb"] 5 | path = src/lpcusb 6 | url = https://github.com/openxc/lpcusb.git 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | openlpc-USB_Bootloader 2 | ====================== 3 | 4 | This repository contains a USB bootloader compatible with the LPC17xx 5 | microcontroller. The lineage of this bootloader: 6 | 7 | * Originally based off of NXP's [AN10866 LPC1700 secondary 8 | bootloader](http://www.lpcware.com/content/nxpfile/an10866-lpc1700-secondary-usb-bootloader) 9 | * Code Red modified the bootloader to use the BSD licensed LPCUSB library, 10 | instead of the restrictively licensed USB stack from Keil (which could only be 11 | used with the uVision/ARM development tools). 12 | * Modifications made for OpenLPC project (not sure on the details) 13 | * Chris Peplin replaced Code Red's fork of the LPCUSB library with a Git 14 | submodule pointing to a branch in the LPCUSB library that supports the 15 | LPC17xx, and re-used as many example files from the LPCUSB project directly. 16 | * Chris also replaced the startup files with a Git submodule pointer to the ARM 17 | CDL project. 18 | * Chris fixed an bug with non-sequntial writes that would break large-ish 19 | firmware writes. 20 | * Chris added workarounds to allow flashing from all platforms from the CLI or a 21 | file browser (it's not exactly pretty, but it works - comments inline about 22 | the specific workarounds). 23 | 24 | ## Installing the Bootloader 25 | 26 | $ script/bootstrap.sh 27 | $ cd src 28 | $ make 29 | 30 | Assuming you have an Olimex ARM-OCD-USB JTAG adapter plugged in, connected to 31 | the board and the board powered up: 32 | 33 | $ make flash 34 | 35 | If you are using an Olimex ARM-USB-OCD-H JTAG adapter, you need to specify a different interface: 36 | 37 | $ JTAG_INTERFACE=olimex-arm-usb-ocd-h make flash 38 | 39 | ## Building User Firmware 40 | 41 | See the simple program in the `example` directory for an example of how to build 42 | a program for the bootloader. 43 | 44 | The only change required is your linker script - instead of starting the user 45 | program at flash memory location 0, start it at `0x10000`, e.g.: 46 | 47 | FLASH (rx) : ORIGIN = 0x10000, LENGTH = 512K - 0x10000 48 | 49 | If you are using the `SystemInit()` function from the ARM CDL, be aware that it 50 | sets the vector table offset register (`VTOR`) back to `0`, so interrupts will 51 | not work. A workaround is to manually set the `VTOR` to the location of your 52 | interrupt vectors at startup: 53 | 54 | void Reset_Handler(void) { 55 | SystemInit(); 56 | SCB->VTOR = (uint32_t) interrupt_vectors; 57 | ... 58 | } 59 | 60 | This workaround doesn't have any negative effects if you use the same code 61 | running on bare metal. 62 | 63 | ## Flashing User Code 64 | 65 | Note that the `firmware.bin` file will always look the same (with an old 66 | modification date and the same `firmware.bin` filename), even if you reflash and 67 | remount the bootloader. It's not a true filesystem, we are just creating a fake 68 | file so you can write to it from standard file browser tools. 69 | 70 | ### Windows 71 | 72 | To flash, hold down the bootloader entry button while plugging into USB or 73 | hitting the reset button. A USB drive should appear. 74 | 75 | * Delete the firmware.bin file 76 | * Copy your new firmware.bin over (the filename doesn't matter) 77 | * Unmount and reset the microcontroller 78 | 79 | ### Mac OS X 80 | 81 | To flash, hold down the bootloader entry button while plugging into USB or 82 | hitting the reset button. A USB drive should appear. 83 | 84 | **Using Finder** 85 | 86 | * Delete the firmware.bin file 87 | * Copy your new firmware.bin over (the filename doesn't matter) 88 | * Eject and reset the microcontroller 89 | 90 | **Command Line** 91 | 92 | Open the Terminal app and run this to update the 93 | firmware, assuming the file "newfirmware.bin" is in the current 94 | directory and is the new version of the firmware you want to flash: 95 | 96 | $ cp newfirmware.bin /Volumes/LPC1759/firmware.bin 97 | 98 | Eject and reset the microcontroller. 99 | 100 | ### Linux 101 | 102 | There are two good options for flashing user firmware from Linux. 103 | 104 | **USB Drive Method** 105 | 106 | To flash, hold down the bootloader entry button while plugging into USB or 107 | hitting the reset button. A USB drive should appear in your file manager (or you 108 | can mount it manually with the `vfat` filesystem type). 109 | 110 | * Delete the firmware.bin file 111 | * Copy your new firmware.bin over (the filename doesn't matter) 112 | * Unmount and reset the microcontroller 113 | 114 | (These instructions are the same as Windows.) 115 | 116 | Mounting the USB disk drive, deleting firmware.bin and copying over the new file 117 | works fine now (after some bug fixes in the [original version of this 118 | bootloader](http://dangerousprototypes.com/docs/LPC_ARM_quick_start#Bootloaders). 119 | 120 | ## License 121 | 122 | The LPCUSB library is made availble under the BSD license. It is linked to from 123 | this project as a Git submodule. 124 | 125 | The core of the bootloader is originally developed by NXP, and is licensed under 126 | NXP's odd example code license: 127 | 128 | Software that is described herein is for illustrative purposes only 129 | which provides customers with programming information regarding the 130 | products. This software is supplied "AS IS" without any warranties. 131 | NXP Semiconductors assumes no responsibility or liability for the 132 | use of the software, conveys no license or title under any patent, 133 | copyright, or mask work right to the product. NXP Semiconductors 134 | reserves the right to make changes in the software without 135 | notification. NXP Semiconductors also make no representation or 136 | warranty that such application will be suitable for the specified 137 | use without further testing or modification. 138 | 139 | NXP claims no liability, but "conveys no license" which makes it not really open 140 | source. Representatives of NXP have publicly stated that they are OK with the 141 | examples being used and redistributed, so we use it here in good faith 142 | ([source](http://knowledgebase.nxp.com/showthread.php?t=2514&langid=2)). 143 | 144 | A few remaining lines of code within other files pieces were developed by Code 145 | Red, and are possibly available under a more restrictive license: 146 | 147 | The software is owned by Code Red Technologies and/or its suppliers, and is 148 | protected under applicable copyright laws. All rights are reserved. Any 149 | use in violation of the foregoing restrictions may subject the user to criminal 150 | sanctions under applicable laws, as well as to civil liability for the breach 151 | of the terms and conditions of this license. 152 | 153 | THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED 154 | OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF 155 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. 156 | USE OF THIS SOFTWARE FOR COMMERCIAL DEVELOPMENT AND/OR EDUCATION IS SUBJECT 157 | TO A CURRENT END USER LICENSE AGREEMENT (COMMERCIAL OR EDUCATIONAL) WITH 158 | CODE RED TECHNOLOGIES LTD. 159 | 160 | Code Red has taken a public position that they are fine with redistributing the 161 | code and including it in products, as long as the copyright message remains 162 | intact so we use it here in good faith 163 | ([source](http://knowledgebase.nxp.trimm.net/showthread.php?p=12830)). 164 | -------------------------------------------------------------------------------- /conf/openocd/flash.cfg: -------------------------------------------------------------------------------- 1 | adapter_nsrst_assert_width 10 2 | reset_config srst_only 3 | 4 | init 5 | sleep 100 6 | reset halt 7 | wait_halt 8 | sleep 100 9 | 10 | flash write_image erase bootloader.bin 0 bin 11 | 12 | reset run 13 | shutdown 14 | -------------------------------------------------------------------------------- /conf/openocd/gdb.cfg: -------------------------------------------------------------------------------- 1 | source [find interface/ftdi/olimex-arm-usb-ocd.cfg] 2 | source [find target/lpc1768.cfg] 3 | 4 | adapter_nsrst_assert_width 10 5 | reset_config srst_only 6 | adapter_khz 1200 7 | 8 | init 9 | sleep 100 10 | reset halt 11 | wait_halt 12 | sleep 100 13 | -------------------------------------------------------------------------------- /conf/openocd/interface/olimex-arm-usb-ocd-custom.cfg: -------------------------------------------------------------------------------- 1 | source [find interface/ftdi/olimex-arm-usb-ocd.cfg] 2 | source [find target/lpc1769.cfg] 3 | 4 | # must set after including lpc1769.cfg, that sets the speed back to 10 khz 5 | adapter_khz 1200 6 | -------------------------------------------------------------------------------- /conf/openocd/interface/olimex-arm-usb-ocd-h-custom.cfg: -------------------------------------------------------------------------------- 1 | source [find interface/ftdi/olimex-arm-usb-ocd-h.cfg] 2 | source [find target/lpc1769.cfg] 3 | 4 | # must set after including lpc1769.cfg, that sets the speed back to 10 khz 5 | adapter_khz 700 6 | -------------------------------------------------------------------------------- /example/.gdbinit: -------------------------------------------------------------------------------- 1 | define hook-step 2 | mon cortex_m3 maskisr on 3 | end 4 | 5 | define hookpost-step 6 | mon cortex_m3 maskisr off 7 | end 8 | 9 | define hook-next 10 | mon cortex_m3 maskisr on 11 | end 12 | 13 | define hookpost-next 14 | mon cortex_m3 maskisr off 15 | end 16 | 17 | set remote hardware-breakpoint-limit 6 18 | set remote hardware-watchpoint-limit 4 19 | 20 | target remote localhost:3333 21 | 22 | echo .gdbinit for blink has been executed \n 23 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | a.map 2 | -------------------------------------------------------------------------------- /example/LPC1768.ld: -------------------------------------------------------------------------------- 1 | /* Linker script for mbed LPC1768 */ 2 | GROUP(-lstdc++ -lsupc++ -lm -lc -lnosys -lgcc) 3 | 4 | /* Linker script to configure memory regions. */ 5 | MEMORY 6 | { 7 | FLASH (rx) : ORIGIN = 0x10000, LENGTH = 512K - 0x10000 8 | RAM (rwx) : ORIGIN = 0x100000C8, LENGTH = 0x7F38 9 | 10 | USB_RAM(rwx) : ORIGIN = 0x2007C000, LENGTH = 16K 11 | ETH_RAM(rwx) : ORIGIN = 0x20080000, LENGTH = 16K 12 | } 13 | 14 | /* Linker script to place sections and symbol values. Should be used together 15 | * with other linker script that defines memory regions FLASH and RAM. 16 | * It references following symbols, which must be defined in code: 17 | * Reset_Handler : Entry of reset handler 18 | * 19 | * It defines following symbols, which code can use without definition: 20 | * __exidx_start 21 | * __exidx_end 22 | * __etext 23 | * __data_start__ 24 | * __preinit_array_start 25 | * __preinit_array_end 26 | * __init_array_start 27 | * __init_array_end 28 | * __fini_array_start 29 | * __fini_array_end 30 | * __data_end__ 31 | * __bss_start__ 32 | * __bss_end__ 33 | * __end__ 34 | * end 35 | * __HeapLimit 36 | * __StackLimit 37 | * __StackTop 38 | * __stack 39 | */ 40 | ENTRY(Reset_Handler) 41 | 42 | SECTIONS 43 | { 44 | .text : 45 | { 46 | KEEP(*(.isr_vector)) 47 | *(.text*) 48 | 49 | KEEP(*(.init)) 50 | KEEP(*(.fini)) 51 | 52 | /* .ctors */ 53 | *crtbegin.o(.ctors) 54 | *crtbegin?.o(.ctors) 55 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 56 | *(SORT(.ctors.*)) 57 | *(.ctors) 58 | 59 | /* .dtors */ 60 | *crtbegin.o(.dtors) 61 | *crtbegin?.o(.dtors) 62 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 63 | *(SORT(.dtors.*)) 64 | *(.dtors) 65 | 66 | *(.rodata*) 67 | 68 | KEEP(*(.eh_frame*)) 69 | } > FLASH 70 | 71 | .ARM.extab : 72 | { 73 | *(.ARM.extab* .gnu.linkonce.armextab.*) 74 | } > FLASH 75 | 76 | __exidx_start = .; 77 | .ARM.exidx : 78 | { 79 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 80 | } > FLASH 81 | __exidx_end = .; 82 | 83 | __etext = .; 84 | 85 | .data : AT (__etext) 86 | { 87 | __data_start__ = .; 88 | *(vtable) 89 | *(.data*) 90 | 91 | . = ALIGN(4); 92 | /* preinit data */ 93 | PROVIDE (__preinit_array_start = .); 94 | KEEP(*(.preinit_array)) 95 | PROVIDE (__preinit_array_end = .); 96 | 97 | . = ALIGN(4); 98 | /* init data */ 99 | PROVIDE (__init_array_start = .); 100 | KEEP(*(SORT(.init_array.*))) 101 | KEEP(*(.init_array)) 102 | PROVIDE (__init_array_end = .); 103 | 104 | 105 | . = ALIGN(4); 106 | /* finit data */ 107 | PROVIDE (__fini_array_start = .); 108 | KEEP(*(SORT(.fini_array.*))) 109 | KEEP(*(.fini_array)) 110 | PROVIDE (__fini_array_end = .); 111 | 112 | . = ALIGN(4); 113 | /* All data end */ 114 | __data_end__ = .; 115 | 116 | } > RAM 117 | 118 | .bss : 119 | { 120 | __bss_start__ = .; 121 | *(.bss*) 122 | *(COMMON) 123 | __bss_end__ = .; 124 | } > RAM 125 | 126 | .heap : 127 | { 128 | __end__ = .; 129 | end = __end__; 130 | *(.heap*) 131 | __HeapLimit = .; 132 | } > RAM 133 | 134 | /* .stack_dummy section doesn't contains any symbols. It is only 135 | * used for linker to calculate size of stack sections, and assign 136 | * values to stack symbols later */ 137 | .stack_dummy : 138 | { 139 | *(.stack) 140 | } > RAM 141 | 142 | /* Set stack top to end of RAM, and stack limit move down by 143 | * size of stack_dummy section */ 144 | __StackTop = ORIGIN(RAM) + LENGTH(RAM); 145 | __StackLimit = __StackTop - SIZEOF(.stack_dummy); 146 | PROVIDE(__stack = __StackTop); 147 | 148 | /* Check if data + heap + stack exceeds RAM limit */ 149 | ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") 150 | } 151 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | GCC_ARM_ON_PATH = $(shell command -v arm-none-eabi-gcc >/dev/null; echo $$?) 2 | 3 | GCC_BIN = 4 | ifneq ($(GCC_ARM_ON_PATH),0) 5 | GCC_BIN = ../dependencies/gcc-arm-embedded/bin/ 6 | endif 7 | 8 | PROJECT = blink 9 | CMSIS_PATH = ../src/CDL/CMSISv2p00_LPC17xx 10 | DRIVER_PATH = ../src/CDL/LPC17xxLib 11 | SYS_OBJECTS = 12 | INCLUDE_PATHS = -I. -I./usbstack/include -I$(DRIVER_PATH)/inc \ 13 | -I$(CMSIS_PATH)/inc -ITimer 14 | LIBRARY_PATHS = 15 | LIBRARIES = 16 | LINKER_SCRIPT = LPC1768.ld 17 | 18 | LOCAL_C_SRCS = $(CMSIS_PATH)/src/core_cm3.c $(CMSIS_PATH)/src/system_LPC17xx.c \ 19 | $(wildcard $(CMSIS_PATH)/source/*.c) main.c startup.c \ 20 | Timer/timer.c 21 | LOCAL_OBJ_FILES = $(LOCAL_C_SRCS:.c=.o) 22 | OBJECTS = $(LOCAL_OBJ_FILES) 23 | 24 | ############################################################################### 25 | CC = $(GCC_BIN)arm-none-eabi-gcc 26 | CPP = $(GCC_BIN)arm-none-eabi-g++ 27 | CC_FLAGS = -g -ggdb -c -Os -fno-common -fmessage-length=0 -Wall -fno-exceptions -mcpu=cortex-m3 -mthumb -ffunction-sections -fdata-sections 28 | ONLY_C_FLAGS = -std=gnu99 29 | ONLY_CPP_FLAGS = -std=gnu++98 30 | CC_SYMBOLS = -DTARGET_LPC1768 -DTOOLCHAIN_GCC_ARM \ 31 | -DUSB_DEVICE_ONLY -D__LPC17XX__ -DBOARD=9 32 | 33 | 34 | AS = $(GCC_BIN)arm-none-eabi-as 35 | 36 | LD = $(GCC_BIN)arm-none-eabi-gcc 37 | LD_FLAGS = -mcpu=cortex-m3 -mthumb -Wl,--gc-sections,-Map=a.map 38 | LD_SYS_LIBS = -lstdc++ -lsupc++ -lm -lc -lgcc 39 | 40 | OBJCOPY = $(GCC_BIN)arm-none-eabi-objcopy 41 | 42 | all: $(PROJECT).bin 43 | 44 | clean: 45 | rm -f $(PROJECT).bin $(PROJECT).elf $(OBJECTS) *.o *.map 46 | 47 | .s.o: 48 | $(AS) $(CC_FLAGS) $(CC_SYMBOLS) -o $@ $< 49 | 50 | .c.o: 51 | $(CC) $(CC_FLAGS) $(CC_SYMBOLS) $(ONLY_C_FLAGS) $(INCLUDE_PATHS) -o $@ $< 52 | 53 | .cpp.o: 54 | $(CPP) $(CC_FLAGS) $(CC_SYMBOLS) $(ONLY_CPP_FLAGS) $(INCLUDE_PATHS) -o $@ $< 55 | 56 | 57 | $(PROJECT).elf: $(OBJECTS) $(SYS_OBJECTS) 58 | $(LD) $(LD_FLAGS) -T$(LINKER_SCRIPT) $(LIBRARY_PATHS) -o $@ $^ $(LIBRARIES) $(LD_SYS_LIBS) $(LIBRARIES) $(LD_SYS_LIBS) 59 | 60 | $(PROJECT).bin: $(PROJECT).elf 61 | $(OBJCOPY) -O binary $< $@ 62 | -------------------------------------------------------------------------------- /example/README.mkd: -------------------------------------------------------------------------------- 1 | Example User Program for USB Bootloader 2 | ======================================== 3 | 4 | To build this example: 5 | 6 | $ make 7 | 8 | Then follow the instructions in src/README to load it to flash using the 9 | bootloader. This program *will not* work if you flash it to bare metal - the 10 | vector table is in the wrong place. 11 | -------------------------------------------------------------------------------- /example/Timer/timer.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * $Id:: timer.c 5823 2010-12-07 19:01:00Z usb00423 $ 3 | * Project: NXP LPC17xx Timer for PWM example 4 | * 5 | * Description: 6 | * This file contains timer code example which include timer 7 | * initialization, timer interrupt handler, and APIs for timer access. 8 | * 9 | **************************************************************************** 10 | * Software that is described herein is for illustrative purposes only 11 | * which provides customers with programming information regarding the 12 | * products. This software is supplied "AS IS" without any warranties. 13 | * NXP Semiconductors assumes no responsibility or liability for the 14 | * use of the software, conveys no license or title under any patent, 15 | * copyright, or mask work right to the product. NXP Semiconductors 16 | * reserves the right to make changes in the software without 17 | * notification. NXP Semiconductors also make no representation or 18 | * warranty that such application will be suitable for the specified 19 | * use without further testing or modification. 20 | ****************************************************************************/ 21 | #include "LPC17xx.h" 22 | #include "lpc_types.h" 23 | #include "timer.h" 24 | 25 | volatile uint32_t timer0_m0_counter = 0; 26 | volatile uint32_t timer1_m0_counter = 0; 27 | volatile uint32_t timer2_m0_counter = 0; 28 | volatile uint32_t timer3_m0_counter = 0; 29 | volatile uint32_t timer0_m1_counter = 0; 30 | volatile uint32_t timer1_m1_counter = 0; 31 | volatile uint32_t timer2_m1_counter = 0; 32 | volatile uint32_t timer3_m1_counter = 0; 33 | 34 | volatile uint32_t timer0_capture0 = 0; 35 | volatile uint32_t timer1_capture0 = 0; 36 | volatile uint32_t timer2_capture0 = 0; 37 | volatile uint32_t timer3_capture0 = 0; 38 | volatile uint32_t timer0_capture1 = 0; 39 | volatile uint32_t timer1_capture1 = 0; 40 | volatile uint32_t timer2_capture1 = 0; 41 | volatile uint32_t timer3_capture1 = 0; 42 | 43 | /***************************************************************************** 44 | ** Function name: delayMs 45 | ** 46 | ** Descriptions: Start the timer delay in milo seconds 47 | ** until elapsed 48 | ** 49 | ** parameters: timer number, Delay value in milo second 50 | ** 51 | ** Returned value: None 52 | ** 53 | *****************************************************************************/ 54 | void delayMs(uint8_t timer_num, uint32_t delayInMs) 55 | { 56 | if ( timer_num == 0 ) 57 | { 58 | LPC_TIM0->TCR = 0x02; /* reset timer */ 59 | LPC_TIM0->PR = 0x00; /* set prescaler to zero */ 60 | LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time 61 | LPC_TIM0->IR = 0xff; /* reset all interrrupts */ 62 | LPC_TIM0->MCR = 0x04; /* stop timer on match */ 63 | LPC_TIM0->TCR = 0x01; /* start timer */ 64 | 65 | /* wait until delay time has elapsed */ 66 | while (LPC_TIM0->TCR & 0x01); 67 | 68 | } 69 | else if ( timer_num == 1 ) 70 | { 71 | LPC_TIM1->TCR = 0x02; /* reset timer */ 72 | LPC_TIM1->PR = 0x00; /* set prescaler to zero */ 73 | LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time 74 | LPC_TIM1->IR = 0xff; /* reset all interrrupts */ 75 | LPC_TIM1->MCR = 0x04; /* stop timer on match */ 76 | LPC_TIM1->TCR = 0x01; /* start timer */ 77 | 78 | /* wait until delay time has elapsed */ 79 | while (LPC_TIM1->TCR & 0x01); 80 | } 81 | 82 | else if ( timer_num == 2 ) 83 | { 84 | LPC_TIM2->TCR = 0x02; /* reset timer */ 85 | LPC_TIM2->PR = 0x00; /* set prescaler to zero */ 86 | LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time 87 | LPC_TIM2->IR = 0xff; /* reset all interrrupts */ 88 | LPC_TIM2->MCR = 0x04; /* stop timer on match */ 89 | LPC_TIM2->TCR = 0x01; /* start timer */ 90 | 91 | /* wait until delay time has elapsed */ 92 | while (LPC_TIM2->TCR & 0x01); 93 | } 94 | 95 | else if ( timer_num == 3 ) 96 | { 97 | LPC_TIM3->TCR = 0x02; /* reset timer */ 98 | LPC_TIM3->PR = 0x00; /* set prescaler to zero */ 99 | LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time 100 | LPC_TIM3->IR = 0xff; /* reset all interrrupts */ 101 | LPC_TIM3->MCR = 0x04; /* stop timer on match */ 102 | LPC_TIM3->TCR = 0x01; /* start timer */ 103 | 104 | /* wait until delay time has elapsed */ 105 | while (LPC_TIM3->TCR & 0x01); 106 | } 107 | return; 108 | } 109 | 110 | /****************************************************************************** 111 | ** Function name: Timer0_IRQHandler 112 | ** 113 | ** Descriptions: Timer/Counter 0 interrupt handler 114 | ** 115 | ** parameters: None 116 | ** Returned value: None 117 | ** 118 | ******************************************************************************/ 119 | void TIMER0_interrupt (void) 120 | { 121 | if ( LPC_TIM0->IR & (0x1<<0) ) 122 | { 123 | LPC_TIM0->IR = 0x1<<0; /* clear interrupt flag */ 124 | timer0_m0_counter++; 125 | } 126 | if ( LPC_TIM0->IR & (0x1<<1) ) 127 | { 128 | LPC_TIM0->IR = 0x1<<1; /* clear interrupt flag */ 129 | timer0_m1_counter++; 130 | } 131 | if ( LPC_TIM0->IR & (0x1<<4) ) 132 | { 133 | LPC_TIM0->IR = 0x1<<4; /* clear interrupt flag */ 134 | timer0_capture0++; 135 | } 136 | if ( LPC_TIM0->IR & (0x1<<5) ) 137 | { 138 | LPC_TIM0->IR = 0x1<<5; /* clear interrupt flag */ 139 | timer0_capture1++; 140 | } 141 | return; 142 | } 143 | 144 | /****************************************************************************** 145 | ** Function name: Timer1_IRQHandler 146 | ** 147 | ** Descriptions: Timer/Counter 1 interrupt handler 148 | ** 149 | ** parameters: None 150 | ** Returned value: None 151 | ** 152 | ******************************************************************************/ 153 | void TIMER1_interrupt (void) 154 | { 155 | if ( LPC_TIM1->IR & (0x1<<0) ) 156 | { 157 | LPC_TIM1->IR = 0x1<<0; /* clear interrupt flag */ 158 | timer1_m0_counter++; 159 | } 160 | if ( LPC_TIM1->IR & (0x1<<1) ) 161 | { 162 | LPC_TIM1->IR = 0x1<<1; /* clear interrupt flag */ 163 | timer1_m1_counter++; 164 | } 165 | if ( LPC_TIM1->IR & (0x1<<4) ) 166 | { 167 | LPC_TIM1->IR = 0x1<<4; /* clear interrupt flag */ 168 | timer1_capture0++; 169 | } 170 | if ( LPC_TIM1->IR & (0x1<<5) ) 171 | { 172 | LPC_TIM1->IR = 0x1<<5; /* clear interrupt flag */ 173 | timer1_capture1++; 174 | } 175 | return; 176 | } 177 | 178 | /****************************************************************************** 179 | ** Function name: Timer2_IRQHandler 180 | ** 181 | ** Descriptions: Timer/Counter 2 interrupt handler 182 | ** 183 | ** parameters: None 184 | ** Returned value: None 185 | ** 186 | ******************************************************************************/ 187 | void TIMER2_interrupt (void) 188 | { 189 | if ( LPC_TIM2->IR & (0x1<<0) ) 190 | { 191 | LPC_TIM2->IR = 0x1<<0; /* clear interrupt flag */ 192 | timer2_m0_counter++; 193 | } 194 | if ( LPC_TIM2->IR & (0x1<<1) ) 195 | { 196 | LPC_TIM2->IR = 0x1<<1; /* clear interrupt flag */ 197 | timer2_m1_counter++; 198 | } 199 | if ( LPC_TIM2->IR & (0x1<<4) ) 200 | { 201 | LPC_TIM2->IR = 0x1<<4; /* clear interrupt flag */ 202 | timer2_capture0++; 203 | } 204 | if ( LPC_TIM2->IR & (0x1<<5) ) 205 | { 206 | LPC_TIM2->IR = 0x1<<5; /* clear interrupt flag */ 207 | timer2_capture1++; 208 | } 209 | return; 210 | } 211 | 212 | /****************************************************************************** 213 | ** Function name: Timer3_IRQHandler 214 | ** 215 | ** Descriptions: Timer/Counter 3 interrupt handler 216 | ** 217 | ** parameters: None 218 | ** Returned value: None 219 | ** 220 | ******************************************************************************/ 221 | void TIMER3_interrupt (void) 222 | { 223 | if ( LPC_TIM3->IR & (0x1<<0) ) 224 | { 225 | LPC_TIM3->IR = 0x1<<0; /* clear interrupt flag */ 226 | timer3_m0_counter++; 227 | } 228 | if ( LPC_TIM3->IR & (0x1<<1) ) 229 | { 230 | LPC_TIM3->IR = 0x1<<1; /* clear interrupt flag */ 231 | timer3_m1_counter++; 232 | } 233 | if ( LPC_TIM3->IR & (0x1<<4) ) 234 | { 235 | LPC_TIM3->IR = 0x1<<4; /* clear interrupt flag */ 236 | timer3_capture0++; 237 | } 238 | if ( LPC_TIM3->IR & (0x1<<5) ) 239 | { 240 | LPC_TIM3->IR = 0x1<<5; /* clear interrupt flag */ 241 | timer3_capture1++; 242 | } 243 | return; 244 | } 245 | 246 | /****************************************************************************** 247 | ** Function name: enable_timer 248 | ** 249 | ** Descriptions: Enable timer 250 | ** 251 | ** parameters: timer number: 0 or 1 or 2 or 3 252 | ** Returned value: None 253 | ** 254 | ******************************************************************************/ 255 | void enable_timer( uint8_t timer_num ) 256 | { 257 | if ( timer_num == 0 ) 258 | { 259 | LPC_TIM0->TCR = 1; 260 | } 261 | else if ( timer_num == 1 ) 262 | { 263 | LPC_TIM1->TCR = 1; 264 | } 265 | else if ( timer_num == 2 ) 266 | { 267 | LPC_TIM2->TCR = 1; 268 | } 269 | else if ( timer_num == 3 ) 270 | { 271 | LPC_TIM3->TCR = 1; 272 | } 273 | return; 274 | } 275 | 276 | /****************************************************************************** 277 | ** Function name: disable_timer 278 | ** 279 | ** Descriptions: Disable timer 280 | ** 281 | ** parameters: timer number: 0 or 1 oe 2 or 3 282 | ** Returned value: None 283 | ** 284 | ******************************************************************************/ 285 | void disable_timer( uint8_t timer_num ) 286 | { 287 | if ( timer_num == 0 ) 288 | { 289 | LPC_TIM0->TCR = 0; 290 | } 291 | else if ( timer_num == 1 ) 292 | { 293 | LPC_TIM1->TCR = 0; 294 | } 295 | else if ( timer_num == 2 ) 296 | { 297 | LPC_TIM2->TCR = 0; 298 | } 299 | else if ( timer_num == 3 ) 300 | { 301 | LPC_TIM2->TCR = 0; 302 | } 303 | return; 304 | } 305 | 306 | /****************************************************************************** 307 | ** Function name: reset_timer 308 | ** 309 | ** Descriptions: Reset timer 310 | ** 311 | ** parameters: timer number: 0 or 1 or 2 or 3 312 | ** Returned value: None 313 | ** 314 | ******************************************************************************/ 315 | void reset_timer( uint8_t timer_num ) 316 | { 317 | uint32_t regVal; 318 | 319 | if ( timer_num == 0 ) 320 | { 321 | regVal = LPC_TIM0->TCR; 322 | regVal |= 0x02; 323 | LPC_TIM0->TCR = regVal; 324 | } 325 | else if ( timer_num == 1 ) 326 | { 327 | regVal = LPC_TIM1->TCR; 328 | regVal |= 0x02; 329 | LPC_TIM1->TCR = regVal; 330 | } 331 | else if ( timer_num == 2 ) 332 | { 333 | regVal = LPC_TIM2->TCR; 334 | regVal |= 0x02; 335 | LPC_TIM2->TCR = regVal; 336 | } 337 | else if ( timer_num == 3 ) 338 | { 339 | regVal = LPC_TIM3->TCR; 340 | regVal |= 0x02; 341 | LPC_TIM3->TCR = regVal; 342 | } 343 | return; 344 | } 345 | 346 | /****************************************************************************** 347 | ** Function name: init_timer 348 | ** 349 | ** Descriptions: Initialize timer, set timer interval, reset timer, 350 | ** install timer interrupt handler 351 | ** 352 | ** parameters: timer number and timer interval 353 | ** Returned value: true or false, if the interrupt handler can't be 354 | ** installed, return false. 355 | ** 356 | ******************************************************************************/ 357 | uint32_t TimerInit( uint8_t timer_num, uint32_t TimerInterval ) 358 | { 359 | uint32_t pclkdiv, pclk; 360 | 361 | if ( timer_num == 0 ) 362 | { 363 | timer0_m0_counter = 0; 364 | timer0_m1_counter = 0; 365 | timer0_capture0 = 0; 366 | timer0_capture1 = 0; 367 | LPC_SC->PCONP |= (0x01<<1); 368 | #if TIMER_MATCH 369 | LPC_PINCON->PINSEL3 &= ~((0x3<<24)|(0x3<<26)); 370 | LPC_PINCON->PINSEL3 |= ((0x3<<24)|(0x3<<26)); 371 | #else 372 | LPC_PINCON->PINSEL3 &= ~((0x3<<20)|(0x3<<22)); 373 | LPC_PINCON->PINSEL3 |= ((0x3<<20)|(0x3<<22)); 374 | #endif 375 | LPC_TIM0->IR = 0x0F; /* Clear MATx interrupt include DMA request */ 376 | 377 | /* By default, the PCLKSELx value is zero, thus, the PCLK for 378 | all the peripherals is 1/4 of the SystemCoreClock. */ 379 | /* Bit 2~3 is for TIMER0 */ 380 | pclkdiv = (LPC_SC->PCLKSEL0 >> 2) & 0x03; 381 | switch ( pclkdiv ) 382 | { 383 | case 0x00: 384 | default: 385 | pclk = SystemCoreClock/4; 386 | break; 387 | case 0x01: 388 | pclk = SystemCoreClock; 389 | break; 390 | case 0x02: 391 | pclk = SystemCoreClock/2; 392 | break; 393 | case 0x03: 394 | pclk = SystemCoreClock/8; 395 | break; 396 | } 397 | LPC_TIM0->PR = 0; 398 | 399 | LPC_TIM0->MR0 = TimerInterval/4; 400 | LPC_TIM0->MR1 = TimerInterval/4; 401 | #if TIMER_MATCH 402 | LPC_TIM0->EMR &= ~(0xFF<<4); 403 | LPC_TIM0->EMR |= ((0x3<<4)|(0x3<<6)); 404 | #else 405 | /* Capture 0 and 1 on rising edge, interrupt enable. */ 406 | LPC_TIM0->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5); 407 | #endif 408 | LPC_TIM0->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */ 409 | NVIC_EnableIRQ(TIMER0_IRQn); 410 | return (TRUE); 411 | } 412 | else if ( timer_num == 1 ) 413 | { 414 | timer1_m0_counter = 0; 415 | timer1_m1_counter = 0; 416 | timer1_capture0 = 0; 417 | timer1_capture1 = 0; 418 | LPC_SC->PCONP |= (0x1<<2); 419 | #if TIMER_MATCH 420 | LPC_PINCON->PINSEL3 &= ~((0x3<<12)|(0x3<<18)); 421 | LPC_PINCON->PINSEL3 |= ((0x3<<12)|(0x3<<18)); 422 | #else 423 | LPC_PINCON->PINSEL3 &= ~((0x3<<4)|(0x3<<6)); 424 | LPC_PINCON->PINSEL3 |= ((0x3<<4)|(0x3<<6)); 425 | #endif 426 | LPC_TIM1->IR = 0x0F; /* Clear MATx interrupt include DMA request */ 427 | /* By default, the PCLKSELx value is zero, thus, the PCLK for 428 | all the peripherals is 1/4 of the SystemCoreClock. */ 429 | /* Bit 4~5 is for TIMER0 */ 430 | pclkdiv = (LPC_SC->PCLKSEL0 >> 4) & 0x03; 431 | switch ( pclkdiv ) 432 | { 433 | case 0x00: 434 | default: 435 | pclk = SystemCoreClock/4; 436 | break; 437 | case 0x01: 438 | pclk = SystemCoreClock; 439 | break; 440 | case 0x02: 441 | pclk = SystemCoreClock/2; 442 | break; 443 | case 0x03: 444 | pclk = SystemCoreClock/8; 445 | break; 446 | } 447 | LPC_TIM1->PR = 0; 448 | LPC_TIM1->MR0 = TimerInterval/4; 449 | LPC_TIM1->MR1 = TimerInterval/4; 450 | #if TIMER_MATCH 451 | LPC_TIM1->EMR &= ~(0xFF<<4); 452 | LPC_TIM1->EMR |= ((0x3<<4)|(0x3<<6)); 453 | #else 454 | /* Capture 0/1 on rising edge, interrupt enable. */ 455 | LPC_TIM1->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5); 456 | #endif 457 | LPC_TIM1->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */ 458 | NVIC_EnableIRQ(TIMER1_IRQn); 459 | return (TRUE); 460 | } 461 | 462 | else if ( timer_num == 2 ) 463 | { 464 | timer2_m0_counter = 0; 465 | timer2_m1_counter = 0; 466 | timer2_capture0 = 0; 467 | timer2_capture1 = 0; 468 | LPC_SC->PCONP |= (0x1<<22); 469 | #if TIMER_MATCH 470 | LPC_PINCON->PINSEL3 &= ~((0x3<<12)|(0x3<<18)); 471 | LPC_PINCON->PINSEL3 |= ((0x3<<12)|(0x3<<18)); 472 | #else 473 | LPC_PINCON->PINSEL3 &= ~((0x3<<4)|(0x3<<6)); 474 | LPC_PINCON->PINSEL3 |= ((0x3<<4)|(0x3<<6)); 475 | #endif 476 | LPC_TIM2->IR = 0x0F; /* Clear MATx interrupt include DMA request */ 477 | /* By default, the PCLKSELx value is zero, thus, the PCLK for 478 | all the peripherals is 1/4 of the SystemCoreClock. */ 479 | /* Bit 12~13 is for TIMER2 */ 480 | pclkdiv = (LPC_SC->PCLKSEL1 >> 12) & 0x03; 481 | switch ( pclkdiv ) 482 | { 483 | case 0x00: 484 | default: 485 | pclk = SystemCoreClock/4; 486 | break; 487 | case 0x01: 488 | pclk = SystemCoreClock; 489 | break; 490 | case 0x02: 491 | pclk = SystemCoreClock/2; 492 | break; 493 | case 0x03: 494 | pclk = SystemCoreClock/8; 495 | break; 496 | } 497 | LPC_TIM2->PR = 0; 498 | LPC_TIM2->MR0 = TimerInterval/4; 499 | LPC_TIM2->MR1 = TimerInterval/4; 500 | #if TIMER_MATCH 501 | LPC_TIM2->EMR &= ~(0xFF<<4); 502 | LPC_TIM2->EMR |= ((0x3<<4)|(0x3<<6)); 503 | #else 504 | /* Capture 0/1 on rising edge, interrupt enable. */ 505 | LPC_TIM2->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5); 506 | #endif 507 | LPC_TIM2->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */ 508 | NVIC_EnableIRQ(TIMER2_IRQn); 509 | return (TRUE); 510 | } 511 | 512 | else if ( timer_num == 3 ) 513 | { 514 | timer3_m0_counter = 0; 515 | timer3_m1_counter = 0; 516 | timer3_capture0 = 0; 517 | timer3_capture1 = 0; 518 | LPC_SC->PCONP |= (0x1<<23); 519 | #if TIMER_MATCH 520 | LPC_PINCON->PINSEL3 &= ~((0x3<<12)|(0x3<<18)); 521 | LPC_PINCON->PINSEL3 |= ((0x3<<12)|(0x3<<18)); 522 | #else 523 | LPC_PINCON->PINSEL3 &= ~((0x3<<4)|(0x3<<6)); 524 | LPC_PINCON->PINSEL3 |= ((0x3<<4)|(0x3<<6)); 525 | #endif 526 | LPC_TIM3->IR = 0x0F; /* Clear MATx interrupt include DMA request */ 527 | /* By default, the PCLKSELx value is zero, thus, the PCLK for 528 | all the peripherals is 1/4 of the SystemCoreClock. */ 529 | /* Bit 14~15 is for TIMER3 */ 530 | pclkdiv = (LPC_SC->PCLKSEL1 >> 14) & 0x03; 531 | switch ( pclkdiv ) 532 | { 533 | case 0x00: 534 | default: 535 | pclk = SystemCoreClock/4; 536 | break; 537 | case 0x01: 538 | pclk = SystemCoreClock; 539 | break; 540 | case 0x02: 541 | pclk = SystemCoreClock/2; 542 | break; 543 | case 0x03: 544 | pclk = SystemCoreClock/8; 545 | break; 546 | } 547 | LPC_TIM3->PR = 0; 548 | LPC_TIM3->MR0 = TimerInterval/4; 549 | LPC_TIM3->MR1 = TimerInterval/4; 550 | #if TIMER_MATCH 551 | LPC_TIM3->EMR &= ~(0xFF<<4); 552 | LPC_TIM3->EMR |= ((0x3<<4)|(0x3<<6)); 553 | #else 554 | /* Capture 0/1 on rising edge, interrupt enable. */ 555 | LPC_TIM3->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5); 556 | #endif 557 | LPC_TIM3->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */ 558 | NVIC_EnableIRQ(TIMER3_IRQn); 559 | return (TRUE); 560 | } 561 | 562 | return (FALSE); 563 | } 564 | 565 | /****************************************************************************** 566 | ** End Of File 567 | ******************************************************************************/ 568 | -------------------------------------------------------------------------------- /example/Timer/timer.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * $Id:: timer.h 5823 2010-12-07 19:01:00Z usb00423 $ 3 | * Project: NXP LPC17xx Timer example 4 | * 5 | * Description: 6 | * This file contains Timer code header definition. 7 | * 8 | **************************************************************************** 9 | * Software that is described herein is for illustrative purposes only 10 | * which provides customers with programming information regarding the 11 | * products. This software is supplied "AS IS" without any warranties. 12 | * NXP Semiconductors assumes no responsibility or liability for the 13 | * use of the software, conveys no license or title under any patent, 14 | * copyright, or mask work right to the product. NXP Semiconductors 15 | * reserves the right to make changes in the software without 16 | * notification. NXP Semiconductors also make no representation or 17 | * warranty that such application will be suitable for the specified 18 | * use without further testing or modification. 19 | ****************************************************************************/ 20 | #ifndef __TIMER_H 21 | #define __TIMER_H 22 | 23 | /* The test is either MAT_OUT or CAP_IN. Default is MAT_OUT. */ 24 | /* If running DMA test, External match is not needed to trigger DMA, but still 25 | set timer as MATx instead of CAPx. */ 26 | #define TIMER_MATCH 1 27 | 28 | /* TIME_INTERVALmS is a value to load the timer match register with 29 | to get a 1 mS delay */ 30 | #define TIME_INTERVALmS 1000 31 | 32 | #define TIME_INTERVAL (9000000/100 - 1) 33 | 34 | extern void delayMs(uint8_t timer_num, uint32_t delayInMs); 35 | extern uint32_t TimerInit( uint8_t timer_num, uint32_t timerInterval ); 36 | extern void enable_timer( uint8_t timer_num ); 37 | extern void disable_timer( uint8_t timer_num ); 38 | extern void reset_timer( uint8_t timer_num ); 39 | extern void TIMER0_interrupt (void); 40 | extern void TIMER1_interrupt (void); 41 | extern void TIMER2_interrupt (void); 42 | extern void TIMER3_interrupt (void); 43 | 44 | #endif /* end __TIMER_H */ 45 | /***************************************************************************** 46 | ** End Of File 47 | ******************************************************************************/ 48 | -------------------------------------------------------------------------------- /example/gdb.cfg: -------------------------------------------------------------------------------- 1 | source [find interface/olimex-arm-usb-ocd.cfg] 2 | source [find target/lpc1769.cfg] 3 | 4 | adapter_nsrst_assert_width 10 5 | reset_config srst_only 6 | adapter_khz 1200 7 | 8 | init 9 | sleep 100 10 | reset halt 11 | wait_halt 12 | sleep 100 13 | -------------------------------------------------------------------------------- /example/main.c: -------------------------------------------------------------------------------- 1 | #include "LPC17xx.h" 2 | 3 | #define LED_PORTNUM 1 4 | #define LED_PINNUM 26 5 | 6 | int main (void) { 7 | LPC_SC->PCONP |= ( 1 << 15 ); // power up GPIO 8 | LPC_GPIO1->FIODIR |= LED_PORTNUM << LED_PINNUM; // puts PLED_PORTNUM.29 into output mode. 9 | LPC_GPIO1->FIODIR |= LED_PORTNUM << 23; // puts PLED_PORTNUM.29 into output mode. 10 | LPC_GPIO1->FIODIR |= LED_PORTNUM << 24; // puts PLED_PORTNUM.29 into output mode. 11 | LPC_GPIO1->FIOPIN &= ~( LED_PORTNUM << LED_PINNUM ); // make PLED_PORTNUM.LED_PINNUM low 12 | LPC_GPIO1->FIOPIN &= ~( LED_PORTNUM << 23 ); // make PLED_PORTNUM.LED_PINNUM low 13 | LPC_GPIO1->FIOPIN &= ~( LED_PORTNUM << 24 ); // make PLED_PORTNUM.LED_PINNUM low 14 | while(1) { 15 | LPC_GPIO1->FIOPIN |= LED_PORTNUM << LED_PINNUM; // make P1LED_PORTNUM high 16 | LPC_GPIO1->FIOPIN |= LED_PORTNUM << 23; // make P1LED_PORTNUM high 17 | LPC_GPIO1->FIOPIN |= LED_PORTNUM << 24; // make P1LED_PORTNUM high 18 | delayMs(0, 500); 19 | LPC_GPIO1->FIOPIN &= ~( LED_PORTNUM << LED_PINNUM ); // make PLED_PORTNUM.LED_PINNUM low 20 | LPC_GPIO1->FIOPIN &= ~( LED_PORTNUM << 23 ); // make PLED_PORTNUM.LED_PINNUM low 21 | LPC_GPIO1->FIOPIN &= ~( LED_PORTNUM << 24 ); // make PLED_PORTNUM.LED_PINNUM low 22 | delayMs(0, 500); 23 | } 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /example/startup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Derived from startup code originally published by Jakub Piotr Cłapa, 3 | * Copyright (c) 2010 LoEE under the new BSD license. 4 | * 5 | * See also: http://bitbucket.org/jpc/lpc1768/ 6 | * 7 | * NVIC handler names from NXP UM10360, comments taken from Opendous Inc. under 8 | * the following license: 9 | * 10 | * Permission to use, copy, modify, and distribute this software and its 11 | * documentation for any purpose and without fee is hereby granted, provided 12 | * that the above copyright notice appear in all copies and that both that the 13 | * copyright notice and this permission notice and warranty disclaimer appear in 14 | * supporting documentation, and that the name of the author not be used in 15 | * advertising or publicity pertaining to distribution of the software without 16 | * specific, written prior permission. 17 | 18 | * The author disclaim all warranties with regard to this software, including 19 | * all implied warranties of merchantability and fitness. In no event shall the 20 | * author be liable for any special, indirect or consequential damages or any 21 | * damages whatsoever resulting from loss of use, data or profits, whether in an 22 | * action of contract, negligence or other tortious action, arising out of or in 23 | * connection with the use or performance of this software. 24 | */ 25 | #include "LPC17xx.h" 26 | 27 | // Defined in linker script 28 | extern void __stack(void); 29 | extern uint32_t __etext; 30 | extern uint32_t __data_start__; 31 | extern uint32_t __data_end__; 32 | extern uint32_t __bss_start__; 33 | extern uint32_t __bss_end__; 34 | 35 | // Defined by user application 36 | extern int main (void); 37 | 38 | // Dummy handler. 39 | void Default_Handler (void) { while (1); } 40 | 41 | // Weakly bind all interrupt vectors to the dummy handler. 42 | void NMI_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 43 | void HardFault_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 44 | void MemManage_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 45 | void BusFault_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 46 | void UsageFault_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 47 | void SVC_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 48 | void DebugMon_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 49 | void PendSV_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 50 | void SysTick_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 51 | void WDT_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 52 | void TIMER0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 53 | void TIMER1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 54 | void TIMER2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 55 | void TIMER3_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 56 | void UART0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 57 | void UART1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 58 | void UART2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 59 | void UART3_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 60 | void PWM1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 61 | void I2C0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 62 | void I2C1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 63 | void I2C2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 64 | void SPI_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 65 | void SSP0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 66 | void SSP1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 67 | void PLL0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 68 | void RTC_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 69 | void EINT0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 70 | void EINT1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 71 | void EINT2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 72 | void EINT3_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 73 | void ADC_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 74 | void BOD_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 75 | void USB_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 76 | void CAN_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 77 | void DMA_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 78 | void I2S_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 79 | void ENET_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 80 | void RIT_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 81 | void MCPWM_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 82 | void QEI_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 83 | void PLL1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 84 | void USBActivity_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 85 | void CANActivity_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 86 | 87 | // The signature of Cortex-M3 interrupt handlers. 88 | typedef void (* const Interrupt_Handler_P)(void); 89 | 90 | // Forward declaration of Reset_Handler so we can refernece interrupt_vectors 91 | // when setting the VTOR in the handler. 92 | void Reset_Handler(void); 93 | 94 | // Interrupt vectors table 95 | __attribute__ ((section(".isr_vector"))) 96 | Interrupt_Handler_P interrupt_vectors[] = { 97 | &__stack, // the first word contains the initial 98 | // stack pointer the hardware loads it 99 | // to the SP register before the first 100 | // instruction 101 | // Standard Cortex-M3 interrupts: 102 | Reset_Handler, 103 | NMI_Handler, 104 | HardFault_Handler, 105 | MemManage_Handler, 106 | BusFault_Handler, 107 | UsageFault_Handler, 108 | 0, 109 | 0, 110 | 0, 111 | 0, 112 | SVC_Handler, 113 | DebugMon_Handler, 114 | 0, 115 | PendSV_Handler, 116 | SysTick_Handler, 117 | // LPC17xx Interrupts: Interrupt ID - Exception Number - Vector Offset - Description and Flags 118 | 119 | WDT_IRQHandler, // 0 16 0x40 WDT Watchdog Interrupt (WDINT) 120 | TIMER0_IRQHandler, // 1 17 0x44 Timer 0 Match 0 - 1 (MR0, MR1) 121 | // Capture 0 - 1 (CR0, CR1) 122 | TIMER1_IRQHandler, // 2 18 0x48 Timer 1 Match 0 - 2 123 | // (MR0, MR1, MR2), Capture 0 - 1 (CR0, CR1) 124 | TIMER2_IRQHandler, // 3 19 0x4C Timer 2 Match 0-3 125 | // Capture 0-1 126 | TIMER3_IRQHandler, // 4 20 0x50 Timer 3 Match 0-3 127 | // Capture 0-1 128 | UART0_IRQHandler, // 5 21 0x54 UART0 Rx Line Status (RLS) 129 | // Transmit Holding Register Empty (THRE) 130 | // Rx Data Available (RDA) 131 | // Character Time-out Indicator (CTI) 132 | // End of Auto-Baud (ABEO) 133 | // Auto-Baud Time-Out (ABTO) 134 | UART1_IRQHandler, // 6 22 0x58 UART1 Rx Line Status (RLS) 135 | // Transmit Holding Register Empty (THRE) 136 | // Rx Data Available (RDA) 137 | // Character Time-out Indicator (CTI) 138 | // Modem Control Change 139 | // End of Auto-Baud (ABEO) 140 | // Auto-Baud Time-Out (ABTO) 141 | UART2_IRQHandler, // 7 23 0x5C UART 2 Rx Line Status (RLS) 142 | // Transmit Holding Register Empty (THRE) 143 | // Rx Data Available (RDA) 144 | // Character Time-out Indicator (CTI) 145 | // End of Auto-Baud (ABEO) 146 | // Auto-Baud Time-Out (ABTO) 147 | UART3_IRQHandler, // 8 24 0x60 UART 3 Rx Line Status (RLS) 148 | // Transmit Holding Register Empty (THRE) 149 | // Rx Data Available (RDA) 150 | // Character Time-out Indicator (CTI) 151 | // End of Auto-Baud (ABEO) 152 | // Auto-Baud Time-Out (ABTO) 153 | PWM1_IRQHandler, // 9 25 0x64 PWM1 Match 0 - 6 of PWM1 154 | // Capture 0-1 of PWM1 155 | I2C0_IRQHandler, // 10 26 0x68 I2C0 SI (state change) 156 | I2C1_IRQHandler, // 11 27 0x6C I2C1 SI (state change) 157 | I2C2_IRQHandler, // 12 28 0x70 I2C2 SI (state change) 158 | SPI_IRQHandler, // 13 29 0x74 SPI SPI Interrupt Flag (SPIF) 159 | // Mode Fault (MODF) 160 | SSP0_IRQHandler, // 14 30 0x78 SSP0 Tx FIFO half empty of SSP0 161 | // Rx FIFO half full of SSP0 162 | // Rx Timeout of SSP0 163 | // Rx Overrun of SSP0 164 | SSP1_IRQHandler, // 15 31 0x7C SSP 1 Tx FIFO half empty 165 | // Rx FIFO half full 166 | // Rx Timeout 167 | // Rx Overrun 168 | PLL0_IRQHandler, // 16 32 0x80 PLL0 (Main PLL) PLL0 Lock (PLOCK0) 169 | RTC_IRQHandler, // 17 33 0x84 RTC Counter Increment (RTCCIF) 170 | // Alarm (RTCALF) 171 | EINT0_IRQHandler, // 18 34 0x88 External Interrupt External Interrupt 0 (EINT0) 172 | EINT1_IRQHandler, // 19 35 0x8C External Interrupt External Interrupt 1 (EINT1) 173 | EINT2_IRQHandler, // 20 36 0x90 External Interrupt External Interrupt 2 (EINT2) 174 | EINT3_IRQHandler, // 21 37 0x94 External Interrupt External Interrupt 3 (EINT3). 175 | // Note: EINT3 channel is shared with GPIO interrupts 176 | ADC_IRQHandler, // 22 38 0x98 ADC A/D Converter end of conversion 177 | BOD_IRQHandler, // 23 39 0x9C BOD Brown Out detect 178 | USB_IRQHandler, // 24 40 0xA0 USB USB_INT_REQ_LP, USB_INT_REQ_HP, USB_INT_REQ_DMA 179 | CAN_IRQHandler, // 25 41 0xA4 CAN CAN Common, CAN 0 Tx, CAN 0 Rx, CAN 1 Tx, CAN 1 Rx 180 | DMA_IRQHandler, // 26 42 0xA8 GPDMA IntStatus of DMA channel 0, IntStatus of DMA channel 1 181 | I2S_IRQHandler, // 27 43 0xAC I2S irq, dmareq1, dmareq2 182 | ENET_IRQHandler, // 28 44 0xB0 Ethernet WakeupInt, SoftInt, TxDoneInt, TxFinishedInt, TxErrorInt, 183 | // TxUnderrunInt, RxDoneInt, RxFinishedInt, RxErrorInt, RxOverrunInt. 184 | RIT_IRQHandler, // 29 45 0xB4 Repetitive Interrupt Timer (RITINT) 185 | MCPWM_IRQHandler, // 30 46 0xB8 Motor Control PWM IPER[2:0], IPW[2:0], ICAP[2:0], FES 186 | QEI_IRQHandler, // 31 47 0xBC Quadrature Encoder INX_Int, TIM_Int, VELC_Int, DIR_Int, ERR_Int, ENCLK_Int, 187 | // POS0_Int, POS1_Int, POS2_Int, REV_Int, POS0REV_Int, POS1REV_Int, POS2REV_Int 188 | PLL1_IRQHandler, // 32 48 0xC0 PLL1 (USB PLL) PLL1 Lock (PLOCK1) 189 | USBActivity_IRQHandler, // 33 49 0xC4 USB Activity Interrupt USB_NEED_CLK 190 | CANActivity_IRQHandler, // 34 50 0xC8 CAN Activity Interrupt CAN1WAKE, CAN2WAKE 191 | }; 192 | 193 | void Reset_Handler(void) { 194 | SystemInit(); 195 | // SystemInit clears the Vector Table Offset Register (VTOR) back to 0. If 196 | // we're running bare metal, the VTOR should be 0. If we're running behind the 197 | // USB bootloader, however, the interrupt vectors are not at to top of flash 198 | // anymore. We set the VTOR in the bootloader, but since we need to run 199 | // SystemInit here to power up the peripherals and clock, we have to re-set it 200 | // to the address of interrupt_vectors. 201 | SCB->VTOR = (uint32_t) interrupt_vectors; 202 | 203 | uint32_t *s, *d; 204 | // Copy initialization data to RAM (.data section) 205 | s = &__etext; 206 | d = &__data_start__; 207 | while (d < &__data_end__) *d++ = *s++; 208 | // Zero the remaining allocated RAM (.bss section) 209 | d = &__bss_start__; 210 | while (d < &__bss_end__) *d++ = 0; 211 | 212 | // Everything is ready. Run the user program. 213 | main(); 214 | while(1); // in case main() fails 215 | } 216 | -------------------------------------------------------------------------------- /script/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | CYGWIN_PACKAGES="git, curl, libsasl2, ca-certificates, make, gcc4, patchutils" 6 | 7 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 8 | pushd $DIR/.. 9 | 10 | KERNEL=`uname` 11 | if [ ${KERNEL:0:7} == "MINGW32" ]; then 12 | OS="windows" 13 | elif [ ${KERNEL:0:6} == "CYGWIN" ]; then 14 | OS="cygwin" 15 | elif [ $KERNEL == "Darwin" ]; then 16 | OS="mac" 17 | else 18 | OS="linux" 19 | if ! command -v lsb_release >/dev/null 2>&1; then 20 | # Arch Linux 21 | if command -v pacman>/dev/null 2>&1; then 22 | sudo pacman -S lsb-release 23 | fi 24 | fi 25 | 26 | DISTRO=`lsb_release -si` 27 | fi 28 | 29 | _cygwin_error() { 30 | echo 31 | echo "${bldred}Missing \"$1\"${txtrst} - run the Cygwin installer again and select the base package set:" 32 | echo " $CYGWIN_PACKAGES" 33 | echo "After installing the packages, re-run this bootstrap script." 34 | die 35 | } 36 | 37 | if [ $OS == "cygwin" ] && ! command -v tput >/dev/null 2>&1; then 38 | _cygwin_error "ncurses" 39 | fi 40 | 41 | txtrst=$(tput sgr0) # reset 42 | bldred=${txtbld}$(tput setaf 1) 43 | bldgreen=${txtbld}$(tput setaf 2) 44 | 45 | die() { 46 | echo >&2 "${bldred}$@${txtrst}" 47 | exit 1 48 | } 49 | 50 | _pushd() { 51 | pushd $1 > /dev/null 52 | } 53 | 54 | _popd() { 55 | popd > /dev/null 56 | } 57 | 58 | _wait() { 59 | if [ -z $CI ]; then 60 | echo "Press Enter when done" 61 | read 62 | fi 63 | } 64 | 65 | _install() { 66 | if [ $OS == "cygwin" ]; then 67 | _cygwin_error $1 68 | elif [ $OS == "mac" ]; then 69 | # brew exists with 1 if it's already installed 70 | set +e 71 | brew install $1 72 | set -e 73 | else 74 | if ! command -v lsb_release >/dev/null 2>&1; then 75 | echo 76 | echo "Missing $1 - install it using your distro's package manager or build from source" 77 | _wait 78 | else 79 | if [ $DISTRO == "arch" ]; then 80 | sudo pacman -S $1 81 | elif [ $DISTRO == "Ubuntu" ]; then 82 | sudo apt-get update -qq 83 | sudo apt-get install $1 -y 84 | else 85 | echo 86 | echo "Missing $1 - install it using your distro's package manager or build from source" 87 | _wait 88 | fi 89 | fi 90 | fi 91 | } 92 | 93 | 94 | download() { 95 | url=$1 96 | filename=$2 97 | curl $url -L -o $filename 98 | } 99 | 100 | if [ `id -u` == 0 ]; then 101 | die "Error: running as root - don't use 'sudo' with this script" 102 | fi 103 | 104 | if ! command -v curl >/dev/null 2>&1; then 105 | if [ $OS == "cygwin" ]; then 106 | _cygwin_error "curl" 107 | else 108 | _install curl 109 | fi 110 | fi 111 | 112 | echo "Storing all downloaded dependencies in the \"dependencies\" folder" 113 | 114 | DEPENDENCIES_FOLDER="dependencies" 115 | mkdir -p $DEPENDENCIES_FOLDER 116 | 117 | if [ $OS == "windows" ]; then 118 | die "Sorry, the bootstrap script for compiling from source doesn't support the Windows console - try Cygwin." 119 | fi 120 | 121 | if [ $OS == "mac" ] && ! command -v brew >/dev/null 2>&1; then 122 | echo "Installing Homebrew..." 123 | ruby -e "$(curl -fsSkL raw.github.com/mxcl/homebrew/go)" 124 | fi 125 | 126 | if ! command -v make >/dev/null 2>&1; then 127 | if [ $OS == "cygwin" ]; then 128 | _cygwin_error "make" 129 | elif [ $OS == "mac" ]; then 130 | echo "Missing 'make' - install the Xcode CLI tools" 131 | die 132 | else 133 | if [ $DISTRO == "arch" ]; then 134 | sudo pacman -S base-devel 135 | elif [ $DISTRO == "Ubuntu" ]; then 136 | sudo apt-get update -qq 137 | sudo apt-get install build-essential -y 138 | fi 139 | fi 140 | fi 141 | 142 | if ! command -v git >/dev/null 2>&1; then 143 | if [ $OS == "cygwin" ]; then 144 | _cygwin_error "git" 145 | elif [ $OS == "mac" ]; then 146 | _install git 147 | fi 148 | fi 149 | 150 | echo "Updating Git submodules..." 151 | 152 | # git submodule update is a shell script and expects some lines to fail 153 | set +e 154 | if ! git submodule update --init --quiet; then 155 | echo "Unable to update git submodules - try running \"git submodule update\" to see the full error" 156 | echo "If git complains that it \"Needed a single revision\", run \"rm -rf src/CDL src/lpcusb\" and then try the bootstrap script again" 157 | if [ $OS == "cygwin" ]; then 158 | echo "In Cygwin this may be true (ignore if you know ca-certifications is installed:" 159 | _cygwin_error "ca-certificates" 160 | fi 161 | die 162 | fi 163 | set -e 164 | 165 | # ARM / LPC17XX Dependencies 166 | 167 | if true || ! command -v arm-none-eabi-gcc >/dev/null 2>&1; then 168 | 169 | echo "Installing GCC for ARM Embedded..." 170 | 171 | GCC_ARM_BASENAME="gcc-arm-none-eabi-4_7-2012q4-20121208" 172 | if [ $OS == "linux" ]; then 173 | GCC_ARM_FILE="$GCC_ARM_BASENAME-linux.tar.bz2" 174 | elif [ $OS == "mac" ]; then 175 | GCC_ARM_FILE="$GCC_ARM_BASENAME-mac.tar.bz2" 176 | elif [ $OS == "cygwin" ]; then 177 | GCC_ARM_FILE="$GCC_ARM_BASENAME-win32.exe" 178 | fi 179 | 180 | GCC_ARM_URL="https://launchpad.net/gcc-arm-embedded/4.7/4.7-2012-q4-major/+download/$GCC_ARM_FILE" 181 | GCC_ARM_DIR="gcc-arm-embedded" 182 | 183 | _pushd $DEPENDENCIES_FOLDER 184 | if ! test -e $GCC_ARM_FILE 185 | then 186 | download $GCC_ARM_URL $GCC_ARM_FILE 187 | fi 188 | 189 | mkdir -p $GCC_ARM_DIR 190 | _pushd $GCC_ARM_DIR 191 | if [ $OS == "cygwin" ]; then 192 | chmod a+x ../$GCC_ARM_FILE 193 | INSTALL_COMMAND="cygstart.exe ../$GCC_ARM_FILE" 194 | PROGRAM_FILES_BASE="/cygdrive/c/" 195 | PROGRAM_FILES="Program Files" 196 | PROGRAM_FILES_64="Program Files (x86)" 197 | TRAILING_DIRNAME="GNU Tools ARM Embedded/4.7 2012q4/" 198 | GCC_INNER_DIR="$PROGRAM_FILES_BASE/$PROGRAM_FILES_64/$TRAILING_DIRNAME" 199 | if ! test -d "$GCC_INNER_DIR"; then 200 | GCC_INNER_DIR="$PROGRAM_FILES_BASE/$PROGRAM_FILES/$TRAILING_DIRNAME" 201 | fi 202 | else 203 | GCC_INNER_DIR="gcc-arm-none-eabi-4_7-2012q4" 204 | INSTALL_COMMAND="tar -xjf ../$GCC_ARM_FILE" 205 | fi 206 | 207 | if ! test -d "$GCC_INNER_DIR" 208 | then 209 | $INSTALL_COMMAND 210 | if [ $OS == "cygwin" ]; then 211 | echo -n "Press Enter when the GCC for ARM Embedded installer is finished" 212 | read 213 | fi 214 | fi 215 | 216 | if [ $OS == "cygwin" ]; then 217 | GCC_INNER_DIR="$PROGRAM_FILES_BASE/$PROGRAM_FILES_64/$TRAILING_DIRNAME" 218 | if ! test -d "$GCC_INNER_DIR"; then 219 | GCC_INNER_DIR="$PROGRAM_FILES_BASE/$PROGRAM_FILES/$TRAILING_DIRNAME" 220 | if ! test -d "$GCC_INNER_DIR"; then 221 | die "GCC for ARM isn't installed in the expected location." 222 | fi 223 | fi 224 | fi 225 | 226 | if ! test -d arm-none-eabi; then 227 | echo "Copying GCC binaries to local dependencies folder..." 228 | cp -R "$GCC_INNER_DIR"/* . 229 | fi 230 | 231 | _popd 232 | _popd 233 | 234 | fi 235 | 236 | if [ -z $CI ] && ! command -v openocd >/dev/null 2>&1; then 237 | 238 | ## Download OpenOCD for flashing ARM via JTAG 239 | _pushd $DEPENDENCIES_FOLDER 240 | 241 | echo "Installing OpenOCD..." 242 | if [ $OS == "linux" ]; then 243 | _install "openocd" 244 | elif [ $OS == "mac" ]; then 245 | _install libftdi 246 | _install libusb 247 | set +e 248 | brew install --enable-ft2232_libftdi open-ocd 249 | set -e 250 | elif [ $OS == "cygwin" ]; then 251 | echo 252 | echo "Missing OpenOCD and it's not trivial to install in Windows - you won't be able to program the ARM platform (not required for the chipKIT translator)" 253 | fi 254 | _popd 255 | fi 256 | 257 | FTDI_USB_DRIVER_PLIST=/System/Library/Extensions/FTDIUSBSerialDriver.kext/Contents/Info.plist 258 | if [ -z $CI ] && [ $OS == "mac" ] && [ -e $FTDI_USB_DRIVER_PLIST ]; then 259 | if grep -q "Olimex OpenOCD JTAG A" $FTDI_USB_DRIVER_PLIST; then 260 | sudo sed -i "" -e "/Olimex OpenOCD JTAG A/{N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;d;}" $FTDI_USB_DRIVER_PLIST 261 | FTDI_USB_DRIVER_MODULE=/System/Library/Extensions/FTDIUSBSerialDriver.kext/ 262 | # Driver may not be loaded yet, but that's OK - don't exit on error. 263 | set +e 264 | sudo kextunload $FTDI_USB_DRIVER_MODULE 265 | set -e 266 | sudo kextload $FTDI_USB_DRIVER_MODULE 267 | fi 268 | fi 269 | 270 | if [ $OS == "cygwin" ] && ! command -v ld >/dev/null 2>&1; then 271 | _cygwin_error "gcc4" 272 | fi 273 | 274 | popd 275 | 276 | echo 277 | echo "${bldgreen}All developer dependencies installed, ready to compile.$txtrst" 278 | -------------------------------------------------------------------------------- /src/.gdbinit: -------------------------------------------------------------------------------- 1 | define hook-step 2 | mon cortex_m3 maskisr on 3 | end 4 | 5 | define hookpost-step 6 | mon cortex_m3 maskisr off 7 | end 8 | 9 | define hook-next 10 | mon cortex_m3 maskisr on 11 | end 12 | 13 | define hookpost-next 14 | mon cortex_m3 maskisr off 15 | end 16 | 17 | set remote hardware-breakpoint-limit 6 18 | set remote hardware-watchpoint-limit 4 19 | 20 | target remote localhost:3333 21 | 22 | echo .gdbinit for openlpc-bootloader has been executed \n 23 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | CMakeCache.txt 2 | CMakeFiles 3 | *.o 4 | *.map 5 | -------------------------------------------------------------------------------- /src/LPC1768.ld: -------------------------------------------------------------------------------- 1 | /* Linker script for mbed LPC1768 */ 2 | GROUP(-lstdc++ -lsupc++ -lm -lc -lnosys -lgcc) 3 | 4 | /* Linker script to configure memory regions. */ 5 | MEMORY 6 | { 7 | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K 8 | RAM (rwx) : ORIGIN = 0x100000C8, LENGTH = 0x7F38 9 | 10 | USB_RAM(rwx) : ORIGIN = 0x2007C000, LENGTH = 16K 11 | ETH_RAM(rwx) : ORIGIN = 0x20080000, LENGTH = 16K 12 | } 13 | 14 | /* Linker script to place sections and symbol values. Should be used together 15 | * with other linker script that defines memory regions FLASH and RAM. 16 | * It references following symbols, which must be defined in code: 17 | * Reset_Handler : Entry of reset handler 18 | * 19 | * It defines following symbols, which code can use without definition: 20 | * __exidx_start 21 | * __exidx_end 22 | * __etext 23 | * __data_start__ 24 | * __preinit_array_start 25 | * __preinit_array_end 26 | * __init_array_start 27 | * __init_array_end 28 | * __fini_array_start 29 | * __fini_array_end 30 | * __data_end__ 31 | * __bss_start__ 32 | * __bss_end__ 33 | * __end__ 34 | * end 35 | * __HeapLimit 36 | * __StackLimit 37 | * __StackTop 38 | * __stack 39 | */ 40 | ENTRY(Reset_Handler) 41 | 42 | SECTIONS 43 | { 44 | .text : 45 | { 46 | KEEP(*(.isr_vector)) 47 | *(.text*) 48 | 49 | KEEP(*(.init)) 50 | KEEP(*(.fini)) 51 | 52 | /* .ctors */ 53 | *crtbegin.o(.ctors) 54 | *crtbegin?.o(.ctors) 55 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 56 | *(SORT(.ctors.*)) 57 | *(.ctors) 58 | 59 | /* .dtors */ 60 | *crtbegin.o(.dtors) 61 | *crtbegin?.o(.dtors) 62 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 63 | *(SORT(.dtors.*)) 64 | *(.dtors) 65 | 66 | *(.rodata*) 67 | 68 | KEEP(*(.eh_frame*)) 69 | } > FLASH 70 | 71 | .ARM.extab : 72 | { 73 | *(.ARM.extab* .gnu.linkonce.armextab.*) 74 | } > FLASH 75 | 76 | __exidx_start = .; 77 | .ARM.exidx : 78 | { 79 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 80 | } > FLASH 81 | __exidx_end = .; 82 | 83 | __etext = .; 84 | 85 | .data : AT (__etext) 86 | { 87 | __data_start__ = .; 88 | *(vtable) 89 | *(.data*) 90 | 91 | . = ALIGN(4); 92 | /* preinit data */ 93 | PROVIDE (__preinit_array_start = .); 94 | KEEP(*(.preinit_array)) 95 | PROVIDE (__preinit_array_end = .); 96 | 97 | . = ALIGN(4); 98 | /* init data */ 99 | PROVIDE (__init_array_start = .); 100 | KEEP(*(SORT(.init_array.*))) 101 | KEEP(*(.init_array)) 102 | PROVIDE (__init_array_end = .); 103 | 104 | 105 | . = ALIGN(4); 106 | /* finit data */ 107 | PROVIDE (__fini_array_start = .); 108 | KEEP(*(SORT(.fini_array.*))) 109 | KEEP(*(.fini_array)) 110 | PROVIDE (__fini_array_end = .); 111 | 112 | . = ALIGN(4); 113 | /* All data end */ 114 | __data_end__ = .; 115 | 116 | } > RAM 117 | 118 | .bss : 119 | { 120 | __bss_start__ = .; 121 | *(.bss*) 122 | *(COMMON) 123 | __bss_end__ = .; 124 | } > RAM 125 | 126 | .heap : 127 | { 128 | __end__ = .; 129 | end = __end__; 130 | *(.heap*) 131 | __HeapLimit = .; 132 | } > RAM 133 | 134 | /* .stack_dummy section doesn't contains any symbols. It is only 135 | * used for linker to calculate size of stack sections, and assign 136 | * values to stack symbols later */ 137 | .stack_dummy : 138 | { 139 | *(.stack) 140 | } > RAM 141 | 142 | /* Set stack top to end of RAM, and stack limit move down by 143 | * size of stack_dummy section */ 144 | __StackTop = ORIGIN(RAM) + LENGTH(RAM); 145 | __StackLimit = __StackTop - SIZEOF(.stack_dummy); 146 | PROVIDE(__stack = __StackTop); 147 | 148 | /* Check if data + heap + stack exceeds RAM limit */ 149 | ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") 150 | } 151 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | GCC_ARM_ON_PATH = $(shell command -v arm-none-eabi-gcc >/dev/null; echo $$?) 2 | 3 | GREEN="$${txtbld}$$(tput setaf 2)" 4 | RED="$${txtbld}$$(tput setaf 1)" 5 | COLOR_RESET=$$(tput sgr0) 6 | 7 | GCC_BIN = 8 | ifneq ($(GCC_ARM_ON_PATH),0) 9 | GCC_BIN = ../dependencies/gcc-arm-embedded/bin/ 10 | endif 11 | 12 | ifndef JTAG_INTERFACE 13 | JTAG_INTERFACE = olimex-arm-usb-ocd-custom 14 | endif 15 | 16 | OPENOCD_CONF_BASE = ../conf/openocd 17 | PROJECT = bootloader 18 | CMSIS_PATH = ./CDL/CMSISv2p00_LPC17xx 19 | DRIVER_PATH = ./CDL/LPC17xxLib 20 | INCLUDE_PATHS = -I. -I./lpcusb/target -I./lpcusb/target/examples \ 21 | -I$(DRIVER_PATH)/inc -I$(CMSIS_PATH)/inc 22 | LINKER_SCRIPT = LPC1768.ld 23 | 24 | LOCAL_C_SRCS = $(CMSIS_PATH)/src/core_cm3.c $(CMSIS_PATH)/src/system_LPC17xx.c \ 25 | $(wildcard $(CMSIS_PATH)/source/*.c) $(wildcard *.c) \ 26 | $(wildcard $(DRIVER_PATH)/src/*.c) \ 27 | $(wildcard lpcusb/target/*.c) \ 28 | lpcusb/target/examples/msc_bot.c 29 | OBJECTS = $(LOCAL_C_SRCS:.c=.o) 30 | 31 | ############################################################################### 32 | CC = $(GCC_BIN)arm-none-eabi-gcc 33 | CPP = $(GCC_BIN)arm-none-eabi-g++ 34 | CC_FLAGS = -c -fno-common -fmessage-length=0 -Wall -fno-exceptions -mcpu=cortex-m3 -mthumb -ffunction-sections -fdata-sections 35 | ONLY_C_FLAGS = -std=gnu99 36 | ONLY_CPP_FLAGS = -std=gnu++98 37 | CC_SYMBOLS = -DTARGET_LPC1768 -DTOOLCHAIN_GCC_ARM \ 38 | -DUSB_DEVICE_ONLY -DLPC17xx -D__LPC17XX__ -DBOARD=9 39 | 40 | 41 | AS = $(GCC_BIN)arm-none-eabi-as 42 | 43 | LD = $(GCC_BIN)arm-none-eabi-gcc 44 | LD_FLAGS = -mcpu=cortex-m3 -mthumb -Wl,--gc-sections,-Map=$(PROJECT).map 45 | LD_SYS_LIBS = -lstdc++ -lsupc++ -lm -lc -lgcc 46 | 47 | ifdef DEBUG 48 | CC_FLAGS += -g -ggdb 49 | CC_SYMBOLS += -D__DEBUG__ 50 | else 51 | CC_FLAGS += -Os 52 | CC_SYMBOLS += -DNDEBUG 53 | endif 54 | 55 | OBJCOPY = $(GCC_BIN)arm-none-eabi-objcopy 56 | 57 | all: $(PROJECT).bin 58 | 59 | clean: 60 | rm -f $(PROJECT).bin $(PROJECT).elf $(OBJECTS) *.o *.map 61 | 62 | .s.o: 63 | $(AS) $(CC_FLAGS) $(CC_SYMBOLS) -o $@ $< 64 | 65 | .c.o: 66 | $(CC) $(CC_FLAGS) $(CC_SYMBOLS) $(ONLY_C_FLAGS) $(INCLUDE_PATHS) -o $@ $< 67 | 68 | .cpp.o: 69 | $(CPP) $(CC_FLAGS) $(CC_SYMBOLS) $(ONLY_CPP_FLAGS) $(INCLUDE_PATHS) -o $@ $< 70 | 71 | 72 | $(PROJECT).elf: $(OBJECTS) 73 | $(LD) $(LD_FLAGS) -T$(LINKER_SCRIPT) -o $@ $^ $(LD_SYS_LIBS) 74 | 75 | $(PROJECT).bin: $(PROJECT).elf 76 | $(OBJCOPY) -O binary $< $@ 77 | 78 | flash: all 79 | @echo "Flashing bootloader via JTAG with OpenOCD..." 80 | @(openocd -s $(OPENOCD_CONF_BASE) -f interface/$(JTAG_INTERFACE).cfg -f flash.cfg && echo "$(GREEN)Flashed bootloader successfully.$(COLOR_RESET)") || echo "$(RED)Flashing bootloader failed.$(COLOR_RESET)" 81 | 82 | 83 | gdb: all 84 | @openocd -f $(OPENOCD_CONF_BASE)/gdb.cfg 85 | -------------------------------------------------------------------------------- /src/blockdev_flash.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "sbl_config.h" 4 | #include "sbl_iap.h" 5 | #include "type.h" 6 | #include "disk.h" 7 | #include "log.h" 8 | 9 | #include 10 | 11 | #define BLOCKSIZE 512 12 | 13 | extern bool user_flash_erased; // from main.c 14 | 15 | static int FORCE_FIRST_CLUSTER_WORKAROUND_OFFSET = 0; 16 | unsigned block_written_map[1024]; 17 | 18 | int BlockDevGetSize(uint32_t *pdwDriveSize) { 19 | *pdwDriveSize = (512 * 1024)- sector_start_map[USER_START_SECTOR]; 20 | return 0; 21 | } 22 | 23 | int BlockDevWrite(uint32_t dwAddress, uint8_t * pbBuf) { 24 | uint32_t offset = 512 * dwAddress; 25 | // first four bytes are reserved 26 | if(offset < BOOT_SECT_SIZE) { 27 | debug("Disallowing write to the boot sector"); 28 | } else if(offset < BOOT_SECT_SIZE + FAT_SIZE) { 29 | debug("Modifying the FAT itself"); 30 | for(uint32_t i = 0; i < BLOCKSIZE; i++) { 31 | FAT[(offset + i) - BOOT_SECT_SIZE] = pbBuf[i]; 32 | } 33 | } else if(offset < BOOT_SECT_SIZE + FAT_SIZE + ROOT_DIR_SIZE) { 34 | debug("Modifying directory entry %d", ((BOOT_SECT_SIZE + FAT_SIZE + 35 | ROOT_DIR_SIZE) - offset) % DIRECTORY_ENTRY_SIZE); 36 | 37 | for(uint32_t i = 0; i < DIRECTORY_ENTRY_SIZE; i++) { 38 | ((uint8_t*)&DIRECTORY_ENTRIES)[(offset + i) - BOOT_SECT_SIZE - 39 | FAT_SIZE] = pbBuf[i]; 40 | } 41 | 42 | for(int i = 0; i < MAX_ROOT_DIR_ENTRIES; i++) { 43 | FatDirectoryEntry_t* directory_entry = &DIRECTORY_ENTRIES[i]; 44 | 45 | // a file is "deleted" when the first byte of the directory entry is 46 | // marked 0xe5 47 | if(directory_entry->filename[0] == 0xe5 && 48 | !strncmp(&(directory_entry->filename[1]), "IRMWARE", 7) && 49 | !user_flash_erased) { 50 | // Delete user flash when firmware.bin is erased 51 | erase_user_flash(); 52 | user_flash_erased = true; 53 | } 54 | 55 | if(directory_entry->first_cluster_low_16 == 3) { 56 | // If we adjust the starting cluster of a firmware write from 3 57 | // to 2, actually update it in the directory entry so if the 58 | // host reads it back later on, it doesn't think cluster 2 is 59 | // still free (and ripe for a stupid hidden file). 60 | debug("Fudging the first cluster for %s", 61 | directory_entry->filename) 62 | directory_entry->first_cluster_low_16 = 2; 63 | } 64 | 65 | if(directory_entry->filename[0] == NULL || directory_entry->filename[0] == 0xe5) { 66 | continue; 67 | } else if(directory_entry->attributes == 0xf) { 68 | debug("Found a VFAT long file name entry..."); 69 | for(int j = 0; j < DIRECTORY_ENTRY_SIZE; j++) { 70 | debug_no_newline("%02x ", ((uint8_t*)directory_entry)[j]); 71 | } 72 | debug(""); 73 | continue; 74 | } 75 | debug("filename: %s, attributes: 0x%x, first cluster: %d, size: %d", 76 | directory_entry->filename, 77 | directory_entry->attributes, 78 | directory_entry->first_cluster_low_16, 79 | directory_entry->filesize); 80 | } 81 | } else { 82 | // Some OSs (e.g. Linux and OS X) start writing the file from the 2nd 83 | // cluster instead of the first. Normally that's fine since they just 84 | // write the correct starting cluster number into the FAT entry - 85 | // however since our FAT entries are transient and aren't actually read 86 | // when the bootloader starts up (they're stored in RAM anyway), the 87 | // bootloader just assumes the host wrote the firmware starting from 88 | // cluster 2 - using 'cp' in Linux it'll start it at 3, however. This 89 | // workaround detects if the first write from the host is coming in at 90 | // the 3rd cluster and sets an offset for all of the remaining writes. 91 | // This makes the assumption that writes will come in sequentially, 92 | // which so far when using 'cp' or the file browser has been true. A 93 | // more proper way to fix this issue would be to actually store the FAT 94 | // directory entires in flash somewhere, read it when the bootloader 95 | // starts, and jump to the correct cluster number. 96 | if(offset == (0x8000 + BOOT_SECT_SIZE + FAT_SIZE + ROOT_DIR_SIZE)) { 97 | // If a small temp file has already been written starting at LBA 4 (right 98 | // where the firmware should start), we need to detect that and 99 | // allow re-writing those blocks with the actual firmware. 100 | // If any of the first 9 blocks aren't written when we get a write 101 | // request at the 3rd cluster (0x18000, meaning it's most likely the 102 | // firmware itself begin written from OS X or Linux), reset the 103 | // "written" status for all of the blocks and allow us to re-write 104 | // the first 8 blocks from 0x10000. 105 | bool bogus_file_up_front = false; 106 | for(int i = 0; i < 9; i++) { 107 | bogus_file_up_front = bogus_file_up_front || !block_written_map[i]; 108 | if(bogus_file_up_front) { 109 | break; 110 | } 111 | } 112 | 113 | if(!block_written_map[0] || bogus_file_up_front) { 114 | FORCE_FIRST_CLUSTER_WORKAROUND_OFFSET = -0x8000; 115 | debug("Detecting a firmware write not starting from first " 116 | "cluster - adjusting offset"); 117 | memset(block_written_map, 0, 1024); 118 | reset_sector_erasure_status(); 119 | } 120 | } 121 | 122 | offset += FORCE_FIRST_CLUSTER_WORKAROUND_OFFSET; 123 | 124 | if(offset < BOOT_SECT_SIZE + FAT_SIZE + ROOT_DIR_SIZE) { 125 | debug("Attempting to write at beginning of flash after fixing " 126 | "offset, bailing!"); 127 | return 0; 128 | } 129 | 130 | unsigned* flash_address = (unsigned *)((uint8_t*)USER_FLASH_START + 131 | (offset - (BOOT_SECT_SIZE + FAT_SIZE + ROOT_DIR_SIZE))); 132 | unsigned int block_array_index = ((unsigned)flash_address - 133 | 0x10000) / BLOCKSIZE; 134 | if(block_array_index > 1024) { 135 | } else if(block_written_map[block_array_index]) { 136 | debug("Address 0x%02x already written, blocking second write", 137 | (unsigned)flash_address); 138 | } else { 139 | write_flash(flash_address, (char *)pbBuf, BLOCKSIZE); 140 | block_written_map[block_array_index] = true; 141 | } 142 | } 143 | return 0; 144 | } 145 | 146 | int BlockDevRead(uint32_t dwAddress, uint8_t * pbBuf) { 147 | uint32_t offset = 512 * dwAddress; 148 | uint8_t data; 149 | for(unsigned int i = 0; i < BLOCKSIZE; i++) { 150 | if(offset < BOOT_SECT_SIZE) { 151 | 152 | switch (offset) { 153 | case 19: 154 | data = (uint8_t)(MSC_BlockCount & 0xFF); 155 | break; 156 | case 20: 157 | data = (uint8_t)((MSC_BlockCount >> 8) & 0xFF); 158 | break; 159 | case 510: 160 | data = 0x55; 161 | break; 162 | case 511: 163 | data = 0xAA; 164 | break; 165 | default: 166 | if(offset > 29 ) { 167 | data = 0x0; 168 | } else { 169 | data = ((char*)&BOOT_SECTOR)[offset]; 170 | } 171 | break; 172 | } 173 | 174 | } else if(offset < BOOT_SECT_SIZE + FAT_SIZE) { 175 | data = FAT[offset - BOOT_SECT_SIZE]; 176 | } else if(offset < BOOT_SECT_SIZE + FAT_SIZE + ROOT_DIR_SIZE) { 177 | uint32_t directory_offset = offset - BOOT_SECT_SIZE - FAT_SIZE; 178 | if(directory_offset > (ROOT_DIR_ENTRIES * DIRECTORY_ENTRY_SIZE)) { 179 | data = 0; 180 | } else { 181 | data = ((uint8_t*)&DIRECTORY_ENTRIES)[directory_offset]; 182 | } 183 | } else { 184 | data = *((uint8_t*)USER_FLASH_START + (offset - (BOOT_SECT_SIZE + 185 | FAT_SIZE + ROOT_DIR_SIZE))); 186 | } 187 | 188 | pbBuf[i] = data; 189 | offset++; 190 | } 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /src/disk.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Software that is described herein is for illustrative purposes only 3 | // which provides customers with programming information regarding the 4 | // products. This software is supplied "AS IS" without any warranties. 5 | // NXP Semiconductors assumes no responsibility or liability for the 6 | // use of the software, conveys no license or title under any patent, 7 | // copyright, or mask work right to the product. NXP Semiconductors 8 | // reserves the right to make changes in the software without 9 | // notification. NXP Semiconductors also make no representation or 10 | // warranty that such application will be suitable for the specified 11 | // use without further testing or modification. 12 | //----------------------------------------------------------------------------- 13 | 14 | #ifndef __DISK_H__ 15 | #define __DISK_H__ 16 | 17 | #include "type.h" 18 | #include 19 | 20 | #define MSC_MemorySize ( BOOT_SECT_SIZE + FAT_SIZE + ROOT_DIR_SIZE + USER_FLASH_SIZE ) 21 | #define MSC_BlockSize 512 22 | #define MSC_BlockCount (MSC_MemorySize / MSC_BlockSize) 23 | 24 | #define MAX_ROOT_DIR_ENTRIES 16 25 | #define ROOT_DIR_ENTRIES 2 26 | #define BOOT_SECT_SIZE MSC_BlockSize 27 | #define ROOT_DIR_SIZE MSC_BlockSize 28 | #define FAT_SIZE (MSC_BlockSize * 2) 29 | 30 | #define BLOCKS_PER_CLUSTER 64 31 | #define NO_OF_CLUSTERS (MSC_BlockCount/BLOCKS_PER_CLUSTER) 32 | 33 | #define DIRECTORY_ENTRY_SIZE 32 34 | 35 | typedef struct FatBootSector { 36 | uint8_t bootjmp[3]; 37 | uint8_t oem_name[8]; 38 | uint16_t bytes_per_sector; 39 | uint8_t sectors_per_cluster; 40 | uint16_t reserved_sector_count; 41 | uint8_t table_count; 42 | uint16_t root_entry_count; 43 | uint16_t total_sectors_16; 44 | uint8_t media_type; 45 | uint16_t table_size_16; 46 | uint16_t sectors_per_track; 47 | uint16_t head_side_count; 48 | uint32_t hidden_sector_count; 49 | uint32_t total_sectors_32; 50 | 51 | //this will be cast to it's specific type once the driver actually knows what type of FAT this is. 52 | uint8_t extended_section[54]; 53 | 54 | } __attribute__((packed)) FatBootSector_t; 55 | 56 | typedef struct FatDirectoryEntry { 57 | uint8_t filename[11]; 58 | uint8_t attributes; 59 | uint8_t reserved; 60 | uint8_t creation_time_ms; 61 | uint16_t creation_time; 62 | uint16_t creation_date; 63 | uint16_t accessed_date; 64 | uint16_t first_cluster_high_16; 65 | uint16_t modification_time; 66 | uint16_t modification_date; 67 | uint16_t first_cluster_low_16; 68 | uint32_t filesize; 69 | } __attribute__((packed)) FatDirectoryEntry_t; 70 | 71 | /* RAM to store the file allocation table */ 72 | extern uint8_t FAT[FAT_SIZE]; 73 | 74 | /* FAT12 Root directory entries */ 75 | extern FatDirectoryEntry_t DIRECTORY_ENTRIES[ROOT_DIR_ENTRIES]; 76 | 77 | extern const FatBootSector_t BOOT_SECTOR; 78 | 79 | #endif /* __DISK_H__ */ 80 | -------------------------------------------------------------------------------- /src/diskimage.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Software that is described herein is for illustrative purposes only 3 | // which provides customers with programming information regarding the 4 | // products. This software is supplied "AS IS" without any warranties. 5 | // NXP Semiconductors assumes no responsibility or liability for the 6 | // use of the software, conveys no license or title under any patent, 7 | // copyright, or mask work right to the product. NXP Semiconductors 8 | // reserves the right to make changes in the software without 9 | // notification. NXP Semiconductors also make no representation or 10 | // warranty that such application will be suitable for the specified 11 | // use without further testing or modification. 12 | //----------------------------------------------------------------------------- 13 | 14 | #include "disk.h" 15 | 16 | const FatBootSector_t BOOT_SECTOR = { 17 | {0xEB, 0x3C, 0x90}, 18 | {0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30}, 19 | MSC_BlockSize, 20 | BLOCKS_PER_CLUSTER, 21 | 1, 22 | 1, 23 | 16, 24 | // this is the block count which can only be known at runtime if we want to 25 | // keep things flexible - it's maximized here but will be smaller when 26 | // handled in BlockDevRead 27 | 0x03EC, 28 | 0xF8, 29 | 2, 30 | 1, 31 | 1 32 | }; 33 | 34 | FatDirectoryEntry_t DIRECTORY_ENTRIES[ROOT_DIR_ENTRIES] = { 35 | { {'L', 'P', 'C', '1', '7', '5', '9',' ', ' ', ' ', ' '}, 36 | // file attributes 37 | 0x28 38 | }, 39 | { 40 | // 8.3 file name 41 | {'F', 'I', 'R', 'M', 'W', 'A', 'R', 'E', 'B', 'I', 'N'}, 42 | // file attributes 43 | 0x20, 44 | // reserved for Windows NT 45 | 0x18, 46 | // creation time in tenths of a second 47 | 0xbc, 48 | // time of file creation 49 | 0x9741, 50 | // date of file creation 51 | 0x3837, 52 | // last accessed date 53 | 0x3837, 54 | // high 16 bits of the first cluster number (always 0 for FAT12) 55 | 0, 56 | // last modification time 57 | 0x6e3d, 58 | // last modification date 59 | 0x382b, 60 | // low 16 bits of the cluster number 61 | 2, 62 | // file size in bytes 63 | 0x7D000 64 | } 65 | }; 66 | 67 | uint8_t FAT[FAT_SIZE]; 68 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "debug_frmwrk.h" 7 | 8 | const int MAX_LOG_LINE_LENGTH = 120; 9 | 10 | void debug_no_newline(const char* format, ...) { 11 | #ifdef __DEBUG__ 12 | va_list args; 13 | va_start(args, format); 14 | char buffer[MAX_LOG_LINE_LENGTH]; 15 | vsnprintf(buffer, MAX_LOG_LINE_LENGTH, format, args); 16 | 17 | _printf(buffer); 18 | va_end(args); 19 | #endif // __DEBUG__ 20 | } 21 | 22 | void initialize_logging() { 23 | debug_frmwrk_init(); 24 | } 25 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOG_H_ 2 | #define _LOG_H_ 3 | 4 | /* Public: Construct a string for the given format and args and output it on 5 | * whatever debug interface the current platform is using. This function 6 | * could be implemented in multiple ways - UART, regular printf, etc. The 7 | * actual effect depends on the platform. 8 | * 9 | * This has to be a macro because we can't unpack va_list args twice (e.g. 10 | * once in debug() and again in debug_no_newline(). An alternative would be 11 | * to duplicate code in debug() and debug_no_newline(). 12 | * 13 | * format - A printf-style format string. 14 | * args - printf-style arguments that match the format string. 15 | */ 16 | #define debug(...) debug_no_newline(__VA_ARGS__); debug_no_newline("\r\n"); 17 | 18 | extern const int MAX_LOG_LINE_LENGTH; 19 | 20 | /* Public: Initialize the debug logging framework. This function must be called 21 | * before using debug(). 22 | */ 23 | void initialize_logging(); 24 | 25 | /* Public: Like debug() but doesn't add a newline to the end of the message. 26 | */ 27 | void debug_no_newline(const char* format, ...); 28 | 29 | #endif // _LOG_H_ 30 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "disk.h" 4 | #include "sbl_iap.h" 5 | #include "sbl_config.h" 6 | 7 | #include "LPC17xx.h" 8 | 9 | bool user_flash_erased; 10 | 11 | // USB mass storage driver - in msc_usb_start.c 12 | void usb_msc_start(void); 13 | 14 | /***************************************************************************** 15 | * enter_usb_isp() is the routine called if the bootloader determines that the 16 | * USB interface needs starting to allow the user to upload a new application 17 | * into the LPC1768's flash memory 18 | *****************************************************************************/ 19 | void enter_usb_isp(void) { 20 | user_flash_erased = false; 21 | 22 | // Generate File Allocation Table to save Flash space 23 | // First Two FAT entries are reserved 24 | FAT[0] = 0xF8; 25 | FAT[1] = 0xFF; 26 | FAT[2] = 0xFF; 27 | /* Start cluster of a file is indicated by the Directory entry = 2 */ 28 | uint32_t m = 3; 29 | uint32_t next_cluster; 30 | for(uint32_t n = 3; n < NO_OF_CLUSTERS + 2; n += 2) { 31 | if(n == (NO_OF_CLUSTERS + 2) - 1) { 32 | next_cluster = 0xFFF; 33 | } else { 34 | next_cluster = n + 1; 35 | } 36 | FAT[m] = (uint8_t)n & 0xFF; 37 | FAT[m + 1] = (((uint8_t)next_cluster & 0xF) << 4) | ((uint8_t)(n>>8)&0xF); 38 | FAT[m + 2] = (uint8_t)(next_cluster >> 4) & 0xFF; 39 | m += 3; 40 | } 41 | 42 | /* Correct file size entry for file firmware.bin since user flash size isn't 43 | * know until runtime. 44 | */ 45 | DIRECTORY_ENTRIES[1].filesize = USER_FLASH_SIZE; 46 | 47 | // Start up LPCUSB mass storage system to allow user to copy 48 | // their application binary to the LPC1768's flash. 49 | usb_msc_start (); 50 | 51 | // Note - should never actually return from usb_msc_start (). 52 | } 53 | 54 | /********************************* 55 | * Main entry point for bootloader 56 | *********************************/ 57 | 58 | int main (void) { 59 | initialize_logging(); 60 | // Check to see if there is a user application in the LPC1768's flash memory. 61 | if(user_code_present()) { 62 | // There is an application, but need to check if user is pressing the button 63 | // to indicate they want to upload a new application. 64 | check_isp_entry_pin(); 65 | } 66 | 67 | // User code not present or isp entry requested 68 | enter_usb_isp(); 69 | 70 | // Note - should never actually return from enter_usb_isp (). 71 | while (1); // loop forever 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /src/msc_scsi.c: -------------------------------------------------------------------------------- 1 | /* 2 | LPCUSB, an USB device driver for LPC microcontrollers 3 | Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. The name of the author may not be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /** 29 | @file 30 | 31 | This is the SCSI layer of the USB mass storage application example. 32 | This layer depends directly on the blockdev layer. 33 | 34 | Windows peculiarities: 35 | * Size of REQUEST SENSE CDB is 12 bytes instead of expected 6 36 | * Windows requires VERIFY(10) command to do a format. 37 | This command is not mandatory in the SBC/SBC-2 specification. 38 | */ 39 | 40 | /********************************************************************* 41 | * Code Red Technologies - modification of LPCUSB mass storage example 42 | * to provide a flash-based USB secondary bootloader for RDB1768 43 | * development board fitted with NXP LPC1768 MCU. 44 | *********************************************************************/ 45 | 46 | #include 47 | 48 | #include "type.h" 49 | #include "log.h" 50 | 51 | #include "blockdev.h" 52 | #include "msc_scsi.h" 53 | #include "disk.h" 54 | 55 | #ifndef MIN 56 | #define MIN(a,b) ((a)<(b)?(a):(b)) 57 | #endif 58 | 59 | #define BLOCKSIZE 512 60 | 61 | // SBC2 mandatory SCSI commands 62 | #define SCSI_CMD_TEST_UNIT_READY 0x00 63 | #define SCSI_CMD_REQUEST_SENSE 0x03 64 | #define SCSI_CMD_FORMAT_UNIT 0x04 65 | #define SCSI_CMD_READ_6 0x08 /* not implemented yet */ 66 | #define SCSI_CMD_INQUIRY 0x12 67 | #define SCSI_CMD_SEND_DIAGNOSTIC 0x1D /* not implemented yet */ 68 | #define SCSI_CMD_READ_CAPACITY_10 0x25 69 | #define SCSI_CMD_READ_10 0x28 70 | #define SCSI_CMD_REPORT_LUNS 0xA0 /* not implemented yet */ 71 | 72 | // SBC2 optional SCSI commands 73 | #define SCSI_CMD_WRITE_6 0x0A /* not implemented yet */ 74 | #define SCSI_CMD_WRITE_10 0x2A 75 | #define SCSI_CMD_VERIFY_10 0x2F /* required for windows format */ 76 | 77 | // Code Red - added to support eject command from Windows 78 | #define SCSI_CMD_STARTSTOPUNIT_1B 0x1B 79 | 80 | // sense codes 81 | #define WRITE_ERROR 0x030C00 82 | #define READ_ERROR 0x031100 83 | #define INVALID_CMD_OPCODE 0x052000 84 | #define INVALID_FIELD_IN_CDB 0x052400 85 | 86 | // Sense code, which is set on error conditions 87 | static uint32_t dwSense; // hex: 00aabbcc, where aa=KEY, bb=ASC, cc=ASCQ 88 | 89 | static const uint8_t abInquiry[] = { 90 | 0x00, // PDT = direct-access device 91 | 0x80, // removeable medium bit = set 92 | 0x05, // version = complies to SPC3 93 | 0x02, // response data format = SPC3 94 | 0x1F, // additional length 95 | 0x00, 96 | 0x00, 97 | 0x00, 98 | 'L','P','C','U','S','B',' ',' ', // vendor 99 | 'M','a','s','s',' ','s','t','o', // product 100 | 'r','a','g','e',' ',' ',' ',' ', 101 | '0','.','1',' ' // revision 102 | }; 103 | 104 | // Data for "request sense" command. The 0xFF are filled in later 105 | static const uint8_t abSense[] = { 0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A, 106 | 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 107 | 0x00, 0x00 }; 108 | 109 | // Buffer for holding one block of disk data 110 | static uint8_t abBlockBuf[512]; 111 | 112 | typedef struct { 113 | uint8_t bOperationCode; 114 | uint8_t abLBA[3]; 115 | uint8_t bLength; 116 | uint8_t bControl; 117 | } TCDB6; 118 | 119 | 120 | /************************************************************************* 121 | SCSIReset 122 | ========= 123 | Resets any SCSI state 124 | 125 | **************************************************************************/ 126 | void SCSIReset(void) { 127 | dwSense = 0; 128 | } 129 | 130 | 131 | /************************************************************************* 132 | SCSIHandleCmd 133 | ============= 134 | Verifies a SCSI CDB and indicates the direction and amount of data 135 | that the device wants to transfer. 136 | 137 | If this call fails, a sense code is set in dwSense. 138 | 139 | IN pbCDB Command data block 140 | iCDBLen Command data block len 141 | OUT *piRspLen Length of intended response data: 142 | *pfDevIn true if data is transferred from device-to-host 143 | 144 | Returns a pointer to the data exchange buffer if successful, 145 | return NULL otherwise. 146 | **************************************************************************/ 147 | uint8_t* SCSIHandleCmd(uint8_t* pbCDB, uint8_t iCDBLen, int *piRspLen, bool *pfDevIn) { 148 | static const uint8_t aiCDBLen[] = {6, 10, 10, 0, 16, 12, 0, 0}; 149 | int i; 150 | uint32_t dwLen, dwLBA; 151 | uint8_t bGroupCode; 152 | 153 | // default direction is from device to host 154 | *pfDevIn = true; 155 | 156 | TCDB6* pCDB = (TCDB6 *)pbCDB; 157 | // check CDB length 158 | bGroupCode = (pCDB->bOperationCode >> 5) & 0x7; 159 | if (iCDBLen < aiCDBLen[bGroupCode]) { 160 | debug("Invalid CBD len (expected %d)!", aiCDBLen[bGroupCode]); 161 | return NULL; 162 | } 163 | 164 | switch (pCDB->bOperationCode) { 165 | 166 | // test unit ready (6) 167 | case SCSI_CMD_TEST_UNIT_READY: 168 | debug("TEST UNIT READY"); 169 | *piRspLen = 0; 170 | break; 171 | 172 | // request sense (6) 173 | case SCSI_CMD_REQUEST_SENSE: 174 | debug("REQUEST SENSE (%06X)", dwSense); 175 | // check params 176 | *piRspLen = MIN(18, pCDB->bLength); 177 | break; 178 | 179 | case SCSI_CMD_FORMAT_UNIT: 180 | debug("FORMAT UNIT %02X", pbCDB[1]); 181 | *piRspLen = 0; 182 | break; 183 | 184 | // inquiry (6) 185 | case SCSI_CMD_INQUIRY: 186 | debug("INQUIRY"); 187 | // see SPC3r23, 4.3.4.6 188 | *piRspLen = MIN(36, pCDB->bLength); 189 | break; 190 | 191 | // read capacity (10) 192 | case SCSI_CMD_READ_CAPACITY_10: 193 | debug("READ CAPACITY"); 194 | *piRspLen = 8; 195 | break; 196 | 197 | // read (10) 198 | case SCSI_CMD_READ_10: 199 | dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]); 200 | dwLen = (pbCDB[7] << 8) | pbCDB[8]; 201 | debug("READ10, LBA=%d, len=%d", dwLBA, dwLen); 202 | *piRspLen = dwLen * BLOCKSIZE; 203 | break; 204 | 205 | // write (10) 206 | case SCSI_CMD_WRITE_10: 207 | dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]); 208 | dwLen = (pbCDB[7] << 8) | pbCDB[8]; 209 | debug("WRITE10, LBA=%d, len=%d", dwLBA, dwLen); 210 | *piRspLen = dwLen * BLOCKSIZE; 211 | *pfDevIn = false; 212 | break; 213 | 214 | case SCSI_CMD_VERIFY_10: 215 | debug("VERIFY10"); 216 | if ((pbCDB[1] & (1 << 1)) != 0) { 217 | // we don't support BYTCHK 218 | debug("BYTCHK not supported"); 219 | return NULL; 220 | } 221 | *piRspLen = 0; 222 | break; 223 | 224 | // Code Red - added to support eject command from Windows 225 | case SCSI_CMD_STARTSTOPUNIT_1B: 226 | *piRspLen = 0; 227 | break; 228 | 229 | default: 230 | debug("Unhandled SCSI: "); 231 | for (i = 0; i < iCDBLen; i++) { 232 | debug(" %02X", pbCDB[i]); 233 | } 234 | debug(""); 235 | // unsupported command 236 | dwSense = INVALID_CMD_OPCODE; 237 | *piRspLen = 0; 238 | return NULL; 239 | } 240 | 241 | 242 | return abBlockBuf; 243 | } 244 | 245 | 246 | /************************************************************************* 247 | SCSIHandleData 248 | ============== 249 | Handles a block of SCSI data. 250 | 251 | IN pbCDB Command data block 252 | iCDBLen Command data block len 253 | IN/OUT pbData Data buffer 254 | IN dwOffset Offset in data 255 | 256 | Returns a pointer to the next data to be exchanged if successful, 257 | returns NULL otherwise. 258 | **************************************************************************/ 259 | uint8_t* SCSIHandleData(uint8_t* pbCDB, uint8_t iCDBLen, uint8_t* pbData, uint32_t dwOffset) { 260 | uint32_t dwLBA; 261 | uint32_t dwBufPos, dwBlockNr; 262 | uint32_t dwDevSize, dwMaxBlock; 263 | 264 | switch (((TCDB6*)pbCDB)->bOperationCode) { 265 | 266 | case SCSI_CMD_TEST_UNIT_READY: 267 | if (dwSense != 0) { 268 | return NULL; 269 | } 270 | break; 271 | 272 | case SCSI_CMD_REQUEST_SENSE: 273 | memcpy(pbData, abSense, 18); 274 | // fill in KEY/ASC/ASCQ 275 | pbData[2] = (dwSense >> 16) & 0xFF; 276 | pbData[12] = (dwSense >> 8) & 0xFF; 277 | pbData[13] = (dwSense >> 0) & 0xFF; 278 | // reset sense data 279 | dwSense = 0; 280 | break; 281 | 282 | case SCSI_CMD_FORMAT_UNIT: 283 | // nothing to do, ignore this command 284 | break; 285 | 286 | case SCSI_CMD_INQUIRY: 287 | memcpy(pbData, abInquiry, sizeof(abInquiry)); 288 | break; 289 | 290 | case SCSI_CMD_READ_CAPACITY_10: 291 | // get size of drive (bytes) 292 | BlockDevGetSize(&dwDevSize); 293 | // calculate highest LBA 294 | dwMaxBlock = (dwDevSize - 1) / 512; 295 | 296 | pbData[0] = (dwMaxBlock >> 24) & 0xFF; 297 | pbData[1] = (dwMaxBlock >> 16) & 0xFF; 298 | pbData[2] = (dwMaxBlock >> 8) & 0xFF; 299 | pbData[3] = (dwMaxBlock >> 0) & 0xFF; 300 | pbData[4] = (BLOCKSIZE >> 24) & 0xFF; 301 | pbData[5] = (BLOCKSIZE >> 16) & 0xFF; 302 | pbData[6] = (BLOCKSIZE >> 8) & 0xFF; 303 | pbData[7] = (BLOCKSIZE >> 0) & 0xFF; 304 | break; 305 | 306 | case SCSI_CMD_READ_10: 307 | dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]); 308 | 309 | // copy data from block buffer 310 | dwBufPos = (dwOffset & (BLOCKSIZE - 1)); 311 | if (dwBufPos == 0) { 312 | // read new block 313 | dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE); 314 | if (BlockDevRead(dwBlockNr, abBlockBuf) < 0) { 315 | dwSense = READ_ERROR; 316 | debug("BlockDevRead failed"); 317 | return NULL; 318 | } 319 | /* debug_no_newline("R: "); */ 320 | /* for(int i = 0; i < BLOCKSIZE; i++) { */ 321 | /* debug_no_newline("0x%x ", (abBlockBuf + dwBufPos)[i]); */ 322 | /* } */ 323 | /* debug(""); */ 324 | } 325 | // return pointer to data 326 | return abBlockBuf + dwBufPos; 327 | 328 | case SCSI_CMD_WRITE_10: 329 | dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]); 330 | 331 | // copy data to block buffer 332 | dwBufPos = ((dwOffset + 64) & (BLOCKSIZE - 1)); 333 | 334 | if (dwBufPos == 0) { 335 | // write new block 336 | dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE); 337 | 338 | if (BlockDevWrite(dwBlockNr, abBlockBuf) < 0) { 339 | dwSense = WRITE_ERROR; 340 | debug("BlockDevWrite failed"); 341 | return NULL; 342 | } 343 | } 344 | // return pointer to next data 345 | return abBlockBuf + dwBufPos; 346 | 347 | case SCSI_CMD_VERIFY_10: 348 | // dummy implementation 349 | break; 350 | 351 | // Code Red - added to support eject command from Windows 352 | case SCSI_CMD_STARTSTOPUNIT_1B: 353 | // dummy implementation 354 | break; 355 | default: 356 | // unsupported command 357 | dwSense = INVALID_CMD_OPCODE; 358 | return NULL; 359 | } 360 | 361 | // default: return pointer to start of block buffer 362 | return abBlockBuf; 363 | } 364 | -------------------------------------------------------------------------------- /src/msc_usb_start.c: -------------------------------------------------------------------------------- 1 | /* 2 | LPCUSB, an USB device driver for LPC microcontrollers 3 | Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. The name of the author may not be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /********************************************************************* 29 | * Code Red Technologies - modification of LPCUSB mass storage example 30 | * to provide a flash-based USB secondary bootloader for RDB1768 31 | * development board fitted with NXP LPC1768 MCU. 32 | *********************************************************************/ 33 | 34 | #include 35 | #include "usbapi.h" 36 | #include "log.h" 37 | #include "msc_bot.h" 38 | #include "disk.h" 39 | 40 | #define BAUD_RATE 115200 41 | #define MAX_PACKET_SIZE 64 42 | #define LE_WORD(x) ((x)&0xFF),((x)>>8) 43 | 44 | static uint8_t abClassReqData[4]; 45 | 46 | static const uint8_t abDescriptors[] = { 47 | 48 | // device descriptor 49 | 0x12, 50 | DESC_DEVICE, 51 | LE_WORD(0x0200), // bcdUSB 52 | 0x00, // bDeviceClass 53 | 0x00, // bDeviceSubClass 54 | 0x00, // bDeviceProtocol 55 | MAX_PACKET_SIZE0, // bMaxPacketSize 56 | LE_WORD(0xFFFF), // idVendor 57 | LE_WORD(0x0003), // idProduct 58 | LE_WORD(0x0100), // bcdDevice 59 | 0x01, // iManufacturer 60 | 0x02, // iProduct 61 | 0x03, // iSerialNumber 62 | 0x01, // bNumConfigurations 63 | 64 | // configuration descriptor 65 | 0x09, 66 | DESC_CONFIGURATION, 67 | LE_WORD(32), // wTotalLength 68 | 0x01, // bNumInterfaces 69 | 0x01, // bConfigurationValue 70 | 0x00, // iConfiguration 71 | 0xC0, // bmAttributes 72 | 0x32, // bMaxPower 73 | 74 | // interface 75 | 0x09, 76 | DESC_INTERFACE, 77 | 0x00, // bInterfaceNumber 78 | 0x00, // bAlternateSetting 79 | 0x02, // bNumEndPoints 80 | 0x08, // bInterfaceClass = mass storage 81 | 0x06, // bInterfaceSubClass = transparent SCSI 82 | 0x50, // bInterfaceProtocol = BOT 83 | 0x00, // iInterface 84 | // EP 85 | 0x07, 86 | DESC_ENDPOINT, 87 | MSC_BULK_IN_EP, // bEndpointAddress 88 | 0x02, // bmAttributes = bulk 89 | LE_WORD(MAX_PACKET_SIZE),// wMaxPacketSize 90 | 0x00, // bInterval 91 | // EP 92 | 0x07, 93 | DESC_ENDPOINT, 94 | MSC_BULK_OUT_EP, // bEndpointAddress 95 | 0x02, // bmAttributes = bulk 96 | LE_WORD(MAX_PACKET_SIZE),// wMaxPacketSize 97 | 0x00, // bInterval 98 | 99 | // string descriptors 100 | 0x04, 101 | DESC_STRING, 102 | LE_WORD(0x0409), 103 | 104 | 0x10, 105 | DESC_STRING, 106 | 'D', 0, 'e', 0, 'v', 0, 'B', 0, 'o', 0, 'a', 0,'r',0,'d','0', 107 | 108 | 0x28, 109 | DESC_STRING, 110 | 'L', 0, 'P', 0, 'C', 0, '1', 0, '7', 0, '5', 0, '9', 0, ' ', 0,'B',0,'o',0,'o',0,'t',0,'l',0,'o',0,'a',0,'d',0,'e',0,'r',0, 111 | 112 | // terminating zero 113 | 0 114 | }; 115 | 116 | 117 | /************************************************************************* 118 | HandleClassRequest 119 | ================== 120 | Handle mass storage class request 121 | 122 | **************************************************************************/ 123 | static bool HandleClassRequest(TSetupPacket *pSetup, int *piLen, uint8_t **ppbData) { 124 | if(pSetup->wIndex != 0) { 125 | debug("Invalid idx %X", pSetup->wIndex); 126 | return false; 127 | } 128 | 129 | if(pSetup->wValue != 0) { 130 | debug("Invalid val %X", pSetup->wValue); 131 | return false; 132 | } 133 | 134 | switch (pSetup->bRequest) { 135 | 136 | // get max LUN 137 | case 0xFE: 138 | *ppbData[0] = 0; // No LUNs 139 | *piLen = 1; 140 | break; 141 | 142 | // MSC reset 143 | case 0xFF: 144 | if(pSetup->wLength > 0) { 145 | return false; 146 | } 147 | MSCBotReset(); 148 | break; 149 | 150 | default: 151 | debug("Unhandled class"); 152 | return false; 153 | } 154 | return true; 155 | } 156 | 157 | 158 | void usb_msc_start (void) { 159 | 160 | debug("Initialising USB stack"); 161 | 162 | // initialise stack 163 | USBInit(); 164 | 165 | // enable bulk-in interrupts on NAKs 166 | // these are required to get the BOT protocol going again after a STALL 167 | USBHwNakIntEnable(INACK_BI); 168 | 169 | // register descriptors 170 | USBRegisterDescriptors(abDescriptors); 171 | 172 | // register class request handler 173 | USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData); 174 | 175 | // register endpoint handlers 176 | USBHwRegisterEPIntHandler(MSC_BULK_IN_EP, MSCBotBulkIn); 177 | USBHwRegisterEPIntHandler(MSC_BULK_OUT_EP, MSCBotBulkOut); 178 | 179 | debug("Starting USB communication"); 180 | 181 | // connect to bus 182 | USBHwConnect(true); 183 | 184 | // call USB interrupt handler continuously 185 | while (1) { 186 | USBHwISR(); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/sbl_config.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------- 2 | * U S B - K e r n e l 3 | *---------------------------------------------------------------------------- 4 | * Name: SBL_CONFIG.H 5 | * Purpose: USB Flash updater 6 | * Version: V1.0 7 | *---------------------------------------------------------------------------- 8 | * Software that is described herein is for illustrative purposes only 9 | * which provides customers with programming information regarding the 10 | * products. This software is supplied "AS IS" without any warranties. 11 | * NXP Semiconductors assumes no responsibility or liability for the 12 | * use of the software, conveys no license or title under any patent, 13 | * copyright, or mask work right to the product. NXP Semiconductors 14 | * reserves the right to make changes in the software without 15 | * notification. NXP Semiconductors also make no representation or 16 | * warranty that such application will be suitable for the specified 17 | * use without further testing or modification. 18 | *---------------------------------------------------------------------------*/ 19 | 20 | /*********************************************************************** 21 | * Code Red Technologies - Minor modifications to original code for use 22 | * in RDB1768 secondary USB bootloader based on LPCUSB USB stack. 23 | * *********************************************************************/ 24 | 25 | #ifndef _SBL_CONFIG_H 26 | #define _SBL_CONFIG_H 27 | 28 | //*** <<< Use Configuration Wizard in Context Menu >>> *** 29 | 30 | /* 31 | // Flash Configuration 32 | // User Start Sector <0-29> 33 | // Device Type 34 | // <7=> LPC17x1 - 8 KB 35 | // <15=> LPC17x2 - 64 KB 36 | // <17=> LPC17x4 - 128 KB 37 | // <21=> LPC17x5/6 - 256 KB 38 | // <29=> LPC17x8 - 512 KB 39 | // Code Read Protection 40 | // <0x11223344=> NO CRP <0x12345678=> CRP1 <0x87654321=> CRP2 <0x43218765=> CRP3 41 | // 42 | */ 43 | 44 | /* 45 | * CodeRed - changed start sector from bank 2 to bank 16 - ie 64k into flash. 46 | */ 47 | #define USER_START_SECTOR 16 48 | #define MAX_USER_SECTOR 29 49 | 50 | /* 51 | * CodeRed - change FLASH_BUF_SIZE from 256 to 512 to match buffer 52 | * size used by SCSI layer of LPCUSB 53 | */ 54 | #define FLASH_BUF_SIZE 512 55 | #define USER_FLASH_START (sector_start_map[USER_START_SECTOR]) 56 | #define USER_FLASH_END (sector_end_map[MAX_USER_SECTOR]) 57 | #define USER_FLASH_SIZE ((USER_FLASH_END - USER_FLASH_START) + 1) 58 | #define MAX_FLASH_SECTOR 30 59 | 60 | #define BOOTLOADER_ENTRY_GPIO_PORT 1 61 | #define BOOTLOADER_ENTRY_GPIO_PIN 12 62 | 63 | /* Define start address of each Flash sector */ 64 | #define SECTOR_0_START 0x00000000 65 | #define SECTOR_1_START 0x00001000 66 | #define SECTOR_2_START 0x00002000 67 | #define SECTOR_3_START 0x00003000 68 | #define SECTOR_4_START 0x00004000 69 | #define SECTOR_5_START 0x00005000 70 | #define SECTOR_6_START 0x00006000 71 | #define SECTOR_7_START 0x00007000 72 | #define SECTOR_8_START 0x00008000 73 | #define SECTOR_9_START 0x00009000 74 | #define SECTOR_10_START 0x0000A000 75 | #define SECTOR_11_START 0x0000B000 76 | #define SECTOR_12_START 0x0000C000 77 | #define SECTOR_13_START 0x0000D000 78 | #define SECTOR_14_START 0x0000E000 79 | #define SECTOR_15_START 0x0000F000 80 | #define SECTOR_16_START 0x00010000 81 | #define SECTOR_17_START 0x00018000 82 | #define SECTOR_18_START 0x00020000 83 | #define SECTOR_19_START 0x00028000 84 | #define SECTOR_20_START 0x00030000 85 | #define SECTOR_21_START 0x00038000 86 | #define SECTOR_22_START 0x00040000 87 | #define SECTOR_23_START 0x00048000 88 | #define SECTOR_24_START 0x00050000 89 | #define SECTOR_25_START 0x00058000 90 | #define SECTOR_26_START 0x00060000 91 | #define SECTOR_27_START 0x00068000 92 | #define SECTOR_28_START 0x00070000 93 | #define SECTOR_29_START 0x00078000 94 | 95 | 96 | 97 | /* Define end address of each Flash sector */ 98 | #define SECTOR_0_END 0x00000FFF 99 | #define SECTOR_1_END 0x00001FFF 100 | #define SECTOR_2_END 0x00002FFF 101 | #define SECTOR_3_END 0x00003FFF 102 | #define SECTOR_4_END 0x00004FFF 103 | #define SECTOR_5_END 0x00005FFF 104 | #define SECTOR_6_END 0x00006FFF 105 | #define SECTOR_7_END 0x00007FFF 106 | #define SECTOR_8_END 0x00008FFF 107 | #define SECTOR_9_END 0x00009FFF 108 | #define SECTOR_10_END 0x0000AFFF 109 | #define SECTOR_11_END 0x0000BFFF 110 | #define SECTOR_12_END 0x0000CFFF 111 | #define SECTOR_13_END 0x0000DFFF 112 | #define SECTOR_14_END 0x0000EFFF 113 | #define SECTOR_15_END 0x0000FFFF 114 | #define SECTOR_16_END 0x00017FFF 115 | #define SECTOR_17_END 0x0001FFFF 116 | #define SECTOR_18_END 0x00027FFF 117 | #define SECTOR_19_END 0x0002FFFF 118 | #define SECTOR_20_END 0x00037FFF 119 | #define SECTOR_21_END 0x0003FFFF 120 | #define SECTOR_22_END 0x00047FFF 121 | #define SECTOR_23_END 0x0004FFFF 122 | #define SECTOR_24_END 0x00057FFF 123 | #define SECTOR_25_END 0x0005FFFF 124 | #define SECTOR_26_END 0x00067FFF 125 | #define SECTOR_27_END 0x0006FFFF 126 | #define SECTOR_28_END 0x00077FFF 127 | #define SECTOR_29_END 0x0007FFFF 128 | 129 | 130 | #endif /* __SBL_CONFIG_H__ */ 131 | -------------------------------------------------------------------------------- /src/sbl_iap.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Software that is described herein is for illustrative purposes only 3 | // which provides customers with programming information regarding the 4 | // products. This software is supplied "AS IS" without any warranties. 5 | // NXP Semiconductors assumes no responsibility or liability for the 6 | // use of the software, conveys no license or title under any patent, 7 | // copyright, or mask work right to the product. NXP Semiconductors 8 | // reserves the right to make changes in the software without 9 | // notification. NXP Semiconductors also make no representation or 10 | // warranty that such application will be suitable for the specified 11 | // use without further testing or modification. 12 | //----------------------------------------------------------------------------- 13 | 14 | /*********************************************************************** 15 | * Code Red Technologies - Minor modifications to original NXP AN10866 16 | * example code for use in RDB1768 secondary USB bootloader based on 17 | * LPCUSB USB stack. 18 | * *********************************************************************/ 19 | 20 | #include "type.h" 21 | #include "sbl_iap.h" 22 | #include "sbl_config.h" 23 | #include "LPC17xx.h" 24 | #include "log.h" 25 | 26 | const unsigned sector_start_map[MAX_FLASH_SECTOR] = {SECTOR_0_START, \ 27 | SECTOR_1_START,SECTOR_2_START,SECTOR_3_START,SECTOR_4_START,SECTOR_5_START, \ 28 | SECTOR_6_START,SECTOR_7_START,SECTOR_8_START,SECTOR_9_START,SECTOR_10_START, \ 29 | SECTOR_11_START,SECTOR_12_START,SECTOR_13_START,SECTOR_14_START,SECTOR_15_START, \ 30 | SECTOR_16_START,SECTOR_17_START,SECTOR_18_START,SECTOR_19_START,SECTOR_20_START, \ 31 | SECTOR_21_START,SECTOR_22_START,SECTOR_23_START,SECTOR_24_START,SECTOR_25_START, \ 32 | SECTOR_26_START,SECTOR_27_START,SECTOR_28_START,SECTOR_29_START}; 33 | 34 | const unsigned sector_end_map[MAX_FLASH_SECTOR] = {SECTOR_0_END,SECTOR_1_END, \ 35 | SECTOR_2_END,SECTOR_3_END,SECTOR_4_END,SECTOR_5_END,SECTOR_6_END,SECTOR_7_END, \ 36 | SECTOR_8_END,SECTOR_9_END,SECTOR_10_END,SECTOR_11_END,SECTOR_12_END, \ 37 | SECTOR_13_END,SECTOR_14_END,SECTOR_15_END,SECTOR_16_END,SECTOR_17_END, \ 38 | SECTOR_18_END,SECTOR_19_END,SECTOR_20_END,SECTOR_21_END,SECTOR_22_END, \ 39 | SECTOR_23_END,SECTOR_24_END,SECTOR_25_END,SECTOR_26_END, \ 40 | SECTOR_27_END,SECTOR_28_END,SECTOR_29_END }; 41 | 42 | unsigned param_table[5]; 43 | unsigned result_table[5]; 44 | 45 | char flash_buf[FLASH_BUF_SIZE]; 46 | 47 | unsigned *flash_address = 0; 48 | unsigned byte_ctr = 0; 49 | 50 | unsigned sector_erased_map[MAX_FLASH_SECTOR]; 51 | 52 | void write_data(unsigned cclk,unsigned flash_address,unsigned * flash_data_buf, unsigned count); 53 | void find_erase_prepare_sector(unsigned cclk, unsigned flash_address); 54 | void erase_sector(unsigned start_sector,unsigned end_sector,unsigned cclk); 55 | void prepare_sector(unsigned start_sector,unsigned end_sector,unsigned cclk); 56 | void iap_entry(unsigned param_tab[],unsigned result_tab[]); 57 | 58 | void reset_sector_erasure_status() { 59 | debug("Clearing erasure status of all sectors to allow rewriting"); 60 | for(int i = 0; i < MAX_FLASH_SECTOR; i++) { 61 | sector_erased_map[i] = false; 62 | } 63 | } 64 | 65 | unsigned write_flash(unsigned * dst, char * src, unsigned no_of_bytes) 66 | { 67 | if (flash_address == 0) { 68 | /* Store flash start address */ 69 | flash_address = (unsigned *)dst; 70 | } 71 | 72 | for(unsigned int i = 0;iPCONP = 0x001817BE; 171 | 172 | /* Change the Vector Table to the USER_FLASH_START 173 | in case the user application uses interrupts */ 174 | SCB->VTOR = (USER_FLASH_START & 0x1FFFFF80); 175 | 176 | // The very top of the user flash should contain the interrupt handler 177 | // vector. The first word should be the initial stack pointer. The second 178 | // word should contain the address of the Reset_Handler (i.e. 179 | // USER_FLASH_START + 4). 180 | p = (unsigned *)(USER_FLASH_START + 4); 181 | 182 | // Set user_code_entry to be the address contained in that second word 183 | // of user flash. 184 | user_code_entry = (void *) *p; 185 | 186 | __enable_irq(); 187 | // Jump to user application 188 | user_code_entry(); 189 | } 190 | 191 | 192 | int user_code_present(void) { 193 | param_table[0] = BLANK_CHECK_SECTOR; 194 | param_table[1] = USER_START_SECTOR; 195 | param_table[2] = USER_START_SECTOR; 196 | iap_entry(param_table,result_table); 197 | if( result_table[0] == CMD_SUCCESS ) 198 | { 199 | 200 | return (false); 201 | } 202 | 203 | return (true); 204 | } 205 | 206 | void check_isp_entry_pin(void) 207 | { 208 | unsigned long i,j; 209 | 210 | for(i=0; i < 60 ; i++) 211 | { 212 | if((LPC_GPIO2->FIOPIN & (BOOTLOADER_ENTRY_GPIO_PORT 213 | << BOOTLOADER_ENTRY_GPIO_PIN)) == 0) 214 | { 215 | break; 216 | } 217 | for(j=0;j< (1<<15);j++); 218 | } 219 | if( i == 60) 220 | { 221 | execute_user_code(); 222 | } 223 | } 224 | 225 | void erase_user_flash(void) 226 | { 227 | debug("Erasing user flash"); 228 | prepare_sector(USER_START_SECTOR, MAX_USER_SECTOR, SystemCoreClock/1000); 229 | erase_sector(USER_START_SECTOR, MAX_USER_SECTOR, SystemCoreClock/1000); 230 | if(result_table[0] != CMD_SUCCESS) 231 | { 232 | debug("Unable to erase user flash - can't recover"); 233 | while(1); /* No way to recover. Just let Windows report a write failure */ 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/sbl_iap.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Software that is described herein is for illustrative purposes only 3 | // which provides customers with programming information regarding the 4 | // products. This software is supplied "AS IS" without any warranties. 5 | // NXP Semiconductors assumes no responsibility or liability for the 6 | // use of the software, conveys no license or title under any patent, 7 | // copyright, or mask work right to the product. NXP Semiconductors 8 | // reserves the right to make changes in the software without 9 | // notification. NXP Semiconductors also make no representation or 10 | // warranty that such application will be suitable for the specified 11 | // use without further testing or modification. 12 | //----------------------------------------------------------------------------- 13 | 14 | #ifndef _SBL_IAP_H 15 | #define _SBL_IAP_H 16 | 17 | #include 18 | 19 | extern const unsigned sector_start_map[]; 20 | extern const unsigned sector_end_map[]; 21 | 22 | 23 | unsigned write_flash(unsigned * dst, char * src, unsigned no_of_bytes); 24 | void execute_user_code(void); 25 | int user_code_present(void); 26 | void erase_user_flash(void); 27 | void check_isp_entry_pin(void); 28 | void erase_user_flash(void); 29 | void reset_sector_erasure_status(); 30 | 31 | typedef enum 32 | { 33 | PREPARE_SECTOR_FOR_WRITE =50, 34 | COPY_RAM_TO_FLASH =51, 35 | ERASE_SECTOR =52, 36 | BLANK_CHECK_SECTOR =53, 37 | READ_PART_ID =54, 38 | READ_BOOT_VER =55, 39 | COMPARE =56, 40 | REINVOKE_ISP =57 41 | }IAP_Command_Code; 42 | 43 | #define CMD_SUCCESS 0 44 | #define IAP_ADDRESS 0x1FFF1FF1 45 | 46 | #endif /* _SBL_IAP_H */ 47 | -------------------------------------------------------------------------------- /src/startup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Derived from startup code originally published by Jakub Piotr Cłapa, 3 | * Copyright (c) 2010 LoEE under the new BSD license. 4 | * 5 | * See also: http://bitbucket.org/jpc/lpc1768/ 6 | * 7 | * NVIC handler names from NXP UM10360, comments taken from Opendous Inc. under 8 | * the following license: 9 | * 10 | * Permission to use, copy, modify, and distribute this software and its 11 | * documentation for any purpose and without fee is hereby granted, provided 12 | * that the above copyright notice appear in all copies and that both that the 13 | * copyright notice and this permission notice and warranty disclaimer appear in 14 | * supporting documentation, and that the name of the author not be used in 15 | * advertising or publicity pertaining to distribution of the software without 16 | * specific, written prior permission. 17 | 18 | * The author disclaim all warranties with regard to this software, including 19 | * all implied warranties of merchantability and fitness. In no event shall the 20 | * author be liable for any special, indirect or consequential damages or any 21 | * damages whatsoever resulting from loss of use, data or profits, whether in an 22 | * action of contract, negligence or other tortious action, arising out of or in 23 | * connection with the use or performance of this software. 24 | */ 25 | #include "LPC17xx.h" 26 | 27 | // Defined in linker script 28 | extern void __stack(void); 29 | extern uint32_t __etext; 30 | extern uint32_t __data_start__; 31 | extern uint32_t __data_end__; 32 | extern uint32_t __bss_start__; 33 | extern uint32_t __bss_end__; 34 | 35 | // Defined by user application 36 | extern int main (void); 37 | 38 | // Dummy handler. 39 | void Default_Handler (void) { while (1); } 40 | 41 | // Weakly bind all interrupt vectors to the dummy handler. 42 | void NMI_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 43 | void HardFault_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 44 | void MemManage_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 45 | void BusFault_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 46 | void UsageFault_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 47 | void SVC_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 48 | void DebugMon_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 49 | void PendSV_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 50 | void SysTick_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 51 | void WDT_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 52 | void TIMER0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 53 | void TIMER1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 54 | void TIMER2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 55 | void TIMER3_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 56 | void UART0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 57 | void UART1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 58 | void UART2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 59 | void UART3_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 60 | void PWM1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 61 | void I2C0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 62 | void I2C1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 63 | void I2C2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 64 | void SPI_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 65 | void SSP0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 66 | void SSP1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 67 | void PLL0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 68 | void RTC_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 69 | void EINT0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 70 | void EINT1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 71 | void EINT2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 72 | void EINT3_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 73 | void ADC_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 74 | void BOD_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 75 | void USB_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 76 | void CAN_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 77 | void DMA_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 78 | void I2S_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 79 | void ENET_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 80 | void RIT_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 81 | void MCPWM_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 82 | void QEI_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 83 | void PLL1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 84 | void USBActivity_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 85 | void CANActivity_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 86 | 87 | // The signature of Cortex-M3 interrupt handlers. 88 | typedef void (* const Interrupt_Handler_P)(void); 89 | 90 | void Reset_Handler(void) { 91 | SystemInit(); 92 | 93 | uint32_t *s, *d; 94 | // Copy initialization data to RAM (.data section) 95 | s = &__etext; 96 | d = &__data_start__; 97 | while (d < &__data_end__) *d++ = *s++; 98 | // Zero the remaining allocated RAM (.bss section) 99 | d = &__bss_start__; 100 | while (d < &__bss_end__) *d++ = 0; 101 | 102 | // Everything is ready. Run the user program. 103 | main(); 104 | while(1); // in case main() fails 105 | } 106 | 107 | // Interrupt vectors table 108 | __attribute__ ((section(".isr_vector"))) 109 | Interrupt_Handler_P interrupt_vectors[] = { 110 | &__stack, // the first word contains the initial 111 | // stack pointer the hardware loads it 112 | // to the SP register before the first 113 | // instruction 114 | // Standard Cortex-M3 interrupts: 115 | Reset_Handler, 116 | NMI_Handler, 117 | HardFault_Handler, 118 | MemManage_Handler, 119 | BusFault_Handler, 120 | UsageFault_Handler, 121 | 0, 122 | 0, 123 | 0, 124 | 0, 125 | SVC_Handler, 126 | DebugMon_Handler, 127 | 0, 128 | PendSV_Handler, 129 | SysTick_Handler, 130 | // LPC17xx Interrupts: Interrupt ID - Exception Number - Vector Offset - Description and Flags 131 | 132 | WDT_IRQHandler, // 0 16 0x40 WDT Watchdog Interrupt (WDINT) 133 | TIMER0_IRQHandler, // 1 17 0x44 Timer 0 Match 0 - 1 (MR0, MR1) 134 | // Capture 0 - 1 (CR0, CR1) 135 | TIMER1_IRQHandler, // 2 18 0x48 Timer 1 Match 0 - 2 136 | // (MR0, MR1, MR2), Capture 0 - 1 (CR0, CR1) 137 | TIMER2_IRQHandler, // 3 19 0x4C Timer 2 Match 0-3 138 | // Capture 0-1 139 | TIMER3_IRQHandler, // 4 20 0x50 Timer 3 Match 0-3 140 | // Capture 0-1 141 | UART0_IRQHandler, // 5 21 0x54 UART0 Rx Line Status (RLS) 142 | // Transmit Holding Register Empty (THRE) 143 | // Rx Data Available (RDA) 144 | // Character Time-out Indicator (CTI) 145 | // End of Auto-Baud (ABEO) 146 | // Auto-Baud Time-Out (ABTO) 147 | UART1_IRQHandler, // 6 22 0x58 UART1 Rx Line Status (RLS) 148 | // Transmit Holding Register Empty (THRE) 149 | // Rx Data Available (RDA) 150 | // Character Time-out Indicator (CTI) 151 | // Modem Control Change 152 | // End of Auto-Baud (ABEO) 153 | // Auto-Baud Time-Out (ABTO) 154 | UART2_IRQHandler, // 7 23 0x5C UART 2 Rx Line Status (RLS) 155 | // Transmit Holding Register Empty (THRE) 156 | // Rx Data Available (RDA) 157 | // Character Time-out Indicator (CTI) 158 | // End of Auto-Baud (ABEO) 159 | // Auto-Baud Time-Out (ABTO) 160 | UART3_IRQHandler, // 8 24 0x60 UART 3 Rx Line Status (RLS) 161 | // Transmit Holding Register Empty (THRE) 162 | // Rx Data Available (RDA) 163 | // Character Time-out Indicator (CTI) 164 | // End of Auto-Baud (ABEO) 165 | // Auto-Baud Time-Out (ABTO) 166 | PWM1_IRQHandler, // 9 25 0x64 PWM1 Match 0 - 6 of PWM1 167 | // Capture 0-1 of PWM1 168 | I2C0_IRQHandler, // 10 26 0x68 I2C0 SI (state change) 169 | I2C1_IRQHandler, // 11 27 0x6C I2C1 SI (state change) 170 | I2C2_IRQHandler, // 12 28 0x70 I2C2 SI (state change) 171 | SPI_IRQHandler, // 13 29 0x74 SPI SPI Interrupt Flag (SPIF) 172 | // Mode Fault (MODF) 173 | SSP0_IRQHandler, // 14 30 0x78 SSP0 Tx FIFO half empty of SSP0 174 | // Rx FIFO half full of SSP0 175 | // Rx Timeout of SSP0 176 | // Rx Overrun of SSP0 177 | SSP1_IRQHandler, // 15 31 0x7C SSP 1 Tx FIFO half empty 178 | // Rx FIFO half full 179 | // Rx Timeout 180 | // Rx Overrun 181 | PLL0_IRQHandler, // 16 32 0x80 PLL0 (Main PLL) PLL0 Lock (PLOCK0) 182 | RTC_IRQHandler, // 17 33 0x84 RTC Counter Increment (RTCCIF) 183 | // Alarm (RTCALF) 184 | EINT0_IRQHandler, // 18 34 0x88 External Interrupt External Interrupt 0 (EINT0) 185 | EINT1_IRQHandler, // 19 35 0x8C External Interrupt External Interrupt 1 (EINT1) 186 | EINT2_IRQHandler, // 20 36 0x90 External Interrupt External Interrupt 2 (EINT2) 187 | EINT3_IRQHandler, // 21 37 0x94 External Interrupt External Interrupt 3 (EINT3). 188 | // Note: EINT3 channel is shared with GPIO interrupts 189 | ADC_IRQHandler, // 22 38 0x98 ADC A/D Converter end of conversion 190 | BOD_IRQHandler, // 23 39 0x9C BOD Brown Out detect 191 | USB_IRQHandler, // 24 40 0xA0 USB USB_INT_REQ_LP, USB_INT_REQ_HP, USB_INT_REQ_DMA 192 | CAN_IRQHandler, // 25 41 0xA4 CAN CAN Common, CAN 0 Tx, CAN 0 Rx, CAN 1 Tx, CAN 1 Rx 193 | DMA_IRQHandler, // 26 42 0xA8 GPDMA IntStatus of DMA channel 0, IntStatus of DMA channel 1 194 | I2S_IRQHandler, // 27 43 0xAC I2S irq, dmareq1, dmareq2 195 | ENET_IRQHandler, // 28 44 0xB0 Ethernet WakeupInt, SoftInt, TxDoneInt, TxFinishedInt, TxErrorInt, 196 | // TxUnderrunInt, RxDoneInt, RxFinishedInt, RxErrorInt, RxOverrunInt. 197 | RIT_IRQHandler, // 29 45 0xB4 Repetitive Interrupt Timer (RITINT) 198 | MCPWM_IRQHandler, // 30 46 0xB8 Motor Control PWM IPER[2:0], IPW[2:0], ICAP[2:0], FES 199 | QEI_IRQHandler, // 31 47 0xBC Quadrature Encoder INX_Int, TIM_Int, VELC_Int, DIR_Int, ERR_Int, ENCLK_Int, 200 | // POS0_Int, POS1_Int, POS2_Int, REV_Int, POS0REV_Int, POS1REV_Int, POS2REV_Int 201 | PLL1_IRQHandler, // 32 48 0xC0 PLL1 (USB PLL) PLL1 Lock (PLOCK1) 202 | USBActivity_IRQHandler, // 33 49 0xC4 USB Activity Interrupt USB_NEED_CLK 203 | CANActivity_IRQHandler, // 34 50 0xC8 CAN Activity Interrupt CAN1WAKE, CAN2WAKE 204 | }; 205 | --------------------------------------------------------------------------------