From fd50d90b1832ea4fe7b7ec5cc9a339e1841c3df8 Mon Sep 17 00:00:00 2001 From: ladyada Date: Wed, 28 Oct 2015 18:32:26 -0400 Subject: [PATCH 01/22] fix makefile for easier programming --- bootloaders/zero/Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bootloaders/zero/Makefile b/bootloaders/zero/Makefile index 508b9c78f..d8fb2f349 100644 --- a/bootloaders/zero/Makefile +++ b/bootloaders/zero/Makefile @@ -1,15 +1,15 @@ -ARM_GCC_PATH=/home/megabug/.arduino15/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin +IDE_PATH="../../../../.." +ARM_GCC_PATH=$(IDE_PATH)/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin CC=$(ARM_GCC_PATH)/arm-none-eabi-gcc -OBJCOPY=$(ARM_GCC_PATH)/arm-none-eabi-objcopy CFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -c -g -Os -w -std=gnu99 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 LDFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols BLD_EXTA_FLAGS=-D__SAMD21G18A__ BUILD_PATH=build -INCLUDES=-I/home/megabug/.arduino15/packages/arduino/tools/CMSIS/4.0.0-atmel/CMSIS/Include/ -I/home/megabug/.arduino15/packages/arduino/tools/CMSIS/4.0.0-atmel/Device/ATMEL/ -I./drivers/ -I./utils/ -I./utils/preprocessor/ -I./utils/interrupt +INCLUDES=-I$(IDE_PATH)/hardware/tools/CMSIS/CMSIS/Include/ -I$(IDE_PATH)/hardware/tools/CMSIS/Device/ATMEL/ -I./drivers/ -I./utils/ -I./utils/preprocessor/ -I./utils/interrupt SOURCES=main.c sam_ba_monitor.c startup_samd21.c usart_sam_ba.c drivers/cdc_enumerate.c drivers/uart_driver.c utils/interrupt/interrupt_sam_nvic.c OBJECTS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.o)) -NAME=samd21_sam_ba_genuino +NAME=samd21_sam_ba EXECUTABLE=$(NAME).bin SLASH=/ @@ -19,11 +19,11 @@ all: $(SOURCES) $(EXECUTABLE) $(EXECUTABLE): $(OBJECTS) $(CC) -L$(BUILD_PATH) $(LDFLAGS) -Os -Wl,--gc-sections -save-temps -Tsamd21j18a_flash.ld -Wl,-Map,$(BUILD_PATH)/$(NAME).map --specs=nano.specs --specs=nosys.specs -o $(BUILD_PATH)/$(NAME).elf $(OBJECTS) -Wl,--start-group -lm -Wl,--end-group - $(OBJCOPY) -O binary $(BUILD_PATH)/$(NAME).elf $@ + $(ARM_GCC_PATH)/arm-none-eabi-objcopy -O binary $(BUILD_PATH)/$(NAME).elf $@ $(BUILD_PATH)/%.o: %.c -@mkdir -p $(@D) $(CC) $(CFLAGS) $(BLD_EXTA_FLAGS) $(INCLUDES) $< -o $@ clean: - rm $(EXECUTABLE) $(subst /,\,$(OBJECTS)) $(subst /,\,$(BUILD_PATH)/$(NAME).*) + del $(EXECUTABLE) $(subst /,\,$(OBJECTS)) $(subst /,\,$(BUILD_PATH)/$(NAME).*) From 11fa3d349f333d258eec9ea9b5f0042f29cacaea Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 31 Oct 2015 00:52:54 -0400 Subject: [PATCH 02/22] pulse D13 LED during bootloader active --- bootloaders/zero/main.c | 32 +++++++++++++++++++++++++++++++ bootloaders/zero/main.h | 7 +++++++ bootloaders/zero/sam_ba_monitor.c | 1 + 3 files changed, 40 insertions(+) diff --git a/bootloaders/zero/main.c b/bootloaders/zero/main.c index 4ad7abd54..82d8b8377 100644 --- a/bootloaders/zero/main.c +++ b/bootloaders/zero/main.c @@ -280,8 +280,15 @@ int main(void) pCdc = (P_USB_CDC)usb_init(); #endif DEBUG_PIN_LOW; + + // output on D13 (PA.17) + LED_PORT.PINCFG[LED_PIN].reg &= ~ (uint8_t)(PORT_PINCFG_INEN); + LED_PORT.DIRSET.reg = (uint32_t)(1 << LED_PIN); + /* Wait for a complete enum on usb or a '#' char on serial line */ while (1) { + pulse_led(1); // while we're waiting, blink the D13 + #if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES if (pCdc->IsConfigured(pCdc) != 0) { main_b_cdc_enable = true; @@ -309,3 +316,28 @@ int main(void) #endif } } + + +// We'll have the D13 LED slowly pulse on and off with bitbang PWM +// for a nice 'hey we're in bootload mode' indication! -ada +static uint8_t pulse_tick=0; +static int8_t pulse_dir=1; +static int16_t pulse_pwm; +void pulse_led(int8_t speed) { + // blink D13 + pulse_tick++; + if (pulse_tick==0) { + pulse_pwm += pulse_dir * speed; + if (pulse_pwm > 255) { + pulse_pwm = 255; + pulse_dir = -1; + } + if (pulse_pwm < 0) { + pulse_pwm = 0; + pulse_dir = +1; + } + LED_ON; + } + if (pulse_tick==pulse_pwm) + LED_OFF; +} diff --git a/bootloaders/zero/main.h b/bootloaders/zero/main.h index b8c58ec79..f2b10dc46 100644 --- a/bootloaders/zero/main.h +++ b/bootloaders/zero/main.h @@ -29,6 +29,13 @@ #pragma once +// Gently pulse the D13 LED +#define LED_PIN 17 +#define PORTA PORT->Group[0] +#define LED_PORT PORTA + +#define LED_ON LED_PORT.OUTSET.reg = (uint32_t)(1 << LED_PIN); +#define LED_OFF LED_PORT.OUTCLR.reg = (uint32_t)(1 << LED_PIN); /* * If BOOT_DOUBLE_TAP_ADDRESS is defined the bootloader is started by * quickly tapping two times on the reset button. diff --git a/bootloaders/zero/sam_ba_monitor.c b/bootloaders/zero/sam_ba_monitor.c index 29c9d8566..8a81d6dac 100644 --- a/bootloaders/zero/sam_ba_monitor.c +++ b/bootloaders/zero/sam_ba_monitor.c @@ -201,6 +201,7 @@ void put_uint32(uint32_t n) { void sam_ba_monitor_loop(void) { + pulse_led(3); length = ptr_monitor_if->getdata(data, SIZEBUFMAX); ptr = data; for (i = 0; i < length; i++, ptr++) From 85d6c73f090da3fa8bd2d190774389b23f06d665 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 31 Oct 2015 00:57:07 -0400 Subject: [PATCH 03/22] makefile now compiles from within Roaming/Arduino15 subfolder --- bootloaders/zero/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bootloaders/zero/Makefile b/bootloaders/zero/Makefile index d8fb2f349..1531b592e 100644 --- a/bootloaders/zero/Makefile +++ b/bootloaders/zero/Makefile @@ -1,11 +1,11 @@ -IDE_PATH="../../../../.." -ARM_GCC_PATH=$(IDE_PATH)/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin +IDE_PATH=../../../../.. +ARM_GCC_PATH=$(IDE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin CC=$(ARM_GCC_PATH)/arm-none-eabi-gcc CFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -c -g -Os -w -std=gnu99 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 LDFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols BLD_EXTA_FLAGS=-D__SAMD21G18A__ BUILD_PATH=build -INCLUDES=-I$(IDE_PATH)/hardware/tools/CMSIS/CMSIS/Include/ -I$(IDE_PATH)/hardware/tools/CMSIS/Device/ATMEL/ -I./drivers/ -I./utils/ -I./utils/preprocessor/ -I./utils/interrupt +INCLUDES=-I$(IDE_PATH)/tools/CMSIS/CMSIS/Include/ -I$(IDE_PATH)/tools/CMSIS/4.0.0-atmel/Device/ATMEL/ -I$(IDE_PATH)/tools/CMSIS/4.0.0-atmel/CMSIS/Include/ -I./drivers/ -I./utils/ -I./utils/preprocessor/ -I./utils/interrupt SOURCES=main.c sam_ba_monitor.c startup_samd21.c usart_sam_ba.c drivers/cdc_enumerate.c drivers/uart_driver.c utils/interrupt/interrupt_sam_nvic.c OBJECTS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.o)) @@ -16,7 +16,7 @@ SLASH=/ BSLASH=$(EMPTY)\$(EMPTY) all: $(SOURCES) $(EXECUTABLE) - + $(EXECUTABLE): $(OBJECTS) $(CC) -L$(BUILD_PATH) $(LDFLAGS) -Os -Wl,--gc-sections -save-temps -Tsamd21j18a_flash.ld -Wl,-Map,$(BUILD_PATH)/$(NAME).map --specs=nano.specs --specs=nosys.specs -o $(BUILD_PATH)/$(NAME).elf $(OBJECTS) -Wl,--start-group -lm -Wl,--end-group $(ARM_GCC_PATH)/arm-none-eabi-objcopy -O binary $(BUILD_PATH)/$(NAME).elf $@ @@ -24,6 +24,6 @@ $(EXECUTABLE): $(OBJECTS) $(BUILD_PATH)/%.o: %.c -@mkdir -p $(@D) $(CC) $(CFLAGS) $(BLD_EXTA_FLAGS) $(INCLUDES) $< -o $@ - + clean: del $(EXECUTABLE) $(subst /,\,$(OBJECTS)) $(subst /,\,$(BUILD_PATH)/$(NAME).*) From e715bf3d975d420c6d1755f9f8a2b97cfc24599b Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 31 Oct 2015 21:28:28 -0400 Subject: [PATCH 04/22] add support for A6 (D8) and A7 (D9) --- cores/arduino/wiring_analog.c | 4 +++- variants/arduino_zero/variant.cpp | 4 ++-- variants/arduino_zero/variant.h | 6 +++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c index 37f1fa045..c5f5695f6 100644 --- a/cores/arduino/wiring_analog.c +++ b/cores/arduino/wiring_analog.c @@ -140,10 +140,12 @@ uint32_t analogRead( uint32_t ulPin ) { uint32_t valueRead = 0; - if ( ulPin < A0 ) + if ( ulPin <= 5 ) // turn '0' -> 'A0' { ulPin += A0 ; } + if (ulPin == 6) ulPin = PIN_A6; + if (ulPin == 7) ulPin = PIN_A7; pinPeripheral(ulPin, g_APinDescription[ulPin].ulPinType); diff --git a/variants/arduino_zero/variant.cpp b/variants/arduino_zero/variant.cpp index ed19dc342..007df58e6 100644 --- a/variants/arduino_zero/variant.cpp +++ b/variants/arduino_zero/variant.cpp @@ -127,8 +127,8 @@ const PinDescription g_APinDescription[]= { PORTA, 21, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_5 }, // Digital High - { PORTA, 6, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM1_CH0, TCC1_CH0, EXTERNAL_INT_6 }, // TCC1/WO[0] - { PORTA, 7, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_7 }, // TCC1/WO[1] + { PORTA, 6, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER|PIN_ATTR_ANALOG), ADC_Channel6, PWM1_CH0, TCC1_CH0, EXTERNAL_INT_6 }, // TCC1/WO[0] + { PORTA, 7, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER|PIN_ATTR_ANALOG), ADC_Channel7, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_7 }, // TCC1/WO[1] { PORTA, 18, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM3_CH0, TC3_CH0, EXTERNAL_INT_2 }, // TC3/WO[0] { PORTA, 16, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_0 }, // TCC2/WO[0] { PORTA, 19, PIO_TIMER_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM0_CH3, TCC0_CH3, EXTERNAL_INT_3 }, // TCC0/WO[3] diff --git a/variants/arduino_zero/variant.h b/variants/arduino_zero/variant.h index 2e84db490..6dc757184 100644 --- a/variants/arduino_zero/variant.h +++ b/variants/arduino_zero/variant.h @@ -52,7 +52,7 @@ extern "C" // Number of pins defined in PinDescription array #define PINS_COUNT (26u) #define NUM_DIGITAL_PINS (14u) -#define NUM_ANALOG_INPUTS (6u) +#define NUM_ANALOG_INPUTS (8u) #define NUM_ANALOG_OUTPUTS (1u) #define digitalPinToPort(P) ( &(PORT->Group[g_APinDescription[P].ulPort]) ) @@ -93,6 +93,8 @@ extern "C" #define PIN_A3 (17ul) #define PIN_A4 (18ul) #define PIN_A5 (19ul) +#define PIN_A6 (8ul) +#define PIN_A7 (9ul) static const uint8_t A0 = PIN_A0 ; static const uint8_t A1 = PIN_A1 ; @@ -100,6 +102,8 @@ static const uint8_t A2 = PIN_A2 ; static const uint8_t A3 = PIN_A3 ; static const uint8_t A4 = PIN_A4 ; static const uint8_t A5 = PIN_A5 ; +static const uint8_t A6 = PIN_A6 ; +static const uint8_t A7 = PIN_A7 ; #define ADC_RESOLUTION 12 // Other pins From f851644783ffb9070534b09a8b2915c4c052fd9e Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 31 Oct 2015 23:00:46 -0400 Subject: [PATCH 05/22] bootloader with different VID/PID --- bootloaders/zero/drivers/cdc_enumerate.c | 4 ++-- bootloaders/zero/samd21_sam_ba.bin | Bin 6328 -> 6480 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootloaders/zero/drivers/cdc_enumerate.c b/bootloaders/zero/drivers/cdc_enumerate.c index bd3873eb2..96d0c6531 100644 --- a/bootloaders/zero/drivers/cdc_enumerate.c +++ b/bootloaders/zero/drivers/cdc_enumerate.c @@ -50,9 +50,9 @@ const char devDescriptor[] = { 0x00, // bDeviceSubclass: CDC class sub code 0x00, // bDeviceProtocol: CDC Device protocol 0x40, // bMaxPacketSize0 - 0x41, // idVendorL + 0x9A, // idVendorL (adafruit) 0x23, // - 0x4D, // idProductL + 0x0B, // idProductL (feather zero) 0x00, // 0x10, // bcdDeviceL 0x01, // diff --git a/bootloaders/zero/samd21_sam_ba.bin b/bootloaders/zero/samd21_sam_ba.bin index 08f40f425437f8fc80c2462668f3d15bdf5453d5..74cf2de8f94f2f8f4b202d46ba1764d00fce0d9c 100644 GIT binary patch delta 1748 zcmcJP`)?FQ9KdJxy6xSy*Y@b^Zf{F>Z>zMuhTfG|DaN)(?c>I_B1E7>*s4vYG2&rB z4i$UQs^t~h4obOJg8?EnBG9G+KUAt>d_la!kf^A+MzmlAFCn2QN7wJR68#6<wp^W8b^374iGRgiSuh|slZdaRCiG^4;Y{meM-1^oXrKb^4WSe|JGLXuuWyyue3 z6t^L?3Jh^(!q?ifi4ef07l#CYCP76)B(omnr>s<$ie1Pa97-6{it!J&AQ#mnThQo7 z`L=ba!0(?h=&B7 z7x|Fd+*0DRiPiviTH7n<668dM=7>m(efzvPVpp@Hf?DLm<)|ng5!6B=(B)!EIH+9a zJ6eKDKX%ZLo5rqu5|nq~18RD$Hd(C61Um))*_-S3KJfvHRo}s}-rKo^lZ8NnxO1uC z4>}!CSV+Z^Hu;Knh)QB#Z4N;NB{;0VC#iNEk;Wf&B}NYV6q-)o@~vrav(oJGCKn$WAR(WF&Z2@pZM+Wj zKJvzl9!wfv3Hmy9*ly0CC*azeTy8*p%^p0AgcNXv%a1dApJO#{$ zm`VUuqAKo)rac3;0K`{=oB(V9eG{-5coDFQ?!})ErSe+ z<6o0b#NfBRSBM)H)~hUL*OMN~8@n5y7^|_tB6>1CX&Imwpcn0C%Zw!J_4w3;e!0LS z=@*QC>l|h$jmNY4ASRDP(gBzU014z=w#l>~zt1e@HKtt9LtvlHHkhBrx$H-?Hf@`& z+u1M4>^~9PQaVh1u<`(Kg;^~9ye{PrAG4%kJita%74w-iga$1LN21|&c(5mI@-y4GIDSy8_ZB(ypZ95@mj_l7_FI$ zV64w9!ROeP%>7tq)~pK4RY-D=-`V3?wXGI2LLNW{T7h<8Q!+F}3PR7r**878QJUwG zO5L6X$n7qlzo>kE8Cqqwpw&P#Qeb=#dFFcHRFE|jp+cYvXa%U*|UkhMw0btu2HWxGePPg zG@kWpD)q8g<kPt!B4ZWhu=Vb8;_l3_NN)v|uim&t1Fg1b)p zCQ;dbqGfQgjSVL4ay=vSpV#KgN0WvfOq`$d z62F@jkFu~eyNB+MOU&e#cA7PPY+~Zq(GRi64*C&hi~JHZYY+0V@QmzM>Sp>_Q17Bs zN4t&M|2@q#KPOOOUHm|79k*M2!m{M@R>rF=^GJfPvec6#AGD|>&M#Yhjs|K^+c*DQ zJbn$-7xQ$r0$-amv$V{XLF*@KEY>FWIJCP1#4(Ou*M zQtAS@h&F>fhoV{p7C?jPxUOHvTsyw75d9+LCdN7B7LpfviS;dy=}z&f!ugTrC-scl z#$IOft=1;r#lOe%BhA}UZY*gm9YKsT#@>Sbwv~z}#wYT|t;9z$Zl-Zv5Ar74*Wy0Z z%rJq{gSHQGqc3t>$$sMHM@m-MM2vee@8W{}9U}7g?D}NRW#swBQvM%>=;*TT!;nOY5*uIt?gaZ%ZfemxX= zFxQJXvG@kGDTJ5-Oo(3rcoTI;{OAV&c}<_5KupK~|#dY1eHSWBPa From def75fadf6611d13db00dc77125db0f1f90ec8f2 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Tue, 17 Nov 2015 16:06:00 -0500 Subject: [PATCH 06/22] adds bootloaders/feather --- bootloaders/feather/Makefile | 29 + bootloaders/feather/drivers/cdc_enumerate.c | 765 +++++++++++ bootloaders/feather/drivers/cdc_enumerate.h | 126 ++ bootloaders/feather/drivers/uart_driver.c | 129 ++ bootloaders/feather/drivers/uart_driver.h | 107 ++ bootloaders/feather/main.c | 343 +++++ bootloaders/feather/main.h | 69 + bootloaders/feather/readme.txt | 21 + bootloaders/feather/sam_ba_monitor.c | 455 +++++++ bootloaders/feather/sam_ba_monitor.h | 77 ++ bootloaders/feather/samd21_sam_ba.bin | Bin 0 -> 6480 bytes bootloaders/feather/samd21j18a_flash.ld | 157 +++ bootloaders/feather/startup_samd21.c | 201 +++ bootloaders/feather/usart_sam_ba.c | 513 ++++++++ bootloaders/feather/usart_sam_ba.h | 155 +++ bootloaders/feather/utils/compiler.h | 1157 +++++++++++++++++ bootloaders/feather/utils/interrupt.h | 117 ++ .../utils/interrupt/interrupt_sam_nvic.c | 69 + .../utils/interrupt/interrupt_sam_nvic.h | 172 +++ .../feather/utils/preprocessor/mrecursion.h | 581 +++++++++ .../feather/utils/preprocessor/mrepeat.h | 321 +++++ .../feather/utils/preprocessor/preprocessor.h | 38 + .../feather/utils/preprocessor/stringz.h | 67 + .../feather/utils/preprocessor/tpaste.h | 85 ++ bootloaders/feather/utils/status_codes.h | 138 ++ 25 files changed, 5892 insertions(+) create mode 100644 bootloaders/feather/Makefile create mode 100644 bootloaders/feather/drivers/cdc_enumerate.c create mode 100644 bootloaders/feather/drivers/cdc_enumerate.h create mode 100644 bootloaders/feather/drivers/uart_driver.c create mode 100644 bootloaders/feather/drivers/uart_driver.h create mode 100644 bootloaders/feather/main.c create mode 100644 bootloaders/feather/main.h create mode 100644 bootloaders/feather/readme.txt create mode 100644 bootloaders/feather/sam_ba_monitor.c create mode 100644 bootloaders/feather/sam_ba_monitor.h create mode 100644 bootloaders/feather/samd21_sam_ba.bin create mode 100644 bootloaders/feather/samd21j18a_flash.ld create mode 100644 bootloaders/feather/startup_samd21.c create mode 100644 bootloaders/feather/usart_sam_ba.c create mode 100644 bootloaders/feather/usart_sam_ba.h create mode 100644 bootloaders/feather/utils/compiler.h create mode 100644 bootloaders/feather/utils/interrupt.h create mode 100644 bootloaders/feather/utils/interrupt/interrupt_sam_nvic.c create mode 100644 bootloaders/feather/utils/interrupt/interrupt_sam_nvic.h create mode 100644 bootloaders/feather/utils/preprocessor/mrecursion.h create mode 100644 bootloaders/feather/utils/preprocessor/mrepeat.h create mode 100644 bootloaders/feather/utils/preprocessor/preprocessor.h create mode 100644 bootloaders/feather/utils/preprocessor/stringz.h create mode 100644 bootloaders/feather/utils/preprocessor/tpaste.h create mode 100644 bootloaders/feather/utils/status_codes.h diff --git a/bootloaders/feather/Makefile b/bootloaders/feather/Makefile new file mode 100644 index 000000000..1531b592e --- /dev/null +++ b/bootloaders/feather/Makefile @@ -0,0 +1,29 @@ +IDE_PATH=../../../../.. +ARM_GCC_PATH=$(IDE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin +CC=$(ARM_GCC_PATH)/arm-none-eabi-gcc +CFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -c -g -Os -w -std=gnu99 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 +LDFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols +BLD_EXTA_FLAGS=-D__SAMD21G18A__ +BUILD_PATH=build +INCLUDES=-I$(IDE_PATH)/tools/CMSIS/CMSIS/Include/ -I$(IDE_PATH)/tools/CMSIS/4.0.0-atmel/Device/ATMEL/ -I$(IDE_PATH)/tools/CMSIS/4.0.0-atmel/CMSIS/Include/ -I./drivers/ -I./utils/ -I./utils/preprocessor/ -I./utils/interrupt +SOURCES=main.c sam_ba_monitor.c startup_samd21.c usart_sam_ba.c drivers/cdc_enumerate.c drivers/uart_driver.c utils/interrupt/interrupt_sam_nvic.c +OBJECTS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.o)) + +NAME=samd21_sam_ba +EXECUTABLE=$(NAME).bin + +SLASH=/ +BSLASH=$(EMPTY)\$(EMPTY) + +all: $(SOURCES) $(EXECUTABLE) + +$(EXECUTABLE): $(OBJECTS) + $(CC) -L$(BUILD_PATH) $(LDFLAGS) -Os -Wl,--gc-sections -save-temps -Tsamd21j18a_flash.ld -Wl,-Map,$(BUILD_PATH)/$(NAME).map --specs=nano.specs --specs=nosys.specs -o $(BUILD_PATH)/$(NAME).elf $(OBJECTS) -Wl,--start-group -lm -Wl,--end-group + $(ARM_GCC_PATH)/arm-none-eabi-objcopy -O binary $(BUILD_PATH)/$(NAME).elf $@ + +$(BUILD_PATH)/%.o: %.c + -@mkdir -p $(@D) + $(CC) $(CFLAGS) $(BLD_EXTA_FLAGS) $(INCLUDES) $< -o $@ + +clean: + del $(EXECUTABLE) $(subst /,\,$(OBJECTS)) $(subst /,\,$(BUILD_PATH)/$(NAME).*) diff --git a/bootloaders/feather/drivers/cdc_enumerate.c b/bootloaders/feather/drivers/cdc_enumerate.c new file mode 100644 index 000000000..96d0c6531 --- /dev/null +++ b/bootloaders/feather/drivers/cdc_enumerate.c @@ -0,0 +1,765 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#include "cdc_enumerate.h" +#include +#include +#include + + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +COMPILER_WORD_ALIGNED UsbDeviceDescriptor usb_endpoint_table[MAX_EP] = {0}; +COMPILER_WORD_ALIGNED uint8_t udd_ep_out_cache_buffer[2][64]; //1 for CTRL, 1 for BULK +COMPILER_WORD_ALIGNED uint8_t udd_ep_in_cache_buffer[2][64]; //1 for CTRL, 1 for BULK + +COMPILER_WORD_ALIGNED +const char devDescriptor[] = { + /* Device descriptor */ + 0x12, // bLength + 0x01, // bDescriptorType + 0x10, // bcdUSBL + 0x01, // + 0x02, // bDeviceClass: CDC class code + 0x00, // bDeviceSubclass: CDC class sub code + 0x00, // bDeviceProtocol: CDC Device protocol + 0x40, // bMaxPacketSize0 + 0x9A, // idVendorL (adafruit) + 0x23, // + 0x0B, // idProductL (feather zero) + 0x00, // + 0x10, // bcdDeviceL + 0x01, // + 0x00, // iManufacturer // 0x01 + 0x00, // iProduct + 0x00, // SerialNumber + 0x01 // bNumConfigs +}; + +COMPILER_WORD_ALIGNED +char cfgDescriptor[] = { + /* ============== CONFIGURATION 1 =========== */ + /* Configuration 1 descriptor */ + 0x09, // CbLength + 0x02, // CbDescriptorType + 0x43, // CwTotalLength 2 EP + Control + 0x00, + 0x02, // CbNumInterfaces + 0x01, // CbConfigurationValue + 0x00, // CiConfiguration + 0xC0, // CbmAttributes 0xA0 + 0x00, // CMaxPower + + /* Communication Class Interface Descriptor Requirement */ + 0x09, // bLength + 0x04, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x01, // bNumEndpoints + 0x02, // bInterfaceClass + 0x02, // bInterfaceSubclass + 0x00, // bInterfaceProtocol + 0x00, // iInterface + + /* Header Functional Descriptor */ + 0x05, // bFunction Length + 0x24, // bDescriptor type: CS_INTERFACE + 0x00, // bDescriptor subtype: Header Func Desc + 0x10, // bcdCDC:1.1 + 0x01, + + /* ACM Functional Descriptor */ + 0x04, // bFunctionLength + 0x24, // bDescriptor Type: CS_INTERFACE + 0x02, // bDescriptor Subtype: ACM Func Desc + 0x00, // bmCapabilities + + /* Union Functional Descriptor */ + 0x05, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x06, // bDescriptor Subtype: Union Func Desc + 0x00, // bMasterInterface: Communication Class Interface + 0x01, // bSlaveInterface0: Data Class Interface + + /* Call Management Functional Descriptor */ + 0x05, // bFunctionLength + 0x24, // bDescriptor Type: CS_INTERFACE + 0x01, // bDescriptor Subtype: Call Management Func Desc + 0x00, // bmCapabilities: D1 + D0 + 0x01, // bDataInterface: Data Class Interface 1 + + /* Endpoint 1 descriptor */ + 0x07, // bLength + 0x05, // bDescriptorType + 0x83, // bEndpointAddress, Endpoint 03 - IN + 0x03, // bmAttributes INT + 0x08, // wMaxPacketSize + 0x00, + 0xFF, // bInterval + + /* Data Class Interface Descriptor Requirement */ + 0x09, // bLength + 0x04, // bDescriptorType + 0x01, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + 0x0A, // bInterfaceClass + 0x00, // bInterfaceSubclass + 0x00, // bInterfaceProtocol + 0x00, // iInterface + + /* First alternate setting */ + /* Endpoint 1 descriptor */ + 0x07, // bLength + 0x05, // bDescriptorType + 0x81, // bEndpointAddress, Endpoint 01 - IN + 0x02, // bmAttributes BULK + USB_EP_IN_SIZE, // wMaxPacketSize + 0x00, + 0x00, // bInterval + + /* Endpoint 2 descriptor */ + 0x07, // bLength + 0x05, // bDescriptorType + 0x02, // bEndpointAddress, Endpoint 02 - OUT + 0x02, // bmAttributes BULK + USB_EP_OUT_SIZE, // wMaxPacketSize + 0x00, + 0x00 // bInterval +}; + + +static usb_cdc_line_coding_t line_coding = { + 115200, // baudrate + 0, // 1 Stop Bit + 0, // None Parity + 8 // 8 Data bits +}; + +static USB_CDC pCdc; + +/* USB standard request code */ +#define STD_GET_STATUS_ZERO 0x0080 +#define STD_GET_STATUS_INTERFACE 0x0081 +#define STD_GET_STATUS_ENDPOINT 0x0082 + +#define STD_CLEAR_FEATURE_ZERO 0x0100 +#define STD_CLEAR_FEATURE_INTERFACE 0x0101 +#define STD_CLEAR_FEATURE_ENDPOINT 0x0102 + +#define STD_SET_FEATURE_ZERO 0x0300 +#define STD_SET_FEATURE_INTERFACE 0x0301 +#define STD_SET_FEATURE_ENDPOINT 0x0302 + +#define STD_SET_ADDRESS 0x0500 +#define STD_GET_DESCRIPTOR 0x0680 +#define STD_SET_DESCRIPTOR 0x0700 +#define STD_GET_CONFIGURATION 0x0880 +#define STD_SET_CONFIGURATION 0x0900 +#define STD_GET_INTERFACE 0x0A81 +#define STD_SET_INTERFACE 0x0B01 +#define STD_SYNCH_FRAME 0x0C82 + +/* CDC Class Specific Request Code */ +#define GET_LINE_CODING 0x21A1 +#define SET_LINE_CODING 0x2021 +#define SET_CONTROL_LINE_STATE 0x2221 + + +static uint8_t USB_IsConfigured(P_USB_CDC pCdc); +static uint32_t USB_Read(P_USB_CDC pCdc, char *pData, uint32_t length); +static uint32_t USB_Write(P_USB_CDC pCdc, const char *pData, uint32_t length, uint8_t ep_num); +static void AT91F_CDC_Enumerate(P_USB_CDC pCdc); + + +/** + * \fn AT91F_InitUSB + * + * \brief Initializes USB + */ +void AT91F_InitUSB(void) +{ + uint32_t pad_transn, pad_transp, pad_trim; + + /* Enable USB clock */ + PM->APBBMASK.reg |= PM_APBBMASK_USB; + + /* Set up the USB DP/DN pins */ + PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); + PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); + PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); + PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); + + /* Setup clock for module */ + GCLK_CLKCTRL_Type clkctrl={0}; + uint16_t temp; + /* GCLK_ID - USB - 0x06 */ + GCLK->CLKCTRL.bit.ID = 0x06; + temp = GCLK->CLKCTRL.reg; + clkctrl.bit.CLKEN = true; + clkctrl.bit.WRTLOCK = false; + clkctrl.bit.GEN = GCLK_CLKCTRL_GEN_GCLK1_Val; + GCLK->CLKCTRL.reg = (clkctrl.reg | temp); + + /* Reset */ + USB->HOST.CTRLA.bit.SWRST = 1; + while (USB->HOST.SYNCBUSY.bit.SWRST) { + /* Sync wait */ + } + + /* Load Pad Calibration */ + pad_transn =( *((uint32_t *)(NVMCTRL_OTP4) + + (NVM_USB_PAD_TRANSN_POS / 32)) + >> (NVM_USB_PAD_TRANSN_POS % 32)) + & ((1 << NVM_USB_PAD_TRANSN_SIZE) - 1); + + if (pad_transn == 0x1F) { + pad_transn = 5; + } + + USB->HOST.PADCAL.bit.TRANSN = pad_transn; + + pad_transp =( *((uint32_t *)(NVMCTRL_OTP4) + + (NVM_USB_PAD_TRANSP_POS / 32)) + >> (NVM_USB_PAD_TRANSP_POS % 32)) + & ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1); + + if (pad_transp == 0x1F) { + pad_transp = 29; + } + + USB->HOST.PADCAL.bit.TRANSP = pad_transp; + pad_trim =( *((uint32_t *)(NVMCTRL_OTP4) + + (NVM_USB_PAD_TRIM_POS / 32)) + >> (NVM_USB_PAD_TRIM_POS % 32)) + & ((1 << NVM_USB_PAD_TRIM_SIZE) - 1); + + if (pad_trim == 0x7) { + pad_trim = 3; + } + + USB->HOST.PADCAL.bit.TRIM = pad_trim; + + /* Set the configuration */ + /* Set mode to Device mode */ + USB->HOST.CTRLA.bit.MODE = 0; + /* Enable Run in Standby */ + USB->HOST.CTRLA.bit.RUNSTDBY = true; + /* Set the descriptor address */ + USB->HOST.DESCADD.reg = (uint32_t)(&usb_endpoint_table[0]); + /* Set speed configuration to Full speed */ + USB->DEVICE.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val; + /* Attach to the USB host */ + USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH; + + /* Initialize endpoint table RAM location to a known value 0 */ + memset((uint8_t *)(&usb_endpoint_table[0]), 0, + sizeof(usb_endpoint_table)); +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_CDC_Open +//* \brief +//*---------------------------------------------------------------------------- +P_USB_CDC AT91F_CDC_Open(P_USB_CDC pCdc,Usb *pUsb) +{ + pCdc->pUsb = pUsb; + pCdc->currentConfiguration = 0; + pCdc->currentConnection = 0; + pCdc->IsConfigured = USB_IsConfigured; + pCdc->Write = USB_Write; + pCdc->Read = USB_Read; + pCdc->pUsb->HOST.CTRLA.bit.ENABLE = true; + return pCdc; +} + +//*---------------------------------------------------------------------------- +//* \fn USB_IsConfigured +//* \brief Test if the device is configured and handle enumerationDEVICE.DeviceEndpoint[ep_num].EPCFG.bit.EPTYPE1 +//*---------------------------------------------------------------------------- +static uint8_t USB_IsConfigured(P_USB_CDC pCdc) +{ + Usb *pUsb = pCdc->pUsb; + + /* Check for End of Reset flag */ + if (pUsb->DEVICE.INTFLAG.reg & USB_DEVICE_INTFLAG_EORST) { + /* Clear the flag */ + pUsb->DEVICE.INTFLAG.bit.EORST = true; + /* Set Device address as 0 */ + pUsb->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | 0; + /* Configure endpoint 0 */ + /* Configure Endpoint 0 for Control IN and Control OUT */ + pUsb->DEVICE.DeviceEndpoint[0].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(1) | USB_DEVICE_EPCFG_EPTYPE1(1); + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; + /* Configure control OUT Packet size to 64 bytes */ + usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.SIZE = 3; + /* Configure control IN Packet size to 64 bytes */ + usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.SIZE = 3; + /* Configure the data buffer address for control OUT */ + usb_endpoint_table[0].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[0]; + /* Configure the data buffer address for control IN */ + usb_endpoint_table[0].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[0]; + /* Set Multipacket size to 8 for control OUT and byte count to 0*/ + usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 8; + usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY; + + // Reset current configuration value to 0 + pCdc->currentConfiguration = 0; + } else if (pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_RXSTP) { + AT91F_CDC_Enumerate(pCdc); + } + + return pCdc->currentConfiguration; +} + + +static volatile bool read_job = false; +//*---------------------------------------------------------------------------- +//* \fn USB_Read +//* \brief Read available data from Endpoint OUT +//*---------------------------------------------------------------------------- +static uint32_t USB_Read(P_USB_CDC pCdc, char *pData, uint32_t length) +{ + Usb *pUsb = pCdc->pUsb; + uint32_t packetSize = 0; + + if (!read_job) { + /* Set the buffer address for ep data */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[USB_EP_OUT-1]; + /* Set the byte count as zero */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; + /* Set the byte count as zero */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 0; + /* Start the reception by clearing the bank 0 ready bit */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSCLR.bit.BK0RDY = true; + /* set the user flag */ + read_job = true; + } + + /* Check for Transfer Complete 0 flag */ + if ( pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0) ) { + /* Set packet size */ + packetSize = MIN(usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT, length); + /* Copy read data to user buffer */ + memcpy(pData, udd_ep_out_cache_buffer[USB_EP_OUT-1], packetSize); + /* Clear the Transfer Complete 0 flag */ + //pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT0 = true; + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT |= (1 << 0); + /* Clear the user flag */ + read_job = false; + } + + return packetSize; +} + +static uint32_t USB_Read_blocking(P_USB_CDC pCdc, char *pData, uint32_t length) +{ + Usb *pUsb = pCdc->pUsb; + + if (read_job) { + /* Stop the reception by setting the bank 0 ready bit */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSSET.bit.BK0RDY = true; + /* Clear the user flag */ + read_job = false; + } + + /* Set the buffer address for ep data */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = ((uint32_t)pData); + /* Set the byte count as zero */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; + /* Set the multi packet size as zero for multi-packet transfers where length > ep size */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = length; + /* Clear the bank 0 ready flag */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSCLR.bit.BK0RDY = true; + /* Wait for transfer to complete */ + while (!( pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0) )); + /* Clear Transfer complete 0 flag */ + //pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT0 = true; + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT |= (1 << 0); + + return length; + +} + + +static uint32_t USB_Write(P_USB_CDC pCdc, const char *pData, uint32_t length, uint8_t ep_num) +{ + Usb *pUsb = pCdc->pUsb; + uint32_t data_address; + uint8_t buf_index; + + /* Set buffer index */ + buf_index = (ep_num == 0) ? 0 : 1; + + /* Check for requirement for multi-packet or auto zlp */ + if (length >= (1 << (usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.SIZE + 3))) { + /* Update the EP data address */ + data_address = (uint32_t) pData; + /* Enable auto zlp */ + usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = true; + } else { + /* Copy to local buffer */ + memcpy(udd_ep_in_cache_buffer[buf_index], pData, length); + /* Update the EP data address */ + data_address = (uint32_t) &udd_ep_in_cache_buffer[buf_index]; + } + + /* Set the buffer address for ep data */ + usb_endpoint_table[ep_num].DeviceDescBank[1].ADDR.reg = data_address; + /* Set the byte count as zero */ + usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = length; + /* Set the multi packet size as zero for multi-packet transfers where length > ep size */ + usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = 0; + /* Clear the transfer complete flag */ + //pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT1 = true; + pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT |= (1 << 1); + /* Set the bank as ready */ + pUsb->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.bit.BK1RDY = true; + + /* Wait for transfer to complete */ + while (!( pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT & (1<<1) )); + + return length; +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_USB_SendData +//* \brief Send Data through the control endpoint +//*---------------------------------------------------------------------------- + +static void AT91F_USB_SendData(P_USB_CDC pCdc, const char *pData, uint32_t length) +{ + USB_Write(pCdc, pData, length, 0); +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_USB_SendZlp +//* \brief Send zero length packet through the control endpoint +//*---------------------------------------------------------------------------- +void AT91F_USB_SendZlp(Usb *pUsb) +{ + /* Set the byte count as zero */ + usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = 0; + /* Clear the transfer complete flag */ + //pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT1 = true; + pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT |= (1 << 1); + /* Set the bank as ready */ + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.BK1RDY = true; + /* Wait for transfer to complete */ + while (!( pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT & (1<<1) )); +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_USB_SendStall +//* \brief Stall the control endpoint +//*---------------------------------------------------------------------------- +void AT91F_USB_SendStall(Usb *pUsb, bool direction_in) +{ + /* Check the direction */ + if (direction_in) { + /* Set STALL request on IN direction */ + //pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.STALLRQ = (1<<1); + } else { + /* Set STALL request on OUT direction */ + //pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.STALLRQ = (1<<0); + } +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_CDC_Enumerate +//* \brief This function is a callback invoked when a SETUP packet is received +//*---------------------------------------------------------------------------- +void AT91F_CDC_Enumerate(P_USB_CDC pCdc) +{ + Usb *pUsb = pCdc->pUsb; + static volatile uint8_t bmRequestType, bRequest, dir; + static volatile uint16_t wValue, wIndex, wLength, wStatus; + + /* Clear the Received Setup flag */ + pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP = true; + + /* Read the USB request parameters */ + bmRequestType = udd_ep_out_cache_buffer[0][0]; + bRequest = udd_ep_out_cache_buffer[0][1]; + wValue = (udd_ep_out_cache_buffer[0][2] & 0xFF); + wValue |= (udd_ep_out_cache_buffer[0][3] << 8); + wIndex = (udd_ep_out_cache_buffer[0][4] & 0xFF); + wIndex |= (udd_ep_out_cache_buffer[0][5] << 8); + wLength = (udd_ep_out_cache_buffer[0][6] & 0xFF); + wLength |= (udd_ep_out_cache_buffer[0][7] << 8); + + /* Clear the Bank 0 ready flag on Control OUT */ + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY; + + /* Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1 */ + switch ((bRequest << 8) | bmRequestType) { + case STD_GET_DESCRIPTOR: + if (wValue == 0x100) + /* Return Device Descriptor */ + AT91F_USB_SendData(pCdc, devDescriptor, MIN(sizeof(devDescriptor), wLength)); + else if (wValue == 0x200) + /* Return Configuration Descriptor */ + AT91F_USB_SendData(pCdc, cfgDescriptor, MIN(sizeof(cfgDescriptor), wLength)); + else + /* Stall the request */ + AT91F_USB_SendStall(pUsb, true); + break; + case STD_SET_ADDRESS: + /* Send ZLP */ + AT91F_USB_SendZlp(pUsb); + /* Set device address to the newly received address from host */ + pUsb->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | wValue; + break; + case STD_SET_CONFIGURATION: + /* Store configuration */ + pCdc->currentConfiguration = (uint8_t)wValue; + /* Send ZLP */ + AT91F_USB_SendZlp(pUsb); + /* Configure BULK OUT endpoint for CDC Data interface*/ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(3); + /* Set maximum packet size as 64 bytes */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.SIZE = 3; + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; + /* Configure the data buffer */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[1]; + /* Configure BULK IN endpoint for CDC Data interface */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_IN].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(3); + /* Set maximum packet size as 64 bytes */ + usb_endpoint_table[USB_EP_IN].DeviceDescBank[1].PCKSIZE.bit.SIZE = 3; + pUsb->DEVICE.DeviceEndpoint[USB_EP_IN].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; + /* Configure the data buffer */ + usb_endpoint_table[USB_EP_IN].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[1]; + /* Configure INTERRUPT IN endpoint for CDC COMM interface*/ + pUsb->DEVICE.DeviceEndpoint[USB_EP_COMM].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(4); + /* Set maximum packet size as 64 bytes */ + usb_endpoint_table[USB_EP_COMM].DeviceDescBank[1].PCKSIZE.bit.SIZE = 0; + pUsb->DEVICE.DeviceEndpoint[USB_EP_COMM].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; + break; + case STD_GET_CONFIGURATION: + /* Return current configuration value */ + AT91F_USB_SendData(pCdc, (char *) &(pCdc->currentConfiguration), sizeof(pCdc->currentConfiguration)); + break; + case STD_GET_STATUS_ZERO: + wStatus = 0; + AT91F_USB_SendData(pCdc, (char *) &wStatus, sizeof(wStatus)); + break; + case STD_GET_STATUS_INTERFACE: + wStatus = 0; + AT91F_USB_SendData(pCdc, (char *) &wStatus, sizeof(wStatus)); + break; + case STD_GET_STATUS_ENDPOINT: + wStatus = 0; + dir = wIndex & 80; + wIndex &= 0x0F; + if (wIndex <= 3) { + if (dir) { + //wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ1) ? 1 : 0; + wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<1)) ? 1 : 0; + } else { + //wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ0) ? 1 : 0; + wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<0)) ? 1 : 0; + } + /* Return current status of endpoint */ + AT91F_USB_SendData(pCdc, (char *) &wStatus, sizeof(wStatus)); + } + else + /* Stall the request */ + AT91F_USB_SendStall(pUsb, true); + break; + case STD_SET_FEATURE_ZERO: + /* Stall the request */ + AT91F_USB_SendStall(pUsb, true); + break; + case STD_SET_FEATURE_INTERFACE: + /* Send ZLP */ + AT91F_USB_SendZlp(pUsb); + break; + case STD_SET_FEATURE_ENDPOINT: + dir = wIndex & 0x80; + wIndex &= 0x0F; + if ((wValue == 0) && wIndex && (wIndex <= 3)) { + /* Set STALL request for the endpoint */ + if (dir) { + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.bit.STALLRQ = (1<<1); + } else { + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.bit.STALLRQ = (1<<0); + } + /* Send ZLP */ + AT91F_USB_SendZlp(pUsb); + } + else + /* Stall the request */ + AT91F_USB_SendStall(pUsb, true); + break; + case STD_CLEAR_FEATURE_ZERO: + /* Stall the request */ + AT91F_USB_SendStall(pUsb, true); + break; + case STD_CLEAR_FEATURE_INTERFACE: + /* Send ZLP */ + AT91F_USB_SendZlp(pUsb); + break; + case STD_CLEAR_FEATURE_ENDPOINT: + dir = wIndex & 0x80; + wIndex &= 0x0F; + if ((wValue == 0) && wIndex && (wIndex <= 3)) { + if (dir) { + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<1)) { + // Remove stall request + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.bit.STALLRQ = (1<<1); + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL & (1<<1)) { + pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL = (1<<1); + // The Stall has occurred, then reset data toggle + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_DTGLIN; + } + } + } else { + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<0)) { + // Remove stall request + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.bit.STALLRQ = (1<<0); + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL & (1<<0)) { + pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL = (1<<0); + // The Stall has occurred, then reset data toggle + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_DTGLOUT; + } + } + } + /* Send ZLP */ + AT91F_USB_SendZlp(pUsb); + } + else { + AT91F_USB_SendStall(pUsb, true); + } + break; + + // handle CDC class requests + case SET_LINE_CODING: + /* Send ZLP */ + AT91F_USB_SendZlp(pUsb); + break; + case GET_LINE_CODING: + /* Send current line coding */ + AT91F_USB_SendData(pCdc, (char *) &line_coding, MIN(sizeof(usb_cdc_line_coding_t), wLength)); + break; + case SET_CONTROL_LINE_STATE: + /* Store the current connection */ + pCdc->currentConnection = wValue; + /* Send ZLP */ + AT91F_USB_SendZlp(pUsb); + break; + default: + /* Stall the request */ + AT91F_USB_SendStall(pUsb, true); + break; + } +} + +P_USB_CDC usb_init(void) +{ + pCdc.pUsb = USB; + + /* Initialize USB */ + AT91F_InitUSB(); + /* Get the default CDC structure settings */ + AT91F_CDC_Open((P_USB_CDC)&pCdc, pCdc.pUsb); + return &pCdc; +} + +int cdc_putc(int value) +{ + /* Send single byte on USB CDC */ + USB_Write(&pCdc, (const char *)&value, 1, USB_EP_IN); + return 1; +} + +int cdc_getc(void) +{ + uint8_t rx_char; + /* Read singly byte on USB CDC */ + USB_Read(&pCdc, (char *)&rx_char, 1); + return (int)rx_char; +} + +bool cdc_is_rx_ready(void) +{ + /* Check whether the device is configured */ + if ( !USB_IsConfigured(&pCdc) ) + return 0; + + /* Return transfer complete 0 flag status */ + return (pCdc.pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0)); +} + +uint32_t cdc_write_buf(void const* data, uint32_t length) +{ + /* Send the specified number of bytes on USB CDC */ + USB_Write(&pCdc, (const char *)data, length, USB_EP_IN); + return length; +} + +uint32_t cdc_read_buf(void* data, uint32_t length) +{ + /* Check whether the device is configured */ + if ( !USB_IsConfigured(&pCdc) ) + return 0; + + /* Read from USB CDC */ + return USB_Read(&pCdc, (char *)data, length); +} + +uint32_t cdc_read_buf_xmd(void* data, uint32_t length) +{ + /* Check whether the device is configured */ + if ( !USB_IsConfigured(&pCdc) ) + return 0; + + /* Blocking read till specified number of bytes is received */ + // XXX: USB_Read_blocking is not reliable + // return USB_Read_blocking(&pCdc, (char *)data, length); + + char *dst = (char *)data; + uint32_t remaining = length; + while (remaining) { + uint32_t readed = USB_Read(&pCdc, (char *)dst, remaining); + remaining -= readed; + dst += readed; + } + + return length; +} diff --git a/bootloaders/feather/drivers/cdc_enumerate.h b/bootloaders/feather/drivers/cdc_enumerate.h new file mode 100644 index 000000000..41002626f --- /dev/null +++ b/bootloaders/feather/drivers/cdc_enumerate.h @@ -0,0 +1,126 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef CDC_ENUMERATE_H +#define CDC_ENUMERATE_H + +#include "sam.h" +#include "stdbool.h" + +#define USB_EP_OUT 2 +#define USB_EP_OUT_SIZE 0x40 +#define USB_EP_IN 1 +#define USB_EP_IN_SIZE 0x40 +#define USB_EP_COMM 3 +#define MAX_EP 4 + +#define NVM_USB_PAD_TRANSN_POS 45 +#define NVM_USB_PAD_TRANSN_SIZE 5 +#define NVM_USB_PAD_TRANSP_POS 50 +#define NVM_USB_PAD_TRANSP_SIZE 5 +#define NVM_USB_PAD_TRIM_POS 55 +#define NVM_USB_PAD_TRIM_SIZE 3 + +typedef struct _USB_CDC +{ + // Private members + Usb *pUsb; + uint8_t currentConfiguration; + uint8_t currentConnection; + // Public Methods: + uint8_t (*IsConfigured)(struct _USB_CDC *pCdc); + uint32_t (*Write) (struct _USB_CDC *pCdc, const char *pData, uint32_t length, uint8_t ep_num); + uint32_t (*Read) (struct _USB_CDC *pCdc, char *pData, uint32_t length); +} USB_CDC, *P_USB_CDC; + +typedef struct { + uint32_t dwDTERate; + uint8_t bCharFormat; + uint8_t bParityType; + uint8_t bDataBits; +} usb_cdc_line_coding_t; + +/** + * \brief Initializes the USB module + * + * \return Pointer to the USB CDC structure + */ +P_USB_CDC usb_init(void); + +/** + * \brief Sends a single byte through USB CDC + * + * \param Data to send + * \return number of data sent + */ +int cdc_putc(int value); + +/** + * \brief Reads a single byte through USB CDC + * + * \return Data read through USB + */ +int cdc_getc(void); + +/** + * \brief Checks if a character has been received on USB CDC + * + * \return \c 1 if a byte is ready to be read. + */ +bool cdc_is_rx_ready(void); + +/** + * \brief Sends buffer on USB CDC + * + * \param data pointer + * \param number of data to send + * \return number of data sent + */ +uint32_t cdc_write_buf(void const* data, uint32_t length); + +/** + * \brief Gets data on USB CDC + * + * \param data pointer + * \param number of data to read + * \return number of data read + */ +uint32_t cdc_read_buf(void* data, uint32_t length); + +/** + * \brief Gets specified number of bytes on USB CDC + * + * \param data pointer + * \param number of data to read + * \return number of data read + */ +uint32_t cdc_read_buf_xmd(void* data, uint32_t length); + + +#endif // CDC_ENUMERATE_H diff --git a/bootloaders/feather/drivers/uart_driver.c b/bootloaders/feather/drivers/uart_driver.c new file mode 100644 index 000000000..f74dc8725 --- /dev/null +++ b/bootloaders/feather/drivers/uart_driver.c @@ -0,0 +1,129 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#include "uart_driver.h" + +bool uart_drv_error_flag = false; + +uint32_t uart_get_sercom_index(Sercom *sercom_instance) +{ + /* Save all available SERCOM instances for compare. */ + Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS; + + /* Find index for sercom instance. */ + for (uint32_t i = 0; i < SERCOM_INST_NUM; i++) { + if ((uintptr_t)sercom_instance == (uintptr_t)sercom_instances[i]) { + return i; + } + } + + return 0; +} + +void uart_basic_init(Sercom *sercom, uint16_t baud_val, enum uart_pad_settings pad_conf) +{ + /* Wait for synchronization */ + while(sercom->USART.SYNCBUSY.bit.ENABLE); + /* Disable the SERCOM UART module */ + sercom->USART.CTRLA.bit.ENABLE = 0; + /* Wait for synchronization */ + while(sercom->USART.SYNCBUSY.bit.SWRST); + /* Perform a software reset */ + sercom->USART.CTRLA.bit.SWRST = 1; + /* Wait for synchronization */ + while(sercom->USART.CTRLA.bit.SWRST); + /* Wait for synchronization */ + while(sercom->USART.SYNCBUSY.bit.SWRST || sercom->USART.SYNCBUSY.bit.ENABLE); + /* Update the UART pad settings, mode and data order settings */ + sercom->USART.CTRLA.reg = pad_conf | SERCOM_USART_CTRLA_MODE(1) | SERCOM_USART_CTRLA_DORD; + /* Wait for synchronization */ + while(sercom->USART.SYNCBUSY.bit.CTRLB); + /* Enable transmit and receive and set data size to 8 bits */ + sercom->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_CHSIZE(0); + /* Load the baud value */ + sercom->USART.BAUD.reg = baud_val; + /* Wait for synchronization */ + while(sercom->USART.SYNCBUSY.bit.ENABLE); + /* Enable SERCOM UART */ + sercom->USART.CTRLA.bit.ENABLE = 1; +} + +void uart_disable(Sercom *sercom) +{ + /* Wait for synchronization */ + while(sercom->USART.SYNCBUSY.bit.ENABLE); + /* Disable SERCOM UART */ + sercom->USART.CTRLA.bit.ENABLE = 0; +} + +void uart_write_byte(Sercom *sercom, uint8_t data) +{ + /* Wait for Data Register Empty flag */ + while(!sercom->USART.INTFLAG.bit.DRE); + /* Write the data to DATA register */ + sercom->USART.DATA.reg = (uint16_t)data; +} + +uint8_t uart_read_byte(Sercom *sercom) +{ + /* Wait for Receive Complete flag */ + while(!sercom->USART.INTFLAG.bit.RXC); + /* Check for errors */ + if (sercom->USART.STATUS.bit.PERR || sercom->USART.STATUS.bit.FERR || sercom->USART.STATUS.bit.BUFOVF) + /* Set the error flag */ + uart_drv_error_flag = true; + /* Return the read data */ + return((uint8_t)sercom->USART.DATA.reg); +} + +void uart_write_buffer_polled(Sercom *sercom, uint8_t *ptr, uint16_t length) +{ + /* Do the following for specified length */ + do { + /* Wait for Data Register Empty flag */ + while(!sercom->USART.INTFLAG.bit.DRE); + /* Send data from the buffer */ + sercom->USART.DATA.reg = (uint16_t)*ptr++; + } while (length--); +} + +void uart_read_buffer_polled(Sercom *sercom, uint8_t *ptr, uint16_t length) +{ + /* Do the following for specified length */ + do { + /* Wait for Receive Complete flag */ + while(!sercom->USART.INTFLAG.bit.RXC); + /* Check for errors */ + if (sercom->USART.STATUS.bit.PERR || sercom->USART.STATUS.bit.FERR || sercom->USART.STATUS.bit.BUFOVF) + /* Set the error flag */ + uart_drv_error_flag = true; + /* Store the read data to the buffer */ + *ptr++ = (uint8_t)sercom->USART.DATA.reg; + } while (length--); +} \ No newline at end of file diff --git a/bootloaders/feather/drivers/uart_driver.h b/bootloaders/feather/drivers/uart_driver.h new file mode 100644 index 000000000..84bfe1b1a --- /dev/null +++ b/bootloaders/feather/drivers/uart_driver.h @@ -0,0 +1,107 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef UART_DRIVER_H +#define UART_DRIVER_H +#include +#include "sam.h" +#include + +#define PINMUX_UNUSED 0xFFFFFFFF +#define GCLK_ID_SERCOM0_CORE 0x14 + +/* SERCOM UART available pad settings */ +enum uart_pad_settings { + UART_RX_PAD0_TX_PAD2 = SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(1), + UART_RX_PAD1_TX_PAD2 = SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(1), + UART_RX_PAD2_TX_PAD0 = SERCOM_USART_CTRLA_RXPO(2), + UART_RX_PAD3_TX_PAD0 = SERCOM_USART_CTRLA_RXPO(3), + UART_RX_PAD1_TX_PAD0 = SERCOM_USART_CTRLA_RXPO(1), + UART_RX_PAD3_TX_PAD2 = SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(1), +}; + +/** + * \brief Gets the index of the provided SERCOM instance + * + * \param Pointer to SERCOM instance + * \return Index of the SERCOM module + */ +uint32_t uart_get_sercom_index(Sercom *sercom_instance); + +/** + * \brief Initializes the UART + * + * \param Pointer to SERCOM instance + * \param Baud value corresponding to the desired baudrate + * \param SERCOM pad settings + */ +void uart_basic_init(Sercom *sercom, uint16_t baud_val, enum uart_pad_settings pad_conf); + +/** + * \brief Disables UART interface + * + * \param Pointer to SERCOM instance + */ +void uart_disable(Sercom *sercom); + +/** + * \brief Sends a single byte through UART interface + * + * \param Pointer to SERCOM instance + * \param Data to send + */ +void uart_write_byte(Sercom *sercom, uint8_t data); + +/** + * \brief Reads a single character from UART interface + * + * \param Pointer to SERCOM instance + * \return Data byte read + */ +uint8_t uart_read_byte(Sercom *sercom); + +/** + * \brief Sends buffer on UART interface + * + * \param Pointer to SERCOM instance + * \param Pointer to data to send + * \param Number of bytes to send + */ +void uart_write_buffer_polled(Sercom *sercom, uint8_t *ptr, uint16_t length); + +/** + * \brief Reads data on UART interface + * + * \param Pointer to SERCOM instance + * \param Pointer to store read data + * \param Number of bytes to read + */ +void uart_read_buffer_polled(Sercom *sercom, uint8_t *ptr, uint16_t length); + +#endif \ No newline at end of file diff --git a/bootloaders/feather/main.c b/bootloaders/feather/main.c new file mode 100644 index 000000000..82d8b8377 --- /dev/null +++ b/bootloaders/feather/main.c @@ -0,0 +1,343 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + * -------------------- + * SAM-BA Implementation on SAMD21 + * -------------------- + * Requirements to use SAM-BA : + * + * Supported communication interfaces : + * -------------------- + * + * SERCOM5 : RX:PB23 TX:PB22 + * Baudrate : 115200 8N1 + * + * USB : D-:PA24 D+:PA25 + * + * Pins Usage + * -------------------- + * The following pins are used by the program : + * PA25 : input/output + * PA24 : input/output + * PB23 : input + * PB22 : output + * PA15 : input + * + * The application board shall avoid driving the PA25,PA24,PB23,PB22 and PA15 signals + * while the boot program is running (after a POR for example) + * + * Clock system + * -------------------- + * CPU clock source (GCLK_GEN_0) - 8MHz internal oscillator (OSC8M) + * SERCOM5 core GCLK source (GCLK_ID_SERCOM5_CORE) - GCLK_GEN_0 (i.e., OSC8M) + * GCLK Generator 1 source (GCLK_GEN_1) - 48MHz DFLL in Clock Recovery mode (DFLL48M) + * USB GCLK source (GCLK_ID_USB) - GCLK_GEN_1 (i.e., DFLL in CRM mode) + * + * Memory Mapping + * -------------------- + * SAM-BA code will be located at 0x0 and executed before any applicative code. + * + * Applications compiled to be executed along with the bootloader will start at + * 0x2000 + * Before jumping to the application, the bootloader changes the VTOR register + * to use the interrupt vectors of the application @0x2000.<- not required as + * application code is taking care of this + * +*/ + +#include +#include +#include "compiler.h" +#include "sam_ba_monitor.h" +#include "usart_sam_ba.h" +#include "main.h" +#include "cdc_enumerate.h" + +#define NVM_SW_CALIB_DFLL48M_COARSE_VAL 58 +#define NVM_SW_CALIB_DFLL48M_FINE_VAL 64 + +static void check_start_application(void); + +static volatile bool main_b_cdc_enable = false; + +/** + * \brief Check the application startup condition + * + */ +static void check_start_application(void) +{ + volatile PortGroup *led_port = (volatile PortGroup *)&PORT->Group[1]; + led_port->DIRSET.reg = (1<<30); + led_port->OUTCLR.reg = (1<<30); + +#if defined(BOOT_DOUBLE_TAP_ADDRESS) + #define DOUBLE_TAP_MAGIC 0x07738135 + if (PM->RCAUSE.bit.POR) + { + /* On power-on initialize double-tap */ + BOOT_DOUBLE_TAP_DATA = 0; + } + else + { + if (BOOT_DOUBLE_TAP_DATA == DOUBLE_TAP_MAGIC) { + /* Second tap, stay in bootloader */ + BOOT_DOUBLE_TAP_DATA = 0; + return; + } + + /* First tap */ + BOOT_DOUBLE_TAP_DATA = DOUBLE_TAP_MAGIC; + + /* Wait 0.5sec to see if the user tap reset again */ + for (uint32_t i=0; i<125000; i++) /* 500ms */ + /* force compiler to not optimize this... */ + __asm__ __volatile__(""); + + /* Timeout happened, continue boot... */ + BOOT_DOUBLE_TAP_DATA = 0; + } +#endif + + uint32_t app_start_address; + + /* Load the Reset Handler address of the application */ + app_start_address = *(uint32_t *)(APP_START_ADDRESS + 4); + + /** + * Test reset vector of application @APP_START_ADDRESS+4 + * Stay in SAM-BA if *(APP_START+0x4) == 0xFFFFFFFF + * Application erased condition + */ + if (app_start_address == 0xFFFFFFFF) { + /* Stay in bootloader */ + return; + } + +#if defined(BOOT_LOAD_PIN) + volatile PortGroup *boot_port = (volatile PortGroup *)(&(PORT->Group[BOOT_LOAD_PIN / 32])); + volatile bool boot_en; + + /* Enable the input mode in Boot GPIO Pin */ + boot_port->DIRCLR.reg = BOOT_PIN_MASK; + boot_port->PINCFG[BOOT_LOAD_PIN & 0x1F].reg = PORT_PINCFG_INEN | PORT_PINCFG_PULLEN; + boot_port->OUTSET.reg = BOOT_PIN_MASK; + /* Read the BOOT_LOAD_PIN status */ + boot_en = (boot_port->IN.reg) & BOOT_PIN_MASK; + + /* Check the bootloader enable condition */ + if (!boot_en) { + /* Stay in bootloader */ + return; + } +#endif + + led_port->OUTSET.reg = (1<<30); + + /* Rebase the Stack Pointer */ + __set_MSP(*(uint32_t *) APP_START_ADDRESS); + + /* Rebase the vector table base address */ + SCB->VTOR = ((uint32_t) APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk); + + /* Jump to application Reset Handler in the application */ + asm("bx %0"::"r"(app_start_address)); +} + +void system_init() +{ + /* Configure flash wait states */ + NVMCTRL->CTRLB.bit.RWS = FLASH_WAIT_STATES; + + /* Set OSC8M prescalar to divide by 1 */ + SYSCTRL->OSC8M.bit.PRESC = 0; + + /* Configure OSC8M as source for GCLK_GEN0 */ + GCLK_GENCTRL_Type genctrl={0}; + uint32_t temp_genctrl; + GCLK->GENCTRL.bit.ID = 0; /* GENERATOR_ID - GCLK_GEN_0 */ + while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); + temp_genctrl = GCLK->GENCTRL.reg; + genctrl.bit.SRC = GCLK_GENCTRL_SRC_OSC8M_Val; + genctrl.bit.GENEN = true; + genctrl.bit.RUNSTDBY = false; + GCLK->GENCTRL.reg = (genctrl.reg | temp_genctrl); + while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); + +#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + SYSCTRL_DFLLCTRL_Type dfllctrl_conf = {0}; + SYSCTRL_DFLLVAL_Type dfllval_conf = {0}; + uint32_t coarse =( *((uint32_t *)(NVMCTRL_OTP4) + + (NVM_SW_CALIB_DFLL48M_COARSE_VAL / 32)) + >> (NVM_SW_CALIB_DFLL48M_COARSE_VAL % 32)) + & ((1 << 6) - 1); + if (coarse == 0x3f) { + coarse = 0x1f; + } + uint32_t fine =( *((uint32_t *)(NVMCTRL_OTP4) + + (NVM_SW_CALIB_DFLL48M_FINE_VAL / 32)) + >> (NVM_SW_CALIB_DFLL48M_FINE_VAL % 32)) + & ((1 << 10) - 1); + if (fine == 0x3ff) { + fine = 0x1ff; + } + dfllval_conf.bit.COARSE = coarse; + dfllval_conf.bit.FINE = fine; + dfllctrl_conf.bit.USBCRM = true; + dfllctrl_conf.bit.BPLCKC = false; + dfllctrl_conf.bit.QLDIS = false; + dfllctrl_conf.bit.CCDIS = true; + dfllctrl_conf.bit.ENABLE = true; + + SYSCTRL->DFLLCTRL.bit.ONDEMAND = false; + while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY)); + SYSCTRL->DFLLMUL.reg = 48000; + SYSCTRL->DFLLVAL.reg = dfllval_conf.reg; + SYSCTRL->DFLLCTRL.reg = dfllctrl_conf.reg; + + GCLK_CLKCTRL_Type clkctrl={0}; + uint16_t temp; + GCLK->CLKCTRL.bit.ID = 0; /* GCLK_ID - DFLL48M Reference */ + temp = GCLK->CLKCTRL.reg; + clkctrl.bit.CLKEN = true; + clkctrl.bit.WRTLOCK = false; + clkctrl.bit.GEN = GCLK_CLKCTRL_GEN_GCLK0_Val; + GCLK->CLKCTRL.reg = (clkctrl.reg | temp); + + /* Configure DFLL48M as source for GCLK_GEN1 */ + GCLK->GENCTRL.bit.ID = 1; /* GENERATOR_ID - GCLK_GEN_1 */ + while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); + temp_genctrl = GCLK->GENCTRL.reg; + genctrl.bit.SRC = GCLK_GENCTRL_SRC_DFLL48M_Val; + genctrl.bit.GENEN = true; + genctrl.bit.RUNSTDBY = false; + GCLK->GENCTRL.reg = (genctrl.reg | temp_genctrl); + while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); +#endif +} + + +#if DEBUG_ENABLE +# define DEBUG_PIN_HIGH port_pin_set_output_level(BOOT_LED, 1) +# define DEBUG_PIN_LOW port_pin_set_output_level(BOOT_LED, 0) +#else +# define DEBUG_PIN_HIGH do{}while(0) +# define DEBUG_PIN_LOW do{}while(0) +#endif + + +/** + * \brief SAMD21 SAM-BA Main loop. + * \return Unused (ANSI-C compatibility). + */ +int main(void) +{ +#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + P_USB_CDC pCdc; +#endif + DEBUG_PIN_HIGH; + + /* Jump in application if condition is satisfied */ + check_start_application(); + + /* We have determined we should stay in the monitor. */ + /* System initialization */ + system_init(); + cpu_irq_enable(); + + #if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + /* UART is enabled in all cases */ + usart_open(); +#endif + +#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + pCdc = (P_USB_CDC)usb_init(); +#endif + DEBUG_PIN_LOW; + + // output on D13 (PA.17) + LED_PORT.PINCFG[LED_PIN].reg &= ~ (uint8_t)(PORT_PINCFG_INEN); + LED_PORT.DIRSET.reg = (uint32_t)(1 << LED_PIN); + + /* Wait for a complete enum on usb or a '#' char on serial line */ + while (1) { + pulse_led(1); // while we're waiting, blink the D13 + +#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + if (pCdc->IsConfigured(pCdc) != 0) { + main_b_cdc_enable = true; + } + + //Check if a USB enumeration has succeeded + //And com port was opened + if (main_b_cdc_enable) { + sam_ba_monitor_init(SAM_BA_INTERFACE_USBCDC); + //SAM-BA on USB loop + while(1) { + sam_ba_monitor_run(); + } + } +#endif +#if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + /* Check if a '#' has been received */ + if (!main_b_cdc_enable && usart_sharp_received()) { + sam_ba_monitor_init(SAM_BA_INTERFACE_USART); + /* SAM-BA on UART loop */ + while(1) { + sam_ba_monitor_run(); + } + } +#endif + } +} + + +// We'll have the D13 LED slowly pulse on and off with bitbang PWM +// for a nice 'hey we're in bootload mode' indication! -ada +static uint8_t pulse_tick=0; +static int8_t pulse_dir=1; +static int16_t pulse_pwm; +void pulse_led(int8_t speed) { + // blink D13 + pulse_tick++; + if (pulse_tick==0) { + pulse_pwm += pulse_dir * speed; + if (pulse_pwm > 255) { + pulse_pwm = 255; + pulse_dir = -1; + } + if (pulse_pwm < 0) { + pulse_pwm = 0; + pulse_dir = +1; + } + LED_ON; + } + if (pulse_tick==pulse_pwm) + LED_OFF; +} diff --git a/bootloaders/feather/main.h b/bootloaders/feather/main.h new file mode 100644 index 000000000..f2b10dc46 --- /dev/null +++ b/bootloaders/feather/main.h @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#pragma once + +// Gently pulse the D13 LED +#define LED_PIN 17 +#define PORTA PORT->Group[0] +#define LED_PORT PORTA + +#define LED_ON LED_PORT.OUTSET.reg = (uint32_t)(1 << LED_PIN); +#define LED_OFF LED_PORT.OUTCLR.reg = (uint32_t)(1 << LED_PIN); +/* + * If BOOT_DOUBLE_TAP_ADDRESS is defined the bootloader is started by + * quickly tapping two times on the reset button. + * BOOT_DOUBLE_TAP_ADDRESS must point to a free SRAM cell that must not + * be touched from the loaded application. + */ +#define BOOT_DOUBLE_TAP_ADDRESS 0x20007FFC +#define BOOT_DOUBLE_TAP_DATA (*((volatile uint32_t *) BOOT_DOUBLE_TAP_ADDRESS)) + +/* + * If BOOT_LOAD_PIN is defined the bootloader is started if the selected + * pin is tied LOW. + */ +//#define BOOT_LOAD_PIN PIN_PA21 // Pin 7 +//#define BOOT_LOAD_PIN PIN_PA15 // Pin 5 +#define BOOT_PIN_MASK (1U << (BOOT_LOAD_PIN & 0x1f)) + +#define CPU_FREQUENCY 8000000 +#define APP_START_ADDRESS 0x00002000 +#define FLASH_WAIT_STATES 1 + +#define BOOT_USART_MODULE SERCOM0 +//#define BOOT_USART_MODULE SERCOM5 +#define BOOT_USART_MUX_SETTINGS UART_RX_PAD3_TX_PAD2 +//#define BOOT_USART_PAD3 PINMUX_PB23D_SERCOM5_PAD3 +//#define BOOT_USART_PAD2 PINMUX_PB22D_SERCOM5_PAD2 +#define BOOT_USART_PAD3 PINMUX_PA11C_SERCOM0_PAD3 +#define BOOT_USART_PAD2 PINMUX_PA10C_SERCOM0_PAD2 +#define BOOT_USART_PAD1 PINMUX_UNUSED +#define BOOT_USART_PAD0 PINMUX_UNUSED + diff --git a/bootloaders/feather/readme.txt b/bootloaders/feather/readme.txt new file mode 100644 index 000000000..8c760449e --- /dev/null +++ b/bootloaders/feather/readme.txt @@ -0,0 +1,21 @@ +1- Prerequisites + +IAR Embedded Workbench for ARM 7.30 + +2- Selecting between USB and UART interface + +Set the define SAM_BA_INTERFACE to +SAM_BA_UART_ONLY for only UART interface +SAM_BA_USBCDC_ONLY for only USB CDC interface +SAM_BA_BOTH_INTERFACES for enabling both the interfaces + +SAM_BA_INTERFACE value should be modified in +Project Options -> C/C++ Compiler -> Preprocessor -> Defined symbols +Project Options -> Assembler -> Preprocessor -> Defined symbols + +3- Start application check + +Bootloader checks for the state of BOOT_LOAD_PIN (configurable by the user from main.h). If BOOT_LOAD_PIN is pulled low, bootloader execution is resumed. +Else, the first location of application is fetched and checked. If it is empty (0xFFFFFFFF), then bootloader execution is resumed. Else it jumps to application and starts execution from there. + +Currently, BOOT_LOAD_PIN is PA15 of SAMD21G18A, pin 5 of Arduino Zero board. diff --git a/bootloaders/feather/sam_ba_monitor.c b/bootloaders/feather/sam_ba_monitor.c new file mode 100644 index 000000000..8a81d6dac --- /dev/null +++ b/bootloaders/feather/sam_ba_monitor.c @@ -0,0 +1,455 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#include "sam.h" +#include +#include "sam_ba_monitor.h" +#include "usart_sam_ba.h" +#include "uart_driver.h" +#include "compiler.h" +#include "cdc_enumerate.h" + +const char RomBOOT_Version[] = SAM_BA_VERSION; +const char RomBOOT_ExtendedCapabilities[] = "[Arduino:XYZ]"; + +/* Provides one common interface to handle both USART and USB-CDC */ +typedef struct +{ + /* send one byte of data */ + int (*put_c)(int value); + /* Get one byte */ + int (*get_c)(void); + /* Receive buffer not empty */ + bool (*is_rx_ready)(void); + /* Send given data (polling) */ + uint32_t (*putdata)(void const* data, uint32_t length); + /* Get data from comm. device */ + uint32_t (*getdata)(void* data, uint32_t length); + /* Send given data (polling) using xmodem (if necessary) */ + uint32_t (*putdata_xmd)(void const* data, uint32_t length); + /* Get data from comm. device using xmodem (if necessary) */ + uint32_t (*getdata_xmd)(void* data, uint32_t length); +} t_monitor_if; + +#if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES +/* Initialize structures with function pointers from supported interfaces */ +const t_monitor_if uart_if = +{ usart_putc, usart_getc, usart_is_rx_ready, usart_putdata, usart_getdata, + usart_putdata_xmd, usart_getdata_xmd }; +#endif + +#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES +//Please note that USB doesn't use Xmodem protocol, since USB already includes flow control and data verification +//Data are simply forwarded without further coding. +const t_monitor_if usbcdc_if = +{ cdc_putc, cdc_getc, cdc_is_rx_ready, cdc_write_buf, + cdc_read_buf, cdc_write_buf, cdc_read_buf_xmd }; +#endif + +/* The pointer to the interface object use by the monitor */ +t_monitor_if * ptr_monitor_if; + +/* b_terminal_mode mode (ascii) or hex mode */ +volatile bool b_terminal_mode = false; +volatile bool b_sam_ba_interface_usart = false; + +void sam_ba_monitor_init(uint8_t com_interface) +{ +#if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + //Selects the requested interface for future actions + if (com_interface == SAM_BA_INTERFACE_USART) { + ptr_monitor_if = (t_monitor_if*) &uart_if; + b_sam_ba_interface_usart = true; + } +#endif +#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + if (com_interface == SAM_BA_INTERFACE_USBCDC) { + ptr_monitor_if = (t_monitor_if*) &usbcdc_if; + } +#endif +} + +/** + * \brief This function allows data rx by USART + * + * \param *data Data pointer + * \param length Length of the data + */ +void sam_ba_putdata_term(uint8_t* data, uint32_t length) +{ + uint8_t temp, buf[12], *data_ascii; + uint32_t i, int_value; + + if (b_terminal_mode) + { + if (length == 4) + int_value = *(uint32_t *) data; + else if (length == 2) + int_value = *(uint16_t *) data; + else + int_value = *(uint8_t *) data; + + data_ascii = buf + 2; + data_ascii += length * 2 - 1; + + for (i = 0; i < length * 2; i++) + { + temp = (uint8_t) (int_value & 0xf); + + if (temp <= 0x9) + *data_ascii = temp | 0x30; + else + *data_ascii = temp + 0x37; + + int_value >>= 4; + data_ascii--; + } + buf[0] = '0'; + buf[1] = 'x'; + buf[length * 2 + 2] = '\n'; + buf[length * 2 + 3] = '\r'; + ptr_monitor_if->putdata(buf, length * 2 + 4); + } + else + ptr_monitor_if->putdata(data, length); + return; +} + +volatile uint32_t sp; +void call_applet(uint32_t address) +{ + uint32_t app_start_address; + + cpu_irq_disable(); + + sp = __get_MSP(); + + /* Rebase the Stack Pointer */ + __set_MSP(*(uint32_t *) address); + + /* Load the Reset Handler address of the application */ + app_start_address = *(uint32_t *)(address + 4); + + /* Jump to application Reset Handler in the application */ + asm("bx %0"::"r"(app_start_address)); +} + + +uint32_t current_number; +uint32_t i, length; +uint8_t command, *ptr_data, *ptr, data[SIZEBUFMAX]; +uint8_t j; +uint32_t u32tmp; + +uint32_t PAGE_SIZE, PAGES, MAX_FLASH; + +/** + * \brief This function starts the SAM-BA monitor. + */ +void sam_ba_monitor_run(void) +{ + uint32_t pageSizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024 }; + PAGE_SIZE = pageSizes[NVMCTRL->PARAM.bit.PSZ]; + PAGES = NVMCTRL->PARAM.bit.NVMP; + MAX_FLASH = PAGE_SIZE * PAGES; + + ptr_data = NULL; + command = 'z'; + while (1) { + sam_ba_monitor_loop(); + } +} + +// Prints a 32-bit integer in hex. +void put_uint32(uint32_t n) { + char buff[8]; + int i; + for (i=0; i<8; i++) { + int d = n & 0XF; + n = (n >> 4); + + buff[7-i] = d > 9 ? 'A' + d - 10 : '0' + d; + } + ptr_monitor_if->putdata(buff, 8); +} + +void sam_ba_monitor_loop(void) +{ + pulse_led(3); + length = ptr_monitor_if->getdata(data, SIZEBUFMAX); + ptr = data; + for (i = 0; i < length; i++, ptr++) + { + if (*ptr == 0xff) continue; + + if (*ptr == '#') + { + if (b_terminal_mode) + { + ptr_monitor_if->putdata("\n\r", 2); + } + if (command == 'S') + { + //Check if some data are remaining in the "data" buffer + if(length>i) + { + //Move current indexes to next avail data (currently ptr points to "#") + ptr++; + i++; + //We need to add first the remaining data of the current buffer already read from usb + //read a maximum of "current_number" bytes + u32tmp=min((length-i),current_number); + memcpy(ptr_data, ptr, u32tmp); + i += u32tmp; + ptr += u32tmp; + j = u32tmp; + } + //update i with the data read from the buffer + i--; + ptr--; + //Do we expect more data ? + if(jgetdata_xmd(ptr_data, current_number-j); + + __asm("nop"); + } + else if (command == 'R') + { + ptr_monitor_if->putdata_xmd(ptr_data, current_number); + } + else if (command == 'O') + { + *ptr_data = (char) current_number; + } + else if (command == 'H') + { + *((uint16_t *) ptr_data) = (uint16_t) current_number; + } + else if (command == 'W') + { + *((int *) ptr_data) = current_number; + } + else if (command == 'o') + { + sam_ba_putdata_term(ptr_data, 1); + } + else if (command == 'h') + { + current_number = *((uint16_t *) ptr_data); + sam_ba_putdata_term((uint8_t*) ¤t_number, 2); + } + else if (command == 'w') + { + current_number = *((uint32_t *) ptr_data); + sam_ba_putdata_term((uint8_t*) ¤t_number, 4); + } + else if (command == 'G') + { + call_applet(current_number); + /* Rebase the Stack Pointer */ + __set_MSP(sp); + cpu_irq_enable(); + if (b_sam_ba_interface_usart) { + ptr_monitor_if->put_c(0x6); + } + } + else if (command == 'T') + { + b_terminal_mode = 1; + ptr_monitor_if->putdata("\n\r", 2); + } + else if (command == 'N') + { + if (b_terminal_mode == 0) + { + ptr_monitor_if->putdata("\n\r", 2); + } + b_terminal_mode = 0; + } + else if (command == 'V') + { + ptr_monitor_if->putdata("v", 1); + ptr_monitor_if->putdata((uint8_t *) RomBOOT_Version, + strlen(RomBOOT_Version)); + ptr_monitor_if->putdata(" ", 1); + ptr_monitor_if->putdata((uint8_t *) RomBOOT_ExtendedCapabilities, + strlen(RomBOOT_ExtendedCapabilities)); + ptr_monitor_if->putdata(" ", 1); + ptr = (uint8_t*) &(__DATE__); + i = 0; + while (*ptr++ != '\0') + i++; + ptr_monitor_if->putdata((uint8_t *) &(__DATE__), i); + ptr_monitor_if->putdata(" ", 1); + i = 0; + ptr = (uint8_t*) &(__TIME__); + while (*ptr++ != '\0') + i++; + ptr_monitor_if->putdata((uint8_t *) &(__TIME__), i); + ptr_monitor_if->putdata("\n\r", 2); + } + else if (command == 'X') + { + // Syntax: X[ADDR]# + // Erase the flash memory starting from ADDR to the end of flash. + + // Note: the flash memory is erased in ROWS, that is in block of 4 pages. + // Even if the starting address is the last byte of a ROW the entire + // ROW is erased anyway. + + uint32_t dst_addr = current_number; // starting address + + while (dst_addr < MAX_FLASH) { + // Execute "ER" Erase Row + NVMCTRL->ADDR.reg = dst_addr / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; + while (NVMCTRL->INTFLAG.bit.READY == 0) + ; + dst_addr += PAGE_SIZE * 4; // Skip a ROW + } + + // Notify command completed + ptr_monitor_if->putdata("X\n\r", 3); + } + else if (command == 'Y') + { + // This command writes the content of a buffer in SRAM into flash memory. + + // Syntax: Y[ADDR],0# + // Set the starting address of the SRAM buffer. + + // Syntax: Y[ROM_ADDR],[SIZE]# + // Write the first SIZE bytes from the SRAM buffer (previously set) into + // flash memory starting from address ROM_ADDR + + static uint32_t *src_buff_addr = NULL; + + if (current_number == 0) { + // Set buffer address + src_buff_addr = ptr_data; + + } else { + // Write to flash + uint32_t size = current_number/4; + uint32_t *src_addr = src_buff_addr; + uint32_t *dst_addr = ptr_data; + + // Set automatic page write + NVMCTRL->CTRLB.bit.MANW = 0; + + // Do writes in pages + while (size) { + // Execute "PBC" Page Buffer Clear + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.READY == 0) + ; + + // Fill page buffer + uint32_t i; + for (i=0; i<(PAGE_SIZE/4) && iADDR.reg = ((uint32_t)dst_addr) / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; + while (NVMCTRL->INTFLAG.bit.READY == 0) + ; + + // Advance to next page + dst_addr += i; + src_addr += i; + size -= i; + } + } + + // Notify command completed + ptr_monitor_if->putdata("Y\n\r", 3); + } + else if (command == 'Z') + { + // This command calculate CRC for a given area of memory. + // It's useful to quickly check if a transfer has been done + // successfully. + + // Syntax: Z[START_ADDR],[SIZE]# + // Returns: Z[CRC]# + + uint8_t *data = (uint8_t *)ptr_data; + uint32_t size = current_number; + uint16_t crc = 0; + uint32_t i = 0; + for (i=0; iputdata("Z", 1); + put_uint32(crc); + ptr_monitor_if->putdata("#\n\r", 3); + } + + command = 'z'; + current_number = 0; + + if (b_terminal_mode) + { + ptr_monitor_if->putdata(">", 1); + } + } + else + { + if (('0' <= *ptr) && (*ptr <= '9')) + { + current_number = (current_number << 4) | (*ptr - '0'); + } + else if (('A' <= *ptr) && (*ptr <= 'F')) + { + current_number = (current_number << 4) | (*ptr - 'A' + 0xa); + } + else if (('a' <= *ptr) && (*ptr <= 'f')) + { + current_number = (current_number << 4) | (*ptr - 'a' + 0xa); + } + else if (*ptr == ',') + { + ptr_data = (uint8_t *) current_number; + current_number = 0; + } + else + { + command = *ptr; + current_number = 0; + } + } + } +} + + + + diff --git a/bootloaders/feather/sam_ba_monitor.h b/bootloaders/feather/sam_ba_monitor.h new file mode 100644 index 000000000..c70ddb187 --- /dev/null +++ b/bootloaders/feather/sam_ba_monitor.h @@ -0,0 +1,77 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef _MONITOR_SAM_BA_H_ +#define _MONITOR_SAM_BA_H_ + +#define SAM_BA_VERSION "1.1" + +/* Enable the interfaces to save code size */ +#define SAM_BA_BOTH_INTERFACES 0 +#define SAM_BA_UART_ONLY 1 +#define SAM_BA_USBCDC_ONLY 2 + +#ifndef SAM_BA_INTERFACE +#define SAM_BA_INTERFACE SAM_BA_BOTH_INTERFACES +#endif + +/* Selects USART as the communication interface of the monitor */ +#define SAM_BA_INTERFACE_USART 1 +/* Selects USB as the communication interface of the monitor */ +#define SAM_BA_INTERFACE_USBCDC 0 + + +/* Selects USB as the communication interface of the monitor */ +#define SIZEBUFMAX 64 + +/** + * \brief Initialize the monitor + * + */ +void sam_ba_monitor_init(uint8_t com_interface); + +/** + * \brief Main function of the SAM-BA Monitor + * + */ +void sam_ba_monitor_run(void); + +/** + * \brief + * + */ +void sam_ba_putdata_term(uint8_t* data, uint32_t length); + +/** + * \brief + * + */ +void call_applet(uint32_t address); + +#endif // _MONITOR_SAM_BA_H_ diff --git a/bootloaders/feather/samd21_sam_ba.bin b/bootloaders/feather/samd21_sam_ba.bin new file mode 100644 index 0000000000000000000000000000000000000000..74cf2de8f94f2f8f4b202d46ba1764d00fce0d9c GIT binary patch literal 6480 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 rom + + /* .ARM.exidx is sorted, so has to go in its own output section. */ + PROVIDE_HIDDEN (__exidx_start = .); + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > rom + PROVIDE_HIDDEN (__exidx_end = .); + + . = ALIGN(4); + _etext = .; + + .relocate : AT (_etext) + { + . = ALIGN(4); + _srelocate = .; + *(.ramfunc .ramfunc.*); + *(.data .data.*); + . = ALIGN(4); + _erelocate = .; + } > ram + + /* .bss section which is used for uninitialized data */ + .bss (NOLOAD) : + { + . = ALIGN(4); + _sbss = . ; + _szero = .; + *(.bss .bss.*) + *(COMMON) + . = ALIGN(4); + _ebss = . ; + _ezero = .; + } > ram + + /* stack section */ + .stack (NOLOAD): + { + . = ALIGN(8); + _sstack = .; + . = . + STACK_SIZE; + . = ALIGN(8); + _estack = .; + } > ram + + . = ALIGN(4); + _end = . ; +} diff --git a/bootloaders/feather/startup_samd21.c b/bootloaders/feather/startup_samd21.c new file mode 100644 index 000000000..0f45ae3f9 --- /dev/null +++ b/bootloaders/feather/startup_samd21.c @@ -0,0 +1,201 @@ +/** + * \file + * + * \brief gcc starttup file for SAMD21 + * + * Copyright (c) 2013-2014 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#include "sam.h" + +/* Initialize segments */ +extern uint32_t _sfixed; +extern uint32_t _efixed; +extern uint32_t _etext; +extern uint32_t _srelocate; +extern uint32_t _erelocate; +extern uint32_t _szero; +extern uint32_t _ezero; +extern uint32_t _sstack; +extern uint32_t _estack; + +/** \cond DOXYGEN_SHOULD_SKIP_THIS */ +int main(void); +/** \endcond */ + +void __libc_init_array(void); + +/* Default empty handler */ +void Dummy_Handler(void); + +/* Cortex-M0+ core handlers */ +void NMI_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void HardFault_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SVC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void PendSV_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SysTick_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); + +/* Peripherals handlers */ +void PM_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SYSCTRL_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void WDT_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void RTC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EIC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void NVMCTRL_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void DMAC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void USB_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void EVSYS_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SERCOM0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SERCOM1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SERCOM2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SERCOM3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SERCOM4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void SERCOM5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TCC0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TCC1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TCC2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TC3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TC4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TC5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TC6_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void TC7_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void ADC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void AC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void DAC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void PTC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); +void I2S_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); + +/* Exception Table */ +__attribute__ ((section(".vectors"))) +const DeviceVectors exception_table = { + + /* Configure Initial Stack Pointer, using linker-generated symbols */ + (void*) (&_estack), + + (void*) Reset_Handler, + (void*) NMI_Handler, + (void*) HardFault_Handler, + (void*) (0UL), /* Reserved */ + (void*) (0UL), /* Reserved */ + (void*) (0UL), /* Reserved */ + (void*) (0UL), /* Reserved */ + (void*) (0UL), /* Reserved */ + (void*) (0UL), /* Reserved */ + (void*) (0UL), /* Reserved */ + (void*) SVC_Handler, + (void*) (0UL), /* Reserved */ + (void*) (0UL), /* Reserved */ + (void*) PendSV_Handler, + (void*) SysTick_Handler, + + /* Configurable interrupts */ + (void*) PM_Handler, /* 0 Power Manager */ + (void*) SYSCTRL_Handler, /* 1 System Control */ + (void*) WDT_Handler, /* 2 Watchdog Timer */ + (void*) RTC_Handler, /* 3 Real-Time Counter */ + (void*) EIC_Handler, /* 4 External Interrupt Controller */ + (void*) NVMCTRL_Handler, /* 5 Non-Volatile Memory Controller */ + (void*) DMAC_Handler, /* 6 Direct Memory Access Controller */ + (void*) USB_Handler, /* 7 Universal Serial Bus */ + (void*) EVSYS_Handler, /* 8 Event System Interface */ + (void*) SERCOM0_Handler, /* 9 Serial Communication Interface 0 */ + (void*) SERCOM1_Handler, /* 10 Serial Communication Interface 1 */ + (void*) SERCOM2_Handler, /* 11 Serial Communication Interface 2 */ + (void*) SERCOM3_Handler, /* 12 Serial Communication Interface 3 */ + (void*) SERCOM4_Handler, /* 13 Serial Communication Interface 4 */ + (void*) SERCOM5_Handler, /* 14 Serial Communication Interface 5 */ + (void*) TCC0_Handler, /* 15 Timer Counter Control 0 */ + (void*) TCC1_Handler, /* 16 Timer Counter Control 1 */ + (void*) TCC2_Handler, /* 17 Timer Counter Control 2 */ + (void*) TC3_Handler, /* 18 Basic Timer Counter 0 */ + (void*) TC4_Handler, /* 19 Basic Timer Counter 1 */ + (void*) TC5_Handler, /* 20 Basic Timer Counter 2 */ + (void*) TC6_Handler, /* 21 Basic Timer Counter 3 */ + (void*) TC7_Handler, /* 22 Basic Timer Counter 4 */ + (void*) ADC_Handler, /* 23 Analog Digital Converter */ + (void*) AC_Handler, /* 24 Analog Comparators */ + (void*) DAC_Handler, /* 25 Digital Analog Converter */ + (void*) PTC_Handler, /* 26 Peripheral Touch Controller */ + (void*) I2S_Handler /* 27 Inter-IC Sound Interface */ +}; + +/** + * \brief This is the code that gets called on processor reset. + * To initialize the device, and call the main() routine. + */ +void Reset_Handler(void) +{ + uint32_t *pSrc, *pDest; + + /* Initialize the relocate segment */ + pSrc = &_etext; + pDest = &_srelocate; + + if (pSrc != pDest) { + for (; pDest < &_erelocate;) { + *pDest++ = *pSrc++; + } + } + + /* Clear the zero segment */ + for (pDest = &_szero; pDest < &_ezero;) { + *pDest++ = 0; + } + + /* Set the vector table base address */ + pSrc = (uint32_t *) & _sfixed; + SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk); + + /* Initialize the C library */ + __libc_init_array(); + + /* Branch to main function */ + main(); + + /* Infinite loop */ + while (1); +} + +/** + * \brief Default interrupt handler for unused IRQs. + */ +void Dummy_Handler(void) +{ + while (1) { + } +} diff --git a/bootloaders/feather/usart_sam_ba.c b/bootloaders/feather/usart_sam_ba.c new file mode 100644 index 000000000..645e725e9 --- /dev/null +++ b/bootloaders/feather/usart_sam_ba.c @@ -0,0 +1,513 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//#include +#include "usart_sam_ba.h" +#include "main.h" +#include "uart_driver.h" +#include "compiler.h" +#include "sam.h" + +/* Local reference to current Usart instance in use with this driver */ +//struct usart_module usart_sam_ba; + +/* Variable to let the main task select the appropriate communication interface */ +volatile uint8_t b_sharp_received; + +/* RX and TX Buffers + rw pointers for each buffer */ +volatile uint8_t buffer_rx_usart[USART_BUFFER_SIZE]; + +volatile uint8_t idx_rx_read; +volatile uint8_t idx_rx_write; + +volatile uint8_t buffer_tx_usart[USART_BUFFER_SIZE]; + +volatile uint8_t idx_tx_read; +volatile uint8_t idx_tx_write; + +/* Test for timeout in AT91F_GetChar */ +uint8_t error_timeout; +uint16_t size_of_data; +uint8_t mode_of_transfer; + +#define BOOT_USART_PAD(n) BOOT_USART_PAD##n + +/** + * \brief Open the given USART + */ +void usart_open() +{ + uint32_t inst; + uint32_t port; + uint8_t pin; + + /* Configure the port pins for SERCOM_USART */ + if (BOOT_USART_PAD0 != PINMUX_UNUSED) { + /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ + port = (BOOT_USART_PAD0 & 0x200000) >> 21; + pin = BOOT_USART_PAD0 >> 16; + PORT->Group[port].PINCFG[(pin - (port*32))].bit.PMUXEN = 1; + PORT->Group[port].PMUX[(pin - (port*32))/2].reg &= ~(0xF << (4 * (pin & 0x01u))); + PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD0 & 0xFF) << (4 * (pin & 0x01u)); + } + if (BOOT_USART_PAD1 != PINMUX_UNUSED) { + /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ + port = (BOOT_USART_PAD1 & 0x200000) >> 21; + pin = BOOT_USART_PAD1 >> 16; + PORT->Group[port].PINCFG[(pin - (port*32))].bit.PMUXEN = 1; + PORT->Group[port].PMUX[(pin - (port*32))/2].reg &= ~(0xF << (4 * (pin & 0x01u))); + PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD1 & 0xFF) << (4 * (pin & 0x01u)); + } + if (BOOT_USART_PAD2 != PINMUX_UNUSED) { + /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ + port = (BOOT_USART_PAD2 & 0x200000) >> 21; + pin = BOOT_USART_PAD2 >> 16; + PORT->Group[port].PINCFG[(pin - (port*32))].bit.PMUXEN = 1; + PORT->Group[port].PMUX[(pin - (port*32))/2].reg &= ~(0xF << (4 * (pin & 0x01u))); + PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD2 & 0xFF) << (4 * (pin & 0x01u)); + } + if (BOOT_USART_PAD3 != PINMUX_UNUSED) { + /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ + port = (BOOT_USART_PAD3 & 0x200000) >> 21; + pin = BOOT_USART_PAD3 >> 16; + PORT->Group[port].PINCFG[(pin - (port*32))].bit.PMUXEN = 1; + PORT->Group[port].PMUX[(pin - (port*32))/2].reg &= ~(0xF << (4 * (pin & 0x01u))); + PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD3 & 0xFF) << (4 * (pin & 0x01u)); + } + + inst = uart_get_sercom_index(BOOT_USART_MODULE); + + /* Enable clock for BOOT_USART_MODULE */ + PM->APBCMASK.reg |= (1u << (inst + PM_APBCMASK_SERCOM0_Pos)); + + /* Set GCLK_GEN0 as source for GCLK_ID_SERCOMx_CORE */ + GCLK_CLKCTRL_Type clkctrl={0}; + uint16_t temp; + GCLK->CLKCTRL.bit.ID = inst + GCLK_ID_SERCOM0_CORE; + temp = GCLK->CLKCTRL.reg; + clkctrl.bit.CLKEN = true; + clkctrl.bit.WRTLOCK = false; + clkctrl.bit.GEN = GCLK_CLKCTRL_GEN_GCLK0_Val; + GCLK->CLKCTRL.reg = (clkctrl.reg | temp); + + /* Baud rate 115200 - clock 8MHz -> BAUD value-50436 */ + uart_basic_init(BOOT_USART_MODULE, 50436, BOOT_USART_MUX_SETTINGS); + + //Initialize flag + b_sharp_received = false; + idx_rx_read = 0; + idx_rx_write = 0; + idx_tx_read = 0; + idx_tx_write = 0; + + error_timeout = 0; +} + +/** + * \brief Configures communication line + * + */ +void usart_close(void) +{ + uart_disable(BOOT_USART_MODULE); +} + +/** + * \brief Puts a byte on usart line + * The type int is used to support printf redirection from compiler LIB. + * + * \param value Value to put + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ +int usart_putc(int value) +{ + uart_write_byte(BOOT_USART_MODULE, (uint8_t)value); + return 1; +} + + + +int usart_getc(void) { + uint16_t retval; + //Wait until input buffer is filled + while(!(usart_is_rx_ready())); + retval = (uint16_t)uart_read_byte(BOOT_USART_MODULE); + //usart_read_wait(&usart_sam_ba, &retval); + return (int)retval; + +} + +int usart_sharp_received(void) { + if (usart_is_rx_ready()) { + if (usart_getc() == SHARP_CHARACTER) + return (true); + } + return (false); +} + +bool usart_is_rx_ready(void) { + return (BOOT_USART_MODULE->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_RXC); +} + +int usart_readc(void) { + int retval; + retval = buffer_rx_usart[idx_rx_read]; + idx_rx_read = (idx_rx_read + 1) & (USART_BUFFER_SIZE - 1); + return (retval); +} + +//Send given data (polling) +uint32_t usart_putdata(void const* data, uint32_t length) { + uint32_t i; + uint8_t* ptrdata; + ptrdata = (uint8_t*) data; + for (i = 0; i < length; i++) { + usart_putc(*ptrdata); + ptrdata++; + } + return (i); +} + +//Get data from comm. device +uint32_t usart_getdata(void* data, uint32_t length) { + uint8_t* ptrdata; + ptrdata = (uint8_t*) data; + *ptrdata = usart_getc(); + return (1); +} + +static const uint16_t crc16Table[256] = { + 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, + 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, + 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, + 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, + 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, + 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, + 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, + 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, + 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, + 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, + 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, + 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, + 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, + 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, + 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, + 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, + 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, + 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, + 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, + 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, + 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, + 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, + 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, + 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, + 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, + 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, + 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, + 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, + 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, + 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, + 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, + 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 +}; + +//*---------------------------------------------------------------------------- +//* \fn add_crc +//* \brief Compute the CRC +//*---------------------------------------------------------------------------- +unsigned short add_crc(char ptr, unsigned short crc) { + return (crc << 8) ^ crc16Table[((crc >> 8) ^ ptr) & 0xff]; +} + +//*---------------------------------------------------------------------------- +//* \fn getbytes +//* \brief +//*---------------------------------------------------------------------------- +static uint16_t getbytes(uint8_t *ptr_data, uint16_t length) { + uint16_t crc = 0; + uint16_t cpt; + uint8_t c; + + for (cpt = 0; cpt < length; ++cpt) { + c = usart_getc(); + if (error_timeout) + return 1; + crc = add_crc(c, crc); + //crc = (crc << 8) ^ xcrc16tab[(crc>>8) ^ c]; + if (size_of_data || mode_of_transfer) { + *ptr_data++ = c; + if (length == PKTLEN_128) + size_of_data--; + } + } + + return crc; +} + +//*---------------------------------------------------------------------------- +//* \fn putPacket +//* \brief Used by Xup to send packets. +//*---------------------------------------------------------------------------- +static int putPacket(uint8_t *tmppkt, uint8_t sno) { + uint32_t i; + uint16_t chksm; + uint8_t data; + + chksm = 0; + + usart_putc(SOH); + + usart_putc(sno); + usart_putc((uint8_t) ~(sno)); + + for (i = 0; i < PKTLEN_128; i++) { + if (size_of_data || mode_of_transfer) { + data = *tmppkt++; + size_of_data--; + } else + data = 0x00; + + usart_putc(data); + + //chksm = (chksm<<8) ^ xcrc16tab[(chksm>>8)^data]; + chksm = add_crc(data, chksm); + } + + /* An "endian independent way to extract the CRC bytes. */ + usart_putc((uint8_t) (chksm >> 8)); + usart_putc((uint8_t) chksm); + + return (usart_getc()); /* Wait for ack */ +} + +//*---------------------------------------------------------------------------- +//* \fn getPacket +//* \brief Used by Xdown to retrieve packets. +//*---------------------------------------------------------------------------- +uint8_t getPacket(uint8_t *ptr_data, uint8_t sno) { + uint8_t seq[2]; + uint16_t crc, xcrc; + + getbytes(seq, 2); + xcrc = getbytes(ptr_data, PKTLEN_128); + if (error_timeout) + return (false); + + /* An "endian independent way to combine the CRC bytes. */ + crc = (uint16_t) usart_getc() << 8; + crc += (uint16_t) usart_getc(); + + if (error_timeout == 1) + return (false); + + if ((crc != xcrc) || (seq[0] != sno) || (seq[1] != (uint8_t) (~sno))) { + usart_putc(CAN); + return (false); + } + + usart_putc(ACK); + return (true); +} + +//*---------------------------------------------------------------------------- +//* \fn Xup +//* \brief Called when a transfer from target to host is being made (considered +//* an upload). +//*---------------------------------------------------------------------------- +//static void Xup(char *ptr_data, uint16_t length) +//Send given data (polling) using xmodem (if necessary) +uint32_t usart_putdata_xmd(void const* data, uint32_t length) { + uint8_t c, sno = 1; + uint8_t done; + uint8_t * ptr_data = (uint8_t *) data; + error_timeout = 0; + if (!length) + mode_of_transfer = 1; + else { + size_of_data = length; + mode_of_transfer = 0; + } + + if (length & (PKTLEN_128 - 1)) { + length += PKTLEN_128; + length &= ~(PKTLEN_128 - 1); + } + + /* Startup synchronization... */ + /* Wait to receive a NAK or 'C' from receiver. */ + done = 0; + while (!done) { + c = (uint8_t) usart_getc(); + if (error_timeout) { // Test for timeout in usart_getc + error_timeout = 0; + c = (uint8_t) usart_getc(); + if (error_timeout) { + error_timeout = 0; + return (0); + } + } + switch (c) { + case NAK: + done = 1; + // ("CSM"); + break; + case 'C': + done = 1; + // ("CRC"); + break; + case 'q': /* ELS addition, not part of XMODEM spec. */ + return (0); + default: + break; + } + } + + done = 0; + sno = 1; + while (!done) { + c = (uint8_t) putPacket((uint8_t *) ptr_data, sno); + if (error_timeout) { // Test for timeout in usart_getc + error_timeout = 0; + return (0); + } + switch (c) { + case ACK: + ++sno; + length -= PKTLEN_128; + ptr_data += PKTLEN_128; + // ("A"); + break; + case NAK: + // ("N"); + break; + case CAN: + case EOT: + default: + done = 0; + break; + } + if (!length) { + usart_putc(EOT); + usart_getc(); /* Flush the ACK */ + break; + } + // ("!"); + } + + mode_of_transfer = 0; + // ("Xup_done."); + return (1); + // return(0); +} + +//*---------------------------------------------------------------------------- +//* \fn Xdown +//* \brief Called when a transfer from host to target is being made (considered +//* an download). +//*---------------------------------------------------------------------------- +//static void Xdown(char *ptr_data, uint16_t length) +//Get data from comm. device using xmodem (if necessary) +uint32_t usart_getdata_xmd(void* data, uint32_t length) { + uint32_t timeout; + char c; + uint8_t * ptr_data = (uint8_t *) data; + uint32_t b_run, nbr_of_timeout = 100; + uint8_t sno = 0x01; + uint32_t data_transfered = 0; + + //Copied from legacy source code ... might need some tweaking + uint32_t loops_per_second = CPU_FREQUENCY/10; /* system_clock_source_get_hz(BOOT_USART_GCLK_GEN_SOURCE) / 10; */ + + error_timeout = 0; + + if (length == 0) + mode_of_transfer = 1; + else { + size_of_data = length; + mode_of_transfer = 0; + } + + /* Startup synchronization... */ + /* Continuously send NAK or 'C' until sender responds. */ + // ("Xdown"); + while (1) { + usart_putc('C'); + timeout = loops_per_second; + while (!(usart_is_rx_ready()) && timeout) + timeout--; + if (timeout) + break; + + if (!(--nbr_of_timeout)) + return (0); +// return -1; + } + + b_run = true; + // ("Got response"); + while (b_run != false) { + c = (char) usart_getc(); + if (error_timeout) { // Test for timeout in usart_getc + error_timeout = 0; + return (0); +// return (-1); + } + switch (c) { + case SOH: /* 128-byte incoming packet */ + // ("O"); + b_run = getPacket(ptr_data, sno); + if (error_timeout) { // Test for timeout in usart_getc + error_timeout = 0; + return (0); +// return (-1); + } + if (b_run == true) { + ++sno; + ptr_data += PKTLEN_128; + data_transfered += PKTLEN_128; + } + break; + case EOT: // ("E"); + usart_putc(ACK); + b_run = false; + break; + case CAN: // ("C"); + case ESC: /* "X" User-invoked abort */ + default: + b_run = false; + break; + } + // ("!"); + } + mode_of_transfer = 0; + return (true); +// return(b_run); +} + diff --git a/bootloaders/feather/usart_sam_ba.h b/bootloaders/feather/usart_sam_ba.h new file mode 100644 index 000000000..d498dc791 --- /dev/null +++ b/bootloaders/feather/usart_sam_ba.h @@ -0,0 +1,155 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef _USART_SAM_BA_H_ +#define _USART_SAM_BA_H_ + +#include "stdint.h" +#include "stdbool.h" + + +/* USART buffer size (must be a power of two) */ +#define USART_BUFFER_SIZE 128 + +/* Define the default time-out value for USART. */ +#define USART_DEFAULT_TIMEOUT 1000 + +/* Xmodem related defines */ +/* CRC16 polynomial */ +#define CRC16POLY 0x1021 + +#define SHARP_CHARACTER '#' + +/* X/Ymodem protocol: */ +#define SOH 0x01 +//#define STX 0x02 +#define EOT 0x04 +#define ACK 0x06 +#define NAK 0x15 +#define CAN 0x18 +#define ESC 0x1b + +#define PKTLEN_128 128 + + +/** + * \brief Open the given USART + */ +void usart_open(void); + +/** + * \brief Stops the USART + */ +void usart_close(void); + +/** + * \brief Puts a byte on usart line + * + * \param value Value to put + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ +int usart_putc(int value); + +/** + * \brief Waits and gets a value on usart line + * + * \return value read on usart line + */ +int usart_getc(void); + +/** + * \brief Returns true if the SAM-BA Uart received the sharp char + * + * \return Returns true if the SAM-BA Uart received the sharp char + */ +int usart_sharp_received(void); + +/** + * \brief This function checks if a character has been received on the usart line + * + * \return \c 1 if a byte is ready to be read. + */ +bool usart_is_rx_ready(void); + +/** + * \brief Gets a value on usart line + * + * \return value read on usart line + */ +int usart_readc(void); + +/** + * \brief Send buffer on usart line + * + * \param data pointer + * \param number of data to send + * \return number of data sent + */ +uint32_t usart_putdata(void const* data, uint32_t length); //Send given data (polling) + +/** + * \brief Gets data from usart line + * + * \param data pointer + * \param number of data to get + * \return value read on usart line + */ +uint32_t usart_getdata(void* data, uint32_t length); //Get data from comm. device + +/** + * \brief Send buffer on usart line using Xmodem protocol + * + * \param data pointer + * \param number of data to send + * \return number of data sent + */ +uint32_t usart_putdata_xmd(void const* data, uint32_t length); //Send given data (polling) using xmodem (if necessary) + +/** + * \brief Gets data from usart line using Xmodem protocol + * + * \param data pointer + * \param number of data to get + * \return value read on usart line + */ +uint32_t usart_getdata_xmd(void* data, uint32_t length); //Get data from comm. device using xmodem (if necessary) + +/** + * \brief Compute the CRC + * + * \param Char to add to CRC + * \param Previous CRC + * \return The new computed CRC + */ +unsigned short add_crc(char c, unsigned short crc); + +uint8_t getPacket(uint8_t *pData, uint8_t sno); + +#endif // _USART_SAM_BA_H_ diff --git a/bootloaders/feather/utils/compiler.h b/bootloaders/feather/utils/compiler.h new file mode 100644 index 000000000..e31d7dba4 --- /dev/null +++ b/bootloaders/feather/utils/compiler.h @@ -0,0 +1,1157 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef UTILS_COMPILER_H_INCLUDED +#define UTILS_COMPILER_H_INCLUDED + +/** + * \defgroup group_sam0_utils Compiler abstraction layer and code utilities + * + * Compiler abstraction layer and code utilities for Cortex-M0+ based Atmel SAM devices. + * This module provides various abstraction layers and utilities to make code compatible between different compilers. + * + * @{ + */ + +#if (defined __ICCARM__) +# include +#endif + +#include +//#include +#include +#include +#include + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include + +/** + * \def UNUSED + * \brief Marking \a v as a unused parameter or value. + */ +#define UNUSED(v) (void)(v) + +/** + * \def barrier + * \brief Memory barrier + */ +#ifdef __GNUC__ +# define barrier() asm volatile("" ::: "memory") +#else +# define barrier() asm ("") +#endif + +/** + * \brief Emit the compiler pragma \a arg. + * + * \param[in] arg The pragma directive as it would appear after \e \#pragma + * (i.e. not stringified). + */ +#define COMPILER_PRAGMA(arg) _Pragma(#arg) + +/** + * \def COMPILER_PACK_SET(alignment) + * \brief Set maximum alignment for subsequent struct and union definitions to \a alignment. + */ +#define COMPILER_PACK_SET(alignment) COMPILER_PRAGMA(pack(alignment)) + +/** + * \def COMPILER_PACK_RESET() + * \brief Set default alignment for subsequent struct and union definitions. + */ +#define COMPILER_PACK_RESET() COMPILER_PRAGMA(pack()) + + +/** + * \brief Set aligned boundary. + */ +#if (defined __GNUC__) || (defined __CC_ARM) +# define COMPILER_ALIGNED(a) __attribute__((__aligned__(a))) +#elif (defined __ICCARM__) +# define COMPILER_ALIGNED(a) COMPILER_PRAGMA(data_alignment = a) +#endif + +/** + * \brief Set word-aligned boundary. + */ +#if (defined __GNUC__) || defined(__CC_ARM) +#define COMPILER_WORD_ALIGNED __attribute__((__aligned__(4))) +#elif (defined __ICCARM__) +#define COMPILER_WORD_ALIGNED COMPILER_PRAGMA(data_alignment = 4) +#endif + +/** + * \def __always_inline + * \brief The function should always be inlined. + * + * This annotation instructs the compiler to ignore its inlining + * heuristics and inline the function no matter how big it thinks it + * becomes. + */ +#if defined(__CC_ARM) +# define __always_inline __forceinline +#elif (defined __GNUC__) +# define __always_inline __attribute__((__always_inline__)) +#elif (defined __ICCARM__) +# define __always_inline _Pragma("inline=forced") +#endif + +/** + * \def __no_inline + * \brief The function should never be inlined + * + * This annotation instructs the compiler to ignore its inlining + * heuristics and not inline the function no matter how small it thinks it + * becomes. + */ +#if defined(__CC_ARM) +# define __no_inline __attribute__((noinline)) +#elif (defined __GNUC__) +# define __no_inline __attribute__((noinline)) +#elif (defined __ICCARM__) +# define __no_inline _Pragma("inline=never") +#endif + + +/** \brief This macro is used to test fatal errors. + * + * The macro tests if the expression is false. If it is, a fatal error is + * detected and the application hangs up. If \c TEST_SUITE_DEFINE_ASSERT_MACRO + * is defined, a unit test version of the macro is used, to allow execution + * of further tests after a false expression. + * + * \param[in] expr Expression to evaluate and supposed to be nonzero. + */ +#if defined(_ASSERT_ENABLE_) +# if defined(TEST_SUITE_DEFINE_ASSERT_MACRO) +# include "unit_test/suite.h" +# else +# undef TEST_SUITE_DEFINE_ASSERT_MACRO +# define Assert(expr) \ + {\ + if (!(expr)) asm("BKPT #0");\ + } +# endif +#else +# define Assert(expr) ((void) 0) +#endif + +/* Define WEAK attribute */ +#if defined ( __CC_ARM ) +# define WEAK __attribute__ ((weak)) +#elif defined ( __ICCARM__ ) +# define WEAK __weak +#elif defined ( __GNUC__ ) +# define WEAK __attribute__ ((weak)) +#endif + +/* Define NO_INIT attribute */ +#if defined ( __CC_ARM ) +# define NO_INIT __attribute__((zero_init)) +#elif defined ( __ICCARM__ ) +# define NO_INIT __no_init +#elif defined ( __GNUC__ ) +# define NO_INIT __attribute__((section(".no_init"))) +#endif + +#include "interrupt.h" + +/** \name Usual Types + * @{ */ +#ifndef __cplusplus +# if !defined(__bool_true_false_are_defined) +typedef unsigned char bool; +# endif +#endif +typedef uint16_t le16_t; +typedef uint16_t be16_t; +typedef uint32_t le32_t; +typedef uint32_t be32_t; +typedef uint32_t iram_size_t; +/** @} */ + +/** \name Aliasing Aggregate Types + * @{ */ + +/** 16-bit union. */ +typedef union +{ + int16_t s16; + uint16_t u16; + int8_t s8[2]; + uint8_t u8[2]; +} Union16; + +/** 32-bit union. */ +typedef union +{ + int32_t s32; + uint32_t u32; + int16_t s16[2]; + uint16_t u16[2]; + int8_t s8[4]; + uint8_t u8[4]; +} Union32; + +/** 64-bit union. */ +typedef union +{ + int64_t s64; + uint64_t u64; + int32_t s32[2]; + uint32_t u32[2]; + int16_t s16[4]; + uint16_t u16[4]; + int8_t s8[8]; + uint8_t u8[8]; +} Union64; + +/** Union of pointers to 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef union +{ + int64_t *s64ptr; + uint64_t *u64ptr; + int32_t *s32ptr; + uint32_t *u32ptr; + int16_t *s16ptr; + uint16_t *u16ptr; + int8_t *s8ptr; + uint8_t *u8ptr; +} UnionPtr; + +/** Union of pointers to volatile 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef union +{ + volatile int64_t *s64ptr; + volatile uint64_t *u64ptr; + volatile int32_t *s32ptr; + volatile uint32_t *u32ptr; + volatile int16_t *s16ptr; + volatile uint16_t *u16ptr; + volatile int8_t *s8ptr; + volatile uint8_t *u8ptr; +} UnionVPtr; + +/** Union of pointers to constant 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef union +{ + const int64_t *s64ptr; + const uint64_t *u64ptr; + const int32_t *s32ptr; + const uint32_t *u32ptr; + const int16_t *s16ptr; + const uint16_t *u16ptr; + const int8_t *s8ptr; + const uint8_t *u8ptr; +} UnionCPtr; + +/** Union of pointers to constant volatile 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef union +{ + const volatile int64_t *s64ptr; + const volatile uint64_t *u64ptr; + const volatile int32_t *s32ptr; + const volatile uint32_t *u32ptr; + const volatile int16_t *s16ptr; + const volatile uint16_t *u16ptr; + const volatile int8_t *s8ptr; + const volatile uint8_t *u8ptr; +} UnionCVPtr; + +/** Structure of pointers to 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef struct +{ + int64_t *s64ptr; + uint64_t *u64ptr; + int32_t *s32ptr; + uint32_t *u32ptr; + int16_t *s16ptr; + uint16_t *u16ptr; + int8_t *s8ptr; + uint8_t *u8ptr; +} StructPtr; + +/** Structure of pointers to volatile 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef struct +{ + volatile int64_t *s64ptr; + volatile uint64_t *u64ptr; + volatile int32_t *s32ptr; + volatile uint32_t *u32ptr; + volatile int16_t *s16ptr; + volatile uint16_t *u16ptr; + volatile int8_t *s8ptr; + volatile uint8_t *u8ptr; +} StructVPtr; + +/** Structure of pointers to constant 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef struct +{ + const int64_t *s64ptr; + const uint64_t *u64ptr; + const int32_t *s32ptr; + const uint32_t *u32ptr; + const int16_t *s16ptr; + const uint16_t *u16ptr; + const int8_t *s8ptr; + const uint8_t *u8ptr; +} StructCPtr; + +/** Structure of pointers to constant volatile 64-, 32-, 16- and 8-bit unsigned integers. */ +typedef struct +{ + const volatile int64_t *s64ptr; + const volatile uint64_t *u64ptr; + const volatile int32_t *s32ptr; + const volatile uint32_t *u32ptr; + const volatile int16_t *s16ptr; + const volatile uint16_t *u16ptr; + const volatile int8_t *s8ptr; + const volatile uint8_t *u8ptr; +} StructCVPtr; + +/** @} */ + +#endif /* #ifndef __ASSEMBLY__ */ + +/** \name Usual Constants + * @{ */ +#define DISABLE 0 +//#define ENABLE 1 + +#ifndef __cplusplus +# if !defined(__bool_true_false_are_defined) +# define false 0 +# define true 1 +# endif +#endif +/** @} */ + +#ifndef __ASSEMBLY__ + +/** \name Optimization Control + * @{ */ + +/** + * \def likely(exp) + * \brief The expression \a exp is likely to be true + */ +#if !defined(likely) || defined(__DOXYGEN__) +# define likely(exp) (exp) +#endif + +/** + * \def unlikely(exp) + * \brief The expression \a exp is unlikely to be true + */ +#if !defined(unlikely) || defined(__DOXYGEN__) +# define unlikely(exp) (exp) +#endif + +/** + * \def is_constant(exp) + * \brief Determine if an expression evaluates to a constant value. + * + * \param[in] exp Any expression + * + * \return true if \a exp is constant, false otherwise. + */ +#if (defined __GNUC__) || (defined __CC_ARM) +# define is_constant(exp) __builtin_constant_p(exp) +#else +# define is_constant(exp) (0) +#endif + +/** @} */ + +/** \name Bit-Field Handling + * @{ */ + +/** \brief Reads the bits of a value specified by a given bit-mask. + * + * \param[in] value Value to read bits from. + * \param[in] mask Bit-mask indicating bits to read. + * + * \return Read bits. + */ +#define Rd_bits( value, mask) ((value) & (mask)) + +/** \brief Writes the bits of a C lvalue specified by a given bit-mask. + * + * \param[in] lvalue C lvalue to write bits to. + * \param[in] mask Bit-mask indicating bits to write. + * \param[in] bits Bits to write. + * + * \return Resulting value with written bits. + */ +#define Wr_bits(lvalue, mask, bits) ((lvalue) = ((lvalue) & ~(mask)) |\ + ((bits ) & (mask))) + +/** \brief Tests the bits of a value specified by a given bit-mask. + * + * \param[in] value Value of which to test bits. + * \param[in] mask Bit-mask indicating bits to test. + * + * \return \c 1 if at least one of the tested bits is set, else \c 0. + */ +#define Tst_bits( value, mask) (Rd_bits(value, mask) != 0) + +/** \brief Clears the bits of a C lvalue specified by a given bit-mask. + * + * \param[in] lvalue C lvalue of which to clear bits. + * \param[in] mask Bit-mask indicating bits to clear. + * + * \return Resulting value with cleared bits. + */ +#define Clr_bits(lvalue, mask) ((lvalue) &= ~(mask)) + +/** \brief Sets the bits of a C lvalue specified by a given bit-mask. + * + * \param[in] lvalue C lvalue of which to set bits. + * \param[in] mask Bit-mask indicating bits to set. + * + * \return Resulting value with set bits. + */ +#define Set_bits(lvalue, mask) ((lvalue) |= (mask)) + +/** \brief Toggles the bits of a C lvalue specified by a given bit-mask. + * + * \param[in] lvalue C lvalue of which to toggle bits. + * \param[in] mask Bit-mask indicating bits to toggle. + * + * \return Resulting value with toggled bits. + */ +#define Tgl_bits(lvalue, mask) ((lvalue) ^= (mask)) + +/** \brief Reads the bit-field of a value specified by a given bit-mask. + * + * \param[in] value Value to read a bit-field from. + * \param[in] mask Bit-mask indicating the bit-field to read. + * + * \return Read bit-field. + */ +#define Rd_bitfield( value, mask) (Rd_bits( value, mask) >> ctz(mask)) + +/** \brief Writes the bit-field of a C lvalue specified by a given bit-mask. + * + * \param[in] lvalue C lvalue to write a bit-field to. + * \param[in] mask Bit-mask indicating the bit-field to write. + * \param[in] bitfield Bit-field to write. + * + * \return Resulting value with written bit-field. + */ +#define Wr_bitfield(lvalue, mask, bitfield) (Wr_bits(lvalue, mask, (uint32_t)(bitfield) << ctz(mask))) + +/** @} */ + + +/** \name Zero-Bit Counting + * + * Under GCC, __builtin_clz and __builtin_ctz behave like macros when + * applied to constant expressions (values known at compile time), so they are + * more optimized than the use of the corresponding assembly instructions and + * they can be used as constant expressions e.g. to initialize objects having + * static storage duration, and like the corresponding assembly instructions + * when applied to non-constant expressions (values unknown at compile time), so + * they are more optimized than an assembly periphrasis. Hence, clz and ctz + * ensure a possible and optimized behavior for both constant and non-constant + * expressions. + * + * @{ */ + +/** \brief Counts the leading zero bits of the given value considered as a 32-bit integer. + * + * \param[in] u Value of which to count the leading zero bits. + * + * \return The count of leading zero bits in \a u. + */ +#if (defined __GNUC__) || (defined __CC_ARM) +# define clz(u) __builtin_clz(u) +#else +# define clz(u) (((u) == 0) ? 32 : \ + ((u) & (1ul << 31)) ? 0 : \ + ((u) & (1ul << 30)) ? 1 : \ + ((u) & (1ul << 29)) ? 2 : \ + ((u) & (1ul << 28)) ? 3 : \ + ((u) & (1ul << 27)) ? 4 : \ + ((u) & (1ul << 26)) ? 5 : \ + ((u) & (1ul << 25)) ? 6 : \ + ((u) & (1ul << 24)) ? 7 : \ + ((u) & (1ul << 23)) ? 8 : \ + ((u) & (1ul << 22)) ? 9 : \ + ((u) & (1ul << 21)) ? 10 : \ + ((u) & (1ul << 20)) ? 11 : \ + ((u) & (1ul << 19)) ? 12 : \ + ((u) & (1ul << 18)) ? 13 : \ + ((u) & (1ul << 17)) ? 14 : \ + ((u) & (1ul << 16)) ? 15 : \ + ((u) & (1ul << 15)) ? 16 : \ + ((u) & (1ul << 14)) ? 17 : \ + ((u) & (1ul << 13)) ? 18 : \ + ((u) & (1ul << 12)) ? 19 : \ + ((u) & (1ul << 11)) ? 20 : \ + ((u) & (1ul << 10)) ? 21 : \ + ((u) & (1ul << 9)) ? 22 : \ + ((u) & (1ul << 8)) ? 23 : \ + ((u) & (1ul << 7)) ? 24 : \ + ((u) & (1ul << 6)) ? 25 : \ + ((u) & (1ul << 5)) ? 26 : \ + ((u) & (1ul << 4)) ? 27 : \ + ((u) & (1ul << 3)) ? 28 : \ + ((u) & (1ul << 2)) ? 29 : \ + ((u) & (1ul << 1)) ? 30 : \ + 31) +#endif + +/** \brief Counts the trailing zero bits of the given value considered as a 32-bit integer. + * + * \param[in] u Value of which to count the trailing zero bits. + * + * \return The count of trailing zero bits in \a u. + */ +#if (defined __GNUC__) || (defined __CC_ARM) +# define ctz(u) __builtin_ctz(u) +#else +# define ctz(u) ((u) & (1ul << 0) ? 0 : \ + (u) & (1ul << 1) ? 1 : \ + (u) & (1ul << 2) ? 2 : \ + (u) & (1ul << 3) ? 3 : \ + (u) & (1ul << 4) ? 4 : \ + (u) & (1ul << 5) ? 5 : \ + (u) & (1ul << 6) ? 6 : \ + (u) & (1ul << 7) ? 7 : \ + (u) & (1ul << 8) ? 8 : \ + (u) & (1ul << 9) ? 9 : \ + (u) & (1ul << 10) ? 10 : \ + (u) & (1ul << 11) ? 11 : \ + (u) & (1ul << 12) ? 12 : \ + (u) & (1ul << 13) ? 13 : \ + (u) & (1ul << 14) ? 14 : \ + (u) & (1ul << 15) ? 15 : \ + (u) & (1ul << 16) ? 16 : \ + (u) & (1ul << 17) ? 17 : \ + (u) & (1ul << 18) ? 18 : \ + (u) & (1ul << 19) ? 19 : \ + (u) & (1ul << 20) ? 20 : \ + (u) & (1ul << 21) ? 21 : \ + (u) & (1ul << 22) ? 22 : \ + (u) & (1ul << 23) ? 23 : \ + (u) & (1ul << 24) ? 24 : \ + (u) & (1ul << 25) ? 25 : \ + (u) & (1ul << 26) ? 26 : \ + (u) & (1ul << 27) ? 27 : \ + (u) & (1ul << 28) ? 28 : \ + (u) & (1ul << 29) ? 29 : \ + (u) & (1ul << 30) ? 30 : \ + (u) & (1ul << 31) ? 31 : \ + 32) +#endif + +/** @} */ + + +/** \name Bit Reversing + * @{ */ + +/** \brief Reverses the bits of \a u8. + * + * \param[in] u8 U8 of which to reverse the bits. + * + * \return Value resulting from \a u8 with reversed bits. + */ +#define bit_reverse8(u8) ((U8)(bit_reverse32((U8)(u8)) >> 24)) + +/** \brief Reverses the bits of \a u16. + * + * \param[in] u16 U16 of which to reverse the bits. + * + * \return Value resulting from \a u16 with reversed bits. + */ +#define bit_reverse16(u16) ((uint16_t)(bit_reverse32((uint16_t)(u16)) >> 16)) + +/** \brief Reverses the bits of \a u32. + * + * \param[in] u32 U32 of which to reverse the bits. + * + * \return Value resulting from \a u32 with reversed bits. + */ +#define bit_reverse32(u32) __RBIT(u32) + +/** \brief Reverses the bits of \a u64. + * + * \param[in] u64 U64 of which to reverse the bits. + * + * \return Value resulting from \a u64 with reversed bits. + */ +#define bit_reverse64(u64) ((uint64_t)(((uint64_t)bit_reverse32((uint64_t)(u64) >> 32)) |\ + ((uint64_t)bit_reverse32((uint64_t)(u64)) << 32))) + +/** @} */ + + +/** \name Alignment + * @{ */ + +/** \brief Tests alignment of the number \a val with the \a n boundary. + * + * \param[in] val Input value. + * \param[in] n Boundary. + * + * \return \c 1 if the number \a val is aligned with the \a n boundary, else \c 0. + */ +#define Test_align(val, n) (!Tst_bits( val, (n) - 1 ) ) + +/** \brief Gets alignment of the number \a val with respect to the \a n boundary. + * + * \param[in] val Input value. + * \param[in] n Boundary. + * + * \return Alignment of the number \a val with respect to the \a n boundary. + */ +#define Get_align(val, n) ( Rd_bits( val, (n) - 1 ) ) + +/** \brief Sets alignment of the lvalue number \a lval to \a alg with respect to the \a n boundary. + * + * \param[in] lval Input/output lvalue. + * \param[in] n Boundary. + * \param[in] alg Alignment. + * + * \return New value of \a lval resulting from its alignment set to \a alg with respect to the \a n boundary. + */ +#define Set_align(lval, n, alg) ( Wr_bits(lval, (n) - 1, alg) ) + +/** \brief Aligns the number \a val with the upper \a n boundary. + * + * \param[in] val Input value. + * \param[in] n Boundary. + * + * \return Value resulting from the number \a val aligned with the upper \a n boundary. + */ +#define Align_up( val, n) (((val) + ((n) - 1)) & ~((n) - 1)) + +/** \brief Aligns the number \a val with the lower \a n boundary. + * + * \param[in] val Input value. + * \param[in] n Boundary. + * + * \return Value resulting from the number \a val aligned with the lower \a n boundary. + */ +#define Align_down(val, n) ( (val) & ~((n) - 1)) + +/** @} */ + + +/** \name Mathematics + * + * The same considerations as for clz and ctz apply here but GCC does not + * provide built-in functions to access the assembly instructions abs, min and + * max and it does not produce them by itself in most cases, so two sets of + * macros are defined here: + * - Abs, Min and Max to apply to constant expressions (values known at + * compile time); + * - abs, min and max to apply to non-constant expressions (values unknown at + * compile time), abs is found in stdlib.h. + * + * @{ */ + +/** \brief Takes the absolute value of \a a. + * + * \param[in] a Input value. + * + * \return Absolute value of \a a. + * + * \note More optimized if only used with values known at compile time. + */ +#define Abs(a) (((a) < 0 ) ? -(a) : (a)) + +/** \brief Takes the minimal value of \a a and \a b. + * + * \param[in] a Input value. + * \param[in] b Input value. + * + * \return Minimal value of \a a and \a b. + * + * \note More optimized if only used with values known at compile time. + */ +#define Min(a, b) (((a) < (b)) ? (a) : (b)) + +/** \brief Takes the maximal value of \a a and \a b. + * + * \param[in] a Input value. + * \param[in] b Input value. + * + * \return Maximal value of \a a and \a b. + * + * \note More optimized if only used with values known at compile time. + */ +#define Max(a, b) (((a) > (b)) ? (a) : (b)) + +/** \brief Takes the minimal value of \a a and \a b. + * + * \param[in] a Input value. + * \param[in] b Input value. + * + * \return Minimal value of \a a and \a b. + * + * \note More optimized if only used with values unknown at compile time. + */ +#define min(a, b) Min(a, b) + +/** \brief Takes the maximal value of \a a and \a b. + * + * \param[in] a Input value. + * \param[in] b Input value. + * + * \return Maximal value of \a a and \a b. + * + * \note More optimized if only used with values unknown at compile time. + */ +#define max(a, b) Max(a, b) + +/** @} */ + + +/** \brief Calls the routine at address \a addr. + * + * It generates a long call opcode. + * + * For example, `Long_call(0x80000000)' generates a software reset on a UC3 if + * it is invoked from the CPU supervisor mode. + * + * \param[in] addr Address of the routine to call. + * + * \note It may be used as a long jump opcode in some special cases. + */ +#define Long_call(addr) ((*(void (*)(void))(addr))()) + + +/** \name MCU Endianism Handling + * ARM is MCU little endian. + * + * @{ */ +#define BE16(x) Swap16(x) +#define LE16(x) (x) + +#define le16_to_cpu(x) (x) +#define cpu_to_le16(x) (x) +#define LE16_TO_CPU(x) (x) +#define CPU_TO_LE16(x) (x) + +#define be16_to_cpu(x) Swap16(x) +#define cpu_to_be16(x) Swap16(x) +#define BE16_TO_CPU(x) Swap16(x) +#define CPU_TO_BE16(x) Swap16(x) + +#define le32_to_cpu(x) (x) +#define cpu_to_le32(x) (x) +#define LE32_TO_CPU(x) (x) +#define CPU_TO_LE32(x) (x) + +#define be32_to_cpu(x) swap32(x) +#define cpu_to_be32(x) swap32(x) +#define BE32_TO_CPU(x) swap32(x) +#define CPU_TO_BE32(x) swap32(x) +/** @} */ + + +/** \name Endianism Conversion + * + * The same considerations as for clz and ctz apply here but GCC's + * __builtin_bswap_32 and __builtin_bswap_64 do not behave like macros when + * applied to constant expressions, so two sets of macros are defined here: + * - Swap16, Swap32 and Swap64 to apply to constant expressions (values known + * at compile time); + * - swap16, swap32 and swap64 to apply to non-constant expressions (values + * unknown at compile time). + * + * @{ */ + +/** \brief Toggles the endianism of \a u16 (by swapping its bytes). + * + * \param[in] u16 U16 of which to toggle the endianism. + * + * \return Value resulting from \a u16 with toggled endianism. + * + * \note More optimized if only used with values known at compile time. + */ +#define Swap16(u16) ((uint16_t)(((uint16_t)(u16) >> 8) |\ + ((uint16_t)(u16) << 8))) + +/** \brief Toggles the endianism of \a u32 (by swapping its bytes). + * + * \param[in] u32 U32 of which to toggle the endianism. + * + * \return Value resulting from \a u32 with toggled endianism. + * + * \note More optimized if only used with values known at compile time. + */ +#define Swap32(u32) ((uint32_t)(((uint32_t)Swap16((uint32_t)(u32) >> 16)) |\ + ((uint32_t)Swap16((uint32_t)(u32)) << 16))) + +/** \brief Toggles the endianism of \a u64 (by swapping its bytes). + * + * \param[in] u64 U64 of which to toggle the endianism. + * + * \return Value resulting from \a u64 with toggled endianism. + * + * \note More optimized if only used with values known at compile time. + */ +#define Swap64(u64) ((uint64_t)(((uint64_t)Swap32((uint64_t)(u64) >> 32)) |\ + ((uint64_t)Swap32((uint64_t)(u64)) << 32))) + +/** \brief Toggles the endianism of \a u16 (by swapping its bytes). + * + * \param[in] u16 U16 of which to toggle the endianism. + * + * \return Value resulting from \a u16 with toggled endianism. + * + * \note More optimized if only used with values unknown at compile time. + */ +#define swap16(u16) Swap16(u16) + +/** \brief Toggles the endianism of \a u32 (by swapping its bytes). + * + * \param[in] u32 U32 of which to toggle the endianism. + * + * \return Value resulting from \a u32 with toggled endianism. + * + * \note More optimized if only used with values unknown at compile time. + */ +#if (defined __GNUC__) +# define swap32(u32) ((uint32_t)__builtin_bswap32((uint32_t)(u32))) +#else +# define swap32(u32) Swap32(u32) +#endif + +/** \brief Toggles the endianism of \a u64 (by swapping its bytes). + * + * \param[in] u64 U64 of which to toggle the endianism. + * + * \return Value resulting from \a u64 with toggled endianism. + * + * \note More optimized if only used with values unknown at compile time. + */ +#if (defined __GNUC__) +# define swap64(u64) ((uint64_t)__builtin_bswap64((uint64_t)(u64))) +#else +# define swap64(u64) ((uint64_t)(((uint64_t)swap32((uint64_t)(u64) >> 32)) |\ + ((uint64_t)swap32((uint64_t)(u64)) << 32))) +#endif + +/** @} */ + + +/** \name Target Abstraction + * + * @{ */ + +#define _GLOBEXT_ extern /**< extern storage-class specifier. */ +#define _CONST_TYPE_ const /**< const type qualifier. */ +#define _MEM_TYPE_SLOW_ /**< Slow memory type. */ +#define _MEM_TYPE_MEDFAST_ /**< Fairly fast memory type. */ +#define _MEM_TYPE_FAST_ /**< Fast memory type. */ + +#define memcmp_ram2ram memcmp /**< Target-specific memcmp of RAM to RAM. */ +#define memcmp_code2ram memcmp /**< Target-specific memcmp of RAM to NVRAM. */ +#define memcpy_ram2ram memcpy /**< Target-specific memcpy from RAM to RAM. */ +#define memcpy_code2ram memcpy /**< Target-specific memcpy from NVRAM to RAM. */ + +/** @} */ + +/** + * \brief Calculate \f$ \left\lceil \frac{a}{b} \right\rceil \f$ using + * integer arithmetic. + * + * \param[in] a An integer + * \param[in] b Another integer + * + * \return (\a a / \a b) rounded up to the nearest integer. + */ +#define div_ceil(a, b) (((a) + (b) - 1) / (b)) + +#endif /* #ifndef __ASSEMBLY__ */ +#ifdef __ICCARM__ +/** \name Compiler Keywords + * + * Port of some keywords from GCC to IAR Embedded Workbench. + * + * @{ */ + +#define __asm__ asm +#define __inline__ inline +#define __volatile__ + +/** @} */ + +#endif + +#define FUNC_PTR void * +/** + * \def unused + * \brief Marking \a v as a unused parameter or value. + */ +#define unused(v) do { (void)(v); } while(0) + +/* Define RAMFUNC attribute */ +#if defined ( __CC_ARM ) /* Keil uVision 4 */ +# define RAMFUNC __attribute__ ((section(".ramfunc"))) +#elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ +# define RAMFUNC __ramfunc +#elif defined ( __GNUC__ ) /* GCC CS3 2009q3-68 */ +# define RAMFUNC __attribute__ ((section(".ramfunc"))) +#endif + +/* Define OPTIMIZE_HIGH attribute */ +#if defined ( __CC_ARM ) /* Keil uVision 4 */ +# define OPTIMIZE_HIGH _Pragma("O3") +#elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ +# define OPTIMIZE_HIGH _Pragma("optimize=high") +#elif defined ( __GNUC__ ) /* GCC CS3 2009q3-68 */ +# define OPTIMIZE_HIGH __attribute__((optimize(s))) +#endif +#define PASS 0 +#define FAIL 1 +#define LOW 0 +#define HIGH 1 + +typedef int8_t S8 ; //!< 8-bit signed integer. +typedef uint8_t U8 ; //!< 8-bit unsigned integer. +typedef int16_t S16; //!< 16-bit signed integer. +typedef uint16_t U16; //!< 16-bit unsigned integer. +typedef int32_t S32; //!< 32-bit signed integer. +typedef uint32_t U32; //!< 32-bit unsigned integer. +typedef int64_t S64; //!< 64-bit signed integer. +typedef uint64_t U64; //!< 64-bit unsigned integer. +typedef float F32; //!< 32-bit floating-point number. +typedef double F64; //!< 64-bit floating-point number. + +#define MSB(u16) (((U8 *)&(u16))[1]) //!< Most significant byte of \a u16. +#define LSB(u16) (((U8 *)&(u16))[0]) //!< Least significant byte of \a u16. + +#define MSH(u32) (((U16 *)&(u32))[1]) //!< Most significant half-word of \a u32. +#define LSH(u32) (((U16 *)&(u32))[0]) //!< Least significant half-word of \a u32. +#define MSB0W(u32) (((U8 *)&(u32))[3]) //!< Most significant byte of 1st rank of \a u32. +#define MSB1W(u32) (((U8 *)&(u32))[2]) //!< Most significant byte of 2nd rank of \a u32. +#define MSB2W(u32) (((U8 *)&(u32))[1]) //!< Most significant byte of 3rd rank of \a u32. +#define MSB3W(u32) (((U8 *)&(u32))[0]) //!< Most significant byte of 4th rank of \a u32. +#define LSB3W(u32) MSB0W(u32) //!< Least significant byte of 4th rank of \a u32. +#define LSB2W(u32) MSB1W(u32) //!< Least significant byte of 3rd rank of \a u32. +#define LSB1W(u32) MSB2W(u32) //!< Least significant byte of 2nd rank of \a u32. +#define LSB0W(u32) MSB3W(u32) //!< Least significant byte of 1st rank of \a u32. + +#define MSW(u64) (((U32 *)&(u64))[1]) //!< Most significant word of \a u64. +#define LSW(u64) (((U32 *)&(u64))[0]) //!< Least significant word of \a u64. +#define MSH0(u64) (((U16 *)&(u64))[3]) //!< Most significant half-word of 1st rank of \a u64. +#define MSH1(u64) (((U16 *)&(u64))[2]) //!< Most significant half-word of 2nd rank of \a u64. +#define MSH2(u64) (((U16 *)&(u64))[1]) //!< Most significant half-word of 3rd rank of \a u64. +#define MSH3(u64) (((U16 *)&(u64))[0]) //!< Most significant half-word of 4th rank of \a u64. +#define LSH3(u64) MSH0(u64) //!< Least significant half-word of 4th rank of \a u64. +#define LSH2(u64) MSH1(u64) //!< Least significant half-word of 3rd rank of \a u64. +#define LSH1(u64) MSH2(u64) //!< Least significant half-word of 2nd rank of \a u64. +#define LSH0(u64) MSH3(u64) //!< Least significant half-word of 1st rank of \a u64. +#define MSB0D(u64) (((U8 *)&(u64))[7]) //!< Most significant byte of 1st rank of \a u64. +#define MSB1D(u64) (((U8 *)&(u64))[6]) //!< Most significant byte of 2nd rank of \a u64. +#define MSB2D(u64) (((U8 *)&(u64))[5]) //!< Most significant byte of 3rd rank of \a u64. +#define MSB3D(u64) (((U8 *)&(u64))[4]) //!< Most significant byte of 4th rank of \a u64. +#define MSB4D(u64) (((U8 *)&(u64))[3]) //!< Most significant byte of 5th rank of \a u64. +#define MSB5D(u64) (((U8 *)&(u64))[2]) //!< Most significant byte of 6th rank of \a u64. +#define MSB6D(u64) (((U8 *)&(u64))[1]) //!< Most significant byte of 7th rank of \a u64. +#define MSB7D(u64) (((U8 *)&(u64))[0]) //!< Most significant byte of 8th rank of \a u64. +#define LSB7D(u64) MSB0D(u64) //!< Least significant byte of 8th rank of \a u64. +#define LSB6D(u64) MSB1D(u64) //!< Least significant byte of 7th rank of \a u64. +#define LSB5D(u64) MSB2D(u64) //!< Least significant byte of 6th rank of \a u64. +#define LSB4D(u64) MSB3D(u64) //!< Least significant byte of 5th rank of \a u64. +#define LSB3D(u64) MSB4D(u64) //!< Least significant byte of 4th rank of \a u64. +#define LSB2D(u64) MSB5D(u64) //!< Least significant byte of 3rd rank of \a u64. +#define LSB1D(u64) MSB6D(u64) //!< Least significant byte of 2nd rank of \a u64. +#define LSB0D(u64) MSB7D(u64) //!< Least significant byte of 1st rank of \a u64. + +#define LSB0(u32) LSB0W(u32) //!< Least significant byte of 1st rank of \a u32. +#define LSB1(u32) LSB1W(u32) //!< Least significant byte of 2nd rank of \a u32. +#define LSB2(u32) LSB2W(u32) //!< Least significant byte of 3rd rank of \a u32. +#define LSB3(u32) LSB3W(u32) //!< Least significant byte of 4th rank of \a u32. +#define MSB3(u32) MSB3W(u32) //!< Most significant byte of 4th rank of \a u32. +#define MSB2(u32) MSB2W(u32) //!< Most significant byte of 3rd rank of \a u32. +#define MSB1(u32) MSB1W(u32) //!< Most significant byte of 2nd rank of \a u32. +#define MSB0(u32) MSB0W(u32) //!< Most significant byte of 1st rank of \a u32. + +#if defined(__ICCARM__) +#define SHORTENUM __packed +#elif defined(__GNUC__) +#define SHORTENUM __attribute__((packed)) +#endif + +/* No operation */ +#if defined(__ICCARM__) +#define nop() __no_operation() +#elif defined(__GNUC__) +#define nop() (__NOP()) +#endif + +#define FLASH_DECLARE(x) const x +#define FLASH_EXTERN(x) extern const x +#define PGM_READ_BYTE(x) *(x) +#define PGM_READ_WORD(x) *(x) +#define MEMCPY_ENDIAN memcpy +#define PGM_READ_BLOCK(dst, src, len) memcpy((dst), (src), (len)) + +/*Defines the Flash Storage for the request and response of MAC*/ +#define CMD_ID_OCTET (0) + +/* Converting of values from CPU endian to little endian. */ +#define CPU_ENDIAN_TO_LE16(x) (x) +#define CPU_ENDIAN_TO_LE32(x) (x) +#define CPU_ENDIAN_TO_LE64(x) (x) + +/* Converting of values from little endian to CPU endian. */ +#define LE16_TO_CPU_ENDIAN(x) (x) +#define LE32_TO_CPU_ENDIAN(x) (x) +#define LE64_TO_CPU_ENDIAN(x) (x) + +/* Converting of constants from little endian to CPU endian. */ +#define CLE16_TO_CPU_ENDIAN(x) (x) +#define CLE32_TO_CPU_ENDIAN(x) (x) +#define CLE64_TO_CPU_ENDIAN(x) (x) + +/* Converting of constants from CPU endian to little endian. */ +#define CCPU_ENDIAN_TO_LE16(x) (x) +#define CCPU_ENDIAN_TO_LE32(x) (x) +#define CCPU_ENDIAN_TO_LE64(x) (x) + +#define ADDR_COPY_DST_SRC_16(dst, src) ((dst) = (src)) +#define ADDR_COPY_DST_SRC_64(dst, src) ((dst) = (src)) + +/** + * @brief Converts a 64-Bit value into a 8 Byte array + * + * @param[in] value 64-Bit value + * @param[out] data Pointer to the 8 Byte array to be updated with 64-Bit value + * @ingroup apiPalApi + */ +static inline void convert_64_bit_to_byte_array(uint64_t value, uint8_t *data) +{ + uint8_t index = 0; + + while (index < 8) + { + data[index++] = value & 0xFF; + value = value >> 8; + } +} + +/** + * @brief Converts a 16-Bit value into a 2 Byte array + * + * @param[in] value 16-Bit value + * @param[out] data Pointer to the 2 Byte array to be updated with 16-Bit value + * @ingroup apiPalApi + */ +static inline void convert_16_bit_to_byte_array(uint16_t value, uint8_t *data) +{ + data[0] = value & 0xFF; + data[1] = (value >> 8) & 0xFF; +} + +/* Converts a 16-Bit value into a 2 Byte array */ +static inline void convert_spec_16_bit_to_byte_array(uint16_t value, uint8_t *data) +{ + data[0] = value & 0xFF; + data[1] = (value >> 8) & 0xFF; +} + +/* Converts a 16-Bit value into a 2 Byte array */ +static inline void convert_16_bit_to_byte_address(uint16_t value, uint8_t *data) +{ + data[0] = value & 0xFF; + data[1] = (value >> 8) & 0xFF; +} + +/* + * @brief Converts a 2 Byte array into a 16-Bit value + * + * @param data Specifies the pointer to the 2 Byte array + * + * @return 16-Bit value + * @ingroup apiPalApi + */ +static inline uint16_t convert_byte_array_to_16_bit(uint8_t *data) +{ + return (data[0] | ((uint16_t)data[1] << 8)); +} + +/* Converts a 4 Byte array into a 32-Bit value */ +static inline uint32_t convert_byte_array_to_32_bit(uint8_t *data) +{ + union + { + uint32_t u32; + uint8_t u8[4]; + }long_addr; + uint8_t index; + for (index = 0; index < 4; index++) + { + long_addr.u8[index] = *data++; + } + return long_addr.u32; +} + +/** + * @brief Converts a 8 Byte array into a 64-Bit value + * + * @param data Specifies the pointer to the 8 Byte array + * + * @return 64-Bit value + * @ingroup apiPalApi + */ +static inline uint64_t convert_byte_array_to_64_bit(uint8_t *data) +{ + union + { + uint64_t u64; + uint8_t u8[8]; + } long_addr; + + uint8_t index; + + for (index = 0; index < 8; index++) + { + long_addr.u8[index] = *data++; + } + + return long_addr.u64; +} + +/** @} */ + +#endif /* UTILS_COMPILER_H_INCLUDED */ diff --git a/bootloaders/feather/utils/interrupt.h b/bootloaders/feather/utils/interrupt.h new file mode 100644 index 000000000..fa4878ee8 --- /dev/null +++ b/bootloaders/feather/utils/interrupt.h @@ -0,0 +1,117 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ +#ifndef UTILS_INTERRUPT_H +#define UTILS_INTERRUPT_H + +//#include + +#include "interrupt/interrupt_sam_nvic.h" + +/** + * \defgroup interrupt_group Global interrupt management + * + * This is a driver for global enabling and disabling of interrupts. + * + * @{ + */ + +#if defined(__DOXYGEN__) +/** + * \def CONFIG_INTERRUPT_FORCE_INTC + * \brief Force usage of the ASF INTC driver + * + * Predefine this symbol when preprocessing to force the use of the ASF INTC driver. + * This is useful to ensure compatibility across compilers and shall be used only when required + * by the application needs. + */ +# define CONFIG_INTERRUPT_FORCE_INTC +#endif + +//! \name Global interrupt flags +//@{ +/** + * \typedef irqflags_t + * \brief Type used for holding state of interrupt flag + */ + +/** + * \def cpu_irq_enable + * \brief Enable interrupts globally + */ + +/** + * \def cpu_irq_disable + * \brief Disable interrupts globally + */ + +/** + * \fn irqflags_t cpu_irq_save(void) + * \brief Get and clear the global interrupt flags + * + * Use in conjunction with \ref cpu_irq_restore. + * + * \return Current state of interrupt flags. + * + * \note This function leaves interrupts disabled. + */ + +/** + * \fn void cpu_irq_restore(irqflags_t flags) + * \brief Restore global interrupt flags + * + * Use in conjunction with \ref cpu_irq_save. + * + * \param flags State to set interrupt flag to. + */ + +/** + * \fn bool cpu_irq_is_enabled_flags(irqflags_t flags) + * \brief Check if interrupts are globally enabled in supplied flags + * + * \param flags Currents state of interrupt flags. + * + * \return True if interrupts are enabled. + */ + +/** + * \def cpu_irq_is_enabled + * \brief Check if interrupts are globally enabled + * + * \return True if interrupts are enabled. + */ +//@} + +//! @} + +/** + * \ingroup interrupt_group + * \defgroup interrupt_deprecated_group Deprecated interrupt definitions + */ + +#endif /* UTILS_INTERRUPT_H */ diff --git a/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.c b/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.c new file mode 100644 index 000000000..d8134852e --- /dev/null +++ b/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.c @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#include "interrupt_sam_nvic.h" + +#if !defined(__DOXYGEN__) +/* Deprecated - global flag to determine the global interrupt state. Required by + * QTouch library, however new applications should use cpu_irq_is_enabled() + * which probes the true global interrupt state from the CPU special registers. + */ +volatile bool g_interrupt_enabled = true; +#endif + +void cpu_irq_enter_critical(void) +{ + if (cpu_irq_critical_section_counter == 0) { + if (cpu_irq_is_enabled()) { + cpu_irq_disable(); + cpu_irq_prev_interrupt_state = true; + } else { + /* Make sure the to save the prev state as false */ + cpu_irq_prev_interrupt_state = false; + } + + } + + cpu_irq_critical_section_counter++; +} + +void cpu_irq_leave_critical(void) +{ + /* Check if the user is trying to leave a critical section when not in a critical section */ + Assert(cpu_irq_critical_section_counter > 0); + + cpu_irq_critical_section_counter--; + + /* Only enable global interrupts when the counter reaches 0 and the state of the global interrupt flag + was enabled when entering critical state */ + if ((cpu_irq_critical_section_counter == 0) && (cpu_irq_prev_interrupt_state)) { + cpu_irq_enable(); + } +} + diff --git a/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.h b/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.h new file mode 100644 index 000000000..9b5645b63 --- /dev/null +++ b/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.h @@ -0,0 +1,172 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef UTILS_INTERRUPT_INTERRUPT_H +#define UTILS_INTERRUPT_INTERRUPT_H + +#include +//#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \weakgroup interrupt_group + * + * @{ + */ + +/** + * \name Interrupt Service Routine definition + * + * @{ + */ + +/** + * \brief Define service routine + * + * \note For NVIC devices the interrupt service routines are predefined to + * add to vector table in binary generation, so there is no service + * register at run time. The routine collections are in exceptions.h. + * + * Usage: + * \code + ISR(foo_irq_handler) + { + // Function definition + ... + } +\endcode + * + * \param func Name for the function. + */ +# define ISR(func) \ + void func (void) + +/** + * \brief Initialize interrupt vectors + * + * For NVIC the interrupt vectors are put in vector table. So nothing + * to do to initialize them, except defined the vector function with + * right name. + * + * This must be called prior to \ref irq_register_handler. + */ +# define irq_initialize_vectors() \ + do { \ + } while(0) + +/** + * \brief Register handler for interrupt + * + * For NVIC the interrupt vectors are put in vector table. So nothing + * to do to register them, except defined the vector function with + * right name. + * + * Usage: + * \code + irq_initialize_vectors(); + irq_register_handler(foo_irq_handler); +\endcode + * + * \note The function \a func must be defined with the \ref ISR macro. + * \note The functions prototypes can be found in the device exception header + * files (exceptions.h). + */ +# define irq_register_handler(int_num, int_prio) \ + NVIC_ClearPendingIRQ( (IRQn_Type)int_num); \ + NVIC_SetPriority( (IRQn_Type)int_num, int_prio); \ + NVIC_EnableIRQ( (IRQn_Type)int_num); \ + +//@} + +# define cpu_irq_enable() \ + do { \ + g_interrupt_enabled = true; \ + __DMB(); \ + __enable_irq(); \ + } while (0) +# define cpu_irq_disable() \ + do { \ + __disable_irq(); \ + __DMB(); \ + g_interrupt_enabled = false; \ + } while (0) + +typedef uint32_t irqflags_t; + +#if !defined(__DOXYGEN__) +extern volatile bool g_interrupt_enabled; +#endif + +#define cpu_irq_is_enabled() (__get_PRIMASK() == 0) + +static volatile uint32_t cpu_irq_critical_section_counter; +static volatile bool cpu_irq_prev_interrupt_state; + +static inline irqflags_t cpu_irq_save(void) +{ + irqflags_t flags = cpu_irq_is_enabled(); + cpu_irq_disable(); + return flags; +} + +static inline bool cpu_irq_is_enabled_flags(irqflags_t flags) +{ + return (flags); +} + +static inline void cpu_irq_restore(irqflags_t flags) +{ + if (cpu_irq_is_enabled_flags(flags)) + cpu_irq_enable(); +} + +void cpu_irq_enter_critical(void); +void cpu_irq_leave_critical(void); + +/** + * \weakgroup interrupt_deprecated_group + * @{ + */ + +#define Enable_global_interrupt() cpu_irq_enable() +#define Disable_global_interrupt() cpu_irq_disable() +#define Is_global_interrupt_enabled() cpu_irq_is_enabled() + +//@} + +//@} + +#ifdef __cplusplus +} +#endif + +#endif /* UTILS_INTERRUPT_INTERRUPT_H */ diff --git a/bootloaders/feather/utils/preprocessor/mrecursion.h b/bootloaders/feather/utils/preprocessor/mrecursion.h new file mode 100644 index 000000000..444792727 --- /dev/null +++ b/bootloaders/feather/utils/preprocessor/mrecursion.h @@ -0,0 +1,581 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef _MRECURSION_H_ +#define _MRECURSION_H_ + +/** + * \defgroup group_sam0_utils_mrecursion Preprocessor - Macro Recursion + * + * \ingroup group_sam0_utils + * + * @{ + */ + +#include "preprocessor.h" + +#define DEC_256 255 +#define DEC_255 254 +#define DEC_254 253 +#define DEC_253 252 +#define DEC_252 251 +#define DEC_251 250 +#define DEC_250 249 +#define DEC_249 248 +#define DEC_248 247 +#define DEC_247 246 +#define DEC_246 245 +#define DEC_245 244 +#define DEC_244 243 +#define DEC_243 242 +#define DEC_242 241 +#define DEC_241 240 +#define DEC_240 239 +#define DEC_239 238 +#define DEC_238 237 +#define DEC_237 236 +#define DEC_236 235 +#define DEC_235 234 +#define DEC_234 233 +#define DEC_233 232 +#define DEC_232 231 +#define DEC_231 230 +#define DEC_230 229 +#define DEC_229 228 +#define DEC_228 227 +#define DEC_227 226 +#define DEC_226 225 +#define DEC_225 224 +#define DEC_224 223 +#define DEC_223 222 +#define DEC_222 221 +#define DEC_221 220 +#define DEC_220 219 +#define DEC_219 218 +#define DEC_218 217 +#define DEC_217 216 +#define DEC_216 215 +#define DEC_215 214 +#define DEC_214 213 +#define DEC_213 212 +#define DEC_212 211 +#define DEC_211 210 +#define DEC_210 209 +#define DEC_209 208 +#define DEC_208 207 +#define DEC_207 206 +#define DEC_206 205 +#define DEC_205 204 +#define DEC_204 203 +#define DEC_203 202 +#define DEC_202 201 +#define DEC_201 200 +#define DEC_200 199 +#define DEC_199 198 +#define DEC_198 197 +#define DEC_197 196 +#define DEC_196 195 +#define DEC_195 194 +#define DEC_194 193 +#define DEC_193 192 +#define DEC_192 191 +#define DEC_191 190 +#define DEC_190 189 +#define DEC_189 188 +#define DEC_188 187 +#define DEC_187 186 +#define DEC_186 185 +#define DEC_185 184 +#define DEC_184 183 +#define DEC_183 182 +#define DEC_182 181 +#define DEC_181 180 +#define DEC_180 179 +#define DEC_179 178 +#define DEC_178 177 +#define DEC_177 176 +#define DEC_176 175 +#define DEC_175 174 +#define DEC_174 173 +#define DEC_173 172 +#define DEC_172 171 +#define DEC_171 170 +#define DEC_170 169 +#define DEC_169 168 +#define DEC_168 167 +#define DEC_167 166 +#define DEC_166 165 +#define DEC_165 164 +#define DEC_164 163 +#define DEC_163 162 +#define DEC_162 161 +#define DEC_161 160 +#define DEC_160 159 +#define DEC_159 158 +#define DEC_158 157 +#define DEC_157 156 +#define DEC_156 155 +#define DEC_155 154 +#define DEC_154 153 +#define DEC_153 152 +#define DEC_152 151 +#define DEC_151 150 +#define DEC_150 149 +#define DEC_149 148 +#define DEC_148 147 +#define DEC_147 146 +#define DEC_146 145 +#define DEC_145 144 +#define DEC_144 143 +#define DEC_143 142 +#define DEC_142 141 +#define DEC_141 140 +#define DEC_140 139 +#define DEC_139 138 +#define DEC_138 137 +#define DEC_137 136 +#define DEC_136 135 +#define DEC_135 134 +#define DEC_134 133 +#define DEC_133 132 +#define DEC_132 131 +#define DEC_131 130 +#define DEC_130 129 +#define DEC_129 128 +#define DEC_128 127 +#define DEC_127 126 +#define DEC_126 125 +#define DEC_125 124 +#define DEC_124 123 +#define DEC_123 122 +#define DEC_122 121 +#define DEC_121 120 +#define DEC_120 119 +#define DEC_119 118 +#define DEC_118 117 +#define DEC_117 116 +#define DEC_116 115 +#define DEC_115 114 +#define DEC_114 113 +#define DEC_113 112 +#define DEC_112 111 +#define DEC_111 110 +#define DEC_110 109 +#define DEC_109 108 +#define DEC_108 107 +#define DEC_107 106 +#define DEC_106 105 +#define DEC_105 104 +#define DEC_104 103 +#define DEC_103 102 +#define DEC_102 101 +#define DEC_101 100 +#define DEC_100 99 +#define DEC_99 98 +#define DEC_98 97 +#define DEC_97 96 +#define DEC_96 95 +#define DEC_95 94 +#define DEC_94 93 +#define DEC_93 92 +#define DEC_92 91 +#define DEC_91 90 +#define DEC_90 89 +#define DEC_89 88 +#define DEC_88 87 +#define DEC_87 86 +#define DEC_86 85 +#define DEC_85 84 +#define DEC_84 83 +#define DEC_83 82 +#define DEC_82 81 +#define DEC_81 80 +#define DEC_80 79 +#define DEC_79 78 +#define DEC_78 77 +#define DEC_77 76 +#define DEC_76 75 +#define DEC_75 74 +#define DEC_74 73 +#define DEC_73 72 +#define DEC_72 71 +#define DEC_71 70 +#define DEC_70 69 +#define DEC_69 68 +#define DEC_68 67 +#define DEC_67 66 +#define DEC_66 65 +#define DEC_65 64 +#define DEC_64 63 +#define DEC_63 62 +#define DEC_62 61 +#define DEC_61 60 +#define DEC_60 59 +#define DEC_59 58 +#define DEC_58 57 +#define DEC_57 56 +#define DEC_56 55 +#define DEC_55 54 +#define DEC_54 53 +#define DEC_53 52 +#define DEC_52 51 +#define DEC_51 50 +#define DEC_50 49 +#define DEC_49 48 +#define DEC_48 47 +#define DEC_47 46 +#define DEC_46 45 +#define DEC_45 44 +#define DEC_44 43 +#define DEC_43 42 +#define DEC_42 41 +#define DEC_41 40 +#define DEC_40 39 +#define DEC_39 38 +#define DEC_38 37 +#define DEC_37 36 +#define DEC_36 35 +#define DEC_35 34 +#define DEC_34 33 +#define DEC_33 32 +#define DEC_32 31 +#define DEC_31 30 +#define DEC_30 29 +#define DEC_29 28 +#define DEC_28 27 +#define DEC_27 26 +#define DEC_26 25 +#define DEC_25 24 +#define DEC_24 23 +#define DEC_23 22 +#define DEC_22 21 +#define DEC_21 20 +#define DEC_20 19 +#define DEC_19 18 +#define DEC_18 17 +#define DEC_17 16 +#define DEC_16 15 +#define DEC_15 14 +#define DEC_14 13 +#define DEC_13 12 +#define DEC_12 11 +#define DEC_11 10 +#define DEC_10 9 +#define DEC_9 8 +#define DEC_8 7 +#define DEC_7 6 +#define DEC_6 5 +#define DEC_5 4 +#define DEC_4 3 +#define DEC_3 2 +#define DEC_2 1 +#define DEC_1 0 +#define DEC_(n) DEC_##n + + +/** Maximal number of repetitions supported by MRECURSION. */ +#define MRECURSION_LIMIT 256 + +/** \brief Macro recursion. + * + * This macro represents a horizontal repetition construct. + * + * \param[in] count The number of repetitious calls to macro. Valid values + * range from 0 to MRECURSION_LIMIT. + * \param[in] macro A binary operation of the form macro(data, n). This macro + * is expanded by MRECURSION with the current repetition number + * and the auxiliary data argument. + * \param[in] data A recursive threshold, building on this to decline by times + * defined with param count. + * + * \return macro(data-count+1,0) macro(data-count+2,1)...macro(data,count-1) + */ +#define MRECURSION(count, macro, data) TPASTE2(MRECURSION, count) (macro, data) + +#define MRECURSION0( macro, data) +#define MRECURSION1( macro, data) MRECURSION0( macro, DEC_(data)) macro(data, 0) +#define MRECURSION2( macro, data) MRECURSION1( macro, DEC_(data)) macro(data, 1) +#define MRECURSION3( macro, data) MRECURSION2( macro, DEC_(data)) macro(data, 2) +#define MRECURSION4( macro, data) MRECURSION3( macro, DEC_(data)) macro(data, 3) +#define MRECURSION5( macro, data) MRECURSION4( macro, DEC_(data)) macro(data, 4) +#define MRECURSION6( macro, data) MRECURSION5( macro, DEC_(data)) macro(data, 5) +#define MRECURSION7( macro, data) MRECURSION6( macro, DEC_(data)) macro(data, 6) +#define MRECURSION8( macro, data) MRECURSION7( macro, DEC_(data)) macro(data, 7) +#define MRECURSION9( macro, data) MRECURSION8( macro, DEC_(data)) macro(data, 8) +#define MRECURSION10( macro, data) MRECURSION9( macro, DEC_(data)) macro(data, 9) +#define MRECURSION11( macro, data) MRECURSION10( macro, DEC_(data)) macro(data, 10) +#define MRECURSION12( macro, data) MRECURSION11( macro, DEC_(data)) macro(data, 11) +#define MRECURSION13( macro, data) MRECURSION12( macro, DEC_(data)) macro(data, 12) +#define MRECURSION14( macro, data) MRECURSION13( macro, DEC_(data)) macro(data, 13) +#define MRECURSION15( macro, data) MRECURSION14( macro, DEC_(data)) macro(data, 14) +#define MRECURSION16( macro, data) MRECURSION15( macro, DEC_(data)) macro(data, 15) +#define MRECURSION17( macro, data) MRECURSION16( macro, DEC_(data)) macro(data, 16) +#define MRECURSION18( macro, data) MRECURSION17( macro, DEC_(data)) macro(data, 17) +#define MRECURSION19( macro, data) MRECURSION18( macro, DEC_(data)) macro(data, 18) +#define MRECURSION20( macro, data) MRECURSION19( macro, DEC_(data)) macro(data, 19) +#define MRECURSION21( macro, data) MRECURSION20( macro, DEC_(data)) macro(data, 20) +#define MRECURSION22( macro, data) MRECURSION21( macro, DEC_(data)) macro(data, 21) +#define MRECURSION23( macro, data) MRECURSION22( macro, DEC_(data)) macro(data, 22) +#define MRECURSION24( macro, data) MRECURSION23( macro, DEC_(data)) macro(data, 23) +#define MRECURSION25( macro, data) MRECURSION24( macro, DEC_(data)) macro(data, 24) +#define MRECURSION26( macro, data) MRECURSION25( macro, DEC_(data)) macro(data, 25) +#define MRECURSION27( macro, data) MRECURSION26( macro, DEC_(data)) macro(data, 26) +#define MRECURSION28( macro, data) MRECURSION27( macro, DEC_(data)) macro(data, 27) +#define MRECURSION29( macro, data) MRECURSION28( macro, DEC_(data)) macro(data, 28) +#define MRECURSION30( macro, data) MRECURSION29( macro, DEC_(data)) macro(data, 29) +#define MRECURSION31( macro, data) MRECURSION30( macro, DEC_(data)) macro(data, 30) +#define MRECURSION32( macro, data) MRECURSION31( macro, DEC_(data)) macro(data, 31) +#define MRECURSION33( macro, data) MRECURSION32( macro, DEC_(data)) macro(data, 32) +#define MRECURSION34( macro, data) MRECURSION33( macro, DEC_(data)) macro(data, 33) +#define MRECURSION35( macro, data) MRECURSION34( macro, DEC_(data)) macro(data, 34) +#define MRECURSION36( macro, data) MRECURSION35( macro, DEC_(data)) macro(data, 35) +#define MRECURSION37( macro, data) MRECURSION36( macro, DEC_(data)) macro(data, 36) +#define MRECURSION38( macro, data) MRECURSION37( macro, DEC_(data)) macro(data, 37) +#define MRECURSION39( macro, data) MRECURSION38( macro, DEC_(data)) macro(data, 38) +#define MRECURSION40( macro, data) MRECURSION39( macro, DEC_(data)) macro(data, 39) +#define MRECURSION41( macro, data) MRECURSION40( macro, DEC_(data)) macro(data, 40) +#define MRECURSION42( macro, data) MRECURSION41( macro, DEC_(data)) macro(data, 41) +#define MRECURSION43( macro, data) MRECURSION42( macro, DEC_(data)) macro(data, 42) +#define MRECURSION44( macro, data) MRECURSION43( macro, DEC_(data)) macro(data, 43) +#define MRECURSION45( macro, data) MRECURSION44( macro, DEC_(data)) macro(data, 44) +#define MRECURSION46( macro, data) MRECURSION45( macro, DEC_(data)) macro(data, 45) +#define MRECURSION47( macro, data) MRECURSION46( macro, DEC_(data)) macro(data, 46) +#define MRECURSION48( macro, data) MRECURSION47( macro, DEC_(data)) macro(data, 47) +#define MRECURSION49( macro, data) MRECURSION48( macro, DEC_(data)) macro(data, 48) +#define MRECURSION50( macro, data) MRECURSION49( macro, DEC_(data)) macro(data, 49) +#define MRECURSION51( macro, data) MRECURSION50( macro, DEC_(data)) macro(data, 50) +#define MRECURSION52( macro, data) MRECURSION51( macro, DEC_(data)) macro(data, 51) +#define MRECURSION53( macro, data) MRECURSION52( macro, DEC_(data)) macro(data, 52) +#define MRECURSION54( macro, data) MRECURSION53( macro, DEC_(data)) macro(data, 53) +#define MRECURSION55( macro, data) MRECURSION54( macro, DEC_(data)) macro(data, 54) +#define MRECURSION56( macro, data) MRECURSION55( macro, DEC_(data)) macro(data, 55) +#define MRECURSION57( macro, data) MRECURSION56( macro, DEC_(data)) macro(data, 56) +#define MRECURSION58( macro, data) MRECURSION57( macro, DEC_(data)) macro(data, 57) +#define MRECURSION59( macro, data) MRECURSION58( macro, DEC_(data)) macro(data, 58) +#define MRECURSION60( macro, data) MRECURSION59( macro, DEC_(data)) macro(data, 59) +#define MRECURSION61( macro, data) MRECURSION60( macro, DEC_(data)) macro(data, 60) +#define MRECURSION62( macro, data) MRECURSION61( macro, DEC_(data)) macro(data, 61) +#define MRECURSION63( macro, data) MRECURSION62( macro, DEC_(data)) macro(data, 62) +#define MRECURSION64( macro, data) MRECURSION63( macro, DEC_(data)) macro(data, 63) +#define MRECURSION65( macro, data) MRECURSION64( macro, DEC_(data)) macro(data, 64) +#define MRECURSION66( macro, data) MRECURSION65( macro, DEC_(data)) macro(data, 65) +#define MRECURSION67( macro, data) MRECURSION66( macro, DEC_(data)) macro(data, 66) +#define MRECURSION68( macro, data) MRECURSION67( macro, DEC_(data)) macro(data, 67) +#define MRECURSION69( macro, data) MRECURSION68( macro, DEC_(data)) macro(data, 68) +#define MRECURSION70( macro, data) MRECURSION69( macro, DEC_(data)) macro(data, 69) +#define MRECURSION71( macro, data) MRECURSION70( macro, DEC_(data)) macro(data, 70) +#define MRECURSION72( macro, data) MRECURSION71( macro, DEC_(data)) macro(data, 71) +#define MRECURSION73( macro, data) MRECURSION72( macro, DEC_(data)) macro(data, 72) +#define MRECURSION74( macro, data) MRECURSION73( macro, DEC_(data)) macro(data, 73) +#define MRECURSION75( macro, data) MRECURSION74( macro, DEC_(data)) macro(data, 74) +#define MRECURSION76( macro, data) MRECURSION75( macro, DEC_(data)) macro(data, 75) +#define MRECURSION77( macro, data) MRECURSION76( macro, DEC_(data)) macro(data, 76) +#define MRECURSION78( macro, data) MRECURSION77( macro, DEC_(data)) macro(data, 77) +#define MRECURSION79( macro, data) MRECURSION78( macro, DEC_(data)) macro(data, 78) +#define MRECURSION80( macro, data) MRECURSION79( macro, DEC_(data)) macro(data, 79) +#define MRECURSION81( macro, data) MRECURSION80( macro, DEC_(data)) macro(data, 80) +#define MRECURSION82( macro, data) MRECURSION81( macro, DEC_(data)) macro(data, 81) +#define MRECURSION83( macro, data) MRECURSION82( macro, DEC_(data)) macro(data, 82) +#define MRECURSION84( macro, data) MRECURSION83( macro, DEC_(data)) macro(data, 83) +#define MRECURSION85( macro, data) MRECURSION84( macro, DEC_(data)) macro(data, 84) +#define MRECURSION86( macro, data) MRECURSION85( macro, DEC_(data)) macro(data, 85) +#define MRECURSION87( macro, data) MRECURSION86( macro, DEC_(data)) macro(data, 86) +#define MRECURSION88( macro, data) MRECURSION87( macro, DEC_(data)) macro(data, 87) +#define MRECURSION89( macro, data) MRECURSION88( macro, DEC_(data)) macro(data, 88) +#define MRECURSION90( macro, data) MRECURSION89( macro, DEC_(data)) macro(data, 89) +#define MRECURSION91( macro, data) MRECURSION90( macro, DEC_(data)) macro(data, 90) +#define MRECURSION92( macro, data) MRECURSION91( macro, DEC_(data)) macro(data, 91) +#define MRECURSION93( macro, data) MRECURSION92( macro, DEC_(data)) macro(data, 92) +#define MRECURSION94( macro, data) MRECURSION93( macro, DEC_(data)) macro(data, 93) +#define MRECURSION95( macro, data) MRECURSION94( macro, DEC_(data)) macro(data, 94) +#define MRECURSION96( macro, data) MRECURSION95( macro, DEC_(data)) macro(data, 95) +#define MRECURSION97( macro, data) MRECURSION96( macro, DEC_(data)) macro(data, 96) +#define MRECURSION98( macro, data) MRECURSION97( macro, DEC_(data)) macro(data, 97) +#define MRECURSION99( macro, data) MRECURSION98( macro, DEC_(data)) macro(data, 98) +#define MRECURSION100(macro, data) MRECURSION99( macro, DEC_(data)) macro(data, 99) +#define MRECURSION101(macro, data) MRECURSION100( macro, DEC_(data)) macro(data, 100) +#define MRECURSION102(macro, data) MRECURSION101( macro, DEC_(data)) macro(data, 101) +#define MRECURSION103(macro, data) MRECURSION102( macro, DEC_(data)) macro(data, 102) +#define MRECURSION104(macro, data) MRECURSION103( macro, DEC_(data)) macro(data, 103) +#define MRECURSION105(macro, data) MRECURSION104( macro, DEC_(data)) macro(data, 104) +#define MRECURSION106(macro, data) MRECURSION105( macro, DEC_(data)) macro(data, 105) +#define MRECURSION107(macro, data) MRECURSION106( macro, DEC_(data)) macro(data, 106) +#define MRECURSION108(macro, data) MRECURSION107( macro, DEC_(data)) macro(data, 107) +#define MRECURSION109(macro, data) MRECURSION108( macro, DEC_(data)) macro(data, 108) +#define MRECURSION110(macro, data) MRECURSION109( macro, DEC_(data)) macro(data, 109) +#define MRECURSION111(macro, data) MRECURSION110( macro, DEC_(data)) macro(data, 110) +#define MRECURSION112(macro, data) MRECURSION111( macro, DEC_(data)) macro(data, 111) +#define MRECURSION113(macro, data) MRECURSION112( macro, DEC_(data)) macro(data, 112) +#define MRECURSION114(macro, data) MRECURSION113( macro, DEC_(data)) macro(data, 113) +#define MRECURSION115(macro, data) MRECURSION114( macro, DEC_(data)) macro(data, 114) +#define MRECURSION116(macro, data) MRECURSION115( macro, DEC_(data)) macro(data, 115) +#define MRECURSION117(macro, data) MRECURSION116( macro, DEC_(data)) macro(data, 116) +#define MRECURSION118(macro, data) MRECURSION117( macro, DEC_(data)) macro(data, 117) +#define MRECURSION119(macro, data) MRECURSION118( macro, DEC_(data)) macro(data, 118) +#define MRECURSION120(macro, data) MRECURSION119( macro, DEC_(data)) macro(data, 119) +#define MRECURSION121(macro, data) MRECURSION120( macro, DEC_(data)) macro(data, 120) +#define MRECURSION122(macro, data) MRECURSION121( macro, DEC_(data)) macro(data, 121) +#define MRECURSION123(macro, data) MRECURSION122( macro, DEC_(data)) macro(data, 122) +#define MRECURSION124(macro, data) MRECURSION123( macro, DEC_(data)) macro(data, 123) +#define MRECURSION125(macro, data) MRECURSION124( macro, DEC_(data)) macro(data, 124) +#define MRECURSION126(macro, data) MRECURSION125( macro, DEC_(data)) macro(data, 125) +#define MRECURSION127(macro, data) MRECURSION126( macro, DEC_(data)) macro(data, 126) +#define MRECURSION128(macro, data) MRECURSION127( macro, DEC_(data)) macro(data, 127) +#define MRECURSION129(macro, data) MRECURSION128( macro, DEC_(data)) macro(data, 128) +#define MRECURSION130(macro, data) MRECURSION129( macro, DEC_(data)) macro(data, 129) +#define MRECURSION131(macro, data) MRECURSION130( macro, DEC_(data)) macro(data, 130) +#define MRECURSION132(macro, data) MRECURSION131( macro, DEC_(data)) macro(data, 131) +#define MRECURSION133(macro, data) MRECURSION132( macro, DEC_(data)) macro(data, 132) +#define MRECURSION134(macro, data) MRECURSION133( macro, DEC_(data)) macro(data, 133) +#define MRECURSION135(macro, data) MRECURSION134( macro, DEC_(data)) macro(data, 134) +#define MRECURSION136(macro, data) MRECURSION135( macro, DEC_(data)) macro(data, 135) +#define MRECURSION137(macro, data) MRECURSION136( macro, DEC_(data)) macro(data, 136) +#define MRECURSION138(macro, data) MRECURSION137( macro, DEC_(data)) macro(data, 137) +#define MRECURSION139(macro, data) MRECURSION138( macro, DEC_(data)) macro(data, 138) +#define MRECURSION140(macro, data) MRECURSION139( macro, DEC_(data)) macro(data, 139) +#define MRECURSION141(macro, data) MRECURSION140( macro, DEC_(data)) macro(data, 140) +#define MRECURSION142(macro, data) MRECURSION141( macro, DEC_(data)) macro(data, 141) +#define MRECURSION143(macro, data) MRECURSION142( macro, DEC_(data)) macro(data, 142) +#define MRECURSION144(macro, data) MRECURSION143( macro, DEC_(data)) macro(data, 143) +#define MRECURSION145(macro, data) MRECURSION144( macro, DEC_(data)) macro(data, 144) +#define MRECURSION146(macro, data) MRECURSION145( macro, DEC_(data)) macro(data, 145) +#define MRECURSION147(macro, data) MRECURSION146( macro, DEC_(data)) macro(data, 146) +#define MRECURSION148(macro, data) MRECURSION147( macro, DEC_(data)) macro(data, 147) +#define MRECURSION149(macro, data) MRECURSION148( macro, DEC_(data)) macro(data, 148) +#define MRECURSION150(macro, data) MRECURSION149( macro, DEC_(data)) macro(data, 149) +#define MRECURSION151(macro, data) MRECURSION150( macro, DEC_(data)) macro(data, 150) +#define MRECURSION152(macro, data) MRECURSION151( macro, DEC_(data)) macro(data, 151) +#define MRECURSION153(macro, data) MRECURSION152( macro, DEC_(data)) macro(data, 152) +#define MRECURSION154(macro, data) MRECURSION153( macro, DEC_(data)) macro(data, 153) +#define MRECURSION155(macro, data) MRECURSION154( macro, DEC_(data)) macro(data, 154) +#define MRECURSION156(macro, data) MRECURSION155( macro, DEC_(data)) macro(data, 155) +#define MRECURSION157(macro, data) MRECURSION156( macro, DEC_(data)) macro(data, 156) +#define MRECURSION158(macro, data) MRECURSION157( macro, DEC_(data)) macro(data, 157) +#define MRECURSION159(macro, data) MRECURSION158( macro, DEC_(data)) macro(data, 158) +#define MRECURSION160(macro, data) MRECURSION159( macro, DEC_(data)) macro(data, 159) +#define MRECURSION161(macro, data) MRECURSION160( macro, DEC_(data)) macro(data, 160) +#define MRECURSION162(macro, data) MRECURSION161( macro, DEC_(data)) macro(data, 161) +#define MRECURSION163(macro, data) MRECURSION162( macro, DEC_(data)) macro(data, 162) +#define MRECURSION164(macro, data) MRECURSION163( macro, DEC_(data)) macro(data, 163) +#define MRECURSION165(macro, data) MRECURSION164( macro, DEC_(data)) macro(data, 164) +#define MRECURSION166(macro, data) MRECURSION165( macro, DEC_(data)) macro(data, 165) +#define MRECURSION167(macro, data) MRECURSION166( macro, DEC_(data)) macro(data, 166) +#define MRECURSION168(macro, data) MRECURSION167( macro, DEC_(data)) macro(data, 167) +#define MRECURSION169(macro, data) MRECURSION168( macro, DEC_(data)) macro(data, 168) +#define MRECURSION170(macro, data) MRECURSION169( macro, DEC_(data)) macro(data, 169) +#define MRECURSION171(macro, data) MRECURSION170( macro, DEC_(data)) macro(data, 170) +#define MRECURSION172(macro, data) MRECURSION171( macro, DEC_(data)) macro(data, 171) +#define MRECURSION173(macro, data) MRECURSION172( macro, DEC_(data)) macro(data, 172) +#define MRECURSION174(macro, data) MRECURSION173( macro, DEC_(data)) macro(data, 173) +#define MRECURSION175(macro, data) MRECURSION174( macro, DEC_(data)) macro(data, 174) +#define MRECURSION176(macro, data) MRECURSION175( macro, DEC_(data)) macro(data, 175) +#define MRECURSION177(macro, data) MRECURSION176( macro, DEC_(data)) macro(data, 176) +#define MRECURSION178(macro, data) MRECURSION177( macro, DEC_(data)) macro(data, 177) +#define MRECURSION179(macro, data) MRECURSION178( macro, DEC_(data)) macro(data, 178) +#define MRECURSION180(macro, data) MRECURSION179( macro, DEC_(data)) macro(data, 179) +#define MRECURSION181(macro, data) MRECURSION180( macro, DEC_(data)) macro(data, 180) +#define MRECURSION182(macro, data) MRECURSION181( macro, DEC_(data)) macro(data, 181) +#define MRECURSION183(macro, data) MRECURSION182( macro, DEC_(data)) macro(data, 182) +#define MRECURSION184(macro, data) MRECURSION183( macro, DEC_(data)) macro(data, 183) +#define MRECURSION185(macro, data) MRECURSION184( macro, DEC_(data)) macro(data, 184) +#define MRECURSION186(macro, data) MRECURSION185( macro, DEC_(data)) macro(data, 185) +#define MRECURSION187(macro, data) MRECURSION186( macro, DEC_(data)) macro(data, 186) +#define MRECURSION188(macro, data) MRECURSION187( macro, DEC_(data)) macro(data, 187) +#define MRECURSION189(macro, data) MRECURSION188( macro, DEC_(data)) macro(data, 188) +#define MRECURSION190(macro, data) MRECURSION189( macro, DEC_(data)) macro(data, 189) +#define MRECURSION191(macro, data) MRECURSION190( macro, DEC_(data)) macro(data, 190) +#define MRECURSION192(macro, data) MRECURSION191( macro, DEC_(data)) macro(data, 191) +#define MRECURSION193(macro, data) MRECURSION192( macro, DEC_(data)) macro(data, 192) +#define MRECURSION194(macro, data) MRECURSION193( macro, DEC_(data)) macro(data, 193) +#define MRECURSION195(macro, data) MRECURSION194( macro, DEC_(data)) macro(data, 194) +#define MRECURSION196(macro, data) MRECURSION195( macro, DEC_(data)) macro(data, 195) +#define MRECURSION197(macro, data) MRECURSION196( macro, DEC_(data)) macro(data, 196) +#define MRECURSION198(macro, data) MRECURSION197( macro, DEC_(data)) macro(data, 197) +#define MRECURSION199(macro, data) MRECURSION198( macro, DEC_(data)) macro(data, 198) +#define MRECURSION200(macro, data) MRECURSION199( macro, DEC_(data)) macro(data, 199) +#define MRECURSION201(macro, data) MRECURSION200( macro, DEC_(data)) macro(data, 200) +#define MRECURSION202(macro, data) MRECURSION201( macro, DEC_(data)) macro(data, 201) +#define MRECURSION203(macro, data) MRECURSION202( macro, DEC_(data)) macro(data, 202) +#define MRECURSION204(macro, data) MRECURSION203( macro, DEC_(data)) macro(data, 203) +#define MRECURSION205(macro, data) MRECURSION204( macro, DEC_(data)) macro(data, 204) +#define MRECURSION206(macro, data) MRECURSION205( macro, DEC_(data)) macro(data, 205) +#define MRECURSION207(macro, data) MRECURSION206( macro, DEC_(data)) macro(data, 206) +#define MRECURSION208(macro, data) MRECURSION207( macro, DEC_(data)) macro(data, 207) +#define MRECURSION209(macro, data) MRECURSION208( macro, DEC_(data)) macro(data, 208) +#define MRECURSION210(macro, data) MRECURSION209( macro, DEC_(data)) macro(data, 209) +#define MRECURSION211(macro, data) MRECURSION210( macro, DEC_(data)) macro(data, 210) +#define MRECURSION212(macro, data) MRECURSION211( macro, DEC_(data)) macro(data, 211) +#define MRECURSION213(macro, data) MRECURSION212( macro, DEC_(data)) macro(data, 212) +#define MRECURSION214(macro, data) MRECURSION213( macro, DEC_(data)) macro(data, 213) +#define MRECURSION215(macro, data) MRECURSION214( macro, DEC_(data)) macro(data, 214) +#define MRECURSION216(macro, data) MRECURSION215( macro, DEC_(data)) macro(data, 215) +#define MRECURSION217(macro, data) MRECURSION216( macro, DEC_(data)) macro(data, 216) +#define MRECURSION218(macro, data) MRECURSION217( macro, DEC_(data)) macro(data, 217) +#define MRECURSION219(macro, data) MRECURSION218( macro, DEC_(data)) macro(data, 218) +#define MRECURSION220(macro, data) MRECURSION219( macro, DEC_(data)) macro(data, 219) +#define MRECURSION221(macro, data) MRECURSION220( macro, DEC_(data)) macro(data, 220) +#define MRECURSION222(macro, data) MRECURSION221( macro, DEC_(data)) macro(data, 221) +#define MRECURSION223(macro, data) MRECURSION222( macro, DEC_(data)) macro(data, 222) +#define MRECURSION224(macro, data) MRECURSION223( macro, DEC_(data)) macro(data, 223) +#define MRECURSION225(macro, data) MRECURSION224( macro, DEC_(data)) macro(data, 224) +#define MRECURSION226(macro, data) MRECURSION225( macro, DEC_(data)) macro(data, 225) +#define MRECURSION227(macro, data) MRECURSION226( macro, DEC_(data)) macro(data, 226) +#define MRECURSION228(macro, data) MRECURSION227( macro, DEC_(data)) macro(data, 227) +#define MRECURSION229(macro, data) MRECURSION228( macro, DEC_(data)) macro(data, 228) +#define MRECURSION230(macro, data) MRECURSION229( macro, DEC_(data)) macro(data, 229) +#define MRECURSION231(macro, data) MRECURSION230( macro, DEC_(data)) macro(data, 230) +#define MRECURSION232(macro, data) MRECURSION231( macro, DEC_(data)) macro(data, 231) +#define MRECURSION233(macro, data) MRECURSION232( macro, DEC_(data)) macro(data, 232) +#define MRECURSION234(macro, data) MRECURSION233( macro, DEC_(data)) macro(data, 233) +#define MRECURSION235(macro, data) MRECURSION234( macro, DEC_(data)) macro(data, 234) +#define MRECURSION236(macro, data) MRECURSION235( macro, DEC_(data)) macro(data, 235) +#define MRECURSION237(macro, data) MRECURSION236( macro, DEC_(data)) macro(data, 236) +#define MRECURSION238(macro, data) MRECURSION237( macro, DEC_(data)) macro(data, 237) +#define MRECURSION239(macro, data) MRECURSION238( macro, DEC_(data)) macro(data, 238) +#define MRECURSION240(macro, data) MRECURSION239( macro, DEC_(data)) macro(data, 239) +#define MRECURSION241(macro, data) MRECURSION240( macro, DEC_(data)) macro(data, 240) +#define MRECURSION242(macro, data) MRECURSION241( macro, DEC_(data)) macro(data, 241) +#define MRECURSION243(macro, data) MRECURSION242( macro, DEC_(data)) macro(data, 242) +#define MRECURSION244(macro, data) MRECURSION243( macro, DEC_(data)) macro(data, 243) +#define MRECURSION245(macro, data) MRECURSION244( macro, DEC_(data)) macro(data, 244) +#define MRECURSION246(macro, data) MRECURSION245( macro, DEC_(data)) macro(data, 245) +#define MRECURSION247(macro, data) MRECURSION246( macro, DEC_(data)) macro(data, 246) +#define MRECURSION248(macro, data) MRECURSION247( macro, DEC_(data)) macro(data, 247) +#define MRECURSION249(macro, data) MRECURSION248( macro, DEC_(data)) macro(data, 248) +#define MRECURSION250(macro, data) MRECURSION249( macro, DEC_(data)) macro(data, 249) +#define MRECURSION251(macro, data) MRECURSION250( macro, DEC_(data)) macro(data, 250) +#define MRECURSION252(macro, data) MRECURSION251( macro, DEC_(data)) macro(data, 251) +#define MRECURSION253(macro, data) MRECURSION252( macro, DEC_(data)) macro(data, 252) +#define MRECURSION254(macro, data) MRECURSION253( macro, DEC_(data)) macro(data, 253) +#define MRECURSION255(macro, data) MRECURSION254( macro, DEC_(data)) macro(data, 254) +#define MRECURSION256(macro, data) MRECURSION255( macro, DEC_(data)) macro(data, 255) + +/** @} */ + +#endif /* _MRECURSION_H_ */ diff --git a/bootloaders/feather/utils/preprocessor/mrepeat.h b/bootloaders/feather/utils/preprocessor/mrepeat.h new file mode 100644 index 000000000..fb820d5bd --- /dev/null +++ b/bootloaders/feather/utils/preprocessor/mrepeat.h @@ -0,0 +1,321 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef _MREPEAT_H_ +#define _MREPEAT_H_ + +/** + * \defgroup group_sam0_utils_mrepeat Preprocessor - Macro Repeat + * + * \ingroup group_sam0_utils + * + * @{ + */ + +#include "preprocessor.h" + +/** Maximal number of repetitions supported by MREPEAT. */ +#define MREPEAT_LIMIT 256 + +/** \brief Macro repeat. + * + * This macro represents a horizontal repetition construct. + * + * \param[in] count The number of repetitious calls to macro. Valid values + * range from 0 to MREPEAT_LIMIT. + * \param[in] macro A binary operation of the form macro(n, data). This macro + * is expanded by MREPEAT with the current repetition number + * and the auxiliary data argument. + * \param[in] data Auxiliary data passed to macro. + * + * \return macro(0, data) macro(1, data) ... macro(count - 1, data) + */ +#define MREPEAT(count, macro, data) TPASTE2(MREPEAT, count) (macro, data) + +#define MREPEAT0( macro, data) +#define MREPEAT1( macro, data) MREPEAT0( macro, data) macro( 0, data) +#define MREPEAT2( macro, data) MREPEAT1( macro, data) macro( 1, data) +#define MREPEAT3( macro, data) MREPEAT2( macro, data) macro( 2, data) +#define MREPEAT4( macro, data) MREPEAT3( macro, data) macro( 3, data) +#define MREPEAT5( macro, data) MREPEAT4( macro, data) macro( 4, data) +#define MREPEAT6( macro, data) MREPEAT5( macro, data) macro( 5, data) +#define MREPEAT7( macro, data) MREPEAT6( macro, data) macro( 6, data) +#define MREPEAT8( macro, data) MREPEAT7( macro, data) macro( 7, data) +#define MREPEAT9( macro, data) MREPEAT8( macro, data) macro( 8, data) +#define MREPEAT10( macro, data) MREPEAT9( macro, data) macro( 9, data) +#define MREPEAT11( macro, data) MREPEAT10( macro, data) macro( 10, data) +#define MREPEAT12( macro, data) MREPEAT11( macro, data) macro( 11, data) +#define MREPEAT13( macro, data) MREPEAT12( macro, data) macro( 12, data) +#define MREPEAT14( macro, data) MREPEAT13( macro, data) macro( 13, data) +#define MREPEAT15( macro, data) MREPEAT14( macro, data) macro( 14, data) +#define MREPEAT16( macro, data) MREPEAT15( macro, data) macro( 15, data) +#define MREPEAT17( macro, data) MREPEAT16( macro, data) macro( 16, data) +#define MREPEAT18( macro, data) MREPEAT17( macro, data) macro( 17, data) +#define MREPEAT19( macro, data) MREPEAT18( macro, data) macro( 18, data) +#define MREPEAT20( macro, data) MREPEAT19( macro, data) macro( 19, data) +#define MREPEAT21( macro, data) MREPEAT20( macro, data) macro( 20, data) +#define MREPEAT22( macro, data) MREPEAT21( macro, data) macro( 21, data) +#define MREPEAT23( macro, data) MREPEAT22( macro, data) macro( 22, data) +#define MREPEAT24( macro, data) MREPEAT23( macro, data) macro( 23, data) +#define MREPEAT25( macro, data) MREPEAT24( macro, data) macro( 24, data) +#define MREPEAT26( macro, data) MREPEAT25( macro, data) macro( 25, data) +#define MREPEAT27( macro, data) MREPEAT26( macro, data) macro( 26, data) +#define MREPEAT28( macro, data) MREPEAT27( macro, data) macro( 27, data) +#define MREPEAT29( macro, data) MREPEAT28( macro, data) macro( 28, data) +#define MREPEAT30( macro, data) MREPEAT29( macro, data) macro( 29, data) +#define MREPEAT31( macro, data) MREPEAT30( macro, data) macro( 30, data) +#define MREPEAT32( macro, data) MREPEAT31( macro, data) macro( 31, data) +#define MREPEAT33( macro, data) MREPEAT32( macro, data) macro( 32, data) +#define MREPEAT34( macro, data) MREPEAT33( macro, data) macro( 33, data) +#define MREPEAT35( macro, data) MREPEAT34( macro, data) macro( 34, data) +#define MREPEAT36( macro, data) MREPEAT35( macro, data) macro( 35, data) +#define MREPEAT37( macro, data) MREPEAT36( macro, data) macro( 36, data) +#define MREPEAT38( macro, data) MREPEAT37( macro, data) macro( 37, data) +#define MREPEAT39( macro, data) MREPEAT38( macro, data) macro( 38, data) +#define MREPEAT40( macro, data) MREPEAT39( macro, data) macro( 39, data) +#define MREPEAT41( macro, data) MREPEAT40( macro, data) macro( 40, data) +#define MREPEAT42( macro, data) MREPEAT41( macro, data) macro( 41, data) +#define MREPEAT43( macro, data) MREPEAT42( macro, data) macro( 42, data) +#define MREPEAT44( macro, data) MREPEAT43( macro, data) macro( 43, data) +#define MREPEAT45( macro, data) MREPEAT44( macro, data) macro( 44, data) +#define MREPEAT46( macro, data) MREPEAT45( macro, data) macro( 45, data) +#define MREPEAT47( macro, data) MREPEAT46( macro, data) macro( 46, data) +#define MREPEAT48( macro, data) MREPEAT47( macro, data) macro( 47, data) +#define MREPEAT49( macro, data) MREPEAT48( macro, data) macro( 48, data) +#define MREPEAT50( macro, data) MREPEAT49( macro, data) macro( 49, data) +#define MREPEAT51( macro, data) MREPEAT50( macro, data) macro( 50, data) +#define MREPEAT52( macro, data) MREPEAT51( macro, data) macro( 51, data) +#define MREPEAT53( macro, data) MREPEAT52( macro, data) macro( 52, data) +#define MREPEAT54( macro, data) MREPEAT53( macro, data) macro( 53, data) +#define MREPEAT55( macro, data) MREPEAT54( macro, data) macro( 54, data) +#define MREPEAT56( macro, data) MREPEAT55( macro, data) macro( 55, data) +#define MREPEAT57( macro, data) MREPEAT56( macro, data) macro( 56, data) +#define MREPEAT58( macro, data) MREPEAT57( macro, data) macro( 57, data) +#define MREPEAT59( macro, data) MREPEAT58( macro, data) macro( 58, data) +#define MREPEAT60( macro, data) MREPEAT59( macro, data) macro( 59, data) +#define MREPEAT61( macro, data) MREPEAT60( macro, data) macro( 60, data) +#define MREPEAT62( macro, data) MREPEAT61( macro, data) macro( 61, data) +#define MREPEAT63( macro, data) MREPEAT62( macro, data) macro( 62, data) +#define MREPEAT64( macro, data) MREPEAT63( macro, data) macro( 63, data) +#define MREPEAT65( macro, data) MREPEAT64( macro, data) macro( 64, data) +#define MREPEAT66( macro, data) MREPEAT65( macro, data) macro( 65, data) +#define MREPEAT67( macro, data) MREPEAT66( macro, data) macro( 66, data) +#define MREPEAT68( macro, data) MREPEAT67( macro, data) macro( 67, data) +#define MREPEAT69( macro, data) MREPEAT68( macro, data) macro( 68, data) +#define MREPEAT70( macro, data) MREPEAT69( macro, data) macro( 69, data) +#define MREPEAT71( macro, data) MREPEAT70( macro, data) macro( 70, data) +#define MREPEAT72( macro, data) MREPEAT71( macro, data) macro( 71, data) +#define MREPEAT73( macro, data) MREPEAT72( macro, data) macro( 72, data) +#define MREPEAT74( macro, data) MREPEAT73( macro, data) macro( 73, data) +#define MREPEAT75( macro, data) MREPEAT74( macro, data) macro( 74, data) +#define MREPEAT76( macro, data) MREPEAT75( macro, data) macro( 75, data) +#define MREPEAT77( macro, data) MREPEAT76( macro, data) macro( 76, data) +#define MREPEAT78( macro, data) MREPEAT77( macro, data) macro( 77, data) +#define MREPEAT79( macro, data) MREPEAT78( macro, data) macro( 78, data) +#define MREPEAT80( macro, data) MREPEAT79( macro, data) macro( 79, data) +#define MREPEAT81( macro, data) MREPEAT80( macro, data) macro( 80, data) +#define MREPEAT82( macro, data) MREPEAT81( macro, data) macro( 81, data) +#define MREPEAT83( macro, data) MREPEAT82( macro, data) macro( 82, data) +#define MREPEAT84( macro, data) MREPEAT83( macro, data) macro( 83, data) +#define MREPEAT85( macro, data) MREPEAT84( macro, data) macro( 84, data) +#define MREPEAT86( macro, data) MREPEAT85( macro, data) macro( 85, data) +#define MREPEAT87( macro, data) MREPEAT86( macro, data) macro( 86, data) +#define MREPEAT88( macro, data) MREPEAT87( macro, data) macro( 87, data) +#define MREPEAT89( macro, data) MREPEAT88( macro, data) macro( 88, data) +#define MREPEAT90( macro, data) MREPEAT89( macro, data) macro( 89, data) +#define MREPEAT91( macro, data) MREPEAT90( macro, data) macro( 90, data) +#define MREPEAT92( macro, data) MREPEAT91( macro, data) macro( 91, data) +#define MREPEAT93( macro, data) MREPEAT92( macro, data) macro( 92, data) +#define MREPEAT94( macro, data) MREPEAT93( macro, data) macro( 93, data) +#define MREPEAT95( macro, data) MREPEAT94( macro, data) macro( 94, data) +#define MREPEAT96( macro, data) MREPEAT95( macro, data) macro( 95, data) +#define MREPEAT97( macro, data) MREPEAT96( macro, data) macro( 96, data) +#define MREPEAT98( macro, data) MREPEAT97( macro, data) macro( 97, data) +#define MREPEAT99( macro, data) MREPEAT98( macro, data) macro( 98, data) +#define MREPEAT100(macro, data) MREPEAT99( macro, data) macro( 99, data) +#define MREPEAT101(macro, data) MREPEAT100(macro, data) macro(100, data) +#define MREPEAT102(macro, data) MREPEAT101(macro, data) macro(101, data) +#define MREPEAT103(macro, data) MREPEAT102(macro, data) macro(102, data) +#define MREPEAT104(macro, data) MREPEAT103(macro, data) macro(103, data) +#define MREPEAT105(macro, data) MREPEAT104(macro, data) macro(104, data) +#define MREPEAT106(macro, data) MREPEAT105(macro, data) macro(105, data) +#define MREPEAT107(macro, data) MREPEAT106(macro, data) macro(106, data) +#define MREPEAT108(macro, data) MREPEAT107(macro, data) macro(107, data) +#define MREPEAT109(macro, data) MREPEAT108(macro, data) macro(108, data) +#define MREPEAT110(macro, data) MREPEAT109(macro, data) macro(109, data) +#define MREPEAT111(macro, data) MREPEAT110(macro, data) macro(110, data) +#define MREPEAT112(macro, data) MREPEAT111(macro, data) macro(111, data) +#define MREPEAT113(macro, data) MREPEAT112(macro, data) macro(112, data) +#define MREPEAT114(macro, data) MREPEAT113(macro, data) macro(113, data) +#define MREPEAT115(macro, data) MREPEAT114(macro, data) macro(114, data) +#define MREPEAT116(macro, data) MREPEAT115(macro, data) macro(115, data) +#define MREPEAT117(macro, data) MREPEAT116(macro, data) macro(116, data) +#define MREPEAT118(macro, data) MREPEAT117(macro, data) macro(117, data) +#define MREPEAT119(macro, data) MREPEAT118(macro, data) macro(118, data) +#define MREPEAT120(macro, data) MREPEAT119(macro, data) macro(119, data) +#define MREPEAT121(macro, data) MREPEAT120(macro, data) macro(120, data) +#define MREPEAT122(macro, data) MREPEAT121(macro, data) macro(121, data) +#define MREPEAT123(macro, data) MREPEAT122(macro, data) macro(122, data) +#define MREPEAT124(macro, data) MREPEAT123(macro, data) macro(123, data) +#define MREPEAT125(macro, data) MREPEAT124(macro, data) macro(124, data) +#define MREPEAT126(macro, data) MREPEAT125(macro, data) macro(125, data) +#define MREPEAT127(macro, data) MREPEAT126(macro, data) macro(126, data) +#define MREPEAT128(macro, data) MREPEAT127(macro, data) macro(127, data) +#define MREPEAT129(macro, data) MREPEAT128(macro, data) macro(128, data) +#define MREPEAT130(macro, data) MREPEAT129(macro, data) macro(129, data) +#define MREPEAT131(macro, data) MREPEAT130(macro, data) macro(130, data) +#define MREPEAT132(macro, data) MREPEAT131(macro, data) macro(131, data) +#define MREPEAT133(macro, data) MREPEAT132(macro, data) macro(132, data) +#define MREPEAT134(macro, data) MREPEAT133(macro, data) macro(133, data) +#define MREPEAT135(macro, data) MREPEAT134(macro, data) macro(134, data) +#define MREPEAT136(macro, data) MREPEAT135(macro, data) macro(135, data) +#define MREPEAT137(macro, data) MREPEAT136(macro, data) macro(136, data) +#define MREPEAT138(macro, data) MREPEAT137(macro, data) macro(137, data) +#define MREPEAT139(macro, data) MREPEAT138(macro, data) macro(138, data) +#define MREPEAT140(macro, data) MREPEAT139(macro, data) macro(139, data) +#define MREPEAT141(macro, data) MREPEAT140(macro, data) macro(140, data) +#define MREPEAT142(macro, data) MREPEAT141(macro, data) macro(141, data) +#define MREPEAT143(macro, data) MREPEAT142(macro, data) macro(142, data) +#define MREPEAT144(macro, data) MREPEAT143(macro, data) macro(143, data) +#define MREPEAT145(macro, data) MREPEAT144(macro, data) macro(144, data) +#define MREPEAT146(macro, data) MREPEAT145(macro, data) macro(145, data) +#define MREPEAT147(macro, data) MREPEAT146(macro, data) macro(146, data) +#define MREPEAT148(macro, data) MREPEAT147(macro, data) macro(147, data) +#define MREPEAT149(macro, data) MREPEAT148(macro, data) macro(148, data) +#define MREPEAT150(macro, data) MREPEAT149(macro, data) macro(149, data) +#define MREPEAT151(macro, data) MREPEAT150(macro, data) macro(150, data) +#define MREPEAT152(macro, data) MREPEAT151(macro, data) macro(151, data) +#define MREPEAT153(macro, data) MREPEAT152(macro, data) macro(152, data) +#define MREPEAT154(macro, data) MREPEAT153(macro, data) macro(153, data) +#define MREPEAT155(macro, data) MREPEAT154(macro, data) macro(154, data) +#define MREPEAT156(macro, data) MREPEAT155(macro, data) macro(155, data) +#define MREPEAT157(macro, data) MREPEAT156(macro, data) macro(156, data) +#define MREPEAT158(macro, data) MREPEAT157(macro, data) macro(157, data) +#define MREPEAT159(macro, data) MREPEAT158(macro, data) macro(158, data) +#define MREPEAT160(macro, data) MREPEAT159(macro, data) macro(159, data) +#define MREPEAT161(macro, data) MREPEAT160(macro, data) macro(160, data) +#define MREPEAT162(macro, data) MREPEAT161(macro, data) macro(161, data) +#define MREPEAT163(macro, data) MREPEAT162(macro, data) macro(162, data) +#define MREPEAT164(macro, data) MREPEAT163(macro, data) macro(163, data) +#define MREPEAT165(macro, data) MREPEAT164(macro, data) macro(164, data) +#define MREPEAT166(macro, data) MREPEAT165(macro, data) macro(165, data) +#define MREPEAT167(macro, data) MREPEAT166(macro, data) macro(166, data) +#define MREPEAT168(macro, data) MREPEAT167(macro, data) macro(167, data) +#define MREPEAT169(macro, data) MREPEAT168(macro, data) macro(168, data) +#define MREPEAT170(macro, data) MREPEAT169(macro, data) macro(169, data) +#define MREPEAT171(macro, data) MREPEAT170(macro, data) macro(170, data) +#define MREPEAT172(macro, data) MREPEAT171(macro, data) macro(171, data) +#define MREPEAT173(macro, data) MREPEAT172(macro, data) macro(172, data) +#define MREPEAT174(macro, data) MREPEAT173(macro, data) macro(173, data) +#define MREPEAT175(macro, data) MREPEAT174(macro, data) macro(174, data) +#define MREPEAT176(macro, data) MREPEAT175(macro, data) macro(175, data) +#define MREPEAT177(macro, data) MREPEAT176(macro, data) macro(176, data) +#define MREPEAT178(macro, data) MREPEAT177(macro, data) macro(177, data) +#define MREPEAT179(macro, data) MREPEAT178(macro, data) macro(178, data) +#define MREPEAT180(macro, data) MREPEAT179(macro, data) macro(179, data) +#define MREPEAT181(macro, data) MREPEAT180(macro, data) macro(180, data) +#define MREPEAT182(macro, data) MREPEAT181(macro, data) macro(181, data) +#define MREPEAT183(macro, data) MREPEAT182(macro, data) macro(182, data) +#define MREPEAT184(macro, data) MREPEAT183(macro, data) macro(183, data) +#define MREPEAT185(macro, data) MREPEAT184(macro, data) macro(184, data) +#define MREPEAT186(macro, data) MREPEAT185(macro, data) macro(185, data) +#define MREPEAT187(macro, data) MREPEAT186(macro, data) macro(186, data) +#define MREPEAT188(macro, data) MREPEAT187(macro, data) macro(187, data) +#define MREPEAT189(macro, data) MREPEAT188(macro, data) macro(188, data) +#define MREPEAT190(macro, data) MREPEAT189(macro, data) macro(189, data) +#define MREPEAT191(macro, data) MREPEAT190(macro, data) macro(190, data) +#define MREPEAT192(macro, data) MREPEAT191(macro, data) macro(191, data) +#define MREPEAT193(macro, data) MREPEAT192(macro, data) macro(192, data) +#define MREPEAT194(macro, data) MREPEAT193(macro, data) macro(193, data) +#define MREPEAT195(macro, data) MREPEAT194(macro, data) macro(194, data) +#define MREPEAT196(macro, data) MREPEAT195(macro, data) macro(195, data) +#define MREPEAT197(macro, data) MREPEAT196(macro, data) macro(196, data) +#define MREPEAT198(macro, data) MREPEAT197(macro, data) macro(197, data) +#define MREPEAT199(macro, data) MREPEAT198(macro, data) macro(198, data) +#define MREPEAT200(macro, data) MREPEAT199(macro, data) macro(199, data) +#define MREPEAT201(macro, data) MREPEAT200(macro, data) macro(200, data) +#define MREPEAT202(macro, data) MREPEAT201(macro, data) macro(201, data) +#define MREPEAT203(macro, data) MREPEAT202(macro, data) macro(202, data) +#define MREPEAT204(macro, data) MREPEAT203(macro, data) macro(203, data) +#define MREPEAT205(macro, data) MREPEAT204(macro, data) macro(204, data) +#define MREPEAT206(macro, data) MREPEAT205(macro, data) macro(205, data) +#define MREPEAT207(macro, data) MREPEAT206(macro, data) macro(206, data) +#define MREPEAT208(macro, data) MREPEAT207(macro, data) macro(207, data) +#define MREPEAT209(macro, data) MREPEAT208(macro, data) macro(208, data) +#define MREPEAT210(macro, data) MREPEAT209(macro, data) macro(209, data) +#define MREPEAT211(macro, data) MREPEAT210(macro, data) macro(210, data) +#define MREPEAT212(macro, data) MREPEAT211(macro, data) macro(211, data) +#define MREPEAT213(macro, data) MREPEAT212(macro, data) macro(212, data) +#define MREPEAT214(macro, data) MREPEAT213(macro, data) macro(213, data) +#define MREPEAT215(macro, data) MREPEAT214(macro, data) macro(214, data) +#define MREPEAT216(macro, data) MREPEAT215(macro, data) macro(215, data) +#define MREPEAT217(macro, data) MREPEAT216(macro, data) macro(216, data) +#define MREPEAT218(macro, data) MREPEAT217(macro, data) macro(217, data) +#define MREPEAT219(macro, data) MREPEAT218(macro, data) macro(218, data) +#define MREPEAT220(macro, data) MREPEAT219(macro, data) macro(219, data) +#define MREPEAT221(macro, data) MREPEAT220(macro, data) macro(220, data) +#define MREPEAT222(macro, data) MREPEAT221(macro, data) macro(221, data) +#define MREPEAT223(macro, data) MREPEAT222(macro, data) macro(222, data) +#define MREPEAT224(macro, data) MREPEAT223(macro, data) macro(223, data) +#define MREPEAT225(macro, data) MREPEAT224(macro, data) macro(224, data) +#define MREPEAT226(macro, data) MREPEAT225(macro, data) macro(225, data) +#define MREPEAT227(macro, data) MREPEAT226(macro, data) macro(226, data) +#define MREPEAT228(macro, data) MREPEAT227(macro, data) macro(227, data) +#define MREPEAT229(macro, data) MREPEAT228(macro, data) macro(228, data) +#define MREPEAT230(macro, data) MREPEAT229(macro, data) macro(229, data) +#define MREPEAT231(macro, data) MREPEAT230(macro, data) macro(230, data) +#define MREPEAT232(macro, data) MREPEAT231(macro, data) macro(231, data) +#define MREPEAT233(macro, data) MREPEAT232(macro, data) macro(232, data) +#define MREPEAT234(macro, data) MREPEAT233(macro, data) macro(233, data) +#define MREPEAT235(macro, data) MREPEAT234(macro, data) macro(234, data) +#define MREPEAT236(macro, data) MREPEAT235(macro, data) macro(235, data) +#define MREPEAT237(macro, data) MREPEAT236(macro, data) macro(236, data) +#define MREPEAT238(macro, data) MREPEAT237(macro, data) macro(237, data) +#define MREPEAT239(macro, data) MREPEAT238(macro, data) macro(238, data) +#define MREPEAT240(macro, data) MREPEAT239(macro, data) macro(239, data) +#define MREPEAT241(macro, data) MREPEAT240(macro, data) macro(240, data) +#define MREPEAT242(macro, data) MREPEAT241(macro, data) macro(241, data) +#define MREPEAT243(macro, data) MREPEAT242(macro, data) macro(242, data) +#define MREPEAT244(macro, data) MREPEAT243(macro, data) macro(243, data) +#define MREPEAT245(macro, data) MREPEAT244(macro, data) macro(244, data) +#define MREPEAT246(macro, data) MREPEAT245(macro, data) macro(245, data) +#define MREPEAT247(macro, data) MREPEAT246(macro, data) macro(246, data) +#define MREPEAT248(macro, data) MREPEAT247(macro, data) macro(247, data) +#define MREPEAT249(macro, data) MREPEAT248(macro, data) macro(248, data) +#define MREPEAT250(macro, data) MREPEAT249(macro, data) macro(249, data) +#define MREPEAT251(macro, data) MREPEAT250(macro, data) macro(250, data) +#define MREPEAT252(macro, data) MREPEAT251(macro, data) macro(251, data) +#define MREPEAT253(macro, data) MREPEAT252(macro, data) macro(252, data) +#define MREPEAT254(macro, data) MREPEAT253(macro, data) macro(253, data) +#define MREPEAT255(macro, data) MREPEAT254(macro, data) macro(254, data) +#define MREPEAT256(macro, data) MREPEAT255(macro, data) macro(255, data) + +/** @} */ + +#endif /* _MREPEAT_H_ */ diff --git a/bootloaders/feather/utils/preprocessor/preprocessor.h b/bootloaders/feather/utils/preprocessor/preprocessor.h new file mode 100644 index 000000000..7f67d8adf --- /dev/null +++ b/bootloaders/feather/utils/preprocessor/preprocessor.h @@ -0,0 +1,38 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef _PREPROCESSOR_H_ +#define _PREPROCESSOR_H_ + +#include "tpaste.h" +#include "stringz.h" +#include "mrepeat.h" +#include "mrecursion.h" + +#endif // _PREPROCESSOR_H_ diff --git a/bootloaders/feather/utils/preprocessor/stringz.h b/bootloaders/feather/utils/preprocessor/stringz.h new file mode 100644 index 000000000..70937c434 --- /dev/null +++ b/bootloaders/feather/utils/preprocessor/stringz.h @@ -0,0 +1,67 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef _STRINGZ_H_ +#define _STRINGZ_H_ + +/** + * \defgroup group_sam0_utils_stringz Preprocessor - Stringize + * + * \ingroup group_sam0_utils + * + * @{ + */ + +/** \brief Stringize. + * + * Stringize a preprocessing token, this token being allowed to be \#defined. + * + * May be used only within macros with the token passed as an argument if the + * token is \#defined. + * + * For example, writing STRINGZ(PIN) within a macro \#defined by PIN_NAME(PIN) + * and invoked as PIN_NAME(PIN0) with PIN0 \#defined as A0 is equivalent to + * writing "A0". + */ +#define STRINGZ(x) #x + +/** \brief Absolute stringize. + * + * Stringize a preprocessing token, this token being allowed to be \#defined. + * + * No restriction of use if the token is \#defined. + * + * For example, writing ASTRINGZ(PIN0) anywhere with PIN0 \#defined as A0 is + * equivalent to writing "A0". + */ +#define ASTRINGZ(x) STRINGZ(x) + +/** @} */ + +#endif // _STRINGZ_H_ diff --git a/bootloaders/feather/utils/preprocessor/tpaste.h b/bootloaders/feather/utils/preprocessor/tpaste.h new file mode 100644 index 000000000..910818347 --- /dev/null +++ b/bootloaders/feather/utils/preprocessor/tpaste.h @@ -0,0 +1,85 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ +#ifndef _TPASTE_H_ +#define _TPASTE_H_ + +/** + * \defgroup group_sam0_utils_tpaste Preprocessor - Token Paste + * + * \ingroup group_sam0_utils + * + * @{ + */ + +/** \name Token Paste + * + * Paste N preprocessing tokens together, these tokens being allowed to be \#defined. + * + * May be used only within macros with the tokens passed as arguments if the tokens are \#defined. + * + * For example, writing TPASTE2(U, WIDTH) within a macro \#defined by + * UTYPE(WIDTH) and invoked as UTYPE(UL_WIDTH) with UL_WIDTH \#defined as 32 is + * equivalent to writing U32. + * + * @{ */ +#define TPASTE2( a, b) a##b +#define TPASTE3( a, b, c) a##b##c +#define TPASTE4( a, b, c, d) a##b##c##d +#define TPASTE5( a, b, c, d, e) a##b##c##d##e +#define TPASTE6( a, b, c, d, e, f) a##b##c##d##e##f +#define TPASTE7( a, b, c, d, e, f, g) a##b##c##d##e##f##g +#define TPASTE8( a, b, c, d, e, f, g, h) a##b##c##d##e##f##g##h +#define TPASTE9( a, b, c, d, e, f, g, h, i) a##b##c##d##e##f##g##h##i +#define TPASTE10(a, b, c, d, e, f, g, h, i, j) a##b##c##d##e##f##g##h##i##j +/** @} */ + +/** \name Absolute Token Paste + * + * Paste N preprocessing tokens together, these tokens being allowed to be \#defined. + * + * No restriction of use if the tokens are \#defined. + * + * For example, writing ATPASTE2(U, UL_WIDTH) anywhere with UL_WIDTH \#defined + * as 32 is equivalent to writing U32. + * + * @{ */ +#define ATPASTE2( a, b) TPASTE2( a, b) +#define ATPASTE3( a, b, c) TPASTE3( a, b, c) +#define ATPASTE4( a, b, c, d) TPASTE4( a, b, c, d) +#define ATPASTE5( a, b, c, d, e) TPASTE5( a, b, c, d, e) +#define ATPASTE6( a, b, c, d, e, f) TPASTE6( a, b, c, d, e, f) +#define ATPASTE7( a, b, c, d, e, f, g) TPASTE7( a, b, c, d, e, f, g) +#define ATPASTE8( a, b, c, d, e, f, g, h) TPASTE8( a, b, c, d, e, f, g, h) +#define ATPASTE9( a, b, c, d, e, f, g, h, i) TPASTE9( a, b, c, d, e, f, g, h, i) +#define ATPASTE10(a, b, c, d, e, f, g, h, i, j) TPASTE10(a, b, c, d, e, f, g, h, i, j) +/** @} */ + +/** @} */ + +#endif // _TPASTE_H_ diff --git a/bootloaders/feather/utils/status_codes.h b/bootloaders/feather/utils/status_codes.h new file mode 100644 index 000000000..29bbf4166 --- /dev/null +++ b/bootloaders/feather/utils/status_codes.h @@ -0,0 +1,138 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011-2012, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following condition is met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef STATUS_CODES_H_INCLUDED +#define STATUS_CODES_H_INCLUDED + +#include + +/** + * \defgroup group_sam0_utils_status_codes Status Codes + * + * \ingroup group_sam0_utils + * + * @{ + */ + +/** Mask to retrieve the error category of a status code. */ +#define STATUS_CATEGORY_MASK 0xF0 + +/** Mask to retrieve the error code within the category of a status code. */ +#define STATUS_ERROR_MASK 0x0F + +/** Status code error categories. */ +enum status_categories { + STATUS_CATEGORY_OK = 0x00, + STATUS_CATEGORY_COMMON = 0x10, + STATUS_CATEGORY_ANALOG = 0x30, + STATUS_CATEGORY_COM = 0x40, + STATUS_CATEGORY_IO = 0x50, +}; + +/** + * Status code that may be returned by shell commands and protocol + * implementations. + * + * \note Any change to these status codes and the corresponding + * message strings is strictly forbidden. New codes can be added, + * however, but make sure that any message string tables are updated + * at the same time. + */ +enum status_code { + STATUS_OK = STATUS_CATEGORY_OK | 0x00, + STATUS_VALID_DATA = STATUS_CATEGORY_OK | 0x01, + STATUS_NO_CHANGE = STATUS_CATEGORY_OK | 0x02, + STATUS_ABORTED = STATUS_CATEGORY_OK | 0x04, + STATUS_BUSY = STATUS_CATEGORY_OK | 0x05, + STATUS_SUSPEND = STATUS_CATEGORY_OK | 0x06, + + STATUS_ERR_IO = STATUS_CATEGORY_COMMON | 0x00, + STATUS_ERR_REQ_FLUSHED = STATUS_CATEGORY_COMMON | 0x01, + STATUS_ERR_TIMEOUT = STATUS_CATEGORY_COMMON | 0x02, + STATUS_ERR_BAD_DATA = STATUS_CATEGORY_COMMON | 0x03, + STATUS_ERR_NOT_FOUND = STATUS_CATEGORY_COMMON | 0x04, + STATUS_ERR_UNSUPPORTED_DEV = STATUS_CATEGORY_COMMON | 0x05, + STATUS_ERR_NO_MEMORY = STATUS_CATEGORY_COMMON | 0x06, + STATUS_ERR_INVALID_ARG = STATUS_CATEGORY_COMMON | 0x07, + STATUS_ERR_BAD_ADDRESS = STATUS_CATEGORY_COMMON | 0x08, + STATUS_ERR_BAD_FORMAT = STATUS_CATEGORY_COMMON | 0x0A, + STATUS_ERR_BAD_FRQ = STATUS_CATEGORY_COMMON | 0x0B, + STATUS_ERR_DENIED = STATUS_CATEGORY_COMMON | 0x0c, + STATUS_ERR_ALREADY_INITIALIZED = STATUS_CATEGORY_COMMON | 0x0d, + STATUS_ERR_OVERFLOW = STATUS_CATEGORY_COMMON | 0x0e, + STATUS_ERR_NOT_INITIALIZED = STATUS_CATEGORY_COMMON | 0x0f, + + STATUS_ERR_SAMPLERATE_UNAVAILABLE = STATUS_CATEGORY_ANALOG | 0x00, + STATUS_ERR_RESOLUTION_UNAVAILABLE = STATUS_CATEGORY_ANALOG | 0x01, + + STATUS_ERR_BAUDRATE_UNAVAILABLE = STATUS_CATEGORY_COM | 0x00, + STATUS_ERR_PACKET_COLLISION = STATUS_CATEGORY_COM | 0x01, + STATUS_ERR_PROTOCOL = STATUS_CATEGORY_COM | 0x02, + + STATUS_ERR_PIN_MUX_INVALID = STATUS_CATEGORY_IO | 0x00, +}; +typedef enum status_code status_code_genare_t; + +/** + Status codes used by MAC stack. + */ +enum status_code_wireless { + //STATUS_OK = 0, //!< Success + ERR_IO_ERROR = -1, //!< I/O error + ERR_FLUSHED = -2, //!< Request flushed from queue + ERR_TIMEOUT = -3, //!< Operation timed out + ERR_BAD_DATA = -4, //!< Data integrity check failed + ERR_PROTOCOL = -5, //!< Protocol error + ERR_UNSUPPORTED_DEV = -6, //!< Unsupported device + ERR_NO_MEMORY = -7, //!< Insufficient memory + ERR_INVALID_ARG = -8, //!< Invalid argument + ERR_BAD_ADDRESS = -9, //!< Bad address + ERR_BUSY = -10, //!< Resource is busy + ERR_BAD_FORMAT = -11, //!< Data format not recognized + ERR_NO_TIMER = -12, //!< No timer available + ERR_TIMER_ALREADY_RUNNING = -13, //!< Timer already running + ERR_TIMER_NOT_RUNNING = -14, //!< Timer not running + + /** + * \brief Operation in progress + * + * This status code is for driver-internal use when an operation + * is currently being performed. + * + * \note Drivers should never return this status code to any + * callers. It is strictly for internal use. + */ + OPERATION_IN_PROGRESS = -128, +}; + +typedef enum status_code_wireless status_code_t; + +/** @} */ + +#endif /* STATUS_CODES_H_INCLUDED */ From 9ad4e0d69b81f1e520969a21aac5cc713133a483 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Tue, 17 Nov 2015 16:35:00 -0500 Subject: [PATCH 07/22] reverts bootloaders/zero changes --- bootloaders/zero/Makefile | 188 ++++- bootloaders/zero/README.md | 75 ++ bootloaders/zero/board_definitions.h | 72 ++ bootloaders/zero/board_driver_led.c | 22 + bootloaders/zero/board_driver_led.h | 41 ++ bootloaders/zero/board_driver_serial.c | 104 +++ bootloaders/zero/board_driver_serial.h | 90 +++ bootloaders/zero/board_driver_usb.c | 367 ++++++++++ bootloaders/zero/board_driver_usb.h | 45 ++ bootloaders/zero/board_init.c | 210 ++++++ bootloaders/zero/board_startup.c | 147 ++++ bootloaders/zero/bootloader_samd21x18.ld | 221 ++++++ bootloaders/zero/main.c | 437 ++++-------- bootloaders/zero/sam_ba_cdc.c | 98 +++ bootloaders/zero/sam_ba_cdc.h | 91 +++ bootloaders/zero/sam_ba_monitor.c | 783 +++++++++++---------- bootloaders/zero/sam_ba_monitor.h | 53 +- bootloaders/zero/sam_ba_serial.c | 534 ++++++++++++++ bootloaders/zero/sam_ba_serial.h | 143 ++++ bootloaders/zero/sam_ba_usb.c | 456 ++++++++++++ bootloaders/zero/sam_ba_usb.h | 107 +++ bootloaders/zero/samd21_sam_ba.atsln | 22 + bootloaders/zero/samd21_sam_ba.bin | Bin 6480 -> 5972 bytes bootloaders/zero/samd21_sam_ba.cproj | 218 ++++++ bootloaders/zero/samd21_sam_ba.elf | Bin 0 -> 647224 bytes bootloaders/zero/samd21_sam_ba.hex | 376 ++++++++++ bootloaders/zero/samd21_sam_ba_genuino.bin | Bin 0 -> 5972 bytes bootloaders/zero/samd21_sam_ba_genuino.hex | 376 ++++++++++ 28 files changed, 4560 insertions(+), 716 deletions(-) create mode 100644 bootloaders/zero/README.md create mode 100644 bootloaders/zero/board_definitions.h create mode 100644 bootloaders/zero/board_driver_led.c create mode 100644 bootloaders/zero/board_driver_led.h create mode 100644 bootloaders/zero/board_driver_serial.c create mode 100644 bootloaders/zero/board_driver_serial.h create mode 100644 bootloaders/zero/board_driver_usb.c create mode 100644 bootloaders/zero/board_driver_usb.h create mode 100644 bootloaders/zero/board_init.c create mode 100644 bootloaders/zero/board_startup.c create mode 100644 bootloaders/zero/bootloader_samd21x18.ld create mode 100644 bootloaders/zero/sam_ba_cdc.c create mode 100644 bootloaders/zero/sam_ba_cdc.h create mode 100644 bootloaders/zero/sam_ba_serial.c create mode 100644 bootloaders/zero/sam_ba_serial.h create mode 100644 bootloaders/zero/sam_ba_usb.c create mode 100644 bootloaders/zero/sam_ba_usb.h create mode 100644 bootloaders/zero/samd21_sam_ba.atsln create mode 100644 bootloaders/zero/samd21_sam_ba.cproj create mode 100644 bootloaders/zero/samd21_sam_ba.elf create mode 100644 bootloaders/zero/samd21_sam_ba.hex create mode 100755 bootloaders/zero/samd21_sam_ba_genuino.bin create mode 100644 bootloaders/zero/samd21_sam_ba_genuino.hex diff --git a/bootloaders/zero/Makefile b/bootloaders/zero/Makefile index 1531b592e..eee929188 100644 --- a/bootloaders/zero/Makefile +++ b/bootloaders/zero/Makefile @@ -1,29 +1,179 @@ -IDE_PATH=../../../../.. -ARM_GCC_PATH=$(IDE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin -CC=$(ARM_GCC_PATH)/arm-none-eabi-gcc -CFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -c -g -Os -w -std=gnu99 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -LDFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -BLD_EXTA_FLAGS=-D__SAMD21G18A__ +# Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. +# Copyright (c) 2015 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# ----------------------------------------------------------------------------- +# Paths +ifeq ($(OS),Windows_NT) + + # Are we using mingw/msys/msys2/cygwin? + ifeq ($(TERM),xterm) +# this is the path coming with night build +# T=$(shell cygpath -u $(LOCALAPPDATA)) +# this is the path till 1.6.5 r5 + T=$(shell cygpath -u $(APPDATA)) + MODULE_PATH?=$(T)/Arduino15/packages/arduino + ARM_GCC_PATH?=$(MODULE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi- + RM=rm + SEP=/ + else +# this is the path coming with night build +# MODULE_PATH?=$(LOCALAPPDATA)/Arduino15/packages/arduino +# this is the path till 1.6.5 r5 + MODULE_PATH?=$(APPDATA)/Arduino15/packages/arduino + ARM_GCC_PATH?=$(MODULE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi- + RM=rm + SEP=\\ + endif +else + UNAME_S := $(shell uname -s) + + ifeq ($(UNAME_S),Linux) + MODULE_PATH?=$(HOME)/.arduino15/packages/arduino + ARM_GCC_PATH?=$(MODULE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi- + RM=rm + SEP=/ + endif + + ifeq ($(UNAME_S),Darwin) + MODULE_PATH?=$(HOME)/Library/Arduino15/packages/arduino/ + ARM_GCC_PATH?=$(MODULE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi- + RM=rm + SEP=/ + endif +endif + BUILD_PATH=build -INCLUDES=-I$(IDE_PATH)/tools/CMSIS/CMSIS/Include/ -I$(IDE_PATH)/tools/CMSIS/4.0.0-atmel/Device/ATMEL/ -I$(IDE_PATH)/tools/CMSIS/4.0.0-atmel/CMSIS/Include/ -I./drivers/ -I./utils/ -I./utils/preprocessor/ -I./utils/interrupt -SOURCES=main.c sam_ba_monitor.c startup_samd21.c usart_sam_ba.c drivers/cdc_enumerate.c drivers/uart_driver.c utils/interrupt/interrupt_sam_nvic.c + +# ----------------------------------------------------------------------------- +# Tools +CC=$(ARM_GCC_PATH)gcc +OBJCOPY=$(ARM_GCC_PATH)objcopy +NM=$(ARM_GCC_PATH)nm +SIZE=$(ARM_GCC_PATH)size + +# ----------------------------------------------------------------------------- +# Compiler options +CFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -c -std=gnu99 -ffunction-sections -fdata-sections -nostdlib -nostartfiles --param max-inline-insns-single=500 +ifdef DEBUG +CFLAGS+=-g3 -O1 -DDEBUG=1 +else +CFLAGS+=-Os -DDEBUG=0 +endif + +# Arduino Zero (PID == 0x004D) +CFLAGS_EXTRA?=-D__SAMD21G18A__ -DUSB_PID_HIGH=0x00 -DUSB_PID_LOW=0x4D +# Genuino Zero (PID == 0x024D) +# CFLAGS_EXTRA?=-D__SAMD21G18A__ -DUSB_PID_HIGH=0x02 -DUSB_PID_LOW=0x4D + +INCLUDES=-I"$(MODULE_PATH)/tools/CMSIS/4.0.0-atmel/CMSIS/Include/" -I"$(MODULE_PATH)/tools/CMSIS/4.0.0-atmel/Device/ATMEL/" + +# ----------------------------------------------------------------------------- +# Linker options +LDFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all +LDFLAGS+=-Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols --specs=nano.specs --specs=nosys.specs + +# ----------------------------------------------------------------------------- +# Source files and objects +SOURCES= \ +board_driver_led.c \ +board_driver_serial.c \ +board_driver_usb.c \ +board_init.c \ +board_startup.c \ +main.c \ +sam_ba_usb.c \ +sam_ba_cdc.c \ +sam_ba_monitor.c \ +sam_ba_serial.c + OBJECTS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.o)) +DEPS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.d)) NAME=samd21_sam_ba -EXECUTABLE=$(NAME).bin +ELF=$(NAME).elf +BIN=$(NAME).bin +HEX=$(NAME).hex + +ifneq "test$(AVRSTUDIO_EXE_PATH)" "test" +AS_BUILD=copy_for_atmel_studio +AS_CLEAN=clean_for_atmel_studio +else +AS_BUILD= +AS_CLEAN= +endif + + +all: print_info $(SOURCES) $(BIN) $(HEX) $(AS_BUILD) -SLASH=/ -BSLASH=$(EMPTY)\$(EMPTY) +$(ELF): Makefile $(BUILD_PATH) $(OBJECTS) + @echo ---------------------------------------------------------- + @echo Creating ELF binary + "$(CC)" -L. -L$(BUILD_PATH) $(LDFLAGS) -Os -Wl,--gc-sections -save-temps -Tbootloader_samd21x18.ld -Wl,-Map,"$(BUILD_PATH)/$(NAME).map" -o "$(BUILD_PATH)/$(ELF)" -Wl,--start-group $(OBJECTS) -lm -Wl,--end-group + "$(NM)" "$(BUILD_PATH)/$(ELF)" >"$(BUILD_PATH)/$(NAME)_symbols.txt" + "$(SIZE)" --format=sysv -t -x $(BUILD_PATH)/$(ELF) -all: $(SOURCES) $(EXECUTABLE) +$(BIN): $(ELF) + @echo ---------------------------------------------------------- + @echo Creating flash binary + "$(OBJCOPY)" -O binary $(BUILD_PATH)/$< $@ -$(EXECUTABLE): $(OBJECTS) - $(CC) -L$(BUILD_PATH) $(LDFLAGS) -Os -Wl,--gc-sections -save-temps -Tsamd21j18a_flash.ld -Wl,-Map,$(BUILD_PATH)/$(NAME).map --specs=nano.specs --specs=nosys.specs -o $(BUILD_PATH)/$(NAME).elf $(OBJECTS) -Wl,--start-group -lm -Wl,--end-group - $(ARM_GCC_PATH)/arm-none-eabi-objcopy -O binary $(BUILD_PATH)/$(NAME).elf $@ +$(HEX): $(ELF) + @echo ---------------------------------------------------------- + @echo Creating flash binary + "$(OBJCOPY)" -O ihex $(BUILD_PATH)/$< $@ $(BUILD_PATH)/%.o: %.c - -@mkdir -p $(@D) - $(CC) $(CFLAGS) $(BLD_EXTA_FLAGS) $(INCLUDES) $< -o $@ + @echo ---------------------------------------------------------- + @echo Compiling $< to $@ + "$(CC)" $(CFLAGS) $(CFLAGS_EXTRA) $(INCLUDES) $< -o $@ + @echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +$(BUILD_PATH): + @echo ---------------------------------------------------------- + @echo Creating build folder + -mkdir $(BUILD_PATH) + +print_info: + @echo ---------------------------------------------------------- + @echo Compiling bootloader using + @echo BASE PATH = $(MODULE_PATH) + @echo GCC PATH = $(ARM_GCC_PATH) +# @echo OS = $(OS) +# @echo SHELL = $(SHELL) +# @echo TERM = $(TERM) +# "$(CC)" -v +# env + +copy_for_atmel_studio: $(BIN) $(HEX) + @echo ---------------------------------------------------------- + @echo Atmel Studio detected, copying ELF to project root for debug + cp $(BUILD_PATH)/$(ELF) . + +clean_for_atmel_studio: + @echo ---------------------------------------------------------- + @echo Atmel Studio detected, cleaning ELF from project root + -$(RM) ./$(ELF) + +clean: $(AS_CLEAN) + @echo ---------------------------------------------------------- + @echo Cleaning project + -$(RM) $(BIN) + -$(RM) $(HEX) + -$(RM) $(BUILD_PATH)/*.* + -rmdir $(BUILD_PATH) -clean: - del $(EXECUTABLE) $(subst /,\,$(OBJECTS)) $(subst /,\,$(BUILD_PATH)/$(NAME).*) +.phony: print_info $(BUILD_PATH) diff --git a/bootloaders/zero/README.md b/bootloaders/zero/README.md new file mode 100644 index 000000000..44f4e4e02 --- /dev/null +++ b/bootloaders/zero/README.md @@ -0,0 +1,75 @@ +# Arduino Zero Bootloader + +## 1- Prerequisites + +The project build is based on Makefile system. +Makefile is present at project root and try to handle multi-platform cases. + +Multi-plaform GCC is provided by ARM here: https://launchpad.net/gcc-arm-embedded/+download + +Atmel Studio contains both make and ARM GCC toolchain. You don't need to install them in this specific use case. + +### Windows + +* Native command line +Make binary can be obtained here: http://gnuwin32.sourceforge.net/packages/make.htm + +* Cygwin/MSys/MSys2/Babun/etc... +It is available natively in all distributions. + +* Atmel Studio +An Atmel Studio **7** Makefile-based project is present at project root, just open samd21_sam_ba.atsln file in AS7. + +### Linux + +Make is usually available by default. + +### OS X + +Make is available through XCode package. + + +## 2- Selecting available SAM-BA interfaces + +By default both USB and UART are made available, but this parameter can be modified in sam_ba_monitor.h, line 31: + +Set the define SAM_BA_INTERFACE to +* SAM_BA_UART_ONLY for only UART interface +* SAM_BA_USBCDC_ONLY for only USB CDC interface +* SAM_BA_BOTH_INTERFACES for enabling both the interfaces + +## 3- Behaviour + +This bootloader implements the double-tap on Reset button. +By quickly pressing this button two times, the board will reset and stay in bootloader, waiting for communication on either USB or USART. + +The USB port in use is the USB Native port, close to the Reset button. +The USART in use is the one available on pins D0/D1, labelled respectively RX/TX. Communication parameters are a baudrate at 115200, 8bits of data, no parity and 1 stop bit (8N1). + +## 4- Description + +**Pinmap** + +The following pins are used by the program : +PA25 : input/output (USB DP) +PA24 : input/output (USB DM) +PA11 : input (USART RX) +PA10 : output (USART TX) + +The application board shall avoid driving the PA25, PA24, PB23 and PB22 signals while the boot program is running (after a POR for example). + +**Clock system** + +CPU runs at 48MHz from Generic Clock Generator 0 on DFLL48M. + +Generic Clock Generator 1 is using external 32kHz oscillator and is the source of DFLL48M. + +USB and USART are using Generic Clock Generator 0 also. + +**Memory Mapping** + +Bootloader code will be located at 0x0 and executed before any applicative code. + +Applications compiled to be executed along with the bootloader will start at 0x2000 (see linker script bootloader_samd21x18.ld). + +Before jumping to the application, the bootloader changes the VTOR register to use the interrupt vectors of the application @0x2000.<- not required as application code is taking care of this. diff --git a/bootloaders/zero/board_definitions.h b/bootloaders/zero/board_definitions.h new file mode 100644 index 000000000..458e1b0a7 --- /dev/null +++ b/bootloaders/zero/board_definitions.h @@ -0,0 +1,72 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _BOARD_DEFINITIONS_H_ +#define _BOARD_DEFINITIONS_H_ + +/* + * If BOOT_DOUBLE_TAP_ADDRESS is defined the bootloader is started by + * quickly tapping two times on the reset button. + * BOOT_DOUBLE_TAP_ADDRESS must point to a free SRAM cell that must not + * be touched from the loaded application. + */ +#define BOOT_DOUBLE_TAP_ADDRESS (0x20007FFCul) +#define BOOT_DOUBLE_TAP_DATA (*((volatile uint32_t *) BOOT_DOUBLE_TAP_ADDRESS)) + +/* + * If BOOT_LOAD_PIN is defined the bootloader is started if the selected + * pin is tied LOW. + */ +//#define BOOT_LOAD_PIN PIN_PA21 // Pin 7 +//#define BOOT_LOAD_PIN PIN_PA15 // Pin 5 +#define BOOT_PIN_MASK (1U << (BOOT_LOAD_PIN & 0x1f)) + +#define CPU_FREQUENCY (48000000ul) + +#define BOOT_USART_MODULE SERCOM0 +#define BOOT_USART_BUS_CLOCK_INDEX PM_APBCMASK_SERCOM0 +#define BOOT_USART_PER_CLOCK_INDEX GCLK_ID_SERCOM0_CORE +#define BOOT_USART_PAD_SETTINGS UART_RX_PAD3_TX_PAD2 +#define BOOT_USART_PAD3 PINMUX_PA11C_SERCOM0_PAD3 +#define BOOT_USART_PAD2 PINMUX_PA10C_SERCOM0_PAD2 +#define BOOT_USART_PAD1 PINMUX_UNUSED +#define BOOT_USART_PAD0 PINMUX_UNUSED + +/* Frequency of the board main oscillator */ +#define VARIANT_MAINOSC (32768ul) + +/* Master clock frequency */ +#define VARIANT_MCK CPU_FREQUENCY + +#define NVM_SW_CALIB_DFLL48M_COARSE_VAL (58) +#define NVM_SW_CALIB_DFLL48M_FINE_VAL (64) + +/* + * LEDs definitions + */ +#define BOARD_LED_PORT (0) +#define BOARD_LED_PIN (17) + +#define BOARD_LEDRX_PORT (1) +#define BOARD_LEDRX_PIN (3) + +#define BOARD_LEDTX_PORT (0) +#define BOARD_LEDTX_PIN (27) + +#endif // _BOARD_DEFINITIONS_H_ diff --git a/bootloaders/zero/board_driver_led.c b/bootloaders/zero/board_driver_led.c new file mode 100644 index 000000000..1a2430aff --- /dev/null +++ b/bootloaders/zero/board_driver_led.c @@ -0,0 +1,22 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "board_driver_led.h" + + diff --git a/bootloaders/zero/board_driver_led.h b/bootloaders/zero/board_driver_led.h new file mode 100644 index 000000000..6f1fd7580 --- /dev/null +++ b/bootloaders/zero/board_driver_led.h @@ -0,0 +1,41 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _BOARD_DRIVER_LED_ +#define _BOARD_DRIVER_LED_ + +#include +#include "board_definitions.h" + +inline void LED_init(void) { PORT->Group[BOARD_LED_PORT].DIRSET.reg = (1<Group[BOARD_LED_PORT].OUTSET.reg = (1<Group[BOARD_LED_PORT].OUTCLR.reg = (1<Group[BOARD_LED_PORT].OUTTGL.reg = (1<Group[BOARD_LEDRX_PORT].DIRSET.reg = (1<Group[BOARD_LEDRX_PORT].OUTSET.reg = (1<Group[BOARD_LEDRX_PORT].OUTCLR.reg = (1<Group[BOARD_LEDRX_PORT].OUTTGL.reg = (1<Group[BOARD_LEDTX_PORT].DIRSET.reg = (1<Group[BOARD_LEDTX_PORT].OUTSET.reg = (1<Group[BOARD_LEDTX_PORT].OUTCLR.reg = (1<Group[BOARD_LEDTX_PORT].OUTTGL.reg = (1<USART.SYNCBUSY.bit.ENABLE); + /* Disable the SERCOM UART module */ + sercom->USART.CTRLA.bit.ENABLE = 0; + /* Wait for synchronization */ + while(sercom->USART.SYNCBUSY.bit.SWRST); + /* Perform a software reset */ + sercom->USART.CTRLA.bit.SWRST = 1; + /* Wait for synchronization */ + while(sercom->USART.CTRLA.bit.SWRST); + /* Wait for synchronization */ + while(sercom->USART.SYNCBUSY.bit.SWRST || sercom->USART.SYNCBUSY.bit.ENABLE); + /* Update the UART pad settings, mode and data order settings */ + sercom->USART.CTRLA.reg = pad_conf | SERCOM_USART_CTRLA_MODE(1) | SERCOM_USART_CTRLA_DORD; + /* Wait for synchronization */ + while(sercom->USART.SYNCBUSY.bit.CTRLB); + /* Enable transmit and receive and set data size to 8 bits */ + sercom->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_CHSIZE(0); + /* Load the baud value */ + sercom->USART.BAUD.reg = baud_val; + /* Wait for synchronization */ + while(sercom->USART.SYNCBUSY.bit.ENABLE); + /* Enable SERCOM UART */ + sercom->USART.CTRLA.bit.ENABLE = 1; +} + +void uart_disable(Sercom *sercom) +{ + /* Wait for synchronization */ + while(sercom->USART.SYNCBUSY.bit.ENABLE); + /* Disable SERCOM UART */ + sercom->USART.CTRLA.bit.ENABLE = 0; +} + +void uart_write_byte(Sercom *sercom, uint8_t data) +{ + /* Wait for Data Register Empty flag */ + while(!sercom->USART.INTFLAG.bit.DRE); + /* Write the data to DATA register */ + sercom->USART.DATA.reg = (uint16_t)data; +} + +uint8_t uart_read_byte(Sercom *sercom) +{ + /* Wait for Receive Complete flag */ + while(!sercom->USART.INTFLAG.bit.RXC); + /* Check for errors */ + if (sercom->USART.STATUS.bit.PERR || sercom->USART.STATUS.bit.FERR || sercom->USART.STATUS.bit.BUFOVF) + /* Set the error flag */ + uart_drv_error_flag = true; + /* Return the read data */ + return((uint8_t)sercom->USART.DATA.reg); +} + +void uart_write_buffer_polled(Sercom *sercom, uint8_t *ptr, uint16_t length) +{ + /* Do the following for specified length */ + do { + /* Wait for Data Register Empty flag */ + while(!sercom->USART.INTFLAG.bit.DRE); + /* Send data from the buffer */ + sercom->USART.DATA.reg = (uint16_t)*ptr++; + } while (length--); +} + +void uart_read_buffer_polled(Sercom *sercom, uint8_t *ptr, uint16_t length) +{ + /* Do the following for specified length */ + do { + /* Wait for Receive Complete flag */ + while(!sercom->USART.INTFLAG.bit.RXC); + /* Check for errors */ + if (sercom->USART.STATUS.bit.PERR || sercom->USART.STATUS.bit.FERR || sercom->USART.STATUS.bit.BUFOVF) + /* Set the error flag */ + uart_drv_error_flag = true; + /* Store the read data to the buffer */ + *ptr++ = (uint8_t)sercom->USART.DATA.reg; + } while (length--); +} diff --git a/bootloaders/zero/board_driver_serial.h b/bootloaders/zero/board_driver_serial.h new file mode 100644 index 000000000..c752d977d --- /dev/null +++ b/bootloaders/zero/board_driver_serial.h @@ -0,0 +1,90 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef UART_DRIVER_H +#define UART_DRIVER_H + +#include +#include +#include + +#define PINMUX_UNUSED 0xFFFFFFFF +#define GCLK_ID_SERCOM0_CORE 0x14 + +/* SERCOM UART available pad settings */ +enum uart_pad_settings { + UART_RX_PAD0_TX_PAD2 = SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(1), + UART_RX_PAD1_TX_PAD2 = SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(1), + UART_RX_PAD2_TX_PAD0 = SERCOM_USART_CTRLA_RXPO(2), + UART_RX_PAD3_TX_PAD0 = SERCOM_USART_CTRLA_RXPO(3), + UART_RX_PAD1_TX_PAD0 = SERCOM_USART_CTRLA_RXPO(1), + UART_RX_PAD3_TX_PAD2 = SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(1), +}; + +/** + * \brief Initializes the UART + * + * \param Pointer to SERCOM instance + * \param Baud value corresponding to the desired baudrate + * \param SERCOM pad settings + */ +void uart_basic_init(Sercom *sercom, uint16_t baud_val, enum uart_pad_settings pad_conf); + +/** + * \brief Disables UART interface + * + * \param Pointer to SERCOM instance + */ +void uart_disable(Sercom *sercom); + +/** + * \brief Sends a single byte through UART interface + * + * \param Pointer to SERCOM instance + * \param Data to send + */ +void uart_write_byte(Sercom *sercom, uint8_t data); + +/** + * \brief Reads a single character from UART interface + * + * \param Pointer to SERCOM instance + * \return Data byte read + */ +uint8_t uart_read_byte(Sercom *sercom); + +/** + * \brief Sends buffer on UART interface + * + * \param Pointer to SERCOM instance + * \param Pointer to data to send + * \param Number of bytes to send + */ +void uart_write_buffer_polled(Sercom *sercom, uint8_t *ptr, uint16_t length); + +/** + * \brief Reads data on UART interface + * + * \param Pointer to SERCOM instance + * \param Pointer to store read data + * \param Number of bytes to read + */ +void uart_read_buffer_polled(Sercom *sercom, uint8_t *ptr, uint16_t length); + +#endif diff --git a/bootloaders/zero/board_driver_usb.c b/bootloaders/zero/board_driver_usb.c new file mode 100644 index 000000000..6534fa338 --- /dev/null +++ b/bootloaders/zero/board_driver_usb.c @@ -0,0 +1,367 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "board_driver_usb.h" +#include "sam_ba_usb.h" +#include "sam_ba_cdc.h" + +#define NVM_USB_PAD_TRANSN_POS (45) +#define NVM_USB_PAD_TRANSN_SIZE (5) +#define NVM_USB_PAD_TRANSP_POS (50) +#define NVM_USB_PAD_TRANSP_SIZE (5) +#define NVM_USB_PAD_TRIM_POS (55) +#define NVM_USB_PAD_TRIM_SIZE (3) + +__attribute__((__aligned__(4))) UsbDeviceDescriptor usb_endpoint_table[MAX_EP]; // Initialized to zero in USB_Init +__attribute__((__aligned__(4))) uint8_t udd_ep_out_cache_buffer[2][64]; //1 for CTRL, 1 for BULK +__attribute__((__aligned__(4))) uint8_t udd_ep_in_cache_buffer[2][64]; //1 for CTRL, 1 for BULK + +static volatile bool read_job = false; + +/*---------------------------------------------------------------------------- + * \brief + */ +P_USB_CDC USB_Open(P_USB_CDC pCdc, Usb *pUsb) +{ + pCdc->pUsb = pUsb; + pCdc->currentConfiguration = 0; + pCdc->currentConnection = 0; + pCdc->IsConfigured = USB_IsConfigured; +// pCdc->Write = USB_Write; +// pCdc->Read = USB_Read; + + pCdc->pUsb->HOST.CTRLA.bit.ENABLE = true; + + return pCdc; +} + +/*---------------------------------------------------------------------------- + * \brief Initializes USB + */ +void USB_Init(void) +{ + uint32_t pad_transn, pad_transp, pad_trim; + + /* Enable USB clock */ + PM->APBBMASK.reg |= PM_APBBMASK_USB; + + /* Set up the USB DP/DN pins */ + PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); + PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); + PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); + PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); + + /* ---------------------------------------------------------------------------------------------- + * Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference) + */ + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( 6 ) | // Generic Clock Multiplexer 6 + GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source + GCLK_CLKCTRL_CLKEN ; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* Reset */ + USB->DEVICE.CTRLA.bit.SWRST = 1; + while (USB->DEVICE.SYNCBUSY.bit.SWRST) + { + /* Sync wait */ + } + + /* Load Pad Calibration */ + pad_transn =( *((uint32_t *)(NVMCTRL_OTP4) + + (NVM_USB_PAD_TRANSN_POS / 32)) + >> (NVM_USB_PAD_TRANSN_POS % 32)) + & ((1 << NVM_USB_PAD_TRANSN_SIZE) - 1); + + if (pad_transn == 0x1F) + { + pad_transn = 5; + } + + USB->HOST.PADCAL.bit.TRANSN = pad_transn; + + pad_transp =( *((uint32_t *)(NVMCTRL_OTP4) + + (NVM_USB_PAD_TRANSP_POS / 32)) + >> (NVM_USB_PAD_TRANSP_POS % 32)) + & ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1); + + if (pad_transp == 0x1F) + { + pad_transp = 29; + } + + USB->HOST.PADCAL.bit.TRANSP = pad_transp; + pad_trim =( *((uint32_t *)(NVMCTRL_OTP4) + + (NVM_USB_PAD_TRIM_POS / 32)) + >> (NVM_USB_PAD_TRIM_POS % 32)) + & ((1 << NVM_USB_PAD_TRIM_SIZE) - 1); + + if (pad_trim == 0x7) + { + pad_trim = 3; + } + + USB->HOST.PADCAL.bit.TRIM = pad_trim; + + /* Set the configuration */ + /* Set mode to Device mode */ + USB->HOST.CTRLA.bit.MODE = 0; + /* Enable Run in Standby */ + USB->HOST.CTRLA.bit.RUNSTDBY = true; + /* Set the descriptor address */ + USB->HOST.DESCADD.reg = (uint32_t)(&usb_endpoint_table[0]); + /* Set speed configuration to Full speed */ + USB->DEVICE.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val; + /* Attach to the USB host */ + USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH; + + /* Initialize endpoint table RAM location to a known value 0 */ + memset((uint8_t *)(&usb_endpoint_table[0]), 0, sizeof(usb_endpoint_table)); +} + +uint32_t USB_Write(Usb *pUsb, const char *pData, uint32_t length, uint8_t ep_num) +{ + uint32_t data_address; + uint8_t buf_index; + + /* Set buffer index */ + buf_index = (ep_num == 0) ? 0 : 1; + + /* Check for requirement for multi-packet or auto zlp */ + if (length >= (1 << (usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.SIZE + 3))) + { + /* Update the EP data address */ + data_address = (uint32_t) pData; + /* Enable auto zlp */ + usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = true; + } + else + { + /* Copy to local buffer */ + memcpy(udd_ep_in_cache_buffer[buf_index], pData, length); + /* Update the EP data address */ + data_address = (uint32_t) &udd_ep_in_cache_buffer[buf_index]; + } + + /* Set the buffer address for ep data */ + usb_endpoint_table[ep_num].DeviceDescBank[1].ADDR.reg = data_address; + /* Set the byte count as zero */ + usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = length; + /* Set the multi packet size as zero for multi-packet transfers where length > ep size */ + usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = 0; + /* Clear the transfer complete flag */ + //pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT1 = true; + pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT |= (1<<1); + /* Set the bank as ready */ + pUsb->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.bit.BK1RDY = true; + + /* Wait for transfer to complete */ + while ( (pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT & (1<<1)) == 0 ); + + return length; +} + +/*---------------------------------------------------------------------------- + * \brief Read available data from Endpoint OUT + */ +uint32_t USB_Read(Usb *pUsb, char *pData, uint32_t length) +{ + uint32_t packetSize = 0; + + if (!read_job) + { + /* Set the buffer address for ep data */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[USB_EP_OUT-1]; + /* Set the byte count as zero */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; + /* Set the byte count as zero */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 0; + /* Start the reception by clearing the bank 0 ready bit */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSCLR.bit.BK0RDY = true; + /* set the user flag */ + read_job = true; + } + + /* Check for Transfer Complete 0 flag */ + if ( pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0) ) + { + /* Set packet size */ + packetSize = SAM_BA_MIN(usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT, length); + /* Copy read data to user buffer */ + memcpy(pData, udd_ep_out_cache_buffer[USB_EP_OUT-1], packetSize); + /* Clear the Transfer Complete 0 flag */ + //pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT0 = true; + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT |= (1 << 0); + /* Clear the user flag */ + read_job = false; + } + + return packetSize; +} + +uint32_t USB_Read_blocking(Usb *pUsb, char *pData, uint32_t length) +{ + if (read_job) + { + /* Stop the reception by setting the bank 0 ready bit */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSSET.bit.BK0RDY = true; + /* Clear the user flag */ + read_job = false; + } + + /* Set the buffer address for ep data */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = ((uint32_t)pData); + /* Set the byte count as zero */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; + /* Set the multi packet size as zero for multi-packet transfers where length > ep size */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = length; + /* Clear the bank 0 ready flag */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSCLR.bit.BK0RDY = true; + /* Wait for transfer to complete */ + while (!( pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0) )); + /* Clear Transfer complete 0 flag */ + //pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT0 = true; + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT |= (1 << 0); + + return length; +} + +/*---------------------------------------------------------------------------- + * \brief Test if the device is configured and handle enumeration + */ +uint8_t USB_IsConfigured(P_USB_CDC pCdc) +{ + Usb *pUsb = pCdc->pUsb; + + /* Check for End of Reset flag */ + if (pUsb->DEVICE.INTFLAG.reg & USB_DEVICE_INTFLAG_EORST) + { + /* Clear the flag */ + pUsb->DEVICE.INTFLAG.bit.EORST = true; + /* Set Device address as 0 */ + pUsb->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | 0; + /* Configure endpoint 0 */ + /* Configure Endpoint 0 for Control IN and Control OUT */ + pUsb->DEVICE.DeviceEndpoint[0].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(1) | USB_DEVICE_EPCFG_EPTYPE1(1); + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; + /* Configure control OUT Packet size to 64 bytes */ + usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.SIZE = 3; + /* Configure control IN Packet size to 64 bytes */ + usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.SIZE = 3; + /* Configure the data buffer address for control OUT */ + usb_endpoint_table[0].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[0]; + /* Configure the data buffer address for control IN */ + usb_endpoint_table[0].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[0]; + /* Set Multipacket size to 8 for control OUT and byte count to 0*/ + usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 8; + usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY; + + // Reset current configuration value to 0 + pCdc->currentConfiguration = 0; + } + else + { + if (pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_RXSTP) + { + sam_ba_usb_CDC_Enumerate(pCdc); + } + } + + return pCdc->currentConfiguration; +} + +/*---------------------------------------------------------------------------- + * \brief Stall the control endpoint + */ +void USB_SendStall(Usb *pUsb, bool direction_in) +{ + /* Check the direction */ + if (direction_in) + { + /* Set STALL request on IN direction */ + //pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.STALLRQ = (1<<1); + } + else + { + /* Set STALL request on OUT direction */ + //pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.STALLRQ = (1<<0); + } +} + +/*---------------------------------------------------------------------------- + * \brief Send zero length packet through the control endpoint + */ +void USB_SendZlp(Usb *pUsb) +{ + /* Set the byte count as zero */ + usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = 0; + /* Clear the transfer complete flag */ + //pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT1 = true; + pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT |= (1 << 1); + /* Set the bank as ready */ + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.BK1RDY = true; + /* Wait for transfer to complete */ + while (!( pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT & (1<<1) )); +} + +/*---------------------------------------------------------------------------- + * \brief Set USB device address obtained from host + */ +void USB_SetAddress(Usb *pUsb, uint16_t wValue) +{ + pUsb->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | wValue; +} + +/*---------------------------------------------------------------------------- + * \brief Configure USB device + */ +void USB_Configure(Usb *pUsb) +{ + /* Configure BULK OUT endpoint for CDC Data interface*/ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(3); + /* Set maximum packet size as 64 bytes */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.SIZE = 3; + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; + /* Configure the data buffer */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[1]; + + /* Configure BULK IN endpoint for CDC Data interface */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_IN].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(3); + /* Set maximum packet size as 64 bytes */ + usb_endpoint_table[USB_EP_IN].DeviceDescBank[1].PCKSIZE.bit.SIZE = 3; + pUsb->DEVICE.DeviceEndpoint[USB_EP_IN].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; + /* Configure the data buffer */ + usb_endpoint_table[USB_EP_IN].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[1]; + + /* Configure INTERRUPT IN endpoint for CDC COMM interface*/ + pUsb->DEVICE.DeviceEndpoint[USB_EP_COMM].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(4); + /* Set maximum packet size as 64 bytes */ + usb_endpoint_table[USB_EP_COMM].DeviceDescBank[1].PCKSIZE.bit.SIZE = 0; + pUsb->DEVICE.DeviceEndpoint[USB_EP_COMM].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; +} diff --git a/bootloaders/zero/board_driver_usb.h b/bootloaders/zero/board_driver_usb.h new file mode 100644 index 000000000..4e71b8c1a --- /dev/null +++ b/bootloaders/zero/board_driver_usb.h @@ -0,0 +1,45 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _BOARD_DRIVER_USB_H_ +#define _BOARD_DRIVER_USB_H_ + +#include "sam_ba_cdc.h" + +extern UsbDeviceDescriptor usb_endpoint_table[MAX_EP]; +extern uint8_t udd_ep_out_cache_buffer[2][64]; //1 for CTRL, 1 for BULK +extern uint8_t udd_ep_in_cache_buffer[2][64]; //1 for CTRL, 1 for BULK + +P_USB_CDC USB_Open(P_USB_CDC pCdc, Usb *pUsb); + +void USB_Init(void); + +uint32_t USB_Write(Usb *pUsb, const char *pData, uint32_t length, uint8_t ep_num); +uint32_t USB_Read(Usb *pUsb, char *pData, uint32_t length); +uint32_t USB_Read_blocking(Usb *pUsb, char *pData, uint32_t length); + +uint8_t USB_IsConfigured(P_USB_CDC pCdc); + +void USB_SendStall(Usb *pUsb, bool direction_in); +void USB_SendZlp(Usb *pUsb); + +void USB_SetAddress(Usb *pUsb, uint16_t wValue); +void USB_Configure(Usb *pUsb); + +#endif // _BOARD_DRIVER_USB_H_ diff --git a/bootloaders/zero/board_init.c b/bootloaders/zero/board_init.c new file mode 100644 index 000000000..c08aedaae --- /dev/null +++ b/bootloaders/zero/board_init.c @@ -0,0 +1,210 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "board_definitions.h" + +/** + * \brief system_init() configures the needed clocks and according Flash Read Wait States. + * At reset: + * - OSC8M clock source is enabled with a divider by 8 (1MHz). + * - Generic Clock Generator 0 (GCLKMAIN) is using OSC8M as source. + * We need to: + * 1) Enable XOSC32K clock (External on-board 32.768Hz oscillator), will be used as DFLL48M reference. + * 2) Put XOSC32K as source of Generic Clock Generator 1 + * 3) Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference) + * 4) Enable DFLL48M clock + * 5) Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz. + * 6) Modify PRESCaler value of OSCM to have 8MHz + * 7) Put OSC8M as source for Generic Clock Generator 3 + */ +// Constants for Clock generators +#define GENERIC_CLOCK_GENERATOR_MAIN (0u) +#define GENERIC_CLOCK_GENERATOR_XOSC32K (1u) +#define GENERIC_CLOCK_GENERATOR_OSCULP32K (2u) /* Initialized at reset for WDT */ +#define GENERIC_CLOCK_GENERATOR_OSC8M (3u) +// Constants for Clock multiplexers +#define GENERIC_CLOCK_MULTIPLEXER_DFLL48M (0u) + +void board_init(void) +{ + /* Set 1 Flash Wait State for 48MHz, cf tables 20.9 and 35.27 in SAMD21 Datasheet */ + NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val; + + /* Turn on the digital interface clock */ + PM->APBAMASK.reg |= PM_APBAMASK_GCLK; + + /* ---------------------------------------------------------------------------------------------- + * 1) Enable XOSC32K clock (External on-board 32.768Hz oscillator) + */ + SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP( 0x6u ) | /* cf table 15.10 of product datasheet in chapter 15.8.6 */ + SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K; + SYSCTRL->XOSC32K.bit.ENABLE = 1; /* separate call, as described in chapter 15.6.3 */ + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY) == 0 ) + { + /* Wait for oscillator stabilization */ + } + + /* Software reset the module to ensure it is re-initialized correctly */ + /* Note: Due to synchronization, there is a delay from writing CTRL.SWRST until the reset is complete. + * CTRL.SWRST and STATUS.SYNCBUSY will both be cleared when the reset is complete, as described in chapter 13.8.1 + */ + GCLK->CTRL.reg = GCLK_CTRL_SWRST; + + while ( (GCLK->CTRL.reg & GCLK_CTRL_SWRST) && (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) ) + { + /* Wait for reset to complete */ + } + + /* ---------------------------------------------------------------------------------------------- + * 2) Put XOSC32K as source of Generic Clock Generator 1 + */ + GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_XOSC32K ); // Generic Clock Generator 1 + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* Write Generic Clock Generator 1 configuration */ + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_XOSC32K ) | // Generic Clock Generator 1 + GCLK_GENCTRL_SRC_XOSC32K | // Selected source is External 32KHz Oscillator +// GCLK_GENCTRL_OE | // Output clock to a pin for tests + GCLK_GENCTRL_GENEN; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* ---------------------------------------------------------------------------------------------- + * 3) Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference) + */ + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GENERIC_CLOCK_MULTIPLEXER_DFLL48M ) | // Generic Clock Multiplexer 0 + GCLK_CLKCTRL_GEN_GCLK1 | // Generic Clock Generator 1 is source + GCLK_CLKCTRL_CLKEN; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* ---------------------------------------------------------------------------------------------- + * 4) Enable DFLL48M clock + */ + + /* DFLL Configuration in Closed Loop mode, cf product datasheet chapter 15.6.7.1 - Closed-Loop Operation */ + + /* Remove the OnDemand mode, Bug http://avr32.icgroup.norway.atmel.com/bugzilla/show_bug.cgi?id=9905 */ + SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0; + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) + { + /* Wait for synchronization */ + } + + SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP( 31 ) | // Coarse step is 31, half of the max value + SYSCTRL_DFLLMUL_FSTEP( 511 ) | // Fine step is 511, half of the max value + SYSCTRL_DFLLMUL_MUL( (VARIANT_MCK/VARIANT_MAINOSC) ); // External 32KHz is the reference + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) + { + /* Wait for synchronization */ + } + + /* Write full configuration to DFLL control register */ + SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE | /* Enable the closed loop mode */ + SYSCTRL_DFLLCTRL_WAITLOCK | + SYSCTRL_DFLLCTRL_QLDIS; /* Disable Quick lock */ + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) + { + /* Wait for synchronization */ + } + + /* Enable the DFLL */ + SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE; + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKC) == 0 || + (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKF) == 0 ) + { + /* Wait for locks flags */ + } + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) + { + /* Wait for synchronization */ + } + + /* ---------------------------------------------------------------------------------------------- + * 5) Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz. + */ + GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_MAIN ); // Generic Clock Generator 0 + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* Write Generic Clock Generator 0 configuration */ + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_MAIN ) | // Generic Clock Generator 0 + GCLK_GENCTRL_SRC_DFLL48M | // Selected source is DFLL 48MHz +// GCLK_GENCTRL_OE | // Output clock to a pin for tests + GCLK_GENCTRL_IDC | // Set 50/50 duty cycle + GCLK_GENCTRL_GENEN; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + +#if 0 + /* ---------------------------------------------------------------------------------------------- + * 6) Modify PRESCaler value of OSC8M to have 8MHz + */ + SYSCTRL->OSC8M.bit.PRESC = SYSCTRL_OSC8M_PRESC_1_Val; + SYSCTRL->OSC8M.bit.ONDEMAND = 0; + + /* ---------------------------------------------------------------------------------------------- + * 7) Put OSC8M as source for Generic Clock Generator 3 + */ + GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_OSC8M ); // Generic Clock Generator 3 + + /* Write Generic Clock Generator 3 configuration */ + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_OSC8M ) | // Generic Clock Generator 3 + GCLK_GENCTRL_SRC_OSC8M | // Selected source is RC OSC 8MHz (already enabled at reset) +// GCLK_GENCTRL_OE | // Output clock to a pin for tests + GCLK_GENCTRL_GENEN; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } +#endif //0 + + /* + * Now that all system clocks are configured, we can set CPU and APBx BUS clocks. + * These values are normally the ones present after Reset. + */ + PM->CPUSEL.reg = PM_CPUSEL_CPUDIV_DIV1; + PM->APBASEL.reg = PM_APBASEL_APBADIV_DIV1_Val; + PM->APBBSEL.reg = PM_APBBSEL_APBBDIV_DIV1_Val; + PM->APBCSEL.reg = PM_APBCSEL_APBCDIV_DIV1_Val; +} diff --git a/bootloaders/zero/board_startup.c b/bootloaders/zero/board_startup.c new file mode 100644 index 000000000..aaa5a019f --- /dev/null +++ b/bootloaders/zero/board_startup.c @@ -0,0 +1,147 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +struct ConstVectors +{ + /* Stack pointer */ + void* pvStack; + + /* Cortex-M handlers */ + void* pfnReset_Handler; + void* pfnNMI_Handler; + void* pfnHardFault_Handler; + void* pfnReservedM12; + void* pfnReservedM11; + void* pfnReservedM10; + void* pfnReservedM9; + void* pfnReservedM8; + void* pfnReservedM7; + void* pfnReservedM6; + void* pfnSVC_Handler; + void* pfnReservedM4; + void* pfnReservedM3; + void* pfnPendSV_Handler; + void* pfnSysTick_Handler; +}; + +/* Symbols exported from linker script */ +extern uint32_t __etext ; +extern uint32_t __data_start__ ; +extern uint32_t __data_end__ ; +extern uint32_t __bss_start__ ; +extern uint32_t __bss_end__ ; +extern uint32_t __StackTop; + +extern int main(void); +extern void __libc_init_array(void); + +/* Exception Table */ +__attribute__ ((section(".isr_vector"))) +const struct ConstVectors exception_table = +{ + /* Configure Initial Stack Pointer, using linker-generated symbols */ + .pvStack = (void*) (&__StackTop), + + .pfnReset_Handler = (void*) Reset_Handler, + .pfnNMI_Handler = (void*) NMI_Handler, + .pfnHardFault_Handler = (void*) HardFault_Handler, + .pfnReservedM12 = (void*) (0UL), /* Reserved */ + .pfnReservedM11 = (void*) (0UL), /* Reserved */ + .pfnReservedM10 = (void*) (0UL), /* Reserved */ + .pfnReservedM9 = (void*) (0UL), /* Reserved */ + .pfnReservedM8 = (void*) (0UL), /* Reserved */ + .pfnReservedM7 = (void*) (0UL), /* Reserved */ + .pfnReservedM6 = (void*) (0UL), /* Reserved */ + .pfnSVC_Handler = (void*) SVC_Handler, + .pfnReservedM4 = (void*) (0UL), /* Reserved */ + .pfnReservedM3 = (void*) (0UL), /* Reserved */ + .pfnPendSV_Handler = (void*) PendSV_Handler, + .pfnSysTick_Handler = (void*) SysTick_Handler, +}; + +/** + * \brief This is the code that gets called on processor reset. + * Initializes the device and call the main() routine. + */ +void Reset_Handler( void ) +{ + uint32_t *pSrc, *pDest; + + /* Initialize the initialized data section */ + pSrc = &__etext; + pDest = &__data_start__; + + if ( (&__data_start__ != &__data_end__) && (pSrc != pDest) ) + { + for (; pDest < &__data_end__ ; pDest++, pSrc++ ) + { + *pDest = *pSrc ; + } + } + + /* Clear the zero section */ + if ( &__bss_start__ != &__bss_end__ ) + { + for ( pDest = &__bss_start__ ; pDest < &__bss_end__ ; pDest++ ) + { + *pDest = 0ul ; + } + } + +// board_init(); // will be done in main() after app check + + /* Initialize the C library */ +// __libc_init_array(); + + main(); + + while (1); +} + +void NMI_Handler(void) +{ + __BKPT(14); + while (1); +} + +void HardFault_Handler(void) +{ + __BKPT(13); + while (1); +} + +void SVC_Handler(void) +{ + __BKPT(5); + while (1); +} + +void PendSV_Handler(void) +{ + __BKPT(2); + while (1); +} + +void SysTick_Handler(void) +{ + __BKPT(1); + while (1); +} diff --git a/bootloaders/zero/bootloader_samd21x18.ld b/bootloaders/zero/bootloader_samd21x18.ld new file mode 100644 index 000000000..2a8b056d3 --- /dev/null +++ b/bootloaders/zero/bootloader_samd21x18.ld @@ -0,0 +1,221 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Linker script to configure memory regions. + * Need modifying for a specific board. + * FLASH.ORIGIN: starting address of flash + * FLASH.LENGTH: length of flash + * RAM.ORIGIN: starting address of RAM bank 0 + * RAM.LENGTH: length of RAM bank 0 + */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x2000 /* First 8KB used by bootloader */ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000-0x0004 /* 4 bytes used by bootloader to keep data between resets */ +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + * __sketch_vectors_ptr + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + . = ORIGIN(FLASH); + + .vectors : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* To copy multiple ROM to RAM sections, + * uncomment .copy.table section and, + * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ + /* + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (__etext2) + LONG (__data2_start__) + LONG (__data2_end__ - __data2_start__) + __copy_table_end__ = .; + } > FLASH + */ + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ + /* + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (__bss2_start__) + LONG (__bss2_end__ - __bss2_start__) + __zero_table_end__ = .; + } > FLASH + */ + + __etext = .; + PROVIDE(__sketch_vectors_ptr = ORIGIN(FLASH) + LENGTH(FLASH)); + + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __end__ = .; + PROVIDE(end = .); + *(.heap*) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + __ram_end__ = ORIGIN(RAM) + LENGTH(RAM) -1 ; + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") +} diff --git a/bootloaders/zero/main.c b/bootloaders/zero/main.c index 82d8b8377..3b18872a8 100644 --- a/bootloaders/zero/main.c +++ b/bootloaders/zero/main.c @@ -1,89 +1,37 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -/** - * -------------------- - * SAM-BA Implementation on SAMD21 - * -------------------- - * Requirements to use SAM-BA : - * - * Supported communication interfaces : - * -------------------- - * - * SERCOM5 : RX:PB23 TX:PB22 - * Baudrate : 115200 8N1 - * - * USB : D-:PA24 D+:PA25 - * - * Pins Usage - * -------------------- - * The following pins are used by the program : - * PA25 : input/output - * PA24 : input/output - * PB23 : input - * PB22 : output - * PA15 : input - * - * The application board shall avoid driving the PA25,PA24,PB23,PB22 and PA15 signals - * while the boot program is running (after a POR for example) - * - * Clock system - * -------------------- - * CPU clock source (GCLK_GEN_0) - 8MHz internal oscillator (OSC8M) - * SERCOM5 core GCLK source (GCLK_ID_SERCOM5_CORE) - GCLK_GEN_0 (i.e., OSC8M) - * GCLK Generator 1 source (GCLK_GEN_1) - 48MHz DFLL in Clock Recovery mode (DFLL48M) - * USB GCLK source (GCLK_ID_USB) - GCLK_GEN_1 (i.e., DFLL in CRM mode) - * - * Memory Mapping - * -------------------- - * SAM-BA code will be located at 0x0 and executed before any applicative code. - * - * Applications compiled to be executed along with the bootloader will start at - * 0x2000 - * Before jumping to the application, the bootloader changes the VTOR register - * to use the interrupt vectors of the application @0x2000.<- not required as - * application code is taking care of this - * +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include -#include "compiler.h" #include "sam_ba_monitor.h" -#include "usart_sam_ba.h" -#include "main.h" -#include "cdc_enumerate.h" +#include "sam_ba_serial.h" +#include "board_definitions.h" +#include "board_driver_led.h" +#include "sam_ba_usb.h" +#include "sam_ba_cdc.h" -#define NVM_SW_CALIB_DFLL48M_COARSE_VAL 58 -#define NVM_SW_CALIB_DFLL48M_FINE_VAL 64 +extern uint32_t __sketch_vectors_ptr; // Exported value from linker script +extern void board_init(void); -static void check_start_application(void); +#if (defined DEBUG) && (DEBUG == 1) +volatile uint32_t* pulSketch_Start_Address; +#endif static volatile bool main_b_cdc_enable = false; @@ -93,156 +41,106 @@ static volatile bool main_b_cdc_enable = false; */ static void check_start_application(void) { - volatile PortGroup *led_port = (volatile PortGroup *)&PORT->Group[1]; - led_port->DIRSET.reg = (1<<30); - led_port->OUTCLR.reg = (1<<30); +// LED_init(); +// LED_off(); #if defined(BOOT_DOUBLE_TAP_ADDRESS) - #define DOUBLE_TAP_MAGIC 0x07738135 - if (PM->RCAUSE.bit.POR) - { - /* On power-on initialize double-tap */ - BOOT_DOUBLE_TAP_DATA = 0; - } - else - { - if (BOOT_DOUBLE_TAP_DATA == DOUBLE_TAP_MAGIC) { - /* Second tap, stay in bootloader */ - BOOT_DOUBLE_TAP_DATA = 0; - return; - } - - /* First tap */ - BOOT_DOUBLE_TAP_DATA = DOUBLE_TAP_MAGIC; - - /* Wait 0.5sec to see if the user tap reset again */ - for (uint32_t i=0; i<125000; i++) /* 500ms */ - /* force compiler to not optimize this... */ - __asm__ __volatile__(""); - - /* Timeout happened, continue boot... */ - BOOT_DOUBLE_TAP_DATA = 0; - } -#endif + #define DOUBLE_TAP_MAGIC 0x07738135 + if (PM->RCAUSE.bit.POR) + { + /* On power-on initialize double-tap */ + BOOT_DOUBLE_TAP_DATA = 0; + } + else + { + if (BOOT_DOUBLE_TAP_DATA == DOUBLE_TAP_MAGIC) + { + /* Second tap, stay in bootloader */ + BOOT_DOUBLE_TAP_DATA = 0; + return; + } - uint32_t app_start_address; + /* First tap */ + BOOT_DOUBLE_TAP_DATA = DOUBLE_TAP_MAGIC; - /* Load the Reset Handler address of the application */ - app_start_address = *(uint32_t *)(APP_START_ADDRESS + 4); + /* Wait 0.5sec to see if the user tap reset again. + * The loop value is based on SAMD21 default 1MHz clock @ reset. + */ + for (uint32_t i=0; i<125000; i++) /* 500ms */ + /* force compiler to not optimize this... */ + __asm__ __volatile__(""); - /** - * Test reset vector of application @APP_START_ADDRESS+4 - * Stay in SAM-BA if *(APP_START+0x4) == 0xFFFFFFFF - * Application erased condition - */ - if (app_start_address == 0xFFFFFFFF) { - /* Stay in bootloader */ - return; - } + /* Timeout happened, continue boot... */ + BOOT_DOUBLE_TAP_DATA = 0; + } +#endif -#if defined(BOOT_LOAD_PIN) - volatile PortGroup *boot_port = (volatile PortGroup *)(&(PORT->Group[BOOT_LOAD_PIN / 32])); - volatile bool boot_en; - - /* Enable the input mode in Boot GPIO Pin */ - boot_port->DIRCLR.reg = BOOT_PIN_MASK; - boot_port->PINCFG[BOOT_LOAD_PIN & 0x1F].reg = PORT_PINCFG_INEN | PORT_PINCFG_PULLEN; - boot_port->OUTSET.reg = BOOT_PIN_MASK; - /* Read the BOOT_LOAD_PIN status */ - boot_en = (boot_port->IN.reg) & BOOT_PIN_MASK; - - /* Check the bootloader enable condition */ - if (!boot_en) { - /* Stay in bootloader */ - return; - } +#if (!defined DEBUG) || ((defined DEBUG) && (DEBUG == 0)) +uint32_t* pulSketch_Start_Address; #endif - led_port->OUTSET.reg = (1<<30); + /* + * Test sketch stack pointer @ &__sketch_vectors_ptr + * Stay in SAM-BA if value @ (&__sketch_vectors_ptr) == 0xFFFFFFFF (Erased flash cell value) + */ + if (__sketch_vectors_ptr == 0xFFFFFFFF) + { + /* Stay in bootloader */ + return; + } + + /* + * Load the sketch Reset Handler address + * __sketch_vectors_ptr is exported from linker script and point on first 32b word of sketch vector table + * First 32b word is sketch stack + * Second 32b word is sketch entry point: Reset_Handler() + */ + pulSketch_Start_Address = &__sketch_vectors_ptr ; + pulSketch_Start_Address++ ; + + /* + * Test vector table address of sketch @ &__sketch_vectors_ptr + * Stay in SAM-BA if this function is not aligned enough, ie not valid + */ + if ( ((uint32_t)(&__sketch_vectors_ptr) & ~SCB_VTOR_TBLOFF_Msk) != 0x00) + { + /* Stay in bootloader */ + return; + } - /* Rebase the Stack Pointer */ - __set_MSP(*(uint32_t *) APP_START_ADDRESS); +/* +#if defined(BOOT_LOAD_PIN) + volatile PortGroup *boot_port = (volatile PortGroup *)(&(PORT->Group[BOOT_LOAD_PIN / 32])); + volatile bool boot_en; + + // Enable the input mode in Boot GPIO Pin + boot_port->DIRCLR.reg = BOOT_PIN_MASK; + boot_port->PINCFG[BOOT_LOAD_PIN & 0x1F].reg = PORT_PINCFG_INEN | PORT_PINCFG_PULLEN; + boot_port->OUTSET.reg = BOOT_PIN_MASK; + // Read the BOOT_LOAD_PIN status + boot_en = (boot_port->IN.reg) & BOOT_PIN_MASK; + + // Check the bootloader enable condition + if (!boot_en) + { + // Stay in bootloader + return; + } +#endif +*/ - /* Rebase the vector table base address */ - SCB->VTOR = ((uint32_t) APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk); +// LED_on(); - /* Jump to application Reset Handler in the application */ - asm("bx %0"::"r"(app_start_address)); -} + /* Rebase the Stack Pointer */ + __set_MSP( (uint32_t)(__sketch_vectors_ptr) ); -void system_init() -{ - /* Configure flash wait states */ - NVMCTRL->CTRLB.bit.RWS = FLASH_WAIT_STATES; - - /* Set OSC8M prescalar to divide by 1 */ - SYSCTRL->OSC8M.bit.PRESC = 0; - - /* Configure OSC8M as source for GCLK_GEN0 */ - GCLK_GENCTRL_Type genctrl={0}; - uint32_t temp_genctrl; - GCLK->GENCTRL.bit.ID = 0; /* GENERATOR_ID - GCLK_GEN_0 */ - while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); - temp_genctrl = GCLK->GENCTRL.reg; - genctrl.bit.SRC = GCLK_GENCTRL_SRC_OSC8M_Val; - genctrl.bit.GENEN = true; - genctrl.bit.RUNSTDBY = false; - GCLK->GENCTRL.reg = (genctrl.reg | temp_genctrl); - while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); + /* Rebase the vector table base address */ + SCB->VTOR = ((uint32_t)(&__sketch_vectors_ptr) & SCB_VTOR_TBLOFF_Msk); -#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - SYSCTRL_DFLLCTRL_Type dfllctrl_conf = {0}; - SYSCTRL_DFLLVAL_Type dfllval_conf = {0}; - uint32_t coarse =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_SW_CALIB_DFLL48M_COARSE_VAL / 32)) - >> (NVM_SW_CALIB_DFLL48M_COARSE_VAL % 32)) - & ((1 << 6) - 1); - if (coarse == 0x3f) { - coarse = 0x1f; - } - uint32_t fine =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_SW_CALIB_DFLL48M_FINE_VAL / 32)) - >> (NVM_SW_CALIB_DFLL48M_FINE_VAL % 32)) - & ((1 << 10) - 1); - if (fine == 0x3ff) { - fine = 0x1ff; - } - dfllval_conf.bit.COARSE = coarse; - dfllval_conf.bit.FINE = fine; - dfllctrl_conf.bit.USBCRM = true; - dfllctrl_conf.bit.BPLCKC = false; - dfllctrl_conf.bit.QLDIS = false; - dfllctrl_conf.bit.CCDIS = true; - dfllctrl_conf.bit.ENABLE = true; - - SYSCTRL->DFLLCTRL.bit.ONDEMAND = false; - while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY)); - SYSCTRL->DFLLMUL.reg = 48000; - SYSCTRL->DFLLVAL.reg = dfllval_conf.reg; - SYSCTRL->DFLLCTRL.reg = dfllctrl_conf.reg; - - GCLK_CLKCTRL_Type clkctrl={0}; - uint16_t temp; - GCLK->CLKCTRL.bit.ID = 0; /* GCLK_ID - DFLL48M Reference */ - temp = GCLK->CLKCTRL.reg; - clkctrl.bit.CLKEN = true; - clkctrl.bit.WRTLOCK = false; - clkctrl.bit.GEN = GCLK_CLKCTRL_GEN_GCLK0_Val; - GCLK->CLKCTRL.reg = (clkctrl.reg | temp); - - /* Configure DFLL48M as source for GCLK_GEN1 */ - GCLK->GENCTRL.bit.ID = 1; /* GENERATOR_ID - GCLK_GEN_1 */ - while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); - temp_genctrl = GCLK->GENCTRL.reg; - genctrl.bit.SRC = GCLK_GENCTRL_SRC_DFLL48M_Val; - genctrl.bit.GENEN = true; - genctrl.bit.RUNSTDBY = false; - GCLK->GENCTRL.reg = (genctrl.reg | temp_genctrl); - while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); -#endif + /* Jump to application Reset Handler in the application */ + asm("bx %0"::"r"(*pulSketch_Start_Address)); } - #if DEBUG_ENABLE # define DEBUG_PIN_HIGH port_pin_set_output_level(BOOT_LED, 1) # define DEBUG_PIN_LOW port_pin_set_output_level(BOOT_LED, 0) @@ -251,93 +149,68 @@ void system_init() # define DEBUG_PIN_LOW do{}while(0) #endif - /** * \brief SAMD21 SAM-BA Main loop. * \return Unused (ANSI-C compatibility). */ int main(void) { -#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - P_USB_CDC pCdc; +#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + P_USB_CDC pCdc; #endif - DEBUG_PIN_HIGH; + DEBUG_PIN_HIGH; - /* Jump in application if condition is satisfied */ - check_start_application(); + /* Jump in application if condition is satisfied */ + check_start_application(); - /* We have determined we should stay in the monitor. */ - /* System initialization */ - system_init(); - cpu_irq_enable(); + /* We have determined we should stay in the monitor. */ + /* System initialization */ + board_init(); + __enable_irq(); - #if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - /* UART is enabled in all cases */ - usart_open(); +#if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + /* UART is enabled in all cases */ + serial_open(); #endif #if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - pCdc = (P_USB_CDC)usb_init(); + pCdc = usb_init(); #endif - DEBUG_PIN_LOW; - - // output on D13 (PA.17) - LED_PORT.PINCFG[LED_PIN].reg &= ~ (uint8_t)(PORT_PINCFG_INEN); - LED_PORT.DIRSET.reg = (uint32_t)(1 << LED_PIN); - /* Wait for a complete enum on usb or a '#' char on serial line */ - while (1) { - pulse_led(1); // while we're waiting, blink the D13 + DEBUG_PIN_LOW; + /* Wait for a complete enum on usb or a '#' char on serial line */ + while (1) + { #if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - if (pCdc->IsConfigured(pCdc) != 0) { - main_b_cdc_enable = true; - } - - //Check if a USB enumeration has succeeded - //And com port was opened - if (main_b_cdc_enable) { - sam_ba_monitor_init(SAM_BA_INTERFACE_USBCDC); - //SAM-BA on USB loop - while(1) { - sam_ba_monitor_run(); - } - } -#endif -#if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - /* Check if a '#' has been received */ - if (!main_b_cdc_enable && usart_sharp_received()) { - sam_ba_monitor_init(SAM_BA_INTERFACE_USART); - /* SAM-BA on UART loop */ - while(1) { - sam_ba_monitor_run(); - } - } -#endif - } -} - + if (pCdc->IsConfigured(pCdc) != 0) + { + main_b_cdc_enable = true; + } -// We'll have the D13 LED slowly pulse on and off with bitbang PWM -// for a nice 'hey we're in bootload mode' indication! -ada -static uint8_t pulse_tick=0; -static int8_t pulse_dir=1; -static int16_t pulse_pwm; -void pulse_led(int8_t speed) { - // blink D13 - pulse_tick++; - if (pulse_tick==0) { - pulse_pwm += pulse_dir * speed; - if (pulse_pwm > 255) { - pulse_pwm = 255; - pulse_dir = -1; + /* Check if a USB enumeration has succeeded and if comm port has been opened */ + if (main_b_cdc_enable) + { + sam_ba_monitor_init(SAM_BA_INTERFACE_USBCDC); + /* SAM-BA on USB loop */ + while( 1 ) + { + sam_ba_monitor_run(); + } } - if (pulse_pwm < 0) { - pulse_pwm = 0; - pulse_dir = +1; +#endif + +#if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + /* Check if a '#' has been received */ + if (!main_b_cdc_enable && serial_sharp_received()) + { + sam_ba_monitor_init(SAM_BA_INTERFACE_USART); + /* SAM-BA on Serial loop */ + while(1) + { + sam_ba_monitor_run(); + } } - LED_ON; +#endif } - if (pulse_tick==pulse_pwm) - LED_OFF; } diff --git a/bootloaders/zero/sam_ba_cdc.c b/bootloaders/zero/sam_ba_cdc.c new file mode 100644 index 000000000..fc5efe348 --- /dev/null +++ b/bootloaders/zero/sam_ba_cdc.c @@ -0,0 +1,98 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "sam_ba_cdc.h" +#include "board_driver_usb.h" + +usb_cdc_line_coding_t line_coding= +{ + 115200, // baudrate + 0, // 1 Stop Bit + 0, // None Parity + 8 // 8 Data bits +}; + +#define pCdc (&sam_ba_cdc) + +int cdc_putc(/*P_USB_CDC pCdc,*/ int value) +{ + /* Send single byte on USB CDC */ + USB_Write(pCdc->pUsb, (const char *)&value, 1, USB_EP_IN); + + return 1; +} + +int cdc_getc(/*P_USB_CDC pCdc*/void) +{ + uint8_t rx_char; + + /* Read singly byte on USB CDC */ + USB_Read(pCdc->pUsb, (char *)&rx_char, 1); + + return (int)rx_char; +} + +bool cdc_is_rx_ready(/*P_USB_CDC pCdc*/void) +{ + /* Check whether the device is configured */ + if ( !USB_IsConfigured(pCdc) ) + return 0; + + /* Return transfer complete 0 flag status */ + return (pCdc->pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0)); +} + +uint32_t cdc_write_buf(/*P_USB_CDC pCdc,*/ void const* data, uint32_t length) +{ + /* Send the specified number of bytes on USB CDC */ + USB_Write(pCdc->pUsb, (const char *)data, length, USB_EP_IN); + return length; +} + +uint32_t cdc_read_buf(/*P_USB_CDC pCdc,*/ void* data, uint32_t length) +{ + /* Check whether the device is configured */ + if ( !USB_IsConfigured(pCdc) ) + return 0; + + /* Read from USB CDC */ + return USB_Read(pCdc->pUsb, (char *)data, length); +} + +uint32_t cdc_read_buf_xmd(/*P_USB_CDC pCdc,*/ void* data, uint32_t length) +{ + /* Check whether the device is configured */ + if ( !USB_IsConfigured(pCdc) ) + return 0; + + /* Blocking read till specified number of bytes is received */ + // XXX: USB_Read_blocking is not reliable + // return USB_Read_blocking(pCdc, (char *)data, length); + + char *dst = (char *)data; + uint32_t remaining = length; + while (remaining) + { + uint32_t readed = USB_Read(pCdc->pUsb, (char *)dst, remaining); + remaining -= readed; + dst += readed; + } + + return length; +} diff --git a/bootloaders/zero/sam_ba_cdc.h b/bootloaders/zero/sam_ba_cdc.h new file mode 100644 index 000000000..49b7643cf --- /dev/null +++ b/bootloaders/zero/sam_ba_cdc.h @@ -0,0 +1,91 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SAM_BA_USB_CDC_H_ +#define _SAM_BA_USB_CDC_H_ + +#include +#include "sam_ba_usb.h" + +typedef struct +{ + uint32_t dwDTERate; + uint8_t bCharFormat; + uint8_t bParityType; + uint8_t bDataBits; +} usb_cdc_line_coding_t; + +/* CDC Class Specific Request Code */ +#define GET_LINE_CODING 0x21A1 +#define SET_LINE_CODING 0x2021 +#define SET_CONTROL_LINE_STATE 0x2221 + +extern usb_cdc_line_coding_t line_coding; + + +/** + * \brief Sends a single byte through USB CDC + * + * \param Data to send + * \return number of data sent + */ +int cdc_putc(/*P_USB_CDC pCdc,*/ int value); + +/** + * \brief Reads a single byte through USB CDC + * + * \return Data read through USB + */ +int cdc_getc(/*P_USB_CDC pCdc*/); + +/** + * \brief Checks if a character has been received on USB CDC + * + * \return \c 1 if a byte is ready to be read. + */ +bool cdc_is_rx_ready(/*P_USB_CDC pCdc*/); + +/** + * \brief Sends buffer on USB CDC + * + * \param data pointer + * \param number of data to send + * \return number of data sent + */ +uint32_t cdc_write_buf(/*P_USB_CDC pCdc,*/ void const* data, uint32_t length); + +/** + * \brief Gets data on USB CDC + * + * \param data pointer + * \param number of data to read + * \return number of data read + */ +uint32_t cdc_read_buf(/*P_USB_CDC pCdc,*/ void* data, uint32_t length); + +/** + * \brief Gets specified number of bytes on USB CDC + * + * \param data pointer + * \param number of data to read + * \return number of data read + */ +uint32_t cdc_read_buf_xmd(/*P_USB_CDC pCdc,*/ void* data, uint32_t length); + +#endif // _SAM_BA_USB_CDC_H_ diff --git a/bootloaders/zero/sam_ba_monitor.c b/bootloaders/zero/sam_ba_monitor.c index 8a81d6dac..7daeb3067 100644 --- a/bootloaders/zero/sam_ba_monitor.c +++ b/bootloaders/zero/sam_ba_monitor.c @@ -1,39 +1,30 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ #include "sam.h" #include #include "sam_ba_monitor.h" -#include "usart_sam_ba.h" -#include "uart_driver.h" -#include "compiler.h" -#include "cdc_enumerate.h" +#include "sam_ba_serial.h" +#include "board_driver_serial.h" +#include "board_driver_usb.h" +#include "sam_ba_usb.h" +#include "sam_ba_cdc.h" const char RomBOOT_Version[] = SAM_BA_VERSION; const char RomBOOT_ExtendedCapabilities[] = "[Arduino:XYZ]"; @@ -41,35 +32,49 @@ const char RomBOOT_ExtendedCapabilities[] = "[Arduino:XYZ]"; /* Provides one common interface to handle both USART and USB-CDC */ typedef struct { - /* send one byte of data */ - int (*put_c)(int value); - /* Get one byte */ - int (*get_c)(void); - /* Receive buffer not empty */ - bool (*is_rx_ready)(void); - /* Send given data (polling) */ - uint32_t (*putdata)(void const* data, uint32_t length); - /* Get data from comm. device */ - uint32_t (*getdata)(void* data, uint32_t length); - /* Send given data (polling) using xmodem (if necessary) */ - uint32_t (*putdata_xmd)(void const* data, uint32_t length); - /* Get data from comm. device using xmodem (if necessary) */ - uint32_t (*getdata_xmd)(void* data, uint32_t length); + /* send one byte of data */ + int (*put_c)(int value); + /* Get one byte */ + int (*get_c)(void); + /* Receive buffer not empty */ + bool (*is_rx_ready)(void); + /* Send given data (polling) */ + uint32_t (*putdata)(void const* data, uint32_t length); + /* Get data from comm. device */ + uint32_t (*getdata)(void* data, uint32_t length); + /* Send given data (polling) using xmodem (if necessary) */ + uint32_t (*putdata_xmd)(void const* data, uint32_t length); + /* Get data from comm. device using xmodem (if necessary) */ + uint32_t (*getdata_xmd)(void* data, uint32_t length); } t_monitor_if; #if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES /* Initialize structures with function pointers from supported interfaces */ const t_monitor_if uart_if = -{ usart_putc, usart_getc, usart_is_rx_ready, usart_putdata, usart_getdata, - usart_putdata_xmd, usart_getdata_xmd }; +{ + .put_c = serial_putc, + .get_c = serial_getc, + .is_rx_ready = serial_is_rx_ready, + .putdata = serial_putdata, + .getdata = serial_getdata, + .putdata_xmd = serial_putdata_xmd, + .getdata_xmd = serial_getdata_xmd +}; #endif #if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES //Please note that USB doesn't use Xmodem protocol, since USB already includes flow control and data verification //Data are simply forwarded without further coding. const t_monitor_if usbcdc_if = -{ cdc_putc, cdc_getc, cdc_is_rx_ready, cdc_write_buf, - cdc_read_buf, cdc_write_buf, cdc_read_buf_xmd }; +{ + .put_c = cdc_putc, + .get_c = cdc_getc, + .is_rx_ready = cdc_is_rx_ready, + .putdata = cdc_write_buf, + .getdata = cdc_read_buf, + .putdata_xmd = cdc_write_buf, + .getdata_xmd = cdc_read_buf_xmd +}; #endif /* The pointer to the interface object use by the monitor */ @@ -81,17 +86,19 @@ volatile bool b_sam_ba_interface_usart = false; void sam_ba_monitor_init(uint8_t com_interface) { -#if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - //Selects the requested interface for future actions - if (com_interface == SAM_BA_INTERFACE_USART) { - ptr_monitor_if = (t_monitor_if*) &uart_if; - b_sam_ba_interface_usart = true; - } +#if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + //Selects the requested interface for future actions + if (com_interface == SAM_BA_INTERFACE_USART) + { + ptr_monitor_if = (t_monitor_if*) &uart_if; + b_sam_ba_interface_usart = true; + } #endif -#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - if (com_interface == SAM_BA_INTERFACE_USBCDC) { - ptr_monitor_if = (t_monitor_if*) &usbcdc_if; - } +#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + if (com_interface == SAM_BA_INTERFACE_USBCDC) + { + ptr_monitor_if = (t_monitor_if*) &usbcdc_if; + } #endif } @@ -103,64 +110,63 @@ void sam_ba_monitor_init(uint8_t com_interface) */ void sam_ba_putdata_term(uint8_t* data, uint32_t length) { - uint8_t temp, buf[12], *data_ascii; - uint32_t i, int_value; - - if (b_terminal_mode) - { - if (length == 4) - int_value = *(uint32_t *) data; - else if (length == 2) - int_value = *(uint16_t *) data; - else - int_value = *(uint8_t *) data; - - data_ascii = buf + 2; - data_ascii += length * 2 - 1; - - for (i = 0; i < length * 2; i++) - { - temp = (uint8_t) (int_value & 0xf); - - if (temp <= 0x9) - *data_ascii = temp | 0x30; - else - *data_ascii = temp + 0x37; - - int_value >>= 4; - data_ascii--; - } - buf[0] = '0'; - buf[1] = 'x'; - buf[length * 2 + 2] = '\n'; - buf[length * 2 + 3] = '\r'; - ptr_monitor_if->putdata(buf, length * 2 + 4); - } - else - ptr_monitor_if->putdata(data, length); - return; + uint8_t temp, buf[12], *data_ascii; + uint32_t i, int_value; + + if (b_terminal_mode) + { + if (length == 4) + int_value = *(uint32_t *) data; + else if (length == 2) + int_value = *(uint16_t *) data; + else + int_value = *(uint8_t *) data; + + data_ascii = buf + 2; + data_ascii += length * 2 - 1; + + for (i = 0; i < length * 2; i++) + { + temp = (uint8_t) (int_value & 0xf); + + if (temp <= 0x9) + *data_ascii = temp | 0x30; + else + *data_ascii = temp + 0x37; + + int_value >>= 4; + data_ascii--; + } + buf[0] = '0'; + buf[1] = 'x'; + buf[length * 2 + 2] = '\n'; + buf[length * 2 + 3] = '\r'; + ptr_monitor_if->putdata(buf, length * 2 + 4); + } + else + ptr_monitor_if->putdata(data, length); + return; } volatile uint32_t sp; void call_applet(uint32_t address) { - uint32_t app_start_address; + uint32_t app_start_address; - cpu_irq_disable(); + __disable_irq(); - sp = __get_MSP(); + sp = __get_MSP(); - /* Rebase the Stack Pointer */ - __set_MSP(*(uint32_t *) address); + /* Rebase the Stack Pointer */ + __set_MSP(*(uint32_t *) address); - /* Load the Reset Handler address of the application */ - app_start_address = *(uint32_t *)(address + 4); + /* Load the Reset Handler address of the application */ + app_start_address = *(uint32_t *)(address + 4); - /* Jump to application Reset Handler in the application */ - asm("bx %0"::"r"(app_start_address)); + /* Jump to application Reset Handler in the application */ + asm("bx %0"::"r"(app_start_address)); } - uint32_t current_number; uint32_t i, length; uint8_t command, *ptr_data, *ptr, data[SIZEBUFMAX]; @@ -169,287 +175,298 @@ uint32_t u32tmp; uint32_t PAGE_SIZE, PAGES, MAX_FLASH; -/** - * \brief This function starts the SAM-BA monitor. - */ -void sam_ba_monitor_run(void) +// Prints a 32-bit integer in hex. +static void put_uint32(uint32_t n) { - uint32_t pageSizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024 }; - PAGE_SIZE = pageSizes[NVMCTRL->PARAM.bit.PSZ]; - PAGES = NVMCTRL->PARAM.bit.NVMP; - MAX_FLASH = PAGE_SIZE * PAGES; - - ptr_data = NULL; - command = 'z'; - while (1) { - sam_ba_monitor_loop(); - } + char buff[8]; + int i; + for (i=0; i<8; i++) + { + int d = n & 0XF; + n = (n >> 4); + + buff[7-i] = d > 9 ? 'A' + d - 10 : '0' + d; + } + ptr_monitor_if->putdata(buff, 8); } -// Prints a 32-bit integer in hex. -void put_uint32(uint32_t n) { - char buff[8]; - int i; - for (i=0; i<8; i++) { - int d = n & 0XF; - n = (n >> 4); - - buff[7-i] = d > 9 ? 'A' + d - 10 : '0' + d; - } - ptr_monitor_if->putdata(buff, 8); +static void sam_ba_monitor_loop(void) +{ + length = ptr_monitor_if->getdata(data, SIZEBUFMAX); + ptr = data; + + for (i = 0; i < length; i++, ptr++) + { + if (*ptr == 0xff) continue; + + if (*ptr == '#') + { + if (b_terminal_mode) + { + ptr_monitor_if->putdata("\n\r", 2); + } + if (command == 'S') + { + //Check if some data are remaining in the "data" buffer + if(length>i) + { + //Move current indexes to next avail data (currently ptr points to "#") + ptr++; + i++; + + //We need to add first the remaining data of the current buffer already read from usb + //read a maximum of "current_number" bytes + if ((length-i) < current_number) + { + u32tmp=(length-i); + } + else + { + u32tmp=current_number; + } + + memcpy(ptr_data, ptr, u32tmp); + i += u32tmp; + ptr += u32tmp; + j = u32tmp; + } + //update i with the data read from the buffer + i--; + ptr--; + //Do we expect more data ? + if(jgetdata_xmd(ptr_data, current_number-j); + + __asm("nop"); + } + else if (command == 'R') + { + ptr_monitor_if->putdata_xmd(ptr_data, current_number); + } + else if (command == 'O') + { + *ptr_data = (char) current_number; + } + else if (command == 'H') + { + *((uint16_t *) ptr_data) = (uint16_t) current_number; + } + else if (command == 'W') + { + *((int *) ptr_data) = current_number; + } + else if (command == 'o') + { + sam_ba_putdata_term(ptr_data, 1); + } + else if (command == 'h') + { + current_number = *((uint16_t *) ptr_data); + sam_ba_putdata_term((uint8_t*) ¤t_number, 2); + } + else if (command == 'w') + { + current_number = *((uint32_t *) ptr_data); + sam_ba_putdata_term((uint8_t*) ¤t_number, 4); + } + else if (command == 'G') + { + call_applet(current_number); + /* Rebase the Stack Pointer */ + __set_MSP(sp); + __enable_irq(); + if (b_sam_ba_interface_usart) { + ptr_monitor_if->put_c(0x6); + } + } + else if (command == 'T') + { + b_terminal_mode = 1; + ptr_monitor_if->putdata("\n\r", 2); + } + else if (command == 'N') + { + if (b_terminal_mode == 0) + { + ptr_monitor_if->putdata("\n\r", 2); + } + b_terminal_mode = 0; + } + else if (command == 'V') + { + ptr_monitor_if->putdata("v", 1); + ptr_monitor_if->putdata((uint8_t *) RomBOOT_Version, strlen(RomBOOT_Version)); + ptr_monitor_if->putdata(" ", 1); + ptr_monitor_if->putdata((uint8_t *) RomBOOT_ExtendedCapabilities, strlen(RomBOOT_ExtendedCapabilities)); + ptr_monitor_if->putdata(" ", 1); + ptr = (uint8_t*) &(__DATE__); + i = 0; + while (*ptr++ != '\0') + i++; + ptr_monitor_if->putdata((uint8_t *) &(__DATE__), i); + ptr_monitor_if->putdata(" ", 1); + i = 0; + ptr = (uint8_t*) &(__TIME__); + while (*ptr++ != '\0') + i++; + ptr_monitor_if->putdata((uint8_t *) &(__TIME__), i); + ptr_monitor_if->putdata("\n\r", 2); + } + else if (command == 'X') + { + // Syntax: X[ADDR]# + // Erase the flash memory starting from ADDR to the end of flash. + + // Note: the flash memory is erased in ROWS, that is in block of 4 pages. + // Even if the starting address is the last byte of a ROW the entire + // ROW is erased anyway. + + uint32_t dst_addr = current_number; // starting address + + while (dst_addr < MAX_FLASH) + { + // Execute "ER" Erase Row + NVMCTRL->ADDR.reg = dst_addr / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; + while (NVMCTRL->INTFLAG.bit.READY == 0) + ; + dst_addr += PAGE_SIZE * 4; // Skip a ROW + } + + // Notify command completed + ptr_monitor_if->putdata("X\n\r", 3); + } + else if (command == 'Y') + { + // This command writes the content of a buffer in SRAM into flash memory. + + // Syntax: Y[ADDR],0# + // Set the starting address of the SRAM buffer. + + // Syntax: Y[ROM_ADDR],[SIZE]# + // Write the first SIZE bytes from the SRAM buffer (previously set) into + // flash memory starting from address ROM_ADDR + + static uint32_t *src_buff_addr = NULL; + + if (current_number == 0) + { + // Set buffer address + src_buff_addr = (uint32_t*)ptr_data; + } + else + { + // Write to flash + uint32_t size = current_number/4; + uint32_t *src_addr = src_buff_addr; + uint32_t *dst_addr = (uint32_t*)ptr_data; + + // Set automatic page write + NVMCTRL->CTRLB.bit.MANW = 0; + + // Do writes in pages + while (size) + { + // Execute "PBC" Page Buffer Clear + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.READY == 0) + ; + + // Fill page buffer + uint32_t i; + for (i=0; i<(PAGE_SIZE/4) && iADDR.reg = ((uint32_t)dst_addr) / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; + while (NVMCTRL->INTFLAG.bit.READY == 0) + ; + + // Advance to next page + dst_addr += i; + src_addr += i; + size -= i; + } + } + + // Notify command completed + ptr_monitor_if->putdata("Y\n\r", 3); + } + else if (command == 'Z') + { + // This command calculate CRC for a given area of memory. + // It's useful to quickly check if a transfer has been done + // successfully. + + // Syntax: Z[START_ADDR],[SIZE]# + // Returns: Z[CRC]# + + uint8_t *data = (uint8_t *)ptr_data; + uint32_t size = current_number; + uint16_t crc = 0; + uint32_t i = 0; + for (i=0; iputdata("Z", 1); + put_uint32(crc); + ptr_monitor_if->putdata("#\n\r", 3); + } + + command = 'z'; + current_number = 0; + + if (b_terminal_mode) + { + ptr_monitor_if->putdata(">", 1); + } + } + else + { + if (('0' <= *ptr) && (*ptr <= '9')) + { + current_number = (current_number << 4) | (*ptr - '0'); + } + else if (('A' <= *ptr) && (*ptr <= 'F')) + { + current_number = (current_number << 4) | (*ptr - 'A' + 0xa); + } + else if (('a' <= *ptr) && (*ptr <= 'f')) + { + current_number = (current_number << 4) | (*ptr - 'a' + 0xa); + } + else if (*ptr == ',') + { + ptr_data = (uint8_t *) current_number; + current_number = 0; + } + else + { + command = *ptr; + current_number = 0; + } + } + } } -void sam_ba_monitor_loop(void) +/** + * \brief This function starts the SAM-BA monitor. + */ +void sam_ba_monitor_run(void) { - pulse_led(3); - length = ptr_monitor_if->getdata(data, SIZEBUFMAX); - ptr = data; - for (i = 0; i < length; i++, ptr++) - { - if (*ptr == 0xff) continue; - - if (*ptr == '#') - { - if (b_terminal_mode) - { - ptr_monitor_if->putdata("\n\r", 2); - } - if (command == 'S') - { - //Check if some data are remaining in the "data" buffer - if(length>i) - { - //Move current indexes to next avail data (currently ptr points to "#") - ptr++; - i++; - //We need to add first the remaining data of the current buffer already read from usb - //read a maximum of "current_number" bytes - u32tmp=min((length-i),current_number); - memcpy(ptr_data, ptr, u32tmp); - i += u32tmp; - ptr += u32tmp; - j = u32tmp; - } - //update i with the data read from the buffer - i--; - ptr--; - //Do we expect more data ? - if(jgetdata_xmd(ptr_data, current_number-j); - - __asm("nop"); - } - else if (command == 'R') - { - ptr_monitor_if->putdata_xmd(ptr_data, current_number); - } - else if (command == 'O') - { - *ptr_data = (char) current_number; - } - else if (command == 'H') - { - *((uint16_t *) ptr_data) = (uint16_t) current_number; - } - else if (command == 'W') - { - *((int *) ptr_data) = current_number; - } - else if (command == 'o') - { - sam_ba_putdata_term(ptr_data, 1); - } - else if (command == 'h') - { - current_number = *((uint16_t *) ptr_data); - sam_ba_putdata_term((uint8_t*) ¤t_number, 2); - } - else if (command == 'w') - { - current_number = *((uint32_t *) ptr_data); - sam_ba_putdata_term((uint8_t*) ¤t_number, 4); - } - else if (command == 'G') - { - call_applet(current_number); - /* Rebase the Stack Pointer */ - __set_MSP(sp); - cpu_irq_enable(); - if (b_sam_ba_interface_usart) { - ptr_monitor_if->put_c(0x6); - } - } - else if (command == 'T') - { - b_terminal_mode = 1; - ptr_monitor_if->putdata("\n\r", 2); - } - else if (command == 'N') - { - if (b_terminal_mode == 0) - { - ptr_monitor_if->putdata("\n\r", 2); - } - b_terminal_mode = 0; - } - else if (command == 'V') - { - ptr_monitor_if->putdata("v", 1); - ptr_monitor_if->putdata((uint8_t *) RomBOOT_Version, - strlen(RomBOOT_Version)); - ptr_monitor_if->putdata(" ", 1); - ptr_monitor_if->putdata((uint8_t *) RomBOOT_ExtendedCapabilities, - strlen(RomBOOT_ExtendedCapabilities)); - ptr_monitor_if->putdata(" ", 1); - ptr = (uint8_t*) &(__DATE__); - i = 0; - while (*ptr++ != '\0') - i++; - ptr_monitor_if->putdata((uint8_t *) &(__DATE__), i); - ptr_monitor_if->putdata(" ", 1); - i = 0; - ptr = (uint8_t*) &(__TIME__); - while (*ptr++ != '\0') - i++; - ptr_monitor_if->putdata((uint8_t *) &(__TIME__), i); - ptr_monitor_if->putdata("\n\r", 2); - } - else if (command == 'X') - { - // Syntax: X[ADDR]# - // Erase the flash memory starting from ADDR to the end of flash. - - // Note: the flash memory is erased in ROWS, that is in block of 4 pages. - // Even if the starting address is the last byte of a ROW the entire - // ROW is erased anyway. - - uint32_t dst_addr = current_number; // starting address - - while (dst_addr < MAX_FLASH) { - // Execute "ER" Erase Row - NVMCTRL->ADDR.reg = dst_addr / 2; - NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; - while (NVMCTRL->INTFLAG.bit.READY == 0) - ; - dst_addr += PAGE_SIZE * 4; // Skip a ROW - } - - // Notify command completed - ptr_monitor_if->putdata("X\n\r", 3); - } - else if (command == 'Y') - { - // This command writes the content of a buffer in SRAM into flash memory. - - // Syntax: Y[ADDR],0# - // Set the starting address of the SRAM buffer. - - // Syntax: Y[ROM_ADDR],[SIZE]# - // Write the first SIZE bytes from the SRAM buffer (previously set) into - // flash memory starting from address ROM_ADDR - - static uint32_t *src_buff_addr = NULL; - - if (current_number == 0) { - // Set buffer address - src_buff_addr = ptr_data; - - } else { - // Write to flash - uint32_t size = current_number/4; - uint32_t *src_addr = src_buff_addr; - uint32_t *dst_addr = ptr_data; - - // Set automatic page write - NVMCTRL->CTRLB.bit.MANW = 0; - - // Do writes in pages - while (size) { - // Execute "PBC" Page Buffer Clear - NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; - while (NVMCTRL->INTFLAG.bit.READY == 0) - ; - - // Fill page buffer - uint32_t i; - for (i=0; i<(PAGE_SIZE/4) && iADDR.reg = ((uint32_t)dst_addr) / 2; - NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; - while (NVMCTRL->INTFLAG.bit.READY == 0) - ; - - // Advance to next page - dst_addr += i; - src_addr += i; - size -= i; - } - } - - // Notify command completed - ptr_monitor_if->putdata("Y\n\r", 3); - } - else if (command == 'Z') - { - // This command calculate CRC for a given area of memory. - // It's useful to quickly check if a transfer has been done - // successfully. - - // Syntax: Z[START_ADDR],[SIZE]# - // Returns: Z[CRC]# - - uint8_t *data = (uint8_t *)ptr_data; - uint32_t size = current_number; - uint16_t crc = 0; - uint32_t i = 0; - for (i=0; iputdata("Z", 1); - put_uint32(crc); - ptr_monitor_if->putdata("#\n\r", 3); - } - - command = 'z'; - current_number = 0; - - if (b_terminal_mode) - { - ptr_monitor_if->putdata(">", 1); - } - } - else - { - if (('0' <= *ptr) && (*ptr <= '9')) - { - current_number = (current_number << 4) | (*ptr - '0'); - } - else if (('A' <= *ptr) && (*ptr <= 'F')) - { - current_number = (current_number << 4) | (*ptr - 'A' + 0xa); - } - else if (('a' <= *ptr) && (*ptr <= 'f')) - { - current_number = (current_number << 4) | (*ptr - 'a' + 0xa); - } - else if (*ptr == ',') - { - ptr_data = (uint8_t *) current_number; - current_number = 0; - } - else - { - command = *ptr; - current_number = 0; - } - } - } + uint32_t pageSizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024 }; + PAGE_SIZE = pageSizes[NVMCTRL->PARAM.bit.PSZ]; + PAGES = NVMCTRL->PARAM.bit.NVMP; + MAX_FLASH = PAGE_SIZE * PAGES; + + ptr_data = NULL; + command = 'z'; + while (1) + { + sam_ba_monitor_loop(); + } } - - - - diff --git a/bootloaders/zero/sam_ba_monitor.h b/bootloaders/zero/sam_ba_monitor.h index c70ddb187..e72582bcf 100644 --- a/bootloaders/zero/sam_ba_monitor.h +++ b/bootloaders/zero/sam_ba_monitor.h @@ -1,36 +1,26 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ #ifndef _MONITOR_SAM_BA_H_ #define _MONITOR_SAM_BA_H_ -#define SAM_BA_VERSION "1.1" +#define SAM_BA_VERSION "2.0" /* Enable the interfaces to save code size */ #define SAM_BA_BOTH_INTERFACES 0 @@ -41,11 +31,10 @@ #define SAM_BA_INTERFACE SAM_BA_BOTH_INTERFACES #endif -/* Selects USART as the communication interface of the monitor */ -#define SAM_BA_INTERFACE_USART 1 /* Selects USB as the communication interface of the monitor */ #define SAM_BA_INTERFACE_USBCDC 0 - +/* Selects USART as the communication interface of the monitor */ +#define SAM_BA_INTERFACE_USART 1 /* Selects USB as the communication interface of the monitor */ #define SIZEBUFMAX 64 diff --git a/bootloaders/zero/sam_ba_serial.c b/bootloaders/zero/sam_ba_serial.c new file mode 100644 index 000000000..a06de01dc --- /dev/null +++ b/bootloaders/zero/sam_ba_serial.c @@ -0,0 +1,534 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "board_definitions.h" +#include "sam_ba_serial.h" +#include "board_driver_serial.h" + +/* Local reference to current Usart instance in use with this driver */ +//struct usart_module usart_sam_ba; + +/* Variable to let the main task select the appropriate communication interface */ +volatile uint8_t b_sharp_received; + +/* RX and TX Buffers + rw pointers for each buffer */ +volatile uint8_t buffer_rx_usart[USART_BUFFER_SIZE]; + +volatile uint8_t idx_rx_read; +volatile uint8_t idx_rx_write; + +volatile uint8_t buffer_tx_usart[USART_BUFFER_SIZE]; + +volatile uint8_t idx_tx_read; +volatile uint8_t idx_tx_write; + +/* Test for timeout in AT91F_GetChar */ +uint8_t error_timeout; +uint16_t size_of_data; +uint8_t mode_of_transfer; + +#define BOOT_USART_PAD(n) BOOT_USART_PAD##n + +/** + * \brief Open the given USART + */ +void serial_open(void) +{ + uint32_t port; + uint32_t pin; + + /* Configure the port pins for SERCOM_USART */ + if (BOOT_USART_PAD0 != PINMUX_UNUSED) + { + /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ + port = (BOOT_USART_PAD0 & 0x200000) >> 21; + pin = (BOOT_USART_PAD0 >> 16); + PORT->Group[port].PINCFG[(pin - (port*32))].bit.PMUXEN = 1; + PORT->Group[port].PMUX[(pin - (port*32))/2].reg &= ~(0xF << (4 * (pin & 0x01u))); + PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD0 & 0xFF) << (4 * (pin & 0x01u)); + } + + if (BOOT_USART_PAD1 != PINMUX_UNUSED) + { + /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ + port = (BOOT_USART_PAD1 & 0x200000) >> 21; + pin = BOOT_USART_PAD1 >> 16; + PORT->Group[port].PINCFG[(pin - (port*32))].bit.PMUXEN = 1; + PORT->Group[port].PMUX[(pin - (port*32))/2].reg &= ~(0xF << (4 * (pin & 0x01u))); + PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD1 & 0xFF) << (4 * (pin & 0x01u)); + } + + if (BOOT_USART_PAD2 != PINMUX_UNUSED) + { + /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ + port = (BOOT_USART_PAD2 & 0x200000) >> 21; + pin = BOOT_USART_PAD2 >> 16; + PORT->Group[port].PINCFG[(pin - (port*32))].bit.PMUXEN = 1; + PORT->Group[port].PMUX[(pin - (port*32))/2].reg &= ~(0xF << (4 * (pin & 0x01u))); + PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD2 & 0xFF) << (4 * (pin & 0x01u)); + } + + if (BOOT_USART_PAD3 != PINMUX_UNUSED) + { + /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ + port = (BOOT_USART_PAD3 & 0x200000) >> 21; + pin = BOOT_USART_PAD3 >> 16; + PORT->Group[port].PINCFG[(pin - (port*32))].bit.PMUXEN = 1; + PORT->Group[port].PMUX[(pin - (port*32))/2].reg &= ~(0xF << (4 * (pin & 0x01u))); + PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD3 & 0xFF) << (4 * (pin & 0x01u)); + } + + /* Enable clock for BOOT_USART_MODULE */ + PM->APBCMASK.reg |= BOOT_USART_BUS_CLOCK_INDEX ; + + /* Set GCLK_GEN0 as source for GCLK_ID_SERCOMx_CORE */ + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( BOOT_USART_PER_CLOCK_INDEX ) | // Generic Clock 0 (SERCOMx) + GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source + GCLK_CLKCTRL_CLKEN ; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* Baud rate 115200 - clock 8MHz -> BAUD value-50436 */ + uart_basic_init(BOOT_USART_MODULE, 50436, BOOT_USART_PAD_SETTINGS); + + //Initialize flag + b_sharp_received = false; + idx_rx_read = 0; + idx_rx_write = 0; + idx_tx_read = 0; + idx_tx_write = 0; + + error_timeout = 0; +} + +/** + * \brief Close communication line + */ +void serial_close(void) +{ + uart_disable(BOOT_USART_MODULE); +} + +/** + * \brief Puts a byte on usart line + * The type int is used to support printf redirection from compiler LIB. + * + * \param value Value to put + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ +int serial_putc(int value) +{ + uart_write_byte(BOOT_USART_MODULE, (uint8_t)value); + return 1; +} + +int serial_getc(void) +{ + uint16_t retval; + //Wait until input buffer is filled + while(!(serial_is_rx_ready())); + retval = (uint16_t)uart_read_byte(BOOT_USART_MODULE); + //usart_read_wait(&usart_sam_ba, &retval); + return (int)retval; + +} + +int serial_sharp_received(void) +{ + if (serial_is_rx_ready()) + { + if (serial_getc() == SHARP_CHARACTER) + return (true); + } + return (false); +} + +bool serial_is_rx_ready(void) +{ + return (BOOT_USART_MODULE->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_RXC); +} + +int serial_readc(void) +{ + int retval; + retval = buffer_rx_usart[idx_rx_read]; + idx_rx_read = (idx_rx_read + 1) & (USART_BUFFER_SIZE - 1); + return (retval); +} + +//Send given data (polling) +uint32_t serial_putdata(void const* data, uint32_t length) +{ + uint32_t i; + uint8_t* ptrdata; + ptrdata = (uint8_t*) data; + for (i = 0; i < length; i++) + { + serial_putc(*ptrdata); + ptrdata++; + } + return (i); +} + +//Get data from comm. device +uint32_t serial_getdata(void* data, uint32_t length) +{ + uint8_t* ptrdata; + ptrdata = (uint8_t*) data; + *ptrdata = serial_getc(); + return (1); +} + +static const uint16_t crc16Table[256]= +{ + 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, + 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, + 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, + 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, + 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, + 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, + 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, + 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, + 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, + 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, + 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, + 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, + 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, + 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, + 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, + 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, + 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, + 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, + 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, + 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, + 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, + 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, + 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, + 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, + 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, + 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, + 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, + 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, + 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, + 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, + 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, + 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 +}; + +//*---------------------------------------------------------------------------- +//* \brief Compute the CRC +//*---------------------------------------------------------------------------- +unsigned short serial_add_crc(char ptr, unsigned short crc) +{ + return (crc << 8) ^ crc16Table[((crc >> 8) ^ ptr) & 0xff]; +} + +//*---------------------------------------------------------------------------- +//* \brief +//*---------------------------------------------------------------------------- +static uint16_t getbytes(uint8_t *ptr_data, uint16_t length) +{ + uint16_t crc = 0; + uint16_t cpt; + uint8_t c; + + for (cpt = 0; cpt < length; ++cpt) + { + c = serial_getc(); + if (error_timeout) + return 1; + crc = serial_add_crc(c, crc); + //crc = (crc << 8) ^ xcrc16tab[(crc>>8) ^ c]; + if (size_of_data || mode_of_transfer) + { + *ptr_data++ = c; + if (length == PKTLEN_128) + size_of_data--; + } + } + + return crc; +} + +//*---------------------------------------------------------------------------- +//* \brief Used by Xup to send packets. +//*---------------------------------------------------------------------------- +static int putPacket(uint8_t *tmppkt, uint8_t sno) +{ + uint32_t i; + uint16_t chksm; + uint8_t data; + + chksm = 0; + + serial_putc(SOH); + + serial_putc(sno); + serial_putc((uint8_t) ~(sno)); + + for (i = 0; i < PKTLEN_128; i++) + { + if (size_of_data || mode_of_transfer) + { + data = *tmppkt++; + size_of_data--; + } + else + data = 0x00; + + serial_putc(data); + + //chksm = (chksm<<8) ^ xcrc16tab[(chksm>>8)^data]; + chksm = serial_add_crc(data, chksm); + } + + /* An "endian independent way to extract the CRC bytes. */ + serial_putc((uint8_t) (chksm >> 8)); + serial_putc((uint8_t) chksm); + + return (serial_getc()); /* Wait for ack */ +} + +//*---------------------------------------------------------------------------- +//* \brief Called when a transfer from target to host is being made (considered +//* an upload). +//*---------------------------------------------------------------------------- +//Send given data (polling) using xmodem (if necessary) +uint32_t serial_putdata_xmd(void const* data, uint32_t length) +{ + uint8_t c, sno = 1; + uint8_t done; + uint8_t * ptr_data = (uint8_t *) data; + error_timeout = 0; + if (!length) + mode_of_transfer = 1; + else + { + size_of_data = length; + mode_of_transfer = 0; + } + + if (length & (PKTLEN_128 - 1)) + { + length += PKTLEN_128; + length &= ~(PKTLEN_128 - 1); + } + + /* Startup synchronization... */ + /* Wait to receive a NAK or 'C' from receiver. */ + done = 0; + while (!done) { + c = (uint8_t) serial_getc(); + if (error_timeout) + { // Test for timeout in serial_getc + error_timeout = 0; + c = (uint8_t) serial_getc(); + if (error_timeout) + { + error_timeout = 0; + return (0); + } + } + switch (c) + { + case NAK: + done = 1; + // ("CSM"); + break; + case 'C': + done = 1; + // ("CRC"); + break; + case 'q': /* ELS addition, not part of XMODEM spec. */ + return (0); + default: + break; + } + } + + done = 0; + sno = 1; + while (!done) + { + c = (uint8_t) putPacket((uint8_t *) ptr_data, sno); + if (error_timeout) + { // Test for timeout in serial_getc + error_timeout = 0; + return (0); + } + switch (c) + { + case ACK: + ++sno; + length -= PKTLEN_128; + ptr_data += PKTLEN_128; + // ("A"); + break; + + case NAK: + // ("N"); + break; + + case CAN: + case EOT: + default: + done = 0; + break; + } + + if (!length) + { + serial_putc(EOT); + serial_getc(); /* Flush the ACK */ + break; + } + // ("!"); + } + + mode_of_transfer = 0; + // ("Xup_done."); + return (1); + // return(0); +} + +/*---------------------------------------------------------------------------- + * \brief Used by serial_getdata_xmd to retrieve packets. + */ +static uint8_t getPacket(uint8_t *ptr_data, uint8_t sno) +{ + uint8_t seq[2]; + uint16_t crc, xcrc; + + getbytes(seq, 2); + xcrc = getbytes(ptr_data, PKTLEN_128); + if (error_timeout) + return (false); + + /* An "endian independent way to combine the CRC bytes. */ + crc = (uint16_t) serial_getc() << 8; + crc += (uint16_t) serial_getc(); + + if (error_timeout == 1) + return (false); + + if ((crc != xcrc) || (seq[0] != sno) || (seq[1] != (uint8_t) (~sno))) + { + serial_putc(CAN); + return (false); + } + + serial_putc(ACK); + return (true); +} + +//*---------------------------------------------------------------------------- +//* \brief Called when a transfer from host to target is being made (considered +//* an download). +//*---------------------------------------------------------------------------- +//Get data from comm. device using xmodem (if necessary) +uint32_t serial_getdata_xmd(void* data, uint32_t length) +{ + uint32_t timeout; + char c; + uint8_t * ptr_data = (uint8_t *) data; + uint32_t b_run, nbr_of_timeout = 100; + uint8_t sno = 0x01; + uint32_t data_transfered = 0; + + //Copied from legacy source code ... might need some tweaking + uint32_t loops_per_second = CPU_FREQUENCY/60; + + error_timeout = 0; + + if (length == 0) + mode_of_transfer = 1; + else + { + size_of_data = length; + mode_of_transfer = 0; + } + + /* Startup synchronization... */ + /* Continuously send NAK or 'C' until sender responds. */ + // ("Xdown"); + while (1) + { + serial_putc('C'); + timeout = loops_per_second; + while (!(serial_is_rx_ready()) && timeout) + timeout--; + if (timeout) + break; + + if (!(--nbr_of_timeout)) + return (0); +// return -1; + } + + b_run = true; + // ("Got response"); + while (b_run != false) + { + c = (char) serial_getc(); + if (error_timeout) + { // Test for timeout in serial_getc + error_timeout = 0; + return (0); +// return (-1); + } + switch (c) + { + case SOH: /* 128-byte incoming packet */ + // ("O"); + b_run = getPacket(ptr_data, sno); + if (error_timeout) + { // Test for timeout in serial_getc + error_timeout = 0; + return (0); + // return (-1); + } + if (b_run == true) + { + ++sno; + ptr_data += PKTLEN_128; + data_transfered += PKTLEN_128; + } + break; + case EOT: // ("E"); + serial_putc(ACK); + b_run = false; + break; + case CAN: // ("C"); + case ESC: /* "X" User-invoked abort */ + default: + b_run = false; + break; + } + // ("!"); + } + mode_of_transfer = 0; + return (true); +// return(b_run); +} + diff --git a/bootloaders/zero/sam_ba_serial.h b/bootloaders/zero/sam_ba_serial.h new file mode 100644 index 000000000..cb69f459e --- /dev/null +++ b/bootloaders/zero/sam_ba_serial.h @@ -0,0 +1,143 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SAM_BA_SERIAL_H_ +#define _SAM_BA_SERIAL_H_ + +#include +#include + + +/* USART buffer size (must be a power of two) */ +#define USART_BUFFER_SIZE (128) + +/* Define the default time-out value for USART. */ +#define USART_DEFAULT_TIMEOUT (1000) + +/* Xmodem related defines */ +/* CRC16 polynomial */ +#define CRC16POLY (0x1021) + +#define SHARP_CHARACTER '#' + +/* X/Ymodem protocol: */ +#define SOH (0x01) +//#define STX (0x02) +#define EOT (0x04) +#define ACK (0x06) +#define NAK (0x15) +#define CAN (0x18) +#define ESC (0x1b) + +#define PKTLEN_128 (128) + + +/** + * \brief Open the given USART + */ +void serial_open(void); + +/** + * \brief Stops the USART + */ +void serial_close(void); + +/** + * \brief Puts a byte on usart line + * + * \param value Value to put + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ +int serial_putc(int value); + +/** + * \brief Waits and gets a value on usart line + * + * \return value read on usart line + */ +int serial_getc(void); + +/** + * \brief Returns true if the SAM-BA Uart received the sharp char + * + * \return Returns true if the SAM-BA Uart received the sharp char + */ +int serial_sharp_received(void); + +/** + * \brief This function checks if a character has been received on the usart line + * + * \return \c 1 if a byte is ready to be read. + */ +bool serial_is_rx_ready(void); + +/** + * \brief Gets a value on usart line + * + * \return value read on usart line + */ +int serial_readc(void); + +/** + * \brief Send buffer on usart line + * + * \param data pointer + * \param number of data to send + * \return number of data sent + */ +uint32_t serial_putdata(void const* data, uint32_t length); //Send given data (polling) + +/** + * \brief Gets data from usart line + * + * \param data pointer + * \param number of data to get + * \return value read on usart line + */ +uint32_t serial_getdata(void* data, uint32_t length); //Get data from comm. device + +/** + * \brief Send buffer on usart line using Xmodem protocol + * + * \param data pointer + * \param number of data to send + * \return number of data sent + */ +uint32_t serial_putdata_xmd(void const* data, uint32_t length); //Send given data (polling) using xmodem (if necessary) + +/** + * \brief Gets data from usart line using Xmodem protocol + * + * \param data pointer + * \param number of data to get + * \return value read on usart line + */ +uint32_t serial_getdata_xmd(void* data, uint32_t length); //Get data from comm. device using xmodem (if necessary) + +/** + * \brief Compute the CRC + * + * \param Char to add to CRC + * \param Previous CRC + * \return The new computed CRC + */ +unsigned short serial_add_crc(char c, unsigned short crc); + +#endif // _SAM_BA_SERIAL_H_ diff --git a/bootloaders/zero/sam_ba_usb.c b/bootloaders/zero/sam_ba_usb.c new file mode 100644 index 000000000..090375c7f --- /dev/null +++ b/bootloaders/zero/sam_ba_usb.c @@ -0,0 +1,456 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include "sam_ba_usb.h" +#include "board_driver_usb.h" +#include "sam_ba_cdc.h" + +/* This data array will be copied into SRAM as its length is inferior to 64 bytes, + * and so can stay in flash. + */ +static __attribute__((__aligned__(4))) +const char devDescriptor[] = +{ + /* Device descriptor */ + 0x12, // bLength + 0x01, // bDescriptorType + 0x00, // bcdUSB L + 0x02, // bcdUSB H + 0x02, // bDeviceClass: CDC class code + 0x00, // bDeviceSubclass: CDC class sub code + 0x00, // bDeviceProtocol: CDC Device protocol + 0x40, // bMaxPacketSize0 + 0x41, // idVendor L + 0x23, // idVendor H + USB_PID_LOW, // idProduct L + USB_PID_HIGH, // idProduct H + 0x00, // bcdDevice L, here matching SAM-BA version + 0x02, // bcdDevice H +#if 0 // TODO: pending validation + STRING_INDEX_MANUFACTURER, // iManufacturer + STRING_INDEX_PRODUCT, // iProduct +#else + 0x00, // iManufacturer + 0x00, // iProduct +#endif // 0 + 0x00, // SerialNumber, should be based on product unique ID + 0x01 // bNumConfigs +}; + +/* This data array will be consumed directly by USB_Write() and must be in SRAM. + * We cannot send data from product internal flash. + */ +static __attribute__((__aligned__(4))) +char cfgDescriptor[] = +{ + /* ============== CONFIGURATION 1 =========== */ + /* Configuration 1 descriptor */ + 0x09, // CbLength + 0x02, // CbDescriptorType + 0x43, // CwTotalLength 2 EP + Control + 0x00, + 0x02, // CbNumInterfaces + 0x01, // CbConfigurationValue + 0x00, // CiConfiguration + 0x80, // CbmAttributes Bus powered without remote wakeup: 0x80, Self powered without remote wakeup: 0xc0 + 0x32, // CMaxPower, report using 100mA, enough for a bootloader + + /* Communication Class Interface Descriptor Requirement */ + 0x09, // bLength + 0x04, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x01, // bNumEndpoints + 0x02, // bInterfaceClass + 0x02, // bInterfaceSubclass + 0x00, // bInterfaceProtocol + 0x00, // iInterface + + /* Header Functional Descriptor */ + 0x05, // bFunction Length + 0x24, // bDescriptor type: CS_INTERFACE + 0x00, // bDescriptor subtype: Header Func Desc + 0x10, // bcdCDC:1.1 + 0x01, + + /* ACM Functional Descriptor */ + 0x04, // bFunctionLength + 0x24, // bDescriptor Type: CS_INTERFACE + 0x02, // bDescriptor Subtype: ACM Func Desc + 0x00, // bmCapabilities + + /* Union Functional Descriptor */ + 0x05, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x06, // bDescriptor Subtype: Union Func Desc + 0x00, // bMasterInterface: Communication Class Interface + 0x01, // bSlaveInterface0: Data Class Interface + + /* Call Management Functional Descriptor */ + 0x05, // bFunctionLength + 0x24, // bDescriptor Type: CS_INTERFACE + 0x01, // bDescriptor Subtype: Call Management Func Desc + 0x00, // bmCapabilities: D1 + D0 + 0x01, // bDataInterface: Data Class Interface 1 + + /* Endpoint 1 descriptor */ + 0x07, // bLength + 0x05, // bDescriptorType + 0x83, // bEndpointAddress, Endpoint 03 - IN + 0x03, // bmAttributes INT + 0x08, // wMaxPacketSize + 0x00, + 0xFF, // bInterval + + /* Data Class Interface Descriptor Requirement */ + 0x09, // bLength + 0x04, // bDescriptorType + 0x01, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + 0x0A, // bInterfaceClass + 0x00, // bInterfaceSubclass + 0x00, // bInterfaceProtocol + 0x00, // iInterface + + /* First alternate setting */ + /* Endpoint 1 descriptor */ + 0x07, // bLength + 0x05, // bDescriptorType + 0x81, // bEndpointAddress, Endpoint 01 - IN + 0x02, // bmAttributes BULK + USB_EP_IN_SIZE, // wMaxPacketSize + 0x00, + 0x00, // bInterval + + /* Endpoint 2 descriptor */ + 0x07, // bLength + 0x05, // bDescriptorType + 0x02, // bEndpointAddress, Endpoint 02 - OUT + 0x02, // bmAttributes BULK + USB_EP_OUT_SIZE, // wMaxPacketSize + 0x00, + 0x00 // bInterval +}; + +#ifndef STRING_MANUFACTURER +# define STRING_MANUFACTURER "Arduino LLC" +#endif + +#ifndef STRING_PRODUCT +# define STRING_PRODUCT "Arduino Zero" +#endif + +USB_CDC sam_ba_cdc; + +/*---------------------------------------------------------------------------- + * \brief This function is a callback invoked when a SETUP packet is received + */ +void sam_ba_usb_CDC_Enumerate(P_USB_CDC pCdc) +{ + Usb *pUsb = pCdc->pUsb; + static volatile uint8_t bmRequestType, bRequest, dir; + static volatile uint16_t wValue, wIndex, wLength, wStatus; + + /* Clear the Received Setup flag */ + pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP = true; + + /* Read the USB request parameters */ + bmRequestType = udd_ep_out_cache_buffer[0][0]; + bRequest = udd_ep_out_cache_buffer[0][1]; + wValue = (udd_ep_out_cache_buffer[0][2] & 0xFF); + wValue |= (udd_ep_out_cache_buffer[0][3] << 8); + wIndex = (udd_ep_out_cache_buffer[0][4] & 0xFF); + wIndex |= (udd_ep_out_cache_buffer[0][5] << 8); + wLength = (udd_ep_out_cache_buffer[0][6] & 0xFF); + wLength |= (udd_ep_out_cache_buffer[0][7] << 8); + + /* Clear the Bank 0 ready flag on Control OUT */ + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY; + + /* Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1 */ + switch ((bRequest << 8) | bmRequestType) + { + case STD_GET_DESCRIPTOR: + if (wValue>>8 == STD_GET_DESCRIPTOR_DEVICE) + { + /* Return Device Descriptor */ + USB_Write(pCdc->pUsb, devDescriptor, SAM_BA_MIN(sizeof(devDescriptor), wLength), USB_EP_CTRL); + } + else + { + if (wValue>>8 == STD_GET_DESCRIPTOR_CONFIGURATION) + { + /* Return Configuration Descriptor */ + USB_Write(pCdc->pUsb, cfgDescriptor, SAM_BA_MIN(sizeof(cfgDescriptor), wLength), USB_EP_CTRL); + } + else + { +#if 0 // TODO: pending validation + if (wValue>>8 == STD_GET_DESCRIPTOR_STRING) + { + switch ( wValue & 0xff ) + { + case STRING_INDEX_LANGUAGES: + uint16_t STRING_LANGUAGE[2] = { (STD_GET_DESCRIPTOR_STRING<<8) | 4, 0x0409 }; + + USB_Write(pCdc->pUsb, (const char*)STRING_LANGUAGE, SAM_BA_MIN(sizeof(STRING_LANGUAGE), wLength), USB_EP_CTRL); + break; + + case STRING_INDEX_MANUFACTURER: + USB_SendString(pCdc->pUsb, STRING_MANUFACTURER, strlen(STRING_MANUFACTURER), wLength ); + break; + + case STRING_INDEX_PRODUCT: + USB_SendString(pCdc->pUsb, STRING_PRODUCT, strlen(STRING_PRODUCT), wLength ); + break; + default: + /* Stall the request */ + USB_SendStall(pUsb, true); + break; + } + } + else +#endif // 0 + { + /* Stall the request */ + USB_SendStall(pUsb, true); + } + } + } + break; + + case STD_SET_ADDRESS: + /* Send ZLP */ + USB_SendZlp(pUsb); + /* Set device address to the newly received address from host */ + USB_SetAddress(pCdc->pUsb, wValue); + break; + + case STD_SET_CONFIGURATION: + /* Store configuration */ + pCdc->currentConfiguration = (uint8_t)wValue; + + /* Send ZLP */ + USB_SendZlp(pUsb); + + /* Configure the 3 needed endpoints */ + USB_Configure(pUsb); + break; + + case STD_GET_CONFIGURATION: + /* Return current configuration value */ + USB_Write(pCdc->pUsb, (char *) &(pCdc->currentConfiguration), sizeof(pCdc->currentConfiguration), USB_EP_CTRL); + break; + + case STD_GET_STATUS_ZERO: + wStatus = 0; + USB_Write(pCdc->pUsb, (char *) &wStatus, sizeof(wStatus), USB_EP_CTRL); + break; + + case STD_GET_STATUS_INTERFACE: + wStatus = 0; + USB_Write(pCdc->pUsb, (char *) &wStatus, sizeof(wStatus), USB_EP_CTRL); + break; + + case STD_GET_STATUS_ENDPOINT: + wStatus = 0; + dir = wIndex & 80; + wIndex &= 0x0F; + if (wIndex <= 3) + { + if (dir) + { + //wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ1) ? 1 : 0; + wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<1)) ? 1 : 0; + } + else + { + //wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ0) ? 1 : 0; + wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<0)) ? 1 : 0; + } + /* Return current status of endpoint */ + USB_Write(pCdc->pUsb, (char *) &wStatus, sizeof(wStatus), USB_EP_CTRL); + } + else + { + /* Stall the request */ + USB_SendStall(pUsb, true); + } + break; + + case STD_SET_FEATURE_ZERO: + /* Stall the request */ + USB_SendStall(pUsb, true); + break; + + case STD_SET_FEATURE_INTERFACE: + /* Send ZLP */ + USB_SendZlp(pUsb); + break; + + case STD_SET_FEATURE_ENDPOINT: + dir = wIndex & 0x80; + wIndex &= 0x0F; + if ((wValue == 0) && wIndex && (wIndex <= 3)) + { + /* Set STALL request for the endpoint */ + if (dir) + { + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.bit.STALLRQ = (1<<1); + } + else + { + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.bit.STALLRQ = (1<<0); + } + + /* Send ZLP */ + USB_SendZlp(pUsb); + } + else + { + /* Stall the request */ + USB_SendStall(pUsb, true); + } + break; + + case STD_SET_INTERFACE: + case STD_CLEAR_FEATURE_ZERO: + /* Stall the request */ + USB_SendStall(pUsb, true); + break; + + case STD_CLEAR_FEATURE_INTERFACE: + /* Send ZLP */ + USB_SendZlp(pUsb); + break; + + case STD_CLEAR_FEATURE_ENDPOINT: + dir = wIndex & 0x80; + wIndex &= 0x0F; + + if ((wValue == 0) && wIndex && (wIndex <= 3)) + { + if (dir) + { + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<1)) + { + // Remove stall request + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.bit.STALLRQ = (1<<1); + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL & (1<<1)) + { + pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL = (1<<1); + // The Stall has occurred, then reset data toggle + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_DTGLIN; + } + } + } + else + { + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<0)) + { + // Remove stall request + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.bit.STALLRQ = (1<<0); + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL & (1<<0)) + { + pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL = (1<<0); + // The Stall has occurred, then reset data toggle + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_DTGLOUT; + } + } + } + /* Send ZLP */ + USB_SendZlp(pUsb); + } + else + { + USB_SendStall(pUsb, true); + } + break; + + // handle CDC class requests + case SET_LINE_CODING: + /* Send ZLP */ + USB_SendZlp(pUsb); + break; + + case GET_LINE_CODING: + /* Send current line coding */ + USB_Write(pCdc->pUsb, (char *) &line_coding, SAM_BA_MIN(sizeof(usb_cdc_line_coding_t), wLength), USB_EP_CTRL); + break; + + case SET_CONTROL_LINE_STATE: + /* Store the current connection */ + pCdc->currentConnection = wValue; + /* Send ZLP */ + USB_SendZlp(pUsb); + break; + + default: + /* Stall the request */ + USB_SendStall(pUsb, true); + break; + } +} + +/*---------------------------------------------------------------------------- + * \brief + */ +P_USB_CDC usb_init(void) +{ + sam_ba_cdc.pUsb = USB; + + /* Initialize USB */ + USB_Init(); + /* Get the default CDC structure settings */ + USB_Open(&sam_ba_cdc, sam_ba_cdc.pUsb); + + return &sam_ba_cdc; +} + +#if 0 // TODO: pending validation +/*---------------------------------------------------------------------------- + * \brief Send a USB descriptor string. + * + * The input string is plain ASCII but is sent out as UTF-16 with the correct 2-byte prefix. + */ +uint32_t USB_SendString(Usb *pUsb, const char* ascii_string, uint8_t length, uint8_t maxLength) +{ + uint8_t string_descriptor[255]; // Max USB-allowed string length + uint16_t* unicode_string=(uint16_t*)(string_descriptor+2); // point on 3 bytes of descriptor + + int resulting_length = 1; + + for ( ; *ascii_string && (length>=0) && (resulting_length<(maxLength>>1)) ; ascii_string++, length--, resulting_length++ ) + { + *unicode_string++ = (uint16_t)(*ascii_string); + } + + string_descriptor[0] = (resulting_length<<1); + string_descriptor[1] = STD_GET_DESCRIPTOR_STRING; + + return USB_Write(pUsb, (const char*)unicode_string, resulting_length, USB_EP_CTRL); +} +#endif // 0 diff --git a/bootloaders/zero/sam_ba_usb.h b/bootloaders/zero/sam_ba_usb.h new file mode 100644 index 000000000..42c0d608f --- /dev/null +++ b/bootloaders/zero/sam_ba_usb.h @@ -0,0 +1,107 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CDC_ENUMERATE_H +#define CDC_ENUMERATE_H + +#include +#include + +#define USB_EP_CTRL (0u) +#define USB_EP_OUT (2u) +#define USB_EP_OUT_SIZE (0x40u) +#define USB_EP_IN (1u) +#define USB_EP_IN_SIZE (0x40u) +#define USB_EP_COMM (3u) +#define MAX_EP (4u) + +/* USB standard request code */ +#define STD_GET_STATUS_ZERO (0x0080u) +#define STD_GET_STATUS_INTERFACE (0x0081u) +#define STD_GET_STATUS_ENDPOINT (0x0082u) + +#define STD_CLEAR_FEATURE_ZERO (0x0100u) +#define STD_CLEAR_FEATURE_INTERFACE (0x0101u) +#define STD_CLEAR_FEATURE_ENDPOINT (0x0102u) + +#define STD_SET_FEATURE_ZERO (0x0300u) +#define STD_SET_FEATURE_INTERFACE (0x0301u) +#define STD_SET_FEATURE_ENDPOINT (0x0302u) + +#define STD_SET_ADDRESS (0x0500u) +#define STD_GET_DESCRIPTOR (0x0680u) +#define STD_SET_DESCRIPTOR (0x0700u) +#define STD_GET_CONFIGURATION (0x0880u) +#define STD_SET_CONFIGURATION (0x0900u) +#define STD_GET_INTERFACE (0x0A81u) +#define STD_SET_INTERFACE (0x0B01u) +#define STD_SYNCH_FRAME (0x0C82u) + +#define STD_GET_DESCRIPTOR_DEVICE (1u) +#define STD_GET_DESCRIPTOR_CONFIGURATION (2u) +#define STD_GET_DESCRIPTOR_STRING (3u) +#define STD_GET_DESCRIPTOR_INTERFACE (4u) +#define STD_GET_DESCRIPTOR_ENDPOINT (5u) +#define STD_GET_DESCRIPTOR_DEVICE_QUALIFIER (6u) +#define STD_GET_DESCRIPTOR_OTHER_SPEED_CONFIGURATION (7u) +#define STD_GET_DESCRIPTOR_INTERFACE_POWER1 (8u) + +#define FEATURE_ENDPOINT_HALT (0u) +#define FEATURE_DEVICE_REMOTE_WAKEUP (1u) +#define FEATURE_TEST_MODE (2u) + +#if 0 // TODO: pending validation +#define STRING_INDEX_LANGUAGES (0x00u) +#define STRING_INDEX_MANUFACTURER (0x01u) +#define STRING_INDEX_PRODUCT (0x02u) +#endif // 0 + +#define SAM_BA_MIN(a, b) (((a) < (b)) ? (a) : (b)) + + +typedef struct _USB_CDC +{ + // Private members + Usb *pUsb; + uint8_t currentConfiguration; + uint8_t currentConnection; + // Public Methods: + uint8_t (*IsConfigured)(struct _USB_CDC *pCdc); +// uint32_t (*Write) (Usb *pUsb, const char *pData, uint32_t length, uint8_t ep_num); +// uint32_t (*Read) (Usb *pUsb, char *pData, uint32_t length); +} USB_CDC, *P_USB_CDC; + +/** + * \brief Initializes the USB module + * + * \return Pointer to the USB CDC structure + */ +P_USB_CDC usb_init(void); + +void sam_ba_usb_CDC_Enumerate(P_USB_CDC pCdc); + +#if 0 // TODO: pending validation +uint32_t USB_SendString(Usb *pUsb, const char* ascii_string, uint8_t length, uint8_t maxLength); +#endif // 0 + +extern USB_CDC sam_ba_cdc; + + + +#endif // CDC_ENUMERATE_H diff --git a/bootloaders/zero/samd21_sam_ba.atsln b/bootloaders/zero/samd21_sam_ba.atsln new file mode 100644 index 000000000..cf1043181 --- /dev/null +++ b/bootloaders/zero/samd21_sam_ba.atsln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Atmel Studio Solution File, Format Version 11.00 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "samd21_sam_ba", "samd21_sam_ba.cproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Release|ARM = Release|ARM + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|ARM.ActiveCfg = Debug|ARM + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|ARM.Build.0 = Debug|ARM + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|ARM.ActiveCfg = Release|ARM + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|ARM.Build.0 = Release|ARM + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/bootloaders/zero/samd21_sam_ba.bin b/bootloaders/zero/samd21_sam_ba.bin index 74cf2de8f94f2f8f4b202d46ba1764d00fce0d9c..d727d0707f3031f1eb86ed72e76749ef1a997fa7 100644 GIT binary patch delta 4385 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 + + + 2.0 + 7.0 + com.Atmel.ARMGCC.C + dce6c7e3-ee26-4d79-826b-08594b9ad897 + ATSAMD21G18A + none + Executable + C + $(MSBuildProjectName) + .elf + $(MSBuildProjectDirectory)\$(Configuration) + samd21_sam_ba + samd21_sam_ba + samd21_sam_ba + Native + true + false + true + true + 0x20000000 + + true + exception_table + 2 + 0 + + + + + + + + + + + + + + com.atmel.avrdbg.tool.atmelice + J41800001895 + 0x10010000 + SWD + + + + 2000000 + + SWD + + com.atmel.avrdbg.tool.atmelice + J41800001895 + Atmel-ICE + + 2000000 + + + + + SWD + + com.atmel.avrdbg.tool.edbg + ATML2320040200000259 + EDBG + + + + + + True + True + True + True + True + + + NDEBUG + + + Optimize for size (-Os) + True + True + + + libm + + + True + -Tsamd21j18a_flash.ld + + + + + + + True + True + True + True + True + + + DEBUG + + + Optimize (-O1) + True + Maximum (-g3) + True + + + libm + + + True + -Tsamd21j18a_flash.ld + Default (-g) + Default (-Wa,-g) + + + True + + DEBUG=1 all + clean + Makefile + + + + compile + board_definitions.h + + + compile + board_driver_led.c + + + compile + board_driver_led.h + + + compile + board_driver_serial.c + + + compile + board_driver_serial.h + + + compile + board_driver_usb.c + + + compile + board_driver_usb.h + + + compile + board_init.c + + + compile + board_startup.c + + + compile + main.c + + + compile + sam_ba_cdc.c + + + compile + sam_ba_cdc.h + + + compile + sam_ba_monitor.c + + + compile + sam_ba_monitor.h + + + compile + sam_ba_serial.c + + + compile + sam_ba_serial.h + + + compile + sam_ba_usb.c + + + compile + sam_ba_usb.h + + + + + compile + Makefile + + + compile + README.md + + + compile + bootloader_samd21x18.ld + + + + \ No newline at end of file diff --git a/bootloaders/zero/samd21_sam_ba.elf b/bootloaders/zero/samd21_sam_ba.elf new file mode 100644 index 0000000000000000000000000000000000000000..edee94811dd8e982f615dc00e61274864060a76b GIT binary patch literal 647224 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 RC_RoqQLmgSp&!-L{{fgVuU`NF literal 0 HcmV?d00001 diff --git a/bootloaders/feather/samd21j18a_flash.ld b/bootloaders/feather/samd21j18a_flash.ld deleted file mode 100644 index c9385c487..000000000 --- a/bootloaders/feather/samd21j18a_flash.ld +++ /dev/null @@ -1,157 +0,0 @@ -/** - * \file - * - * \brief Linker script for running in internal FLASH on the SAMD21J18A - * - * Copyright (c) 2013-2014 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ - - -OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") -OUTPUT_ARCH(arm) -SEARCH_DIR(.) - -/* Memory Spaces Definitions */ -MEMORY -{ - rom (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000 - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000-0x0004 /* 4 bytes used by bootloader to keep data between resets */ -} - -/* The stack size used by the application. NOTE: you need to adjust according to your application. */ -STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x2000; - -/* Section Definitions */ -SECTIONS -{ - .text : - { - . = ALIGN(4); - _sfixed = .; - KEEP(*(.vectors .vectors.*)) - *(.text .text.* .gnu.linkonce.t.*) - *(.glue_7t) *(.glue_7) - *(.rodata .rodata* .gnu.linkonce.r.*) - *(.ARM.extab* .gnu.linkonce.armextab.*) - - /* Support C constructors, and C destructors in both user code - and the C library. This also provides support for C++ code. */ - . = ALIGN(4); - KEEP(*(.init)) - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; - - . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; - - . = ALIGN(4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - - . = ALIGN(4); - KEEP(*(.fini)) - - . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - - . = ALIGN(4); - _efixed = .; /* End of text section */ - } > rom - - /* .ARM.exidx is sorted, so has to go in its own output section. */ - PROVIDE_HIDDEN (__exidx_start = .); - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > rom - PROVIDE_HIDDEN (__exidx_end = .); - - . = ALIGN(4); - _etext = .; - - .relocate : AT (_etext) - { - . = ALIGN(4); - _srelocate = .; - *(.ramfunc .ramfunc.*); - *(.data .data.*); - . = ALIGN(4); - _erelocate = .; - } > ram - - /* .bss section which is used for uninitialized data */ - .bss (NOLOAD) : - { - . = ALIGN(4); - _sbss = . ; - _szero = .; - *(.bss .bss.*) - *(COMMON) - . = ALIGN(4); - _ebss = . ; - _ezero = .; - } > ram - - /* stack section */ - .stack (NOLOAD): - { - . = ALIGN(8); - _sstack = .; - . = . + STACK_SIZE; - . = ALIGN(8); - _estack = .; - } > ram - - . = ALIGN(4); - _end = . ; -} diff --git a/bootloaders/feather/startup_samd21.c b/bootloaders/feather/startup_samd21.c deleted file mode 100644 index 0f45ae3f9..000000000 --- a/bootloaders/feather/startup_samd21.c +++ /dev/null @@ -1,201 +0,0 @@ -/** - * \file - * - * \brief gcc starttup file for SAMD21 - * - * Copyright (c) 2013-2014 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ - -#include "sam.h" - -/* Initialize segments */ -extern uint32_t _sfixed; -extern uint32_t _efixed; -extern uint32_t _etext; -extern uint32_t _srelocate; -extern uint32_t _erelocate; -extern uint32_t _szero; -extern uint32_t _ezero; -extern uint32_t _sstack; -extern uint32_t _estack; - -/** \cond DOXYGEN_SHOULD_SKIP_THIS */ -int main(void); -/** \endcond */ - -void __libc_init_array(void); - -/* Default empty handler */ -void Dummy_Handler(void); - -/* Cortex-M0+ core handlers */ -void NMI_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void HardFault_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void SVC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void PendSV_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void SysTick_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); - -/* Peripherals handlers */ -void PM_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void SYSCTRL_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void WDT_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void RTC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void EIC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void NVMCTRL_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void DMAC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void USB_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void EVSYS_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void SERCOM0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void SERCOM1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void SERCOM2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void SERCOM3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void SERCOM4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void SERCOM5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void TCC0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void TCC1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void TCC2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void TC3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void TC4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void TC5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void TC6_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void TC7_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void ADC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void AC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void DAC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void PTC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); -void I2S_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); - -/* Exception Table */ -__attribute__ ((section(".vectors"))) -const DeviceVectors exception_table = { - - /* Configure Initial Stack Pointer, using linker-generated symbols */ - (void*) (&_estack), - - (void*) Reset_Handler, - (void*) NMI_Handler, - (void*) HardFault_Handler, - (void*) (0UL), /* Reserved */ - (void*) (0UL), /* Reserved */ - (void*) (0UL), /* Reserved */ - (void*) (0UL), /* Reserved */ - (void*) (0UL), /* Reserved */ - (void*) (0UL), /* Reserved */ - (void*) (0UL), /* Reserved */ - (void*) SVC_Handler, - (void*) (0UL), /* Reserved */ - (void*) (0UL), /* Reserved */ - (void*) PendSV_Handler, - (void*) SysTick_Handler, - - /* Configurable interrupts */ - (void*) PM_Handler, /* 0 Power Manager */ - (void*) SYSCTRL_Handler, /* 1 System Control */ - (void*) WDT_Handler, /* 2 Watchdog Timer */ - (void*) RTC_Handler, /* 3 Real-Time Counter */ - (void*) EIC_Handler, /* 4 External Interrupt Controller */ - (void*) NVMCTRL_Handler, /* 5 Non-Volatile Memory Controller */ - (void*) DMAC_Handler, /* 6 Direct Memory Access Controller */ - (void*) USB_Handler, /* 7 Universal Serial Bus */ - (void*) EVSYS_Handler, /* 8 Event System Interface */ - (void*) SERCOM0_Handler, /* 9 Serial Communication Interface 0 */ - (void*) SERCOM1_Handler, /* 10 Serial Communication Interface 1 */ - (void*) SERCOM2_Handler, /* 11 Serial Communication Interface 2 */ - (void*) SERCOM3_Handler, /* 12 Serial Communication Interface 3 */ - (void*) SERCOM4_Handler, /* 13 Serial Communication Interface 4 */ - (void*) SERCOM5_Handler, /* 14 Serial Communication Interface 5 */ - (void*) TCC0_Handler, /* 15 Timer Counter Control 0 */ - (void*) TCC1_Handler, /* 16 Timer Counter Control 1 */ - (void*) TCC2_Handler, /* 17 Timer Counter Control 2 */ - (void*) TC3_Handler, /* 18 Basic Timer Counter 0 */ - (void*) TC4_Handler, /* 19 Basic Timer Counter 1 */ - (void*) TC5_Handler, /* 20 Basic Timer Counter 2 */ - (void*) TC6_Handler, /* 21 Basic Timer Counter 3 */ - (void*) TC7_Handler, /* 22 Basic Timer Counter 4 */ - (void*) ADC_Handler, /* 23 Analog Digital Converter */ - (void*) AC_Handler, /* 24 Analog Comparators */ - (void*) DAC_Handler, /* 25 Digital Analog Converter */ - (void*) PTC_Handler, /* 26 Peripheral Touch Controller */ - (void*) I2S_Handler /* 27 Inter-IC Sound Interface */ -}; - -/** - * \brief This is the code that gets called on processor reset. - * To initialize the device, and call the main() routine. - */ -void Reset_Handler(void) -{ - uint32_t *pSrc, *pDest; - - /* Initialize the relocate segment */ - pSrc = &_etext; - pDest = &_srelocate; - - if (pSrc != pDest) { - for (; pDest < &_erelocate;) { - *pDest++ = *pSrc++; - } - } - - /* Clear the zero segment */ - for (pDest = &_szero; pDest < &_ezero;) { - *pDest++ = 0; - } - - /* Set the vector table base address */ - pSrc = (uint32_t *) & _sfixed; - SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk); - - /* Initialize the C library */ - __libc_init_array(); - - /* Branch to main function */ - main(); - - /* Infinite loop */ - while (1); -} - -/** - * \brief Default interrupt handler for unused IRQs. - */ -void Dummy_Handler(void) -{ - while (1) { - } -} diff --git a/bootloaders/feather/usart_sam_ba.h b/bootloaders/feather/usart_sam_ba.h deleted file mode 100644 index d498dc791..000000000 --- a/bootloaders/feather/usart_sam_ba.h +++ /dev/null @@ -1,155 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#ifndef _USART_SAM_BA_H_ -#define _USART_SAM_BA_H_ - -#include "stdint.h" -#include "stdbool.h" - - -/* USART buffer size (must be a power of two) */ -#define USART_BUFFER_SIZE 128 - -/* Define the default time-out value for USART. */ -#define USART_DEFAULT_TIMEOUT 1000 - -/* Xmodem related defines */ -/* CRC16 polynomial */ -#define CRC16POLY 0x1021 - -#define SHARP_CHARACTER '#' - -/* X/Ymodem protocol: */ -#define SOH 0x01 -//#define STX 0x02 -#define EOT 0x04 -#define ACK 0x06 -#define NAK 0x15 -#define CAN 0x18 -#define ESC 0x1b - -#define PKTLEN_128 128 - - -/** - * \brief Open the given USART - */ -void usart_open(void); - -/** - * \brief Stops the USART - */ -void usart_close(void); - -/** - * \brief Puts a byte on usart line - * - * \param value Value to put - * - * \return \c 1 if function was successfully done, otherwise \c 0. - */ -int usart_putc(int value); - -/** - * \brief Waits and gets a value on usart line - * - * \return value read on usart line - */ -int usart_getc(void); - -/** - * \brief Returns true if the SAM-BA Uart received the sharp char - * - * \return Returns true if the SAM-BA Uart received the sharp char - */ -int usart_sharp_received(void); - -/** - * \brief This function checks if a character has been received on the usart line - * - * \return \c 1 if a byte is ready to be read. - */ -bool usart_is_rx_ready(void); - -/** - * \brief Gets a value on usart line - * - * \return value read on usart line - */ -int usart_readc(void); - -/** - * \brief Send buffer on usart line - * - * \param data pointer - * \param number of data to send - * \return number of data sent - */ -uint32_t usart_putdata(void const* data, uint32_t length); //Send given data (polling) - -/** - * \brief Gets data from usart line - * - * \param data pointer - * \param number of data to get - * \return value read on usart line - */ -uint32_t usart_getdata(void* data, uint32_t length); //Get data from comm. device - -/** - * \brief Send buffer on usart line using Xmodem protocol - * - * \param data pointer - * \param number of data to send - * \return number of data sent - */ -uint32_t usart_putdata_xmd(void const* data, uint32_t length); //Send given data (polling) using xmodem (if necessary) - -/** - * \brief Gets data from usart line using Xmodem protocol - * - * \param data pointer - * \param number of data to get - * \return value read on usart line - */ -uint32_t usart_getdata_xmd(void* data, uint32_t length); //Get data from comm. device using xmodem (if necessary) - -/** - * \brief Compute the CRC - * - * \param Char to add to CRC - * \param Previous CRC - * \return The new computed CRC - */ -unsigned short add_crc(char c, unsigned short crc); - -uint8_t getPacket(uint8_t *pData, uint8_t sno); - -#endif // _USART_SAM_BA_H_ diff --git a/bootloaders/feather/utils/compiler.h b/bootloaders/feather/utils/compiler.h deleted file mode 100644 index e31d7dba4..000000000 --- a/bootloaders/feather/utils/compiler.h +++ /dev/null @@ -1,1157 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#ifndef UTILS_COMPILER_H_INCLUDED -#define UTILS_COMPILER_H_INCLUDED - -/** - * \defgroup group_sam0_utils Compiler abstraction layer and code utilities - * - * Compiler abstraction layer and code utilities for Cortex-M0+ based Atmel SAM devices. - * This module provides various abstraction layers and utilities to make code compatible between different compilers. - * - * @{ - */ - -#if (defined __ICCARM__) -# include -#endif - -#include -//#include -#include -#include -#include - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include - -/** - * \def UNUSED - * \brief Marking \a v as a unused parameter or value. - */ -#define UNUSED(v) (void)(v) - -/** - * \def barrier - * \brief Memory barrier - */ -#ifdef __GNUC__ -# define barrier() asm volatile("" ::: "memory") -#else -# define barrier() asm ("") -#endif - -/** - * \brief Emit the compiler pragma \a arg. - * - * \param[in] arg The pragma directive as it would appear after \e \#pragma - * (i.e. not stringified). - */ -#define COMPILER_PRAGMA(arg) _Pragma(#arg) - -/** - * \def COMPILER_PACK_SET(alignment) - * \brief Set maximum alignment for subsequent struct and union definitions to \a alignment. - */ -#define COMPILER_PACK_SET(alignment) COMPILER_PRAGMA(pack(alignment)) - -/** - * \def COMPILER_PACK_RESET() - * \brief Set default alignment for subsequent struct and union definitions. - */ -#define COMPILER_PACK_RESET() COMPILER_PRAGMA(pack()) - - -/** - * \brief Set aligned boundary. - */ -#if (defined __GNUC__) || (defined __CC_ARM) -# define COMPILER_ALIGNED(a) __attribute__((__aligned__(a))) -#elif (defined __ICCARM__) -# define COMPILER_ALIGNED(a) COMPILER_PRAGMA(data_alignment = a) -#endif - -/** - * \brief Set word-aligned boundary. - */ -#if (defined __GNUC__) || defined(__CC_ARM) -#define COMPILER_WORD_ALIGNED __attribute__((__aligned__(4))) -#elif (defined __ICCARM__) -#define COMPILER_WORD_ALIGNED COMPILER_PRAGMA(data_alignment = 4) -#endif - -/** - * \def __always_inline - * \brief The function should always be inlined. - * - * This annotation instructs the compiler to ignore its inlining - * heuristics and inline the function no matter how big it thinks it - * becomes. - */ -#if defined(__CC_ARM) -# define __always_inline __forceinline -#elif (defined __GNUC__) -# define __always_inline __attribute__((__always_inline__)) -#elif (defined __ICCARM__) -# define __always_inline _Pragma("inline=forced") -#endif - -/** - * \def __no_inline - * \brief The function should never be inlined - * - * This annotation instructs the compiler to ignore its inlining - * heuristics and not inline the function no matter how small it thinks it - * becomes. - */ -#if defined(__CC_ARM) -# define __no_inline __attribute__((noinline)) -#elif (defined __GNUC__) -# define __no_inline __attribute__((noinline)) -#elif (defined __ICCARM__) -# define __no_inline _Pragma("inline=never") -#endif - - -/** \brief This macro is used to test fatal errors. - * - * The macro tests if the expression is false. If it is, a fatal error is - * detected and the application hangs up. If \c TEST_SUITE_DEFINE_ASSERT_MACRO - * is defined, a unit test version of the macro is used, to allow execution - * of further tests after a false expression. - * - * \param[in] expr Expression to evaluate and supposed to be nonzero. - */ -#if defined(_ASSERT_ENABLE_) -# if defined(TEST_SUITE_DEFINE_ASSERT_MACRO) -# include "unit_test/suite.h" -# else -# undef TEST_SUITE_DEFINE_ASSERT_MACRO -# define Assert(expr) \ - {\ - if (!(expr)) asm("BKPT #0");\ - } -# endif -#else -# define Assert(expr) ((void) 0) -#endif - -/* Define WEAK attribute */ -#if defined ( __CC_ARM ) -# define WEAK __attribute__ ((weak)) -#elif defined ( __ICCARM__ ) -# define WEAK __weak -#elif defined ( __GNUC__ ) -# define WEAK __attribute__ ((weak)) -#endif - -/* Define NO_INIT attribute */ -#if defined ( __CC_ARM ) -# define NO_INIT __attribute__((zero_init)) -#elif defined ( __ICCARM__ ) -# define NO_INIT __no_init -#elif defined ( __GNUC__ ) -# define NO_INIT __attribute__((section(".no_init"))) -#endif - -#include "interrupt.h" - -/** \name Usual Types - * @{ */ -#ifndef __cplusplus -# if !defined(__bool_true_false_are_defined) -typedef unsigned char bool; -# endif -#endif -typedef uint16_t le16_t; -typedef uint16_t be16_t; -typedef uint32_t le32_t; -typedef uint32_t be32_t; -typedef uint32_t iram_size_t; -/** @} */ - -/** \name Aliasing Aggregate Types - * @{ */ - -/** 16-bit union. */ -typedef union -{ - int16_t s16; - uint16_t u16; - int8_t s8[2]; - uint8_t u8[2]; -} Union16; - -/** 32-bit union. */ -typedef union -{ - int32_t s32; - uint32_t u32; - int16_t s16[2]; - uint16_t u16[2]; - int8_t s8[4]; - uint8_t u8[4]; -} Union32; - -/** 64-bit union. */ -typedef union -{ - int64_t s64; - uint64_t u64; - int32_t s32[2]; - uint32_t u32[2]; - int16_t s16[4]; - uint16_t u16[4]; - int8_t s8[8]; - uint8_t u8[8]; -} Union64; - -/** Union of pointers to 64-, 32-, 16- and 8-bit unsigned integers. */ -typedef union -{ - int64_t *s64ptr; - uint64_t *u64ptr; - int32_t *s32ptr; - uint32_t *u32ptr; - int16_t *s16ptr; - uint16_t *u16ptr; - int8_t *s8ptr; - uint8_t *u8ptr; -} UnionPtr; - -/** Union of pointers to volatile 64-, 32-, 16- and 8-bit unsigned integers. */ -typedef union -{ - volatile int64_t *s64ptr; - volatile uint64_t *u64ptr; - volatile int32_t *s32ptr; - volatile uint32_t *u32ptr; - volatile int16_t *s16ptr; - volatile uint16_t *u16ptr; - volatile int8_t *s8ptr; - volatile uint8_t *u8ptr; -} UnionVPtr; - -/** Union of pointers to constant 64-, 32-, 16- and 8-bit unsigned integers. */ -typedef union -{ - const int64_t *s64ptr; - const uint64_t *u64ptr; - const int32_t *s32ptr; - const uint32_t *u32ptr; - const int16_t *s16ptr; - const uint16_t *u16ptr; - const int8_t *s8ptr; - const uint8_t *u8ptr; -} UnionCPtr; - -/** Union of pointers to constant volatile 64-, 32-, 16- and 8-bit unsigned integers. */ -typedef union -{ - const volatile int64_t *s64ptr; - const volatile uint64_t *u64ptr; - const volatile int32_t *s32ptr; - const volatile uint32_t *u32ptr; - const volatile int16_t *s16ptr; - const volatile uint16_t *u16ptr; - const volatile int8_t *s8ptr; - const volatile uint8_t *u8ptr; -} UnionCVPtr; - -/** Structure of pointers to 64-, 32-, 16- and 8-bit unsigned integers. */ -typedef struct -{ - int64_t *s64ptr; - uint64_t *u64ptr; - int32_t *s32ptr; - uint32_t *u32ptr; - int16_t *s16ptr; - uint16_t *u16ptr; - int8_t *s8ptr; - uint8_t *u8ptr; -} StructPtr; - -/** Structure of pointers to volatile 64-, 32-, 16- and 8-bit unsigned integers. */ -typedef struct -{ - volatile int64_t *s64ptr; - volatile uint64_t *u64ptr; - volatile int32_t *s32ptr; - volatile uint32_t *u32ptr; - volatile int16_t *s16ptr; - volatile uint16_t *u16ptr; - volatile int8_t *s8ptr; - volatile uint8_t *u8ptr; -} StructVPtr; - -/** Structure of pointers to constant 64-, 32-, 16- and 8-bit unsigned integers. */ -typedef struct -{ - const int64_t *s64ptr; - const uint64_t *u64ptr; - const int32_t *s32ptr; - const uint32_t *u32ptr; - const int16_t *s16ptr; - const uint16_t *u16ptr; - const int8_t *s8ptr; - const uint8_t *u8ptr; -} StructCPtr; - -/** Structure of pointers to constant volatile 64-, 32-, 16- and 8-bit unsigned integers. */ -typedef struct -{ - const volatile int64_t *s64ptr; - const volatile uint64_t *u64ptr; - const volatile int32_t *s32ptr; - const volatile uint32_t *u32ptr; - const volatile int16_t *s16ptr; - const volatile uint16_t *u16ptr; - const volatile int8_t *s8ptr; - const volatile uint8_t *u8ptr; -} StructCVPtr; - -/** @} */ - -#endif /* #ifndef __ASSEMBLY__ */ - -/** \name Usual Constants - * @{ */ -#define DISABLE 0 -//#define ENABLE 1 - -#ifndef __cplusplus -# if !defined(__bool_true_false_are_defined) -# define false 0 -# define true 1 -# endif -#endif -/** @} */ - -#ifndef __ASSEMBLY__ - -/** \name Optimization Control - * @{ */ - -/** - * \def likely(exp) - * \brief The expression \a exp is likely to be true - */ -#if !defined(likely) || defined(__DOXYGEN__) -# define likely(exp) (exp) -#endif - -/** - * \def unlikely(exp) - * \brief The expression \a exp is unlikely to be true - */ -#if !defined(unlikely) || defined(__DOXYGEN__) -# define unlikely(exp) (exp) -#endif - -/** - * \def is_constant(exp) - * \brief Determine if an expression evaluates to a constant value. - * - * \param[in] exp Any expression - * - * \return true if \a exp is constant, false otherwise. - */ -#if (defined __GNUC__) || (defined __CC_ARM) -# define is_constant(exp) __builtin_constant_p(exp) -#else -# define is_constant(exp) (0) -#endif - -/** @} */ - -/** \name Bit-Field Handling - * @{ */ - -/** \brief Reads the bits of a value specified by a given bit-mask. - * - * \param[in] value Value to read bits from. - * \param[in] mask Bit-mask indicating bits to read. - * - * \return Read bits. - */ -#define Rd_bits( value, mask) ((value) & (mask)) - -/** \brief Writes the bits of a C lvalue specified by a given bit-mask. - * - * \param[in] lvalue C lvalue to write bits to. - * \param[in] mask Bit-mask indicating bits to write. - * \param[in] bits Bits to write. - * - * \return Resulting value with written bits. - */ -#define Wr_bits(lvalue, mask, bits) ((lvalue) = ((lvalue) & ~(mask)) |\ - ((bits ) & (mask))) - -/** \brief Tests the bits of a value specified by a given bit-mask. - * - * \param[in] value Value of which to test bits. - * \param[in] mask Bit-mask indicating bits to test. - * - * \return \c 1 if at least one of the tested bits is set, else \c 0. - */ -#define Tst_bits( value, mask) (Rd_bits(value, mask) != 0) - -/** \brief Clears the bits of a C lvalue specified by a given bit-mask. - * - * \param[in] lvalue C lvalue of which to clear bits. - * \param[in] mask Bit-mask indicating bits to clear. - * - * \return Resulting value with cleared bits. - */ -#define Clr_bits(lvalue, mask) ((lvalue) &= ~(mask)) - -/** \brief Sets the bits of a C lvalue specified by a given bit-mask. - * - * \param[in] lvalue C lvalue of which to set bits. - * \param[in] mask Bit-mask indicating bits to set. - * - * \return Resulting value with set bits. - */ -#define Set_bits(lvalue, mask) ((lvalue) |= (mask)) - -/** \brief Toggles the bits of a C lvalue specified by a given bit-mask. - * - * \param[in] lvalue C lvalue of which to toggle bits. - * \param[in] mask Bit-mask indicating bits to toggle. - * - * \return Resulting value with toggled bits. - */ -#define Tgl_bits(lvalue, mask) ((lvalue) ^= (mask)) - -/** \brief Reads the bit-field of a value specified by a given bit-mask. - * - * \param[in] value Value to read a bit-field from. - * \param[in] mask Bit-mask indicating the bit-field to read. - * - * \return Read bit-field. - */ -#define Rd_bitfield( value, mask) (Rd_bits( value, mask) >> ctz(mask)) - -/** \brief Writes the bit-field of a C lvalue specified by a given bit-mask. - * - * \param[in] lvalue C lvalue to write a bit-field to. - * \param[in] mask Bit-mask indicating the bit-field to write. - * \param[in] bitfield Bit-field to write. - * - * \return Resulting value with written bit-field. - */ -#define Wr_bitfield(lvalue, mask, bitfield) (Wr_bits(lvalue, mask, (uint32_t)(bitfield) << ctz(mask))) - -/** @} */ - - -/** \name Zero-Bit Counting - * - * Under GCC, __builtin_clz and __builtin_ctz behave like macros when - * applied to constant expressions (values known at compile time), so they are - * more optimized than the use of the corresponding assembly instructions and - * they can be used as constant expressions e.g. to initialize objects having - * static storage duration, and like the corresponding assembly instructions - * when applied to non-constant expressions (values unknown at compile time), so - * they are more optimized than an assembly periphrasis. Hence, clz and ctz - * ensure a possible and optimized behavior for both constant and non-constant - * expressions. - * - * @{ */ - -/** \brief Counts the leading zero bits of the given value considered as a 32-bit integer. - * - * \param[in] u Value of which to count the leading zero bits. - * - * \return The count of leading zero bits in \a u. - */ -#if (defined __GNUC__) || (defined __CC_ARM) -# define clz(u) __builtin_clz(u) -#else -# define clz(u) (((u) == 0) ? 32 : \ - ((u) & (1ul << 31)) ? 0 : \ - ((u) & (1ul << 30)) ? 1 : \ - ((u) & (1ul << 29)) ? 2 : \ - ((u) & (1ul << 28)) ? 3 : \ - ((u) & (1ul << 27)) ? 4 : \ - ((u) & (1ul << 26)) ? 5 : \ - ((u) & (1ul << 25)) ? 6 : \ - ((u) & (1ul << 24)) ? 7 : \ - ((u) & (1ul << 23)) ? 8 : \ - ((u) & (1ul << 22)) ? 9 : \ - ((u) & (1ul << 21)) ? 10 : \ - ((u) & (1ul << 20)) ? 11 : \ - ((u) & (1ul << 19)) ? 12 : \ - ((u) & (1ul << 18)) ? 13 : \ - ((u) & (1ul << 17)) ? 14 : \ - ((u) & (1ul << 16)) ? 15 : \ - ((u) & (1ul << 15)) ? 16 : \ - ((u) & (1ul << 14)) ? 17 : \ - ((u) & (1ul << 13)) ? 18 : \ - ((u) & (1ul << 12)) ? 19 : \ - ((u) & (1ul << 11)) ? 20 : \ - ((u) & (1ul << 10)) ? 21 : \ - ((u) & (1ul << 9)) ? 22 : \ - ((u) & (1ul << 8)) ? 23 : \ - ((u) & (1ul << 7)) ? 24 : \ - ((u) & (1ul << 6)) ? 25 : \ - ((u) & (1ul << 5)) ? 26 : \ - ((u) & (1ul << 4)) ? 27 : \ - ((u) & (1ul << 3)) ? 28 : \ - ((u) & (1ul << 2)) ? 29 : \ - ((u) & (1ul << 1)) ? 30 : \ - 31) -#endif - -/** \brief Counts the trailing zero bits of the given value considered as a 32-bit integer. - * - * \param[in] u Value of which to count the trailing zero bits. - * - * \return The count of trailing zero bits in \a u. - */ -#if (defined __GNUC__) || (defined __CC_ARM) -# define ctz(u) __builtin_ctz(u) -#else -# define ctz(u) ((u) & (1ul << 0) ? 0 : \ - (u) & (1ul << 1) ? 1 : \ - (u) & (1ul << 2) ? 2 : \ - (u) & (1ul << 3) ? 3 : \ - (u) & (1ul << 4) ? 4 : \ - (u) & (1ul << 5) ? 5 : \ - (u) & (1ul << 6) ? 6 : \ - (u) & (1ul << 7) ? 7 : \ - (u) & (1ul << 8) ? 8 : \ - (u) & (1ul << 9) ? 9 : \ - (u) & (1ul << 10) ? 10 : \ - (u) & (1ul << 11) ? 11 : \ - (u) & (1ul << 12) ? 12 : \ - (u) & (1ul << 13) ? 13 : \ - (u) & (1ul << 14) ? 14 : \ - (u) & (1ul << 15) ? 15 : \ - (u) & (1ul << 16) ? 16 : \ - (u) & (1ul << 17) ? 17 : \ - (u) & (1ul << 18) ? 18 : \ - (u) & (1ul << 19) ? 19 : \ - (u) & (1ul << 20) ? 20 : \ - (u) & (1ul << 21) ? 21 : \ - (u) & (1ul << 22) ? 22 : \ - (u) & (1ul << 23) ? 23 : \ - (u) & (1ul << 24) ? 24 : \ - (u) & (1ul << 25) ? 25 : \ - (u) & (1ul << 26) ? 26 : \ - (u) & (1ul << 27) ? 27 : \ - (u) & (1ul << 28) ? 28 : \ - (u) & (1ul << 29) ? 29 : \ - (u) & (1ul << 30) ? 30 : \ - (u) & (1ul << 31) ? 31 : \ - 32) -#endif - -/** @} */ - - -/** \name Bit Reversing - * @{ */ - -/** \brief Reverses the bits of \a u8. - * - * \param[in] u8 U8 of which to reverse the bits. - * - * \return Value resulting from \a u8 with reversed bits. - */ -#define bit_reverse8(u8) ((U8)(bit_reverse32((U8)(u8)) >> 24)) - -/** \brief Reverses the bits of \a u16. - * - * \param[in] u16 U16 of which to reverse the bits. - * - * \return Value resulting from \a u16 with reversed bits. - */ -#define bit_reverse16(u16) ((uint16_t)(bit_reverse32((uint16_t)(u16)) >> 16)) - -/** \brief Reverses the bits of \a u32. - * - * \param[in] u32 U32 of which to reverse the bits. - * - * \return Value resulting from \a u32 with reversed bits. - */ -#define bit_reverse32(u32) __RBIT(u32) - -/** \brief Reverses the bits of \a u64. - * - * \param[in] u64 U64 of which to reverse the bits. - * - * \return Value resulting from \a u64 with reversed bits. - */ -#define bit_reverse64(u64) ((uint64_t)(((uint64_t)bit_reverse32((uint64_t)(u64) >> 32)) |\ - ((uint64_t)bit_reverse32((uint64_t)(u64)) << 32))) - -/** @} */ - - -/** \name Alignment - * @{ */ - -/** \brief Tests alignment of the number \a val with the \a n boundary. - * - * \param[in] val Input value. - * \param[in] n Boundary. - * - * \return \c 1 if the number \a val is aligned with the \a n boundary, else \c 0. - */ -#define Test_align(val, n) (!Tst_bits( val, (n) - 1 ) ) - -/** \brief Gets alignment of the number \a val with respect to the \a n boundary. - * - * \param[in] val Input value. - * \param[in] n Boundary. - * - * \return Alignment of the number \a val with respect to the \a n boundary. - */ -#define Get_align(val, n) ( Rd_bits( val, (n) - 1 ) ) - -/** \brief Sets alignment of the lvalue number \a lval to \a alg with respect to the \a n boundary. - * - * \param[in] lval Input/output lvalue. - * \param[in] n Boundary. - * \param[in] alg Alignment. - * - * \return New value of \a lval resulting from its alignment set to \a alg with respect to the \a n boundary. - */ -#define Set_align(lval, n, alg) ( Wr_bits(lval, (n) - 1, alg) ) - -/** \brief Aligns the number \a val with the upper \a n boundary. - * - * \param[in] val Input value. - * \param[in] n Boundary. - * - * \return Value resulting from the number \a val aligned with the upper \a n boundary. - */ -#define Align_up( val, n) (((val) + ((n) - 1)) & ~((n) - 1)) - -/** \brief Aligns the number \a val with the lower \a n boundary. - * - * \param[in] val Input value. - * \param[in] n Boundary. - * - * \return Value resulting from the number \a val aligned with the lower \a n boundary. - */ -#define Align_down(val, n) ( (val) & ~((n) - 1)) - -/** @} */ - - -/** \name Mathematics - * - * The same considerations as for clz and ctz apply here but GCC does not - * provide built-in functions to access the assembly instructions abs, min and - * max and it does not produce them by itself in most cases, so two sets of - * macros are defined here: - * - Abs, Min and Max to apply to constant expressions (values known at - * compile time); - * - abs, min and max to apply to non-constant expressions (values unknown at - * compile time), abs is found in stdlib.h. - * - * @{ */ - -/** \brief Takes the absolute value of \a a. - * - * \param[in] a Input value. - * - * \return Absolute value of \a a. - * - * \note More optimized if only used with values known at compile time. - */ -#define Abs(a) (((a) < 0 ) ? -(a) : (a)) - -/** \brief Takes the minimal value of \a a and \a b. - * - * \param[in] a Input value. - * \param[in] b Input value. - * - * \return Minimal value of \a a and \a b. - * - * \note More optimized if only used with values known at compile time. - */ -#define Min(a, b) (((a) < (b)) ? (a) : (b)) - -/** \brief Takes the maximal value of \a a and \a b. - * - * \param[in] a Input value. - * \param[in] b Input value. - * - * \return Maximal value of \a a and \a b. - * - * \note More optimized if only used with values known at compile time. - */ -#define Max(a, b) (((a) > (b)) ? (a) : (b)) - -/** \brief Takes the minimal value of \a a and \a b. - * - * \param[in] a Input value. - * \param[in] b Input value. - * - * \return Minimal value of \a a and \a b. - * - * \note More optimized if only used with values unknown at compile time. - */ -#define min(a, b) Min(a, b) - -/** \brief Takes the maximal value of \a a and \a b. - * - * \param[in] a Input value. - * \param[in] b Input value. - * - * \return Maximal value of \a a and \a b. - * - * \note More optimized if only used with values unknown at compile time. - */ -#define max(a, b) Max(a, b) - -/** @} */ - - -/** \brief Calls the routine at address \a addr. - * - * It generates a long call opcode. - * - * For example, `Long_call(0x80000000)' generates a software reset on a UC3 if - * it is invoked from the CPU supervisor mode. - * - * \param[in] addr Address of the routine to call. - * - * \note It may be used as a long jump opcode in some special cases. - */ -#define Long_call(addr) ((*(void (*)(void))(addr))()) - - -/** \name MCU Endianism Handling - * ARM is MCU little endian. - * - * @{ */ -#define BE16(x) Swap16(x) -#define LE16(x) (x) - -#define le16_to_cpu(x) (x) -#define cpu_to_le16(x) (x) -#define LE16_TO_CPU(x) (x) -#define CPU_TO_LE16(x) (x) - -#define be16_to_cpu(x) Swap16(x) -#define cpu_to_be16(x) Swap16(x) -#define BE16_TO_CPU(x) Swap16(x) -#define CPU_TO_BE16(x) Swap16(x) - -#define le32_to_cpu(x) (x) -#define cpu_to_le32(x) (x) -#define LE32_TO_CPU(x) (x) -#define CPU_TO_LE32(x) (x) - -#define be32_to_cpu(x) swap32(x) -#define cpu_to_be32(x) swap32(x) -#define BE32_TO_CPU(x) swap32(x) -#define CPU_TO_BE32(x) swap32(x) -/** @} */ - - -/** \name Endianism Conversion - * - * The same considerations as for clz and ctz apply here but GCC's - * __builtin_bswap_32 and __builtin_bswap_64 do not behave like macros when - * applied to constant expressions, so two sets of macros are defined here: - * - Swap16, Swap32 and Swap64 to apply to constant expressions (values known - * at compile time); - * - swap16, swap32 and swap64 to apply to non-constant expressions (values - * unknown at compile time). - * - * @{ */ - -/** \brief Toggles the endianism of \a u16 (by swapping its bytes). - * - * \param[in] u16 U16 of which to toggle the endianism. - * - * \return Value resulting from \a u16 with toggled endianism. - * - * \note More optimized if only used with values known at compile time. - */ -#define Swap16(u16) ((uint16_t)(((uint16_t)(u16) >> 8) |\ - ((uint16_t)(u16) << 8))) - -/** \brief Toggles the endianism of \a u32 (by swapping its bytes). - * - * \param[in] u32 U32 of which to toggle the endianism. - * - * \return Value resulting from \a u32 with toggled endianism. - * - * \note More optimized if only used with values known at compile time. - */ -#define Swap32(u32) ((uint32_t)(((uint32_t)Swap16((uint32_t)(u32) >> 16)) |\ - ((uint32_t)Swap16((uint32_t)(u32)) << 16))) - -/** \brief Toggles the endianism of \a u64 (by swapping its bytes). - * - * \param[in] u64 U64 of which to toggle the endianism. - * - * \return Value resulting from \a u64 with toggled endianism. - * - * \note More optimized if only used with values known at compile time. - */ -#define Swap64(u64) ((uint64_t)(((uint64_t)Swap32((uint64_t)(u64) >> 32)) |\ - ((uint64_t)Swap32((uint64_t)(u64)) << 32))) - -/** \brief Toggles the endianism of \a u16 (by swapping its bytes). - * - * \param[in] u16 U16 of which to toggle the endianism. - * - * \return Value resulting from \a u16 with toggled endianism. - * - * \note More optimized if only used with values unknown at compile time. - */ -#define swap16(u16) Swap16(u16) - -/** \brief Toggles the endianism of \a u32 (by swapping its bytes). - * - * \param[in] u32 U32 of which to toggle the endianism. - * - * \return Value resulting from \a u32 with toggled endianism. - * - * \note More optimized if only used with values unknown at compile time. - */ -#if (defined __GNUC__) -# define swap32(u32) ((uint32_t)__builtin_bswap32((uint32_t)(u32))) -#else -# define swap32(u32) Swap32(u32) -#endif - -/** \brief Toggles the endianism of \a u64 (by swapping its bytes). - * - * \param[in] u64 U64 of which to toggle the endianism. - * - * \return Value resulting from \a u64 with toggled endianism. - * - * \note More optimized if only used with values unknown at compile time. - */ -#if (defined __GNUC__) -# define swap64(u64) ((uint64_t)__builtin_bswap64((uint64_t)(u64))) -#else -# define swap64(u64) ((uint64_t)(((uint64_t)swap32((uint64_t)(u64) >> 32)) |\ - ((uint64_t)swap32((uint64_t)(u64)) << 32))) -#endif - -/** @} */ - - -/** \name Target Abstraction - * - * @{ */ - -#define _GLOBEXT_ extern /**< extern storage-class specifier. */ -#define _CONST_TYPE_ const /**< const type qualifier. */ -#define _MEM_TYPE_SLOW_ /**< Slow memory type. */ -#define _MEM_TYPE_MEDFAST_ /**< Fairly fast memory type. */ -#define _MEM_TYPE_FAST_ /**< Fast memory type. */ - -#define memcmp_ram2ram memcmp /**< Target-specific memcmp of RAM to RAM. */ -#define memcmp_code2ram memcmp /**< Target-specific memcmp of RAM to NVRAM. */ -#define memcpy_ram2ram memcpy /**< Target-specific memcpy from RAM to RAM. */ -#define memcpy_code2ram memcpy /**< Target-specific memcpy from NVRAM to RAM. */ - -/** @} */ - -/** - * \brief Calculate \f$ \left\lceil \frac{a}{b} \right\rceil \f$ using - * integer arithmetic. - * - * \param[in] a An integer - * \param[in] b Another integer - * - * \return (\a a / \a b) rounded up to the nearest integer. - */ -#define div_ceil(a, b) (((a) + (b) - 1) / (b)) - -#endif /* #ifndef __ASSEMBLY__ */ -#ifdef __ICCARM__ -/** \name Compiler Keywords - * - * Port of some keywords from GCC to IAR Embedded Workbench. - * - * @{ */ - -#define __asm__ asm -#define __inline__ inline -#define __volatile__ - -/** @} */ - -#endif - -#define FUNC_PTR void * -/** - * \def unused - * \brief Marking \a v as a unused parameter or value. - */ -#define unused(v) do { (void)(v); } while(0) - -/* Define RAMFUNC attribute */ -#if defined ( __CC_ARM ) /* Keil uVision 4 */ -# define RAMFUNC __attribute__ ((section(".ramfunc"))) -#elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ -# define RAMFUNC __ramfunc -#elif defined ( __GNUC__ ) /* GCC CS3 2009q3-68 */ -# define RAMFUNC __attribute__ ((section(".ramfunc"))) -#endif - -/* Define OPTIMIZE_HIGH attribute */ -#if defined ( __CC_ARM ) /* Keil uVision 4 */ -# define OPTIMIZE_HIGH _Pragma("O3") -#elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ -# define OPTIMIZE_HIGH _Pragma("optimize=high") -#elif defined ( __GNUC__ ) /* GCC CS3 2009q3-68 */ -# define OPTIMIZE_HIGH __attribute__((optimize(s))) -#endif -#define PASS 0 -#define FAIL 1 -#define LOW 0 -#define HIGH 1 - -typedef int8_t S8 ; //!< 8-bit signed integer. -typedef uint8_t U8 ; //!< 8-bit unsigned integer. -typedef int16_t S16; //!< 16-bit signed integer. -typedef uint16_t U16; //!< 16-bit unsigned integer. -typedef int32_t S32; //!< 32-bit signed integer. -typedef uint32_t U32; //!< 32-bit unsigned integer. -typedef int64_t S64; //!< 64-bit signed integer. -typedef uint64_t U64; //!< 64-bit unsigned integer. -typedef float F32; //!< 32-bit floating-point number. -typedef double F64; //!< 64-bit floating-point number. - -#define MSB(u16) (((U8 *)&(u16))[1]) //!< Most significant byte of \a u16. -#define LSB(u16) (((U8 *)&(u16))[0]) //!< Least significant byte of \a u16. - -#define MSH(u32) (((U16 *)&(u32))[1]) //!< Most significant half-word of \a u32. -#define LSH(u32) (((U16 *)&(u32))[0]) //!< Least significant half-word of \a u32. -#define MSB0W(u32) (((U8 *)&(u32))[3]) //!< Most significant byte of 1st rank of \a u32. -#define MSB1W(u32) (((U8 *)&(u32))[2]) //!< Most significant byte of 2nd rank of \a u32. -#define MSB2W(u32) (((U8 *)&(u32))[1]) //!< Most significant byte of 3rd rank of \a u32. -#define MSB3W(u32) (((U8 *)&(u32))[0]) //!< Most significant byte of 4th rank of \a u32. -#define LSB3W(u32) MSB0W(u32) //!< Least significant byte of 4th rank of \a u32. -#define LSB2W(u32) MSB1W(u32) //!< Least significant byte of 3rd rank of \a u32. -#define LSB1W(u32) MSB2W(u32) //!< Least significant byte of 2nd rank of \a u32. -#define LSB0W(u32) MSB3W(u32) //!< Least significant byte of 1st rank of \a u32. - -#define MSW(u64) (((U32 *)&(u64))[1]) //!< Most significant word of \a u64. -#define LSW(u64) (((U32 *)&(u64))[0]) //!< Least significant word of \a u64. -#define MSH0(u64) (((U16 *)&(u64))[3]) //!< Most significant half-word of 1st rank of \a u64. -#define MSH1(u64) (((U16 *)&(u64))[2]) //!< Most significant half-word of 2nd rank of \a u64. -#define MSH2(u64) (((U16 *)&(u64))[1]) //!< Most significant half-word of 3rd rank of \a u64. -#define MSH3(u64) (((U16 *)&(u64))[0]) //!< Most significant half-word of 4th rank of \a u64. -#define LSH3(u64) MSH0(u64) //!< Least significant half-word of 4th rank of \a u64. -#define LSH2(u64) MSH1(u64) //!< Least significant half-word of 3rd rank of \a u64. -#define LSH1(u64) MSH2(u64) //!< Least significant half-word of 2nd rank of \a u64. -#define LSH0(u64) MSH3(u64) //!< Least significant half-word of 1st rank of \a u64. -#define MSB0D(u64) (((U8 *)&(u64))[7]) //!< Most significant byte of 1st rank of \a u64. -#define MSB1D(u64) (((U8 *)&(u64))[6]) //!< Most significant byte of 2nd rank of \a u64. -#define MSB2D(u64) (((U8 *)&(u64))[5]) //!< Most significant byte of 3rd rank of \a u64. -#define MSB3D(u64) (((U8 *)&(u64))[4]) //!< Most significant byte of 4th rank of \a u64. -#define MSB4D(u64) (((U8 *)&(u64))[3]) //!< Most significant byte of 5th rank of \a u64. -#define MSB5D(u64) (((U8 *)&(u64))[2]) //!< Most significant byte of 6th rank of \a u64. -#define MSB6D(u64) (((U8 *)&(u64))[1]) //!< Most significant byte of 7th rank of \a u64. -#define MSB7D(u64) (((U8 *)&(u64))[0]) //!< Most significant byte of 8th rank of \a u64. -#define LSB7D(u64) MSB0D(u64) //!< Least significant byte of 8th rank of \a u64. -#define LSB6D(u64) MSB1D(u64) //!< Least significant byte of 7th rank of \a u64. -#define LSB5D(u64) MSB2D(u64) //!< Least significant byte of 6th rank of \a u64. -#define LSB4D(u64) MSB3D(u64) //!< Least significant byte of 5th rank of \a u64. -#define LSB3D(u64) MSB4D(u64) //!< Least significant byte of 4th rank of \a u64. -#define LSB2D(u64) MSB5D(u64) //!< Least significant byte of 3rd rank of \a u64. -#define LSB1D(u64) MSB6D(u64) //!< Least significant byte of 2nd rank of \a u64. -#define LSB0D(u64) MSB7D(u64) //!< Least significant byte of 1st rank of \a u64. - -#define LSB0(u32) LSB0W(u32) //!< Least significant byte of 1st rank of \a u32. -#define LSB1(u32) LSB1W(u32) //!< Least significant byte of 2nd rank of \a u32. -#define LSB2(u32) LSB2W(u32) //!< Least significant byte of 3rd rank of \a u32. -#define LSB3(u32) LSB3W(u32) //!< Least significant byte of 4th rank of \a u32. -#define MSB3(u32) MSB3W(u32) //!< Most significant byte of 4th rank of \a u32. -#define MSB2(u32) MSB2W(u32) //!< Most significant byte of 3rd rank of \a u32. -#define MSB1(u32) MSB1W(u32) //!< Most significant byte of 2nd rank of \a u32. -#define MSB0(u32) MSB0W(u32) //!< Most significant byte of 1st rank of \a u32. - -#if defined(__ICCARM__) -#define SHORTENUM __packed -#elif defined(__GNUC__) -#define SHORTENUM __attribute__((packed)) -#endif - -/* No operation */ -#if defined(__ICCARM__) -#define nop() __no_operation() -#elif defined(__GNUC__) -#define nop() (__NOP()) -#endif - -#define FLASH_DECLARE(x) const x -#define FLASH_EXTERN(x) extern const x -#define PGM_READ_BYTE(x) *(x) -#define PGM_READ_WORD(x) *(x) -#define MEMCPY_ENDIAN memcpy -#define PGM_READ_BLOCK(dst, src, len) memcpy((dst), (src), (len)) - -/*Defines the Flash Storage for the request and response of MAC*/ -#define CMD_ID_OCTET (0) - -/* Converting of values from CPU endian to little endian. */ -#define CPU_ENDIAN_TO_LE16(x) (x) -#define CPU_ENDIAN_TO_LE32(x) (x) -#define CPU_ENDIAN_TO_LE64(x) (x) - -/* Converting of values from little endian to CPU endian. */ -#define LE16_TO_CPU_ENDIAN(x) (x) -#define LE32_TO_CPU_ENDIAN(x) (x) -#define LE64_TO_CPU_ENDIAN(x) (x) - -/* Converting of constants from little endian to CPU endian. */ -#define CLE16_TO_CPU_ENDIAN(x) (x) -#define CLE32_TO_CPU_ENDIAN(x) (x) -#define CLE64_TO_CPU_ENDIAN(x) (x) - -/* Converting of constants from CPU endian to little endian. */ -#define CCPU_ENDIAN_TO_LE16(x) (x) -#define CCPU_ENDIAN_TO_LE32(x) (x) -#define CCPU_ENDIAN_TO_LE64(x) (x) - -#define ADDR_COPY_DST_SRC_16(dst, src) ((dst) = (src)) -#define ADDR_COPY_DST_SRC_64(dst, src) ((dst) = (src)) - -/** - * @brief Converts a 64-Bit value into a 8 Byte array - * - * @param[in] value 64-Bit value - * @param[out] data Pointer to the 8 Byte array to be updated with 64-Bit value - * @ingroup apiPalApi - */ -static inline void convert_64_bit_to_byte_array(uint64_t value, uint8_t *data) -{ - uint8_t index = 0; - - while (index < 8) - { - data[index++] = value & 0xFF; - value = value >> 8; - } -} - -/** - * @brief Converts a 16-Bit value into a 2 Byte array - * - * @param[in] value 16-Bit value - * @param[out] data Pointer to the 2 Byte array to be updated with 16-Bit value - * @ingroup apiPalApi - */ -static inline void convert_16_bit_to_byte_array(uint16_t value, uint8_t *data) -{ - data[0] = value & 0xFF; - data[1] = (value >> 8) & 0xFF; -} - -/* Converts a 16-Bit value into a 2 Byte array */ -static inline void convert_spec_16_bit_to_byte_array(uint16_t value, uint8_t *data) -{ - data[0] = value & 0xFF; - data[1] = (value >> 8) & 0xFF; -} - -/* Converts a 16-Bit value into a 2 Byte array */ -static inline void convert_16_bit_to_byte_address(uint16_t value, uint8_t *data) -{ - data[0] = value & 0xFF; - data[1] = (value >> 8) & 0xFF; -} - -/* - * @brief Converts a 2 Byte array into a 16-Bit value - * - * @param data Specifies the pointer to the 2 Byte array - * - * @return 16-Bit value - * @ingroup apiPalApi - */ -static inline uint16_t convert_byte_array_to_16_bit(uint8_t *data) -{ - return (data[0] | ((uint16_t)data[1] << 8)); -} - -/* Converts a 4 Byte array into a 32-Bit value */ -static inline uint32_t convert_byte_array_to_32_bit(uint8_t *data) -{ - union - { - uint32_t u32; - uint8_t u8[4]; - }long_addr; - uint8_t index; - for (index = 0; index < 4; index++) - { - long_addr.u8[index] = *data++; - } - return long_addr.u32; -} - -/** - * @brief Converts a 8 Byte array into a 64-Bit value - * - * @param data Specifies the pointer to the 8 Byte array - * - * @return 64-Bit value - * @ingroup apiPalApi - */ -static inline uint64_t convert_byte_array_to_64_bit(uint8_t *data) -{ - union - { - uint64_t u64; - uint8_t u8[8]; - } long_addr; - - uint8_t index; - - for (index = 0; index < 8; index++) - { - long_addr.u8[index] = *data++; - } - - return long_addr.u64; -} - -/** @} */ - -#endif /* UTILS_COMPILER_H_INCLUDED */ diff --git a/bootloaders/feather/utils/interrupt.h b/bootloaders/feather/utils/interrupt.h deleted file mode 100644 index fa4878ee8..000000000 --- a/bootloaders/feather/utils/interrupt.h +++ /dev/null @@ -1,117 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ -#ifndef UTILS_INTERRUPT_H -#define UTILS_INTERRUPT_H - -//#include - -#include "interrupt/interrupt_sam_nvic.h" - -/** - * \defgroup interrupt_group Global interrupt management - * - * This is a driver for global enabling and disabling of interrupts. - * - * @{ - */ - -#if defined(__DOXYGEN__) -/** - * \def CONFIG_INTERRUPT_FORCE_INTC - * \brief Force usage of the ASF INTC driver - * - * Predefine this symbol when preprocessing to force the use of the ASF INTC driver. - * This is useful to ensure compatibility across compilers and shall be used only when required - * by the application needs. - */ -# define CONFIG_INTERRUPT_FORCE_INTC -#endif - -//! \name Global interrupt flags -//@{ -/** - * \typedef irqflags_t - * \brief Type used for holding state of interrupt flag - */ - -/** - * \def cpu_irq_enable - * \brief Enable interrupts globally - */ - -/** - * \def cpu_irq_disable - * \brief Disable interrupts globally - */ - -/** - * \fn irqflags_t cpu_irq_save(void) - * \brief Get and clear the global interrupt flags - * - * Use in conjunction with \ref cpu_irq_restore. - * - * \return Current state of interrupt flags. - * - * \note This function leaves interrupts disabled. - */ - -/** - * \fn void cpu_irq_restore(irqflags_t flags) - * \brief Restore global interrupt flags - * - * Use in conjunction with \ref cpu_irq_save. - * - * \param flags State to set interrupt flag to. - */ - -/** - * \fn bool cpu_irq_is_enabled_flags(irqflags_t flags) - * \brief Check if interrupts are globally enabled in supplied flags - * - * \param flags Currents state of interrupt flags. - * - * \return True if interrupts are enabled. - */ - -/** - * \def cpu_irq_is_enabled - * \brief Check if interrupts are globally enabled - * - * \return True if interrupts are enabled. - */ -//@} - -//! @} - -/** - * \ingroup interrupt_group - * \defgroup interrupt_deprecated_group Deprecated interrupt definitions - */ - -#endif /* UTILS_INTERRUPT_H */ diff --git a/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.c b/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.c deleted file mode 100644 index d8134852e..000000000 --- a/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.c +++ /dev/null @@ -1,69 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#include "interrupt_sam_nvic.h" - -#if !defined(__DOXYGEN__) -/* Deprecated - global flag to determine the global interrupt state. Required by - * QTouch library, however new applications should use cpu_irq_is_enabled() - * which probes the true global interrupt state from the CPU special registers. - */ -volatile bool g_interrupt_enabled = true; -#endif - -void cpu_irq_enter_critical(void) -{ - if (cpu_irq_critical_section_counter == 0) { - if (cpu_irq_is_enabled()) { - cpu_irq_disable(); - cpu_irq_prev_interrupt_state = true; - } else { - /* Make sure the to save the prev state as false */ - cpu_irq_prev_interrupt_state = false; - } - - } - - cpu_irq_critical_section_counter++; -} - -void cpu_irq_leave_critical(void) -{ - /* Check if the user is trying to leave a critical section when not in a critical section */ - Assert(cpu_irq_critical_section_counter > 0); - - cpu_irq_critical_section_counter--; - - /* Only enable global interrupts when the counter reaches 0 and the state of the global interrupt flag - was enabled when entering critical state */ - if ((cpu_irq_critical_section_counter == 0) && (cpu_irq_prev_interrupt_state)) { - cpu_irq_enable(); - } -} - diff --git a/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.h b/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.h deleted file mode 100644 index 9b5645b63..000000000 --- a/bootloaders/feather/utils/interrupt/interrupt_sam_nvic.h +++ /dev/null @@ -1,172 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#ifndef UTILS_INTERRUPT_INTERRUPT_H -#define UTILS_INTERRUPT_INTERRUPT_H - -#include -//#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \weakgroup interrupt_group - * - * @{ - */ - -/** - * \name Interrupt Service Routine definition - * - * @{ - */ - -/** - * \brief Define service routine - * - * \note For NVIC devices the interrupt service routines are predefined to - * add to vector table in binary generation, so there is no service - * register at run time. The routine collections are in exceptions.h. - * - * Usage: - * \code - ISR(foo_irq_handler) - { - // Function definition - ... - } -\endcode - * - * \param func Name for the function. - */ -# define ISR(func) \ - void func (void) - -/** - * \brief Initialize interrupt vectors - * - * For NVIC the interrupt vectors are put in vector table. So nothing - * to do to initialize them, except defined the vector function with - * right name. - * - * This must be called prior to \ref irq_register_handler. - */ -# define irq_initialize_vectors() \ - do { \ - } while(0) - -/** - * \brief Register handler for interrupt - * - * For NVIC the interrupt vectors are put in vector table. So nothing - * to do to register them, except defined the vector function with - * right name. - * - * Usage: - * \code - irq_initialize_vectors(); - irq_register_handler(foo_irq_handler); -\endcode - * - * \note The function \a func must be defined with the \ref ISR macro. - * \note The functions prototypes can be found in the device exception header - * files (exceptions.h). - */ -# define irq_register_handler(int_num, int_prio) \ - NVIC_ClearPendingIRQ( (IRQn_Type)int_num); \ - NVIC_SetPriority( (IRQn_Type)int_num, int_prio); \ - NVIC_EnableIRQ( (IRQn_Type)int_num); \ - -//@} - -# define cpu_irq_enable() \ - do { \ - g_interrupt_enabled = true; \ - __DMB(); \ - __enable_irq(); \ - } while (0) -# define cpu_irq_disable() \ - do { \ - __disable_irq(); \ - __DMB(); \ - g_interrupt_enabled = false; \ - } while (0) - -typedef uint32_t irqflags_t; - -#if !defined(__DOXYGEN__) -extern volatile bool g_interrupt_enabled; -#endif - -#define cpu_irq_is_enabled() (__get_PRIMASK() == 0) - -static volatile uint32_t cpu_irq_critical_section_counter; -static volatile bool cpu_irq_prev_interrupt_state; - -static inline irqflags_t cpu_irq_save(void) -{ - irqflags_t flags = cpu_irq_is_enabled(); - cpu_irq_disable(); - return flags; -} - -static inline bool cpu_irq_is_enabled_flags(irqflags_t flags) -{ - return (flags); -} - -static inline void cpu_irq_restore(irqflags_t flags) -{ - if (cpu_irq_is_enabled_flags(flags)) - cpu_irq_enable(); -} - -void cpu_irq_enter_critical(void); -void cpu_irq_leave_critical(void); - -/** - * \weakgroup interrupt_deprecated_group - * @{ - */ - -#define Enable_global_interrupt() cpu_irq_enable() -#define Disable_global_interrupt() cpu_irq_disable() -#define Is_global_interrupt_enabled() cpu_irq_is_enabled() - -//@} - -//@} - -#ifdef __cplusplus -} -#endif - -#endif /* UTILS_INTERRUPT_INTERRUPT_H */ diff --git a/bootloaders/feather/utils/preprocessor/mrecursion.h b/bootloaders/feather/utils/preprocessor/mrecursion.h deleted file mode 100644 index 444792727..000000000 --- a/bootloaders/feather/utils/preprocessor/mrecursion.h +++ /dev/null @@ -1,581 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#ifndef _MRECURSION_H_ -#define _MRECURSION_H_ - -/** - * \defgroup group_sam0_utils_mrecursion Preprocessor - Macro Recursion - * - * \ingroup group_sam0_utils - * - * @{ - */ - -#include "preprocessor.h" - -#define DEC_256 255 -#define DEC_255 254 -#define DEC_254 253 -#define DEC_253 252 -#define DEC_252 251 -#define DEC_251 250 -#define DEC_250 249 -#define DEC_249 248 -#define DEC_248 247 -#define DEC_247 246 -#define DEC_246 245 -#define DEC_245 244 -#define DEC_244 243 -#define DEC_243 242 -#define DEC_242 241 -#define DEC_241 240 -#define DEC_240 239 -#define DEC_239 238 -#define DEC_238 237 -#define DEC_237 236 -#define DEC_236 235 -#define DEC_235 234 -#define DEC_234 233 -#define DEC_233 232 -#define DEC_232 231 -#define DEC_231 230 -#define DEC_230 229 -#define DEC_229 228 -#define DEC_228 227 -#define DEC_227 226 -#define DEC_226 225 -#define DEC_225 224 -#define DEC_224 223 -#define DEC_223 222 -#define DEC_222 221 -#define DEC_221 220 -#define DEC_220 219 -#define DEC_219 218 -#define DEC_218 217 -#define DEC_217 216 -#define DEC_216 215 -#define DEC_215 214 -#define DEC_214 213 -#define DEC_213 212 -#define DEC_212 211 -#define DEC_211 210 -#define DEC_210 209 -#define DEC_209 208 -#define DEC_208 207 -#define DEC_207 206 -#define DEC_206 205 -#define DEC_205 204 -#define DEC_204 203 -#define DEC_203 202 -#define DEC_202 201 -#define DEC_201 200 -#define DEC_200 199 -#define DEC_199 198 -#define DEC_198 197 -#define DEC_197 196 -#define DEC_196 195 -#define DEC_195 194 -#define DEC_194 193 -#define DEC_193 192 -#define DEC_192 191 -#define DEC_191 190 -#define DEC_190 189 -#define DEC_189 188 -#define DEC_188 187 -#define DEC_187 186 -#define DEC_186 185 -#define DEC_185 184 -#define DEC_184 183 -#define DEC_183 182 -#define DEC_182 181 -#define DEC_181 180 -#define DEC_180 179 -#define DEC_179 178 -#define DEC_178 177 -#define DEC_177 176 -#define DEC_176 175 -#define DEC_175 174 -#define DEC_174 173 -#define DEC_173 172 -#define DEC_172 171 -#define DEC_171 170 -#define DEC_170 169 -#define DEC_169 168 -#define DEC_168 167 -#define DEC_167 166 -#define DEC_166 165 -#define DEC_165 164 -#define DEC_164 163 -#define DEC_163 162 -#define DEC_162 161 -#define DEC_161 160 -#define DEC_160 159 -#define DEC_159 158 -#define DEC_158 157 -#define DEC_157 156 -#define DEC_156 155 -#define DEC_155 154 -#define DEC_154 153 -#define DEC_153 152 -#define DEC_152 151 -#define DEC_151 150 -#define DEC_150 149 -#define DEC_149 148 -#define DEC_148 147 -#define DEC_147 146 -#define DEC_146 145 -#define DEC_145 144 -#define DEC_144 143 -#define DEC_143 142 -#define DEC_142 141 -#define DEC_141 140 -#define DEC_140 139 -#define DEC_139 138 -#define DEC_138 137 -#define DEC_137 136 -#define DEC_136 135 -#define DEC_135 134 -#define DEC_134 133 -#define DEC_133 132 -#define DEC_132 131 -#define DEC_131 130 -#define DEC_130 129 -#define DEC_129 128 -#define DEC_128 127 -#define DEC_127 126 -#define DEC_126 125 -#define DEC_125 124 -#define DEC_124 123 -#define DEC_123 122 -#define DEC_122 121 -#define DEC_121 120 -#define DEC_120 119 -#define DEC_119 118 -#define DEC_118 117 -#define DEC_117 116 -#define DEC_116 115 -#define DEC_115 114 -#define DEC_114 113 -#define DEC_113 112 -#define DEC_112 111 -#define DEC_111 110 -#define DEC_110 109 -#define DEC_109 108 -#define DEC_108 107 -#define DEC_107 106 -#define DEC_106 105 -#define DEC_105 104 -#define DEC_104 103 -#define DEC_103 102 -#define DEC_102 101 -#define DEC_101 100 -#define DEC_100 99 -#define DEC_99 98 -#define DEC_98 97 -#define DEC_97 96 -#define DEC_96 95 -#define DEC_95 94 -#define DEC_94 93 -#define DEC_93 92 -#define DEC_92 91 -#define DEC_91 90 -#define DEC_90 89 -#define DEC_89 88 -#define DEC_88 87 -#define DEC_87 86 -#define DEC_86 85 -#define DEC_85 84 -#define DEC_84 83 -#define DEC_83 82 -#define DEC_82 81 -#define DEC_81 80 -#define DEC_80 79 -#define DEC_79 78 -#define DEC_78 77 -#define DEC_77 76 -#define DEC_76 75 -#define DEC_75 74 -#define DEC_74 73 -#define DEC_73 72 -#define DEC_72 71 -#define DEC_71 70 -#define DEC_70 69 -#define DEC_69 68 -#define DEC_68 67 -#define DEC_67 66 -#define DEC_66 65 -#define DEC_65 64 -#define DEC_64 63 -#define DEC_63 62 -#define DEC_62 61 -#define DEC_61 60 -#define DEC_60 59 -#define DEC_59 58 -#define DEC_58 57 -#define DEC_57 56 -#define DEC_56 55 -#define DEC_55 54 -#define DEC_54 53 -#define DEC_53 52 -#define DEC_52 51 -#define DEC_51 50 -#define DEC_50 49 -#define DEC_49 48 -#define DEC_48 47 -#define DEC_47 46 -#define DEC_46 45 -#define DEC_45 44 -#define DEC_44 43 -#define DEC_43 42 -#define DEC_42 41 -#define DEC_41 40 -#define DEC_40 39 -#define DEC_39 38 -#define DEC_38 37 -#define DEC_37 36 -#define DEC_36 35 -#define DEC_35 34 -#define DEC_34 33 -#define DEC_33 32 -#define DEC_32 31 -#define DEC_31 30 -#define DEC_30 29 -#define DEC_29 28 -#define DEC_28 27 -#define DEC_27 26 -#define DEC_26 25 -#define DEC_25 24 -#define DEC_24 23 -#define DEC_23 22 -#define DEC_22 21 -#define DEC_21 20 -#define DEC_20 19 -#define DEC_19 18 -#define DEC_18 17 -#define DEC_17 16 -#define DEC_16 15 -#define DEC_15 14 -#define DEC_14 13 -#define DEC_13 12 -#define DEC_12 11 -#define DEC_11 10 -#define DEC_10 9 -#define DEC_9 8 -#define DEC_8 7 -#define DEC_7 6 -#define DEC_6 5 -#define DEC_5 4 -#define DEC_4 3 -#define DEC_3 2 -#define DEC_2 1 -#define DEC_1 0 -#define DEC_(n) DEC_##n - - -/** Maximal number of repetitions supported by MRECURSION. */ -#define MRECURSION_LIMIT 256 - -/** \brief Macro recursion. - * - * This macro represents a horizontal repetition construct. - * - * \param[in] count The number of repetitious calls to macro. Valid values - * range from 0 to MRECURSION_LIMIT. - * \param[in] macro A binary operation of the form macro(data, n). This macro - * is expanded by MRECURSION with the current repetition number - * and the auxiliary data argument. - * \param[in] data A recursive threshold, building on this to decline by times - * defined with param count. - * - * \return macro(data-count+1,0) macro(data-count+2,1)...macro(data,count-1) - */ -#define MRECURSION(count, macro, data) TPASTE2(MRECURSION, count) (macro, data) - -#define MRECURSION0( macro, data) -#define MRECURSION1( macro, data) MRECURSION0( macro, DEC_(data)) macro(data, 0) -#define MRECURSION2( macro, data) MRECURSION1( macro, DEC_(data)) macro(data, 1) -#define MRECURSION3( macro, data) MRECURSION2( macro, DEC_(data)) macro(data, 2) -#define MRECURSION4( macro, data) MRECURSION3( macro, DEC_(data)) macro(data, 3) -#define MRECURSION5( macro, data) MRECURSION4( macro, DEC_(data)) macro(data, 4) -#define MRECURSION6( macro, data) MRECURSION5( macro, DEC_(data)) macro(data, 5) -#define MRECURSION7( macro, data) MRECURSION6( macro, DEC_(data)) macro(data, 6) -#define MRECURSION8( macro, data) MRECURSION7( macro, DEC_(data)) macro(data, 7) -#define MRECURSION9( macro, data) MRECURSION8( macro, DEC_(data)) macro(data, 8) -#define MRECURSION10( macro, data) MRECURSION9( macro, DEC_(data)) macro(data, 9) -#define MRECURSION11( macro, data) MRECURSION10( macro, DEC_(data)) macro(data, 10) -#define MRECURSION12( macro, data) MRECURSION11( macro, DEC_(data)) macro(data, 11) -#define MRECURSION13( macro, data) MRECURSION12( macro, DEC_(data)) macro(data, 12) -#define MRECURSION14( macro, data) MRECURSION13( macro, DEC_(data)) macro(data, 13) -#define MRECURSION15( macro, data) MRECURSION14( macro, DEC_(data)) macro(data, 14) -#define MRECURSION16( macro, data) MRECURSION15( macro, DEC_(data)) macro(data, 15) -#define MRECURSION17( macro, data) MRECURSION16( macro, DEC_(data)) macro(data, 16) -#define MRECURSION18( macro, data) MRECURSION17( macro, DEC_(data)) macro(data, 17) -#define MRECURSION19( macro, data) MRECURSION18( macro, DEC_(data)) macro(data, 18) -#define MRECURSION20( macro, data) MRECURSION19( macro, DEC_(data)) macro(data, 19) -#define MRECURSION21( macro, data) MRECURSION20( macro, DEC_(data)) macro(data, 20) -#define MRECURSION22( macro, data) MRECURSION21( macro, DEC_(data)) macro(data, 21) -#define MRECURSION23( macro, data) MRECURSION22( macro, DEC_(data)) macro(data, 22) -#define MRECURSION24( macro, data) MRECURSION23( macro, DEC_(data)) macro(data, 23) -#define MRECURSION25( macro, data) MRECURSION24( macro, DEC_(data)) macro(data, 24) -#define MRECURSION26( macro, data) MRECURSION25( macro, DEC_(data)) macro(data, 25) -#define MRECURSION27( macro, data) MRECURSION26( macro, DEC_(data)) macro(data, 26) -#define MRECURSION28( macro, data) MRECURSION27( macro, DEC_(data)) macro(data, 27) -#define MRECURSION29( macro, data) MRECURSION28( macro, DEC_(data)) macro(data, 28) -#define MRECURSION30( macro, data) MRECURSION29( macro, DEC_(data)) macro(data, 29) -#define MRECURSION31( macro, data) MRECURSION30( macro, DEC_(data)) macro(data, 30) -#define MRECURSION32( macro, data) MRECURSION31( macro, DEC_(data)) macro(data, 31) -#define MRECURSION33( macro, data) MRECURSION32( macro, DEC_(data)) macro(data, 32) -#define MRECURSION34( macro, data) MRECURSION33( macro, DEC_(data)) macro(data, 33) -#define MRECURSION35( macro, data) MRECURSION34( macro, DEC_(data)) macro(data, 34) -#define MRECURSION36( macro, data) MRECURSION35( macro, DEC_(data)) macro(data, 35) -#define MRECURSION37( macro, data) MRECURSION36( macro, DEC_(data)) macro(data, 36) -#define MRECURSION38( macro, data) MRECURSION37( macro, DEC_(data)) macro(data, 37) -#define MRECURSION39( macro, data) MRECURSION38( macro, DEC_(data)) macro(data, 38) -#define MRECURSION40( macro, data) MRECURSION39( macro, DEC_(data)) macro(data, 39) -#define MRECURSION41( macro, data) MRECURSION40( macro, DEC_(data)) macro(data, 40) -#define MRECURSION42( macro, data) MRECURSION41( macro, DEC_(data)) macro(data, 41) -#define MRECURSION43( macro, data) MRECURSION42( macro, DEC_(data)) macro(data, 42) -#define MRECURSION44( macro, data) MRECURSION43( macro, DEC_(data)) macro(data, 43) -#define MRECURSION45( macro, data) MRECURSION44( macro, DEC_(data)) macro(data, 44) -#define MRECURSION46( macro, data) MRECURSION45( macro, DEC_(data)) macro(data, 45) -#define MRECURSION47( macro, data) MRECURSION46( macro, DEC_(data)) macro(data, 46) -#define MRECURSION48( macro, data) MRECURSION47( macro, DEC_(data)) macro(data, 47) -#define MRECURSION49( macro, data) MRECURSION48( macro, DEC_(data)) macro(data, 48) -#define MRECURSION50( macro, data) MRECURSION49( macro, DEC_(data)) macro(data, 49) -#define MRECURSION51( macro, data) MRECURSION50( macro, DEC_(data)) macro(data, 50) -#define MRECURSION52( macro, data) MRECURSION51( macro, DEC_(data)) macro(data, 51) -#define MRECURSION53( macro, data) MRECURSION52( macro, DEC_(data)) macro(data, 52) -#define MRECURSION54( macro, data) MRECURSION53( macro, DEC_(data)) macro(data, 53) -#define MRECURSION55( macro, data) MRECURSION54( macro, DEC_(data)) macro(data, 54) -#define MRECURSION56( macro, data) MRECURSION55( macro, DEC_(data)) macro(data, 55) -#define MRECURSION57( macro, data) MRECURSION56( macro, DEC_(data)) macro(data, 56) -#define MRECURSION58( macro, data) MRECURSION57( macro, DEC_(data)) macro(data, 57) -#define MRECURSION59( macro, data) MRECURSION58( macro, DEC_(data)) macro(data, 58) -#define MRECURSION60( macro, data) MRECURSION59( macro, DEC_(data)) macro(data, 59) -#define MRECURSION61( macro, data) MRECURSION60( macro, DEC_(data)) macro(data, 60) -#define MRECURSION62( macro, data) MRECURSION61( macro, DEC_(data)) macro(data, 61) -#define MRECURSION63( macro, data) MRECURSION62( macro, DEC_(data)) macro(data, 62) -#define MRECURSION64( macro, data) MRECURSION63( macro, DEC_(data)) macro(data, 63) -#define MRECURSION65( macro, data) MRECURSION64( macro, DEC_(data)) macro(data, 64) -#define MRECURSION66( macro, data) MRECURSION65( macro, DEC_(data)) macro(data, 65) -#define MRECURSION67( macro, data) MRECURSION66( macro, DEC_(data)) macro(data, 66) -#define MRECURSION68( macro, data) MRECURSION67( macro, DEC_(data)) macro(data, 67) -#define MRECURSION69( macro, data) MRECURSION68( macro, DEC_(data)) macro(data, 68) -#define MRECURSION70( macro, data) MRECURSION69( macro, DEC_(data)) macro(data, 69) -#define MRECURSION71( macro, data) MRECURSION70( macro, DEC_(data)) macro(data, 70) -#define MRECURSION72( macro, data) MRECURSION71( macro, DEC_(data)) macro(data, 71) -#define MRECURSION73( macro, data) MRECURSION72( macro, DEC_(data)) macro(data, 72) -#define MRECURSION74( macro, data) MRECURSION73( macro, DEC_(data)) macro(data, 73) -#define MRECURSION75( macro, data) MRECURSION74( macro, DEC_(data)) macro(data, 74) -#define MRECURSION76( macro, data) MRECURSION75( macro, DEC_(data)) macro(data, 75) -#define MRECURSION77( macro, data) MRECURSION76( macro, DEC_(data)) macro(data, 76) -#define MRECURSION78( macro, data) MRECURSION77( macro, DEC_(data)) macro(data, 77) -#define MRECURSION79( macro, data) MRECURSION78( macro, DEC_(data)) macro(data, 78) -#define MRECURSION80( macro, data) MRECURSION79( macro, DEC_(data)) macro(data, 79) -#define MRECURSION81( macro, data) MRECURSION80( macro, DEC_(data)) macro(data, 80) -#define MRECURSION82( macro, data) MRECURSION81( macro, DEC_(data)) macro(data, 81) -#define MRECURSION83( macro, data) MRECURSION82( macro, DEC_(data)) macro(data, 82) -#define MRECURSION84( macro, data) MRECURSION83( macro, DEC_(data)) macro(data, 83) -#define MRECURSION85( macro, data) MRECURSION84( macro, DEC_(data)) macro(data, 84) -#define MRECURSION86( macro, data) MRECURSION85( macro, DEC_(data)) macro(data, 85) -#define MRECURSION87( macro, data) MRECURSION86( macro, DEC_(data)) macro(data, 86) -#define MRECURSION88( macro, data) MRECURSION87( macro, DEC_(data)) macro(data, 87) -#define MRECURSION89( macro, data) MRECURSION88( macro, DEC_(data)) macro(data, 88) -#define MRECURSION90( macro, data) MRECURSION89( macro, DEC_(data)) macro(data, 89) -#define MRECURSION91( macro, data) MRECURSION90( macro, DEC_(data)) macro(data, 90) -#define MRECURSION92( macro, data) MRECURSION91( macro, DEC_(data)) macro(data, 91) -#define MRECURSION93( macro, data) MRECURSION92( macro, DEC_(data)) macro(data, 92) -#define MRECURSION94( macro, data) MRECURSION93( macro, DEC_(data)) macro(data, 93) -#define MRECURSION95( macro, data) MRECURSION94( macro, DEC_(data)) macro(data, 94) -#define MRECURSION96( macro, data) MRECURSION95( macro, DEC_(data)) macro(data, 95) -#define MRECURSION97( macro, data) MRECURSION96( macro, DEC_(data)) macro(data, 96) -#define MRECURSION98( macro, data) MRECURSION97( macro, DEC_(data)) macro(data, 97) -#define MRECURSION99( macro, data) MRECURSION98( macro, DEC_(data)) macro(data, 98) -#define MRECURSION100(macro, data) MRECURSION99( macro, DEC_(data)) macro(data, 99) -#define MRECURSION101(macro, data) MRECURSION100( macro, DEC_(data)) macro(data, 100) -#define MRECURSION102(macro, data) MRECURSION101( macro, DEC_(data)) macro(data, 101) -#define MRECURSION103(macro, data) MRECURSION102( macro, DEC_(data)) macro(data, 102) -#define MRECURSION104(macro, data) MRECURSION103( macro, DEC_(data)) macro(data, 103) -#define MRECURSION105(macro, data) MRECURSION104( macro, DEC_(data)) macro(data, 104) -#define MRECURSION106(macro, data) MRECURSION105( macro, DEC_(data)) macro(data, 105) -#define MRECURSION107(macro, data) MRECURSION106( macro, DEC_(data)) macro(data, 106) -#define MRECURSION108(macro, data) MRECURSION107( macro, DEC_(data)) macro(data, 107) -#define MRECURSION109(macro, data) MRECURSION108( macro, DEC_(data)) macro(data, 108) -#define MRECURSION110(macro, data) MRECURSION109( macro, DEC_(data)) macro(data, 109) -#define MRECURSION111(macro, data) MRECURSION110( macro, DEC_(data)) macro(data, 110) -#define MRECURSION112(macro, data) MRECURSION111( macro, DEC_(data)) macro(data, 111) -#define MRECURSION113(macro, data) MRECURSION112( macro, DEC_(data)) macro(data, 112) -#define MRECURSION114(macro, data) MRECURSION113( macro, DEC_(data)) macro(data, 113) -#define MRECURSION115(macro, data) MRECURSION114( macro, DEC_(data)) macro(data, 114) -#define MRECURSION116(macro, data) MRECURSION115( macro, DEC_(data)) macro(data, 115) -#define MRECURSION117(macro, data) MRECURSION116( macro, DEC_(data)) macro(data, 116) -#define MRECURSION118(macro, data) MRECURSION117( macro, DEC_(data)) macro(data, 117) -#define MRECURSION119(macro, data) MRECURSION118( macro, DEC_(data)) macro(data, 118) -#define MRECURSION120(macro, data) MRECURSION119( macro, DEC_(data)) macro(data, 119) -#define MRECURSION121(macro, data) MRECURSION120( macro, DEC_(data)) macro(data, 120) -#define MRECURSION122(macro, data) MRECURSION121( macro, DEC_(data)) macro(data, 121) -#define MRECURSION123(macro, data) MRECURSION122( macro, DEC_(data)) macro(data, 122) -#define MRECURSION124(macro, data) MRECURSION123( macro, DEC_(data)) macro(data, 123) -#define MRECURSION125(macro, data) MRECURSION124( macro, DEC_(data)) macro(data, 124) -#define MRECURSION126(macro, data) MRECURSION125( macro, DEC_(data)) macro(data, 125) -#define MRECURSION127(macro, data) MRECURSION126( macro, DEC_(data)) macro(data, 126) -#define MRECURSION128(macro, data) MRECURSION127( macro, DEC_(data)) macro(data, 127) -#define MRECURSION129(macro, data) MRECURSION128( macro, DEC_(data)) macro(data, 128) -#define MRECURSION130(macro, data) MRECURSION129( macro, DEC_(data)) macro(data, 129) -#define MRECURSION131(macro, data) MRECURSION130( macro, DEC_(data)) macro(data, 130) -#define MRECURSION132(macro, data) MRECURSION131( macro, DEC_(data)) macro(data, 131) -#define MRECURSION133(macro, data) MRECURSION132( macro, DEC_(data)) macro(data, 132) -#define MRECURSION134(macro, data) MRECURSION133( macro, DEC_(data)) macro(data, 133) -#define MRECURSION135(macro, data) MRECURSION134( macro, DEC_(data)) macro(data, 134) -#define MRECURSION136(macro, data) MRECURSION135( macro, DEC_(data)) macro(data, 135) -#define MRECURSION137(macro, data) MRECURSION136( macro, DEC_(data)) macro(data, 136) -#define MRECURSION138(macro, data) MRECURSION137( macro, DEC_(data)) macro(data, 137) -#define MRECURSION139(macro, data) MRECURSION138( macro, DEC_(data)) macro(data, 138) -#define MRECURSION140(macro, data) MRECURSION139( macro, DEC_(data)) macro(data, 139) -#define MRECURSION141(macro, data) MRECURSION140( macro, DEC_(data)) macro(data, 140) -#define MRECURSION142(macro, data) MRECURSION141( macro, DEC_(data)) macro(data, 141) -#define MRECURSION143(macro, data) MRECURSION142( macro, DEC_(data)) macro(data, 142) -#define MRECURSION144(macro, data) MRECURSION143( macro, DEC_(data)) macro(data, 143) -#define MRECURSION145(macro, data) MRECURSION144( macro, DEC_(data)) macro(data, 144) -#define MRECURSION146(macro, data) MRECURSION145( macro, DEC_(data)) macro(data, 145) -#define MRECURSION147(macro, data) MRECURSION146( macro, DEC_(data)) macro(data, 146) -#define MRECURSION148(macro, data) MRECURSION147( macro, DEC_(data)) macro(data, 147) -#define MRECURSION149(macro, data) MRECURSION148( macro, DEC_(data)) macro(data, 148) -#define MRECURSION150(macro, data) MRECURSION149( macro, DEC_(data)) macro(data, 149) -#define MRECURSION151(macro, data) MRECURSION150( macro, DEC_(data)) macro(data, 150) -#define MRECURSION152(macro, data) MRECURSION151( macro, DEC_(data)) macro(data, 151) -#define MRECURSION153(macro, data) MRECURSION152( macro, DEC_(data)) macro(data, 152) -#define MRECURSION154(macro, data) MRECURSION153( macro, DEC_(data)) macro(data, 153) -#define MRECURSION155(macro, data) MRECURSION154( macro, DEC_(data)) macro(data, 154) -#define MRECURSION156(macro, data) MRECURSION155( macro, DEC_(data)) macro(data, 155) -#define MRECURSION157(macro, data) MRECURSION156( macro, DEC_(data)) macro(data, 156) -#define MRECURSION158(macro, data) MRECURSION157( macro, DEC_(data)) macro(data, 157) -#define MRECURSION159(macro, data) MRECURSION158( macro, DEC_(data)) macro(data, 158) -#define MRECURSION160(macro, data) MRECURSION159( macro, DEC_(data)) macro(data, 159) -#define MRECURSION161(macro, data) MRECURSION160( macro, DEC_(data)) macro(data, 160) -#define MRECURSION162(macro, data) MRECURSION161( macro, DEC_(data)) macro(data, 161) -#define MRECURSION163(macro, data) MRECURSION162( macro, DEC_(data)) macro(data, 162) -#define MRECURSION164(macro, data) MRECURSION163( macro, DEC_(data)) macro(data, 163) -#define MRECURSION165(macro, data) MRECURSION164( macro, DEC_(data)) macro(data, 164) -#define MRECURSION166(macro, data) MRECURSION165( macro, DEC_(data)) macro(data, 165) -#define MRECURSION167(macro, data) MRECURSION166( macro, DEC_(data)) macro(data, 166) -#define MRECURSION168(macro, data) MRECURSION167( macro, DEC_(data)) macro(data, 167) -#define MRECURSION169(macro, data) MRECURSION168( macro, DEC_(data)) macro(data, 168) -#define MRECURSION170(macro, data) MRECURSION169( macro, DEC_(data)) macro(data, 169) -#define MRECURSION171(macro, data) MRECURSION170( macro, DEC_(data)) macro(data, 170) -#define MRECURSION172(macro, data) MRECURSION171( macro, DEC_(data)) macro(data, 171) -#define MRECURSION173(macro, data) MRECURSION172( macro, DEC_(data)) macro(data, 172) -#define MRECURSION174(macro, data) MRECURSION173( macro, DEC_(data)) macro(data, 173) -#define MRECURSION175(macro, data) MRECURSION174( macro, DEC_(data)) macro(data, 174) -#define MRECURSION176(macro, data) MRECURSION175( macro, DEC_(data)) macro(data, 175) -#define MRECURSION177(macro, data) MRECURSION176( macro, DEC_(data)) macro(data, 176) -#define MRECURSION178(macro, data) MRECURSION177( macro, DEC_(data)) macro(data, 177) -#define MRECURSION179(macro, data) MRECURSION178( macro, DEC_(data)) macro(data, 178) -#define MRECURSION180(macro, data) MRECURSION179( macro, DEC_(data)) macro(data, 179) -#define MRECURSION181(macro, data) MRECURSION180( macro, DEC_(data)) macro(data, 180) -#define MRECURSION182(macro, data) MRECURSION181( macro, DEC_(data)) macro(data, 181) -#define MRECURSION183(macro, data) MRECURSION182( macro, DEC_(data)) macro(data, 182) -#define MRECURSION184(macro, data) MRECURSION183( macro, DEC_(data)) macro(data, 183) -#define MRECURSION185(macro, data) MRECURSION184( macro, DEC_(data)) macro(data, 184) -#define MRECURSION186(macro, data) MRECURSION185( macro, DEC_(data)) macro(data, 185) -#define MRECURSION187(macro, data) MRECURSION186( macro, DEC_(data)) macro(data, 186) -#define MRECURSION188(macro, data) MRECURSION187( macro, DEC_(data)) macro(data, 187) -#define MRECURSION189(macro, data) MRECURSION188( macro, DEC_(data)) macro(data, 188) -#define MRECURSION190(macro, data) MRECURSION189( macro, DEC_(data)) macro(data, 189) -#define MRECURSION191(macro, data) MRECURSION190( macro, DEC_(data)) macro(data, 190) -#define MRECURSION192(macro, data) MRECURSION191( macro, DEC_(data)) macro(data, 191) -#define MRECURSION193(macro, data) MRECURSION192( macro, DEC_(data)) macro(data, 192) -#define MRECURSION194(macro, data) MRECURSION193( macro, DEC_(data)) macro(data, 193) -#define MRECURSION195(macro, data) MRECURSION194( macro, DEC_(data)) macro(data, 194) -#define MRECURSION196(macro, data) MRECURSION195( macro, DEC_(data)) macro(data, 195) -#define MRECURSION197(macro, data) MRECURSION196( macro, DEC_(data)) macro(data, 196) -#define MRECURSION198(macro, data) MRECURSION197( macro, DEC_(data)) macro(data, 197) -#define MRECURSION199(macro, data) MRECURSION198( macro, DEC_(data)) macro(data, 198) -#define MRECURSION200(macro, data) MRECURSION199( macro, DEC_(data)) macro(data, 199) -#define MRECURSION201(macro, data) MRECURSION200( macro, DEC_(data)) macro(data, 200) -#define MRECURSION202(macro, data) MRECURSION201( macro, DEC_(data)) macro(data, 201) -#define MRECURSION203(macro, data) MRECURSION202( macro, DEC_(data)) macro(data, 202) -#define MRECURSION204(macro, data) MRECURSION203( macro, DEC_(data)) macro(data, 203) -#define MRECURSION205(macro, data) MRECURSION204( macro, DEC_(data)) macro(data, 204) -#define MRECURSION206(macro, data) MRECURSION205( macro, DEC_(data)) macro(data, 205) -#define MRECURSION207(macro, data) MRECURSION206( macro, DEC_(data)) macro(data, 206) -#define MRECURSION208(macro, data) MRECURSION207( macro, DEC_(data)) macro(data, 207) -#define MRECURSION209(macro, data) MRECURSION208( macro, DEC_(data)) macro(data, 208) -#define MRECURSION210(macro, data) MRECURSION209( macro, DEC_(data)) macro(data, 209) -#define MRECURSION211(macro, data) MRECURSION210( macro, DEC_(data)) macro(data, 210) -#define MRECURSION212(macro, data) MRECURSION211( macro, DEC_(data)) macro(data, 211) -#define MRECURSION213(macro, data) MRECURSION212( macro, DEC_(data)) macro(data, 212) -#define MRECURSION214(macro, data) MRECURSION213( macro, DEC_(data)) macro(data, 213) -#define MRECURSION215(macro, data) MRECURSION214( macro, DEC_(data)) macro(data, 214) -#define MRECURSION216(macro, data) MRECURSION215( macro, DEC_(data)) macro(data, 215) -#define MRECURSION217(macro, data) MRECURSION216( macro, DEC_(data)) macro(data, 216) -#define MRECURSION218(macro, data) MRECURSION217( macro, DEC_(data)) macro(data, 217) -#define MRECURSION219(macro, data) MRECURSION218( macro, DEC_(data)) macro(data, 218) -#define MRECURSION220(macro, data) MRECURSION219( macro, DEC_(data)) macro(data, 219) -#define MRECURSION221(macro, data) MRECURSION220( macro, DEC_(data)) macro(data, 220) -#define MRECURSION222(macro, data) MRECURSION221( macro, DEC_(data)) macro(data, 221) -#define MRECURSION223(macro, data) MRECURSION222( macro, DEC_(data)) macro(data, 222) -#define MRECURSION224(macro, data) MRECURSION223( macro, DEC_(data)) macro(data, 223) -#define MRECURSION225(macro, data) MRECURSION224( macro, DEC_(data)) macro(data, 224) -#define MRECURSION226(macro, data) MRECURSION225( macro, DEC_(data)) macro(data, 225) -#define MRECURSION227(macro, data) MRECURSION226( macro, DEC_(data)) macro(data, 226) -#define MRECURSION228(macro, data) MRECURSION227( macro, DEC_(data)) macro(data, 227) -#define MRECURSION229(macro, data) MRECURSION228( macro, DEC_(data)) macro(data, 228) -#define MRECURSION230(macro, data) MRECURSION229( macro, DEC_(data)) macro(data, 229) -#define MRECURSION231(macro, data) MRECURSION230( macro, DEC_(data)) macro(data, 230) -#define MRECURSION232(macro, data) MRECURSION231( macro, DEC_(data)) macro(data, 231) -#define MRECURSION233(macro, data) MRECURSION232( macro, DEC_(data)) macro(data, 232) -#define MRECURSION234(macro, data) MRECURSION233( macro, DEC_(data)) macro(data, 233) -#define MRECURSION235(macro, data) MRECURSION234( macro, DEC_(data)) macro(data, 234) -#define MRECURSION236(macro, data) MRECURSION235( macro, DEC_(data)) macro(data, 235) -#define MRECURSION237(macro, data) MRECURSION236( macro, DEC_(data)) macro(data, 236) -#define MRECURSION238(macro, data) MRECURSION237( macro, DEC_(data)) macro(data, 237) -#define MRECURSION239(macro, data) MRECURSION238( macro, DEC_(data)) macro(data, 238) -#define MRECURSION240(macro, data) MRECURSION239( macro, DEC_(data)) macro(data, 239) -#define MRECURSION241(macro, data) MRECURSION240( macro, DEC_(data)) macro(data, 240) -#define MRECURSION242(macro, data) MRECURSION241( macro, DEC_(data)) macro(data, 241) -#define MRECURSION243(macro, data) MRECURSION242( macro, DEC_(data)) macro(data, 242) -#define MRECURSION244(macro, data) MRECURSION243( macro, DEC_(data)) macro(data, 243) -#define MRECURSION245(macro, data) MRECURSION244( macro, DEC_(data)) macro(data, 244) -#define MRECURSION246(macro, data) MRECURSION245( macro, DEC_(data)) macro(data, 245) -#define MRECURSION247(macro, data) MRECURSION246( macro, DEC_(data)) macro(data, 246) -#define MRECURSION248(macro, data) MRECURSION247( macro, DEC_(data)) macro(data, 247) -#define MRECURSION249(macro, data) MRECURSION248( macro, DEC_(data)) macro(data, 248) -#define MRECURSION250(macro, data) MRECURSION249( macro, DEC_(data)) macro(data, 249) -#define MRECURSION251(macro, data) MRECURSION250( macro, DEC_(data)) macro(data, 250) -#define MRECURSION252(macro, data) MRECURSION251( macro, DEC_(data)) macro(data, 251) -#define MRECURSION253(macro, data) MRECURSION252( macro, DEC_(data)) macro(data, 252) -#define MRECURSION254(macro, data) MRECURSION253( macro, DEC_(data)) macro(data, 253) -#define MRECURSION255(macro, data) MRECURSION254( macro, DEC_(data)) macro(data, 254) -#define MRECURSION256(macro, data) MRECURSION255( macro, DEC_(data)) macro(data, 255) - -/** @} */ - -#endif /* _MRECURSION_H_ */ diff --git a/bootloaders/feather/utils/preprocessor/mrepeat.h b/bootloaders/feather/utils/preprocessor/mrepeat.h deleted file mode 100644 index fb820d5bd..000000000 --- a/bootloaders/feather/utils/preprocessor/mrepeat.h +++ /dev/null @@ -1,321 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#ifndef _MREPEAT_H_ -#define _MREPEAT_H_ - -/** - * \defgroup group_sam0_utils_mrepeat Preprocessor - Macro Repeat - * - * \ingroup group_sam0_utils - * - * @{ - */ - -#include "preprocessor.h" - -/** Maximal number of repetitions supported by MREPEAT. */ -#define MREPEAT_LIMIT 256 - -/** \brief Macro repeat. - * - * This macro represents a horizontal repetition construct. - * - * \param[in] count The number of repetitious calls to macro. Valid values - * range from 0 to MREPEAT_LIMIT. - * \param[in] macro A binary operation of the form macro(n, data). This macro - * is expanded by MREPEAT with the current repetition number - * and the auxiliary data argument. - * \param[in] data Auxiliary data passed to macro. - * - * \return macro(0, data) macro(1, data) ... macro(count - 1, data) - */ -#define MREPEAT(count, macro, data) TPASTE2(MREPEAT, count) (macro, data) - -#define MREPEAT0( macro, data) -#define MREPEAT1( macro, data) MREPEAT0( macro, data) macro( 0, data) -#define MREPEAT2( macro, data) MREPEAT1( macro, data) macro( 1, data) -#define MREPEAT3( macro, data) MREPEAT2( macro, data) macro( 2, data) -#define MREPEAT4( macro, data) MREPEAT3( macro, data) macro( 3, data) -#define MREPEAT5( macro, data) MREPEAT4( macro, data) macro( 4, data) -#define MREPEAT6( macro, data) MREPEAT5( macro, data) macro( 5, data) -#define MREPEAT7( macro, data) MREPEAT6( macro, data) macro( 6, data) -#define MREPEAT8( macro, data) MREPEAT7( macro, data) macro( 7, data) -#define MREPEAT9( macro, data) MREPEAT8( macro, data) macro( 8, data) -#define MREPEAT10( macro, data) MREPEAT9( macro, data) macro( 9, data) -#define MREPEAT11( macro, data) MREPEAT10( macro, data) macro( 10, data) -#define MREPEAT12( macro, data) MREPEAT11( macro, data) macro( 11, data) -#define MREPEAT13( macro, data) MREPEAT12( macro, data) macro( 12, data) -#define MREPEAT14( macro, data) MREPEAT13( macro, data) macro( 13, data) -#define MREPEAT15( macro, data) MREPEAT14( macro, data) macro( 14, data) -#define MREPEAT16( macro, data) MREPEAT15( macro, data) macro( 15, data) -#define MREPEAT17( macro, data) MREPEAT16( macro, data) macro( 16, data) -#define MREPEAT18( macro, data) MREPEAT17( macro, data) macro( 17, data) -#define MREPEAT19( macro, data) MREPEAT18( macro, data) macro( 18, data) -#define MREPEAT20( macro, data) MREPEAT19( macro, data) macro( 19, data) -#define MREPEAT21( macro, data) MREPEAT20( macro, data) macro( 20, data) -#define MREPEAT22( macro, data) MREPEAT21( macro, data) macro( 21, data) -#define MREPEAT23( macro, data) MREPEAT22( macro, data) macro( 22, data) -#define MREPEAT24( macro, data) MREPEAT23( macro, data) macro( 23, data) -#define MREPEAT25( macro, data) MREPEAT24( macro, data) macro( 24, data) -#define MREPEAT26( macro, data) MREPEAT25( macro, data) macro( 25, data) -#define MREPEAT27( macro, data) MREPEAT26( macro, data) macro( 26, data) -#define MREPEAT28( macro, data) MREPEAT27( macro, data) macro( 27, data) -#define MREPEAT29( macro, data) MREPEAT28( macro, data) macro( 28, data) -#define MREPEAT30( macro, data) MREPEAT29( macro, data) macro( 29, data) -#define MREPEAT31( macro, data) MREPEAT30( macro, data) macro( 30, data) -#define MREPEAT32( macro, data) MREPEAT31( macro, data) macro( 31, data) -#define MREPEAT33( macro, data) MREPEAT32( macro, data) macro( 32, data) -#define MREPEAT34( macro, data) MREPEAT33( macro, data) macro( 33, data) -#define MREPEAT35( macro, data) MREPEAT34( macro, data) macro( 34, data) -#define MREPEAT36( macro, data) MREPEAT35( macro, data) macro( 35, data) -#define MREPEAT37( macro, data) MREPEAT36( macro, data) macro( 36, data) -#define MREPEAT38( macro, data) MREPEAT37( macro, data) macro( 37, data) -#define MREPEAT39( macro, data) MREPEAT38( macro, data) macro( 38, data) -#define MREPEAT40( macro, data) MREPEAT39( macro, data) macro( 39, data) -#define MREPEAT41( macro, data) MREPEAT40( macro, data) macro( 40, data) -#define MREPEAT42( macro, data) MREPEAT41( macro, data) macro( 41, data) -#define MREPEAT43( macro, data) MREPEAT42( macro, data) macro( 42, data) -#define MREPEAT44( macro, data) MREPEAT43( macro, data) macro( 43, data) -#define MREPEAT45( macro, data) MREPEAT44( macro, data) macro( 44, data) -#define MREPEAT46( macro, data) MREPEAT45( macro, data) macro( 45, data) -#define MREPEAT47( macro, data) MREPEAT46( macro, data) macro( 46, data) -#define MREPEAT48( macro, data) MREPEAT47( macro, data) macro( 47, data) -#define MREPEAT49( macro, data) MREPEAT48( macro, data) macro( 48, data) -#define MREPEAT50( macro, data) MREPEAT49( macro, data) macro( 49, data) -#define MREPEAT51( macro, data) MREPEAT50( macro, data) macro( 50, data) -#define MREPEAT52( macro, data) MREPEAT51( macro, data) macro( 51, data) -#define MREPEAT53( macro, data) MREPEAT52( macro, data) macro( 52, data) -#define MREPEAT54( macro, data) MREPEAT53( macro, data) macro( 53, data) -#define MREPEAT55( macro, data) MREPEAT54( macro, data) macro( 54, data) -#define MREPEAT56( macro, data) MREPEAT55( macro, data) macro( 55, data) -#define MREPEAT57( macro, data) MREPEAT56( macro, data) macro( 56, data) -#define MREPEAT58( macro, data) MREPEAT57( macro, data) macro( 57, data) -#define MREPEAT59( macro, data) MREPEAT58( macro, data) macro( 58, data) -#define MREPEAT60( macro, data) MREPEAT59( macro, data) macro( 59, data) -#define MREPEAT61( macro, data) MREPEAT60( macro, data) macro( 60, data) -#define MREPEAT62( macro, data) MREPEAT61( macro, data) macro( 61, data) -#define MREPEAT63( macro, data) MREPEAT62( macro, data) macro( 62, data) -#define MREPEAT64( macro, data) MREPEAT63( macro, data) macro( 63, data) -#define MREPEAT65( macro, data) MREPEAT64( macro, data) macro( 64, data) -#define MREPEAT66( macro, data) MREPEAT65( macro, data) macro( 65, data) -#define MREPEAT67( macro, data) MREPEAT66( macro, data) macro( 66, data) -#define MREPEAT68( macro, data) MREPEAT67( macro, data) macro( 67, data) -#define MREPEAT69( macro, data) MREPEAT68( macro, data) macro( 68, data) -#define MREPEAT70( macro, data) MREPEAT69( macro, data) macro( 69, data) -#define MREPEAT71( macro, data) MREPEAT70( macro, data) macro( 70, data) -#define MREPEAT72( macro, data) MREPEAT71( macro, data) macro( 71, data) -#define MREPEAT73( macro, data) MREPEAT72( macro, data) macro( 72, data) -#define MREPEAT74( macro, data) MREPEAT73( macro, data) macro( 73, data) -#define MREPEAT75( macro, data) MREPEAT74( macro, data) macro( 74, data) -#define MREPEAT76( macro, data) MREPEAT75( macro, data) macro( 75, data) -#define MREPEAT77( macro, data) MREPEAT76( macro, data) macro( 76, data) -#define MREPEAT78( macro, data) MREPEAT77( macro, data) macro( 77, data) -#define MREPEAT79( macro, data) MREPEAT78( macro, data) macro( 78, data) -#define MREPEAT80( macro, data) MREPEAT79( macro, data) macro( 79, data) -#define MREPEAT81( macro, data) MREPEAT80( macro, data) macro( 80, data) -#define MREPEAT82( macro, data) MREPEAT81( macro, data) macro( 81, data) -#define MREPEAT83( macro, data) MREPEAT82( macro, data) macro( 82, data) -#define MREPEAT84( macro, data) MREPEAT83( macro, data) macro( 83, data) -#define MREPEAT85( macro, data) MREPEAT84( macro, data) macro( 84, data) -#define MREPEAT86( macro, data) MREPEAT85( macro, data) macro( 85, data) -#define MREPEAT87( macro, data) MREPEAT86( macro, data) macro( 86, data) -#define MREPEAT88( macro, data) MREPEAT87( macro, data) macro( 87, data) -#define MREPEAT89( macro, data) MREPEAT88( macro, data) macro( 88, data) -#define MREPEAT90( macro, data) MREPEAT89( macro, data) macro( 89, data) -#define MREPEAT91( macro, data) MREPEAT90( macro, data) macro( 90, data) -#define MREPEAT92( macro, data) MREPEAT91( macro, data) macro( 91, data) -#define MREPEAT93( macro, data) MREPEAT92( macro, data) macro( 92, data) -#define MREPEAT94( macro, data) MREPEAT93( macro, data) macro( 93, data) -#define MREPEAT95( macro, data) MREPEAT94( macro, data) macro( 94, data) -#define MREPEAT96( macro, data) MREPEAT95( macro, data) macro( 95, data) -#define MREPEAT97( macro, data) MREPEAT96( macro, data) macro( 96, data) -#define MREPEAT98( macro, data) MREPEAT97( macro, data) macro( 97, data) -#define MREPEAT99( macro, data) MREPEAT98( macro, data) macro( 98, data) -#define MREPEAT100(macro, data) MREPEAT99( macro, data) macro( 99, data) -#define MREPEAT101(macro, data) MREPEAT100(macro, data) macro(100, data) -#define MREPEAT102(macro, data) MREPEAT101(macro, data) macro(101, data) -#define MREPEAT103(macro, data) MREPEAT102(macro, data) macro(102, data) -#define MREPEAT104(macro, data) MREPEAT103(macro, data) macro(103, data) -#define MREPEAT105(macro, data) MREPEAT104(macro, data) macro(104, data) -#define MREPEAT106(macro, data) MREPEAT105(macro, data) macro(105, data) -#define MREPEAT107(macro, data) MREPEAT106(macro, data) macro(106, data) -#define MREPEAT108(macro, data) MREPEAT107(macro, data) macro(107, data) -#define MREPEAT109(macro, data) MREPEAT108(macro, data) macro(108, data) -#define MREPEAT110(macro, data) MREPEAT109(macro, data) macro(109, data) -#define MREPEAT111(macro, data) MREPEAT110(macro, data) macro(110, data) -#define MREPEAT112(macro, data) MREPEAT111(macro, data) macro(111, data) -#define MREPEAT113(macro, data) MREPEAT112(macro, data) macro(112, data) -#define MREPEAT114(macro, data) MREPEAT113(macro, data) macro(113, data) -#define MREPEAT115(macro, data) MREPEAT114(macro, data) macro(114, data) -#define MREPEAT116(macro, data) MREPEAT115(macro, data) macro(115, data) -#define MREPEAT117(macro, data) MREPEAT116(macro, data) macro(116, data) -#define MREPEAT118(macro, data) MREPEAT117(macro, data) macro(117, data) -#define MREPEAT119(macro, data) MREPEAT118(macro, data) macro(118, data) -#define MREPEAT120(macro, data) MREPEAT119(macro, data) macro(119, data) -#define MREPEAT121(macro, data) MREPEAT120(macro, data) macro(120, data) -#define MREPEAT122(macro, data) MREPEAT121(macro, data) macro(121, data) -#define MREPEAT123(macro, data) MREPEAT122(macro, data) macro(122, data) -#define MREPEAT124(macro, data) MREPEAT123(macro, data) macro(123, data) -#define MREPEAT125(macro, data) MREPEAT124(macro, data) macro(124, data) -#define MREPEAT126(macro, data) MREPEAT125(macro, data) macro(125, data) -#define MREPEAT127(macro, data) MREPEAT126(macro, data) macro(126, data) -#define MREPEAT128(macro, data) MREPEAT127(macro, data) macro(127, data) -#define MREPEAT129(macro, data) MREPEAT128(macro, data) macro(128, data) -#define MREPEAT130(macro, data) MREPEAT129(macro, data) macro(129, data) -#define MREPEAT131(macro, data) MREPEAT130(macro, data) macro(130, data) -#define MREPEAT132(macro, data) MREPEAT131(macro, data) macro(131, data) -#define MREPEAT133(macro, data) MREPEAT132(macro, data) macro(132, data) -#define MREPEAT134(macro, data) MREPEAT133(macro, data) macro(133, data) -#define MREPEAT135(macro, data) MREPEAT134(macro, data) macro(134, data) -#define MREPEAT136(macro, data) MREPEAT135(macro, data) macro(135, data) -#define MREPEAT137(macro, data) MREPEAT136(macro, data) macro(136, data) -#define MREPEAT138(macro, data) MREPEAT137(macro, data) macro(137, data) -#define MREPEAT139(macro, data) MREPEAT138(macro, data) macro(138, data) -#define MREPEAT140(macro, data) MREPEAT139(macro, data) macro(139, data) -#define MREPEAT141(macro, data) MREPEAT140(macro, data) macro(140, data) -#define MREPEAT142(macro, data) MREPEAT141(macro, data) macro(141, data) -#define MREPEAT143(macro, data) MREPEAT142(macro, data) macro(142, data) -#define MREPEAT144(macro, data) MREPEAT143(macro, data) macro(143, data) -#define MREPEAT145(macro, data) MREPEAT144(macro, data) macro(144, data) -#define MREPEAT146(macro, data) MREPEAT145(macro, data) macro(145, data) -#define MREPEAT147(macro, data) MREPEAT146(macro, data) macro(146, data) -#define MREPEAT148(macro, data) MREPEAT147(macro, data) macro(147, data) -#define MREPEAT149(macro, data) MREPEAT148(macro, data) macro(148, data) -#define MREPEAT150(macro, data) MREPEAT149(macro, data) macro(149, data) -#define MREPEAT151(macro, data) MREPEAT150(macro, data) macro(150, data) -#define MREPEAT152(macro, data) MREPEAT151(macro, data) macro(151, data) -#define MREPEAT153(macro, data) MREPEAT152(macro, data) macro(152, data) -#define MREPEAT154(macro, data) MREPEAT153(macro, data) macro(153, data) -#define MREPEAT155(macro, data) MREPEAT154(macro, data) macro(154, data) -#define MREPEAT156(macro, data) MREPEAT155(macro, data) macro(155, data) -#define MREPEAT157(macro, data) MREPEAT156(macro, data) macro(156, data) -#define MREPEAT158(macro, data) MREPEAT157(macro, data) macro(157, data) -#define MREPEAT159(macro, data) MREPEAT158(macro, data) macro(158, data) -#define MREPEAT160(macro, data) MREPEAT159(macro, data) macro(159, data) -#define MREPEAT161(macro, data) MREPEAT160(macro, data) macro(160, data) -#define MREPEAT162(macro, data) MREPEAT161(macro, data) macro(161, data) -#define MREPEAT163(macro, data) MREPEAT162(macro, data) macro(162, data) -#define MREPEAT164(macro, data) MREPEAT163(macro, data) macro(163, data) -#define MREPEAT165(macro, data) MREPEAT164(macro, data) macro(164, data) -#define MREPEAT166(macro, data) MREPEAT165(macro, data) macro(165, data) -#define MREPEAT167(macro, data) MREPEAT166(macro, data) macro(166, data) -#define MREPEAT168(macro, data) MREPEAT167(macro, data) macro(167, data) -#define MREPEAT169(macro, data) MREPEAT168(macro, data) macro(168, data) -#define MREPEAT170(macro, data) MREPEAT169(macro, data) macro(169, data) -#define MREPEAT171(macro, data) MREPEAT170(macro, data) macro(170, data) -#define MREPEAT172(macro, data) MREPEAT171(macro, data) macro(171, data) -#define MREPEAT173(macro, data) MREPEAT172(macro, data) macro(172, data) -#define MREPEAT174(macro, data) MREPEAT173(macro, data) macro(173, data) -#define MREPEAT175(macro, data) MREPEAT174(macro, data) macro(174, data) -#define MREPEAT176(macro, data) MREPEAT175(macro, data) macro(175, data) -#define MREPEAT177(macro, data) MREPEAT176(macro, data) macro(176, data) -#define MREPEAT178(macro, data) MREPEAT177(macro, data) macro(177, data) -#define MREPEAT179(macro, data) MREPEAT178(macro, data) macro(178, data) -#define MREPEAT180(macro, data) MREPEAT179(macro, data) macro(179, data) -#define MREPEAT181(macro, data) MREPEAT180(macro, data) macro(180, data) -#define MREPEAT182(macro, data) MREPEAT181(macro, data) macro(181, data) -#define MREPEAT183(macro, data) MREPEAT182(macro, data) macro(182, data) -#define MREPEAT184(macro, data) MREPEAT183(macro, data) macro(183, data) -#define MREPEAT185(macro, data) MREPEAT184(macro, data) macro(184, data) -#define MREPEAT186(macro, data) MREPEAT185(macro, data) macro(185, data) -#define MREPEAT187(macro, data) MREPEAT186(macro, data) macro(186, data) -#define MREPEAT188(macro, data) MREPEAT187(macro, data) macro(187, data) -#define MREPEAT189(macro, data) MREPEAT188(macro, data) macro(188, data) -#define MREPEAT190(macro, data) MREPEAT189(macro, data) macro(189, data) -#define MREPEAT191(macro, data) MREPEAT190(macro, data) macro(190, data) -#define MREPEAT192(macro, data) MREPEAT191(macro, data) macro(191, data) -#define MREPEAT193(macro, data) MREPEAT192(macro, data) macro(192, data) -#define MREPEAT194(macro, data) MREPEAT193(macro, data) macro(193, data) -#define MREPEAT195(macro, data) MREPEAT194(macro, data) macro(194, data) -#define MREPEAT196(macro, data) MREPEAT195(macro, data) macro(195, data) -#define MREPEAT197(macro, data) MREPEAT196(macro, data) macro(196, data) -#define MREPEAT198(macro, data) MREPEAT197(macro, data) macro(197, data) -#define MREPEAT199(macro, data) MREPEAT198(macro, data) macro(198, data) -#define MREPEAT200(macro, data) MREPEAT199(macro, data) macro(199, data) -#define MREPEAT201(macro, data) MREPEAT200(macro, data) macro(200, data) -#define MREPEAT202(macro, data) MREPEAT201(macro, data) macro(201, data) -#define MREPEAT203(macro, data) MREPEAT202(macro, data) macro(202, data) -#define MREPEAT204(macro, data) MREPEAT203(macro, data) macro(203, data) -#define MREPEAT205(macro, data) MREPEAT204(macro, data) macro(204, data) -#define MREPEAT206(macro, data) MREPEAT205(macro, data) macro(205, data) -#define MREPEAT207(macro, data) MREPEAT206(macro, data) macro(206, data) -#define MREPEAT208(macro, data) MREPEAT207(macro, data) macro(207, data) -#define MREPEAT209(macro, data) MREPEAT208(macro, data) macro(208, data) -#define MREPEAT210(macro, data) MREPEAT209(macro, data) macro(209, data) -#define MREPEAT211(macro, data) MREPEAT210(macro, data) macro(210, data) -#define MREPEAT212(macro, data) MREPEAT211(macro, data) macro(211, data) -#define MREPEAT213(macro, data) MREPEAT212(macro, data) macro(212, data) -#define MREPEAT214(macro, data) MREPEAT213(macro, data) macro(213, data) -#define MREPEAT215(macro, data) MREPEAT214(macro, data) macro(214, data) -#define MREPEAT216(macro, data) MREPEAT215(macro, data) macro(215, data) -#define MREPEAT217(macro, data) MREPEAT216(macro, data) macro(216, data) -#define MREPEAT218(macro, data) MREPEAT217(macro, data) macro(217, data) -#define MREPEAT219(macro, data) MREPEAT218(macro, data) macro(218, data) -#define MREPEAT220(macro, data) MREPEAT219(macro, data) macro(219, data) -#define MREPEAT221(macro, data) MREPEAT220(macro, data) macro(220, data) -#define MREPEAT222(macro, data) MREPEAT221(macro, data) macro(221, data) -#define MREPEAT223(macro, data) MREPEAT222(macro, data) macro(222, data) -#define MREPEAT224(macro, data) MREPEAT223(macro, data) macro(223, data) -#define MREPEAT225(macro, data) MREPEAT224(macro, data) macro(224, data) -#define MREPEAT226(macro, data) MREPEAT225(macro, data) macro(225, data) -#define MREPEAT227(macro, data) MREPEAT226(macro, data) macro(226, data) -#define MREPEAT228(macro, data) MREPEAT227(macro, data) macro(227, data) -#define MREPEAT229(macro, data) MREPEAT228(macro, data) macro(228, data) -#define MREPEAT230(macro, data) MREPEAT229(macro, data) macro(229, data) -#define MREPEAT231(macro, data) MREPEAT230(macro, data) macro(230, data) -#define MREPEAT232(macro, data) MREPEAT231(macro, data) macro(231, data) -#define MREPEAT233(macro, data) MREPEAT232(macro, data) macro(232, data) -#define MREPEAT234(macro, data) MREPEAT233(macro, data) macro(233, data) -#define MREPEAT235(macro, data) MREPEAT234(macro, data) macro(234, data) -#define MREPEAT236(macro, data) MREPEAT235(macro, data) macro(235, data) -#define MREPEAT237(macro, data) MREPEAT236(macro, data) macro(236, data) -#define MREPEAT238(macro, data) MREPEAT237(macro, data) macro(237, data) -#define MREPEAT239(macro, data) MREPEAT238(macro, data) macro(238, data) -#define MREPEAT240(macro, data) MREPEAT239(macro, data) macro(239, data) -#define MREPEAT241(macro, data) MREPEAT240(macro, data) macro(240, data) -#define MREPEAT242(macro, data) MREPEAT241(macro, data) macro(241, data) -#define MREPEAT243(macro, data) MREPEAT242(macro, data) macro(242, data) -#define MREPEAT244(macro, data) MREPEAT243(macro, data) macro(243, data) -#define MREPEAT245(macro, data) MREPEAT244(macro, data) macro(244, data) -#define MREPEAT246(macro, data) MREPEAT245(macro, data) macro(245, data) -#define MREPEAT247(macro, data) MREPEAT246(macro, data) macro(246, data) -#define MREPEAT248(macro, data) MREPEAT247(macro, data) macro(247, data) -#define MREPEAT249(macro, data) MREPEAT248(macro, data) macro(248, data) -#define MREPEAT250(macro, data) MREPEAT249(macro, data) macro(249, data) -#define MREPEAT251(macro, data) MREPEAT250(macro, data) macro(250, data) -#define MREPEAT252(macro, data) MREPEAT251(macro, data) macro(251, data) -#define MREPEAT253(macro, data) MREPEAT252(macro, data) macro(252, data) -#define MREPEAT254(macro, data) MREPEAT253(macro, data) macro(253, data) -#define MREPEAT255(macro, data) MREPEAT254(macro, data) macro(254, data) -#define MREPEAT256(macro, data) MREPEAT255(macro, data) macro(255, data) - -/** @} */ - -#endif /* _MREPEAT_H_ */ diff --git a/bootloaders/feather/utils/preprocessor/preprocessor.h b/bootloaders/feather/utils/preprocessor/preprocessor.h deleted file mode 100644 index 7f67d8adf..000000000 --- a/bootloaders/feather/utils/preprocessor/preprocessor.h +++ /dev/null @@ -1,38 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#ifndef _PREPROCESSOR_H_ -#define _PREPROCESSOR_H_ - -#include "tpaste.h" -#include "stringz.h" -#include "mrepeat.h" -#include "mrecursion.h" - -#endif // _PREPROCESSOR_H_ diff --git a/bootloaders/feather/utils/preprocessor/stringz.h b/bootloaders/feather/utils/preprocessor/stringz.h deleted file mode 100644 index 70937c434..000000000 --- a/bootloaders/feather/utils/preprocessor/stringz.h +++ /dev/null @@ -1,67 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#ifndef _STRINGZ_H_ -#define _STRINGZ_H_ - -/** - * \defgroup group_sam0_utils_stringz Preprocessor - Stringize - * - * \ingroup group_sam0_utils - * - * @{ - */ - -/** \brief Stringize. - * - * Stringize a preprocessing token, this token being allowed to be \#defined. - * - * May be used only within macros with the token passed as an argument if the - * token is \#defined. - * - * For example, writing STRINGZ(PIN) within a macro \#defined by PIN_NAME(PIN) - * and invoked as PIN_NAME(PIN0) with PIN0 \#defined as A0 is equivalent to - * writing "A0". - */ -#define STRINGZ(x) #x - -/** \brief Absolute stringize. - * - * Stringize a preprocessing token, this token being allowed to be \#defined. - * - * No restriction of use if the token is \#defined. - * - * For example, writing ASTRINGZ(PIN0) anywhere with PIN0 \#defined as A0 is - * equivalent to writing "A0". - */ -#define ASTRINGZ(x) STRINGZ(x) - -/** @} */ - -#endif // _STRINGZ_H_ diff --git a/bootloaders/feather/utils/preprocessor/tpaste.h b/bootloaders/feather/utils/preprocessor/tpaste.h deleted file mode 100644 index 910818347..000000000 --- a/bootloaders/feather/utils/preprocessor/tpaste.h +++ /dev/null @@ -1,85 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ -#ifndef _TPASTE_H_ -#define _TPASTE_H_ - -/** - * \defgroup group_sam0_utils_tpaste Preprocessor - Token Paste - * - * \ingroup group_sam0_utils - * - * @{ - */ - -/** \name Token Paste - * - * Paste N preprocessing tokens together, these tokens being allowed to be \#defined. - * - * May be used only within macros with the tokens passed as arguments if the tokens are \#defined. - * - * For example, writing TPASTE2(U, WIDTH) within a macro \#defined by - * UTYPE(WIDTH) and invoked as UTYPE(UL_WIDTH) with UL_WIDTH \#defined as 32 is - * equivalent to writing U32. - * - * @{ */ -#define TPASTE2( a, b) a##b -#define TPASTE3( a, b, c) a##b##c -#define TPASTE4( a, b, c, d) a##b##c##d -#define TPASTE5( a, b, c, d, e) a##b##c##d##e -#define TPASTE6( a, b, c, d, e, f) a##b##c##d##e##f -#define TPASTE7( a, b, c, d, e, f, g) a##b##c##d##e##f##g -#define TPASTE8( a, b, c, d, e, f, g, h) a##b##c##d##e##f##g##h -#define TPASTE9( a, b, c, d, e, f, g, h, i) a##b##c##d##e##f##g##h##i -#define TPASTE10(a, b, c, d, e, f, g, h, i, j) a##b##c##d##e##f##g##h##i##j -/** @} */ - -/** \name Absolute Token Paste - * - * Paste N preprocessing tokens together, these tokens being allowed to be \#defined. - * - * No restriction of use if the tokens are \#defined. - * - * For example, writing ATPASTE2(U, UL_WIDTH) anywhere with UL_WIDTH \#defined - * as 32 is equivalent to writing U32. - * - * @{ */ -#define ATPASTE2( a, b) TPASTE2( a, b) -#define ATPASTE3( a, b, c) TPASTE3( a, b, c) -#define ATPASTE4( a, b, c, d) TPASTE4( a, b, c, d) -#define ATPASTE5( a, b, c, d, e) TPASTE5( a, b, c, d, e) -#define ATPASTE6( a, b, c, d, e, f) TPASTE6( a, b, c, d, e, f) -#define ATPASTE7( a, b, c, d, e, f, g) TPASTE7( a, b, c, d, e, f, g) -#define ATPASTE8( a, b, c, d, e, f, g, h) TPASTE8( a, b, c, d, e, f, g, h) -#define ATPASTE9( a, b, c, d, e, f, g, h, i) TPASTE9( a, b, c, d, e, f, g, h, i) -#define ATPASTE10(a, b, c, d, e, f, g, h, i, j) TPASTE10(a, b, c, d, e, f, g, h, i, j) -/** @} */ - -/** @} */ - -#endif // _TPASTE_H_ diff --git a/bootloaders/feather/utils/status_codes.h b/bootloaders/feather/utils/status_codes.h deleted file mode 100644 index 29bbf4166..000000000 --- a/bootloaders/feather/utils/status_codes.h +++ /dev/null @@ -1,138 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#ifndef STATUS_CODES_H_INCLUDED -#define STATUS_CODES_H_INCLUDED - -#include - -/** - * \defgroup group_sam0_utils_status_codes Status Codes - * - * \ingroup group_sam0_utils - * - * @{ - */ - -/** Mask to retrieve the error category of a status code. */ -#define STATUS_CATEGORY_MASK 0xF0 - -/** Mask to retrieve the error code within the category of a status code. */ -#define STATUS_ERROR_MASK 0x0F - -/** Status code error categories. */ -enum status_categories { - STATUS_CATEGORY_OK = 0x00, - STATUS_CATEGORY_COMMON = 0x10, - STATUS_CATEGORY_ANALOG = 0x30, - STATUS_CATEGORY_COM = 0x40, - STATUS_CATEGORY_IO = 0x50, -}; - -/** - * Status code that may be returned by shell commands and protocol - * implementations. - * - * \note Any change to these status codes and the corresponding - * message strings is strictly forbidden. New codes can be added, - * however, but make sure that any message string tables are updated - * at the same time. - */ -enum status_code { - STATUS_OK = STATUS_CATEGORY_OK | 0x00, - STATUS_VALID_DATA = STATUS_CATEGORY_OK | 0x01, - STATUS_NO_CHANGE = STATUS_CATEGORY_OK | 0x02, - STATUS_ABORTED = STATUS_CATEGORY_OK | 0x04, - STATUS_BUSY = STATUS_CATEGORY_OK | 0x05, - STATUS_SUSPEND = STATUS_CATEGORY_OK | 0x06, - - STATUS_ERR_IO = STATUS_CATEGORY_COMMON | 0x00, - STATUS_ERR_REQ_FLUSHED = STATUS_CATEGORY_COMMON | 0x01, - STATUS_ERR_TIMEOUT = STATUS_CATEGORY_COMMON | 0x02, - STATUS_ERR_BAD_DATA = STATUS_CATEGORY_COMMON | 0x03, - STATUS_ERR_NOT_FOUND = STATUS_CATEGORY_COMMON | 0x04, - STATUS_ERR_UNSUPPORTED_DEV = STATUS_CATEGORY_COMMON | 0x05, - STATUS_ERR_NO_MEMORY = STATUS_CATEGORY_COMMON | 0x06, - STATUS_ERR_INVALID_ARG = STATUS_CATEGORY_COMMON | 0x07, - STATUS_ERR_BAD_ADDRESS = STATUS_CATEGORY_COMMON | 0x08, - STATUS_ERR_BAD_FORMAT = STATUS_CATEGORY_COMMON | 0x0A, - STATUS_ERR_BAD_FRQ = STATUS_CATEGORY_COMMON | 0x0B, - STATUS_ERR_DENIED = STATUS_CATEGORY_COMMON | 0x0c, - STATUS_ERR_ALREADY_INITIALIZED = STATUS_CATEGORY_COMMON | 0x0d, - STATUS_ERR_OVERFLOW = STATUS_CATEGORY_COMMON | 0x0e, - STATUS_ERR_NOT_INITIALIZED = STATUS_CATEGORY_COMMON | 0x0f, - - STATUS_ERR_SAMPLERATE_UNAVAILABLE = STATUS_CATEGORY_ANALOG | 0x00, - STATUS_ERR_RESOLUTION_UNAVAILABLE = STATUS_CATEGORY_ANALOG | 0x01, - - STATUS_ERR_BAUDRATE_UNAVAILABLE = STATUS_CATEGORY_COM | 0x00, - STATUS_ERR_PACKET_COLLISION = STATUS_CATEGORY_COM | 0x01, - STATUS_ERR_PROTOCOL = STATUS_CATEGORY_COM | 0x02, - - STATUS_ERR_PIN_MUX_INVALID = STATUS_CATEGORY_IO | 0x00, -}; -typedef enum status_code status_code_genare_t; - -/** - Status codes used by MAC stack. - */ -enum status_code_wireless { - //STATUS_OK = 0, //!< Success - ERR_IO_ERROR = -1, //!< I/O error - ERR_FLUSHED = -2, //!< Request flushed from queue - ERR_TIMEOUT = -3, //!< Operation timed out - ERR_BAD_DATA = -4, //!< Data integrity check failed - ERR_PROTOCOL = -5, //!< Protocol error - ERR_UNSUPPORTED_DEV = -6, //!< Unsupported device - ERR_NO_MEMORY = -7, //!< Insufficient memory - ERR_INVALID_ARG = -8, //!< Invalid argument - ERR_BAD_ADDRESS = -9, //!< Bad address - ERR_BUSY = -10, //!< Resource is busy - ERR_BAD_FORMAT = -11, //!< Data format not recognized - ERR_NO_TIMER = -12, //!< No timer available - ERR_TIMER_ALREADY_RUNNING = -13, //!< Timer already running - ERR_TIMER_NOT_RUNNING = -14, //!< Timer not running - - /** - * \brief Operation in progress - * - * This status code is for driver-internal use when an operation - * is currently being performed. - * - * \note Drivers should never return this status code to any - * callers. It is strictly for internal use. - */ - OPERATION_IN_PROGRESS = -128, -}; - -typedef enum status_code_wireless status_code_t; - -/** @} */ - -#endif /* STATUS_CODES_H_INCLUDED */ From 83834c322d5f2e41bfde143894a2d8dfb05c5a0b Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 5 Mar 2016 21:28:46 -0500 Subject: [PATCH 22/22] feather bootloader files --- bootloaders/feather/samd21_sam_ba.bin | Bin 0 -> 6136 bytes bootloaders/feather/samd21_sam_ba.hex | 386 ++++++++++++++++++++++++++ 2 files changed, 386 insertions(+) create mode 100644 bootloaders/feather/samd21_sam_ba.bin create mode 100644 bootloaders/feather/samd21_sam_ba.hex diff --git a/bootloaders/feather/samd21_sam_ba.bin b/bootloaders/feather/samd21_sam_ba.bin new file mode 100644 index 0000000000000000000000000000000000000000..331adde78ca5d7be378390d93c9be8db40ceb326 GIT binary patch literal 6136 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%0AEg*(Ah!_ZRK+!WUF>R zv?n<>>06l2h$TmN}AXLV);cQ_EZR4p(kVD0!4Aw8DV5Y@_Lx3y~ z`sxwx2obK=l{>;UzEO#Zb4seG2-&dWhfr(KbgIUr)XfYzCFi5ZAtPLB|99VbZU)S+ zN7$n*@dXlDLLoP;5)~7P9KpgDDkjjoN{|Znvn{4oJSxtWCvzUj^XR{zHS*Z2Zxhf{ z2Tc2e#E1Us0?DA|Qt~rs_7WVJGym(pf=9msxo1$NgK?aqKJK$|<5GRCQEGi_5*BWZ zkSn0VuN_^%S+X}$0=K`)t9Y`3{;m(fp4Rfe>9Ch30sH_7Fdm@oJqC~u@B+#J+MeX0 z%?|Aw-~?#

T=Kq5h|U8GtB&0aO8q7gTjIlsiCX7JTafOMsqGJuw8{o!T=-Po}$+ zvC&h~{3U6{=z_7t>g=|!nZ0olM2u5DLHAORU`nmF2Ud!NFL(7ik56>LUZr>!cv@?4 zyi9@L<_LKp(NcLqfj%#sT2|nw$!`p>>ksy)?4a2|vqgWrtm?6Y z$b*|bV!LJo4^}3HZPKLh>cVW11sz`um(GPeVilnFcoP53HNt>6Mp zMti?2OLWJGX2>pNo%fD}0ouMlJXO)ZLb&{}W+PSHCPD6HRXq_BR??n;e0$hPsLA(+ zkHkEYJMBke*f&BZJD-Kuvp{4&+%rFC8zVij4)7y8XnS!Oc}PXm``j?m>4w`AA)~@V z(V}2D({RUqv{ZT_hFcEz=~KG}7y4=A&H3J1cQiR2-W!ppHAu?;Saxg?4qWZCc9HZZ zdn>%rIYb<|)~CJY4aB==54>r5^LMkwiXVPwVMGuR>N-3Y2z0Q=;2LIv!U}K#7=Q%O z>Qj73Kwq;VbOG=lz?OyJfd-*Cpeq}phoMz;eP%tzy{q<2F$-%HbJ>`X5;FI>K}Npyk<%5a*%adgU(g{EzAq^ z{>Jx-rj13r!h7#KwBxM5m` zSN?TrWj;H}sly}xYxO(7cz)K_MQdK*;@+)kPknXygKz)i_|DS{r!*GYM*9u_eE7Sc zJ$2WgW-tBox)&Y0%O3kUIo$WmKi_=kSm<)iuZ0&QjH%8}cs*tRIPvA#-+cD!)zG&3 zcJs@=*S@X&DE#Mjzg^Qn%`*qevx=|xoIiPF@OPg#b=GX3_6D{8_iG<}3sT3`js!Axc=~sK=I4nS&#Hg@`ohOUALJY< ze|5>Tktd?NUf%fbq0jfGCvJOd&NmPCO4hyTZT}^wZe9U1TfCQlZF5`e;J$NzyyGbS z;f6~qt{ftov#z*Ll}-+hT=2`4cQyWZ{NxKSJ+*D?1K-ZQJpS~E;}<6#&EGR}qwZ(F zs92r9NI$FR#cO|Vf9x;2@9A5g%zbD2KR+z|pDDWx2S?xivxgrZHG9%sRcG%%k#Tk6 zXMb=1Y}@0n?SFYz%}+yy$T*?f-fP-aw$JbdEg$1C((>0`g1p)UX6 zk&ioHef`MUCkCD!^T3q#i|71eMeBsvj6_C%p5`q#+%Sz`5rL6Zng-5@HTTu$BP-Uy xIj_$*Ags^F2pjdANfT1jbl~8rHz55+f`O+XJ)so{y{$R43Dv{@OpS)${{n`n4t4+l literal 0 HcmV?d00001 diff --git a/bootloaders/feather/samd21_sam_ba.hex b/bootloaders/feather/samd21_sam_ba.hex new file mode 100644 index 000000000..5ae649d9d --- /dev/null +++ b/bootloaders/feather/samd21_sam_ba.hex @@ -0,0 +1,386 @@ +:10000000FC7F0020E9050000D5050000D9050000AF +:1000100000000000000000000000000000000000E0 +:10002000000000000000000000000000DD050000EE +:100030000000000000000000E1050000E5050000F0 +:1000400010B5064C2378002B07D1054B002B02D0AE +:10005000044800E000BF0123237010BD5C000020B5 +:10006000000000009817000008B5084B002B03D0D3 +:100070000748084900E000BF07480368002B03D089 +:10008000064B002B00D0984708BDC046000000007A +:1000900098170000600000205800002000000000B9 +:1000A00010B5C3699C07FCD403680224A343036012 +:1000B000C46901231C42FBD1046823430360036825 +:1000C000DC07FCD4C46901231C42FBD1C469DC40B9 +:1000D0001C42F7D1084B1A430260C3695A07FCD48B +:1000E000C0239B0243608181C3699C07FCD40368E1 +:1000F00002221343036010BD04000040037EDA07B0 +:10010000FCD5018570470000027E01235107FBD515 +:10011000428B1A4207D1428BDA401A4203D1428BFA +:1001200092081A4202D0034B01221A70008DC0B20D +:100130007047C0467800002070B50368041C988B97 +:100140001A1C0821FF32084228D0988B174D014312 +:10015000802099839872112353704021144B917120 +:1001600050715E68C0202E40800506435E605E6967 +:100170003540284358610F4818600F4818615D6882 +:100180000E4828408025AD02284358605868800BEF +:100190008003586000235171237105E0137ADA0659 +:1001A00002D5201C00F0EEFA207970BDFFFFFF8F12 +:1001B000940100209400002014010020FF3F00F073 +:1001C000002303714371044B016083600B780222AA +:1001D00013430B707047C0463901000038B5364BE9 +:1001E0002021DA6901200A43DA61344B06241A78A7 +:1001F00002431A70324B0F22197891431970197803 +:10020000214319702F490C782043087019780A404F +:100210001A701A7860210A431A702B4B2B4A5A80A5 +:100220005A7852B2002AFBDB294B01211A780A4383 +:100230001A709A78D107FCD426480268510B1F2205 +:100240001140914200D1052111408C011D8D2249A0 +:100250002940214319850468A10C0A401F2A00D1B6 +:100260001D221C8D1F210A408C4322431A850268DF +:100270000721D20D0A408A4200D103220A40188D7C +:100280001103164A02400A431A8519787F220A4050 +:100290001A701A78042112480A431A7058621A898F +:1002A0000C218A431A811A8901218A431A8100216B +:1002B000802201F006F938BD000400405844004196 +:1002C0003C44004159440041000C004006400000FD +:1002D00000500041246080003FF8FFFFFF8FFFFFC8 +:1002E00094010020F7B5141C234A5F0101971D1CDF +:1002F000D319061C5869271C4000400F03301033E7 +:10030000C74006D00F1C8022596812060A435A6063 +:1003100009E02F1C7B1E9F41184BBF01FF18381CA2 +:10032000221C01F0C5F801991348083542181761DD +:10033000131C5269A104920B890C92030A435A615F +:1003400059690F4A02200A405A616B01F318D979A2 +:10035000032211400143D8799043021C0A43DA7109 +:100360005979802252420A435A716B01F318DB79A2 +:100370009A07FAD5201CFEBD94010020140100202C +:10038000FF3F00F0F8B51E4E041C3378151C002BFF +:1003900012D11C4B1C4A1A645A6C920B92035A6479 +:1003A000586C1A4A02405A64A2235B00E25C402067 +:1003B0000243E254012333704827FF37E25D0123F3 +:1003C00013401AD00F4B5A6C9204920CAA4202D2DC +:1003D0005D6CAD04AD0C081C2A1C0B4901F068F8DB +:1003E000E25D03231A4001210A43E15D99430B1C9E +:1003F0001343E3550023337000E01D1C281CF8BD97 +:100400007900002094010020D4000020FF3F00F07C +:10041000FF30827930239A43131C2022002900D117 +:1004200010221343837170470C4BFF305A6902212D +:10043000920B92035A61027A03231A400A43017A0B +:1004400099430B1C13430372827980235B4213434D +:100450008371037A9A07FCD57047C0469401002047 +:1004600080235B421943C9B28172704770B5A023E3 +:1004700003225B00C254134B134A5C6CC02114402E +:1004800089050C4346255C64FF35402444550F4DD7 +:1004900030261D6490256D0046555D6B154029433F +:1004A000922559636D0080214155094D1D63B0258A +:1004B0006D0044555C6F22405A67B2235B00C15403 +:1004C00070BDC04694010020FFFFFF8FD4000020C4 +:1004D0005401002030B5364A1E2351680820994344 +:1004E00002231943516033498A6902438A613248C1 +:1004F000324A9082908A03439382D3689807FCD54E +:100500002F4B012018701878C40704D52C48407868 +:1005100040B20028F7DB01209860587840B20028EC +:10052000FBDB284C26484460587840B20028FBDBAF +:1005300082242348E4014480587840B20028FBDB41 +:10054000908C8024A0439084D068C506FCD51E4CB6 +:100550001A48C462D4681948E506FBD5848C1B4D43 +:100560002C438484D4681548E506FBD5848C022589 +:100570002C438484D0680406FCD51048C068450626 +:10058000F8D5D068C406FCD500229A605A7852B2D9 +:10059000002AFBDB0E480A4A50605A7852B2002A01 +:1005A000FBDB00230B724B728B72CB7230BDC046EB +:1005B00000400041000400400C060000000800401C +:1005C000000C004001050100B805FF7D040A000091 +:1005D000000703000EBEFEE70DBEFEE705BEFEE708 +:1005E00002BEFEE701BEFEE70E4A0F4838B5824262 +:1005F00004D10E4A0E4B93420ED10AE00D4C9442A8 +:10060000F7D00023D1188842F3D9E55804330D60A0 +:10061000F8E700F04DF804E09342FAD2002102C35B +:10062000FAE7FEE7000000205C000020A0030020A5 +:100630005C0000209C170000194A10B51188FA24AC +:10064000013189B2174BA400A14201D011801CE0F6 +:1006500000211180144900240C5760431C880019A4 +:1006600080B204B2FF2C01DC188002E0FF20188069 +:1006700008700024185F002803DA00201880012089 +:1006800008708020094980028861128800215B5E21 +:100690009A4203D18022054B92025A6110BDC04696 +:1006A0007A0000207C00002000000020004400416F +:1006B00038B580222B4B92029A605A612A4A1C1C40 +:1006C000117801221140294B002200290AD1186813 +:1006D000274A904201D1196018E01A60254A013A70 +:1006E000002AFCD11A60244B1A68191C501C0DD02A +:1006F000D8B200280AD180208002A06182F3088845 +:10070000FF2293431D4A93604B681847FFF7E2FEB0 +:1007100062B600F0FBFC00F0CFF980239B02051CC1 +:10072000A3610320FFF788FFAB68281C9847144B90 +:10073000002801D001221A701A78002A05D0002062 +:1007400000F036FA00F092FAFCE71B78002BE8D1B3 +:1007500000F050FD0028E4D0012000F029FA00F05C +:1007600085FAFCE70044004138040040FC7F00208B +:100770003581730748E801000020000000ED00E02B +:100780007E000020F8B50468051C201CFF30037AA9 +:10079000B64A10210B430372B54F1378B5493B702D +:1007A0005378B54E0B7093783380D1783388090233 +:1007B0000B4333801179B14B198051791F8809029D +:1007C0000F431F809779AE490F80D2790F881202AC +:1007D0003A430A8040224271A648A54F02783878F1 +:1007E000A84F12020243181CBA4200D199E01EDC45 +:1007F000802149008A4200D158E107DC812A6AD071 +:10080000822A6ED0802A00D050E164E081235B0010 +:100810009A4200D1AFE000DA23E1C0239B009A4264 +:1008200000D143E1984B9A4200D11AE13EE1902376 +:100830001B019A4242D015DCD023DB009A4222D021 +:1008400088231B019A4242D0A023DB009A4200D0A9 +:100850002CE1201CFFF7E8FD3188286889B2FFF7FA +:10086000FFFD27E1894B9A4200D1FAE000DC1DE14F +:10087000874B9A4200D1E8E0864B9A4200D015E1BE +:1008800033886B71EDE033881B0A012B08D10B888C +:1008900012222868934201D80A8892B27E49DCE08D +:1008A00033881B0A022B00D000E10B884322286802 +:1008B000934201D80A8892B27849CEE03388201C4E +:1008C0002B71FFF7B1FD201CFFF7D0FDF2E0291CD2 +:1008D00001C90122C1E0724900230B80286802226D +:1008E000BCE06F4900220A801888502210406D4AEF +:1008F00010701E880F20304018801888032800D9F7 +:10090000D4E012781B8808335B01E418A379002A2D +:1009100001D09B0600E0DB06DB0F0B80286802227B +:100920009BE019887F2291435E4AC9B211701888F2 +:100930000F21014019803188002900D0B6E01988C4 +:10094000002900D1B2E01988032900D9AEE012785D +:100950001B8808335B01E318002A05D05A7930213F +:100960008A4320210A4304E05A7930218A43102027 +:1009700002435A7175E002887F239A43494BD2B2F1 +:100980001A7001880F220A4002803288002A00D0A3 +:100990008CE00288002A00D188E00288032A00D96E +:1009A00084E01B78002B27D0038808335B01E31811 +:1009B0009B79990655D50388302108335B01E318EC +:1009C0001A798A4320210A431A71038808335B018C +:1009D000E318DB795A0644D50388602108335B01AC +:1009E000E318DA798A4340210A43DA710388022244 +:1009F00008335B01E31826E0038808335B01E31842 +:100A00009B79DF062DD50388302108335B01E3187D +:100A10001A798A4310210A431A71038808335B014B +:100A2000E318DB7999061CD50388602108335B0144 +:100A3000E318DA798A4320210A43DA710388012214 +:100A400008335B01E3181A710BE00B880822286851 +:100A5000934201D80A8892B213490023FFF742FC5F +:100A600028E0201CFFF7E0FC24E0C04694000020B2 +:100A7000890000207F0000208000002084000020EA +:100A80008600002002030000010300002120000076 +:100A9000A121000021220000EC140000040000202D +:100AA000820000208800002048000020201C012136 +:100AB000FFF7AEFCF8BDC04610B5054B054C2360F2 +:100AC000FFF78CFB201C2168FFF77AFB201C10BD70 +:100AD000005000411402002007B5054B012201908F +:100AE00001A91868131CFFF7FDFB01200EBDC046CD +:100AF0001402002013B5054B6C4607341868211CFE +:100B00000122FFF73FFC207816BDC04614020020EA +:100B100010B5074C201CFFF70FFB031C002083427D +:100B200005D022684823FF33D05C0123184010BD54 +:100B30001402002010B5054A0C1C031C191C106877 +:100B40000123221CFFF7CEFB201C10BD1402002045 +:100B500070B5084C061C201C0D1CFFF7EDFA002395 +:100B6000984205D02068311C2A1CFFF70BFC031C9F +:100B7000181C70BD14020020F8B50C4C051C201C7C +:100B80000E1CFFF7D9FA0023271C341C98420AD008 +:100B9000002C07D0291C221C3868FFF7F3FB241A0D +:100BA0002D18F5E7331C181CF8BDC04614020020B0 +:100BB000012805D1054B064A1A60064B187004E05F +:100BC000002802D1044A014B1A60704784020020B9 +:100BD00020150000910000206C15000030B51A4B64 +:100BE00085B01B78002B29D0042901D1026804E0CC +:100BF000022901D1028800E00278490004A84318C4 +:100C00000B3B5C1AA3420BD00F201040092802D8DE +:100C10003025284300E0373018701209013BF1E716 +:100C200001A830230370782343700A2243189A7076 +:100C30000D22DA70054B04311B6801E0034B1B6881 +:100C4000DB68984705B030BD90000020840200208A +:100C500072B6EFF30883044A1360036883F30888CD +:100C6000436818477047C04688020020F0B58FB02F +:100C700006A9CE4A0B1C31CA31C351CA51C360CA3E +:100C800060C3CB4CCB48A3687A255B035B0F9B000A +:100C90005B58C9490360A26892B253430A60C749CE +:100CA000C74A0B6000231360C64B1D700320FFF77B +:100CB000C3FCC54BC54D1B68281C1B6940219847C8 +:100CC000C34B00221860C34B1D60C34BC24DC04FC5 +:100CD0001A60286839688842E8D2BE4B1B681A78C7 +:100CE000FF2A00D1F6E1232A00D0CDE1BB4E3378B4 +:100CF000002B05D0B44BBA481B680221DB6898472B +:100D0000B04B1B78532B38D13B682A6893421ED9CD +:100D1000B04801322A609A1AB24B01681B6801314F +:100D20000160B14E9A4201D2326000E03360A448C3 +:100D300032680068029000F0BBFB336829685A18DB +:100D40002A60A44A1668F1181160A84A13702B682B +:100D5000013B2B609F4B1A68013A1A60A34BA14AD2 +:100D60001B7811688B4206D2974A95481268006832 +:100D7000C91A92699047C04675E1522B07D1904A33 +:100D8000914B10681B68974A5B6911686AE14F2BA9 +:100D900005D18B4B934A1B6812681A7063E1482B8C +:100DA00005D1874B8F4A1B6812681A805BE1572B6D +:100DB00005D1834B8B4A1B6812681A6053E16F2B75 +:100DC00003D17F4B0121186807E0682B08D17C4BC9 +:100DD00084481B6802211B880360FFF7FFFE42E185 +:100DE000772B06D1764B7F481B6804211B68036074 +:100DF000F3E7472B13D17B4B1868FFF729FF7C4B98 +:100E00001B6883F3088862B67A4B1B78002B00D1ED +:100E100029E16D4B06201B681B68984723E1542B82 +:100E200004D101233370684B1B685CE04E2B0BD15F +:100E30003378002B05D1644B69481B680221DB68BD +:100E40009847002333700EE1562B50D15E4D01219F +:100E50002B686948DB6898472B680321DB68674883 +:100E60009847674E2B68301CDB68012198472B6838 +:100E70000D21DB68634898472B68301CDB68012133 +:100E80009847544F604B544E3B60002333603A1CEC +:100E9000311C1368581C10601B780393002B03D07F +:100EA0000B6801330B60F4E72B683168DB68564848 +:100EB00098472B685248DB680121984703983060B7 +:100EC00052483860434A1368591C11601A78424BE3 +:100ED000002A03D01A6801321A60F3E72A681968F9 +:100EE000D36898472B68DB683D480221BAE03D4A49 +:100EF000582B15D12F4E314D366813682A68B10032 +:100F0000934208D25808E06141482080207DC507FF +:100F1000FCD55B18F4E72C4B3E481B68DB68A0E06F +:100F2000592B33D11268264B3B49002A02D11B684A +:100F30000B6026E00868196863688025AB43920857 +:100F40006360002A1DD0354B2380237DDE07FCD54E +:100F50000023184D2D680095AD08AB4202D3304DEB +:100F6000258006E09342FAD09D00465901334E5148 +:100F7000EFE7257DEE07FCD59D0049194019D21AEF +:100F8000DFE7114B27481B68DB686AE05A2B6AD100 +:100F90000B4B17681D680026EF19BD4244D0287816 +:100FA000311C00F049F90135061CF6E70015000078 +:100FB000004000413C0200203402002030020020AA +:100FC000800200202C020020840200204002002029 +:100FD0002402002028020020380200209000002077 +:100FE000601500008C0200209002002020020020EA +:100FF00088020020910000203C15000065150000CB +:101000003E15000088150000401500004C1500003A +:1010100002A5FFFF551500008C00002044A5FFFF2E +:1010200004A5FFFF591500002E4D2F482B68012104 +:10103000DB68984707230F223240111C36093031F4 +:10104000092A00DD07311020C0186A468154013B8F +:10105000F1D22B6804A8DB68082198472B68234845 +:10106000DB6803219847224D7A232B70214B002205 +:101070001A60214B1B7893422CD01A4B01211B681C +:101080001E48DB68984725E0111C3039C8B2194B5F +:10109000092804D81E683201114319601AE0111C96 +:1010A0004139052903D81868373A010106E0111CB7 +:1010B0006139052904D81D68573A29010A4308E017 +:1010C0002C2A03D10E4A1E68166001E008490A70F6 +:1010D00000221A600B4B1A6801321A600A4B1A6818 +:1010E0000132F3E5840200205D1500005F15000069 +:1010F0002C0200208C0200209000002063150000CC +:1011000080020020380200202802002010B51C4B6D +:1011100001201A78022402431A701A4B0F22197800 +:101120009143197019782143197017490C7820439D +:10113000087019780A401A701A7820210A431A7028 +:10114000124B04211A6A0A431A62114B114A5A803F +:101150005A7852B2002AFBDBC4220F480F4992038F +:10116000FEF79EFF0E4A002313700E4A13700E4ABC +:1011700013700E4A13700E4A13700E4A137010BD8E +:101180004A440041354400414B44004100040040C2 +:10119000000C004014400000000800422AF6000045 +:1011A000940200201B0300209502002098020020DA +:1011B0001C0300201903002008B5C1B20248FEF745 +:1011C0009DFF012008BDC04600080042024B187E6A +:1011D0004007C00F7047C0460008004208B5FFF73F +:1011E000F5FF0028FBD00248FEF78EFF08BDC04681 +:1011F0000008004208B5FFF7E9FF0023984205D038 +:10120000FFF7ECFF031C233B5A425341181C08BD57 +:1012100070B5041C0D1C4618B44204D02078FFF7AA +:10122000CBFF0134F8E7281C70BD10B5041CFFF794 +:10123000D5FF2070012010BD0B0A5840034B400021 +:10124000C05A0902484080B27047C0469615000057 +:10125000F7B50024051C0F1C261CBC4220D0FFF74C +:10126000BDFF114BC0B21B780190002B1AD1311C6D +:10127000FFF7E2FF0D4B061C1A88002A04D10C4A26 +:1012800011782A1C002907D001996A1C2970802F27 +:1012900002D11988013919800134A4B2151CDCE788 +:1012A000301C00E00120FEBD190300209602002042 +:1012B0001A030020F0B53E4E85B0002203900C1CAE +:1012C00032703C4B914201D1012201E03A490C803D +:1012D0001A707F231C4201D080349C43FFF77EFFAD +:1012E0003378C0B2002B07D000253570FFF776FFAA +:1012F0003378C0B2AB4236D1432803D0712853D0E3 +:101300001528EBD1012300930120FFF755FF00982A +:10131000FFF752FF00998025C843C0B2FFF74CFF8A +:10132000039B00270293244A1388002B1DD12149D7 +:1013300001930978002918D10198FFF73DFF391C66 +:101340000198FFF779FF013D071C002DEBD1000A42 +:10135000C0B2FFF731FFF8B2FFF72EFFFFF73EFFF5 +:101360003378002B0AD035701FE00299013B0978D1 +:101370001380029B019101330293DDE7C0B206287E +:1013800007D1009B03990133DBB280310093803C8D +:101390000391002CB8D10420FFF70EFFFFF71EFFCA +:1013A000044B01251C7000E00025281C05B0F0BD91 +:1013B000190300201A03002096020020F0B5384CD3 +:1013C00087B0002301902370994201D1012301E0ED +:1013D000344A1180344A642613704320FFF7ECFE30 +:1013E000324FFFF7F3FE002803D1002F03D0013F57 +:1013F000F7E7002F03D1013E002EEED14DE001258D +:10140000FFF7ECFE2378002B38D1C0B20290012800 +:1014100005D004283DD10620FFF7CEFE39E005AE09 +:101420000221301CFFF714FF01988021FFF710FF05 +:1014300023780390002B18D1FFF7D0FE0702FFF7A7 +:10144000CDFEBFB223783F18BFB2012B0DD0039B56 +:101450009F4207D13378AB4204D1EB437278DBB2C1 +:101460009A4204D01820FFF7A7FE002303E00620CD +:10147000FFF7A2FE029B2278002A02D000262670E7 +:101480000BE0012B05D1019A6B1C8032DDB2019279 +:10149000B6E7054A002313700126301C07B0F0BDE3 +:1014A00019030020960200201A03002000350C00CA +:1014B00010B50023934203D0CC5CC4540133F9E748 +:1014C00010BD031C8218934202D019700133FAE751 +:1014D00070470000F8B5C046F8BC08BC9E4670478F +:1014E000F8B5C046F8BC08BC9E4670471201000221 +:1014F000020000409A230B000002000000010000DF +:101500000800000010000000200000004000000063 +:101510008000000000010000000200000004000044 +:10152000B9110000DD110000CD1100001112000002 +:101530002B120000B5120000BD1300007600200041 +:101540004D617220203520323031360032313A324E +:10155000383A333400580A0D00590A0D005A002356 +:101560000A0D003E00322E3000000000D90A0000B3 +:10157000F50A0000110B0000350B0000510B0000B4 +:10158000350B0000790B00005B41726475696E6F6A +:101590003A58595A5D0000002110422063308440BF +:1015A000A550C660E770088129914AA16BB18CC132 +:1015B000ADD1CEE1EFF13112100273325222B552A9 +:1015C0009442F772D662399318837BB35AA3BDD382 +:1015D0009CC3FFF3DEE36224433420040114E66479 +:1015E000C774A44485546AA54BB528850995EEE5D2 +:1015F000CFF5ACC58DD55336722611163006D77689 +:10160000F6669556B4465BB77AA719973887DFF721 +:10161000FEE79DD7BCC7C448E5588668A778400850 +:10162000611802282338CCC9EDD98EE9AFF9488971 +:1016300069990AA92BB9F55AD44AB77A966A711AE8 +:10164000500A333A122AFDDBDCCBBFFB9EEB799BC1 +:10165000588B3BBB1AABA66C877CE44CC55C222C38 +:10166000033C600C411CAEED8FFDECCDCDDD2AAD11 +:101670000BBD688D499D977EB66ED55EF44E133EC8 +:10168000322E511E700E9FFFBEEFDDDFFCCF1BBF61 +:101690003AAF599F788F8891A981CAB1EBA10CD13B +:1016A0002DC14EF16FE18010A100C230E320045043 +:1016B000254046706760B9839893FBA3DAB33DC3B6 +:1016C0001CD37FE35EF3B1029012F322D232354293 +:1016D000145277625672EAB5CBA5A89589856EF546 +:1016E0004FE52CD50DC5E234C324A01481046674E3 +:1016F000476424540544DBA7FAB79987B8975FE796 +:101700007EF71DC73CD7D326F2369106B016576632 +:101710007676154634564CD96DC90EF92FE9C8991D +:10172000E9898AB9ABA94458654806782768C01882 +:10173000E1088238A3287DCB5CDB3FEB1EFBF98BF5 +:10174000D89BBBAB9ABB754A545A376A167AF10AD2 +:10175000D01AB32A923A2EFD0FED6CDD4DCDAABD05 +:101760008BADE89DC98D267C076C645C454CA23C22 +:10177000832CE01CC10C1FEF3EFF5DCF7CDF9BAFD5 +:10178000BABFD98FF89F176E367E554E745E932E72 +:0C179000B23ED10EF01E00000000000070 +:10179C00010000000902430002010080320904002C +:1017AC0000010202000005240010010424020005BF +:1017BC00240600010524010001070583030800FF2E +:1017CC0009040100020A0000000705810240000024 +:1017DC00070502024000000000C2010000000800E2 +:0C17EC0069000000410000000000000047 +:04000003000005E90B +:00000001FF

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 RC_RoqQLmgSp&!-L{{fgVuU`NF literal 0 HcmV?d00001 diff --git a/bootloaders/zero/samd21_sam_ba.hex b/bootloaders/zero/samd21_sam_ba.hex new file mode 100644 index 000000000..1fde99e8a --- /dev/null +++ b/bootloaders/zero/samd21_sam_ba.hex @@ -0,0 +1,376 @@ +:10000000FC7F0020E9050000D5050000D9050000AF +:1000100000000000000000000000000000000000E0 +:10002000000000000000000000000000DD050000EE +:100030000000000000000000E1050000E5050000F0 +:1000400010B5064C2378002B07D1054B002B02D0AE +:10005000044800E000BF0123237010BD58000020B9 +:1000600000000000F816000008B5084B002B03D074 +:100070000748084900E000BF07480368002B03D089 +:10008000064B002B00D0984708BDC046000000007A +:10009000F81600005C000020540000200000000062 +:1000A00010B5C3699C07FCD403680224A343036012 +:1000B000C46901231C42FBD1046823430360036825 +:1000C000DC07FCD4C46901231C42FBD1C469DC40B9 +:1000D0001C42F7D1084B1A430260C3695A07FCD48B +:1000E000C0239B0243608181C3699C07FCD40368E1 +:1000F00002221343036010BD04000040037EDA07B0 +:10010000FCD5018570470000027E01235107FBD515 +:10011000428B1A4207D1428BDA401A4203D1428BFA +:1001200092081A4202D0034B01221A70008DC0B20D +:100130007047C0467400002070B50368041C988B9B +:100140001A1C0821FF32084228D0988B174D014312 +:10015000802099839872112353704021144B917120 +:1001600050715E68C0202E40800506435E605E6967 +:100170003540284358610F4818600F4818615D6882 +:100180000E4828408025AD02284358605868800BEF +:100190008003586000235171237105E0137ADA0659 +:1001A00002D5201C00F0A0FA207970BDFFFFFF8F60 +:1001B0008C0100208C0000200C010020FF3F00F08B +:1001C000002303714371044B016083600B780222AA +:1001D00013430B707047C0463901000038B5364BE9 +:1001E0002021DA6901200A43DA61344B06241A78A7 +:1001F00002431A70324B0F22197891431970197803 +:10020000214319702F490C782043087019780A404F +:100210001A701A7860210A431A702B4B2B4A5A80A5 +:100220005A7852B2002AFBDB294B01211A780A4383 +:100230001A709A78D107FCD426480268510B1F2205 +:100240001140914200D1052111408C011D8D2249A0 +:100250002940214319850468A10C0A401F2A00D1B6 +:100260001D221C8D1F210A408C4322431A850268DF +:100270000721D20D0A408A4200D103220A40188D7C +:100280001103164A02400A431A8519787F220A4050 +:100290001A701A78042112480A431A7058621A898F +:1002A0000C218A431A811A8901218A431A8100216B +:1002B000802201F0B6F838BD0004004058440041E7 +:1002C0003C44004159440041000C004006400000FD +:1002D00000500041246080003FF8FFFFFF8FFFFFC8 +:1002E0008C010020F7B5141C234A5F0101971D1CE7 +:1002F000D319061C5869271C4000400F03301033E7 +:10030000C74006D00F1C8022596812060A435A6063 +:1003100009E02F1C7B1E9F41184BBF01FF18381CA2 +:10032000221C01F075F8019913480835421817612D +:10033000131C5269A104920B890C92030A435A615F +:1003400059690F4A02200A405A616B01F318D979A2 +:10035000032211400143D8799043021C0A43DA7109 +:100360005979802252420A435A716B01F318DB79A2 +:100370009A07FAD5201CFEBD8C0100200C0100203C +:10038000FF3F00F0F8B51E4E041C3378151C002BFF +:1003900012D11C4B1C4A1A645A6C920B92035A6479 +:1003A000586C1A4A02405A64A2235B00E25C402067 +:1003B0000243E254012333704827FF37E25D0123F3 +:1003C00013401AD00F4B5A6C9204920CAA4202D2DC +:1003D0005D6CAD04AD0C081C2A1C0B4901F018F82B +:1003E000E25D03231A4001210A43E15D99430B1C9E +:1003F0001343E3550023337000E01D1C281CF8BD97 +:10040000750000208C010020CC000020FF3F00F090 +:10041000FF30827930239A43131C2022002900D117 +:1004200010221343837170470C4BFF305A6902212D +:10043000920B92035A61027A03231A400A43017A0B +:1004400099430B1C13430372827980235B4213434D +:100450008371037A9A07FCD57047C0468C0100204F +:1004600080235B421943C9B28172704770B5A023E3 +:1004700003225B00C254134B134A5C6CC02114402E +:1004800089050C4346255C64FF35402444550F4DD7 +:1004900030261D6490256D0046555D6B154029433F +:1004A000922559636D0080214155094D1D63B0258A +:1004B0006D0044555C6F22405A67B2235B00C15403 +:1004C00070BDC0468C010020FFFFFF8FCC000020D4 +:1004D0004C01002030B5364A1E235168082099434C +:1004E00002231943516033498A6902438A613248C1 +:1004F000324A9082908A03439382D3689807FCD54E +:100500002F4B012018701878C40704D52C48407868 +:1005100040B20028F7DB01209860587840B20028EC +:10052000FBDB284C26484460587840B20028FBDBAF +:1005300082242348E4014480587840B20028FBDB41 +:10054000908C8024A0439084D068C506FCD51E4CB6 +:100550001A48C462D4681948E506FBD5848C1B4D43 +:100560002C438484D4681548E506FBD5848C022589 +:100570002C438484D0680406FCD51048C068450626 +:10058000F8D5D068C406FCD500229A605A7852B2D9 +:10059000002AFBDB0E480A4A50605A7852B2002A01 +:1005A000FBDB00230B724B728B72CB7230BDC046EB +:1005B00000400041000400400C060000000800401C +:1005C000000C004001050100B805FF7D040A000091 +:1005D000000703000EBEFEE70DBEFEE705BEFEE708 +:1005E00002BEFEE701BEFEE70E4A0F4838B5824262 +:1005F00004D10E4A0E4B93420ED10AE00D4C9442A8 +:10060000F7D00023D1188842F3D9E55804330D60A0 +:10061000F8E700F011F804E09342FAD2002102C397 +:10062000FAE7FEE7000000205800002098030020B1 +:1006300058000020FC16000010B5244B0022197849 +:1006400001231940224B0AD11868224A904201D155 +:10065000196014E01A60204A013A002AFCD11A609D +:100660001E4B1968181C4A1C09D0FF22134206D1E0 +:1006700081F3088893431A4A936043681847FFF749 +:1006800029FF62B600F0F2FC00F0C8F9041CA36870 +:10069000201C9847134B002801D001221A701A78A9 +:1006A000002A05D0002000F035FA00F091FAFCE7AE +:1006B0001B78002BEBD100F04DFD0028E7D0012086 +:1006C00000F028FA00F084FAFCE7C0463804004045 +:1006D000FC7F00203581730748E8010000200000FE +:1006E00000ED00E076000020F8B50468051C201C31 +:1006F000FF30037AB64A10210B430372B54F1378CB +:10070000B5493B705378B54E0B7093783380D178F0 +:10071000338809020B4333801179B14B1980517929 +:100720001F8809020F431F809779AE490F80D27945 +:100730000F8812023A430A8040224271A648A54F10 +:1007400002783878A84F12020243181CBA4200D12E +:1007500099E01EDC802149008A4200D158E107DC83 +:10076000812A6AD0822A6ED0802A00D050E164E0CB +:1007700081235B009A4200D1AFE000DA23E1C0237D +:100780009B009A4200D143E1984B9A4200D11AE172 +:100790003EE190231B019A4242D015DCD023DB00BE +:1007A0009A4222D088231B019A4242D0A023DB0028 +:1007B0009A4200D02CE1201CFFF736FE31882868D1 +:1007C00089B2FFF74DFE27E1894B9A4200D1FAE04A +:1007D00000DC1DE1874B9A4200D1E8E0864B9A424B +:1007E00000D015E133886B71EDE033881B0A012BD3 +:1007F00008D10B8812222868934201D80A8892B245 +:100800007E49DCE033881B0A022B00D000E10B8814 +:1008100043222868934201D80A8892B27849CEE0F0 +:100820003388201C2B71FFF7FFFD201CFFF71EFEF5 +:10083000F2E0291C01C90122C1E0724900230B80AA +:1008400028680222BCE06F4900220A8018885022E2 +:1008500010406D4A10701E880F2030401880188894 +:10086000032800D9D4E012781B8808335B01E41810 +:10087000A379002A01D09B0600E0DB06DB0F0B808A +:10088000286802229BE019887F2291435E4AC9B200 +:10089000117018880F21014019803188002900D07B +:1008A000B6E01988002900D1B2E01988032900D9DF +:1008B000AEE012781B8808335B01E318002A05D0EC +:1008C0005A7930218A4320210A4304E05A793021A1 +:1008D0008A43102002435A7175E002887F239A43AD +:1008E000494BD2B21A7001880F220A400280328826 +:1008F000002A00D08CE00288002A00D188E002881B +:10090000032A00D984E01B78002B27D00388083302 +:100910005B01E3189B79990655D50388302108338C +:100920005B01E3181A798A4320210A431A7103886C +:1009300008335B01E318DB795A0644D5038860214C +:1009400008335B01E318DA798A4340210A43DA71FC +:100950000388022208335B01E31826E0038808338A +:100960005B01E3189B79DF062DD50388302108331E +:100970005B01E3181A798A4310210A431A7103882C +:1009800008335B01E318DB7999061CD503886021E5 +:1009900008335B01E318DA798A4320210A43DA71CC +:1009A0000388012208335B01E3181A710BE00B88FE +:1009B00008222868934201D80A8892B2134900237A +:1009C000FFF790FC28E0201CFFF72EFD24E0C04636 +:1009D0008C0000208100002077000020780000209B +:1009E0007C0000207E0000200203000001030000C4 +:1009F00021200000A1210000212200004C14000051 +:100A0000000000207A000020800000204400002028 +:100A1000201C0121FFF7FCFCF8BDC04610B5054BBA +:100A2000054C2360FFF7DAFB201C2168FFF7C8FBA9 +:100A3000201C10BD005000410C02002007B5054BE2 +:100A40000122019001A91868131CFFF74BFC01203B +:100A50000EBDC0460C02002013B5054B6C46073492 +:100A60001868211C0122FFF78DFC207816BDC046B6 +:100A70000C02002010B5074C201CFFF75DFB031C87 +:100A80000020834205D022684823FF33D05C012335 +:100A9000184010BD0C02002010B5054A0C1C031CA8 +:100AA000191C10680123221CFFF71CFC201C10BD20 +:100AB0000C02002070B5084C061C201C0D1CFFF712 +:100AC0003BFB0023984205D02068311C2A1CFFF70D +:100AD00059FC031C181C70BD0C020020F8B50C4C0E +:100AE000051C201C0E1CFFF727FB0023271C341CB1 +:100AF00098420AD0002C07D0291C221C3868FFF726 +:100B000041FC241A2D18F5E7331C181CF8BDC0460B +:100B10000C020020012805D1054B064A1A60064B3D +:100B2000187004E0002802D1044A014B1A60704793 +:100B30007C0200208014000089000020CC140000FA +:100B400030B51A4B85B01B78002B29D0042901D170 +:100B5000026804E0022901D1028800E0027849001D +:100B600004A843180B3B5C1AA3420BD00F20104083 +:100B7000092802D83025284300E0373018701209C0 +:100B8000013BF1E701A830230370782343700A2268 +:100B900043189A700D22DA70054B04311B6801E08E +:100BA000034B1B68DB68984705B030BD8800002008 +:100BB0007C02002072B6EFF30883044A13600368D6 +:100BC00083F30888436818477047C04680020020B6 +:100BD000F0B58FB006A9CD4A0B1C31CA31C351CA3A +:100BE00051C360CA60C3CA4CCA48A3687A255B0374 +:100BF0005B0F9B005B58C8490360A26892B25343E5 +:100C00000A60C649C64A0B6000231360C54B1D70BD +:100C1000C54BC64D1B68281C1B6940219847C44B17 +:100C200000221860C34B1D60C34BC34DC04F1A60F8 +:100C3000286839688842EBD2BE4B1B681A78FF2AB5 +:100C400000D1F7E1232A00D0CEE1BC4E3378002B4F +:100C500005D0B54BBA481B680221DB689847B14BF9 +:100C60001B78532B38D13B682A6893421ED9B14870 +:100C700001322A609A1AB34B01681B680131016086 +:100C8000B14E9A4201D2326000E03360A44832682B +:100C90000068029000F0BCFB336829685A182A608B +:100CA000A44A1668F1181160A84A13702B68013B1A +:100CB0002B60A04B1A68013A1A60A44BA14A1B781A +:100CC00011688B4206D2984A954812680068C91A82 +:100CD00092699047C04676E1522B07D1904A924BD9 +:100CE00010681B68974A5B6911686BE14F2B05D14F +:100CF0008B4B944A1B6812681A7064E1482B05D12B +:100D0000874B904A1B6812681A805CE1572B05D10B +:100D1000834B8C4A1B6812681A6054E16F2B03D115 +:100D20007F4B0121186807E0682B08D17C4B854870 +:100D30001B6802211B880360FFF702FF43E1772B4A +:100D400006D1774B7F481B6804211B680360F3E7DB +:100D5000472B13D17B4B1868FFF72CFF7C4B1B688C +:100D600083F3088862B67B4B1B78002B00D12AE105 +:100D70006D4B06201B681B68984724E1542B04D157 +:100D800001233370684B1B685CE04E2B0BD133782A +:100D9000002B05D1644B6A481B680221DB68984729 +:100DA000002333700FE1562B50D15F4D01212B688A +:100DB0006948DB6898472B680321DB6867489847D8 +:100DC000674E2B68301CDB68012198472B680D218A +:100DD000DB68644898472B68301CDB680121984722 +:100DE000544F614B544E3B60002333603A1C311C1E +:100DF0001368581C10601B780393002B03D00B68FA +:100E000001330B60F4E72B683168DB68564898477C +:100E10002B685348DB68012198470398306053489A +:100E20003860444A1368591C11601A78424B002AF2 +:100E300003D01A6801321A60F3E72A681968D36888 +:100E400098472B68DB683E480221BBE03D4A582B9F +:100E500015D1304E314D366813682A68B10093427F +:100E600008D25808E06142482080207DC507FCD5A3 +:100E70005B18F4E72C4B3F481B68DB68A1E0592B5B +:100E800033D11268264B3C49002A02D11B680B6003 +:100E900026E00868196863688025AB4392086360A0 +:100EA000002A1DD0354B2380237DDE07FCD500238F +:100EB000184D2D680095AD08AB4202D3304D25800A +:100EC00006E09342FAD09D00465901334E51EFE7B8 +:100ED000257DEE07FCD59D0049194019D21ADFE7A0 +:100EE000114B28481B68DB686BE05A2B6BD10C4B0D +:100EF00017681D680026EF19BD4245D02878311CBF +:100F000000F04AF90135061CF6E7C04660140000FF +:100F100000400041340200202C0200202802002062 +:100F200078020020240200207C02002038020020E9 +:100F30001C02002020020020300200208800002037 +:100F4000C014000084020020880200201802002043 +:100F500080020020890000209C140000C5140000BD +:100F60009E140000E8140000A0140000AC1400005F +:100F700002A5FFFFB51400008400002044A5FFFF78 +:100F800004A5FFFFB91400002E4D2F482B68012146 +:100F9000DB68984707230F223240111C3609303195 +:100FA000092A00DD07311020C0186A468154013B30 +:100FB000F1D22B6804A8DB68082198472B682348E6 +:100FC000DB6803219847224D7A232B70214B0022A6 +:100FD0001A60214B1B7893422CD01A4B01211B68BD +:100FE0001E48DB68984725E0111C3039C8B2194B00 +:100FF000092804D81E683201114319601AE0111C37 +:101000004139052903D81868373A010106E0111C57 +:101010006139052904D81D68573A29010A4308E0B7 +:101020002C2A03D10E4A1E68166001E008490A7096 +:1010300000221A600B4B1A6801321A600A4B1A68B8 +:101040000132F2E57C020020BD140000BF14000054 +:10105000240200208402002088000020C314000025 +:1010600078020020300200202002002010B51C4B26 +:1010700001201A78022402431A701A4B0F221978A1 +:101080009143197019782143197017490C7820433E +:10109000087019780A401A701A7820210A431A70C9 +:1010A000124B04211A6A0A431A62114B114A5A80E0 +:1010B0005A7852B2002AFBDBC4220F480F49920330 +:1010C000FEF7EEFF0E4A002313700E4A13700E4A0D +:1010D00013700E4A13700E4A13700E4A137010BD2F +:1010E0004A440041354400414B4400410004004063 +:1010F000000C0040144000000008004204C500003D +:101100008C020020130300208D020020900200209A +:10111000140300201103002008B5C1B20248FEF7F5 +:10112000EDFF012008BDC04600080042024B187EBA +:101130004007C00F7047C0460008004208B5FFF7DF +:10114000F5FF0028FBD00248FEF7DEFF08BDC046D1 +:101150000008004208B5FFF7E9FF0023984205D0D8 +:10116000FFF7ECFF031C233B5A425341181C08BDF8 +:1011700070B5041C0D1C4618B44204D02078FFF74B +:10118000CBFF0134F8E7281C70BD10B5041CFFF735 +:10119000D5FF2070012010BD0B0A5840034B4000C2 +:1011A000C05A0902484080B27047C046F614000099 +:1011B000F7B50024051C0F1C261CBC4220D0FFF7ED +:1011C000BDFF114BC0B21B780190002B1AD1311C0E +:1011D000FFF7E2FF0D4B061C1A88002A04D10C4AC7 +:1011E00011782A1C002907D001996A1C2970802FC8 +:1011F00002D11988013919800134A4B2151CDCE729 +:10120000301C00E00120FEBD110300208E020020F2 +:1012100012030020F0B53E4E85B0002203900C1C56 +:1012200032703C4B914201D1012201E03A490C80DD +:101230001A707F231C4201D080349C43FFF77EFF4D +:101240003378C0B2002B07D000253570FFF776FF4A +:101250003378C0B2AB4236D1432803D0712853D083 +:101260001528EBD1012300930120FFF755FF0098CB +:10127000FFF752FF00998025C843C0B2FFF74CFF2B +:10128000039B00270293244A1388002B1DD1214978 +:1012900001930978002918D10198FFF73DFF391C07 +:1012A0000198FFF779FF013D071C002DEBD1000AE3 +:1012B000C0B2FFF731FFF8B2FFF72EFFFFF73EFF96 +:1012C0003378002B0AD035701FE00299013B097872 +:1012D0001380029B019101330293DDE7C0B206281F +:1012E00007D1009B03990133DBB280310093803C2E +:1012F0000391002CB8D10420FFF70EFFFFF71EFF6B +:10130000044B01251C7000E00025281C05B0F0BD31 +:1013100011030020120300208E020020F0B5384C8B +:1013200087B0002301902370994201D1012301E08D +:10133000344A1180344A642613704320FFF7ECFED0 +:10134000324FFFF7F3FE002803D1002F03D0013FF7 +:10135000F7E7002F03D1013E002EEED14DE001252D +:10136000FFF7ECFE2378002B38D1C0B202900128A1 +:1013700005D004283DD10620FFF7CEFE39E005AEAA +:101380000221301CFFF714FF01988021FFF710FFA6 +:1013900023780390002B18D1FFF7D0FE0702FFF748 +:1013A000CDFEBFB223783F18BFB2012B0DD0039BF7 +:1013B0009F4207D13378AB4204D1EB437278DBB262 +:1013C0009A4204D01820FFF7A7FE002303E006206E +:1013D000FFF7A2FE029B2278002A02D00026267088 +:1013E0000BE0012B05D1019A6B1C8032DDB201921A +:1013F000B6E7054A002313700126301C07B0F0BD84 +:10140000110300208E0200201203002000350C0082 +:1014100010B50023934203D0CC5CC4540133F9E7E8 +:1014200010BD031C8218934202D019700133FAE7F1 +:1014300070470000F8B5C046F8BC08BC9E4670472F +:10144000F8B5C046F8BC08BC9E46704712010002C1 +:101450000200004041234D00000200000001000096 +:101460000800000010000000200000004000000004 +:1014700080000000000100000002000000040000E5 +:10148000191100003D1100002D1100007111000024 +:101490008B110000151200001D13000076002000C3 +:1014A0004F637420313020323031350031353A35D8 +:1014B000373A343500580A0D00590A0D005A0023F6 +:1014C0000A0D003E00322E30000000003D0A0000F0 +:1014D000590A0000750A0000990A0000B50A0000C8 +:1014E000990A0000DD0A00005B41726475696E6F45 +:1014F0003A58595A5D000000211042206330844060 +:10150000A550C660E770088129914AA16BB18CC1D2 +:10151000ADD1CEE1EFF13112100273325222B55249 +:101520009442F772D662399318837BB35AA3BDD322 +:101530009CC3FFF3DEE36224433420040114E66419 +:10154000C774A44485546AA54BB528850995EEE572 +:10155000CFF5ACC58DD55336722611163006D77629 +:10156000F6669556B4465BB77AA719973887DFF7C2 +:10157000FEE79DD7BCC7C448E5588668A7784008F1 +:10158000611802282338CCC9EDD98EE9AFF9488912 +:1015900069990AA92BB9F55AD44AB77A966A711A89 +:1015A000500A333A122AFDDBDCCBBFFB9EEB799B62 +:1015B000588B3BBB1AABA66C877CE44CC55C222CD9 +:1015C000033C600C411CAEED8FFDECCDCDDD2AADB2 +:1015D0000BBD688D499D977EB66ED55EF44E133E69 +:1015E000322E511E700E9FFFBEEFDDDFFCCF1BBF02 +:1015F0003AAF599F788F8891A981CAB1EBA10CD1DC +:101600002DC14EF16FE18010A100C230E3200450E3 +:10161000254046706760B9839893FBA3DAB33DC356 +:101620001CD37FE35EF3B1029012F322D232354233 +:10163000145277625672EAB5CBA5A89589856EF5E6 +:101640004FE52CD50DC5E234C324A0148104667483 +:10165000476424540544DBA7FAB79987B8975FE736 +:101660007EF71DC73CD7D326F2369106B0165766D3 +:101670007676154634564CD96DC90EF92FE9C899BE +:10168000E9898AB9ABA94458654806782768C01823 +:10169000E1088238A3287DCB5CDB3FEB1EFBF98B96 +:1016A000D89BBBAB9ABB754A545A376A167AF10A73 +:1016B000D01AB32A923A2EFD0FED6CDD4DCDAABDA6 +:1016C0008BADE89DC98D267C076C645C454CA23CC3 +:1016D000832CE01CC10C1FEF3EFF5DCF7CDF9BAF76 +:1016E000BABFD98FF89F176E367E554E745E932E13 +:0C16F000B23ED10EF01E00000000000011 +:1016FC0009024300020100803209040000010202C9 +:10170C000000052400100104240200052406000139 +:10171C000524010001070583030800FF09040100EB +:10172C00020A0000000705810240000007050202C2 +:10173C004000000000C20100000008006900000029 +:08174C00410000000000000054 +:04000003000005E90B +:00000001FF diff --git a/bootloaders/zero/samd21_sam_ba_genuino.bin b/bootloaders/zero/samd21_sam_ba_genuino.bin new file mode 100755 index 0000000000000000000000000000000000000000..47cd3cf0562c2fe28e2d2733f622e5d3be0c29b2 GIT binary patch literal 5972 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 Ugh~+liyF)Z)ByhrR33i+3t#BkDgXcg literal 0 HcmV?d00001 diff --git a/bootloaders/zero/samd21_sam_ba_genuino.hex b/bootloaders/zero/samd21_sam_ba_genuino.hex new file mode 100644 index 000000000..c1aef61b0 --- /dev/null +++ b/bootloaders/zero/samd21_sam_ba_genuino.hex @@ -0,0 +1,376 @@ +:10000000FC7F0020E9050000D5050000D9050000AF +:1000100000000000000000000000000000000000E0 +:10002000000000000000000000000000DD050000EE +:100030000000000000000000E1050000E5050000F0 +:1000400010B5064C2378002B07D1054B002B02D0AE +:10005000044800E000BF0123237010BD58000020B9 +:1000600000000000F816000008B5084B002B03D074 +:100070000748084900E000BF07480368002B03D089 +:10008000064B002B00D0984708BDC046000000007A +:10009000F81600005C000020540000200000000062 +:1000A00010B5C3699C07FCD403680224A343036012 +:1000B000C46901231C42FBD1046823430360036825 +:1000C000DC07FCD4C46901231C42FBD1C469DC40B9 +:1000D0001C42F7D1084B1A430260C3695A07FCD48B +:1000E000C0239B0243608181C3699C07FCD40368E1 +:1000F00002221343036010BD04000040037EDA07B0 +:10010000FCD5018570470000027E01235107FBD515 +:10011000428B1A4207D1428BDA401A4203D1428BFA +:1001200092081A4202D0034B01221A70008DC0B20D +:100130007047C0467400002070B50368041C988B9B +:100140001A1C0821FF32084228D0988B174D014312 +:10015000802099839872112353704021144B917120 +:1001600050715E68C0202E40800506435E605E6967 +:100170003540284358610F4818600F4818615D6882 +:100180000E4828408025AD02284358605868800BEF +:100190008003586000235171237105E0137ADA0659 +:1001A00002D5201C00F0A0FA207970BDFFFFFF8F60 +:1001B0008C0100208C0000200C010020FF3F00F08B +:1001C000002303714371044B016083600B780222AA +:1001D00013430B707047C0463901000038B5364BE9 +:1001E0002021DA6901200A43DA61344B06241A78A7 +:1001F00002431A70324B0F22197891431970197803 +:10020000214319702F490C782043087019780A404F +:100210001A701A7860210A431A702B4B2B4A5A80A5 +:100220005A7852B2002AFBDB294B01211A780A4383 +:100230001A709A78D107FCD426480268510B1F2205 +:100240001140914200D1052111408C011D8D2249A0 +:100250002940214319850468A10C0A401F2A00D1B6 +:100260001D221C8D1F210A408C4322431A850268DF +:100270000721D20D0A408A4200D103220A40188D7C +:100280001103164A02400A431A8519787F220A4050 +:100290001A701A78042112480A431A7058621A898F +:1002A0000C218A431A811A8901218A431A8100216B +:1002B000802201F0B6F838BD0004004058440041E7 +:1002C0003C44004159440041000C004006400000FD +:1002D00000500041246080003FF8FFFFFF8FFFFFC8 +:1002E0008C010020F7B5141C234A5F0101971D1CE7 +:1002F000D319061C5869271C4000400F03301033E7 +:10030000C74006D00F1C8022596812060A435A6063 +:1003100009E02F1C7B1E9F41184BBF01FF18381CA2 +:10032000221C01F075F8019913480835421817612D +:10033000131C5269A104920B890C92030A435A615F +:1003400059690F4A02200A405A616B01F318D979A2 +:10035000032211400143D8799043021C0A43DA7109 +:100360005979802252420A435A716B01F318DB79A2 +:100370009A07FAD5201CFEBD8C0100200C0100203C +:10038000FF3F00F0F8B51E4E041C3378151C002BFF +:1003900012D11C4B1C4A1A645A6C920B92035A6479 +:1003A000586C1A4A02405A64A2235B00E25C402067 +:1003B0000243E254012333704827FF37E25D0123F3 +:1003C00013401AD00F4B5A6C9204920CAA4202D2DC +:1003D0005D6CAD04AD0C081C2A1C0B4901F018F82B +:1003E000E25D03231A4001210A43E15D99430B1C9E +:1003F0001343E3550023337000E01D1C281CF8BD97 +:10040000750000208C010020CC000020FF3F00F090 +:10041000FF30827930239A43131C2022002900D117 +:1004200010221343837170470C4BFF305A6902212D +:10043000920B92035A61027A03231A400A43017A0B +:1004400099430B1C13430372827980235B4213434D +:100450008371037A9A07FCD57047C0468C0100204F +:1004600080235B421943C9B28172704770B5A023E3 +:1004700003225B00C254134B134A5C6CC02114402E +:1004800089050C4346255C64FF35402444550F4DD7 +:1004900030261D6490256D0046555D6B154029433F +:1004A000922559636D0080214155094D1D63B0258A +:1004B0006D0044555C6F22405A67B2235B00C15403 +:1004C00070BDC0468C010020FFFFFF8FCC000020D4 +:1004D0004C01002030B5364A1E235168082099434C +:1004E00002231943516033498A6902438A613248C1 +:1004F000324A9082908A03439382D3689807FCD54E +:100500002F4B012018701878C40704D52C48407868 +:1005100040B20028F7DB01209860587840B20028EC +:10052000FBDB284C26484460587840B20028FBDBAF +:1005300082242348E4014480587840B20028FBDB41 +:10054000908C8024A0439084D068C506FCD51E4CB6 +:100550001A48C462D4681948E506FBD5848C1B4D43 +:100560002C438484D4681548E506FBD5848C022589 +:100570002C438484D0680406FCD51048C068450626 +:10058000F8D5D068C406FCD500229A605A7852B2D9 +:10059000002AFBDB0E480A4A50605A7852B2002A01 +:1005A000FBDB00230B724B728B72CB7230BDC046EB +:1005B00000400041000400400C060000000800401C +:1005C000000C004001050100B805FF7D040A000091 +:1005D000000703000EBEFEE70DBEFEE705BEFEE708 +:1005E00002BEFEE701BEFEE70E4A0F4838B5824262 +:1005F00004D10E4A0E4B93420ED10AE00D4C9442A8 +:10060000F7D00023D1188842F3D9E55804330D60A0 +:10061000F8E700F011F804E09342FAD2002102C397 +:10062000FAE7FEE7000000205800002098030020B1 +:1006300058000020FC16000010B5244B0022197849 +:1006400001231940224B0AD11868224A904201D155 +:10065000196014E01A60204A013A002AFCD11A609D +:100660001E4B1968181C4A1C09D0FF22134206D1E0 +:1006700081F3088893431A4A936043681847FFF749 +:1006800029FF62B600F0F2FC00F0C8F9041CA36870 +:10069000201C9847134B002801D001221A701A78A9 +:1006A000002A05D0002000F035FA00F091FAFCE7AE +:1006B0001B78002BEBD100F04DFD0028E7D0012086 +:1006C00000F028FA00F084FAFCE7C0463804004045 +:1006D000FC7F00203581730748E8010000200000FE +:1006E00000ED00E076000020F8B50468051C201C31 +:1006F000FF30037AB64A10210B430372B54F1378CB +:10070000B5493B705378B54E0B7093783380D178F0 +:10071000338809020B4333801179B14B1980517929 +:100720001F8809020F431F809779AE490F80D27945 +:100730000F8812023A430A8040224271A648A54F10 +:1007400002783878A84F12020243181CBA4200D12E +:1007500099E01EDC802149008A4200D158E107DC83 +:10076000812A6AD0822A6ED0802A00D050E164E0CB +:1007700081235B009A4200D1AFE000DA23E1C0237D +:100780009B009A4200D143E1984B9A4200D11AE172 +:100790003EE190231B019A4242D015DCD023DB00BE +:1007A0009A4222D088231B019A4242D0A023DB0028 +:1007B0009A4200D02CE1201CFFF736FE31882868D1 +:1007C00089B2FFF74DFE27E1894B9A4200D1FAE04A +:1007D00000DC1DE1874B9A4200D1E8E0864B9A424B +:1007E00000D015E133886B71EDE033881B0A012BD3 +:1007F00008D10B8812222868934201D80A8892B245 +:100800007E49DCE033881B0A022B00D000E10B8814 +:1008100043222868934201D80A8892B27849CEE0F0 +:100820003388201C2B71FFF7FFFD201CFFF71EFEF5 +:10083000F2E0291C01C90122C1E0724900230B80AA +:1008400028680222BCE06F4900220A8018885022E2 +:1008500010406D4A10701E880F2030401880188894 +:10086000032800D9D4E012781B8808335B01E41810 +:10087000A379002A01D09B0600E0DB06DB0F0B808A +:10088000286802229BE019887F2291435E4AC9B200 +:10089000117018880F21014019803188002900D07B +:1008A000B6E01988002900D1B2E01988032900D9DF +:1008B000AEE012781B8808335B01E318002A05D0EC +:1008C0005A7930218A4320210A4304E05A793021A1 +:1008D0008A43102002435A7175E002887F239A43AD +:1008E000494BD2B21A7001880F220A400280328826 +:1008F000002A00D08CE00288002A00D188E002881B +:10090000032A00D984E01B78002B27D00388083302 +:100910005B01E3189B79990655D50388302108338C +:100920005B01E3181A798A4320210A431A7103886C +:1009300008335B01E318DB795A0644D5038860214C +:1009400008335B01E318DA798A4340210A43DA71FC +:100950000388022208335B01E31826E0038808338A +:100960005B01E3189B79DF062DD50388302108331E +:100970005B01E3181A798A4310210A431A7103882C +:1009800008335B01E318DB7999061CD503886021E5 +:1009900008335B01E318DA798A4320210A43DA71CC +:1009A0000388012208335B01E3181A710BE00B88FE +:1009B00008222868934201D80A8892B2134900237A +:1009C000FFF790FC28E0201CFFF72EFD24E0C04636 +:1009D0008C0000208100002077000020780000209B +:1009E0007C0000207E0000200203000001030000C4 +:1009F00021200000A1210000212200004C14000051 +:100A0000000000207A000020800000204400002028 +:100A1000201C0121FFF7FCFCF8BDC04610B5054BBA +:100A2000054C2360FFF7DAFB201C2168FFF7C8FBA9 +:100A3000201C10BD005000410C02002007B5054BE2 +:100A40000122019001A91868131CFFF74BFC01203B +:100A50000EBDC0460C02002013B5054B6C46073492 +:100A60001868211C0122FFF78DFC207816BDC046B6 +:100A70000C02002010B5074C201CFFF75DFB031C87 +:100A80000020834205D022684823FF33D05C012335 +:100A9000184010BD0C02002010B5054A0C1C031CA8 +:100AA000191C10680123221CFFF71CFC201C10BD20 +:100AB0000C02002070B5084C061C201C0D1CFFF712 +:100AC0003BFB0023984205D02068311C2A1CFFF70D +:100AD00059FC031C181C70BD0C020020F8B50C4C0E +:100AE000051C201C0E1CFFF727FB0023271C341CB1 +:100AF00098420AD0002C07D0291C221C3868FFF726 +:100B000041FC241A2D18F5E7331C181CF8BDC0460B +:100B10000C020020012805D1054B064A1A60064B3D +:100B2000187004E0002802D1044A014B1A60704793 +:100B30007C0200208014000089000020CC140000FA +:100B400030B51A4B85B01B78002B29D0042901D170 +:100B5000026804E0022901D1028800E0027849001D +:100B600004A843180B3B5C1AA3420BD00F20104083 +:100B7000092802D83025284300E0373018701209C0 +:100B8000013BF1E701A830230370782343700A2268 +:100B900043189A700D22DA70054B04311B6801E08E +:100BA000034B1B68DB68984705B030BD8800002008 +:100BB0007C02002072B6EFF30883044A13600368D6 +:100BC00083F30888436818477047C04680020020B6 +:100BD000F0B58FB006A9CD4A0B1C31CA31C351CA3A +:100BE00051C360CA60C3CA4CCA48A3687A255B0374 +:100BF0005B0F9B005B58C8490360A26892B25343E5 +:100C00000A60C649C64A0B6000231360C54B1D70BD +:100C1000C54BC64D1B68281C1B6940219847C44B17 +:100C200000221860C34B1D60C34BC34DC04F1A60F8 +:100C3000286839688842EBD2BE4B1B681A78FF2AB5 +:100C400000D1F7E1232A00D0CEE1BC4E3378002B4F +:100C500005D0B54BBA481B680221DB689847B14BF9 +:100C60001B78532B38D13B682A6893421ED9B14870 +:100C700001322A609A1AB34B01681B680131016086 +:100C8000B14E9A4201D2326000E03360A44832682B +:100C90000068029000F0BCFB336829685A182A608B +:100CA000A44A1668F1181160A84A13702B68013B1A +:100CB0002B60A04B1A68013A1A60A44BA14A1B781A +:100CC00011688B4206D2984A954812680068C91A82 +:100CD00092699047C04676E1522B07D1904A924BD9 +:100CE00010681B68974A5B6911686BE14F2B05D14F +:100CF0008B4B944A1B6812681A7064E1482B05D12B +:100D0000874B904A1B6812681A805CE1572B05D10B +:100D1000834B8C4A1B6812681A6054E16F2B03D115 +:100D20007F4B0121186807E0682B08D17C4B854870 +:100D30001B6802211B880360FFF702FF43E1772B4A +:100D400006D1774B7F481B6804211B680360F3E7DB +:100D5000472B13D17B4B1868FFF72CFF7C4B1B688C +:100D600083F3088862B67B4B1B78002B00D12AE105 +:100D70006D4B06201B681B68984724E1542B04D157 +:100D800001233370684B1B685CE04E2B0BD133782A +:100D9000002B05D1644B6A481B680221DB68984729 +:100DA000002333700FE1562B50D15F4D01212B688A +:100DB0006948DB6898472B680321DB6867489847D8 +:100DC000674E2B68301CDB68012198472B680D218A +:100DD000DB68644898472B68301CDB680121984722 +:100DE000544F614B544E3B60002333603A1C311C1E +:100DF0001368581C10601B780393002B03D00B68FA +:100E000001330B60F4E72B683168DB68564898477C +:100E10002B685348DB68012198470398306053489A +:100E20003860444A1368591C11601A78424B002AF2 +:100E300003D01A6801321A60F3E72A681968D36888 +:100E400098472B68DB683E480221BBE03D4A582B9F +:100E500015D1304E314D366813682A68B10093427F +:100E600008D25808E06142482080207DC507FCD5A3 +:100E70005B18F4E72C4B3F481B68DB68A1E0592B5B +:100E800033D11268264B3C49002A02D11B680B6003 +:100E900026E00868196863688025AB4392086360A0 +:100EA000002A1DD0354B2380237DDE07FCD500238F +:100EB000184D2D680095AD08AB4202D3304D25800A +:100EC00006E09342FAD09D00465901334E51EFE7B8 +:100ED000257DEE07FCD59D0049194019D21ADFE7A0 +:100EE000114B28481B68DB686BE05A2B6BD10C4B0D +:100EF00017681D680026EF19BD4245D02878311CBF +:100F000000F04AF90135061CF6E7C04660140000FF +:100F100000400041340200202C0200202802002062 +:100F200078020020240200207C02002038020020E9 +:100F30001C02002020020020300200208800002037 +:100F4000C014000084020020880200201802002043 +:100F500080020020890000209C140000C5140000BD +:100F60009E140000E8140000A0140000AC1400005F +:100F700002A5FFFFB51400008400002044A5FFFF78 +:100F800004A5FFFFB91400002E4D2F482B68012146 +:100F9000DB68984707230F223240111C3609303195 +:100FA000092A00DD07311020C0186A468154013B30 +:100FB000F1D22B6804A8DB68082198472B682348E6 +:100FC000DB6803219847224D7A232B70214B0022A6 +:100FD0001A60214B1B7893422CD01A4B01211B68BD +:100FE0001E48DB68984725E0111C3039C8B2194B00 +:100FF000092804D81E683201114319601AE0111C37 +:101000004139052903D81868373A010106E0111C57 +:101010006139052904D81D68573A29010A4308E0B7 +:101020002C2A03D10E4A1E68166001E008490A7096 +:1010300000221A600B4B1A6801321A600A4B1A68B8 +:101040000132F2E57C020020BD140000BF14000054 +:10105000240200208402002088000020C314000025 +:1010600078020020300200202002002010B51C4B26 +:1010700001201A78022402431A701A4B0F221978A1 +:101080009143197019782143197017490C7820433E +:10109000087019780A401A701A7820210A431A70C9 +:1010A000124B04211A6A0A431A62114B114A5A80E0 +:1010B0005A7852B2002AFBDBC4220F480F49920330 +:1010C000FEF7EEFF0E4A002313700E4A13700E4A0D +:1010D00013700E4A13700E4A13700E4A137010BD2F +:1010E0004A440041354400414B4400410004004063 +:1010F000000C0040144000000008004204C500003D +:101100008C020020130300208D020020900200209A +:10111000140300201103002008B5C1B20248FEF7F5 +:10112000EDFF012008BDC04600080042024B187EBA +:101130004007C00F7047C0460008004208B5FFF7DF +:10114000F5FF0028FBD00248FEF7DEFF08BDC046D1 +:101150000008004208B5FFF7E9FF0023984205D0D8 +:10116000FFF7ECFF031C233B5A425341181C08BDF8 +:1011700070B5041C0D1C4618B44204D02078FFF74B +:10118000CBFF0134F8E7281C70BD10B5041CFFF735 +:10119000D5FF2070012010BD0B0A5840034B4000C2 +:1011A000C05A0902484080B27047C046F614000099 +:1011B000F7B50024051C0F1C261CBC4220D0FFF7ED +:1011C000BDFF114BC0B21B780190002B1AD1311C0E +:1011D000FFF7E2FF0D4B061C1A88002A04D10C4AC7 +:1011E00011782A1C002907D001996A1C2970802FC8 +:1011F00002D11988013919800134A4B2151CDCE729 +:10120000301C00E00120FEBD110300208E020020F2 +:1012100012030020F0B53E4E85B0002203900C1C56 +:1012200032703C4B914201D1012201E03A490C80DD +:101230001A707F231C4201D080349C43FFF77EFF4D +:101240003378C0B2002B07D000253570FFF776FF4A +:101250003378C0B2AB4236D1432803D0712853D083 +:101260001528EBD1012300930120FFF755FF0098CB +:10127000FFF752FF00998025C843C0B2FFF74CFF2B +:10128000039B00270293244A1388002B1DD1214978 +:1012900001930978002918D10198FFF73DFF391C07 +:1012A0000198FFF779FF013D071C002DEBD1000AE3 +:1012B000C0B2FFF731FFF8B2FFF72EFFFFF73EFF96 +:1012C0003378002B0AD035701FE00299013B097872 +:1012D0001380029B019101330293DDE7C0B206281F +:1012E00007D1009B03990133DBB280310093803C2E +:1012F0000391002CB8D10420FFF70EFFFFF71EFF6B +:10130000044B01251C7000E00025281C05B0F0BD31 +:1013100011030020120300208E020020F0B5384C8B +:1013200087B0002301902370994201D1012301E08D +:10133000344A1180344A642613704320FFF7ECFED0 +:10134000324FFFF7F3FE002803D1002F03D0013FF7 +:10135000F7E7002F03D1013E002EEED14DE001252D +:10136000FFF7ECFE2378002B38D1C0B202900128A1 +:1013700005D004283DD10620FFF7CEFE39E005AEAA +:101380000221301CFFF714FF01988021FFF710FFA6 +:1013900023780390002B18D1FFF7D0FE0702FFF748 +:1013A000CDFEBFB223783F18BFB2012B0DD0039BF7 +:1013B0009F4207D13378AB4204D1EB437278DBB262 +:1013C0009A4204D01820FFF7A7FE002303E006206E +:1013D000FFF7A2FE029B2278002A02D00026267088 +:1013E0000BE0012B05D1019A6B1C8032DDB201921A +:1013F000B6E7054A002313700126301C07B0F0BD84 +:10140000110300208E0200201203002000350C0082 +:1014100010B50023934203D0CC5CC4540133F9E7E8 +:1014200010BD031C8218934202D019700133FAE7F1 +:1014300070470000F8B5C046F8BC08BC9E4670472F +:10144000F8B5C046F8BC08BC9E46704712010002C1 +:101450000200004041234D02000200000001000094 +:101460000800000010000000200000004000000004 +:1014700080000000000100000002000000040000E5 +:10148000191100003D1100002D1100007111000024 +:101490008B110000151200001D13000076002000C3 +:1014A0004E6F7620313220323031350031373A32CA +:1014B000323A323800580A0D00590A0D005A0023FA +:1014C0000A0D003E00322E30000000003D0A0000F0 +:1014D000590A0000750A0000990A0000B50A0000C8 +:1014E000990A0000DD0A00005B41726475696E6F45 +:1014F0003A58595A5D000000211042206330844060 +:10150000A550C660E770088129914AA16BB18CC1D2 +:10151000ADD1CEE1EFF13112100273325222B55249 +:101520009442F772D662399318837BB35AA3BDD322 +:101530009CC3FFF3DEE36224433420040114E66419 +:10154000C774A44485546AA54BB528850995EEE572 +:10155000CFF5ACC58DD55336722611163006D77629 +:10156000F6669556B4465BB77AA719973887DFF7C2 +:10157000FEE79DD7BCC7C448E5588668A7784008F1 +:10158000611802282338CCC9EDD98EE9AFF9488912 +:1015900069990AA92BB9F55AD44AB77A966A711A89 +:1015A000500A333A122AFDDBDCCBBFFB9EEB799B62 +:1015B000588B3BBB1AABA66C877CE44CC55C222CD9 +:1015C000033C600C411CAEED8FFDECCDCDDD2AADB2 +:1015D0000BBD688D499D977EB66ED55EF44E133E69 +:1015E000322E511E700E9FFFBEEFDDDFFCCF1BBF02 +:1015F0003AAF599F788F8891A981CAB1EBA10CD1DC +:101600002DC14EF16FE18010A100C230E3200450E3 +:10161000254046706760B9839893FBA3DAB33DC356 +:101620001CD37FE35EF3B1029012F322D232354233 +:10163000145277625672EAB5CBA5A89589856EF5E6 +:101640004FE52CD50DC5E234C324A0148104667483 +:10165000476424540544DBA7FAB79987B8975FE736 +:101660007EF71DC73CD7D326F2369106B0165766D3 +:101670007676154634564CD96DC90EF92FE9C899BE +:10168000E9898AB9ABA94458654806782768C01823 +:10169000E1088238A3287DCB5CDB3FEB1EFBF98B96 +:1016A000D89BBBAB9ABB754A545A376A167AF10A73 +:1016B000D01AB32A923A2EFD0FED6CDD4DCDAABDA6 +:1016C0008BADE89DC98D267C076C645C454CA23CC3 +:1016D000832CE01CC10C1FEF3EFF5DCF7CDF9BAF76 +:1016E000BABFD98FF89F176E367E554E745E932E13 +:0C16F000B23ED10EF01E00000000000011 +:1016FC0009024300020100803209040000010202C9 +:10170C000000052400100104240200052406000139 +:10171C000524010001070583030800FF09040100EB +:10172C00020A0000000705810240000007050202C2 +:10173C004000000000C20100000008006900000029 +:08174C00410000000000000054 +:04000003000005E90B +:00000001FF From e7579eb5e757d928b83eeb49859fb697a7d3c7c0 Mon Sep 17 00:00:00 2001 From: Todd Treece Date: Wed, 18 Nov 2015 14:46:06 -0500 Subject: [PATCH 08/22] adds new boards.txt --- boards.txt | 132 ++++++++---------------- platform.txt | 286 +++++++++++++++++++++++++-------------------------- 2 files changed, 186 insertions(+), 232 deletions(-) diff --git a/boards.txt b/boards.txt index 5e9985120..f8d2ebf46 100644 --- a/boards.txt +++ b/boards.txt @@ -1,89 +1,43 @@ -# Copyright (c) 2014-2015 Arduino LLC. All right reserved. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -# Arduino/Genuino Zero (Prorgamming Port) -# --------------------------------------- -arduino_zero_edbg.name=Arduino/Genuino Zero (Programming Port) -arduino_zero_edbg.vid.0=0x03eb -arduino_zero_edbg.pid.0=0x2157 - -arduino_zero_edbg.upload.tool=openocd -arduino_zero_edbg.upload.protocol=sam-ba -arduino_zero_edbg.upload.maximum_size=262144 -arduino_zero_edbg.upload.use_1200bps_touch=false -arduino_zero_edbg.upload.wait_for_upload_port=false -arduino_zero_edbg.upload.native_usb=false -arduino_zero_edbg.build.mcu=cortex-m0plus -arduino_zero_edbg.build.f_cpu=48000000L -arduino_zero_edbg.build.usb_product="Arduino Zero" -arduino_zero_edbg.build.usb_manufacturer="Arduino LLC" -arduino_zero_edbg.build.board=SAMD_ZERO -arduino_zero_edbg.build.core=arduino -arduino_zero_edbg.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} -arduino_zero_edbg.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld -arduino_zero_edbg.build.openocdscript=openocd_scripts/arduino_zero.cfg -arduino_zero_edbg.build.variant=arduino_zero -arduino_zero_edbg.build.variant_system_lib= -arduino_zero_edbg.build.vid=0x2341 -arduino_zero_edbg.build.pid=0x804d -arduino_zero_edbg.bootloader.tool=openocd -arduino_zero_edbg.bootloader.file=zero/samd21_sam_ba.bin - -# Arduino/Genuino Zero (Native USB Port) -# --------------------------------------- -arduino_zero_native.name=Arduino/Genuino Zero (Native USB Port) -arduino_zero_native.vid.0=0x2341 -arduino_zero_native.pid.0=0x804d -arduino_zero_native.vid.1=0x2341 -arduino_zero_native.pid.1=0x004d - -arduino_zero_native.vid.2=0x2341 -arduino_zero_native.pid.2=0x824d -# If the board is a 2341:824d use 2341:824d for build and set other parameters as well -arduino_zero_native.vid.2.build.vid=0x2341 -arduino_zero_native.vid.2.build.pid=0x824d -arduino_zero_native.vid.2.build.usb_product="Genuino Zero" -arduino_zero_native.vid.2.bootloader.file=zero/samd21_sam_ba_genuino.bin - -arduino_zero_native.vid.3=0x2341 -arduino_zero_native.pid.3=0x024d -# If the board is a 2341:024d use 2341:824d for build and set other parameters as well -arduino_zero_native.vid.3.build.vid=0x2341 -arduino_zero_native.vid.3.build.pid=0x824d -arduino_zero_native.vid.3.build.usb_product="Genuino Zero" -arduino_zero_native.vid.3.bootloader.file=zero/samd21_sam_ba_genuino.bin - -arduino_zero_native.upload.tool=bossac -arduino_zero_native.upload.protocol=sam-ba -arduino_zero_native.upload.maximum_size=262144 -arduino_zero_native.upload.use_1200bps_touch=true -arduino_zero_native.upload.wait_for_upload_port=true -arduino_zero_native.upload.native_usb=true -arduino_zero_native.build.mcu=cortex-m0plus -arduino_zero_native.build.f_cpu=48000000L -arduino_zero_native.build.usb_product="Arduino Zero" -arduino_zero_native.build.usb_manufacturer="Arduino LLC" -arduino_zero_native.build.board=SAMD_ZERO -arduino_zero_native.build.core=arduino -arduino_zero_native.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} -arduino_zero_native.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld -arduino_zero_native.build.openocdscript=openocd_scripts/arduino_zero.cfg -arduino_zero_native.build.variant=arduino_zero -arduino_zero_native.build.variant_system_lib= -arduino_zero_native.build.vid=0x2341 -arduino_zero_native.build.pid=0x804d -arduino_zero_native.bootloader.tool=openocd -arduino_zero_native.bootloader.file=zero/samd21_sam_ba.bin +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +adafruit_feather_m0.name=Adafruit Feather M0 (Native USB Port) +adafruit_feather_m0.vid.0=0x239A +adafruit_feather_m0.pid.0=0x800B +adafruit_feather_m0.vid.1=0x239A +adafruit_feather_m0.pid.1=0x000B +adafruit_feather_m0.upload.tool=bossac +adafruit_feather_m0.upload.protocol=sam-ba +adafruit_feather_m0.upload.maximum_size=262144 +adafruit_feather_m0.upload.use_1200bps_touch=true +adafruit_feather_m0.upload.wait_for_upload_port=true +adafruit_feather_m0.upload.native_usb=true +adafruit_feather_m0.build.mcu=cortex-m0plus +adafruit_feather_m0.build.f_cpu=48000000L +adafruit_feather_m0.build.usb_product="Feather M0" +adafruit_feather_m0.build.usb_manufacturer="Adafruit" +adafruit_feather_m0.build.board=SAMD_ZERO +adafruit_feather_m0.build.core=arduino +adafruit_feather_m0.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} +adafruit_feather_m0.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld +adafruit_feather_m0.build.openocdscript=openocd_scripts/arduino_zero.cfg +adafruit_feather_m0.build.variant=arduino_zero +adafruit_feather_m0.build.variant_system_lib= +adafruit_feather_m0.build.vid=0x239A +adafruit_feather_m0.build.pid=0x800B +adafruit_feather_m0.bootloader.tool=openocd +adafruit_feather_m0.bootloader.file=feather/samd21_sam_ba.bin diff --git a/platform.txt b/platform.txt index ccd6a899e..b6d4be6f8 100644 --- a/platform.txt +++ b/platform.txt @@ -1,143 +1,143 @@ -# Copyright (c) 2014-2015 Arduino LLC. All right reserved. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -# Arduino SAMD Core and platform. -# -# For more info: -# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification - -name=Arduino SAMD (32-bits ARM Cortex-M0+) Boards -version=1.6.2 - -# Compile variables -# ----------------- - -compiler.warning_flags=-w -compiler.warning_flags.none=-w -compiler.warning_flags.default= -compiler.warning_flags.more=-Wall -compiler.warning_flags.all=-Wall -Wextra - -compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ -compiler.c.cmd=arm-none-eabi-gcc -compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD -compiler.c.elf.cmd=arm-none-eabi-gcc -compiler.c.elf.flags=-Os -Wl,--gc-sections -save-temps -compiler.S.cmd=arm-none-eabi-gcc -compiler.S.flags=-c -g -x assembler-with-cpp -compiler.cpp.cmd=arm-none-eabi-g++ -compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g -Os {compiler.warning_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD -compiler.ar.cmd=arm-none-eabi-ar -compiler.ar.flags=rcs -compiler.objcopy.cmd=arm-none-eabi-objcopy -compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 -compiler.elf2hex.flags=-O binary -compiler.elf2hex.cmd=arm-none-eabi-objcopy -compiler.ldflags=-mcpu={build.mcu} -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -compiler.size.cmd=arm-none-eabi-size -compiler.define=-DARDUINO= - -# this can be overriden in boards.txt -build.extra_flags= - -# These can be overridden in platform.local.txt -compiler.c.extra_flags= -compiler.c.elf.extra_flags= -#compiler.c.elf.extra_flags=-v -compiler.cpp.extra_flags= -compiler.S.extra_flags= -compiler.ar.extra_flags= -compiler.elf2hex.extra_flags= - -compiler.arm.cmsis.path="-I{runtime.tools.CMSIS.path}/CMSIS/Include/" "-I{runtime.tools.CMSIS.path}/Device/ATMEL/" - -# USB Flags -# --------- -build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} -DUSBCON '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' - -# Default usb manufacturer will be replaced at compile time using -# numeric vendor ID if available or by board's specific value. -build.usb_manufacturer="Unknown" - - -# Compile patterns -# ---------------- - -## Compile c files -recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {compiler.arm.cmsis.path} {includes} "{source_file}" -o "{object_file}" - -## Compile c++ files -recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {compiler.arm.cmsis.path} {includes} "{source_file}" -o "{object_file}" - -## Compile S files -recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {compiler.arm.cmsis.path} {includes} "{source_file}" -o "{object_file}" - -## Create archives -recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/{archive_file}" "{object_file}" - -## Combine gc-sections, archives, and objects -recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" --specs=nano.specs --specs=nosys.specs {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} -Wl,--start-group -lm "{build.path}/{archive_file}" -Wl,--end-group - -## Create output (bin file) -recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" - -## Save hex -recipe.output.tmp_file={build.project_name}.bin -recipe.output.save_file={build.project_name}.{build.variant}.bin - -## Compute size -recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" -recipe.size.regex=\.text\s+([0-9]+).* - - -# Uploader tools -# -------------- - -# -# BOSSA -# -tools.bossac.path={runtime.tools.bossac-1.6.1-arduino.path} -tools.bossac.cmd=bossac -tools.bossac.cmd.windows=bossac.exe - -tools.bossac.upload.params.verbose=-i -d -tools.bossac.upload.params.quiet= -tools.bossac.upload.pattern="{path}/{cmd}" {upload.verbose} --port={serial.port.file} -U {upload.native_usb} -i -e -w -v "{build.path}/{build.project_name}.bin" -R - -# -# OpenOCD sketch upload -# - -tools.openocd.path={runtime.tools.openocd.path} -tools.openocd.cmd=bin/openocd -tools.openocd.cmd.windows=bin/openocd.exe - -tools.openocd.upload.params.verbose=-d2 -tools.openocd.upload.params.quiet=-d0 -tools.openocd.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{{build.path}/{build.project_name}.bin}} verify reset 0x00002000; shutdown" - -tools.openocd.program.params.verbose=-d2 -tools.openocd.program.params.quiet=-d0 -tools.openocd.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{{build.path}/{build.project_name}.elf}} verify reset; shutdown" - -tools.openocd.erase.params.verbose=-d3 -tools.openocd.erase.params.quiet=-d0 -tools.openocd.erase.pattern= - -tools.openocd.bootloader.params.verbose=-d2 -tools.openocd.bootloader.params.quiet=-d0 -tools.openocd.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{{runtime.platform.path}/bootloaders/{bootloader.file}}} verify reset; shutdown" - +# Copyright (c) 2014-2015 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Arduino SAMD Core and platform. +# +# For more info: +# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification + +name=Arduino SAMD (32-bits ARM Cortex-M0+) Boards +version=1.6.1 + +# Compile variables +# ----------------- + +compiler.warning_flags=-w +compiler.warning_flags.none=-w +compiler.warning_flags.default= +compiler.warning_flags.more=-Wall +compiler.warning_flags.all=-Wall -Wextra + +compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ +compiler.c.cmd=arm-none-eabi-gcc +compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD +compiler.c.elf.cmd=arm-none-eabi-gcc +compiler.c.elf.flags=-Os -Wl,--gc-sections -save-temps +compiler.S.cmd=arm-none-eabi-gcc +compiler.S.flags=-c -g -x assembler-with-cpp +compiler.cpp.cmd=arm-none-eabi-g++ +compiler.cpp.flags=-mcpu={build.mcu} -mthumb -c -g -Os {compiler.warning_flags} -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD +compiler.ar.cmd=arm-none-eabi-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=arm-none-eabi-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2hex.flags=-O binary +compiler.elf2hex.cmd=arm-none-eabi-objcopy +compiler.ldflags=-mcpu={build.mcu} -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align +compiler.size.cmd=arm-none-eabi-size +compiler.define=-DARDUINO= + +# this can be overriden in boards.txt +build.extra_flags= + +# These can be overridden in platform.local.txt +compiler.c.extra_flags= +compiler.c.elf.extra_flags= +#compiler.c.elf.extra_flags=-v +compiler.cpp.extra_flags= +compiler.S.extra_flags= +compiler.ar.extra_flags= +compiler.elf2hex.extra_flags= + +compiler.arm.cmsis.path="-I{runtime.tools.CMSIS.path}/CMSIS/Include/" "-I{runtime.tools.CMSIS.path}/Device/ATMEL/" + +# USB Flags +# --------- +build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} -DUSBCON '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' + +# Default usb manufacturer will be replaced at compile time using +# numeric vendor ID if available or by board's specific value. +build.usb_manufacturer="Unknown" + + +# Compile patterns +# ---------------- + +## Compile c files +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {compiler.arm.cmsis.path} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {compiler.arm.cmsis.path} {includes} "{source_file}" -o "{object_file}" + +## Compile S files +recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {compiler.arm.cmsis.path} {includes} "{source_file}" -o "{object_file}" + +## Create archives +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/{archive_file}" "{object_file}" + +## Combine gc-sections, archives, and objects +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" --specs=nano.specs --specs=nosys.specs {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} -Wl,--start-group -lm "{build.path}/{archive_file}" -Wl,--end-group + +## Create output (bin file) +recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" + +## Save hex +recipe.output.tmp_file={build.project_name}.bin +recipe.output.save_file={build.project_name}.{build.variant}.bin + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" +recipe.size.regex=\.text\s+([0-9]+).* + + +# Uploader tools +# -------------- + +# +# BOSSA +# +tools.bossac.path={runtime.tools.bossac-1.6-arduino.path} +tools.bossac.cmd=bossac +tools.bossac.cmd.windows=bossac.exe + +tools.bossac.upload.params.verbose=-i -d +tools.bossac.upload.params.quiet= +tools.bossac.upload.pattern="{path}/{cmd}" {upload.verbose} --port={serial.port.file} -U {upload.native_usb} -i -e -w -v "{build.path}/{build.project_name}.bin" -R + +# +# OpenOCD sketch upload +# + +tools.openocd.path={runtime.tools.openocd.path} +tools.openocd.cmd=bin/openocd +tools.openocd.cmd.windows=bin/openocd.exe + +tools.openocd.upload.params.verbose=-d2 +tools.openocd.upload.params.quiet=-d0 +tools.openocd.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{{build.path}/{build.project_name}.bin}} verify reset 0x00002000; shutdown" + +tools.openocd.program.params.verbose=-d2 +tools.openocd.program.params.quiet=-d0 +tools.openocd.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{{build.path}/{build.project_name}.elf}} verify reset; shutdown" + +tools.openocd.erase.params.verbose=-d3 +tools.openocd.erase.params.quiet=-d0 +tools.openocd.erase.pattern= + +tools.openocd.bootloader.params.verbose=-d2 +tools.openocd.bootloader.params.quiet=-d0 +tools.openocd.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{{runtime.platform.path}/bootloaders/{bootloader.file}}} verify reset; shutdown" + From 22f47bb654e9688af8d2e18ea7b5d6033d44e73e Mon Sep 17 00:00:00 2001 From: "Limor \"Ladyada\" Fried" Date: Tue, 24 Nov 2015 15:50:01 -0500 Subject: [PATCH 09/22] Update platform.txt add subver so we can find it! --- platform.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform.txt b/platform.txt index b6d4be6f8..a46f1181d 100644 --- a/platform.txt +++ b/platform.txt @@ -109,7 +109,7 @@ recipe.size.regex=\.text\s+([0-9]+).* # # BOSSA # -tools.bossac.path={runtime.tools.bossac-1.6-arduino.path} +tools.bossac.path={runtime.tools.bossac-1.6.1-arduino.path} tools.bossac.cmd=bossac tools.bossac.cmd.windows=bossac.exe From 5c7319f52f2dd59d4f1e15b23e2c537d14f9ae37 Mon Sep 17 00:00:00 2001 From: ladyada Date: Wed, 13 Jan 2016 15:59:44 -0500 Subject: [PATCH 10/22] make it so native USB is Serial --- cores/arduino/USB/CDC.cpp | 2 +- cores/arduino/USB/USBAPI.h | 2 +- cores/arduino/USB/USBCore.cpp | 2 +- variants/arduino_zero/variant.cpp | 4 ++-- variants/arduino_zero/variant.h | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp index 0f1016848..981174444 100644 --- a/cores/arduino/USB/CDC.cpp +++ b/cores/arduino/USB/CDC.cpp @@ -289,6 +289,6 @@ Serial_::operator bool() return result; } -Serial_ SerialUSB(USBDevice); +Serial_ Serial(USBDevice); #endif diff --git a/cores/arduino/USB/USBAPI.h b/cores/arduino/USB/USBAPI.h index f4a0babf8..72039a734 100644 --- a/cores/arduino/USB/USBAPI.h +++ b/cores/arduino/USB/USBAPI.h @@ -130,7 +130,7 @@ class Serial_ : public Stream USBDeviceClass &usb; RingBuffer *_cdc_rx_buffer; }; -extern Serial_ SerialUSB; +extern Serial_ Serial; //================================================================================ //================================================================================ diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 9642c2aad..caec4634f 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -250,7 +250,7 @@ void USBDeviceClass::handleEndpoint(uint8_t ep) // Handle received bytes if (available(CDC_ENDPOINT_OUT)) - SerialUSB.accept(); + Serial.accept(); } if (ep == CDC_ENDPOINT_IN) { diff --git a/variants/arduino_zero/variant.cpp b/variants/arduino_zero/variant.cpp index d8808bbee..55749ebc6 100644 --- a/variants/arduino_zero/variant.cpp +++ b/variants/arduino_zero/variant.cpp @@ -208,7 +208,7 @@ SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; -Uart Serial( &sercom5, PIN_SERIAL_RX, PIN_SERIAL_TX, PAD_SERIAL_RX, PAD_SERIAL_TX ) ; +Uart Serial5( &sercom5, PIN_SERIAL_RX, PIN_SERIAL_TX, PAD_SERIAL_RX, PAD_SERIAL_TX ) ; void SERCOM0_Handler() { Serial1.IrqHandler(); @@ -216,6 +216,6 @@ void SERCOM0_Handler() void SERCOM5_Handler() { - Serial.IrqHandler(); + Serial5.IrqHandler(); } diff --git a/variants/arduino_zero/variant.h b/variants/arduino_zero/variant.h index c9d73f7da..32e79792b 100644 --- a/variants/arduino_zero/variant.h +++ b/variants/arduino_zero/variant.h @@ -183,7 +183,7 @@ extern SERCOM sercom3; extern SERCOM sercom4; extern SERCOM sercom5; -extern Uart Serial; +extern Uart Serial5; extern Uart Serial1; #endif @@ -203,7 +203,7 @@ extern Uart Serial1; // // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX // pins are NOT connected to anything by default. -#define SERIAL_PORT_USBVIRTUAL SerialUSB +#define SERIAL_PORT_USBVIRTUAL Serial #define SERIAL_PORT_MONITOR Serial // Serial has no physical pins broken out, so it's not listed as HARDWARE port #define SERIAL_PORT_HARDWARE Serial1 From d8f4306d0f5c94951bb761b267480623fd0b9239 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 23 Jan 2016 19:41:31 -0500 Subject: [PATCH 11/22] Serial5 not available anyhow --- variants/arduino_zero/variant.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/variants/arduino_zero/variant.cpp b/variants/arduino_zero/variant.cpp index 55749ebc6..a6cb3056b 100644 --- a/variants/arduino_zero/variant.cpp +++ b/variants/arduino_zero/variant.cpp @@ -208,14 +208,18 @@ SERCOM sercom4( SERCOM4 ) ; SERCOM sercom5( SERCOM5 ) ; Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ; -Uart Serial5( &sercom5, PIN_SERIAL_RX, PIN_SERIAL_TX, PAD_SERIAL_RX, PAD_SERIAL_TX ) ; void SERCOM0_Handler() { Serial1.IrqHandler(); } + +// Serial5 not available on Feather so ditch it + +//Uart Serial5( &sercom5, PIN_SERIAL_RX, PIN_SERIAL_TX, PAD_SERIAL_RX, PAD_SERIAL_TX ) ; +/* void SERCOM5_Handler() { Serial5.IrqHandler(); } - +*/ From d95e053d0e2c66b917970cadd4967bc2f8e3c999 Mon Sep 17 00:00:00 2001 From: Andre Price Date: Wed, 10 Feb 2016 13:48:17 -0800 Subject: [PATCH 12/22] Update Board for Feather M0 --- boards.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards.txt b/boards.txt index f8d2ebf46..a2901d23b 100644 --- a/boards.txt +++ b/boards.txt @@ -30,7 +30,7 @@ adafruit_feather_m0.build.mcu=cortex-m0plus adafruit_feather_m0.build.f_cpu=48000000L adafruit_feather_m0.build.usb_product="Feather M0" adafruit_feather_m0.build.usb_manufacturer="Adafruit" -adafruit_feather_m0.build.board=SAMD_ZERO +adafruit_feather_m0.build.board=SAMD_FEATHER_M0 adafruit_feather_m0.build.core=arduino adafruit_feather_m0.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} adafruit_feather_m0.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld From c34dd054021e3ee3c7ed88b99f062f2b8d1f5e3f Mon Sep 17 00:00:00 2001 From: Andre Price Date: Thu, 11 Feb 2016 14:23:11 -0800 Subject: [PATCH 13/22] Keep ARDUINO_SAMD_ZERO flag for compatilibity - Instead of removing it in favor of ARDUINO_SAMD_FEATHER_M0 have both flags present to increase chances of compatibility with libraries. --- boards.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards.txt b/boards.txt index a2901d23b..90a3d8825 100644 --- a/boards.txt +++ b/boards.txt @@ -32,7 +32,7 @@ adafruit_feather_m0.build.usb_product="Feather M0" adafruit_feather_m0.build.usb_manufacturer="Adafruit" adafruit_feather_m0.build.board=SAMD_FEATHER_M0 adafruit_feather_m0.build.core=arduino -adafruit_feather_m0.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} +adafruit_feather_m0.build.extra_flags=-DARDUINO_SAMD_ZERO -D__SAMD21G18A__ {build.usb_flags} adafruit_feather_m0.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld adafruit_feather_m0.build.openocdscript=openocd_scripts/arduino_zero.cfg adafruit_feather_m0.build.variant=arduino_zero From 9d193cc0ba1cea1f4f4c7c3f0698a3b4ba0fe7ee Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 14 Feb 2016 15:30:08 -0500 Subject: [PATCH 14/22] add metro m0 (testing) --- boards.txt | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/boards.txt b/boards.txt index f8d2ebf46..fab3a884c 100644 --- a/boards.txt +++ b/boards.txt @@ -41,3 +41,32 @@ adafruit_feather_m0.build.vid=0x239A adafruit_feather_m0.build.pid=0x800B adafruit_feather_m0.bootloader.tool=openocd adafruit_feather_m0.bootloader.file=feather/samd21_sam_ba.bin + + +adafruit_metro_m0.name=Adafruit Metro M0 (Native USB Port) +adafruit_metro_m0.vid.0=0x239A +adafruit_metro_m0.pid.0=0x8013 +adafruit_metro_m0.vid.1=0x239A +adafruit_metro_m0.pid.1=0x0013 +adafruit_metro_m0.upload.tool=bossac +adafruit_metro_m0.upload.protocol=sam-ba +adafruit_metro_m0.upload.maximum_size=262144 +adafruit_metro_m0.upload.use_1200bps_touch=true +adafruit_metro_m0.upload.wait_for_upload_port=true +adafruit_metro_m0.upload.native_usb=true +adafruit_metro_m0.build.mcu=cortex-m0plus +adafruit_metro_m0.build.f_cpu=48000000L +adafruit_metro_m0.build.usb_product="Metro M0" +adafruit_metro_m0.build.usb_manufacturer="Adafruit" +adafruit_metro_m0.build.board=SAMD_ZERO +adafruit_metro_m0.build.core=arduino +adafruit_metro_m0.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} +adafruit_metro_m0.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld +adafruit_metro_m0.build.openocdscript=openocd_scripts/arduino_zero.cfg +adafruit_metro_m0.build.variant=arduino_zero +adafruit_metro_m0.build.variant_system_lib= +adafruit_metro_m0.build.vid=0x239A +adafruit_metro_m0.build.pid=0x8013 +adafruit_metro_m0.bootloader.tool=openocd +adafruit_metro_m0.bootloader.file=metro/samd21_sam_ba.bin + From 440afc570d64ae96f1210723c0479e1704ee3368 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 14 Feb 2016 15:37:58 -0500 Subject: [PATCH 15/22] add USB CDC RX & TX LEDs with 10ms minimum on time, tested --- cores/arduino/USB/CDC.cpp | 14 ++++++++++++++ cores/arduino/delay.c | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp index 981174444..b691f51c5 100644 --- a/cores/arduino/USB/CDC.cpp +++ b/cores/arduino/USB/CDC.cpp @@ -23,6 +23,8 @@ #include #include +uint8_t USB_TXLEDticks = 0, USB_RXLEDticks = 0; + #ifdef CDC_ENABLED #define CDC_SERIAL_BUFFER_SIZE 256 @@ -98,6 +100,12 @@ bool CDC_Setup(USBSetup& setup) uint8_t requestType = setup.bmRequestType; uint8_t r = setup.bRequest; + digitalWrite(PIN_LED_RXL, HIGH); + digitalWrite(PIN_LED_TXL, HIGH); + pinMode(PIN_LED_RXL, OUTPUT); + pinMode(PIN_LED_TXL, OUTPUT); + USB_TXLEDticks = USB_RXLEDticks = 0; + if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) { if (r == CDC_GET_LINE_CODING) @@ -209,6 +217,9 @@ int Serial_::read(void) { ring_buffer *buffer = &cdc_rx_buffer; + digitalWrite(PIN_LED_RXL, LOW); + USB_RXLEDticks = 10; // how many ms to keep LED on + // if the head isn't ahead of the tail, we don't have any characters if (buffer->head == buffer->tail && !buffer->full) { @@ -243,6 +254,9 @@ size_t Serial_::write(const uint8_t *buffer, size_t size) bytes sent before the user opens the connection or after the connection is closed are lost - just like with a UART. */ + digitalWrite(PIN_LED_TXL, LOW); + USB_TXLEDticks = 10; // how many ms to keep LED on + // TODO - ZE - check behavior on different OSes and test what happens if an // open connection isn't broken cleanly (cable is yanked out, host dies // or locks up, or host virtual serial port hangs) diff --git a/cores/arduino/delay.c b/cores/arduino/delay.c index ea000abb0..f73037ea7 100644 --- a/cores/arduino/delay.c +++ b/cores/arduino/delay.c @@ -19,6 +19,9 @@ #include "delay.h" #include "Arduino.h" +extern uint8_t USB_TXLEDticks, USB_RXLEDticks; + + #ifdef __cplusplus extern "C" { #endif @@ -83,6 +86,21 @@ void SysTick_DefaultHandler(void) // Increment tick count each ms _ulTickCount++; tickReset(); + + // turn off CDC LEDs if time + if (USB_RXLEDticks) { + USB_RXLEDticks--; + if (USB_RXLEDticks == 0) { + digitalWrite(PIN_LED_RXL, HIGH); + } + } + + if (USB_TXLEDticks) { + USB_TXLEDticks--; + if (USB_TXLEDticks == 0) { + digitalWrite(PIN_LED_TXL, HIGH); + } + } } #ifdef __cplusplus From 616475aea99b6ba1c2c68bc59699672688d523c4 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 14 Feb 2016 19:02:45 -0500 Subject: [PATCH 16/22] fix random init() call, set debug output to Serial1 --- libraries/USBHost/src/Usb.cpp | 20 +++++++++----------- libraries/USBHost/src/Usb.h | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/libraries/USBHost/src/Usb.cpp b/libraries/USBHost/src/Usb.cpp index cdde1a670..9abcc2036 100644 --- a/libraries/USBHost/src/Usb.cpp +++ b/libraries/USBHost/src/Usb.cpp @@ -36,7 +36,6 @@ USBHost::USBHost() : bmHubPre(0) { uint32_t USBHost::Init() { //devConfigIndex = 0; // Init host stack - init(); bmHubPre = 0; UHD_Init(); return 0; @@ -124,7 +123,7 @@ uint32_t USBHost::SetPipeAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint /* 01-0f = non-zero HRSLT */ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint32_t nbytes, uint8_t* dataptr, USBReadParser *p) { - + uint32_t direction = 0; // Request direction, IN or OUT uint32_t rcode; SETUP_PKT setup_pkt; @@ -143,7 +142,7 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t if (rcode) { TRACE_USBHOST(printf("/!\\ USBHost::ctrlReq : EP0 allocation error: %lu\r\n", rcode);) - //USBTRACE2("\n\rUSBHost::ctrlReq : EP0 allocation error: ", rcode"); + //USBTRACE2("\n\rUSBHost::ctrlReq : EP0 allocation error: ", rcode"); return rcode; } @@ -195,14 +194,14 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t ((USBReadParser*)p)->Parse(read, dataptr, total - left); } else // OUT transfer - { + { pep->bmSndToggle = 1; //bmSNDTOG1; rcode = OutTransfer(pep, nak_limit, nbytes, dataptr); } if(rcode) //return error return (rcode); } - + // Status stage UHD_Pipe_CountZero(pep->epAddr); USB->HOST.HostPipe[pep->epAddr].PSTATUSSET.reg = USB_HOST_PSTATUSSET_DTGL; @@ -268,11 +267,11 @@ uint32_t USBHost::InTransfer(EpInfo *pep, uint32_t nak_limit, uint8_t *nbytesptr } /* check for RCVDAVIRQ and generate error if not present */ /* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */ - + pktsize = uhd_byte_count(pep->epAddr); // Number of received bytes - + USB->HOST.HostPipe[pep->epAddr].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_BK0RDY; - + //printf("Got %i bytes \r\n", pktsize); // This would be OK, but... //assert(pktsize <= nbytes); @@ -297,7 +296,7 @@ uint32_t USBHost::InTransfer(EpInfo *pep, uint32_t nak_limit, uint8_t *nbytesptr /* 1. The device sent a short packet (L.T. maxPacketSize) */ /* 2. 'nbytes' have been transferred. */ if((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes? - { + { // Save toggle value pep->bmRcvToggle = USB_HOST_DTGL(pep->epAddr); //printf("\r\n"); @@ -494,8 +493,7 @@ void USBHost::Task(void) //USB state machine TRACE_USBHOST(printf(" + USB_DETACHED_SUBSTATE_INITIALIZE\r\n");) // Init USB stack and driver - UHD_Init(); - init(); + Init(); // Free all USB resources for (uint32_t i = 0; i < USB_NUMDEVICES; ++i) diff --git a/libraries/USBHost/src/Usb.h b/libraries/USBHost/src/Usb.h index 919b83523..9ac26c7c4 100644 --- a/libraries/USBHost/src/Usb.h +++ b/libraries/USBHost/src/Usb.h @@ -27,7 +27,7 @@ e-mail : support@circuitsathome.com // None of these should ever be included by a driver, or a user's sketch. #include "variant.h" -#define USB_HOST_SERIAL SERIAL_PORT_MONITOR +#define USB_HOST_SERIAL Serial1 #include "Print.h" #include "printhex.h" #include "message.h" From ae5e0b8f1ec26cf25e5b6d5b498ab549b34e807d Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 14 Feb 2016 19:03:50 -0500 Subject: [PATCH 17/22] use Serial1 option for debug output (since USB port is taken) --- .../USBHost/examples/USB_desc/USB_desc.ino | 100 ++++++++---------- 1 file changed, 47 insertions(+), 53 deletions(-) diff --git a/libraries/USBHost/examples/USB_desc/USB_desc.ino b/libraries/USBHost/examples/USB_desc/USB_desc.ino index 0bc039b58..5f1789550 100644 --- a/libraries/USBHost/examples/USB_desc/USB_desc.ino +++ b/libraries/USBHost/examples/USB_desc/USB_desc.ino @@ -1,22 +1,16 @@ - - #include "Arduino.h" #include #include "wiring_constants.h" #include "pgmstrings.h" -// Satisfy IDE, which only needs to see the include statment in the ino. -#ifdef dobogusinclude -#include -#endif + + +// on a zero with debug port, use debug port +//#define SerialDebug Serial + +// on a feather or non-debug Zero, use Serial1 (since USB is taken!) +#define SerialDebug Serial1 USBHost usb; -//USBHub Hub1(&Usb); -//USBHub Hub2(&Usb); -//USBHub Hub3(&Usb); -//USBHub Hub4(&Usb); -//USBHub Hub5(&Usb); -//USBHub Hub6(&Usb); -//USBHub Hub7(&Usb); uint32_t next_time; @@ -33,39 +27,40 @@ void PrintAllAddresses(UsbDeviceDefinition *pdev) { UsbDeviceAddress adr; adr.devAddress = pdev->address.devAddress; - SERIAL_PORT_MONITOR.print("\r\nAddr:"); - SERIAL_PORT_MONITOR.print(adr.devAddress, HEX); - SERIAL_PORT_MONITOR.print("("); - SERIAL_PORT_MONITOR.print(adr.bmHub, HEX); - SERIAL_PORT_MONITOR.print("."); - SERIAL_PORT_MONITOR.print(adr.bmParent, HEX); - SERIAL_PORT_MONITOR.print("."); - SERIAL_PORT_MONITOR.print(adr.bmAddress, HEX); - SERIAL_PORT_MONITOR.println(")"); + SerialDebug.print("\r\nAddr:"); + SerialDebug.print(adr.devAddress, HEX); + SerialDebug.print("("); + SerialDebug.print(adr.bmHub, HEX); + SerialDebug.print("."); + SerialDebug.print(adr.bmParent, HEX); + SerialDebug.print("."); + SerialDebug.print(adr.bmAddress, HEX); + SerialDebug.println(")"); } void PrintAddress(uint8_t addr) { UsbDeviceAddress adr; adr.devAddress = addr; - SERIAL_PORT_MONITOR.print("\r\nADDR:\t"); - SERIAL_PORT_MONITOR.println(adr.devAddress,HEX); - SERIAL_PORT_MONITOR.print("DEV:\t"); - SERIAL_PORT_MONITOR.println(adr.bmAddress,HEX); - SERIAL_PORT_MONITOR.print("PRNT:\t"); - SERIAL_PORT_MONITOR.println(adr.bmParent,HEX); - SERIAL_PORT_MONITOR.print("HUB:\t"); - SERIAL_PORT_MONITOR.println(adr.bmHub,HEX); + SerialDebug.print("\r\nADDR:\t"); + SerialDebug.println(adr.devAddress,HEX); + SerialDebug.print("DEV:\t"); + SerialDebug.println(adr.bmAddress,HEX); + SerialDebug.print("PRNT:\t"); + SerialDebug.println(adr.bmParent,HEX); + SerialDebug.print("HUB:\t"); + SerialDebug.println(adr.bmHub,HEX); } void setup() { - SERIAL_PORT_MONITOR.begin( 115200 ); - while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection - SERIAL_PORT_MONITOR.println("Start USB Desc"); + Serial.begin(115200); + SerialDebug.begin(115200); + SerialDebug.println("Starting USB Descriptor test"); + SerialDebug.println("Initializing USB"); if (usb.Init() == -1) - SERIAL_PORT_MONITOR.println("OSC did not start."); + SerialDebug.println("USBhost did not start."); delay( 20 ); @@ -85,7 +80,7 @@ void PrintDescriptors(uint8_t addr) printProgStr(Gen_Error_str); print_hex( rcode, 8 ); } - SERIAL_PORT_MONITOR.print("\r\n"); + SerialDebug.print("\r\n"); for (int i=0; iaddress.devAddress, 8); - SERIAL_PORT_MONITOR.println("\r\n--"); + SerialDebug.println("\r\n--"); PrintDescriptors( pdev->address.devAddress ); } @@ -171,37 +166,37 @@ void printhubdescr(uint8_t *descrptr, uint8_t addr) printProgStr(PSTR("\r\n\r\nHub Descriptor:\r\n")); printProgStr(PSTR("bDescLength:\t\t")); - SERIAL_PORT_MONITOR.println(pHub->bDescLength, HEX); + SerialDebug.println(pHub->bDescLength, HEX); printProgStr(PSTR("bDescriptorType:\t")); - SERIAL_PORT_MONITOR.println(pHub->bDescriptorType, HEX); + SerialDebug.println(pHub->bDescriptorType, HEX); printProgStr(PSTR("bNbrPorts:\t\t")); - SERIAL_PORT_MONITOR.println(pHub->bNbrPorts, HEX); + SerialDebug.println(pHub->bNbrPorts, HEX); printProgStr(PSTR("LogPwrSwitchMode:\t")); - SERIAL_PORT_MONITOR.println(pHub->LogPwrSwitchMode, BIN); + SerialDebug.println(pHub->LogPwrSwitchMode, BIN); printProgStr(PSTR("CompoundDevice:\t\t")); - SERIAL_PORT_MONITOR.println(pHub->CompoundDevice, BIN); + SerialDebug.println(pHub->CompoundDevice, BIN); printProgStr(PSTR("OverCurrentProtectMode:\t")); - SERIAL_PORT_MONITOR.println(pHub->OverCurrentProtectMode, BIN); + SerialDebug.println(pHub->OverCurrentProtectMode, BIN); printProgStr(PSTR("TTThinkTime:\t\t")); - SERIAL_PORT_MONITOR.println(pHub->TTThinkTime, BIN); + SerialDebug.println(pHub->TTThinkTime, BIN); printProgStr(PSTR("PortIndicatorsSupported:")); - SERIAL_PORT_MONITOR.println(pHub->PortIndicatorsSupported, BIN); + SerialDebug.println(pHub->PortIndicatorsSupported, BIN); printProgStr(PSTR("Reserved:\t\t")); - SERIAL_PORT_MONITOR.println(pHub->Reserved, HEX); + SerialDebug.println(pHub->Reserved, HEX); printProgStr(PSTR("bPwrOn2PwrGood:\t\t")); - SERIAL_PORT_MONITOR.println(pHub->bPwrOn2PwrGood, HEX); + SerialDebug.println(pHub->bPwrOn2PwrGood, HEX); printProgStr(PSTR("bHubContrCurrent:\t")); - SERIAL_PORT_MONITOR.println(pHub->bHubContrCurrent, HEX); + SerialDebug.println(pHub->bHubContrCurrent, HEX); for (uint8_t i=7; i> (num_nibbles-1) * 4)) & 0x0f; - SERIAL_PORT_MONITOR.print(digit, HEX); + SerialDebug.print(digit, HEX); } while(--num_nibbles); } @@ -329,7 +324,7 @@ void printHIDdescr( uint8_t* descr_ptr ) printProgStr(PSTR("\r\nNumb Class Descriptor:\t")); print_hex( ep_ptr->bNumDescriptors, 8 ); printProgStr(PSTR("\r\nDescriptor Type:\t")); - if( ep_ptr->bDescrType == 0x22 ) + if( ep_ptr->bDescrType == 0x22 ) printProgStr(PSTR("REPORT DESCRIPTOR")); else print_hex( ep_ptr->bDescrType, 8 ); @@ -383,5 +378,4 @@ void printProgStr(const prog_char str[]) char c; if(!str) return; while((c = pgm_read_byte(str++))) - SERIAL_PORT_MONITOR.print(c); -} + SerialDebug.print(c); From e25840e0e490c2d8819fb967a64b80ccdc4b4964 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 14 Feb 2016 19:25:53 -0500 Subject: [PATCH 18/22] manually did https://github.com/arduino/ArduinoCore-samd/pull/88 and tested - fixes keyboardcontroller sluggishness --- libraries/USBHost/src/Usb.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/libraries/USBHost/src/Usb.cpp b/libraries/USBHost/src/Usb.cpp index 9abcc2036..33f782eb9 100644 --- a/libraries/USBHost/src/Usb.cpp +++ b/libraries/USBHost/src/Usb.cpp @@ -262,7 +262,8 @@ uint32_t USBHost::InTransfer(EpInfo *pep, uint32_t nak_limit, uint8_t *nbytesptr continue; } if(rcode) { - //printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode); + uhd_freeze_pipe(pep->epAddr); + //printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode); return(rcode);// break; //should be 0, indicating ACK. Else return error code. } /* check for RCVDAVIRQ and generate error if not present */ @@ -304,6 +305,7 @@ uint32_t USBHost::InTransfer(EpInfo *pep, uint32_t nak_limit, uint8_t *nbytesptr break; } // if } //while( 1 ) + uhd_freeze_pipe(pep->epAddr); return ( rcode); } @@ -422,6 +424,15 @@ uint32_t USBHost::dispatchPkt(uint32_t token, uint32_t epAddr, uint32_t nak_limi } //case hrNAK: + if((USB->HOST.HostPipe[epAddr].PINTFLAG.reg & USB_HOST_PINTFLAG_TRFAIL) ) { + USB->HOST.HostPipe[epAddr].PINTFLAG.reg = USB_HOST_PINTFLAG_TRFAIL; + nak_count++; + if(nak_limit && (nak_count == nak_limit)) { + rcode = USB_ERRORFLOW; + return (rcode); + } + } + if( (usb_pipe_table[epAddr].HostDescBank[0].STATUS_BK.reg & USB_ERRORFLOW ) ) { nak_count++; if(nak_limit && (nak_count == nak_limit)) { From f41f197319bd6e2a1a8b2cd3ad99d9eedfdda669 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 14 Feb 2016 19:26:57 -0500 Subject: [PATCH 19/22] Working demo with nice status change notifications --- .../KeyboardController/KeyboardController.ino | 72 +++++++++++++------ 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/libraries/USBHost/examples/KeyboardController/KeyboardController.ino b/libraries/USBHost/examples/KeyboardController/KeyboardController.ino index b869ad803..126bd4754 100644 --- a/libraries/USBHost/examples/KeyboardController/KeyboardController.ino +++ b/libraries/USBHost/examples/KeyboardController/KeyboardController.ino @@ -2,7 +2,7 @@ Keyboard Controller Example Shows the output of a USB Keyboard connected to - the Native USB port on an Arduino Due Board. + the Native USB port on an Arduino Zero created 8 Oct 2012 by Cristian Maglie @@ -15,6 +15,13 @@ // Require keyboard control library #include + +// on a zero with debug port, use debug port +//#define SerialDebug Serial + +// on a feather or non-debug Zero, use Serial1 (since USB is taken!) +#define SerialDebug Serial1 + // Initialize USB Controller USBHost usb; @@ -25,60 +32,62 @@ void printKey(); // This function intercepts key press void keyPressed() { - SERIAL_PORT_MONITOR.print("Pressed: "); + SerialDebug.print("Pressed: "); printKey(); } // This function intercepts key release void keyReleased() { - SERIAL_PORT_MONITOR.print("Released: "); + SerialDebug.print("Released: "); printKey(); } void printKey() { // getOemKey() returns the OEM-code associated with the key - SERIAL_PORT_MONITOR.print(" key:"); - SERIAL_PORT_MONITOR.print(keyboard.getOemKey()); + SerialDebug.print(" key:"); + SerialDebug.print(keyboard.getOemKey()); // getModifiers() returns a bits field with the modifiers-keys int mod = keyboard.getModifiers(); - SERIAL_PORT_MONITOR.print(" mod:"); - SERIAL_PORT_MONITOR.print(mod); + SerialDebug.print(" mod:"); + SerialDebug.print(mod); - SERIAL_PORT_MONITOR.print(" => "); + SerialDebug.print(" => "); if (mod & LeftCtrl) - SERIAL_PORT_MONITOR.print("L-Ctrl "); + SerialDebug.print("L-Ctrl "); if (mod & LeftShift) - SERIAL_PORT_MONITOR.print("L-Shift "); + SerialDebug.print("L-Shift "); if (mod & Alt) - SERIAL_PORT_MONITOR.print("Alt "); + SerialDebug.print("Alt "); if (mod & LeftCmd) - SERIAL_PORT_MONITOR.print("L-Cmd "); + SerialDebug.print("L-Cmd "); if (mod & RightCtrl) - SERIAL_PORT_MONITOR.print("R-Ctrl "); + SerialDebug.print("R-Ctrl "); if (mod & RightShift) - SERIAL_PORT_MONITOR.print("R-Shift "); + SerialDebug.print("R-Shift "); if (mod & AltGr) - SERIAL_PORT_MONITOR.print("AltGr "); + SerialDebug.print("AltGr "); if (mod & RightCmd) - SERIAL_PORT_MONITOR.print("R-Cmd "); + SerialDebug.print("R-Cmd "); // getKey() returns the ASCII translation of OEM key // combined with modifiers. - SERIAL_PORT_MONITOR.write(keyboard.getKey()); - SERIAL_PORT_MONITOR.println(); + SerialDebug.write(keyboard.getKey()); + SerialDebug.println(); } +uint32_t lastUSBstate = 0; + void setup() { - SERIAL_PORT_MONITOR.begin( 115200 ); - while (!SERIAL_PORT_MONITOR); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection - SERIAL_PORT_MONITOR.println("Keyboard Controller Program started"); + SerialDebug.begin( 115200 ); + SerialDebug.println("USB Host Keyboard Controller Program started"); if (usb.Init() == -1) - SERIAL_PORT_MONITOR.println("OSC did not start."); - + SerialDebug.println("USB Host did not start."); + + SerialDebug.println("USB Host started"); delay( 20 ); } @@ -86,4 +95,21 @@ void loop() { // Process USB tasks usb.Task(); + + uint32_t currentUSBstate = usb.getUsbTaskState(); + if (lastUSBstate != currentUSBstate) { + SerialDebug.print("USB state changed: 0x"); + SerialDebug.print(lastUSBstate, HEX); + SerialDebug.print(" -> 0x"); + SerialDebug.println(currentUSBstate, HEX); + switch (currentUSBstate) { + case USB_ATTACHED_SUBSTATE_SETTLE: SerialDebug.println("Device Attached"); break; + case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: SerialDebug.println("Detached, waiting for Device"); break; + case USB_ATTACHED_SUBSTATE_RESET_DEVICE: SerialDebug.println("Resetting Device"); break; + case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE: SerialDebug.println("Reset complete"); break; + case USB_STATE_CONFIGURING: SerialDebug.println("USB Configuring"); break; + case USB_STATE_RUNNING: SerialDebug.println("USB Running"); break; + } + lastUSBstate = currentUSBstate; + } } From 188d8809da64cf970a40388e56784e25a79b58b0 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 14 Feb 2016 19:31:19 -0500 Subject: [PATCH 20/22] woot, that wasnt too bad - updated debug for Serial1, works nicely --- .../MouseController/MouseController.ino | 69 +++++++++++++------ 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/libraries/USBHost/examples/MouseController/MouseController.ino b/libraries/USBHost/examples/MouseController/MouseController.ino index 0cdeef677..62604fc7a 100644 --- a/libraries/USBHost/examples/MouseController/MouseController.ino +++ b/libraries/USBHost/examples/MouseController/MouseController.ino @@ -15,6 +15,14 @@ // Require mouse control library #include +// on a zero with debug port, use debug port +//#define SerialDebug Serial + +// on a feather or non-debug Zero, use Serial1 (since USB is taken!) +#define SerialDebug Serial1 + +uint32_t lastUSBstate = 0; + // Initialize USB Controller USBHost usb; @@ -28,65 +36,65 @@ boolean rightButton = false; // This function intercepts mouse movements void mouseMoved() { - SERIAL_PORT_MONITOR.print("Move: "); - SERIAL_PORT_MONITOR.print(mouse.getXChange()); - SERIAL_PORT_MONITOR.print(", "); - SERIAL_PORT_MONITOR.println(mouse.getYChange()); + SerialDebug.print("Move: "); + SerialDebug.print(mouse.getXChange()); + SerialDebug.print(", "); + SerialDebug.println(mouse.getYChange()); } // This function intercepts mouse movements while a button is pressed void mouseDragged() { - SERIAL_PORT_MONITOR.print("DRAG: "); - SERIAL_PORT_MONITOR.print(mouse.getXChange()); - SERIAL_PORT_MONITOR.print(", "); - SERIAL_PORT_MONITOR.println(mouse.getYChange()); + SerialDebug.print("Drag: "); + SerialDebug.print(mouse.getXChange()); + SerialDebug.print(", "); + SerialDebug.println(mouse.getYChange()); } // This function intercepts mouse button press void mousePressed() { - SERIAL_PORT_MONITOR.print("Pressed: "); + SerialDebug.print("Pressed: "); if (mouse.getButton(LEFT_BUTTON)) { - SERIAL_PORT_MONITOR.print("L"); + SerialDebug.print("L"); leftButton = true; } if (mouse.getButton(MIDDLE_BUTTON)) { - SERIAL_PORT_MONITOR.print("M"); + SerialDebug.print("M"); middleButton = true; } if (mouse.getButton(RIGHT_BUTTON)) { - SERIAL_PORT_MONITOR.print("R"); + SerialDebug.print("R"); rightButton = true; } - SERIAL_PORT_MONITOR.println(); + SerialDebug.println(); } // This function intercepts mouse button release void mouseReleased() { - SERIAL_PORT_MONITOR.print("Released: "); + SerialDebug.print("Released: "); if (!mouse.getButton(LEFT_BUTTON) && leftButton == true) { - SERIAL_PORT_MONITOR.print("L"); + SerialDebug.print("L"); leftButton = false; } if (!mouse.getButton(MIDDLE_BUTTON) && middleButton == true) { - SERIAL_PORT_MONITOR.print("M"); + SerialDebug.print("M"); middleButton = false; } if (!mouse.getButton(RIGHT_BUTTON) && rightButton == true) { - SERIAL_PORT_MONITOR.print("R"); + SerialDebug.print("R"); rightButton = false; } - SERIAL_PORT_MONITOR.println(); + SerialDebug.println(); } void setup() { - SERIAL_PORT_MONITOR.begin( 115200 ); - while (!SERIAL_PORT_MONITOR); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection - SERIAL_PORT_MONITOR.println("Mouse Controller Program started"); + SerialDebug.begin( 115200 ); + SerialDebug.println("USB Host Mouse Controller Program started"); if (usb.Init() == -1) - SERIAL_PORT_MONITOR.println("OSC did not start."); + SerialDebug.println("USB Host did not start."); + SerialDebug.println("USB Host started"); delay( 20 ); } @@ -94,4 +102,21 @@ void loop() { // Process USB tasks usb.Task(); + + uint32_t currentUSBstate = usb.getUsbTaskState(); + if (lastUSBstate != currentUSBstate) { + SerialDebug.print("USB state changed: 0x"); + SerialDebug.print(lastUSBstate, HEX); + SerialDebug.print(" -> 0x"); + SerialDebug.println(currentUSBstate, HEX); + switch (currentUSBstate) { + case USB_ATTACHED_SUBSTATE_SETTLE: SerialDebug.println("Device Attached"); break; + case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: SerialDebug.println("Detached, waiting for Device"); break; + case USB_ATTACHED_SUBSTATE_RESET_DEVICE: SerialDebug.println("Resetting Device"); break; + case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE: SerialDebug.println("Reset complete"); break; + case USB_STATE_CONFIGURING: SerialDebug.println("USB Configuring"); break; + case USB_STATE_RUNNING: SerialDebug.println("USB Running"); break; + } + lastUSBstate = currentUSBstate; + } } From 0303c1635d80e498e76d149598c93d6bd4c577cb Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 5 Mar 2016 21:28:27 -0500 Subject: [PATCH 21/22] merge with upstream, pulse LED & VID/PID change for bootloader --- bootloaders/feather/Makefile | 187 ++- bootloaders/feather/README.md | 75 ++ bootloaders/feather/board_definitions.h | 72 + bootloaders/feather/board_driver_led.c | 22 + bootloaders/feather/board_driver_led.h | 41 + .../uart_driver.c => board_driver_serial.c} | 61 +- .../uart_driver.h => board_driver_serial.h} | 59 +- bootloaders/feather/board_driver_usb.c | 367 ++++++ bootloaders/feather/board_driver_usb.h | 45 + bootloaders/feather/board_init.c | 210 +++ bootloaders/feather/board_startup.c | 147 +++ bootloaders/feather/bootloader_samd21x18.ld | 221 ++++ bootloaders/feather/drivers/cdc_enumerate.c | 765 ----------- bootloaders/feather/drivers/cdc_enumerate.h | 126 -- bootloaders/feather/main.c | 426 +++--- bootloaders/feather/main.h | 69 - bootloaders/feather/readme.txt | 21 - bootloaders/feather/sam_ba_cdc.c | 98 ++ bootloaders/feather/sam_ba_cdc.h | 91 ++ bootloaders/feather/sam_ba_monitor.c | 785 +++++------ bootloaders/feather/sam_ba_monitor.h | 53 +- .../{usart_sam_ba.c => sam_ba_serial.c} | 409 +++--- bootloaders/feather/sam_ba_serial.h | 143 ++ bootloaders/feather/sam_ba_usb.c | 456 +++++++ bootloaders/feather/sam_ba_usb.h | 107 ++ bootloaders/feather/samd21_sam_ba.atsln | 22 + bootloaders/feather/samd21_sam_ba.bin | Bin 6480 -> 0 bytes bootloaders/feather/samd21_sam_ba.cproj | 218 ++++ bootloaders/feather/samd21_sam_ba.elf | Bin 0 -> 647224 bytes bootloaders/feather/samd21j18a_flash.ld | 157 --- bootloaders/feather/startup_samd21.c | 201 --- bootloaders/feather/usart_sam_ba.h | 155 --- bootloaders/feather/utils/compiler.h | 1157 ----------------- bootloaders/feather/utils/interrupt.h | 117 -- .../utils/interrupt/interrupt_sam_nvic.c | 69 - .../utils/interrupt/interrupt_sam_nvic.h | 172 --- .../feather/utils/preprocessor/mrecursion.h | 581 --------- .../feather/utils/preprocessor/mrepeat.h | 321 ----- .../feather/utils/preprocessor/preprocessor.h | 38 - .../feather/utils/preprocessor/stringz.h | 67 - .../feather/utils/preprocessor/tpaste.h | 85 -- bootloaders/feather/utils/status_codes.h | 138 -- 42 files changed, 3345 insertions(+), 5209 deletions(-) create mode 100644 bootloaders/feather/README.md create mode 100644 bootloaders/feather/board_definitions.h create mode 100644 bootloaders/feather/board_driver_led.c create mode 100644 bootloaders/feather/board_driver_led.h rename bootloaders/feather/{drivers/uart_driver.c => board_driver_serial.c} (59%) rename bootloaders/feather/{drivers/uart_driver.h => board_driver_serial.h} (51%) create mode 100644 bootloaders/feather/board_driver_usb.c create mode 100644 bootloaders/feather/board_driver_usb.h create mode 100644 bootloaders/feather/board_init.c create mode 100644 bootloaders/feather/board_startup.c create mode 100644 bootloaders/feather/bootloader_samd21x18.ld delete mode 100644 bootloaders/feather/drivers/cdc_enumerate.c delete mode 100644 bootloaders/feather/drivers/cdc_enumerate.h delete mode 100644 bootloaders/feather/main.h delete mode 100644 bootloaders/feather/readme.txt create mode 100644 bootloaders/feather/sam_ba_cdc.c create mode 100644 bootloaders/feather/sam_ba_cdc.h rename bootloaders/feather/{usart_sam_ba.c => sam_ba_serial.c} (61%) create mode 100644 bootloaders/feather/sam_ba_serial.h create mode 100644 bootloaders/feather/sam_ba_usb.c create mode 100644 bootloaders/feather/sam_ba_usb.h create mode 100644 bootloaders/feather/samd21_sam_ba.atsln delete mode 100644 bootloaders/feather/samd21_sam_ba.bin create mode 100644 bootloaders/feather/samd21_sam_ba.cproj create mode 100644 bootloaders/feather/samd21_sam_ba.elf delete mode 100644 bootloaders/feather/samd21j18a_flash.ld delete mode 100644 bootloaders/feather/startup_samd21.c delete mode 100644 bootloaders/feather/usart_sam_ba.h delete mode 100644 bootloaders/feather/utils/compiler.h delete mode 100644 bootloaders/feather/utils/interrupt.h delete mode 100644 bootloaders/feather/utils/interrupt/interrupt_sam_nvic.c delete mode 100644 bootloaders/feather/utils/interrupt/interrupt_sam_nvic.h delete mode 100644 bootloaders/feather/utils/preprocessor/mrecursion.h delete mode 100644 bootloaders/feather/utils/preprocessor/mrepeat.h delete mode 100644 bootloaders/feather/utils/preprocessor/preprocessor.h delete mode 100644 bootloaders/feather/utils/preprocessor/stringz.h delete mode 100644 bootloaders/feather/utils/preprocessor/tpaste.h delete mode 100644 bootloaders/feather/utils/status_codes.h diff --git a/bootloaders/feather/Makefile b/bootloaders/feather/Makefile index 1531b592e..dc10c59b9 100644 --- a/bootloaders/feather/Makefile +++ b/bootloaders/feather/Makefile @@ -1,29 +1,178 @@ -IDE_PATH=../../../../.. -ARM_GCC_PATH=$(IDE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin -CC=$(ARM_GCC_PATH)/arm-none-eabi-gcc -CFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -c -g -Os -w -std=gnu99 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -LDFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -BLD_EXTA_FLAGS=-D__SAMD21G18A__ +# Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. +# Copyright (c) 2015 Arduino LLC. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# ----------------------------------------------------------------------------- +# Paths +ifeq ($(OS),Windows_NT) + + # Are we using mingw/msys/msys2/cygwin? + ifeq ($(TERM),xterm) + T=$(shell cygpath -u $(LOCALAPPDATA)) + MODULE_PATH?=$(T)/Arduino15/packages/arduino + ARM_GCC_PATH?=$(MODULE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi- + RM=rm + SEP=/ + else + MODULE_PATH?=$(LOCALAPPDATA)/Arduino15/packages/arduino + ARM_GCC_PATH?=$(MODULE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi- + RM=rm + SEP=\\ + endif +else + UNAME_S := $(shell uname -s) + + ifeq ($(UNAME_S),Linux) + MODULE_PATH?=$(HOME)/.arduino15/packages/arduino + ARM_GCC_PATH?=$(MODULE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi- + RM=rm + SEP=/ + endif + + ifeq ($(UNAME_S),Darwin) + MODULE_PATH?=$(HOME)/Library/Arduino15/packages/arduino/ + ARM_GCC_PATH?=$(MODULE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi- + RM=rm + SEP=/ + endif +endif + BUILD_PATH=build -INCLUDES=-I$(IDE_PATH)/tools/CMSIS/CMSIS/Include/ -I$(IDE_PATH)/tools/CMSIS/4.0.0-atmel/Device/ATMEL/ -I$(IDE_PATH)/tools/CMSIS/4.0.0-atmel/CMSIS/Include/ -I./drivers/ -I./utils/ -I./utils/preprocessor/ -I./utils/interrupt -SOURCES=main.c sam_ba_monitor.c startup_samd21.c usart_sam_ba.c drivers/cdc_enumerate.c drivers/uart_driver.c utils/interrupt/interrupt_sam_nvic.c + +# ----------------------------------------------------------------------------- +# Tools +CC=$(ARM_GCC_PATH)gcc +OBJCOPY=$(ARM_GCC_PATH)objcopy +NM=$(ARM_GCC_PATH)nm +SIZE=$(ARM_GCC_PATH)size + +# ----------------------------------------------------------------------------- +# Compiler options +CFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -c -std=gnu99 -ffunction-sections -fdata-sections -nostdlib -nostartfiles --param max-inline-insns-single=500 +ifdef DEBUG +CFLAGS+=-g3 -O1 -DDEBUG=1 +else +CFLAGS+=-Os -DDEBUG=0 +endif + +CFLAGS_EXTRA?=-D__SAMD21G18A__ -DUSB_PID_HIGH=0x00 -DUSB_PID_LOW=0x0B -DUSB_VID_LOW=0x9A -DUSB_VID_HIGH=0x23 +# Arduino Zero (PID == 0x004D) +# CFLAGS_EXTRA?=-D__SAMD21G18A__ -DUSB_PID_HIGH=0x00 -DUSB_PID_LOW=0x4D -DUSB_VID_LOW=0x41 -DUSB_VID_HIGH=0x23 +# Genuino Zero (PID == 0x024D) +# CFLAGS_EXTRA?=-D__SAMD21G18A__ -DUSB_PID_HIGH=0x02 -DUSB_PID_LOW=0x4D -DUSB_VID_LOW=0x41 -DUSB_VID_HIGH=0x23 +# Arduino MKR1000 (PID == 0x004E) +# CFLAGS_EXTRA?=-D__SAMD21G18A__ -DUSB_PID_HIGH=0x00 -DUSB_PID_LOW=0x4E -DUSB_VID_LOW=0x41 -DUSB_VID_HIGH=0x23 +# Genuino MKR1000 (PID == 0x024E) +# CFLAGS_EXTRA?=-D__SAMD21G18A__ -DUSB_PID_HIGH=0x02 -DUSB_PID_LOW=0x4E -DUSB_VID_LOW=0x41 -DUSB_VID_HIGH=0x23 + +INCLUDES=-I"$(MODULE_PATH)/tools/CMSIS/4.0.0-atmel/CMSIS/Include/" -I"$(MODULE_PATH)/tools/CMSIS/4.0.0-atmel/Device/ATMEL/" + +# ----------------------------------------------------------------------------- +# Linker options +LDFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all +LDFLAGS+=-Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols --specs=nano.specs --specs=nosys.specs + +# ----------------------------------------------------------------------------- +# Source files and objects +SOURCES= \ +board_driver_led.c \ +board_driver_serial.c \ +board_driver_usb.c \ +board_init.c \ +board_startup.c \ +main.c \ +sam_ba_usb.c \ +sam_ba_cdc.c \ +sam_ba_monitor.c \ +sam_ba_serial.c + OBJECTS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.o)) +DEPS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.d)) NAME=samd21_sam_ba -EXECUTABLE=$(NAME).bin +ELF=$(NAME).elf +BIN=$(NAME).bin +HEX=$(NAME).hex + +ifneq "test$(AVRSTUDIO_EXE_PATH)" "test" +AS_BUILD=copy_for_atmel_studio +AS_CLEAN=clean_for_atmel_studio +else +AS_BUILD= +AS_CLEAN= +endif + + +all: print_info $(SOURCES) $(BIN) $(HEX) $(AS_BUILD) -SLASH=/ -BSLASH=$(EMPTY)\$(EMPTY) +$(ELF): Makefile $(BUILD_PATH) $(OBJECTS) + @echo ---------------------------------------------------------- + @echo Creating ELF binary + "$(CC)" -L. -L$(BUILD_PATH) $(LDFLAGS) -Os -Wl,--gc-sections -save-temps -Tbootloader_samd21x18.ld -Wl,-Map,"$(BUILD_PATH)/$(NAME).map" -o "$(BUILD_PATH)/$(ELF)" -Wl,--start-group $(OBJECTS) -lm -Wl,--end-group + "$(NM)" "$(BUILD_PATH)/$(ELF)" >"$(BUILD_PATH)/$(NAME)_symbols.txt" + "$(SIZE)" --format=sysv -t -x $(BUILD_PATH)/$(ELF) -all: $(SOURCES) $(EXECUTABLE) +$(BIN): $(ELF) + @echo ---------------------------------------------------------- + @echo Creating flash binary + "$(OBJCOPY)" -O binary $(BUILD_PATH)/$< $@ -$(EXECUTABLE): $(OBJECTS) - $(CC) -L$(BUILD_PATH) $(LDFLAGS) -Os -Wl,--gc-sections -save-temps -Tsamd21j18a_flash.ld -Wl,-Map,$(BUILD_PATH)/$(NAME).map --specs=nano.specs --specs=nosys.specs -o $(BUILD_PATH)/$(NAME).elf $(OBJECTS) -Wl,--start-group -lm -Wl,--end-group - $(ARM_GCC_PATH)/arm-none-eabi-objcopy -O binary $(BUILD_PATH)/$(NAME).elf $@ +$(HEX): $(ELF) + @echo ---------------------------------------------------------- + @echo Creating flash binary + "$(OBJCOPY)" -O ihex $(BUILD_PATH)/$< $@ $(BUILD_PATH)/%.o: %.c - -@mkdir -p $(@D) - $(CC) $(CFLAGS) $(BLD_EXTA_FLAGS) $(INCLUDES) $< -o $@ + @echo ---------------------------------------------------------- + @echo Compiling $< to $@ + "$(CC)" $(CFLAGS) $(CFLAGS_EXTRA) $(INCLUDES) $< -o $@ + @echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +$(BUILD_PATH): + @echo ---------------------------------------------------------- + @echo Creating build folder + -mkdir $(BUILD_PATH) + +print_info: + @echo ---------------------------------------------------------- + @echo Compiling bootloader using + @echo BASE PATH = $(MODULE_PATH) + @echo GCC PATH = $(ARM_GCC_PATH) +# @echo OS = $(OS) +# @echo SHELL = $(SHELL) +# @echo TERM = $(TERM) +# "$(CC)" -v +# env + +copy_for_atmel_studio: $(BIN) $(HEX) + @echo ---------------------------------------------------------- + @echo Atmel Studio detected, copying ELF to project root for debug + cp $(BUILD_PATH)/$(ELF) . + +clean_for_atmel_studio: + @echo ---------------------------------------------------------- + @echo Atmel Studio detected, cleaning ELF from project root + -$(RM) ./$(ELF) + +clean: $(AS_CLEAN) + @echo ---------------------------------------------------------- + @echo Cleaning project + -$(RM) $(BIN) + -$(RM) $(HEX) + -$(RM) $(BUILD_PATH)/*.* + -rmdir $(BUILD_PATH) -clean: - del $(EXECUTABLE) $(subst /,\,$(OBJECTS)) $(subst /,\,$(BUILD_PATH)/$(NAME).*) +.phony: print_info $(BUILD_PATH) diff --git a/bootloaders/feather/README.md b/bootloaders/feather/README.md new file mode 100644 index 000000000..44f4e4e02 --- /dev/null +++ b/bootloaders/feather/README.md @@ -0,0 +1,75 @@ +# Arduino Zero Bootloader + +## 1- Prerequisites + +The project build is based on Makefile system. +Makefile is present at project root and try to handle multi-platform cases. + +Multi-plaform GCC is provided by ARM here: https://launchpad.net/gcc-arm-embedded/+download + +Atmel Studio contains both make and ARM GCC toolchain. You don't need to install them in this specific use case. + +### Windows + +* Native command line +Make binary can be obtained here: http://gnuwin32.sourceforge.net/packages/make.htm + +* Cygwin/MSys/MSys2/Babun/etc... +It is available natively in all distributions. + +* Atmel Studio +An Atmel Studio **7** Makefile-based project is present at project root, just open samd21_sam_ba.atsln file in AS7. + +### Linux + +Make is usually available by default. + +### OS X + +Make is available through XCode package. + + +## 2- Selecting available SAM-BA interfaces + +By default both USB and UART are made available, but this parameter can be modified in sam_ba_monitor.h, line 31: + +Set the define SAM_BA_INTERFACE to +* SAM_BA_UART_ONLY for only UART interface +* SAM_BA_USBCDC_ONLY for only USB CDC interface +* SAM_BA_BOTH_INTERFACES for enabling both the interfaces + +## 3- Behaviour + +This bootloader implements the double-tap on Reset button. +By quickly pressing this button two times, the board will reset and stay in bootloader, waiting for communication on either USB or USART. + +The USB port in use is the USB Native port, close to the Reset button. +The USART in use is the one available on pins D0/D1, labelled respectively RX/TX. Communication parameters are a baudrate at 115200, 8bits of data, no parity and 1 stop bit (8N1). + +## 4- Description + +**Pinmap** + +The following pins are used by the program : +PA25 : input/output (USB DP) +PA24 : input/output (USB DM) +PA11 : input (USART RX) +PA10 : output (USART TX) + +The application board shall avoid driving the PA25, PA24, PB23 and PB22 signals while the boot program is running (after a POR for example). + +**Clock system** + +CPU runs at 48MHz from Generic Clock Generator 0 on DFLL48M. + +Generic Clock Generator 1 is using external 32kHz oscillator and is the source of DFLL48M. + +USB and USART are using Generic Clock Generator 0 also. + +**Memory Mapping** + +Bootloader code will be located at 0x0 and executed before any applicative code. + +Applications compiled to be executed along with the bootloader will start at 0x2000 (see linker script bootloader_samd21x18.ld). + +Before jumping to the application, the bootloader changes the VTOR register to use the interrupt vectors of the application @0x2000.<- not required as application code is taking care of this. diff --git a/bootloaders/feather/board_definitions.h b/bootloaders/feather/board_definitions.h new file mode 100644 index 000000000..458e1b0a7 --- /dev/null +++ b/bootloaders/feather/board_definitions.h @@ -0,0 +1,72 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _BOARD_DEFINITIONS_H_ +#define _BOARD_DEFINITIONS_H_ + +/* + * If BOOT_DOUBLE_TAP_ADDRESS is defined the bootloader is started by + * quickly tapping two times on the reset button. + * BOOT_DOUBLE_TAP_ADDRESS must point to a free SRAM cell that must not + * be touched from the loaded application. + */ +#define BOOT_DOUBLE_TAP_ADDRESS (0x20007FFCul) +#define BOOT_DOUBLE_TAP_DATA (*((volatile uint32_t *) BOOT_DOUBLE_TAP_ADDRESS)) + +/* + * If BOOT_LOAD_PIN is defined the bootloader is started if the selected + * pin is tied LOW. + */ +//#define BOOT_LOAD_PIN PIN_PA21 // Pin 7 +//#define BOOT_LOAD_PIN PIN_PA15 // Pin 5 +#define BOOT_PIN_MASK (1U << (BOOT_LOAD_PIN & 0x1f)) + +#define CPU_FREQUENCY (48000000ul) + +#define BOOT_USART_MODULE SERCOM0 +#define BOOT_USART_BUS_CLOCK_INDEX PM_APBCMASK_SERCOM0 +#define BOOT_USART_PER_CLOCK_INDEX GCLK_ID_SERCOM0_CORE +#define BOOT_USART_PAD_SETTINGS UART_RX_PAD3_TX_PAD2 +#define BOOT_USART_PAD3 PINMUX_PA11C_SERCOM0_PAD3 +#define BOOT_USART_PAD2 PINMUX_PA10C_SERCOM0_PAD2 +#define BOOT_USART_PAD1 PINMUX_UNUSED +#define BOOT_USART_PAD0 PINMUX_UNUSED + +/* Frequency of the board main oscillator */ +#define VARIANT_MAINOSC (32768ul) + +/* Master clock frequency */ +#define VARIANT_MCK CPU_FREQUENCY + +#define NVM_SW_CALIB_DFLL48M_COARSE_VAL (58) +#define NVM_SW_CALIB_DFLL48M_FINE_VAL (64) + +/* + * LEDs definitions + */ +#define BOARD_LED_PORT (0) +#define BOARD_LED_PIN (17) + +#define BOARD_LEDRX_PORT (1) +#define BOARD_LEDRX_PIN (3) + +#define BOARD_LEDTX_PORT (0) +#define BOARD_LEDTX_PIN (27) + +#endif // _BOARD_DEFINITIONS_H_ diff --git a/bootloaders/feather/board_driver_led.c b/bootloaders/feather/board_driver_led.c new file mode 100644 index 000000000..1a2430aff --- /dev/null +++ b/bootloaders/feather/board_driver_led.c @@ -0,0 +1,22 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "board_driver_led.h" + + diff --git a/bootloaders/feather/board_driver_led.h b/bootloaders/feather/board_driver_led.h new file mode 100644 index 000000000..6f1fd7580 --- /dev/null +++ b/bootloaders/feather/board_driver_led.h @@ -0,0 +1,41 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _BOARD_DRIVER_LED_ +#define _BOARD_DRIVER_LED_ + +#include +#include "board_definitions.h" + +inline void LED_init(void) { PORT->Group[BOARD_LED_PORT].DIRSET.reg = (1<Group[BOARD_LED_PORT].OUTSET.reg = (1<Group[BOARD_LED_PORT].OUTCLR.reg = (1<Group[BOARD_LED_PORT].OUTTGL.reg = (1<Group[BOARD_LEDRX_PORT].DIRSET.reg = (1<Group[BOARD_LEDRX_PORT].OUTSET.reg = (1<Group[BOARD_LEDRX_PORT].OUTCLR.reg = (1<Group[BOARD_LEDRX_PORT].OUTTGL.reg = (1<Group[BOARD_LEDTX_PORT].DIRSET.reg = (1<Group[BOARD_LEDTX_PORT].OUTSET.reg = (1<Group[BOARD_LEDTX_PORT].OUTCLR.reg = (1<Group[BOARD_LEDTX_PORT].OUTTGL.reg = (1<USART.DATA.reg; } while (length--); -} \ No newline at end of file +} diff --git a/bootloaders/feather/drivers/uart_driver.h b/bootloaders/feather/board_driver_serial.h similarity index 51% rename from bootloaders/feather/drivers/uart_driver.h rename to bootloaders/feather/board_driver_serial.h index 84bfe1b1a..c752d977d 100644 --- a/bootloaders/feather/drivers/uart_driver.h +++ b/bootloaders/feather/board_driver_serial.h @@ -1,37 +1,28 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ #ifndef UART_DRIVER_H #define UART_DRIVER_H + #include -#include "sam.h" #include +#include #define PINMUX_UNUSED 0xFFFFFFFF #define GCLK_ID_SERCOM0_CORE 0x14 @@ -46,14 +37,6 @@ enum uart_pad_settings { UART_RX_PAD3_TX_PAD2 = SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(1), }; -/** - * \brief Gets the index of the provided SERCOM instance - * - * \param Pointer to SERCOM instance - * \return Index of the SERCOM module - */ -uint32_t uart_get_sercom_index(Sercom *sercom_instance); - /** * \brief Initializes the UART * @@ -104,4 +87,4 @@ void uart_write_buffer_polled(Sercom *sercom, uint8_t *ptr, uint16_t length); */ void uart_read_buffer_polled(Sercom *sercom, uint8_t *ptr, uint16_t length); -#endif \ No newline at end of file +#endif diff --git a/bootloaders/feather/board_driver_usb.c b/bootloaders/feather/board_driver_usb.c new file mode 100644 index 000000000..6534fa338 --- /dev/null +++ b/bootloaders/feather/board_driver_usb.c @@ -0,0 +1,367 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "board_driver_usb.h" +#include "sam_ba_usb.h" +#include "sam_ba_cdc.h" + +#define NVM_USB_PAD_TRANSN_POS (45) +#define NVM_USB_PAD_TRANSN_SIZE (5) +#define NVM_USB_PAD_TRANSP_POS (50) +#define NVM_USB_PAD_TRANSP_SIZE (5) +#define NVM_USB_PAD_TRIM_POS (55) +#define NVM_USB_PAD_TRIM_SIZE (3) + +__attribute__((__aligned__(4))) UsbDeviceDescriptor usb_endpoint_table[MAX_EP]; // Initialized to zero in USB_Init +__attribute__((__aligned__(4))) uint8_t udd_ep_out_cache_buffer[2][64]; //1 for CTRL, 1 for BULK +__attribute__((__aligned__(4))) uint8_t udd_ep_in_cache_buffer[2][64]; //1 for CTRL, 1 for BULK + +static volatile bool read_job = false; + +/*---------------------------------------------------------------------------- + * \brief + */ +P_USB_CDC USB_Open(P_USB_CDC pCdc, Usb *pUsb) +{ + pCdc->pUsb = pUsb; + pCdc->currentConfiguration = 0; + pCdc->currentConnection = 0; + pCdc->IsConfigured = USB_IsConfigured; +// pCdc->Write = USB_Write; +// pCdc->Read = USB_Read; + + pCdc->pUsb->HOST.CTRLA.bit.ENABLE = true; + + return pCdc; +} + +/*---------------------------------------------------------------------------- + * \brief Initializes USB + */ +void USB_Init(void) +{ + uint32_t pad_transn, pad_transp, pad_trim; + + /* Enable USB clock */ + PM->APBBMASK.reg |= PM_APBBMASK_USB; + + /* Set up the USB DP/DN pins */ + PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); + PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); + PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); + PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); + + /* ---------------------------------------------------------------------------------------------- + * Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference) + */ + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( 6 ) | // Generic Clock Multiplexer 6 + GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source + GCLK_CLKCTRL_CLKEN ; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* Reset */ + USB->DEVICE.CTRLA.bit.SWRST = 1; + while (USB->DEVICE.SYNCBUSY.bit.SWRST) + { + /* Sync wait */ + } + + /* Load Pad Calibration */ + pad_transn =( *((uint32_t *)(NVMCTRL_OTP4) + + (NVM_USB_PAD_TRANSN_POS / 32)) + >> (NVM_USB_PAD_TRANSN_POS % 32)) + & ((1 << NVM_USB_PAD_TRANSN_SIZE) - 1); + + if (pad_transn == 0x1F) + { + pad_transn = 5; + } + + USB->HOST.PADCAL.bit.TRANSN = pad_transn; + + pad_transp =( *((uint32_t *)(NVMCTRL_OTP4) + + (NVM_USB_PAD_TRANSP_POS / 32)) + >> (NVM_USB_PAD_TRANSP_POS % 32)) + & ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1); + + if (pad_transp == 0x1F) + { + pad_transp = 29; + } + + USB->HOST.PADCAL.bit.TRANSP = pad_transp; + pad_trim =( *((uint32_t *)(NVMCTRL_OTP4) + + (NVM_USB_PAD_TRIM_POS / 32)) + >> (NVM_USB_PAD_TRIM_POS % 32)) + & ((1 << NVM_USB_PAD_TRIM_SIZE) - 1); + + if (pad_trim == 0x7) + { + pad_trim = 3; + } + + USB->HOST.PADCAL.bit.TRIM = pad_trim; + + /* Set the configuration */ + /* Set mode to Device mode */ + USB->HOST.CTRLA.bit.MODE = 0; + /* Enable Run in Standby */ + USB->HOST.CTRLA.bit.RUNSTDBY = true; + /* Set the descriptor address */ + USB->HOST.DESCADD.reg = (uint32_t)(&usb_endpoint_table[0]); + /* Set speed configuration to Full speed */ + USB->DEVICE.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val; + /* Attach to the USB host */ + USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH; + + /* Initialize endpoint table RAM location to a known value 0 */ + memset((uint8_t *)(&usb_endpoint_table[0]), 0, sizeof(usb_endpoint_table)); +} + +uint32_t USB_Write(Usb *pUsb, const char *pData, uint32_t length, uint8_t ep_num) +{ + uint32_t data_address; + uint8_t buf_index; + + /* Set buffer index */ + buf_index = (ep_num == 0) ? 0 : 1; + + /* Check for requirement for multi-packet or auto zlp */ + if (length >= (1 << (usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.SIZE + 3))) + { + /* Update the EP data address */ + data_address = (uint32_t) pData; + /* Enable auto zlp */ + usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = true; + } + else + { + /* Copy to local buffer */ + memcpy(udd_ep_in_cache_buffer[buf_index], pData, length); + /* Update the EP data address */ + data_address = (uint32_t) &udd_ep_in_cache_buffer[buf_index]; + } + + /* Set the buffer address for ep data */ + usb_endpoint_table[ep_num].DeviceDescBank[1].ADDR.reg = data_address; + /* Set the byte count as zero */ + usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = length; + /* Set the multi packet size as zero for multi-packet transfers where length > ep size */ + usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = 0; + /* Clear the transfer complete flag */ + //pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT1 = true; + pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT |= (1<<1); + /* Set the bank as ready */ + pUsb->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.bit.BK1RDY = true; + + /* Wait for transfer to complete */ + while ( (pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT & (1<<1)) == 0 ); + + return length; +} + +/*---------------------------------------------------------------------------- + * \brief Read available data from Endpoint OUT + */ +uint32_t USB_Read(Usb *pUsb, char *pData, uint32_t length) +{ + uint32_t packetSize = 0; + + if (!read_job) + { + /* Set the buffer address for ep data */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[USB_EP_OUT-1]; + /* Set the byte count as zero */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; + /* Set the byte count as zero */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 0; + /* Start the reception by clearing the bank 0 ready bit */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSCLR.bit.BK0RDY = true; + /* set the user flag */ + read_job = true; + } + + /* Check for Transfer Complete 0 flag */ + if ( pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0) ) + { + /* Set packet size */ + packetSize = SAM_BA_MIN(usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT, length); + /* Copy read data to user buffer */ + memcpy(pData, udd_ep_out_cache_buffer[USB_EP_OUT-1], packetSize); + /* Clear the Transfer Complete 0 flag */ + //pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT0 = true; + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT |= (1 << 0); + /* Clear the user flag */ + read_job = false; + } + + return packetSize; +} + +uint32_t USB_Read_blocking(Usb *pUsb, char *pData, uint32_t length) +{ + if (read_job) + { + /* Stop the reception by setting the bank 0 ready bit */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSSET.bit.BK0RDY = true; + /* Clear the user flag */ + read_job = false; + } + + /* Set the buffer address for ep data */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = ((uint32_t)pData); + /* Set the byte count as zero */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; + /* Set the multi packet size as zero for multi-packet transfers where length > ep size */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = length; + /* Clear the bank 0 ready flag */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSCLR.bit.BK0RDY = true; + /* Wait for transfer to complete */ + while (!( pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0) )); + /* Clear Transfer complete 0 flag */ + //pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT0 = true; + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT |= (1 << 0); + + return length; +} + +/*---------------------------------------------------------------------------- + * \brief Test if the device is configured and handle enumeration + */ +uint8_t USB_IsConfigured(P_USB_CDC pCdc) +{ + Usb *pUsb = pCdc->pUsb; + + /* Check for End of Reset flag */ + if (pUsb->DEVICE.INTFLAG.reg & USB_DEVICE_INTFLAG_EORST) + { + /* Clear the flag */ + pUsb->DEVICE.INTFLAG.bit.EORST = true; + /* Set Device address as 0 */ + pUsb->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | 0; + /* Configure endpoint 0 */ + /* Configure Endpoint 0 for Control IN and Control OUT */ + pUsb->DEVICE.DeviceEndpoint[0].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(1) | USB_DEVICE_EPCFG_EPTYPE1(1); + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; + /* Configure control OUT Packet size to 64 bytes */ + usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.SIZE = 3; + /* Configure control IN Packet size to 64 bytes */ + usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.SIZE = 3; + /* Configure the data buffer address for control OUT */ + usb_endpoint_table[0].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[0]; + /* Configure the data buffer address for control IN */ + usb_endpoint_table[0].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[0]; + /* Set Multipacket size to 8 for control OUT and byte count to 0*/ + usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 8; + usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY; + + // Reset current configuration value to 0 + pCdc->currentConfiguration = 0; + } + else + { + if (pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_RXSTP) + { + sam_ba_usb_CDC_Enumerate(pCdc); + } + } + + return pCdc->currentConfiguration; +} + +/*---------------------------------------------------------------------------- + * \brief Stall the control endpoint + */ +void USB_SendStall(Usb *pUsb, bool direction_in) +{ + /* Check the direction */ + if (direction_in) + { + /* Set STALL request on IN direction */ + //pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.STALLRQ = (1<<1); + } + else + { + /* Set STALL request on OUT direction */ + //pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0; + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.STALLRQ = (1<<0); + } +} + +/*---------------------------------------------------------------------------- + * \brief Send zero length packet through the control endpoint + */ +void USB_SendZlp(Usb *pUsb) +{ + /* Set the byte count as zero */ + usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = 0; + /* Clear the transfer complete flag */ + //pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT1 = true; + pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT |= (1 << 1); + /* Set the bank as ready */ + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.BK1RDY = true; + /* Wait for transfer to complete */ + while (!( pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT & (1<<1) )); +} + +/*---------------------------------------------------------------------------- + * \brief Set USB device address obtained from host + */ +void USB_SetAddress(Usb *pUsb, uint16_t wValue) +{ + pUsb->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | wValue; +} + +/*---------------------------------------------------------------------------- + * \brief Configure USB device + */ +void USB_Configure(Usb *pUsb) +{ + /* Configure BULK OUT endpoint for CDC Data interface*/ + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(3); + /* Set maximum packet size as 64 bytes */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.SIZE = 3; + pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; + /* Configure the data buffer */ + usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[1]; + + /* Configure BULK IN endpoint for CDC Data interface */ + pUsb->DEVICE.DeviceEndpoint[USB_EP_IN].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(3); + /* Set maximum packet size as 64 bytes */ + usb_endpoint_table[USB_EP_IN].DeviceDescBank[1].PCKSIZE.bit.SIZE = 3; + pUsb->DEVICE.DeviceEndpoint[USB_EP_IN].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; + /* Configure the data buffer */ + usb_endpoint_table[USB_EP_IN].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[1]; + + /* Configure INTERRUPT IN endpoint for CDC COMM interface*/ + pUsb->DEVICE.DeviceEndpoint[USB_EP_COMM].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(4); + /* Set maximum packet size as 64 bytes */ + usb_endpoint_table[USB_EP_COMM].DeviceDescBank[1].PCKSIZE.bit.SIZE = 0; + pUsb->DEVICE.DeviceEndpoint[USB_EP_COMM].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; +} diff --git a/bootloaders/feather/board_driver_usb.h b/bootloaders/feather/board_driver_usb.h new file mode 100644 index 000000000..4e71b8c1a --- /dev/null +++ b/bootloaders/feather/board_driver_usb.h @@ -0,0 +1,45 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _BOARD_DRIVER_USB_H_ +#define _BOARD_DRIVER_USB_H_ + +#include "sam_ba_cdc.h" + +extern UsbDeviceDescriptor usb_endpoint_table[MAX_EP]; +extern uint8_t udd_ep_out_cache_buffer[2][64]; //1 for CTRL, 1 for BULK +extern uint8_t udd_ep_in_cache_buffer[2][64]; //1 for CTRL, 1 for BULK + +P_USB_CDC USB_Open(P_USB_CDC pCdc, Usb *pUsb); + +void USB_Init(void); + +uint32_t USB_Write(Usb *pUsb, const char *pData, uint32_t length, uint8_t ep_num); +uint32_t USB_Read(Usb *pUsb, char *pData, uint32_t length); +uint32_t USB_Read_blocking(Usb *pUsb, char *pData, uint32_t length); + +uint8_t USB_IsConfigured(P_USB_CDC pCdc); + +void USB_SendStall(Usb *pUsb, bool direction_in); +void USB_SendZlp(Usb *pUsb); + +void USB_SetAddress(Usb *pUsb, uint16_t wValue); +void USB_Configure(Usb *pUsb); + +#endif // _BOARD_DRIVER_USB_H_ diff --git a/bootloaders/feather/board_init.c b/bootloaders/feather/board_init.c new file mode 100644 index 000000000..c08aedaae --- /dev/null +++ b/bootloaders/feather/board_init.c @@ -0,0 +1,210 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "board_definitions.h" + +/** + * \brief system_init() configures the needed clocks and according Flash Read Wait States. + * At reset: + * - OSC8M clock source is enabled with a divider by 8 (1MHz). + * - Generic Clock Generator 0 (GCLKMAIN) is using OSC8M as source. + * We need to: + * 1) Enable XOSC32K clock (External on-board 32.768Hz oscillator), will be used as DFLL48M reference. + * 2) Put XOSC32K as source of Generic Clock Generator 1 + * 3) Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference) + * 4) Enable DFLL48M clock + * 5) Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz. + * 6) Modify PRESCaler value of OSCM to have 8MHz + * 7) Put OSC8M as source for Generic Clock Generator 3 + */ +// Constants for Clock generators +#define GENERIC_CLOCK_GENERATOR_MAIN (0u) +#define GENERIC_CLOCK_GENERATOR_XOSC32K (1u) +#define GENERIC_CLOCK_GENERATOR_OSCULP32K (2u) /* Initialized at reset for WDT */ +#define GENERIC_CLOCK_GENERATOR_OSC8M (3u) +// Constants for Clock multiplexers +#define GENERIC_CLOCK_MULTIPLEXER_DFLL48M (0u) + +void board_init(void) +{ + /* Set 1 Flash Wait State for 48MHz, cf tables 20.9 and 35.27 in SAMD21 Datasheet */ + NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val; + + /* Turn on the digital interface clock */ + PM->APBAMASK.reg |= PM_APBAMASK_GCLK; + + /* ---------------------------------------------------------------------------------------------- + * 1) Enable XOSC32K clock (External on-board 32.768Hz oscillator) + */ + SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP( 0x6u ) | /* cf table 15.10 of product datasheet in chapter 15.8.6 */ + SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K; + SYSCTRL->XOSC32K.bit.ENABLE = 1; /* separate call, as described in chapter 15.6.3 */ + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY) == 0 ) + { + /* Wait for oscillator stabilization */ + } + + /* Software reset the module to ensure it is re-initialized correctly */ + /* Note: Due to synchronization, there is a delay from writing CTRL.SWRST until the reset is complete. + * CTRL.SWRST and STATUS.SYNCBUSY will both be cleared when the reset is complete, as described in chapter 13.8.1 + */ + GCLK->CTRL.reg = GCLK_CTRL_SWRST; + + while ( (GCLK->CTRL.reg & GCLK_CTRL_SWRST) && (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) ) + { + /* Wait for reset to complete */ + } + + /* ---------------------------------------------------------------------------------------------- + * 2) Put XOSC32K as source of Generic Clock Generator 1 + */ + GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_XOSC32K ); // Generic Clock Generator 1 + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* Write Generic Clock Generator 1 configuration */ + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_XOSC32K ) | // Generic Clock Generator 1 + GCLK_GENCTRL_SRC_XOSC32K | // Selected source is External 32KHz Oscillator +// GCLK_GENCTRL_OE | // Output clock to a pin for tests + GCLK_GENCTRL_GENEN; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* ---------------------------------------------------------------------------------------------- + * 3) Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference) + */ + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GENERIC_CLOCK_MULTIPLEXER_DFLL48M ) | // Generic Clock Multiplexer 0 + GCLK_CLKCTRL_GEN_GCLK1 | // Generic Clock Generator 1 is source + GCLK_CLKCTRL_CLKEN; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* ---------------------------------------------------------------------------------------------- + * 4) Enable DFLL48M clock + */ + + /* DFLL Configuration in Closed Loop mode, cf product datasheet chapter 15.6.7.1 - Closed-Loop Operation */ + + /* Remove the OnDemand mode, Bug http://avr32.icgroup.norway.atmel.com/bugzilla/show_bug.cgi?id=9905 */ + SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0; + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) + { + /* Wait for synchronization */ + } + + SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP( 31 ) | // Coarse step is 31, half of the max value + SYSCTRL_DFLLMUL_FSTEP( 511 ) | // Fine step is 511, half of the max value + SYSCTRL_DFLLMUL_MUL( (VARIANT_MCK/VARIANT_MAINOSC) ); // External 32KHz is the reference + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) + { + /* Wait for synchronization */ + } + + /* Write full configuration to DFLL control register */ + SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE | /* Enable the closed loop mode */ + SYSCTRL_DFLLCTRL_WAITLOCK | + SYSCTRL_DFLLCTRL_QLDIS; /* Disable Quick lock */ + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) + { + /* Wait for synchronization */ + } + + /* Enable the DFLL */ + SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE; + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKC) == 0 || + (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKF) == 0 ) + { + /* Wait for locks flags */ + } + + while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) + { + /* Wait for synchronization */ + } + + /* ---------------------------------------------------------------------------------------------- + * 5) Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz. + */ + GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_MAIN ); // Generic Clock Generator 0 + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* Write Generic Clock Generator 0 configuration */ + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_MAIN ) | // Generic Clock Generator 0 + GCLK_GENCTRL_SRC_DFLL48M | // Selected source is DFLL 48MHz +// GCLK_GENCTRL_OE | // Output clock to a pin for tests + GCLK_GENCTRL_IDC | // Set 50/50 duty cycle + GCLK_GENCTRL_GENEN; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + +#if 0 + /* ---------------------------------------------------------------------------------------------- + * 6) Modify PRESCaler value of OSC8M to have 8MHz + */ + SYSCTRL->OSC8M.bit.PRESC = SYSCTRL_OSC8M_PRESC_1_Val; + SYSCTRL->OSC8M.bit.ONDEMAND = 0; + + /* ---------------------------------------------------------------------------------------------- + * 7) Put OSC8M as source for Generic Clock Generator 3 + */ + GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_OSC8M ); // Generic Clock Generator 3 + + /* Write Generic Clock Generator 3 configuration */ + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_OSC8M ) | // Generic Clock Generator 3 + GCLK_GENCTRL_SRC_OSC8M | // Selected source is RC OSC 8MHz (already enabled at reset) +// GCLK_GENCTRL_OE | // Output clock to a pin for tests + GCLK_GENCTRL_GENEN; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } +#endif //0 + + /* + * Now that all system clocks are configured, we can set CPU and APBx BUS clocks. + * These values are normally the ones present after Reset. + */ + PM->CPUSEL.reg = PM_CPUSEL_CPUDIV_DIV1; + PM->APBASEL.reg = PM_APBASEL_APBADIV_DIV1_Val; + PM->APBBSEL.reg = PM_APBBSEL_APBBDIV_DIV1_Val; + PM->APBCSEL.reg = PM_APBCSEL_APBCDIV_DIV1_Val; +} diff --git a/bootloaders/feather/board_startup.c b/bootloaders/feather/board_startup.c new file mode 100644 index 000000000..aaa5a019f --- /dev/null +++ b/bootloaders/feather/board_startup.c @@ -0,0 +1,147 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +struct ConstVectors +{ + /* Stack pointer */ + void* pvStack; + + /* Cortex-M handlers */ + void* pfnReset_Handler; + void* pfnNMI_Handler; + void* pfnHardFault_Handler; + void* pfnReservedM12; + void* pfnReservedM11; + void* pfnReservedM10; + void* pfnReservedM9; + void* pfnReservedM8; + void* pfnReservedM7; + void* pfnReservedM6; + void* pfnSVC_Handler; + void* pfnReservedM4; + void* pfnReservedM3; + void* pfnPendSV_Handler; + void* pfnSysTick_Handler; +}; + +/* Symbols exported from linker script */ +extern uint32_t __etext ; +extern uint32_t __data_start__ ; +extern uint32_t __data_end__ ; +extern uint32_t __bss_start__ ; +extern uint32_t __bss_end__ ; +extern uint32_t __StackTop; + +extern int main(void); +extern void __libc_init_array(void); + +/* Exception Table */ +__attribute__ ((section(".isr_vector"))) +const struct ConstVectors exception_table = +{ + /* Configure Initial Stack Pointer, using linker-generated symbols */ + .pvStack = (void*) (&__StackTop), + + .pfnReset_Handler = (void*) Reset_Handler, + .pfnNMI_Handler = (void*) NMI_Handler, + .pfnHardFault_Handler = (void*) HardFault_Handler, + .pfnReservedM12 = (void*) (0UL), /* Reserved */ + .pfnReservedM11 = (void*) (0UL), /* Reserved */ + .pfnReservedM10 = (void*) (0UL), /* Reserved */ + .pfnReservedM9 = (void*) (0UL), /* Reserved */ + .pfnReservedM8 = (void*) (0UL), /* Reserved */ + .pfnReservedM7 = (void*) (0UL), /* Reserved */ + .pfnReservedM6 = (void*) (0UL), /* Reserved */ + .pfnSVC_Handler = (void*) SVC_Handler, + .pfnReservedM4 = (void*) (0UL), /* Reserved */ + .pfnReservedM3 = (void*) (0UL), /* Reserved */ + .pfnPendSV_Handler = (void*) PendSV_Handler, + .pfnSysTick_Handler = (void*) SysTick_Handler, +}; + +/** + * \brief This is the code that gets called on processor reset. + * Initializes the device and call the main() routine. + */ +void Reset_Handler( void ) +{ + uint32_t *pSrc, *pDest; + + /* Initialize the initialized data section */ + pSrc = &__etext; + pDest = &__data_start__; + + if ( (&__data_start__ != &__data_end__) && (pSrc != pDest) ) + { + for (; pDest < &__data_end__ ; pDest++, pSrc++ ) + { + *pDest = *pSrc ; + } + } + + /* Clear the zero section */ + if ( &__bss_start__ != &__bss_end__ ) + { + for ( pDest = &__bss_start__ ; pDest < &__bss_end__ ; pDest++ ) + { + *pDest = 0ul ; + } + } + +// board_init(); // will be done in main() after app check + + /* Initialize the C library */ +// __libc_init_array(); + + main(); + + while (1); +} + +void NMI_Handler(void) +{ + __BKPT(14); + while (1); +} + +void HardFault_Handler(void) +{ + __BKPT(13); + while (1); +} + +void SVC_Handler(void) +{ + __BKPT(5); + while (1); +} + +void PendSV_Handler(void) +{ + __BKPT(2); + while (1); +} + +void SysTick_Handler(void) +{ + __BKPT(1); + while (1); +} diff --git a/bootloaders/feather/bootloader_samd21x18.ld b/bootloaders/feather/bootloader_samd21x18.ld new file mode 100644 index 000000000..2a8b056d3 --- /dev/null +++ b/bootloaders/feather/bootloader_samd21x18.ld @@ -0,0 +1,221 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* Linker script to configure memory regions. + * Need modifying for a specific board. + * FLASH.ORIGIN: starting address of flash + * FLASH.LENGTH: length of flash + * RAM.ORIGIN: starting address of RAM bank 0 + * RAM.LENGTH: length of RAM bank 0 + */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x2000 /* First 8KB used by bootloader */ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000-0x0004 /* 4 bytes used by bootloader to keep data between resets */ +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + * __sketch_vectors_ptr + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + . = ORIGIN(FLASH); + + .vectors : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* To copy multiple ROM to RAM sections, + * uncomment .copy.table section and, + * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ + /* + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (__etext2) + LONG (__data2_start__) + LONG (__data2_end__ - __data2_start__) + __copy_table_end__ = .; + } > FLASH + */ + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ + /* + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (__bss2_start__) + LONG (__bss2_end__ - __bss2_start__) + __zero_table_end__ = .; + } > FLASH + */ + + __etext = .; + PROVIDE(__sketch_vectors_ptr = ORIGIN(FLASH) + LENGTH(FLASH)); + + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __end__ = .; + PROVIDE(end = .); + *(.heap*) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + __ram_end__ = ORIGIN(RAM) + LENGTH(RAM) -1 ; + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") +} diff --git a/bootloaders/feather/drivers/cdc_enumerate.c b/bootloaders/feather/drivers/cdc_enumerate.c deleted file mode 100644 index 96d0c6531..000000000 --- a/bootloaders/feather/drivers/cdc_enumerate.c +++ /dev/null @@ -1,765 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#include "cdc_enumerate.h" -#include -#include -#include - - -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - -COMPILER_WORD_ALIGNED UsbDeviceDescriptor usb_endpoint_table[MAX_EP] = {0}; -COMPILER_WORD_ALIGNED uint8_t udd_ep_out_cache_buffer[2][64]; //1 for CTRL, 1 for BULK -COMPILER_WORD_ALIGNED uint8_t udd_ep_in_cache_buffer[2][64]; //1 for CTRL, 1 for BULK - -COMPILER_WORD_ALIGNED -const char devDescriptor[] = { - /* Device descriptor */ - 0x12, // bLength - 0x01, // bDescriptorType - 0x10, // bcdUSBL - 0x01, // - 0x02, // bDeviceClass: CDC class code - 0x00, // bDeviceSubclass: CDC class sub code - 0x00, // bDeviceProtocol: CDC Device protocol - 0x40, // bMaxPacketSize0 - 0x9A, // idVendorL (adafruit) - 0x23, // - 0x0B, // idProductL (feather zero) - 0x00, // - 0x10, // bcdDeviceL - 0x01, // - 0x00, // iManufacturer // 0x01 - 0x00, // iProduct - 0x00, // SerialNumber - 0x01 // bNumConfigs -}; - -COMPILER_WORD_ALIGNED -char cfgDescriptor[] = { - /* ============== CONFIGURATION 1 =========== */ - /* Configuration 1 descriptor */ - 0x09, // CbLength - 0x02, // CbDescriptorType - 0x43, // CwTotalLength 2 EP + Control - 0x00, - 0x02, // CbNumInterfaces - 0x01, // CbConfigurationValue - 0x00, // CiConfiguration - 0xC0, // CbmAttributes 0xA0 - 0x00, // CMaxPower - - /* Communication Class Interface Descriptor Requirement */ - 0x09, // bLength - 0x04, // bDescriptorType - 0x00, // bInterfaceNumber - 0x00, // bAlternateSetting - 0x01, // bNumEndpoints - 0x02, // bInterfaceClass - 0x02, // bInterfaceSubclass - 0x00, // bInterfaceProtocol - 0x00, // iInterface - - /* Header Functional Descriptor */ - 0x05, // bFunction Length - 0x24, // bDescriptor type: CS_INTERFACE - 0x00, // bDescriptor subtype: Header Func Desc - 0x10, // bcdCDC:1.1 - 0x01, - - /* ACM Functional Descriptor */ - 0x04, // bFunctionLength - 0x24, // bDescriptor Type: CS_INTERFACE - 0x02, // bDescriptor Subtype: ACM Func Desc - 0x00, // bmCapabilities - - /* Union Functional Descriptor */ - 0x05, // bFunctionLength - 0x24, // bDescriptorType: CS_INTERFACE - 0x06, // bDescriptor Subtype: Union Func Desc - 0x00, // bMasterInterface: Communication Class Interface - 0x01, // bSlaveInterface0: Data Class Interface - - /* Call Management Functional Descriptor */ - 0x05, // bFunctionLength - 0x24, // bDescriptor Type: CS_INTERFACE - 0x01, // bDescriptor Subtype: Call Management Func Desc - 0x00, // bmCapabilities: D1 + D0 - 0x01, // bDataInterface: Data Class Interface 1 - - /* Endpoint 1 descriptor */ - 0x07, // bLength - 0x05, // bDescriptorType - 0x83, // bEndpointAddress, Endpoint 03 - IN - 0x03, // bmAttributes INT - 0x08, // wMaxPacketSize - 0x00, - 0xFF, // bInterval - - /* Data Class Interface Descriptor Requirement */ - 0x09, // bLength - 0x04, // bDescriptorType - 0x01, // bInterfaceNumber - 0x00, // bAlternateSetting - 0x02, // bNumEndpoints - 0x0A, // bInterfaceClass - 0x00, // bInterfaceSubclass - 0x00, // bInterfaceProtocol - 0x00, // iInterface - - /* First alternate setting */ - /* Endpoint 1 descriptor */ - 0x07, // bLength - 0x05, // bDescriptorType - 0x81, // bEndpointAddress, Endpoint 01 - IN - 0x02, // bmAttributes BULK - USB_EP_IN_SIZE, // wMaxPacketSize - 0x00, - 0x00, // bInterval - - /* Endpoint 2 descriptor */ - 0x07, // bLength - 0x05, // bDescriptorType - 0x02, // bEndpointAddress, Endpoint 02 - OUT - 0x02, // bmAttributes BULK - USB_EP_OUT_SIZE, // wMaxPacketSize - 0x00, - 0x00 // bInterval -}; - - -static usb_cdc_line_coding_t line_coding = { - 115200, // baudrate - 0, // 1 Stop Bit - 0, // None Parity - 8 // 8 Data bits -}; - -static USB_CDC pCdc; - -/* USB standard request code */ -#define STD_GET_STATUS_ZERO 0x0080 -#define STD_GET_STATUS_INTERFACE 0x0081 -#define STD_GET_STATUS_ENDPOINT 0x0082 - -#define STD_CLEAR_FEATURE_ZERO 0x0100 -#define STD_CLEAR_FEATURE_INTERFACE 0x0101 -#define STD_CLEAR_FEATURE_ENDPOINT 0x0102 - -#define STD_SET_FEATURE_ZERO 0x0300 -#define STD_SET_FEATURE_INTERFACE 0x0301 -#define STD_SET_FEATURE_ENDPOINT 0x0302 - -#define STD_SET_ADDRESS 0x0500 -#define STD_GET_DESCRIPTOR 0x0680 -#define STD_SET_DESCRIPTOR 0x0700 -#define STD_GET_CONFIGURATION 0x0880 -#define STD_SET_CONFIGURATION 0x0900 -#define STD_GET_INTERFACE 0x0A81 -#define STD_SET_INTERFACE 0x0B01 -#define STD_SYNCH_FRAME 0x0C82 - -/* CDC Class Specific Request Code */ -#define GET_LINE_CODING 0x21A1 -#define SET_LINE_CODING 0x2021 -#define SET_CONTROL_LINE_STATE 0x2221 - - -static uint8_t USB_IsConfigured(P_USB_CDC pCdc); -static uint32_t USB_Read(P_USB_CDC pCdc, char *pData, uint32_t length); -static uint32_t USB_Write(P_USB_CDC pCdc, const char *pData, uint32_t length, uint8_t ep_num); -static void AT91F_CDC_Enumerate(P_USB_CDC pCdc); - - -/** - * \fn AT91F_InitUSB - * - * \brief Initializes USB - */ -void AT91F_InitUSB(void) -{ - uint32_t pad_transn, pad_transp, pad_trim; - - /* Enable USB clock */ - PM->APBBMASK.reg |= PM_APBBMASK_USB; - - /* Set up the USB DP/DN pins */ - PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; - PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); - PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); - PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; - PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); - PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); - - /* Setup clock for module */ - GCLK_CLKCTRL_Type clkctrl={0}; - uint16_t temp; - /* GCLK_ID - USB - 0x06 */ - GCLK->CLKCTRL.bit.ID = 0x06; - temp = GCLK->CLKCTRL.reg; - clkctrl.bit.CLKEN = true; - clkctrl.bit.WRTLOCK = false; - clkctrl.bit.GEN = GCLK_CLKCTRL_GEN_GCLK1_Val; - GCLK->CLKCTRL.reg = (clkctrl.reg | temp); - - /* Reset */ - USB->HOST.CTRLA.bit.SWRST = 1; - while (USB->HOST.SYNCBUSY.bit.SWRST) { - /* Sync wait */ - } - - /* Load Pad Calibration */ - pad_transn =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_USB_PAD_TRANSN_POS / 32)) - >> (NVM_USB_PAD_TRANSN_POS % 32)) - & ((1 << NVM_USB_PAD_TRANSN_SIZE) - 1); - - if (pad_transn == 0x1F) { - pad_transn = 5; - } - - USB->HOST.PADCAL.bit.TRANSN = pad_transn; - - pad_transp =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_USB_PAD_TRANSP_POS / 32)) - >> (NVM_USB_PAD_TRANSP_POS % 32)) - & ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1); - - if (pad_transp == 0x1F) { - pad_transp = 29; - } - - USB->HOST.PADCAL.bit.TRANSP = pad_transp; - pad_trim =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_USB_PAD_TRIM_POS / 32)) - >> (NVM_USB_PAD_TRIM_POS % 32)) - & ((1 << NVM_USB_PAD_TRIM_SIZE) - 1); - - if (pad_trim == 0x7) { - pad_trim = 3; - } - - USB->HOST.PADCAL.bit.TRIM = pad_trim; - - /* Set the configuration */ - /* Set mode to Device mode */ - USB->HOST.CTRLA.bit.MODE = 0; - /* Enable Run in Standby */ - USB->HOST.CTRLA.bit.RUNSTDBY = true; - /* Set the descriptor address */ - USB->HOST.DESCADD.reg = (uint32_t)(&usb_endpoint_table[0]); - /* Set speed configuration to Full speed */ - USB->DEVICE.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val; - /* Attach to the USB host */ - USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH; - - /* Initialize endpoint table RAM location to a known value 0 */ - memset((uint8_t *)(&usb_endpoint_table[0]), 0, - sizeof(usb_endpoint_table)); -} - -//*---------------------------------------------------------------------------- -//* \fn AT91F_CDC_Open -//* \brief -//*---------------------------------------------------------------------------- -P_USB_CDC AT91F_CDC_Open(P_USB_CDC pCdc,Usb *pUsb) -{ - pCdc->pUsb = pUsb; - pCdc->currentConfiguration = 0; - pCdc->currentConnection = 0; - pCdc->IsConfigured = USB_IsConfigured; - pCdc->Write = USB_Write; - pCdc->Read = USB_Read; - pCdc->pUsb->HOST.CTRLA.bit.ENABLE = true; - return pCdc; -} - -//*---------------------------------------------------------------------------- -//* \fn USB_IsConfigured -//* \brief Test if the device is configured and handle enumerationDEVICE.DeviceEndpoint[ep_num].EPCFG.bit.EPTYPE1 -//*---------------------------------------------------------------------------- -static uint8_t USB_IsConfigured(P_USB_CDC pCdc) -{ - Usb *pUsb = pCdc->pUsb; - - /* Check for End of Reset flag */ - if (pUsb->DEVICE.INTFLAG.reg & USB_DEVICE_INTFLAG_EORST) { - /* Clear the flag */ - pUsb->DEVICE.INTFLAG.bit.EORST = true; - /* Set Device address as 0 */ - pUsb->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | 0; - /* Configure endpoint 0 */ - /* Configure Endpoint 0 for Control IN and Control OUT */ - pUsb->DEVICE.DeviceEndpoint[0].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(1) | USB_DEVICE_EPCFG_EPTYPE1(1); - pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; - pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; - /* Configure control OUT Packet size to 64 bytes */ - usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.SIZE = 3; - /* Configure control IN Packet size to 64 bytes */ - usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.SIZE = 3; - /* Configure the data buffer address for control OUT */ - usb_endpoint_table[0].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[0]; - /* Configure the data buffer address for control IN */ - usb_endpoint_table[0].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[0]; - /* Set Multipacket size to 8 for control OUT and byte count to 0*/ - usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 8; - usb_endpoint_table[0].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; - pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY; - - // Reset current configuration value to 0 - pCdc->currentConfiguration = 0; - } else if (pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_RXSTP) { - AT91F_CDC_Enumerate(pCdc); - } - - return pCdc->currentConfiguration; -} - - -static volatile bool read_job = false; -//*---------------------------------------------------------------------------- -//* \fn USB_Read -//* \brief Read available data from Endpoint OUT -//*---------------------------------------------------------------------------- -static uint32_t USB_Read(P_USB_CDC pCdc, char *pData, uint32_t length) -{ - Usb *pUsb = pCdc->pUsb; - uint32_t packetSize = 0; - - if (!read_job) { - /* Set the buffer address for ep data */ - usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[USB_EP_OUT-1]; - /* Set the byte count as zero */ - usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; - /* Set the byte count as zero */ - usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 0; - /* Start the reception by clearing the bank 0 ready bit */ - pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSCLR.bit.BK0RDY = true; - /* set the user flag */ - read_job = true; - } - - /* Check for Transfer Complete 0 flag */ - if ( pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0) ) { - /* Set packet size */ - packetSize = MIN(usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT, length); - /* Copy read data to user buffer */ - memcpy(pData, udd_ep_out_cache_buffer[USB_EP_OUT-1], packetSize); - /* Clear the Transfer Complete 0 flag */ - //pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT0 = true; - pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT |= (1 << 0); - /* Clear the user flag */ - read_job = false; - } - - return packetSize; -} - -static uint32_t USB_Read_blocking(P_USB_CDC pCdc, char *pData, uint32_t length) -{ - Usb *pUsb = pCdc->pUsb; - - if (read_job) { - /* Stop the reception by setting the bank 0 ready bit */ - pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSSET.bit.BK0RDY = true; - /* Clear the user flag */ - read_job = false; - } - - /* Set the buffer address for ep data */ - usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = ((uint32_t)pData); - /* Set the byte count as zero */ - usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; - /* Set the multi packet size as zero for multi-packet transfers where length > ep size */ - usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = length; - /* Clear the bank 0 ready flag */ - pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSCLR.bit.BK0RDY = true; - /* Wait for transfer to complete */ - while (!( pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0) )); - /* Clear Transfer complete 0 flag */ - //pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT0 = true; - pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT |= (1 << 0); - - return length; - -} - - -static uint32_t USB_Write(P_USB_CDC pCdc, const char *pData, uint32_t length, uint8_t ep_num) -{ - Usb *pUsb = pCdc->pUsb; - uint32_t data_address; - uint8_t buf_index; - - /* Set buffer index */ - buf_index = (ep_num == 0) ? 0 : 1; - - /* Check for requirement for multi-packet or auto zlp */ - if (length >= (1 << (usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.SIZE + 3))) { - /* Update the EP data address */ - data_address = (uint32_t) pData; - /* Enable auto zlp */ - usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = true; - } else { - /* Copy to local buffer */ - memcpy(udd_ep_in_cache_buffer[buf_index], pData, length); - /* Update the EP data address */ - data_address = (uint32_t) &udd_ep_in_cache_buffer[buf_index]; - } - - /* Set the buffer address for ep data */ - usb_endpoint_table[ep_num].DeviceDescBank[1].ADDR.reg = data_address; - /* Set the byte count as zero */ - usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = length; - /* Set the multi packet size as zero for multi-packet transfers where length > ep size */ - usb_endpoint_table[ep_num].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = 0; - /* Clear the transfer complete flag */ - //pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT1 = true; - pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT |= (1 << 1); - /* Set the bank as ready */ - pUsb->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.bit.BK1RDY = true; - - /* Wait for transfer to complete */ - while (!( pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT & (1<<1) )); - - return length; -} - -//*---------------------------------------------------------------------------- -//* \fn AT91F_USB_SendData -//* \brief Send Data through the control endpoint -//*---------------------------------------------------------------------------- - -static void AT91F_USB_SendData(P_USB_CDC pCdc, const char *pData, uint32_t length) -{ - USB_Write(pCdc, pData, length, 0); -} - -//*---------------------------------------------------------------------------- -//* \fn AT91F_USB_SendZlp -//* \brief Send zero length packet through the control endpoint -//*---------------------------------------------------------------------------- -void AT91F_USB_SendZlp(Usb *pUsb) -{ - /* Set the byte count as zero */ - usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = 0; - /* Clear the transfer complete flag */ - //pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT1 = true; - pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT |= (1 << 1); - /* Set the bank as ready */ - pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.BK1RDY = true; - /* Wait for transfer to complete */ - while (!( pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT & (1<<1) )); -} - -//*---------------------------------------------------------------------------- -//* \fn AT91F_USB_SendStall -//* \brief Stall the control endpoint -//*---------------------------------------------------------------------------- -void AT91F_USB_SendStall(Usb *pUsb, bool direction_in) -{ - /* Check the direction */ - if (direction_in) { - /* Set STALL request on IN direction */ - //pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1; - pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.STALLRQ = (1<<1); - } else { - /* Set STALL request on OUT direction */ - //pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0; - pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.STALLRQ = (1<<0); - } -} - -//*---------------------------------------------------------------------------- -//* \fn AT91F_CDC_Enumerate -//* \brief This function is a callback invoked when a SETUP packet is received -//*---------------------------------------------------------------------------- -void AT91F_CDC_Enumerate(P_USB_CDC pCdc) -{ - Usb *pUsb = pCdc->pUsb; - static volatile uint8_t bmRequestType, bRequest, dir; - static volatile uint16_t wValue, wIndex, wLength, wStatus; - - /* Clear the Received Setup flag */ - pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP = true; - - /* Read the USB request parameters */ - bmRequestType = udd_ep_out_cache_buffer[0][0]; - bRequest = udd_ep_out_cache_buffer[0][1]; - wValue = (udd_ep_out_cache_buffer[0][2] & 0xFF); - wValue |= (udd_ep_out_cache_buffer[0][3] << 8); - wIndex = (udd_ep_out_cache_buffer[0][4] & 0xFF); - wIndex |= (udd_ep_out_cache_buffer[0][5] << 8); - wLength = (udd_ep_out_cache_buffer[0][6] & 0xFF); - wLength |= (udd_ep_out_cache_buffer[0][7] << 8); - - /* Clear the Bank 0 ready flag on Control OUT */ - pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY; - - /* Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1 */ - switch ((bRequest << 8) | bmRequestType) { - case STD_GET_DESCRIPTOR: - if (wValue == 0x100) - /* Return Device Descriptor */ - AT91F_USB_SendData(pCdc, devDescriptor, MIN(sizeof(devDescriptor), wLength)); - else if (wValue == 0x200) - /* Return Configuration Descriptor */ - AT91F_USB_SendData(pCdc, cfgDescriptor, MIN(sizeof(cfgDescriptor), wLength)); - else - /* Stall the request */ - AT91F_USB_SendStall(pUsb, true); - break; - case STD_SET_ADDRESS: - /* Send ZLP */ - AT91F_USB_SendZlp(pUsb); - /* Set device address to the newly received address from host */ - pUsb->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | wValue; - break; - case STD_SET_CONFIGURATION: - /* Store configuration */ - pCdc->currentConfiguration = (uint8_t)wValue; - /* Send ZLP */ - AT91F_USB_SendZlp(pUsb); - /* Configure BULK OUT endpoint for CDC Data interface*/ - pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(3); - /* Set maximum packet size as 64 bytes */ - usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].PCKSIZE.bit.SIZE = 3; - pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; - /* Configure the data buffer */ - usb_endpoint_table[USB_EP_OUT].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[1]; - /* Configure BULK IN endpoint for CDC Data interface */ - pUsb->DEVICE.DeviceEndpoint[USB_EP_IN].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(3); - /* Set maximum packet size as 64 bytes */ - usb_endpoint_table[USB_EP_IN].DeviceDescBank[1].PCKSIZE.bit.SIZE = 3; - pUsb->DEVICE.DeviceEndpoint[USB_EP_IN].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; - /* Configure the data buffer */ - usb_endpoint_table[USB_EP_IN].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[1]; - /* Configure INTERRUPT IN endpoint for CDC COMM interface*/ - pUsb->DEVICE.DeviceEndpoint[USB_EP_COMM].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(4); - /* Set maximum packet size as 64 bytes */ - usb_endpoint_table[USB_EP_COMM].DeviceDescBank[1].PCKSIZE.bit.SIZE = 0; - pUsb->DEVICE.DeviceEndpoint[USB_EP_COMM].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; - break; - case STD_GET_CONFIGURATION: - /* Return current configuration value */ - AT91F_USB_SendData(pCdc, (char *) &(pCdc->currentConfiguration), sizeof(pCdc->currentConfiguration)); - break; - case STD_GET_STATUS_ZERO: - wStatus = 0; - AT91F_USB_SendData(pCdc, (char *) &wStatus, sizeof(wStatus)); - break; - case STD_GET_STATUS_INTERFACE: - wStatus = 0; - AT91F_USB_SendData(pCdc, (char *) &wStatus, sizeof(wStatus)); - break; - case STD_GET_STATUS_ENDPOINT: - wStatus = 0; - dir = wIndex & 80; - wIndex &= 0x0F; - if (wIndex <= 3) { - if (dir) { - //wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ1) ? 1 : 0; - wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<1)) ? 1 : 0; - } else { - //wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ0) ? 1 : 0; - wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<0)) ? 1 : 0; - } - /* Return current status of endpoint */ - AT91F_USB_SendData(pCdc, (char *) &wStatus, sizeof(wStatus)); - } - else - /* Stall the request */ - AT91F_USB_SendStall(pUsb, true); - break; - case STD_SET_FEATURE_ZERO: - /* Stall the request */ - AT91F_USB_SendStall(pUsb, true); - break; - case STD_SET_FEATURE_INTERFACE: - /* Send ZLP */ - AT91F_USB_SendZlp(pUsb); - break; - case STD_SET_FEATURE_ENDPOINT: - dir = wIndex & 0x80; - wIndex &= 0x0F; - if ((wValue == 0) && wIndex && (wIndex <= 3)) { - /* Set STALL request for the endpoint */ - if (dir) { - //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1; - pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.bit.STALLRQ = (1<<1); - } else { - //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0; - pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.bit.STALLRQ = (1<<0); - } - /* Send ZLP */ - AT91F_USB_SendZlp(pUsb); - } - else - /* Stall the request */ - AT91F_USB_SendStall(pUsb, true); - break; - case STD_CLEAR_FEATURE_ZERO: - /* Stall the request */ - AT91F_USB_SendStall(pUsb, true); - break; - case STD_CLEAR_FEATURE_INTERFACE: - /* Send ZLP */ - AT91F_USB_SendZlp(pUsb); - break; - case STD_CLEAR_FEATURE_ENDPOINT: - dir = wIndex & 0x80; - wIndex &= 0x0F; - if ((wValue == 0) && wIndex && (wIndex <= 3)) { - if (dir) { - if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<1)) { - // Remove stall request - //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1; - pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.bit.STALLRQ = (1<<1); - if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL & (1<<1)) { - pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL = (1<<1); - // The Stall has occurred, then reset data toggle - pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_DTGLIN; - } - } - } else { - if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<0)) { - // Remove stall request - //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0; - pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.bit.STALLRQ = (1<<0); - if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL & (1<<0)) { - pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL = (1<<0); - // The Stall has occurred, then reset data toggle - pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_DTGLOUT; - } - } - } - /* Send ZLP */ - AT91F_USB_SendZlp(pUsb); - } - else { - AT91F_USB_SendStall(pUsb, true); - } - break; - - // handle CDC class requests - case SET_LINE_CODING: - /* Send ZLP */ - AT91F_USB_SendZlp(pUsb); - break; - case GET_LINE_CODING: - /* Send current line coding */ - AT91F_USB_SendData(pCdc, (char *) &line_coding, MIN(sizeof(usb_cdc_line_coding_t), wLength)); - break; - case SET_CONTROL_LINE_STATE: - /* Store the current connection */ - pCdc->currentConnection = wValue; - /* Send ZLP */ - AT91F_USB_SendZlp(pUsb); - break; - default: - /* Stall the request */ - AT91F_USB_SendStall(pUsb, true); - break; - } -} - -P_USB_CDC usb_init(void) -{ - pCdc.pUsb = USB; - - /* Initialize USB */ - AT91F_InitUSB(); - /* Get the default CDC structure settings */ - AT91F_CDC_Open((P_USB_CDC)&pCdc, pCdc.pUsb); - return &pCdc; -} - -int cdc_putc(int value) -{ - /* Send single byte on USB CDC */ - USB_Write(&pCdc, (const char *)&value, 1, USB_EP_IN); - return 1; -} - -int cdc_getc(void) -{ - uint8_t rx_char; - /* Read singly byte on USB CDC */ - USB_Read(&pCdc, (char *)&rx_char, 1); - return (int)rx_char; -} - -bool cdc_is_rx_ready(void) -{ - /* Check whether the device is configured */ - if ( !USB_IsConfigured(&pCdc) ) - return 0; - - /* Return transfer complete 0 flag status */ - return (pCdc.pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0)); -} - -uint32_t cdc_write_buf(void const* data, uint32_t length) -{ - /* Send the specified number of bytes on USB CDC */ - USB_Write(&pCdc, (const char *)data, length, USB_EP_IN); - return length; -} - -uint32_t cdc_read_buf(void* data, uint32_t length) -{ - /* Check whether the device is configured */ - if ( !USB_IsConfigured(&pCdc) ) - return 0; - - /* Read from USB CDC */ - return USB_Read(&pCdc, (char *)data, length); -} - -uint32_t cdc_read_buf_xmd(void* data, uint32_t length) -{ - /* Check whether the device is configured */ - if ( !USB_IsConfigured(&pCdc) ) - return 0; - - /* Blocking read till specified number of bytes is received */ - // XXX: USB_Read_blocking is not reliable - // return USB_Read_blocking(&pCdc, (char *)data, length); - - char *dst = (char *)data; - uint32_t remaining = length; - while (remaining) { - uint32_t readed = USB_Read(&pCdc, (char *)dst, remaining); - remaining -= readed; - dst += readed; - } - - return length; -} diff --git a/bootloaders/feather/drivers/cdc_enumerate.h b/bootloaders/feather/drivers/cdc_enumerate.h deleted file mode 100644 index 41002626f..000000000 --- a/bootloaders/feather/drivers/cdc_enumerate.h +++ /dev/null @@ -1,126 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#ifndef CDC_ENUMERATE_H -#define CDC_ENUMERATE_H - -#include "sam.h" -#include "stdbool.h" - -#define USB_EP_OUT 2 -#define USB_EP_OUT_SIZE 0x40 -#define USB_EP_IN 1 -#define USB_EP_IN_SIZE 0x40 -#define USB_EP_COMM 3 -#define MAX_EP 4 - -#define NVM_USB_PAD_TRANSN_POS 45 -#define NVM_USB_PAD_TRANSN_SIZE 5 -#define NVM_USB_PAD_TRANSP_POS 50 -#define NVM_USB_PAD_TRANSP_SIZE 5 -#define NVM_USB_PAD_TRIM_POS 55 -#define NVM_USB_PAD_TRIM_SIZE 3 - -typedef struct _USB_CDC -{ - // Private members - Usb *pUsb; - uint8_t currentConfiguration; - uint8_t currentConnection; - // Public Methods: - uint8_t (*IsConfigured)(struct _USB_CDC *pCdc); - uint32_t (*Write) (struct _USB_CDC *pCdc, const char *pData, uint32_t length, uint8_t ep_num); - uint32_t (*Read) (struct _USB_CDC *pCdc, char *pData, uint32_t length); -} USB_CDC, *P_USB_CDC; - -typedef struct { - uint32_t dwDTERate; - uint8_t bCharFormat; - uint8_t bParityType; - uint8_t bDataBits; -} usb_cdc_line_coding_t; - -/** - * \brief Initializes the USB module - * - * \return Pointer to the USB CDC structure - */ -P_USB_CDC usb_init(void); - -/** - * \brief Sends a single byte through USB CDC - * - * \param Data to send - * \return number of data sent - */ -int cdc_putc(int value); - -/** - * \brief Reads a single byte through USB CDC - * - * \return Data read through USB - */ -int cdc_getc(void); - -/** - * \brief Checks if a character has been received on USB CDC - * - * \return \c 1 if a byte is ready to be read. - */ -bool cdc_is_rx_ready(void); - -/** - * \brief Sends buffer on USB CDC - * - * \param data pointer - * \param number of data to send - * \return number of data sent - */ -uint32_t cdc_write_buf(void const* data, uint32_t length); - -/** - * \brief Gets data on USB CDC - * - * \param data pointer - * \param number of data to read - * \return number of data read - */ -uint32_t cdc_read_buf(void* data, uint32_t length); - -/** - * \brief Gets specified number of bytes on USB CDC - * - * \param data pointer - * \param number of data to read - * \return number of data read - */ -uint32_t cdc_read_buf_xmd(void* data, uint32_t length); - - -#endif // CDC_ENUMERATE_H diff --git a/bootloaders/feather/main.c b/bootloaders/feather/main.c index 82d8b8377..b490596b4 100644 --- a/bootloaders/feather/main.c +++ b/bootloaders/feather/main.c @@ -1,89 +1,37 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -/** - * -------------------- - * SAM-BA Implementation on SAMD21 - * -------------------- - * Requirements to use SAM-BA : - * - * Supported communication interfaces : - * -------------------- - * - * SERCOM5 : RX:PB23 TX:PB22 - * Baudrate : 115200 8N1 - * - * USB : D-:PA24 D+:PA25 - * - * Pins Usage - * -------------------- - * The following pins are used by the program : - * PA25 : input/output - * PA24 : input/output - * PB23 : input - * PB22 : output - * PA15 : input - * - * The application board shall avoid driving the PA25,PA24,PB23,PB22 and PA15 signals - * while the boot program is running (after a POR for example) - * - * Clock system - * -------------------- - * CPU clock source (GCLK_GEN_0) - 8MHz internal oscillator (OSC8M) - * SERCOM5 core GCLK source (GCLK_ID_SERCOM5_CORE) - GCLK_GEN_0 (i.e., OSC8M) - * GCLK Generator 1 source (GCLK_GEN_1) - 48MHz DFLL in Clock Recovery mode (DFLL48M) - * USB GCLK source (GCLK_ID_USB) - GCLK_GEN_1 (i.e., DFLL in CRM mode) - * - * Memory Mapping - * -------------------- - * SAM-BA code will be located at 0x0 and executed before any applicative code. - * - * Applications compiled to be executed along with the bootloader will start at - * 0x2000 - * Before jumping to the application, the bootloader changes the VTOR register - * to use the interrupt vectors of the application @0x2000.<- not required as - * application code is taking care of this - * +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include -#include "compiler.h" #include "sam_ba_monitor.h" -#include "usart_sam_ba.h" -#include "main.h" -#include "cdc_enumerate.h" +#include "sam_ba_serial.h" +#include "board_definitions.h" +#include "board_driver_led.h" +#include "sam_ba_usb.h" +#include "sam_ba_cdc.h" -#define NVM_SW_CALIB_DFLL48M_COARSE_VAL 58 -#define NVM_SW_CALIB_DFLL48M_FINE_VAL 64 +extern uint32_t __sketch_vectors_ptr; // Exported value from linker script +extern void board_init(void); -static void check_start_application(void); +#if (defined DEBUG) && (DEBUG == 1) +volatile uint32_t* pulSketch_Start_Address; +#endif static volatile bool main_b_cdc_enable = false; @@ -93,155 +41,105 @@ static volatile bool main_b_cdc_enable = false; */ static void check_start_application(void) { - volatile PortGroup *led_port = (volatile PortGroup *)&PORT->Group[1]; - led_port->DIRSET.reg = (1<<30); - led_port->OUTCLR.reg = (1<<30); + LED_init(); + LED_off(); #if defined(BOOT_DOUBLE_TAP_ADDRESS) - #define DOUBLE_TAP_MAGIC 0x07738135 - if (PM->RCAUSE.bit.POR) - { - /* On power-on initialize double-tap */ - BOOT_DOUBLE_TAP_DATA = 0; - } - else - { - if (BOOT_DOUBLE_TAP_DATA == DOUBLE_TAP_MAGIC) { - /* Second tap, stay in bootloader */ - BOOT_DOUBLE_TAP_DATA = 0; - return; - } - - /* First tap */ - BOOT_DOUBLE_TAP_DATA = DOUBLE_TAP_MAGIC; - - /* Wait 0.5sec to see if the user tap reset again */ - for (uint32_t i=0; i<125000; i++) /* 500ms */ - /* force compiler to not optimize this... */ - __asm__ __volatile__(""); - - /* Timeout happened, continue boot... */ - BOOT_DOUBLE_TAP_DATA = 0; - } -#endif + #define DOUBLE_TAP_MAGIC 0x07738135 + if (PM->RCAUSE.bit.POR) + { + /* On power-on initialize double-tap */ + BOOT_DOUBLE_TAP_DATA = 0; + } + else + { + if (BOOT_DOUBLE_TAP_DATA == DOUBLE_TAP_MAGIC) + { + /* Second tap, stay in bootloader */ + BOOT_DOUBLE_TAP_DATA = 0; + return; + } - uint32_t app_start_address; + /* First tap */ + BOOT_DOUBLE_TAP_DATA = DOUBLE_TAP_MAGIC; - /* Load the Reset Handler address of the application */ - app_start_address = *(uint32_t *)(APP_START_ADDRESS + 4); + /* Wait 0.5sec to see if the user tap reset again. + * The loop value is based on SAMD21 default 1MHz clock @ reset. + */ + for (uint32_t i=0; i<125000; i++) /* 500ms */ + /* force compiler to not optimize this... */ + __asm__ __volatile__(""); - /** - * Test reset vector of application @APP_START_ADDRESS+4 - * Stay in SAM-BA if *(APP_START+0x4) == 0xFFFFFFFF - * Application erased condition - */ - if (app_start_address == 0xFFFFFFFF) { - /* Stay in bootloader */ - return; - } + /* Timeout happened, continue boot... */ + BOOT_DOUBLE_TAP_DATA = 0; + } +#endif -#if defined(BOOT_LOAD_PIN) - volatile PortGroup *boot_port = (volatile PortGroup *)(&(PORT->Group[BOOT_LOAD_PIN / 32])); - volatile bool boot_en; - - /* Enable the input mode in Boot GPIO Pin */ - boot_port->DIRCLR.reg = BOOT_PIN_MASK; - boot_port->PINCFG[BOOT_LOAD_PIN & 0x1F].reg = PORT_PINCFG_INEN | PORT_PINCFG_PULLEN; - boot_port->OUTSET.reg = BOOT_PIN_MASK; - /* Read the BOOT_LOAD_PIN status */ - boot_en = (boot_port->IN.reg) & BOOT_PIN_MASK; - - /* Check the bootloader enable condition */ - if (!boot_en) { - /* Stay in bootloader */ - return; - } +#if (!defined DEBUG) || ((defined DEBUG) && (DEBUG == 0)) +uint32_t* pulSketch_Start_Address; #endif - led_port->OUTSET.reg = (1<<30); + /* + * Test sketch stack pointer @ &__sketch_vectors_ptr + * Stay in SAM-BA if value @ (&__sketch_vectors_ptr) == 0xFFFFFFFF (Erased flash cell value) + */ + if (__sketch_vectors_ptr == 0xFFFFFFFF) + { + /* Stay in bootloader */ + return; + } - /* Rebase the Stack Pointer */ - __set_MSP(*(uint32_t *) APP_START_ADDRESS); + /* + * Load the sketch Reset Handler address + * __sketch_vectors_ptr is exported from linker script and point on first 32b word of sketch vector table + * First 32b word is sketch stack + * Second 32b word is sketch entry point: Reset_Handler() + */ + pulSketch_Start_Address = &__sketch_vectors_ptr ; + pulSketch_Start_Address++ ; + + /* + * Test vector table address of sketch @ &__sketch_vectors_ptr + * Stay in SAM-BA if this function is not aligned enough, ie not valid + */ + if ( ((uint32_t)(&__sketch_vectors_ptr) & ~SCB_VTOR_TBLOFF_Msk) != 0x00) + { + /* Stay in bootloader */ + return; + } - /* Rebase the vector table base address */ - SCB->VTOR = ((uint32_t) APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk); +/* +#if defined(BOOT_LOAD_PIN) + volatile PortGroup *boot_port = (volatile PortGroup *)(&(PORT->Group[BOOT_LOAD_PIN / 32])); + volatile bool boot_en; + + // Enable the input mode in Boot GPIO Pin + boot_port->DIRCLR.reg = BOOT_PIN_MASK; + boot_port->PINCFG[BOOT_LOAD_PIN & 0x1F].reg = PORT_PINCFG_INEN | PORT_PINCFG_PULLEN; + boot_port->OUTSET.reg = BOOT_PIN_MASK; + // Read the BOOT_LOAD_PIN status + boot_en = (boot_port->IN.reg) & BOOT_PIN_MASK; + + // Check the bootloader enable condition + if (!boot_en) + { + // Stay in bootloader + return; + } +#endif +*/ - /* Jump to application Reset Handler in the application */ - asm("bx %0"::"r"(app_start_address)); -} + LED_on(); -void system_init() -{ - /* Configure flash wait states */ - NVMCTRL->CTRLB.bit.RWS = FLASH_WAIT_STATES; - - /* Set OSC8M prescalar to divide by 1 */ - SYSCTRL->OSC8M.bit.PRESC = 0; - - /* Configure OSC8M as source for GCLK_GEN0 */ - GCLK_GENCTRL_Type genctrl={0}; - uint32_t temp_genctrl; - GCLK->GENCTRL.bit.ID = 0; /* GENERATOR_ID - GCLK_GEN_0 */ - while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); - temp_genctrl = GCLK->GENCTRL.reg; - genctrl.bit.SRC = GCLK_GENCTRL_SRC_OSC8M_Val; - genctrl.bit.GENEN = true; - genctrl.bit.RUNSTDBY = false; - GCLK->GENCTRL.reg = (genctrl.reg | temp_genctrl); - while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); + /* Rebase the Stack Pointer */ + __set_MSP( (uint32_t)(__sketch_vectors_ptr) ); -#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - SYSCTRL_DFLLCTRL_Type dfllctrl_conf = {0}; - SYSCTRL_DFLLVAL_Type dfllval_conf = {0}; - uint32_t coarse =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_SW_CALIB_DFLL48M_COARSE_VAL / 32)) - >> (NVM_SW_CALIB_DFLL48M_COARSE_VAL % 32)) - & ((1 << 6) - 1); - if (coarse == 0x3f) { - coarse = 0x1f; - } - uint32_t fine =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_SW_CALIB_DFLL48M_FINE_VAL / 32)) - >> (NVM_SW_CALIB_DFLL48M_FINE_VAL % 32)) - & ((1 << 10) - 1); - if (fine == 0x3ff) { - fine = 0x1ff; - } - dfllval_conf.bit.COARSE = coarse; - dfllval_conf.bit.FINE = fine; - dfllctrl_conf.bit.USBCRM = true; - dfllctrl_conf.bit.BPLCKC = false; - dfllctrl_conf.bit.QLDIS = false; - dfllctrl_conf.bit.CCDIS = true; - dfllctrl_conf.bit.ENABLE = true; - - SYSCTRL->DFLLCTRL.bit.ONDEMAND = false; - while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY)); - SYSCTRL->DFLLMUL.reg = 48000; - SYSCTRL->DFLLVAL.reg = dfllval_conf.reg; - SYSCTRL->DFLLCTRL.reg = dfllctrl_conf.reg; - - GCLK_CLKCTRL_Type clkctrl={0}; - uint16_t temp; - GCLK->CLKCTRL.bit.ID = 0; /* GCLK_ID - DFLL48M Reference */ - temp = GCLK->CLKCTRL.reg; - clkctrl.bit.CLKEN = true; - clkctrl.bit.WRTLOCK = false; - clkctrl.bit.GEN = GCLK_CLKCTRL_GEN_GCLK0_Val; - GCLK->CLKCTRL.reg = (clkctrl.reg | temp); - - /* Configure DFLL48M as source for GCLK_GEN1 */ - GCLK->GENCTRL.bit.ID = 1; /* GENERATOR_ID - GCLK_GEN_1 */ - while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); - temp_genctrl = GCLK->GENCTRL.reg; - genctrl.bit.SRC = GCLK_GENCTRL_SRC_DFLL48M_Val; - genctrl.bit.GENEN = true; - genctrl.bit.RUNSTDBY = false; - GCLK->GENCTRL.reg = (genctrl.reg | temp_genctrl); - while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); -#endif -} + /* Rebase the vector table base address */ + SCB->VTOR = ((uint32_t)(&__sketch_vectors_ptr) & SCB_VTOR_TBLOFF_Msk); + /* Jump to application Reset Handler in the application */ + asm("bx %0"::"r"(*pulSketch_Start_Address)); +} #if DEBUG_ENABLE # define DEBUG_PIN_HIGH port_pin_set_output_level(BOOT_LED, 1) @@ -251,82 +149,88 @@ void system_init() # define DEBUG_PIN_LOW do{}while(0) #endif - /** * \brief SAMD21 SAM-BA Main loop. * \return Unused (ANSI-C compatibility). */ int main(void) { -#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - P_USB_CDC pCdc; +#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + P_USB_CDC pCdc; #endif - DEBUG_PIN_HIGH; + DEBUG_PIN_HIGH; - /* Jump in application if condition is satisfied */ - check_start_application(); + /* Jump in application if condition is satisfied */ + check_start_application(); - /* We have determined we should stay in the monitor. */ - /* System initialization */ - system_init(); - cpu_irq_enable(); + /* We have determined we should stay in the monitor. */ + /* System initialization */ + board_init(); + __enable_irq(); - #if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - /* UART is enabled in all cases */ - usart_open(); +#if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + /* UART is enabled in all cases */ + serial_open(); #endif #if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - pCdc = (P_USB_CDC)usb_init(); + pCdc = usb_init(); #endif - DEBUG_PIN_LOW; - // output on D13 (PA.17) - LED_PORT.PINCFG[LED_PIN].reg &= ~ (uint8_t)(PORT_PINCFG_INEN); - LED_PORT.DIRSET.reg = (uint32_t)(1 << LED_PIN); + DEBUG_PIN_LOW; + + LED_on(); - /* Wait for a complete enum on usb or a '#' char on serial line */ - while (1) { - pulse_led(1); // while we're waiting, blink the D13 + /* Wait for a complete enum on usb or a '#' char on serial line */ + while (1) + { + pulse_led(3); // while we're waiting, blink the D13 #if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - if (pCdc->IsConfigured(pCdc) != 0) { - main_b_cdc_enable = true; - } - - //Check if a USB enumeration has succeeded - //And com port was opened - if (main_b_cdc_enable) { - sam_ba_monitor_init(SAM_BA_INTERFACE_USBCDC); - //SAM-BA on USB loop - while(1) { - sam_ba_monitor_run(); - } - } + if (pCdc->IsConfigured(pCdc) != 0) + { + main_b_cdc_enable = true; + } + + /* Check if a USB enumeration has succeeded and if comm port has been opened */ + if (main_b_cdc_enable) + { + sam_ba_monitor_init(SAM_BA_INTERFACE_USBCDC); + /* SAM-BA on USB loop */ + while( 1 ) + { + sam_ba_monitor_run(); + } + } #endif + #if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - /* Check if a '#' has been received */ - if (!main_b_cdc_enable && usart_sharp_received()) { - sam_ba_monitor_init(SAM_BA_INTERFACE_USART); - /* SAM-BA on UART loop */ - while(1) { - sam_ba_monitor_run(); - } - } + /* Check if a '#' has been received */ + if (!main_b_cdc_enable && serial_sharp_received()) + { + sam_ba_monitor_init(SAM_BA_INTERFACE_USART); + /* SAM-BA on Serial loop */ + while(1) + { + sam_ba_monitor_run(); + } + } #endif - } + } } // We'll have the D13 LED slowly pulse on and off with bitbang PWM // for a nice 'hey we're in bootload mode' indication! -ada -static uint8_t pulse_tick=0; +static uint16_t pulse_tick=0; +#define BOOT_PULSE_MAX 1000 static int8_t pulse_dir=1; static int16_t pulse_pwm; void pulse_led(int8_t speed) { // blink D13 pulse_tick++; - if (pulse_tick==0) { + if (pulse_tick==BOOT_PULSE_MAX) { + pulse_tick = 0; pulse_pwm += pulse_dir * speed; if (pulse_pwm > 255) { pulse_pwm = 255; @@ -336,8 +240,8 @@ void pulse_led(int8_t speed) { pulse_pwm = 0; pulse_dir = +1; } - LED_ON; + LED_on(); } if (pulse_tick==pulse_pwm) - LED_OFF; + LED_off(); } diff --git a/bootloaders/feather/main.h b/bootloaders/feather/main.h deleted file mode 100644 index f2b10dc46..000000000 --- a/bootloaders/feather/main.h +++ /dev/null @@ -1,69 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -#pragma once - -// Gently pulse the D13 LED -#define LED_PIN 17 -#define PORTA PORT->Group[0] -#define LED_PORT PORTA - -#define LED_ON LED_PORT.OUTSET.reg = (uint32_t)(1 << LED_PIN); -#define LED_OFF LED_PORT.OUTCLR.reg = (uint32_t)(1 << LED_PIN); -/* - * If BOOT_DOUBLE_TAP_ADDRESS is defined the bootloader is started by - * quickly tapping two times on the reset button. - * BOOT_DOUBLE_TAP_ADDRESS must point to a free SRAM cell that must not - * be touched from the loaded application. - */ -#define BOOT_DOUBLE_TAP_ADDRESS 0x20007FFC -#define BOOT_DOUBLE_TAP_DATA (*((volatile uint32_t *) BOOT_DOUBLE_TAP_ADDRESS)) - -/* - * If BOOT_LOAD_PIN is defined the bootloader is started if the selected - * pin is tied LOW. - */ -//#define BOOT_LOAD_PIN PIN_PA21 // Pin 7 -//#define BOOT_LOAD_PIN PIN_PA15 // Pin 5 -#define BOOT_PIN_MASK (1U << (BOOT_LOAD_PIN & 0x1f)) - -#define CPU_FREQUENCY 8000000 -#define APP_START_ADDRESS 0x00002000 -#define FLASH_WAIT_STATES 1 - -#define BOOT_USART_MODULE SERCOM0 -//#define BOOT_USART_MODULE SERCOM5 -#define BOOT_USART_MUX_SETTINGS UART_RX_PAD3_TX_PAD2 -//#define BOOT_USART_PAD3 PINMUX_PB23D_SERCOM5_PAD3 -//#define BOOT_USART_PAD2 PINMUX_PB22D_SERCOM5_PAD2 -#define BOOT_USART_PAD3 PINMUX_PA11C_SERCOM0_PAD3 -#define BOOT_USART_PAD2 PINMUX_PA10C_SERCOM0_PAD2 -#define BOOT_USART_PAD1 PINMUX_UNUSED -#define BOOT_USART_PAD0 PINMUX_UNUSED - diff --git a/bootloaders/feather/readme.txt b/bootloaders/feather/readme.txt deleted file mode 100644 index 8c760449e..000000000 --- a/bootloaders/feather/readme.txt +++ /dev/null @@ -1,21 +0,0 @@ -1- Prerequisites - -IAR Embedded Workbench for ARM 7.30 - -2- Selecting between USB and UART interface - -Set the define SAM_BA_INTERFACE to -SAM_BA_UART_ONLY for only UART interface -SAM_BA_USBCDC_ONLY for only USB CDC interface -SAM_BA_BOTH_INTERFACES for enabling both the interfaces - -SAM_BA_INTERFACE value should be modified in -Project Options -> C/C++ Compiler -> Preprocessor -> Defined symbols -Project Options -> Assembler -> Preprocessor -> Defined symbols - -3- Start application check - -Bootloader checks for the state of BOOT_LOAD_PIN (configurable by the user from main.h). If BOOT_LOAD_PIN is pulled low, bootloader execution is resumed. -Else, the first location of application is fetched and checked. If it is empty (0xFFFFFFFF), then bootloader execution is resumed. Else it jumps to application and starts execution from there. - -Currently, BOOT_LOAD_PIN is PA15 of SAMD21G18A, pin 5 of Arduino Zero board. diff --git a/bootloaders/feather/sam_ba_cdc.c b/bootloaders/feather/sam_ba_cdc.c new file mode 100644 index 000000000..fc5efe348 --- /dev/null +++ b/bootloaders/feather/sam_ba_cdc.c @@ -0,0 +1,98 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "sam_ba_cdc.h" +#include "board_driver_usb.h" + +usb_cdc_line_coding_t line_coding= +{ + 115200, // baudrate + 0, // 1 Stop Bit + 0, // None Parity + 8 // 8 Data bits +}; + +#define pCdc (&sam_ba_cdc) + +int cdc_putc(/*P_USB_CDC pCdc,*/ int value) +{ + /* Send single byte on USB CDC */ + USB_Write(pCdc->pUsb, (const char *)&value, 1, USB_EP_IN); + + return 1; +} + +int cdc_getc(/*P_USB_CDC pCdc*/void) +{ + uint8_t rx_char; + + /* Read singly byte on USB CDC */ + USB_Read(pCdc->pUsb, (char *)&rx_char, 1); + + return (int)rx_char; +} + +bool cdc_is_rx_ready(/*P_USB_CDC pCdc*/void) +{ + /* Check whether the device is configured */ + if ( !USB_IsConfigured(pCdc) ) + return 0; + + /* Return transfer complete 0 flag status */ + return (pCdc->pUsb->DEVICE.DeviceEndpoint[USB_EP_OUT].EPINTFLAG.bit.TRCPT & (1<<0)); +} + +uint32_t cdc_write_buf(/*P_USB_CDC pCdc,*/ void const* data, uint32_t length) +{ + /* Send the specified number of bytes on USB CDC */ + USB_Write(pCdc->pUsb, (const char *)data, length, USB_EP_IN); + return length; +} + +uint32_t cdc_read_buf(/*P_USB_CDC pCdc,*/ void* data, uint32_t length) +{ + /* Check whether the device is configured */ + if ( !USB_IsConfigured(pCdc) ) + return 0; + + /* Read from USB CDC */ + return USB_Read(pCdc->pUsb, (char *)data, length); +} + +uint32_t cdc_read_buf_xmd(/*P_USB_CDC pCdc,*/ void* data, uint32_t length) +{ + /* Check whether the device is configured */ + if ( !USB_IsConfigured(pCdc) ) + return 0; + + /* Blocking read till specified number of bytes is received */ + // XXX: USB_Read_blocking is not reliable + // return USB_Read_blocking(pCdc, (char *)data, length); + + char *dst = (char *)data; + uint32_t remaining = length; + while (remaining) + { + uint32_t readed = USB_Read(pCdc->pUsb, (char *)dst, remaining); + remaining -= readed; + dst += readed; + } + + return length; +} diff --git a/bootloaders/feather/sam_ba_cdc.h b/bootloaders/feather/sam_ba_cdc.h new file mode 100644 index 000000000..49b7643cf --- /dev/null +++ b/bootloaders/feather/sam_ba_cdc.h @@ -0,0 +1,91 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SAM_BA_USB_CDC_H_ +#define _SAM_BA_USB_CDC_H_ + +#include +#include "sam_ba_usb.h" + +typedef struct +{ + uint32_t dwDTERate; + uint8_t bCharFormat; + uint8_t bParityType; + uint8_t bDataBits; +} usb_cdc_line_coding_t; + +/* CDC Class Specific Request Code */ +#define GET_LINE_CODING 0x21A1 +#define SET_LINE_CODING 0x2021 +#define SET_CONTROL_LINE_STATE 0x2221 + +extern usb_cdc_line_coding_t line_coding; + + +/** + * \brief Sends a single byte through USB CDC + * + * \param Data to send + * \return number of data sent + */ +int cdc_putc(/*P_USB_CDC pCdc,*/ int value); + +/** + * \brief Reads a single byte through USB CDC + * + * \return Data read through USB + */ +int cdc_getc(/*P_USB_CDC pCdc*/); + +/** + * \brief Checks if a character has been received on USB CDC + * + * \return \c 1 if a byte is ready to be read. + */ +bool cdc_is_rx_ready(/*P_USB_CDC pCdc*/); + +/** + * \brief Sends buffer on USB CDC + * + * \param data pointer + * \param number of data to send + * \return number of data sent + */ +uint32_t cdc_write_buf(/*P_USB_CDC pCdc,*/ void const* data, uint32_t length); + +/** + * \brief Gets data on USB CDC + * + * \param data pointer + * \param number of data to read + * \return number of data read + */ +uint32_t cdc_read_buf(/*P_USB_CDC pCdc,*/ void* data, uint32_t length); + +/** + * \brief Gets specified number of bytes on USB CDC + * + * \param data pointer + * \param number of data to read + * \return number of data read + */ +uint32_t cdc_read_buf_xmd(/*P_USB_CDC pCdc,*/ void* data, uint32_t length); + +#endif // _SAM_BA_USB_CDC_H_ diff --git a/bootloaders/feather/sam_ba_monitor.c b/bootloaders/feather/sam_ba_monitor.c index 8a81d6dac..ddf7b9773 100644 --- a/bootloaders/feather/sam_ba_monitor.c +++ b/bootloaders/feather/sam_ba_monitor.c @@ -1,39 +1,30 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ #include "sam.h" #include #include "sam_ba_monitor.h" -#include "usart_sam_ba.h" -#include "uart_driver.h" -#include "compiler.h" -#include "cdc_enumerate.h" +#include "sam_ba_serial.h" +#include "board_driver_serial.h" +#include "board_driver_usb.h" +#include "sam_ba_usb.h" +#include "sam_ba_cdc.h" const char RomBOOT_Version[] = SAM_BA_VERSION; const char RomBOOT_ExtendedCapabilities[] = "[Arduino:XYZ]"; @@ -41,35 +32,49 @@ const char RomBOOT_ExtendedCapabilities[] = "[Arduino:XYZ]"; /* Provides one common interface to handle both USART and USB-CDC */ typedef struct { - /* send one byte of data */ - int (*put_c)(int value); - /* Get one byte */ - int (*get_c)(void); - /* Receive buffer not empty */ - bool (*is_rx_ready)(void); - /* Send given data (polling) */ - uint32_t (*putdata)(void const* data, uint32_t length); - /* Get data from comm. device */ - uint32_t (*getdata)(void* data, uint32_t length); - /* Send given data (polling) using xmodem (if necessary) */ - uint32_t (*putdata_xmd)(void const* data, uint32_t length); - /* Get data from comm. device using xmodem (if necessary) */ - uint32_t (*getdata_xmd)(void* data, uint32_t length); + /* send one byte of data */ + int (*put_c)(int value); + /* Get one byte */ + int (*get_c)(void); + /* Receive buffer not empty */ + bool (*is_rx_ready)(void); + /* Send given data (polling) */ + uint32_t (*putdata)(void const* data, uint32_t length); + /* Get data from comm. device */ + uint32_t (*getdata)(void* data, uint32_t length); + /* Send given data (polling) using xmodem (if necessary) */ + uint32_t (*putdata_xmd)(void const* data, uint32_t length); + /* Get data from comm. device using xmodem (if necessary) */ + uint32_t (*getdata_xmd)(void* data, uint32_t length); } t_monitor_if; #if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES /* Initialize structures with function pointers from supported interfaces */ const t_monitor_if uart_if = -{ usart_putc, usart_getc, usart_is_rx_ready, usart_putdata, usart_getdata, - usart_putdata_xmd, usart_getdata_xmd }; +{ + .put_c = serial_putc, + .get_c = serial_getc, + .is_rx_ready = serial_is_rx_ready, + .putdata = serial_putdata, + .getdata = serial_getdata, + .putdata_xmd = serial_putdata_xmd, + .getdata_xmd = serial_getdata_xmd +}; #endif #if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES //Please note that USB doesn't use Xmodem protocol, since USB already includes flow control and data verification //Data are simply forwarded without further coding. const t_monitor_if usbcdc_if = -{ cdc_putc, cdc_getc, cdc_is_rx_ready, cdc_write_buf, - cdc_read_buf, cdc_write_buf, cdc_read_buf_xmd }; +{ + .put_c = cdc_putc, + .get_c = cdc_getc, + .is_rx_ready = cdc_is_rx_ready, + .putdata = cdc_write_buf, + .getdata = cdc_read_buf, + .putdata_xmd = cdc_write_buf, + .getdata_xmd = cdc_read_buf_xmd +}; #endif /* The pointer to the interface object use by the monitor */ @@ -81,17 +86,19 @@ volatile bool b_sam_ba_interface_usart = false; void sam_ba_monitor_init(uint8_t com_interface) { -#if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - //Selects the requested interface for future actions - if (com_interface == SAM_BA_INTERFACE_USART) { - ptr_monitor_if = (t_monitor_if*) &uart_if; - b_sam_ba_interface_usart = true; - } +#if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + //Selects the requested interface for future actions + if (com_interface == SAM_BA_INTERFACE_USART) + { + ptr_monitor_if = (t_monitor_if*) &uart_if; + b_sam_ba_interface_usart = true; + } #endif -#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES - if (com_interface == SAM_BA_INTERFACE_USBCDC) { - ptr_monitor_if = (t_monitor_if*) &usbcdc_if; - } +#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES + if (com_interface == SAM_BA_INTERFACE_USBCDC) + { + ptr_monitor_if = (t_monitor_if*) &usbcdc_if; + } #endif } @@ -103,64 +110,63 @@ void sam_ba_monitor_init(uint8_t com_interface) */ void sam_ba_putdata_term(uint8_t* data, uint32_t length) { - uint8_t temp, buf[12], *data_ascii; - uint32_t i, int_value; - - if (b_terminal_mode) - { - if (length == 4) - int_value = *(uint32_t *) data; - else if (length == 2) - int_value = *(uint16_t *) data; - else - int_value = *(uint8_t *) data; - - data_ascii = buf + 2; - data_ascii += length * 2 - 1; - - for (i = 0; i < length * 2; i++) - { - temp = (uint8_t) (int_value & 0xf); - - if (temp <= 0x9) - *data_ascii = temp | 0x30; - else - *data_ascii = temp + 0x37; - - int_value >>= 4; - data_ascii--; - } - buf[0] = '0'; - buf[1] = 'x'; - buf[length * 2 + 2] = '\n'; - buf[length * 2 + 3] = '\r'; - ptr_monitor_if->putdata(buf, length * 2 + 4); - } - else - ptr_monitor_if->putdata(data, length); - return; + uint8_t temp, buf[12], *data_ascii; + uint32_t i, int_value; + + if (b_terminal_mode) + { + if (length == 4) + int_value = *(uint32_t *) data; + else if (length == 2) + int_value = *(uint16_t *) data; + else + int_value = *(uint8_t *) data; + + data_ascii = buf + 2; + data_ascii += length * 2 - 1; + + for (i = 0; i < length * 2; i++) + { + temp = (uint8_t) (int_value & 0xf); + + if (temp <= 0x9) + *data_ascii = temp | 0x30; + else + *data_ascii = temp + 0x37; + + int_value >>= 4; + data_ascii--; + } + buf[0] = '0'; + buf[1] = 'x'; + buf[length * 2 + 2] = '\n'; + buf[length * 2 + 3] = '\r'; + ptr_monitor_if->putdata(buf, length * 2 + 4); + } + else + ptr_monitor_if->putdata(data, length); + return; } volatile uint32_t sp; void call_applet(uint32_t address) { - uint32_t app_start_address; + uint32_t app_start_address; - cpu_irq_disable(); + __disable_irq(); - sp = __get_MSP(); + sp = __get_MSP(); - /* Rebase the Stack Pointer */ - __set_MSP(*(uint32_t *) address); + /* Rebase the Stack Pointer */ + __set_MSP(*(uint32_t *) address); - /* Load the Reset Handler address of the application */ - app_start_address = *(uint32_t *)(address + 4); + /* Load the Reset Handler address of the application */ + app_start_address = *(uint32_t *)(address + 4); - /* Jump to application Reset Handler in the application */ - asm("bx %0"::"r"(app_start_address)); + /* Jump to application Reset Handler in the application */ + asm("bx %0"::"r"(app_start_address)); } - uint32_t current_number; uint32_t i, length; uint8_t command, *ptr_data, *ptr, data[SIZEBUFMAX]; @@ -169,287 +175,300 @@ uint32_t u32tmp; uint32_t PAGE_SIZE, PAGES, MAX_FLASH; -/** - * \brief This function starts the SAM-BA monitor. - */ -void sam_ba_monitor_run(void) +// Prints a 32-bit integer in hex. +static void put_uint32(uint32_t n) { - uint32_t pageSizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024 }; - PAGE_SIZE = pageSizes[NVMCTRL->PARAM.bit.PSZ]; - PAGES = NVMCTRL->PARAM.bit.NVMP; - MAX_FLASH = PAGE_SIZE * PAGES; - - ptr_data = NULL; - command = 'z'; - while (1) { - sam_ba_monitor_loop(); - } + char buff[8]; + int i; + for (i=0; i<8; i++) + { + int d = n & 0XF; + n = (n >> 4); + + buff[7-i] = d > 9 ? 'A' + d - 10 : '0' + d; + } + ptr_monitor_if->putdata(buff, 8); } -// Prints a 32-bit integer in hex. -void put_uint32(uint32_t n) { - char buff[8]; - int i; - for (i=0; i<8; i++) { - int d = n & 0XF; - n = (n >> 4); - - buff[7-i] = d > 9 ? 'A' + d - 10 : '0' + d; - } - ptr_monitor_if->putdata(buff, 8); +static void sam_ba_monitor_loop(void) +{ + pulse_led(3); + + length = ptr_monitor_if->getdata(data, SIZEBUFMAX); + ptr = data; + + for (i = 0; i < length; i++, ptr++) + { + if (*ptr == 0xff) continue; + + if (*ptr == '#') + { + if (b_terminal_mode) + { + ptr_monitor_if->putdata("\n\r", 2); + } + if (command == 'S') + { + //Check if some data are remaining in the "data" buffer + if(length>i) + { + //Move current indexes to next avail data (currently ptr points to "#") + ptr++; + i++; + + //We need to add first the remaining data of the current buffer already read from usb + //read a maximum of "current_number" bytes + if ((length-i) < current_number) + { + u32tmp=(length-i); + } + else + { + u32tmp=current_number; + } + + memcpy(ptr_data, ptr, u32tmp); + i += u32tmp; + ptr += u32tmp; + j = u32tmp; + } + //update i with the data read from the buffer + i--; + ptr--; + //Do we expect more data ? + if(jgetdata_xmd(ptr_data, current_number-j); + + __asm("nop"); + } + else if (command == 'R') + { + ptr_monitor_if->putdata_xmd(ptr_data, current_number); + } + else if (command == 'O') + { + *ptr_data = (char) current_number; + } + else if (command == 'H') + { + *((uint16_t *) ptr_data) = (uint16_t) current_number; + } + else if (command == 'W') + { + *((int *) ptr_data) = current_number; + } + else if (command == 'o') + { + sam_ba_putdata_term(ptr_data, 1); + } + else if (command == 'h') + { + current_number = *((uint16_t *) ptr_data); + sam_ba_putdata_term((uint8_t*) ¤t_number, 2); + } + else if (command == 'w') + { + current_number = *((uint32_t *) ptr_data); + sam_ba_putdata_term((uint8_t*) ¤t_number, 4); + } + else if (command == 'G') + { + call_applet(current_number); + /* Rebase the Stack Pointer */ + __set_MSP(sp); + __enable_irq(); + if (b_sam_ba_interface_usart) { + ptr_monitor_if->put_c(0x6); + } + } + else if (command == 'T') + { + b_terminal_mode = 1; + ptr_monitor_if->putdata("\n\r", 2); + } + else if (command == 'N') + { + if (b_terminal_mode == 0) + { + ptr_monitor_if->putdata("\n\r", 2); + } + b_terminal_mode = 0; + } + else if (command == 'V') + { + ptr_monitor_if->putdata("v", 1); + ptr_monitor_if->putdata((uint8_t *) RomBOOT_Version, strlen(RomBOOT_Version)); + ptr_monitor_if->putdata(" ", 1); + ptr_monitor_if->putdata((uint8_t *) RomBOOT_ExtendedCapabilities, strlen(RomBOOT_ExtendedCapabilities)); + ptr_monitor_if->putdata(" ", 1); + ptr = (uint8_t*) &(__DATE__); + i = 0; + while (*ptr++ != '\0') + i++; + ptr_monitor_if->putdata((uint8_t *) &(__DATE__), i); + ptr_monitor_if->putdata(" ", 1); + i = 0; + ptr = (uint8_t*) &(__TIME__); + while (*ptr++ != '\0') + i++; + ptr_monitor_if->putdata((uint8_t *) &(__TIME__), i); + ptr_monitor_if->putdata("\n\r", 2); + } + else if (command == 'X') + { + // Syntax: X[ADDR]# + // Erase the flash memory starting from ADDR to the end of flash. + + // Note: the flash memory is erased in ROWS, that is in block of 4 pages. + // Even if the starting address is the last byte of a ROW the entire + // ROW is erased anyway. + + uint32_t dst_addr = current_number; // starting address + + while (dst_addr < MAX_FLASH) + { + // Execute "ER" Erase Row + NVMCTRL->ADDR.reg = dst_addr / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; + while (NVMCTRL->INTFLAG.bit.READY == 0) + ; + dst_addr += PAGE_SIZE * 4; // Skip a ROW + } + + // Notify command completed + ptr_monitor_if->putdata("X\n\r", 3); + } + else if (command == 'Y') + { + // This command writes the content of a buffer in SRAM into flash memory. + + // Syntax: Y[ADDR],0# + // Set the starting address of the SRAM buffer. + + // Syntax: Y[ROM_ADDR],[SIZE]# + // Write the first SIZE bytes from the SRAM buffer (previously set) into + // flash memory starting from address ROM_ADDR + + static uint32_t *src_buff_addr = NULL; + + if (current_number == 0) + { + // Set buffer address + src_buff_addr = (uint32_t*)ptr_data; + } + else + { + // Write to flash + uint32_t size = current_number/4; + uint32_t *src_addr = src_buff_addr; + uint32_t *dst_addr = (uint32_t*)ptr_data; + + // Set automatic page write + NVMCTRL->CTRLB.bit.MANW = 0; + + // Do writes in pages + while (size) + { + // Execute "PBC" Page Buffer Clear + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.READY == 0) + ; + + // Fill page buffer + uint32_t i; + for (i=0; i<(PAGE_SIZE/4) && iADDR.reg = ((uint32_t)dst_addr) / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; + while (NVMCTRL->INTFLAG.bit.READY == 0) + ; + + // Advance to next page + dst_addr += i; + src_addr += i; + size -= i; + } + } + + // Notify command completed + ptr_monitor_if->putdata("Y\n\r", 3); + } + else if (command == 'Z') + { + // This command calculate CRC for a given area of memory. + // It's useful to quickly check if a transfer has been done + // successfully. + + // Syntax: Z[START_ADDR],[SIZE]# + // Returns: Z[CRC]# + + uint8_t *data = (uint8_t *)ptr_data; + uint32_t size = current_number; + uint16_t crc = 0; + uint32_t i = 0; + for (i=0; iputdata("Z", 1); + put_uint32(crc); + ptr_monitor_if->putdata("#\n\r", 3); + } + + command = 'z'; + current_number = 0; + + if (b_terminal_mode) + { + ptr_monitor_if->putdata(">", 1); + } + } + else + { + if (('0' <= *ptr) && (*ptr <= '9')) + { + current_number = (current_number << 4) | (*ptr - '0'); + } + else if (('A' <= *ptr) && (*ptr <= 'F')) + { + current_number = (current_number << 4) | (*ptr - 'A' + 0xa); + } + else if (('a' <= *ptr) && (*ptr <= 'f')) + { + current_number = (current_number << 4) | (*ptr - 'a' + 0xa); + } + else if (*ptr == ',') + { + ptr_data = (uint8_t *) current_number; + current_number = 0; + } + else + { + command = *ptr; + current_number = 0; + } + } + } } -void sam_ba_monitor_loop(void) +/** + * \brief This function starts the SAM-BA monitor. + */ +void sam_ba_monitor_run(void) { - pulse_led(3); - length = ptr_monitor_if->getdata(data, SIZEBUFMAX); - ptr = data; - for (i = 0; i < length; i++, ptr++) - { - if (*ptr == 0xff) continue; - - if (*ptr == '#') - { - if (b_terminal_mode) - { - ptr_monitor_if->putdata("\n\r", 2); - } - if (command == 'S') - { - //Check if some data are remaining in the "data" buffer - if(length>i) - { - //Move current indexes to next avail data (currently ptr points to "#") - ptr++; - i++; - //We need to add first the remaining data of the current buffer already read from usb - //read a maximum of "current_number" bytes - u32tmp=min((length-i),current_number); - memcpy(ptr_data, ptr, u32tmp); - i += u32tmp; - ptr += u32tmp; - j = u32tmp; - } - //update i with the data read from the buffer - i--; - ptr--; - //Do we expect more data ? - if(jgetdata_xmd(ptr_data, current_number-j); - - __asm("nop"); - } - else if (command == 'R') - { - ptr_monitor_if->putdata_xmd(ptr_data, current_number); - } - else if (command == 'O') - { - *ptr_data = (char) current_number; - } - else if (command == 'H') - { - *((uint16_t *) ptr_data) = (uint16_t) current_number; - } - else if (command == 'W') - { - *((int *) ptr_data) = current_number; - } - else if (command == 'o') - { - sam_ba_putdata_term(ptr_data, 1); - } - else if (command == 'h') - { - current_number = *((uint16_t *) ptr_data); - sam_ba_putdata_term((uint8_t*) ¤t_number, 2); - } - else if (command == 'w') - { - current_number = *((uint32_t *) ptr_data); - sam_ba_putdata_term((uint8_t*) ¤t_number, 4); - } - else if (command == 'G') - { - call_applet(current_number); - /* Rebase the Stack Pointer */ - __set_MSP(sp); - cpu_irq_enable(); - if (b_sam_ba_interface_usart) { - ptr_monitor_if->put_c(0x6); - } - } - else if (command == 'T') - { - b_terminal_mode = 1; - ptr_monitor_if->putdata("\n\r", 2); - } - else if (command == 'N') - { - if (b_terminal_mode == 0) - { - ptr_monitor_if->putdata("\n\r", 2); - } - b_terminal_mode = 0; - } - else if (command == 'V') - { - ptr_monitor_if->putdata("v", 1); - ptr_monitor_if->putdata((uint8_t *) RomBOOT_Version, - strlen(RomBOOT_Version)); - ptr_monitor_if->putdata(" ", 1); - ptr_monitor_if->putdata((uint8_t *) RomBOOT_ExtendedCapabilities, - strlen(RomBOOT_ExtendedCapabilities)); - ptr_monitor_if->putdata(" ", 1); - ptr = (uint8_t*) &(__DATE__); - i = 0; - while (*ptr++ != '\0') - i++; - ptr_monitor_if->putdata((uint8_t *) &(__DATE__), i); - ptr_monitor_if->putdata(" ", 1); - i = 0; - ptr = (uint8_t*) &(__TIME__); - while (*ptr++ != '\0') - i++; - ptr_monitor_if->putdata((uint8_t *) &(__TIME__), i); - ptr_monitor_if->putdata("\n\r", 2); - } - else if (command == 'X') - { - // Syntax: X[ADDR]# - // Erase the flash memory starting from ADDR to the end of flash. - - // Note: the flash memory is erased in ROWS, that is in block of 4 pages. - // Even if the starting address is the last byte of a ROW the entire - // ROW is erased anyway. - - uint32_t dst_addr = current_number; // starting address - - while (dst_addr < MAX_FLASH) { - // Execute "ER" Erase Row - NVMCTRL->ADDR.reg = dst_addr / 2; - NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; - while (NVMCTRL->INTFLAG.bit.READY == 0) - ; - dst_addr += PAGE_SIZE * 4; // Skip a ROW - } - - // Notify command completed - ptr_monitor_if->putdata("X\n\r", 3); - } - else if (command == 'Y') - { - // This command writes the content of a buffer in SRAM into flash memory. - - // Syntax: Y[ADDR],0# - // Set the starting address of the SRAM buffer. - - // Syntax: Y[ROM_ADDR],[SIZE]# - // Write the first SIZE bytes from the SRAM buffer (previously set) into - // flash memory starting from address ROM_ADDR - - static uint32_t *src_buff_addr = NULL; - - if (current_number == 0) { - // Set buffer address - src_buff_addr = ptr_data; - - } else { - // Write to flash - uint32_t size = current_number/4; - uint32_t *src_addr = src_buff_addr; - uint32_t *dst_addr = ptr_data; - - // Set automatic page write - NVMCTRL->CTRLB.bit.MANW = 0; - - // Do writes in pages - while (size) { - // Execute "PBC" Page Buffer Clear - NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; - while (NVMCTRL->INTFLAG.bit.READY == 0) - ; - - // Fill page buffer - uint32_t i; - for (i=0; i<(PAGE_SIZE/4) && iADDR.reg = ((uint32_t)dst_addr) / 2; - NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; - while (NVMCTRL->INTFLAG.bit.READY == 0) - ; - - // Advance to next page - dst_addr += i; - src_addr += i; - size -= i; - } - } - - // Notify command completed - ptr_monitor_if->putdata("Y\n\r", 3); - } - else if (command == 'Z') - { - // This command calculate CRC for a given area of memory. - // It's useful to quickly check if a transfer has been done - // successfully. - - // Syntax: Z[START_ADDR],[SIZE]# - // Returns: Z[CRC]# - - uint8_t *data = (uint8_t *)ptr_data; - uint32_t size = current_number; - uint16_t crc = 0; - uint32_t i = 0; - for (i=0; iputdata("Z", 1); - put_uint32(crc); - ptr_monitor_if->putdata("#\n\r", 3); - } - - command = 'z'; - current_number = 0; - - if (b_terminal_mode) - { - ptr_monitor_if->putdata(">", 1); - } - } - else - { - if (('0' <= *ptr) && (*ptr <= '9')) - { - current_number = (current_number << 4) | (*ptr - '0'); - } - else if (('A' <= *ptr) && (*ptr <= 'F')) - { - current_number = (current_number << 4) | (*ptr - 'A' + 0xa); - } - else if (('a' <= *ptr) && (*ptr <= 'f')) - { - current_number = (current_number << 4) | (*ptr - 'a' + 0xa); - } - else if (*ptr == ',') - { - ptr_data = (uint8_t *) current_number; - current_number = 0; - } - else - { - command = *ptr; - current_number = 0; - } - } - } + uint32_t pageSizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024 }; + PAGE_SIZE = pageSizes[NVMCTRL->PARAM.bit.PSZ]; + PAGES = NVMCTRL->PARAM.bit.NVMP; + MAX_FLASH = PAGE_SIZE * PAGES; + + ptr_data = NULL; + command = 'z'; + while (1) + { + sam_ba_monitor_loop(); + } } - - - - diff --git a/bootloaders/feather/sam_ba_monitor.h b/bootloaders/feather/sam_ba_monitor.h index c70ddb187..e72582bcf 100644 --- a/bootloaders/feather/sam_ba_monitor.h +++ b/bootloaders/feather/sam_ba_monitor.h @@ -1,36 +1,26 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ #ifndef _MONITOR_SAM_BA_H_ #define _MONITOR_SAM_BA_H_ -#define SAM_BA_VERSION "1.1" +#define SAM_BA_VERSION "2.0" /* Enable the interfaces to save code size */ #define SAM_BA_BOTH_INTERFACES 0 @@ -41,11 +31,10 @@ #define SAM_BA_INTERFACE SAM_BA_BOTH_INTERFACES #endif -/* Selects USART as the communication interface of the monitor */ -#define SAM_BA_INTERFACE_USART 1 /* Selects USB as the communication interface of the monitor */ #define SAM_BA_INTERFACE_USBCDC 0 - +/* Selects USART as the communication interface of the monitor */ +#define SAM_BA_INTERFACE_USART 1 /* Selects USB as the communication interface of the monitor */ #define SIZEBUFMAX 64 diff --git a/bootloaders/feather/usart_sam_ba.c b/bootloaders/feather/sam_ba_serial.c similarity index 61% rename from bootloaders/feather/usart_sam_ba.c rename to bootloaders/feather/sam_ba_serial.c index 645e725e9..09607ecf6 100644 --- a/bootloaders/feather/usart_sam_ba.c +++ b/bootloaders/feather/sam_ba_serial.c @@ -1,38 +1,26 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011-2012, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following condition is met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -//#include -#include "usart_sam_ba.h" -#include "main.h" -#include "uart_driver.h" -#include "compiler.h" -#include "sam.h" +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "board_definitions.h" +#include "sam_ba_serial.h" +#include "board_driver_serial.h" /* Local reference to current Usart instance in use with this driver */ //struct usart_module usart_sam_ba; @@ -61,22 +49,24 @@ uint8_t mode_of_transfer; /** * \brief Open the given USART */ -void usart_open() +void serial_open(void) { - uint32_t inst; uint32_t port; - uint8_t pin; + uint32_t pin; /* Configure the port pins for SERCOM_USART */ - if (BOOT_USART_PAD0 != PINMUX_UNUSED) { + if (BOOT_USART_PAD0 != PINMUX_UNUSED) + { /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ port = (BOOT_USART_PAD0 & 0x200000) >> 21; - pin = BOOT_USART_PAD0 >> 16; + pin = (BOOT_USART_PAD0 >> 16); PORT->Group[port].PINCFG[(pin - (port*32))].bit.PMUXEN = 1; PORT->Group[port].PMUX[(pin - (port*32))/2].reg &= ~(0xF << (4 * (pin & 0x01u))); PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD0 & 0xFF) << (4 * (pin & 0x01u)); } - if (BOOT_USART_PAD1 != PINMUX_UNUSED) { + + if (BOOT_USART_PAD1 != PINMUX_UNUSED) + { /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ port = (BOOT_USART_PAD1 & 0x200000) >> 21; pin = BOOT_USART_PAD1 >> 16; @@ -84,7 +74,9 @@ void usart_open() PORT->Group[port].PMUX[(pin - (port*32))/2].reg &= ~(0xF << (4 * (pin & 0x01u))); PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD1 & 0xFF) << (4 * (pin & 0x01u)); } - if (BOOT_USART_PAD2 != PINMUX_UNUSED) { + + if (BOOT_USART_PAD2 != PINMUX_UNUSED) + { /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ port = (BOOT_USART_PAD2 & 0x200000) >> 21; pin = BOOT_USART_PAD2 >> 16; @@ -92,7 +84,9 @@ void usart_open() PORT->Group[port].PMUX[(pin - (port*32))/2].reg &= ~(0xF << (4 * (pin & 0x01u))); PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD2 & 0xFF) << (4 * (pin & 0x01u)); } - if (BOOT_USART_PAD3 != PINMUX_UNUSED) { + + if (BOOT_USART_PAD3 != PINMUX_UNUSED) + { /* Mask 6th bit in pin number to check whether it is greater than 32 i.e., PORTB pin */ port = (BOOT_USART_PAD3 & 0x200000) >> 21; pin = BOOT_USART_PAD3 >> 16; @@ -101,23 +95,21 @@ void usart_open() PORT->Group[port].PMUX[(pin - (port*32))/2].reg |= (BOOT_USART_PAD3 & 0xFF) << (4 * (pin & 0x01u)); } - inst = uart_get_sercom_index(BOOT_USART_MODULE); - /* Enable clock for BOOT_USART_MODULE */ - PM->APBCMASK.reg |= (1u << (inst + PM_APBCMASK_SERCOM0_Pos)); + PM->APBCMASK.reg |= BOOT_USART_BUS_CLOCK_INDEX ; /* Set GCLK_GEN0 as source for GCLK_ID_SERCOMx_CORE */ - GCLK_CLKCTRL_Type clkctrl={0}; - uint16_t temp; - GCLK->CLKCTRL.bit.ID = inst + GCLK_ID_SERCOM0_CORE; - temp = GCLK->CLKCTRL.reg; - clkctrl.bit.CLKEN = true; - clkctrl.bit.WRTLOCK = false; - clkctrl.bit.GEN = GCLK_CLKCTRL_GEN_GCLK0_Val; - GCLK->CLKCTRL.reg = (clkctrl.reg | temp); - - /* Baud rate 115200 - clock 8MHz -> BAUD value-50436 */ - uart_basic_init(BOOT_USART_MODULE, 50436, BOOT_USART_MUX_SETTINGS); + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( BOOT_USART_PER_CLOCK_INDEX ) | // Generic Clock 0 (SERCOMx) + GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source + GCLK_CLKCTRL_CLKEN ; + + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) + { + /* Wait for synchronization */ + } + + /* Baud rate 115200 - clock 48MHz -> BAUD value-63018 */ + uart_basic_init(BOOT_USART_MODULE, 63018, BOOT_USART_PAD_SETTINGS); //Initialize flag b_sharp_received = false; @@ -130,10 +122,9 @@ void usart_open() } /** - * \brief Configures communication line - * + * \brief Close communication line */ -void usart_close(void) +void serial_close(void) { uart_disable(BOOT_USART_MODULE); } @@ -146,37 +137,40 @@ void usart_close(void) * * \return \c 1 if function was successfully done, otherwise \c 0. */ -int usart_putc(int value) +int serial_putc(int value) { uart_write_byte(BOOT_USART_MODULE, (uint8_t)value); return 1; } - - -int usart_getc(void) { +int serial_getc(void) +{ uint16_t retval; //Wait until input buffer is filled - while(!(usart_is_rx_ready())); + while(!(serial_is_rx_ready())); retval = (uint16_t)uart_read_byte(BOOT_USART_MODULE); //usart_read_wait(&usart_sam_ba, &retval); return (int)retval; } -int usart_sharp_received(void) { - if (usart_is_rx_ready()) { - if (usart_getc() == SHARP_CHARACTER) +int serial_sharp_received(void) +{ + if (serial_is_rx_ready()) + { + if (serial_getc() == SHARP_CHARACTER) return (true); } return (false); } -bool usart_is_rx_ready(void) { +bool serial_is_rx_ready(void) +{ return (BOOT_USART_MODULE->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_RXC); } -int usart_readc(void) { +int serial_readc(void) +{ int retval; retval = buffer_rx_usart[idx_rx_read]; idx_rx_read = (idx_rx_read + 1) & (USART_BUFFER_SIZE - 1); @@ -184,26 +178,30 @@ int usart_readc(void) { } //Send given data (polling) -uint32_t usart_putdata(void const* data, uint32_t length) { +uint32_t serial_putdata(void const* data, uint32_t length) +{ uint32_t i; uint8_t* ptrdata; ptrdata = (uint8_t*) data; - for (i = 0; i < length; i++) { - usart_putc(*ptrdata); + for (i = 0; i < length; i++) + { + serial_putc(*ptrdata); ptrdata++; } return (i); } //Get data from comm. device -uint32_t usart_getdata(void* data, uint32_t length) { +uint32_t serial_getdata(void* data, uint32_t length) +{ uint8_t* ptrdata; ptrdata = (uint8_t*) data; - *ptrdata = usart_getc(); + *ptrdata = serial_getc(); return (1); } -static const uint16_t crc16Table[256] = { +static const uint16_t crc16Table[256]= +{ 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, @@ -239,29 +237,31 @@ static const uint16_t crc16Table[256] = { }; //*---------------------------------------------------------------------------- -//* \fn add_crc //* \brief Compute the CRC //*---------------------------------------------------------------------------- -unsigned short add_crc(char ptr, unsigned short crc) { +unsigned short serial_add_crc(char ptr, unsigned short crc) +{ return (crc << 8) ^ crc16Table[((crc >> 8) ^ ptr) & 0xff]; } //*---------------------------------------------------------------------------- -//* \fn getbytes //* \brief //*---------------------------------------------------------------------------- -static uint16_t getbytes(uint8_t *ptr_data, uint16_t length) { +static uint16_t getbytes(uint8_t *ptr_data, uint16_t length) +{ uint16_t crc = 0; uint16_t cpt; uint8_t c; - for (cpt = 0; cpt < length; ++cpt) { - c = usart_getc(); + for (cpt = 0; cpt < length; ++cpt) + { + c = serial_getc(); if (error_timeout) return 1; - crc = add_crc(c, crc); + crc = serial_add_crc(c, crc); //crc = (crc << 8) ^ xcrc16tab[(crc>>8) ^ c]; - if (size_of_data || mode_of_transfer) { + if (size_of_data || mode_of_transfer) + { *ptr_data++ = c; if (length == PKTLEN_128) size_of_data--; @@ -272,90 +272,65 @@ static uint16_t getbytes(uint8_t *ptr_data, uint16_t length) { } //*---------------------------------------------------------------------------- -//* \fn putPacket //* \brief Used by Xup to send packets. //*---------------------------------------------------------------------------- -static int putPacket(uint8_t *tmppkt, uint8_t sno) { +static int putPacket(uint8_t *tmppkt, uint8_t sno) +{ uint32_t i; uint16_t chksm; uint8_t data; chksm = 0; - usart_putc(SOH); + serial_putc(SOH); - usart_putc(sno); - usart_putc((uint8_t) ~(sno)); + serial_putc(sno); + serial_putc((uint8_t) ~(sno)); - for (i = 0; i < PKTLEN_128; i++) { - if (size_of_data || mode_of_transfer) { + for (i = 0; i < PKTLEN_128; i++) + { + if (size_of_data || mode_of_transfer) + { data = *tmppkt++; size_of_data--; - } else + } + else data = 0x00; - usart_putc(data); + serial_putc(data); //chksm = (chksm<<8) ^ xcrc16tab[(chksm>>8)^data]; - chksm = add_crc(data, chksm); + chksm = serial_add_crc(data, chksm); } /* An "endian independent way to extract the CRC bytes. */ - usart_putc((uint8_t) (chksm >> 8)); - usart_putc((uint8_t) chksm); + serial_putc((uint8_t) (chksm >> 8)); + serial_putc((uint8_t) chksm); - return (usart_getc()); /* Wait for ack */ + return (serial_getc()); /* Wait for ack */ } //*---------------------------------------------------------------------------- -//* \fn getPacket -//* \brief Used by Xdown to retrieve packets. -//*---------------------------------------------------------------------------- -uint8_t getPacket(uint8_t *ptr_data, uint8_t sno) { - uint8_t seq[2]; - uint16_t crc, xcrc; - - getbytes(seq, 2); - xcrc = getbytes(ptr_data, PKTLEN_128); - if (error_timeout) - return (false); - - /* An "endian independent way to combine the CRC bytes. */ - crc = (uint16_t) usart_getc() << 8; - crc += (uint16_t) usart_getc(); - - if (error_timeout == 1) - return (false); - - if ((crc != xcrc) || (seq[0] != sno) || (seq[1] != (uint8_t) (~sno))) { - usart_putc(CAN); - return (false); - } - - usart_putc(ACK); - return (true); -} - -//*---------------------------------------------------------------------------- -//* \fn Xup //* \brief Called when a transfer from target to host is being made (considered //* an upload). //*---------------------------------------------------------------------------- -//static void Xup(char *ptr_data, uint16_t length) //Send given data (polling) using xmodem (if necessary) -uint32_t usart_putdata_xmd(void const* data, uint32_t length) { +uint32_t serial_putdata_xmd(void const* data, uint32_t length) +{ uint8_t c, sno = 1; uint8_t done; uint8_t * ptr_data = (uint8_t *) data; error_timeout = 0; if (!length) mode_of_transfer = 1; - else { + else + { size_of_data = length; mode_of_transfer = 0; } - if (length & (PKTLEN_128 - 1)) { + if (length & (PKTLEN_128 - 1)) + { length += PKTLEN_128; length &= ~(PKTLEN_128 - 1); } @@ -364,58 +339,68 @@ uint32_t usart_putdata_xmd(void const* data, uint32_t length) { /* Wait to receive a NAK or 'C' from receiver. */ done = 0; while (!done) { - c = (uint8_t) usart_getc(); - if (error_timeout) { // Test for timeout in usart_getc + c = (uint8_t) serial_getc(); + if (error_timeout) + { // Test for timeout in serial_getc error_timeout = 0; - c = (uint8_t) usart_getc(); - if (error_timeout) { + c = (uint8_t) serial_getc(); + if (error_timeout) + { error_timeout = 0; return (0); } } - switch (c) { - case NAK: - done = 1; - // ("CSM"); + switch (c) + { + case NAK: + done = 1; + // ("CSM"); break; - case 'C': - done = 1; - // ("CRC"); + case 'C': + done = 1; + // ("CRC"); break; - case 'q': /* ELS addition, not part of XMODEM spec. */ - return (0); - default: + case 'q': /* ELS addition, not part of XMODEM spec. */ + return (0); + default: break; } } done = 0; sno = 1; - while (!done) { + while (!done) + { c = (uint8_t) putPacket((uint8_t *) ptr_data, sno); - if (error_timeout) { // Test for timeout in usart_getc + if (error_timeout) + { // Test for timeout in serial_getc error_timeout = 0; return (0); } - switch (c) { - case ACK: - ++sno; - length -= PKTLEN_128; - ptr_data += PKTLEN_128; - // ("A"); + switch (c) + { + case ACK: + ++sno; + length -= PKTLEN_128; + ptr_data += PKTLEN_128; + // ("A"); break; - case NAK: - // ("N"); + + case NAK: + // ("N"); break; - case CAN: - case EOT: - default: - done = 0; + + case CAN: + case EOT: + default: + done = 0; break; } - if (!length) { - usart_putc(EOT); - usart_getc(); /* Flush the ACK */ + + if (!length) + { + serial_putc(EOT); + serial_getc(); /* Flush the ACK */ break; } // ("!"); @@ -427,14 +412,43 @@ uint32_t usart_putdata_xmd(void const* data, uint32_t length) { // return(0); } +/*---------------------------------------------------------------------------- + * \brief Used by serial_getdata_xmd to retrieve packets. + */ +static uint8_t getPacket(uint8_t *ptr_data, uint8_t sno) +{ + uint8_t seq[2]; + uint16_t crc, xcrc; + + getbytes(seq, 2); + xcrc = getbytes(ptr_data, PKTLEN_128); + if (error_timeout) + return (false); + + /* An "endian independent way to combine the CRC bytes. */ + crc = (uint16_t) serial_getc() << 8; + crc += (uint16_t) serial_getc(); + + if (error_timeout == 1) + return (false); + + if ((crc != xcrc) || (seq[0] != sno) || (seq[1] != (uint8_t) (~sno))) + { + serial_putc(CAN); + return (false); + } + + serial_putc(ACK); + return (true); +} + //*---------------------------------------------------------------------------- -//* \fn Xdown //* \brief Called when a transfer from host to target is being made (considered //* an download). //*---------------------------------------------------------------------------- -//static void Xdown(char *ptr_data, uint16_t length) //Get data from comm. device using xmodem (if necessary) -uint32_t usart_getdata_xmd(void* data, uint32_t length) { +uint32_t serial_getdata_xmd(void* data, uint32_t length) +{ uint32_t timeout; char c; uint8_t * ptr_data = (uint8_t *) data; @@ -443,13 +457,14 @@ uint32_t usart_getdata_xmd(void* data, uint32_t length) { uint32_t data_transfered = 0; //Copied from legacy source code ... might need some tweaking - uint32_t loops_per_second = CPU_FREQUENCY/10; /* system_clock_source_get_hz(BOOT_USART_GCLK_GEN_SOURCE) / 10; */ + uint32_t loops_per_second = CPU_FREQUENCY/60; error_timeout = 0; if (length == 0) mode_of_transfer = 1; - else { + else + { size_of_data = length; mode_of_transfer = 0; } @@ -457,10 +472,11 @@ uint32_t usart_getdata_xmd(void* data, uint32_t length) { /* Startup synchronization... */ /* Continuously send NAK or 'C' until sender responds. */ // ("Xdown"); - while (1) { - usart_putc('C'); + while (1) + { + serial_putc('C'); timeout = loops_per_second; - while (!(usart_is_rx_ready()) && timeout) + while (!(serial_is_rx_ready()) && timeout) timeout--; if (timeout) break; @@ -472,36 +488,41 @@ uint32_t usart_getdata_xmd(void* data, uint32_t length) { b_run = true; // ("Got response"); - while (b_run != false) { - c = (char) usart_getc(); - if (error_timeout) { // Test for timeout in usart_getc + while (b_run != false) + { + c = (char) serial_getc(); + if (error_timeout) + { // Test for timeout in serial_getc error_timeout = 0; return (0); // return (-1); } - switch (c) { - case SOH: /* 128-byte incoming packet */ - // ("O"); - b_run = getPacket(ptr_data, sno); - if (error_timeout) { // Test for timeout in usart_getc - error_timeout = 0; - return (0); -// return (-1); - } - if (b_run == true) { - ++sno; - ptr_data += PKTLEN_128; - data_transfered += PKTLEN_128; - } + switch (c) + { + case SOH: /* 128-byte incoming packet */ + // ("O"); + b_run = getPacket(ptr_data, sno); + if (error_timeout) + { // Test for timeout in serial_getc + error_timeout = 0; + return (0); + // return (-1); + } + if (b_run == true) + { + ++sno; + ptr_data += PKTLEN_128; + data_transfered += PKTLEN_128; + } break; - case EOT: // ("E"); - usart_putc(ACK); - b_run = false; + case EOT: // ("E"); + serial_putc(ACK); + b_run = false; break; - case CAN: // ("C"); - case ESC: /* "X" User-invoked abort */ - default: - b_run = false; + case CAN: // ("C"); + case ESC: /* "X" User-invoked abort */ + default: + b_run = false; break; } // ("!"); diff --git a/bootloaders/feather/sam_ba_serial.h b/bootloaders/feather/sam_ba_serial.h new file mode 100644 index 000000000..cb69f459e --- /dev/null +++ b/bootloaders/feather/sam_ba_serial.h @@ -0,0 +1,143 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SAM_BA_SERIAL_H_ +#define _SAM_BA_SERIAL_H_ + +#include +#include + + +/* USART buffer size (must be a power of two) */ +#define USART_BUFFER_SIZE (128) + +/* Define the default time-out value for USART. */ +#define USART_DEFAULT_TIMEOUT (1000) + +/* Xmodem related defines */ +/* CRC16 polynomial */ +#define CRC16POLY (0x1021) + +#define SHARP_CHARACTER '#' + +/* X/Ymodem protocol: */ +#define SOH (0x01) +//#define STX (0x02) +#define EOT (0x04) +#define ACK (0x06) +#define NAK (0x15) +#define CAN (0x18) +#define ESC (0x1b) + +#define PKTLEN_128 (128) + + +/** + * \brief Open the given USART + */ +void serial_open(void); + +/** + * \brief Stops the USART + */ +void serial_close(void); + +/** + * \brief Puts a byte on usart line + * + * \param value Value to put + * + * \return \c 1 if function was successfully done, otherwise \c 0. + */ +int serial_putc(int value); + +/** + * \brief Waits and gets a value on usart line + * + * \return value read on usart line + */ +int serial_getc(void); + +/** + * \brief Returns true if the SAM-BA Uart received the sharp char + * + * \return Returns true if the SAM-BA Uart received the sharp char + */ +int serial_sharp_received(void); + +/** + * \brief This function checks if a character has been received on the usart line + * + * \return \c 1 if a byte is ready to be read. + */ +bool serial_is_rx_ready(void); + +/** + * \brief Gets a value on usart line + * + * \return value read on usart line + */ +int serial_readc(void); + +/** + * \brief Send buffer on usart line + * + * \param data pointer + * \param number of data to send + * \return number of data sent + */ +uint32_t serial_putdata(void const* data, uint32_t length); //Send given data (polling) + +/** + * \brief Gets data from usart line + * + * \param data pointer + * \param number of data to get + * \return value read on usart line + */ +uint32_t serial_getdata(void* data, uint32_t length); //Get data from comm. device + +/** + * \brief Send buffer on usart line using Xmodem protocol + * + * \param data pointer + * \param number of data to send + * \return number of data sent + */ +uint32_t serial_putdata_xmd(void const* data, uint32_t length); //Send given data (polling) using xmodem (if necessary) + +/** + * \brief Gets data from usart line using Xmodem protocol + * + * \param data pointer + * \param number of data to get + * \return value read on usart line + */ +uint32_t serial_getdata_xmd(void* data, uint32_t length); //Get data from comm. device using xmodem (if necessary) + +/** + * \brief Compute the CRC + * + * \param Char to add to CRC + * \param Previous CRC + * \return The new computed CRC + */ +unsigned short serial_add_crc(char c, unsigned short crc); + +#endif // _SAM_BA_SERIAL_H_ diff --git a/bootloaders/feather/sam_ba_usb.c b/bootloaders/feather/sam_ba_usb.c new file mode 100644 index 000000000..687e065e9 --- /dev/null +++ b/bootloaders/feather/sam_ba_usb.c @@ -0,0 +1,456 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include "sam_ba_usb.h" +#include "board_driver_usb.h" +#include "sam_ba_cdc.h" + +/* This data array will be copied into SRAM as its length is inferior to 64 bytes, + * and so can stay in flash. + */ +static __attribute__((__aligned__(4))) +const char devDescriptor[] = +{ + /* Device descriptor */ + 0x12, // bLength + 0x01, // bDescriptorType + 0x00, // bcdUSB L + 0x02, // bcdUSB H + 0x02, // bDeviceClass: CDC class code + 0x00, // bDeviceSubclass: CDC class sub code + 0x00, // bDeviceProtocol: CDC Device protocol + 0x40, // bMaxPacketSize0 + USB_VID_LOW, // idVendor L + USB_VID_HIGH, // idVendor H + USB_PID_LOW, // idProduct L + USB_PID_HIGH, // idProduct H + 0x00, // bcdDevice L, here matching SAM-BA version + 0x02, // bcdDevice H +#if 0 // TODO: pending validation + STRING_INDEX_MANUFACTURER, // iManufacturer + STRING_INDEX_PRODUCT, // iProduct +#else + 0x00, // iManufacturer + 0x00, // iProduct +#endif // 0 + 0x00, // SerialNumber, should be based on product unique ID + 0x01 // bNumConfigs +}; + +/* This data array will be consumed directly by USB_Write() and must be in SRAM. + * We cannot send data from product internal flash. + */ +static __attribute__((__aligned__(4))) +char cfgDescriptor[] = +{ + /* ============== CONFIGURATION 1 =========== */ + /* Configuration 1 descriptor */ + 0x09, // CbLength + 0x02, // CbDescriptorType + 0x43, // CwTotalLength 2 EP + Control + 0x00, + 0x02, // CbNumInterfaces + 0x01, // CbConfigurationValue + 0x00, // CiConfiguration + 0x80, // CbmAttributes Bus powered without remote wakeup: 0x80, Self powered without remote wakeup: 0xc0 + 0x32, // CMaxPower, report using 100mA, enough for a bootloader + + /* Communication Class Interface Descriptor Requirement */ + 0x09, // bLength + 0x04, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x01, // bNumEndpoints + 0x02, // bInterfaceClass + 0x02, // bInterfaceSubclass + 0x00, // bInterfaceProtocol + 0x00, // iInterface + + /* Header Functional Descriptor */ + 0x05, // bFunction Length + 0x24, // bDescriptor type: CS_INTERFACE + 0x00, // bDescriptor subtype: Header Func Desc + 0x10, // bcdCDC:1.1 + 0x01, + + /* ACM Functional Descriptor */ + 0x04, // bFunctionLength + 0x24, // bDescriptor Type: CS_INTERFACE + 0x02, // bDescriptor Subtype: ACM Func Desc + 0x00, // bmCapabilities + + /* Union Functional Descriptor */ + 0x05, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x06, // bDescriptor Subtype: Union Func Desc + 0x00, // bMasterInterface: Communication Class Interface + 0x01, // bSlaveInterface0: Data Class Interface + + /* Call Management Functional Descriptor */ + 0x05, // bFunctionLength + 0x24, // bDescriptor Type: CS_INTERFACE + 0x01, // bDescriptor Subtype: Call Management Func Desc + 0x00, // bmCapabilities: D1 + D0 + 0x01, // bDataInterface: Data Class Interface 1 + + /* Endpoint 1 descriptor */ + 0x07, // bLength + 0x05, // bDescriptorType + 0x83, // bEndpointAddress, Endpoint 03 - IN + 0x03, // bmAttributes INT + 0x08, // wMaxPacketSize + 0x00, + 0xFF, // bInterval + + /* Data Class Interface Descriptor Requirement */ + 0x09, // bLength + 0x04, // bDescriptorType + 0x01, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + 0x0A, // bInterfaceClass + 0x00, // bInterfaceSubclass + 0x00, // bInterfaceProtocol + 0x00, // iInterface + + /* First alternate setting */ + /* Endpoint 1 descriptor */ + 0x07, // bLength + 0x05, // bDescriptorType + 0x81, // bEndpointAddress, Endpoint 01 - IN + 0x02, // bmAttributes BULK + USB_EP_IN_SIZE, // wMaxPacketSize + 0x00, + 0x00, // bInterval + + /* Endpoint 2 descriptor */ + 0x07, // bLength + 0x05, // bDescriptorType + 0x02, // bEndpointAddress, Endpoint 02 - OUT + 0x02, // bmAttributes BULK + USB_EP_OUT_SIZE, // wMaxPacketSize + 0x00, + 0x00 // bInterval +}; + +#ifndef STRING_MANUFACTURER +# define STRING_MANUFACTURER "Arduino LLC" +#endif + +#ifndef STRING_PRODUCT +# define STRING_PRODUCT "Arduino Zero" +#endif + +USB_CDC sam_ba_cdc; + +/*---------------------------------------------------------------------------- + * \brief This function is a callback invoked when a SETUP packet is received + */ +void sam_ba_usb_CDC_Enumerate(P_USB_CDC pCdc) +{ + Usb *pUsb = pCdc->pUsb; + static volatile uint8_t bmRequestType, bRequest, dir; + static volatile uint16_t wValue, wIndex, wLength, wStatus; + + /* Clear the Received Setup flag */ + pUsb->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP = true; + + /* Read the USB request parameters */ + bmRequestType = udd_ep_out_cache_buffer[0][0]; + bRequest = udd_ep_out_cache_buffer[0][1]; + wValue = (udd_ep_out_cache_buffer[0][2] & 0xFF); + wValue |= (udd_ep_out_cache_buffer[0][3] << 8); + wIndex = (udd_ep_out_cache_buffer[0][4] & 0xFF); + wIndex |= (udd_ep_out_cache_buffer[0][5] << 8); + wLength = (udd_ep_out_cache_buffer[0][6] & 0xFF); + wLength |= (udd_ep_out_cache_buffer[0][7] << 8); + + /* Clear the Bank 0 ready flag on Control OUT */ + pUsb->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY; + + /* Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1 */ + switch ((bRequest << 8) | bmRequestType) + { + case STD_GET_DESCRIPTOR: + if (wValue>>8 == STD_GET_DESCRIPTOR_DEVICE) + { + /* Return Device Descriptor */ + USB_Write(pCdc->pUsb, devDescriptor, SAM_BA_MIN(sizeof(devDescriptor), wLength), USB_EP_CTRL); + } + else + { + if (wValue>>8 == STD_GET_DESCRIPTOR_CONFIGURATION) + { + /* Return Configuration Descriptor */ + USB_Write(pCdc->pUsb, cfgDescriptor, SAM_BA_MIN(sizeof(cfgDescriptor), wLength), USB_EP_CTRL); + } + else + { +#if 0 // TODO: pending validation + if (wValue>>8 == STD_GET_DESCRIPTOR_STRING) + { + switch ( wValue & 0xff ) + { + case STRING_INDEX_LANGUAGES: + uint16_t STRING_LANGUAGE[2] = { (STD_GET_DESCRIPTOR_STRING<<8) | 4, 0x0409 }; + + USB_Write(pCdc->pUsb, (const char*)STRING_LANGUAGE, SAM_BA_MIN(sizeof(STRING_LANGUAGE), wLength), USB_EP_CTRL); + break; + + case STRING_INDEX_MANUFACTURER: + USB_SendString(pCdc->pUsb, STRING_MANUFACTURER, strlen(STRING_MANUFACTURER), wLength ); + break; + + case STRING_INDEX_PRODUCT: + USB_SendString(pCdc->pUsb, STRING_PRODUCT, strlen(STRING_PRODUCT), wLength ); + break; + default: + /* Stall the request */ + USB_SendStall(pUsb, true); + break; + } + } + else +#endif // 0 + { + /* Stall the request */ + USB_SendStall(pUsb, true); + } + } + } + break; + + case STD_SET_ADDRESS: + /* Send ZLP */ + USB_SendZlp(pUsb); + /* Set device address to the newly received address from host */ + USB_SetAddress(pCdc->pUsb, wValue); + break; + + case STD_SET_CONFIGURATION: + /* Store configuration */ + pCdc->currentConfiguration = (uint8_t)wValue; + + /* Send ZLP */ + USB_SendZlp(pUsb); + + /* Configure the 3 needed endpoints */ + USB_Configure(pUsb); + break; + + case STD_GET_CONFIGURATION: + /* Return current configuration value */ + USB_Write(pCdc->pUsb, (char *) &(pCdc->currentConfiguration), sizeof(pCdc->currentConfiguration), USB_EP_CTRL); + break; + + case STD_GET_STATUS_ZERO: + wStatus = 0; + USB_Write(pCdc->pUsb, (char *) &wStatus, sizeof(wStatus), USB_EP_CTRL); + break; + + case STD_GET_STATUS_INTERFACE: + wStatus = 0; + USB_Write(pCdc->pUsb, (char *) &wStatus, sizeof(wStatus), USB_EP_CTRL); + break; + + case STD_GET_STATUS_ENDPOINT: + wStatus = 0; + dir = wIndex & 80; + wIndex &= 0x0F; + if (wIndex <= 3) + { + if (dir) + { + //wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ1) ? 1 : 0; + wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<1)) ? 1 : 0; + } + else + { + //wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.reg & USB_DEVICE_EPSTATUSSET_STALLRQ0) ? 1 : 0; + wStatus = (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<0)) ? 1 : 0; + } + /* Return current status of endpoint */ + USB_Write(pCdc->pUsb, (char *) &wStatus, sizeof(wStatus), USB_EP_CTRL); + } + else + { + /* Stall the request */ + USB_SendStall(pUsb, true); + } + break; + + case STD_SET_FEATURE_ZERO: + /* Stall the request */ + USB_SendStall(pUsb, true); + break; + + case STD_SET_FEATURE_INTERFACE: + /* Send ZLP */ + USB_SendZlp(pUsb); + break; + + case STD_SET_FEATURE_ENDPOINT: + dir = wIndex & 0x80; + wIndex &= 0x0F; + if ((wValue == 0) && wIndex && (wIndex <= 3)) + { + /* Set STALL request for the endpoint */ + if (dir) + { + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.bit.STALLRQ = (1<<1); + } + else + { + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.bit.STALLRQ = (1<<0); + } + + /* Send ZLP */ + USB_SendZlp(pUsb); + } + else + { + /* Stall the request */ + USB_SendStall(pUsb, true); + } + break; + + case STD_SET_INTERFACE: + case STD_CLEAR_FEATURE_ZERO: + /* Stall the request */ + USB_SendStall(pUsb, true); + break; + + case STD_CLEAR_FEATURE_INTERFACE: + /* Send ZLP */ + USB_SendZlp(pUsb); + break; + + case STD_CLEAR_FEATURE_ENDPOINT: + dir = wIndex & 0x80; + wIndex &= 0x0F; + + if ((wValue == 0) && wIndex && (wIndex <= 3)) + { + if (dir) + { + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<1)) + { + // Remove stall request + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.bit.STALLRQ = (1<<1); + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL & (1<<1)) + { + pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL = (1<<1); + // The Stall has occurred, then reset data toggle + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_DTGLIN; + } + } + } + else + { + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUS.bit.STALLRQ & (1<<0)) + { + // Remove stall request + //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0; + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.bit.STALLRQ = (1<<0); + if (pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL & (1<<0)) + { + pUsb->DEVICE.DeviceEndpoint[wIndex].EPINTFLAG.bit.STALL = (1<<0); + // The Stall has occurred, then reset data toggle + pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSSET_DTGLOUT; + } + } + } + /* Send ZLP */ + USB_SendZlp(pUsb); + } + else + { + USB_SendStall(pUsb, true); + } + break; + + // handle CDC class requests + case SET_LINE_CODING: + /* Send ZLP */ + USB_SendZlp(pUsb); + break; + + case GET_LINE_CODING: + /* Send current line coding */ + USB_Write(pCdc->pUsb, (char *) &line_coding, SAM_BA_MIN(sizeof(usb_cdc_line_coding_t), wLength), USB_EP_CTRL); + break; + + case SET_CONTROL_LINE_STATE: + /* Store the current connection */ + pCdc->currentConnection = wValue; + /* Send ZLP */ + USB_SendZlp(pUsb); + break; + + default: + /* Stall the request */ + USB_SendStall(pUsb, true); + break; + } +} + +/*---------------------------------------------------------------------------- + * \brief + */ +P_USB_CDC usb_init(void) +{ + sam_ba_cdc.pUsb = USB; + + /* Initialize USB */ + USB_Init(); + /* Get the default CDC structure settings */ + USB_Open(&sam_ba_cdc, sam_ba_cdc.pUsb); + + return &sam_ba_cdc; +} + +#if 0 // TODO: pending validation +/*---------------------------------------------------------------------------- + * \brief Send a USB descriptor string. + * + * The input string is plain ASCII but is sent out as UTF-16 with the correct 2-byte prefix. + */ +uint32_t USB_SendString(Usb *pUsb, const char* ascii_string, uint8_t length, uint8_t maxLength) +{ + uint8_t string_descriptor[255]; // Max USB-allowed string length + uint16_t* unicode_string=(uint16_t*)(string_descriptor+2); // point on 3 bytes of descriptor + + int resulting_length = 1; + + for ( ; *ascii_string && (length>=0) && (resulting_length<(maxLength>>1)) ; ascii_string++, length--, resulting_length++ ) + { + *unicode_string++ = (uint16_t)(*ascii_string); + } + + string_descriptor[0] = (resulting_length<<1); + string_descriptor[1] = STD_GET_DESCRIPTOR_STRING; + + return USB_Write(pUsb, (const char*)unicode_string, resulting_length, USB_EP_CTRL); +} +#endif // 0 diff --git a/bootloaders/feather/sam_ba_usb.h b/bootloaders/feather/sam_ba_usb.h new file mode 100644 index 000000000..42c0d608f --- /dev/null +++ b/bootloaders/feather/sam_ba_usb.h @@ -0,0 +1,107 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CDC_ENUMERATE_H +#define CDC_ENUMERATE_H + +#include +#include + +#define USB_EP_CTRL (0u) +#define USB_EP_OUT (2u) +#define USB_EP_OUT_SIZE (0x40u) +#define USB_EP_IN (1u) +#define USB_EP_IN_SIZE (0x40u) +#define USB_EP_COMM (3u) +#define MAX_EP (4u) + +/* USB standard request code */ +#define STD_GET_STATUS_ZERO (0x0080u) +#define STD_GET_STATUS_INTERFACE (0x0081u) +#define STD_GET_STATUS_ENDPOINT (0x0082u) + +#define STD_CLEAR_FEATURE_ZERO (0x0100u) +#define STD_CLEAR_FEATURE_INTERFACE (0x0101u) +#define STD_CLEAR_FEATURE_ENDPOINT (0x0102u) + +#define STD_SET_FEATURE_ZERO (0x0300u) +#define STD_SET_FEATURE_INTERFACE (0x0301u) +#define STD_SET_FEATURE_ENDPOINT (0x0302u) + +#define STD_SET_ADDRESS (0x0500u) +#define STD_GET_DESCRIPTOR (0x0680u) +#define STD_SET_DESCRIPTOR (0x0700u) +#define STD_GET_CONFIGURATION (0x0880u) +#define STD_SET_CONFIGURATION (0x0900u) +#define STD_GET_INTERFACE (0x0A81u) +#define STD_SET_INTERFACE (0x0B01u) +#define STD_SYNCH_FRAME (0x0C82u) + +#define STD_GET_DESCRIPTOR_DEVICE (1u) +#define STD_GET_DESCRIPTOR_CONFIGURATION (2u) +#define STD_GET_DESCRIPTOR_STRING (3u) +#define STD_GET_DESCRIPTOR_INTERFACE (4u) +#define STD_GET_DESCRIPTOR_ENDPOINT (5u) +#define STD_GET_DESCRIPTOR_DEVICE_QUALIFIER (6u) +#define STD_GET_DESCRIPTOR_OTHER_SPEED_CONFIGURATION (7u) +#define STD_GET_DESCRIPTOR_INTERFACE_POWER1 (8u) + +#define FEATURE_ENDPOINT_HALT (0u) +#define FEATURE_DEVICE_REMOTE_WAKEUP (1u) +#define FEATURE_TEST_MODE (2u) + +#if 0 // TODO: pending validation +#define STRING_INDEX_LANGUAGES (0x00u) +#define STRING_INDEX_MANUFACTURER (0x01u) +#define STRING_INDEX_PRODUCT (0x02u) +#endif // 0 + +#define SAM_BA_MIN(a, b) (((a) < (b)) ? (a) : (b)) + + +typedef struct _USB_CDC +{ + // Private members + Usb *pUsb; + uint8_t currentConfiguration; + uint8_t currentConnection; + // Public Methods: + uint8_t (*IsConfigured)(struct _USB_CDC *pCdc); +// uint32_t (*Write) (Usb *pUsb, const char *pData, uint32_t length, uint8_t ep_num); +// uint32_t (*Read) (Usb *pUsb, char *pData, uint32_t length); +} USB_CDC, *P_USB_CDC; + +/** + * \brief Initializes the USB module + * + * \return Pointer to the USB CDC structure + */ +P_USB_CDC usb_init(void); + +void sam_ba_usb_CDC_Enumerate(P_USB_CDC pCdc); + +#if 0 // TODO: pending validation +uint32_t USB_SendString(Usb *pUsb, const char* ascii_string, uint8_t length, uint8_t maxLength); +#endif // 0 + +extern USB_CDC sam_ba_cdc; + + + +#endif // CDC_ENUMERATE_H diff --git a/bootloaders/feather/samd21_sam_ba.atsln b/bootloaders/feather/samd21_sam_ba.atsln new file mode 100644 index 000000000..cf1043181 --- /dev/null +++ b/bootloaders/feather/samd21_sam_ba.atsln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Atmel Studio Solution File, Format Version 11.00 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "samd21_sam_ba", "samd21_sam_ba.cproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Release|ARM = Release|ARM + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|ARM.ActiveCfg = Debug|ARM + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|ARM.Build.0 = Debug|ARM + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|ARM.ActiveCfg = Release|ARM + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|ARM.Build.0 = Release|ARM + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/bootloaders/feather/samd21_sam_ba.bin b/bootloaders/feather/samd21_sam_ba.bin deleted file mode 100644 index 74cf2de8f94f2f8f4b202d46ba1764d00fce0d9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6480 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 + + + 2.0 + 7.0 + com.Atmel.ARMGCC.C + dce6c7e3-ee26-4d79-826b-08594b9ad897 + ATSAMD21G18A + none + Executable + C + $(MSBuildProjectName) + .elf + $(MSBuildProjectDirectory)\$(Configuration) + samd21_sam_ba + samd21_sam_ba + samd21_sam_ba + Native + true + false + true + true + 0x20000000 + + true + exception_table + 2 + 0 + + + + + + + + + + + + + + com.atmel.avrdbg.tool.atmelice + J41800001895 + 0x10010000 + SWD + + + + 2000000 + + SWD + + com.atmel.avrdbg.tool.atmelice + J41800001895 + Atmel-ICE + + 2000000 + + + + + SWD + + com.atmel.avrdbg.tool.edbg + ATML2320040200000259 + EDBG + + + + + + True + True + True + True + True + + + NDEBUG + + + Optimize for size (-Os) + True + True + + + libm + + + True + -Tsamd21j18a_flash.ld + + + + + + + True + True + True + True + True + + + DEBUG + + + Optimize (-O1) + True + Maximum (-g3) + True + + + libm + + + True + -Tsamd21j18a_flash.ld + Default (-g) + Default (-Wa,-g) + + + True + + DEBUG=1 all + clean + Makefile + + + + compile + board_definitions.h + + + compile + board_driver_led.c + + + compile + board_driver_led.h + + + compile + board_driver_serial.c + + + compile + board_driver_serial.h + + + compile + board_driver_usb.c + + + compile + board_driver_usb.h + + + compile + board_init.c + + + compile + board_startup.c + + + compile + main.c + + + compile + sam_ba_cdc.c + + + compile + sam_ba_cdc.h + + + compile + sam_ba_monitor.c + + + compile + sam_ba_monitor.h + + + compile + sam_ba_serial.c + + + compile + sam_ba_serial.h + + + compile + sam_ba_usb.c + + + compile + sam_ba_usb.h + + + + + compile + Makefile + + + compile + README.md + + + compile + bootloader_samd21x18.ld + + + + \ No newline at end of file diff --git a/bootloaders/feather/samd21_sam_ba.elf b/bootloaders/feather/samd21_sam_ba.elf new file mode 100644 index 0000000000000000000000000000000000000000..edee94811dd8e982f615dc00e61274864060a76b GIT binary patch literal 647224 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