From 891779c87e6e94674bc465b8e9ad08d989f9e450 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Mon, 5 Oct 2015 19:17:53 +0200 Subject: [PATCH 01/22] [bl] first pass rework, work in progress --- bootloaders/zero/Makefile | 168 ++- bootloaders/zero/{readme.txt => README.md} | 0 bootloaders/zero/board_definitions.h | 71 + bootloaders/zero/board_driver_led.c | 3 + bootloaders/zero/board_driver_led.h | 22 + .../uart_driver.c => board_driver_serial.c} | 60 +- .../uart_driver.h => board_driver_serial.h} | 58 +- bootloaders/zero/board_driver_usb.c | 314 +++++ bootloaders/zero/board_driver_usb.h | 43 + bootloaders/zero/board_init.c | 209 +++ bootloaders/zero/board_init.c.old | 89 ++ bootloaders/zero/board_startup.c | 146 +++ bootloaders/zero/bootloader_samd21x18.ld | 220 ++++ bootloaders/zero/drivers/cdc_enumerate.c | 765 ----------- bootloaders/zero/drivers/cdc_enumerate.h | 126 -- bootloaders/zero/main.c | 343 ++--- bootloaders/zero/main.h | 62 - bootloaders/zero/sam_ba_cdc.c | 97 ++ bootloaders/zero/sam_ba_cdc.h | 91 ++ bootloaders/zero/sam_ba_led.c | 0 bootloaders/zero/sam_ba_led.h | 0 bootloaders/zero/sam_ba_monitor.c | 780 +++++------ bootloaders/zero/sam_ba_monitor.h | 52 +- .../zero/{usart_sam_ba.c => sam_ba_serial.c} | 402 +++--- bootloaders/zero/sam_ba_serial.h | 142 ++ bootloaders/zero/sam_ba_usb.c | 388 ++++++ bootloaders/zero/sam_ba_usb.h | 83 ++ bootloaders/zero/samd21_sam_ba.bin | Bin 6328 -> 5996 bytes bootloaders/zero/samd21j18a_flash.ld | 157 --- bootloaders/zero/startup_samd21.c | 201 --- bootloaders/zero/usart_sam_ba.h | 155 --- bootloaders/zero/utils/compiler.h | 1157 ----------------- bootloaders/zero/utils/interrupt.h | 117 -- .../zero/utils/interrupt/interrupt_sam_nvic.c | 69 - .../zero/utils/interrupt/interrupt_sam_nvic.h | 172 --- .../zero/utils/preprocessor/mrecursion.h | 581 --------- bootloaders/zero/utils/preprocessor/mrepeat.h | 321 ----- .../zero/utils/preprocessor/preprocessor.h | 38 - bootloaders/zero/utils/preprocessor/stringz.h | 67 - bootloaders/zero/utils/preprocessor/tpaste.h | 85 -- bootloaders/zero/utils/status_codes.h | 138 -- 41 files changed, 2869 insertions(+), 5123 deletions(-) rename bootloaders/zero/{readme.txt => README.md} (100%) 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 rename bootloaders/zero/{drivers/uart_driver.c => board_driver_serial.c} (59%) rename bootloaders/zero/{drivers/uart_driver.h => board_driver_serial.h} (51%) 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_init.c.old create mode 100644 bootloaders/zero/board_startup.c create mode 100644 bootloaders/zero/bootloader_samd21x18.ld delete mode 100644 bootloaders/zero/drivers/cdc_enumerate.c delete mode 100644 bootloaders/zero/drivers/cdc_enumerate.h delete mode 100644 bootloaders/zero/main.h 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_led.c create mode 100644 bootloaders/zero/sam_ba_led.h rename bootloaders/zero/{usart_sam_ba.c => sam_ba_serial.c} (61%) 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 delete mode 100644 bootloaders/zero/samd21j18a_flash.ld delete mode 100644 bootloaders/zero/startup_samd21.c delete mode 100644 bootloaders/zero/usart_sam_ba.h delete mode 100644 bootloaders/zero/utils/compiler.h delete mode 100644 bootloaders/zero/utils/interrupt.h delete mode 100644 bootloaders/zero/utils/interrupt/interrupt_sam_nvic.c delete mode 100644 bootloaders/zero/utils/interrupt/interrupt_sam_nvic.h delete mode 100644 bootloaders/zero/utils/preprocessor/mrecursion.h delete mode 100644 bootloaders/zero/utils/preprocessor/mrepeat.h delete mode 100644 bootloaders/zero/utils/preprocessor/preprocessor.h delete mode 100644 bootloaders/zero/utils/preprocessor/stringz.h delete mode 100644 bootloaders/zero/utils/preprocessor/tpaste.h delete mode 100644 bootloaders/zero/utils/status_codes.h diff --git a/bootloaders/zero/Makefile b/bootloaders/zero/Makefile index d8fb2f349..efc5068b1 100644 --- a/bootloaders/zero/Makefile +++ b/bootloaders/zero/Makefile @@ -1,29 +1,159 @@ -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 -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 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)) + 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 +# MODULE_PATH?=$(LOCALAPPDATA)/Arduino15/packages/arduino + 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)/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 + +# ----------------------------------------------------------------------------- +# Tools +CC=$(ARM_GCC_PATH)gcc +OBJCOPY=$(ARM_GCC_PATH)objcopy +NM=$(ARM_GCC_PATH)nm +SIZE=$(ARM_GCC_PATH)size + +# ----------------------------------------------------------------------------- +# Compiler options +#-w +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 +else +CFLAGS+=-Os +endif +#CFLAGS_EXTRA?=-D__SAMD21G18A__ -DUSB_PID_LOW=0x4D -DUSB_PID_HIGH=0x00 +CFLAGS_EXTRA?=-D__SAMD21J18A__ -DUSB_PID_LOW=0x01 -DUSB_PID_HIGH=0xE0 +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 \ +cdc_enumerate.c \ +main.c \ +sam_ba_cdc.c \ +sam_ba_led.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 +ELF=$(NAME).elf EXECUTABLE=$(NAME).bin -SLASH=/ -BSLASH=$(EMPTY)\$(EMPTY) +ifneq "test$(AVRSTUDIO_EXE_PATH)" "test" +AS=copy_for_atmel_studio +else +AS= +endif + + +all: print_info $(SOURCES) $(EXECUTABLE) $(AS) -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 $@ +$(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) + +$(EXECUTABLE): $(ELF) + @echo ---------------------------------------------------------- + @echo Creating flash binary + "$(OBJCOPY)" -O binary $(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: $(EXECUTABLE) + @echo ---------------------------------------------------------- + @echo Atmel Studio detected, copying ELF to project root for debug + cp $(BUILD_PATH)/$(ELF) . + clean: - del $(EXECUTABLE) $(subst /,\,$(OBJECTS)) $(subst /,\,$(BUILD_PATH)/$(NAME).*) + @echo ---------------------------------------------------------- + @echo Cleaning project + -$(RM) $(EXECUTABLE) + -$(RM) $(BUILD_PATH)/*.* + -rmdir $(BUILD_PATH) + +.phony: clean print_info $(BUILD_PATH) diff --git a/bootloaders/zero/readme.txt b/bootloaders/zero/README.md similarity index 100% rename from bootloaders/zero/readme.txt rename to bootloaders/zero/README.md diff --git a/bootloaders/zero/board_definitions.h b/bootloaders/zero/board_definitions.h new file mode 100644 index 000000000..e986dde42 --- /dev/null +++ b/bootloaders/zero/board_definitions.h @@ -0,0 +1,71 @@ +/* + 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 +*/ + +#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..9adf7f634 --- /dev/null +++ b/bootloaders/zero/board_driver_led.c @@ -0,0 +1,3 @@ +#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..f4954df35 --- /dev/null +++ b/bootloaders/zero/board_driver_led.h @@ -0,0 +1,22 @@ +#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/zero/drivers/uart_driver.h b/bootloaders/zero/board_driver_serial.h similarity index 51% rename from bootloaders/zero/drivers/uart_driver.h rename to bootloaders/zero/board_driver_serial.h index 84bfe1b1a..44e070f61 100644 --- a/bootloaders/zero/drivers/uart_driver.h +++ b/bootloaders/zero/board_driver_serial.h @@ -1,37 +1,27 @@ -/* ---------------------------------------------------------------------------- - * 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. + + 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 +36,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 +86,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/zero/board_driver_usb.c b/bootloaders/zero/board_driver_usb.c new file mode 100644 index 000000000..8a962b3fb --- /dev/null +++ b/bootloaders/zero/board_driver_usb.c @@ -0,0 +1,314 @@ + +#include +#include "board_driver_usb.h" +#include "sam_ba_cdc.h" +#include "cdc_enumerate.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) )); + + 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) )); +} + diff --git a/bootloaders/zero/board_driver_usb.h b/bootloaders/zero/board_driver_usb.h new file mode 100644 index 000000000..0267b240e --- /dev/null +++ b/bootloaders/zero/board_driver_usb.h @@ -0,0 +1,43 @@ +/* + 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 +*/ + +#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); + + +#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..d6063459a --- /dev/null +++ b/bootloaders/zero/board_init.c @@ -0,0 +1,209 @@ +/* + 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 +*/ + +#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_init.c.old b/bootloaders/zero/board_init.c.old new file mode 100644 index 000000000..1bcca3d18 --- /dev/null +++ b/bootloaders/zero/board_init.c.old @@ -0,0 +1,89 @@ +/* + 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 +*/ + +void system_init(void) +{ + /* 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 +} diff --git a/bootloaders/zero/board_startup.c b/bootloaders/zero/board_startup.c new file mode 100644 index 000000000..747a3576a --- /dev/null +++ b/bootloaders/zero/board_startup.c @@ -0,0 +1,146 @@ +/* + 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 +*/ + +#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..b08198203 --- /dev/null +++ b/bootloaders/zero/bootloader_samd21x18.ld @@ -0,0 +1,220 @@ +/* + 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 +*/ + +/* 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 + * __app_start_address + */ +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(__app_start_address = 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/drivers/cdc_enumerate.c b/bootloaders/zero/drivers/cdc_enumerate.c deleted file mode 100644 index bd3873eb2..000000000 --- a/bootloaders/zero/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 - 0x41, // idVendorL - 0x23, // - 0x4D, // idProductL - 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/zero/drivers/cdc_enumerate.h b/bootloaders/zero/drivers/cdc_enumerate.h deleted file mode 100644 index 41002626f..000000000 --- a/bootloaders/zero/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/zero/main.c b/bootloaders/zero/main.c index 4ad7abd54..6dede8ccb 100644 --- a/bootloaders/zero/main.c +++ b/bootloaders/zero/main.c @@ -1,31 +1,20 @@ -/* ---------------------------------------------------------------------------- - * 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. + + 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 +*/ /** * -------------------- @@ -74,16 +63,18 @@ #include #include -#include "compiler.h" #include "sam_ba_monitor.h" -#include "usart_sam_ba.h" -#include "main.h" +#include "sam_ba_serial.h" +#include "board_definitions.h" +#include "board_driver_led.h" #include "cdc_enumerate.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 __app_start_address; +extern void board_init(void); -static void check_start_application(void); +//static void check_start_application(void); static volatile bool main_b_cdc_enable = false; @@ -93,156 +84,85 @@ 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; - } + #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; + uint32_t app_start_address; - /* Load the Reset Handler address of the application */ - app_start_address = *(uint32_t *)(APP_START_ADDRESS + 4); + /* 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; - } + /** + * Test reset vector of application @__app_start_address+4 + * Stay in SAM-BA if *(__app_start_address+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; - } + 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); + LED_on(); - /* 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)); -} + /* Rebase the Stack Pointer */ + __set_MSP(*(uint32_t *) &__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); + /* Rebase the vector table base address */ + SCB->VTOR = ((uint32_t) &__app_start_address & 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"(app_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,61 +171,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; - /* Wait for a complete enum on usb or a '#' char on serial line */ - while (1) { + + 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(); - } - } + 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 - } + } } diff --git a/bootloaders/zero/main.h b/bootloaders/zero/main.h deleted file mode 100644 index b8c58ec79..000000000 --- a/bootloaders/zero/main.h +++ /dev/null @@ -1,62 +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 - -/* - * 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/zero/sam_ba_cdc.c b/bootloaders/zero/sam_ba_cdc.c new file mode 100644 index 000000000..494ac3b6d --- /dev/null +++ b/bootloaders/zero/sam_ba_cdc.c @@ -0,0 +1,97 @@ +/* + 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 +*/ + +#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..31ec49bad --- /dev/null +++ b/bootloaders/zero/sam_ba_cdc.h @@ -0,0 +1,91 @@ +/* + 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 +*/ + +#ifndef _SAM_BA_USB_CDC_H_ +#define _SAM_BA_USB_CDC_H_ + +#include +#include "cdc_enumerate.h" +//#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_led.c b/bootloaders/zero/sam_ba_led.c new file mode 100644 index 000000000..e69de29bb diff --git a/bootloaders/zero/sam_ba_led.h b/bootloaders/zero/sam_ba_led.h new file mode 100644 index 000000000..e69de29bb diff --git a/bootloaders/zero/sam_ba_monitor.c b/bootloaders/zero/sam_ba_monitor.c index 29c9d8566..1cc3fabac 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. + + 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 "sam_ba_serial.h" +#include "board_driver_serial.h" +#include "board_driver_usb.h" +//#include "sam_ba_usb.h" #include "cdc_enumerate.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,286 +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) { - 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..977b3d5e6 100644 --- a/bootloaders/zero/sam_ba_monitor.h +++ b/bootloaders/zero/sam_ba_monitor.h @@ -1,36 +1,25 @@ -/* ---------------------------------------------------------------------------- - * 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. + + 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 +30,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/usart_sam_ba.c b/bootloaders/zero/sam_ba_serial.c similarity index 61% rename from bootloaders/zero/usart_sam_ba.c rename to bootloaders/zero/sam_ba_serial.c index 645e725e9..50496fd53 100644 --- a/bootloaders/zero/usart_sam_ba.c +++ b/bootloaders/zero/sam_ba_serial.c @@ -1,38 +1,25 @@ -/* ---------------------------------------------------------------------------- - * 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. -//#include -#include "usart_sam_ba.h" -#include "main.h" -#include "uart_driver.h" -#include "compiler.h" -#include "sam.h" + 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 +48,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 +73,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 +83,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 +94,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); + 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_MUX_SETTINGS); + uart_basic_init(BOOT_USART_MODULE, 50436, BOOT_USART_PAD_SETTINGS); //Initialize flag b_sharp_received = false; @@ -130,10 +121,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 +136,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 +177,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 +236,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 +271,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); - - 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(); + serial_putc((uint8_t) (chksm >> 8)); + serial_putc((uint8_t) chksm); - 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); + return (serial_getc()); /* Wait for ack */ } //*---------------------------------------------------------------------------- -//* \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 +338,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 +411,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 +456,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 +471,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 +487,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/zero/sam_ba_serial.h b/bootloaders/zero/sam_ba_serial.h new file mode 100644 index 000000000..5bc5a99d6 --- /dev/null +++ b/bootloaders/zero/sam_ba_serial.h @@ -0,0 +1,142 @@ +/* + 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 +*/ + +#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..151e436c2 --- /dev/null +++ b/bootloaders/zero/sam_ba_usb.c @@ -0,0 +1,388 @@ +/* + 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 +*/ + +#include +#include +#include "cdc_enumerate.h" +#include "board_driver_usb.h" +#include "sam_ba_cdc.h" + +__attribute__((__aligned__(4))) +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 + 0x41, // idVendorL + 0x23, // + USB_PID_LOW, // idProductL + USB_PID_HIGH, // + 0x10, // bcdDeviceL + 0x01, // + 0x00, // iManufacturer // 0x01 + 0x00, // iProduct + 0x00, // SerialNumber + 0x01 // bNumConfigs +}; + +__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 + 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 +}; + + +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 == 0x100) + /* Return Device Descriptor */ + USB_Write(pCdc->pUsb, devDescriptor, SAM_BA_MIN(sizeof(devDescriptor), wLength), USB_EP_CTRL); + else if (wValue == 0x200) + /* Return Configuration Descriptor */ + USB_Write(pCdc->pUsb, cfgDescriptor, SAM_BA_MIN(sizeof(cfgDescriptor), wLength), USB_EP_CTRL); + else + /* 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 */ + pUsb->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | wValue; + break; + + case STD_SET_CONFIGURATION: + /* Store configuration */ + pCdc->currentConfiguration = (uint8_t)wValue; + /* Send ZLP */ + 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 */ + 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_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; +} diff --git a/bootloaders/zero/sam_ba_usb.h b/bootloaders/zero/sam_ba_usb.h new file mode 100644 index 000000000..f37034c79 --- /dev/null +++ b/bootloaders/zero/sam_ba_usb.h @@ -0,0 +1,83 @@ +/* + 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 +*/ + +#ifndef CDC_ENUMERATE_H +#define CDC_ENUMERATE_H + +#include +#include + +#define USB_EP_CTRL (0) +#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) + +/* 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) + +#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); + +extern USB_CDC sam_ba_cdc; + + + +#endif // CDC_ENUMERATE_H diff --git a/bootloaders/zero/samd21_sam_ba.bin b/bootloaders/zero/samd21_sam_ba.bin index 08f40f425437f8fc80c2462668f3d15bdf5453d5..6d645a2c2c63a438fa06b8fe77758a6dce60fd7e 100644 GIT binary patch delta 4429 zcmZ8l4RjONm40tVe@I4_ECcdr@EK`rS4jNGHqIKm1fc<2*4X@-)EG7ygVQ{RbSrz? zM5akJ{Pa}(ZH<*|joEG?Bxl>rrU%rTlamdpcY&OQ-So_munRHij@o2>_9UCSrL7!r zJbOo&E(f3U>Am|i_q})TyZ624*K0pp?wm;@?%QUBdH|1`kGp*f5JG)G-23|m^!v@n ze_CnpLWncCu0_ZHBjj`~LTD#&I*Z)w-txaqe+#L0eAu&6v{W%EN??+8VrifvbzG=OR;2v! zyP~Zm#R)c`>`^Akq$Ix`w8COI(JgnUw&YOg&cqTC`+!;DkJIyL zS=?ZE?P3m<_zw%rKIRZEw#Y9B@YKIfH(o#{6zy7v)_xVR9e_$u)Di_BZ$fLUBpI!l zHrA%=usW_VR?hN?$1wiEV)p$C3!AN)zdVhn_D$mxp17?c=3Ug|VYl?1HVr!tl?>B% zp}S{$UulBk?9uL?J@}UQ#vmPVN3n2ya7dt7Sb6{UK{>D`2Achbd}46adK=t2d%+m) zo*$>jDmR$e`qTmzh09b{WD`tp_fx};VY<7wEBi`Gvk6aCO=mwY;ey`=_Zy%7JG4d! z^vM3f2tO)#ST2B;Ak_syIMAPL&3@)wnKl$7V-F=N`OU<}oe(I#Lf9TOnf3oAjnGSxwiL#-pid4h0Jnm>ZG0iv2qi!SjP2||HN|V+QFl~j-|rEgCCFub2L?L z&Mn;tBCBu|Pa+ zKtXJ=8Kc+D`g10G8kklZIp3O{oDVPqC;$dH6Q%LSvHdZV>P$GrY|N?JwfXHY#0m=H zRc|JC>&7QtruzBP^dy=pd|}eEvD;UXpSpN^a&{7|az>tx(0AK%$kM4X6Z!60KdaZ; z_u}I}-{A7&llHX04CFfMQn|KJav+uKuqSh=qb(u%_o*eBGRiK5mUI-mK<8vF))uvaU&d8+15 zC>PtKD8)9R9BTtp%H#Qy+7WRSbav(&ZVvH241J|LAI?Op>3)vY3vbMx;_1K+^y|+3 z;(eo6v=*n=QDBd z?z3D`_Dw3<{X~x6f%2Wp@&m_7? zZ^~@qndl=TlU$uC4TPdia#My5p&K7*z7z^ul;(`Beh2>8duH&Y#jO25HDQ@3y=!S) ztH`7S$A$HYchfm{(wiyu<7kDvBm>#0ya7TZOV2|~FF`kQT3O0hH2E7Z3YnDd!3b0@ z&QEK1doC!3-Tf!ERYjAL#Jgazv1oDCoWfkm@-?gTUG^e40MieyE{^kr7Fjo87euRW$X=9Tc2Y zFi2#O+yn_!!0c(t1NRH??*AffKP<}%%fbOXgn!~C9@zYAW-#Z3B^yiffb6Lj>q;;2 z!!fEC_RVmqg>y33n6=$Vmd$r)7I6n+W+g!4yk4*D#Jo4^x^UMe=0pigvlXn1U_Joa zF2iN%qA)pTYqzi*J0I99?jU{yOmL)@4FTOTL$h8sS=5^zD`_`_o)h>!(EAFzk{yZJ z6|~f&hB#Y=xnlu!oR8s>219?1A&yBwd~!Z;^qR8vFiP%TL}*IM~`NwHG&E*?dvDB3-=F zekFc}?5*BG?chS1cT zck0O!((MgNFDDj~-+A5Aj}x9`nBeBHbV_6hZepaD#nTC2%1w^MELTSo=@;W=@bSCM zaNiJI(Vot430u{n#IWdsfqszK(dQ<6@*Bfu^@#XF!bi#olkCmMf&QL2beEQQ=D!B? z0rBWvTI$SyGfb;#xSV;3RU=`W`mFff;?jH>8q$i=h5R#Ni~5Y1j{DNY%jgn>5CiOFrmT2PsB%BpV$y45jH(RFhnd&<^#JI*aq`1 zuXAIM*tww@Vq7mZv9+v+bg?eUm!h*MOe+q8>mAY`Cc~tbOpr&4Uv7mV3~TgAMA{l} zl-4CYWIOAYm{d$eAzFa|)G@Hs5UC(=wSuuG(&XVd<^N}Gb)qZ0K#gpu?RbcIAnNB( zHfFopWz%|MaZcu*yA1cR9o|1oE*00n3Ma^EZF{(0Eh9DJSKCmCQhmfB)o3;_yqn0? zuL{Gq-4Y5dRvJWJ=AZi&e2sW-$1;Lme9iW1jCw!PQ7v2G{*u0}{1CNl$MqXF|8}za zxz9oIhp4S0T5*;6uSvHUEDp9u>kjWxOT4&U^k_{U!8(XR{uz!7|5>!T7t2H+pS@lk? zLYx;gU9Ti{*ez5@3~<-3GB2U8d&yrkVQc}q2WZpv#pG*EOR!zAX-h*iTqP^XLJ4cO zHha<-!C@pK>;t>ert5zHiQ%4Wu!{c#815>11Xef!wBbU-U549SV=Uan;k{I4yqK5= zUQCM~crkIs7gL#N@-t7uV`!IKbl>-Ox)dmlm$nVl>Dj`sb!P(VSkeil;z77BB;ak- z01%Bgk_jSQf}-V72#XEHOqbzchlzRM%6kmjAwW6w-2mIzzvQU+Y$2~>&IYC0(5FQ2 z^HJ+~sqq*zXxo^c{n5O6rrE+(J^N4dB+9uU>$G>kY?aa3U)h(spV#YC<2e+z zDyX_4sTZEk`W%Zr+jKOd7q;l=gk1fOFrL#3?OD;Wm|v~0VlhYtb-dcjqGfPI+6`%~ zJ`KOib-nO#_K2f7?Sx*X4zJW|Hi!XF!X&gRei$wPT!D-^p|;feC8Fp!$ajmAuh7pC$Lv+(TJz;NNES?Xi}ZVQxxYHE@W4MTOt zqkCAn?xP$YK0j$LMtc#iiLlnW72kC>To)QjvX3pO4o#1Zw@kljd-LyGlCAgm%diVm zkmhT_6D|y!0B83v2z{uJq=bj?*10XHE?y2+6GkH*i>KN z6j_D3?DNrfKsVyy_hD4GJOT#MHaq;&18@v*4)ESw`$zlF>Tj-OOQmT$LNr-}Xdip1E+*O$>IM#>QtrR>*JJNH!t$OmR~U`%8GEuXzSVV@?UQ=rlKUby zK?@cF91IH~)8>a)rVWXOoQCB-pVT)y*NOsY8#1DRx}>V800pW933&jj79kZQB>f|J zXTZpk^zvXmZ%XLvujOKP${NLPYrw-JH>x$slvu+Z4Px0Llq*i5io?yQZb^0u4DS^0 zqY6?IGoLryFEPh(g*bfG7_a0d*9e{zENyCbk6OWFw=?qk)vr9a=T(&PUB{WfT+~t1 zB27)SmGQ`fQ$+5JqPn~k>_UdQcM)aIeYUhv5k=nL$S9Mzjyww~45D(7{4Gf4TBUo? zwk914EX5GL@!(etp}HZbZU1QpBL-X*15cmzfRpcq-{XG58wEs{3HF$9q4QtD z^yZ4bG*gFCv*|ZGyx_Pl#fWc&=0%NbqHT_^h~DSjEWZZh zjN)jp^71(z*H?)3f`dx(*zXX2$RBc6h*Lpy*-5?1pX;!Tbpp;DS^WD>uXv}}Bu+VA z?yMKyv^NW}A8@wF>F|qP`QnS6W@@X5TN;EGYPyrq7rE2CRji0U6U@8l7GDTma3XPh zV6<(nl}_*Q>gAIhBU;4oa61RAVtKmDna!M%2?4uo3Sm-Cm818E@o%rPFJYbJ3I;@v&Sq zV-sx%M6W6Ld)tADVebY*6K#yBh1Py(?T5YdQ1c)m+(O{)%gJx?dOQ0%#1LY9f>)@g zYAKue6>62RCW`LRrpzL4Fbkh9Fk-Dp&IBXwf=P*`FNf|Bd;-VWVq!04708-(sSxB3 zu6Kf$Uktc6x5@$KUarSmCfmgAP&>ABW#Sn$9L&Gi$@LoL{?4#fvOe)|hNbs+I>=Za z#&jvY-g>!2Y~n*o zakYqQK5@(j^(jx(Pod1IYj~rc`W@(zxYj}3e3Y8)UxtXnI4#7XD8_#S60V4(osbWE zmk9nDoOGh@0`-R#l0tU_Xh0R95kOM*mypFCXvYEH1RMcS0Ft64RY``=fzE#e-UJks zBXk~U3a}1zngFC6#x&nk)yu$)z<_(8tpofV`f0$2fCYe+@@;x&W)+|B(Ot5O8f;}9 zf>W_l+cxFZYA;oacQyO59{T;z*Iim8KG3`gDzi~pSErRtoL#gCSji8YBE(7K%}q9} z(3qh4mEmj#ip4EYh*!i*;;k=fB5876l1ucscI6@^b+{?XaJb4waSe`WS&NJ9ecT=`j=AEjJz|e)sy#sYdP}sT zgJvyI|2>p7-~dX)#paBl%u6@Q_=A-5kt2apmfBghnAOt2Brn19}u-hjtmjn0#YK z6GEB4yOC(N*62{?_>II~tDtd~C;r*m7b7a;pk59%lYHu|_T@YZkI|IIrDoq&J(L9W z4b|46r%3&=%W76q4H`B3g!=l7H@emS`V96Krp^V8G84s9iJ(rNXZJ+sXQqO>l$}_5qO&dviJ3xG#md|a_T;5>o>Ce7?Z{3nTa+fs50%5J zlHlRgx`i_A%-$}OQqa*bOU|r zQZQ~F*P7S^{euG*&bZMOIM9#(=23jzetAd>ZzK(k*-JyCtcEhN9}M;mN$wp%c$f{Y z=*$mI8LqugQ_HhtS_+bbOxu)f;%V0h1I09q>Aw?hGe;CkOr()_L=QGYgNo{11uPZu zw^v8Y*lOt00g^OA6%9$Vp5I#46F%|MgsoKxXtnn%oWO1&}O3+tD`i za@@M8s_Jv9N?bvVc90#^^H>-b@_3E=E%?>;o1-??9Er5e6}DCvBUDz1&`1G736HKZ zMn+|mIx&x$e#S^^12m=jkheAkJ(roC9=5tAX8J%d5^x^^%V+pA?YqS}S506fuZZ0( z>>g+gKn3YP9d-zS{$1irVOKz^dO-tRp;sI+k7#=Z!~_SugXuK>hQ)1#=k*n69q%-; zngb_dUG>ou;pWJJ=tP$(@}ubS&Lge$(zR%PJYQpC>!s$QiLgmB#fOHT?;@OL>DjIy z4IS-jmNvzYaCl4}!c!~!fNM|dwn1xjgv-~Iz`h;fj<$|){r4hyDotIH*2d6lF!lc` z`Bx6sB6&hN1iw>COsYkxXVYWKL1rhK1O;mveQ+o}#~jP`K2W4|oJRN{Nd7`8xN?%2 z2mZcPDo6R$*LWC{dMrJue3i81KTU7EGRjn7!hJB^5T_~cpqgz|PcmBfPV}GMU*>mn zJ^SWd7Kk5|%e}2JTJ;5LYPx$vzM6o~zIT)kpqlQUM+0ju0nComy$=SE70@2wQTpV<1DRl60&k&fX?&3*$7Lfb5m!oPnT?ou8RLpikGX_E6aUTO|M5zP8r#PEmq zzM;b`?J|Jr+c_5U0XBF_86NVv6D;kvvBQJkSLRyDK_`iF9E!}Xj2}aA?~a3@6w2q< zfkpuszQQyB7kszug3|C^7qs07Q7fOFbUEnS0oL5oxBS7<2V}DFhf-wO59VS~bu$(p z+9!uJOkCgnzBTTvG5W)}KV~-$on`47A8Qd3;_w10M@DH)zTQ9|bP~wak(V^-Yi)lGu$$ z@o7!S2DZ*GVY+CR@NLO`u~tK)3yzj1q-GB+(b4jpz>+kylWEW0&{BvV4(6rYVu(>2 zQoAr?4_I#MXsH6qO*trS2*Xk*m&lZJt;BF7X>8Y1G*t*TzI6jJ6JUXctE&$BTbHzy zor>gaEGG9BwC90h5eN=~;##Vanh2UwXq_Qd3&xv(zjmq0x!(TiLIVt2{Coma_^;qW z7`YI6>yg|qVkXg-dgAa*zzuruqKs&y*eU(l$gIykcH;Ri2gE9pEaHngP}N7yGnPu~ zWzd~QS9>PfaO2_v${fCCTUwonmeLOm 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/zero/startup_samd21.c b/bootloaders/zero/startup_samd21.c deleted file mode 100644 index 0f45ae3f9..000000000 --- a/bootloaders/zero/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/zero/usart_sam_ba.h b/bootloaders/zero/usart_sam_ba.h deleted file mode 100644 index d498dc791..000000000 --- a/bootloaders/zero/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/zero/utils/compiler.h b/bootloaders/zero/utils/compiler.h deleted file mode 100644 index e31d7dba4..000000000 --- a/bootloaders/zero/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/zero/utils/interrupt.h b/bootloaders/zero/utils/interrupt.h deleted file mode 100644 index fa4878ee8..000000000 --- a/bootloaders/zero/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/zero/utils/interrupt/interrupt_sam_nvic.c b/bootloaders/zero/utils/interrupt/interrupt_sam_nvic.c deleted file mode 100644 index d8134852e..000000000 --- a/bootloaders/zero/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/zero/utils/interrupt/interrupt_sam_nvic.h b/bootloaders/zero/utils/interrupt/interrupt_sam_nvic.h deleted file mode 100644 index 9b5645b63..000000000 --- a/bootloaders/zero/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/zero/utils/preprocessor/mrecursion.h b/bootloaders/zero/utils/preprocessor/mrecursion.h deleted file mode 100644 index 444792727..000000000 --- a/bootloaders/zero/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/zero/utils/preprocessor/mrepeat.h b/bootloaders/zero/utils/preprocessor/mrepeat.h deleted file mode 100644 index fb820d5bd..000000000 --- a/bootloaders/zero/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/zero/utils/preprocessor/preprocessor.h b/bootloaders/zero/utils/preprocessor/preprocessor.h deleted file mode 100644 index 7f67d8adf..000000000 --- a/bootloaders/zero/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/zero/utils/preprocessor/stringz.h b/bootloaders/zero/utils/preprocessor/stringz.h deleted file mode 100644 index 70937c434..000000000 --- a/bootloaders/zero/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/zero/utils/preprocessor/tpaste.h b/bootloaders/zero/utils/preprocessor/tpaste.h deleted file mode 100644 index 910818347..000000000 --- a/bootloaders/zero/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/zero/utils/status_codes.h b/bootloaders/zero/utils/status_codes.h deleted file mode 100644 index 29bbf4166..000000000 --- a/bootloaders/zero/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 1ca18af7d4321d10b019661b744d7d0b76d0a027 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Tue, 6 Oct 2015 11:32:27 +0200 Subject: [PATCH 02/22] [bl] remove wrong file from build --- bootloaders/zero/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/bootloaders/zero/Makefile b/bootloaders/zero/Makefile index efc5068b1..1306e70c0 100644 --- a/bootloaders/zero/Makefile +++ b/bootloaders/zero/Makefile @@ -86,7 +86,6 @@ board_driver_serial.c \ board_driver_usb.c \ board_init.c \ board_startup.c \ -cdc_enumerate.c \ main.c \ sam_ba_cdc.c \ sam_ba_led.c \ From cdca72a4b2ce094e05f22f425e67d6c6356b2e9a Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Tue, 6 Oct 2015 11:56:58 +0200 Subject: [PATCH 03/22] [bl] add missing file to build --- bootloaders/zero/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/bootloaders/zero/Makefile b/bootloaders/zero/Makefile index 1306e70c0..214bdc3b0 100644 --- a/bootloaders/zero/Makefile +++ b/bootloaders/zero/Makefile @@ -87,6 +87,7 @@ board_driver_usb.c \ board_init.c \ board_startup.c \ main.c \ +sam_ba_usb.c \ sam_ba_cdc.c \ sam_ba_led.c \ sam_ba_monitor.c \ From 0fd8b8b349ab0d76d422b5bd049a1adb42d0651e Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Tue, 6 Oct 2015 11:58:20 +0200 Subject: [PATCH 04/22] [bl] fix wrong includes --- bootloaders/zero/board_driver_usb.c | 2 +- bootloaders/zero/main.c | 3 +-- bootloaders/zero/sam_ba_cdc.h | 3 +-- bootloaders/zero/sam_ba_monitor.c | 3 +-- bootloaders/zero/sam_ba_usb.c | 2 +- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/bootloaders/zero/board_driver_usb.c b/bootloaders/zero/board_driver_usb.c index 8a962b3fb..33b7e7f87 100644 --- a/bootloaders/zero/board_driver_usb.c +++ b/bootloaders/zero/board_driver_usb.c @@ -1,8 +1,8 @@ #include #include "board_driver_usb.h" +#include "sam_ba_usb.h" #include "sam_ba_cdc.h" -#include "cdc_enumerate.h" #define NVM_USB_PAD_TRANSN_POS (45) #define NVM_USB_PAD_TRANSN_SIZE (5) diff --git a/bootloaders/zero/main.c b/bootloaders/zero/main.c index 6dede8ccb..3bb9fdc01 100644 --- a/bootloaders/zero/main.c +++ b/bootloaders/zero/main.c @@ -67,8 +67,7 @@ #include "sam_ba_serial.h" #include "board_definitions.h" #include "board_driver_led.h" -#include "cdc_enumerate.h" -//#include "sam_ba_usb.h" +#include "sam_ba_usb.h" #include "sam_ba_cdc.h" extern uint32_t __app_start_address; diff --git a/bootloaders/zero/sam_ba_cdc.h b/bootloaders/zero/sam_ba_cdc.h index 31ec49bad..385fcd696 100644 --- a/bootloaders/zero/sam_ba_cdc.h +++ b/bootloaders/zero/sam_ba_cdc.h @@ -20,8 +20,7 @@ #define _SAM_BA_USB_CDC_H_ #include -#include "cdc_enumerate.h" -//#include "sam_ba_usb.h" +#include "sam_ba_usb.h" typedef struct { diff --git a/bootloaders/zero/sam_ba_monitor.c b/bootloaders/zero/sam_ba_monitor.c index 1cc3fabac..6096eda05 100644 --- a/bootloaders/zero/sam_ba_monitor.c +++ b/bootloaders/zero/sam_ba_monitor.c @@ -22,8 +22,7 @@ #include "sam_ba_serial.h" #include "board_driver_serial.h" #include "board_driver_usb.h" -//#include "sam_ba_usb.h" -#include "cdc_enumerate.h" +#include "sam_ba_usb.h" #include "sam_ba_cdc.h" const char RomBOOT_Version[] = SAM_BA_VERSION; diff --git a/bootloaders/zero/sam_ba_usb.c b/bootloaders/zero/sam_ba_usb.c index 151e436c2..61204a39a 100644 --- a/bootloaders/zero/sam_ba_usb.c +++ b/bootloaders/zero/sam_ba_usb.c @@ -18,7 +18,7 @@ #include #include -#include "cdc_enumerate.h" +#include "sam_ba_usb.h" #include "board_driver_usb.h" #include "sam_ba_cdc.h" From e1c9e646c2a6f9d789a46ed6586dd954e8814be7 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Tue, 6 Oct 2015 11:59:21 +0200 Subject: [PATCH 05/22] [bl] fix power failure in usb descriptor --- bootloaders/zero/sam_ba_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootloaders/zero/sam_ba_usb.c b/bootloaders/zero/sam_ba_usb.c index 61204a39a..67a374405 100644 --- a/bootloaders/zero/sam_ba_usb.c +++ b/bootloaders/zero/sam_ba_usb.c @@ -58,8 +58,8 @@ char cfgDescriptor[] = 0x02, // CbNumInterfaces 0x01, // CbConfigurationValue 0x00, // CiConfiguration - 0xC0, // CbmAttributes 0xA0 - 0x00, // CMaxPower + 0xC0, // CbmAttributes Bus powered without remote wakeup: 0xc0, Self powered with remote wakeup: 0xa0 + 0x32, // CMaxPower, report using 100mA, enough for a bootloader /* Communication Class Interface Descriptor Requirement */ 0x09, // bLength From 13dcceb052f86f880cefc361ec8cdf9c940cb2d9 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Tue, 6 Oct 2015 12:00:33 +0200 Subject: [PATCH 06/22] [bl] fix failed usb set_interface answer --- bootloaders/zero/sam_ba_usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bootloaders/zero/sam_ba_usb.c b/bootloaders/zero/sam_ba_usb.c index 67a374405..68880d44f 100644 --- a/bootloaders/zero/sam_ba_usb.c +++ b/bootloaders/zero/sam_ba_usb.c @@ -292,6 +292,7 @@ void sam_ba_usb_CDC_Enumerate(P_USB_CDC pCdc) } break; + case STD_SET_INTERFACE: case STD_CLEAR_FEATURE_ZERO: /* Stall the request */ USB_SendStall(pUsb, true); From d2a2c0172d170ba339ce8e5d60bbb2a6ca46f69e Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Tue, 6 Oct 2015 17:09:00 +0200 Subject: [PATCH 07/22] [bl] fix makefile for Studio case --- bootloaders/zero/Makefile | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/bootloaders/zero/Makefile b/bootloaders/zero/Makefile index 214bdc3b0..e10b40b9f 100644 --- a/bootloaders/zero/Makefile +++ b/bootloaders/zero/Makefile @@ -102,13 +102,15 @@ ELF=$(NAME).elf EXECUTABLE=$(NAME).bin ifneq "test$(AVRSTUDIO_EXE_PATH)" "test" -AS=copy_for_atmel_studio +AS_BUILD=copy_for_atmel_studio +AS_CLEAN=clean_for_atmel_studio else -AS= +AS_BUILD= +AS_CLEAN= endif -all: print_info $(SOURCES) $(EXECUTABLE) $(AS) +all: print_info $(SOURCES) $(EXECUTABLE) $(AS_BUILD) $(ELF): Makefile $(BUILD_PATH) $(OBJECTS) @echo ---------------------------------------------------------- @@ -149,11 +151,16 @@ copy_for_atmel_studio: $(EXECUTABLE) @echo Atmel Studio detected, copying ELF to project root for debug cp $(BUILD_PATH)/$(ELF) . -clean: +clean_for_atmel_studio: + @echo ---------------------------------------------------------- + @echo Atmel Studio detected, cleaing ELF from project root + -$(RM) $(BUILD_PATH)/$(ELF) . + +clean: $(AS_CLEAN) @echo ---------------------------------------------------------- @echo Cleaning project -$(RM) $(EXECUTABLE) -$(RM) $(BUILD_PATH)/*.* -rmdir $(BUILD_PATH) -.phony: clean print_info $(BUILD_PATH) +.phony: clean print_info $(BUILD_PATH) $(AS_BUILD) $(AS_CLEAN) From f140c86f5fdfab2572ccfea5bc39722cddc69d8c Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Tue, 6 Oct 2015 17:32:11 +0200 Subject: [PATCH 08/22] [bl] Fix usb power, move more functions to USB driver --- bootloaders/zero/board_driver_usb.c | 36 +++++++++++++++ bootloaders/zero/board_driver_usb.h | 3 +- bootloaders/zero/sam_ba_usb.c | 59 ++++++++++++------------ bootloaders/zero/sam_ba_usb.h | 67 +++++++++++++++++----------- bootloaders/zero/samd21_sam_ba.bin | Bin 5996 -> 5996 bytes 5 files changed, 108 insertions(+), 57 deletions(-) diff --git a/bootloaders/zero/board_driver_usb.c b/bootloaders/zero/board_driver_usb.c index 33b7e7f87..ff5a29f98 100644 --- a/bootloaders/zero/board_driver_usb.c +++ b/bootloaders/zero/board_driver_usb.c @@ -312,3 +312,39 @@ void USB_SendZlp(Usb *pUsb) 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 index 0267b240e..27d17d94e 100644 --- a/bootloaders/zero/board_driver_usb.h +++ b/bootloaders/zero/board_driver_usb.h @@ -25,7 +25,6 @@ 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); @@ -39,5 +38,7 @@ 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/sam_ba_usb.c b/bootloaders/zero/sam_ba_usb.c index 68880d44f..b40c12843 100644 --- a/bootloaders/zero/sam_ba_usb.c +++ b/bootloaders/zero/sam_ba_usb.c @@ -22,7 +22,10 @@ #include "board_driver_usb.h" #include "sam_ba_cdc.h" -__attribute__((__aligned__(4))) +/* 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 */ @@ -46,7 +49,10 @@ const char devDescriptor[] = 0x01 // bNumConfigs }; -__attribute__((__aligned__(4))) +/* 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 =========== */ @@ -58,7 +64,7 @@ char cfgDescriptor[] = 0x02, // CbNumInterfaces 0x01, // CbConfigurationValue 0x00, // CiConfiguration - 0xC0, // CbmAttributes Bus powered without remote wakeup: 0xc0, Self powered with remote wakeup: 0xa0 + 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 */ @@ -171,48 +177,42 @@ void sam_ba_usb_CDC_Enumerate(P_USB_CDC pCdc) switch ((bRequest << 8) | bmRequestType) { case STD_GET_DESCRIPTOR: - if (wValue == 0x100) + if (wValue == (STD_GET_DESCRIPTOR_DEVICE<<8)) + { /* Return Device Descriptor */ USB_Write(pCdc->pUsb, devDescriptor, SAM_BA_MIN(sizeof(devDescriptor), wLength), USB_EP_CTRL); - else if (wValue == 0x200) - /* Return Configuration Descriptor */ - USB_Write(pCdc->pUsb, cfgDescriptor, SAM_BA_MIN(sizeof(cfgDescriptor), wLength), USB_EP_CTRL); + } else - /* Stall the request */ - USB_SendStall(pUsb, true); + { + if (wValue == (STD_GET_DESCRIPTOR_CONFIGURATION<<8)) + { + /* Return Configuration Descriptor */ + USB_Write(pCdc->pUsb, cfgDescriptor, SAM_BA_MIN(sizeof(cfgDescriptor), wLength), USB_EP_CTRL); + } + else + { + /* 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 */ - pUsb->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | wValue; + USB_SetAddress(pCdc->pUsb, wValue); break; case STD_SET_CONFIGURATION: /* Store configuration */ pCdc->currentConfiguration = (uint8_t)wValue; + /* Send ZLP */ 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; + + /* Configure the 3 needed endpoints */ + USB_Configure(pUsb); break; case STD_GET_CONFIGURATION: @@ -282,6 +282,7 @@ void sam_ba_usb_CDC_Enumerate(P_USB_CDC pCdc) //pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0; pUsb->DEVICE.DeviceEndpoint[wIndex].EPSTATUSSET.bit.STALLRQ = (1<<0); } + /* Send ZLP */ USB_SendZlp(pUsb); } diff --git a/bootloaders/zero/sam_ba_usb.h b/bootloaders/zero/sam_ba_usb.h index f37034c79..d1ee0db9d 100644 --- a/bootloaders/zero/sam_ba_usb.h +++ b/bootloaders/zero/sam_ba_usb.h @@ -22,35 +22,48 @@ #include #include -#define USB_EP_CTRL (0) -#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 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 (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) +#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) #define SAM_BA_MIN(a, b) (((a) < (b)) ? (a) : (b)) diff --git a/bootloaders/zero/samd21_sam_ba.bin b/bootloaders/zero/samd21_sam_ba.bin index 6d645a2c2c63a438fa06b8fe77758a6dce60fd7e..e23e7b9889f3f3904a2541ef4eb3507a023604ba 100644 GIT binary patch delta 1173 zcmZ8hZ)h837=P~4#5Nfw{WF%P*Y@tR&Lo>9ZEV$waLd(hNjAIA6|}8VT+v8ZmK4;> z5brt$zAFQ}1#xY@Ob3qbgSwPPlnpw+70S2_2lmhKjw(YP7!*vcY0oEVD`f{ip67Xg z&-;6y_kG^?9yLE|ezG6~`>Pq?K4QUqv9hiP03Kkl{pslca`VM^DC)-aHR@YhR^0u; zT5&EtHX1t=o4MjP@%`}qiRwsoc;M75S0kJ^?-IM328N6_VQ*)z{iuIm{m?|y2z2$n zKD=A-ikF&RJ2?Uhcd)nOX#L5rk?HImIL!-vZ>Qb;aOXtq_H5S$3RuH1KAs0)kD%|L zX%9EJd!ps+n|0hs z{=h~H@kGz3jl8(w)yGTo3mPmp>ZIiVrhQbjs=P-Jkm2|rS}VaeqhNW~MyhyEG#R9R zw316{IrN~!l}b@Tw-Ip%D~0ZA0m3r-<3|3k_2R-+8-HqEhMJ@JJKAUn+&0A%rTJUh z=@9T%#Yv9w4q+thh&2#9>ld6d4w*c#@Pk$*)sgZ*KlQWoY65(enzDelWLdIr3Z%4J zBJ&r;H^Ou2%9xYbIZCKiS_pVS%^-(1n?`H$!orvTYppnoccCxg=f*{rvx;Tfrte^B zu`m9vMiW_fPl=((y|gPv5j$@cXr+|^w&MblXtM;Z$p;JPwBj{-N;Q>=Tydrnla}85 zCgSIcMXxwriOnTk@$HPIM4zP-GX}RZ7BNG>A{H@&<~L{UleO*iRN^Pg(~k){Fny=s zq=k7*u(+$DAhjjvirX|BDc{keYHWg$KUeT*#rE*)do_G*czQw64)X3jL>$nZa n;NUKL`nYx2YHw#-{Vi?K@@z+Idx!s->G_&&8c#Y|zo+{@PYIU7 delta 1140 zcmZ8gVQ3p=7=FJ?bIUGeP3v@766G!-YBM&jErs^V@XWbjn$?aili2!Www+6-X(qRyQ8BB?OXmD{Xi|>Y7h}s ze^h>k4i{?I8nT})aUrXXnMB3!U-NNjfsq0eYF~R^O~%G2@@gM5uI6VGG3B3pD{i3} zDW+V_t9kQ%6Tk2hS|R62 zqp`a9{6kRVW18mFUTrQ(l-gNy!MKo`Cz?0S&g#WT5RqORFb`od>dLVptG@DhG2#jj z!XN4B)Th0fcM28GC!TkEq|8WywfJb74~e{g@9b}SN(I2QCd(%6>gi6zAPGy!|sPogXSl3b+W)}$d|p52->%Tp4| zBB?pIqxnTXO^^O6;4|9_ohU@2&~rVQ3foV7*Pk*fiCF-)K=2_!o?w#TV*=zNQ_2Ov zu>i9OSj)0LKThhG9GQgyM(l5i2o-`)2zC~iWSu@t7VnPcdm`E;I`l*|JG>nYZAS~_ zyr&E=_UyX(J>)j6`cE5socn)!(?u%ctorFq_fqXfCGiRg;k)KexsONASap7b4RKkk z{v4^k8*l<%Zlr)MchQ-~p3R}_Q0rZ{>OWfL%XEmHTZ7u)Ya93M_u;+{wXfFU#d{iJ up{5X~x>mkTv(z*!pJc|ErcSn Date: Tue, 6 Oct 2015 17:36:29 +0200 Subject: [PATCH 09/22] [bl] Adding Atmel Studio 7 makefile based project, allowing debug --- bootloaders/zero/samd21_sam_ba.atsln | 22 +++ bootloaders/zero/samd21_sam_ba.cproj | 244 +++++++++++++++++++++++++++ 2 files changed, 266 insertions(+) create mode 100644 bootloaders/zero/samd21_sam_ba.atsln create mode 100644 bootloaders/zero/samd21_sam_ba.cproj 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.cproj b/bootloaders/zero/samd21_sam_ba.cproj new file mode 100644 index 000000000..fa48316c0 --- /dev/null +++ b/bootloaders/zero/samd21_sam_ba.cproj @@ -0,0 +1,244 @@ + + + + 2.0 + 7.0 + com.Atmel.ARMGCC.C + dce6c7e3-ee26-4d79-826b-08594b9ad897 + ATSAMD21J18A + 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 + + + + + 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_led.c + + + compile + sam_ba_led.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 + board_init.c.old + + + compile + Makefile + + + compile + README.md + + + compile + bootloader_samd21x18.ld + + + + From 4667b66525b94c6b6acddcac2b5f1c8fdbc1bfc1 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Thu, 8 Oct 2015 12:34:48 +0200 Subject: [PATCH 10/22] [bl] Fixing the jump to sketch --- bootloaders/zero/Makefile | 9 ++-- bootloaders/zero/bootloader_samd21x18.ld | 4 +- bootloaders/zero/main.c | 60 ++++++++++++++++------- bootloaders/zero/samd21_sam_ba.bin | Bin 5996 -> 6004 bytes bootloaders/zero/samd21_sam_ba.cproj | 26 +--------- 5 files changed, 50 insertions(+), 49 deletions(-) diff --git a/bootloaders/zero/Makefile b/bootloaders/zero/Makefile index e10b40b9f..956b758d1 100644 --- a/bootloaders/zero/Makefile +++ b/bootloaders/zero/Makefile @@ -65,9 +65,9 @@ SIZE=$(ARM_GCC_PATH)size #-w 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 +CFLAGS+=-g3 -O1 -DDEBUG=1 else -CFLAGS+=-Os +CFLAGS+=-Os -DDEBUG=0 endif #CFLAGS_EXTRA?=-D__SAMD21G18A__ -DUSB_PID_LOW=0x4D -DUSB_PID_HIGH=0x00 CFLAGS_EXTRA?=-D__SAMD21J18A__ -DUSB_PID_LOW=0x01 -DUSB_PID_HIGH=0xE0 @@ -153,8 +153,9 @@ copy_for_atmel_studio: $(EXECUTABLE) clean_for_atmel_studio: @echo ---------------------------------------------------------- - @echo Atmel Studio detected, cleaing ELF from project root - -$(RM) $(BUILD_PATH)/$(ELF) . + @echo Atmel Studio detected, cleaning ELF from project root +# -$(RM) $(BUILD_PATH)/$(ELF) + -$(RM) ./$(ELF) clean: $(AS_CLEAN) @echo ---------------------------------------------------------- diff --git a/bootloaders/zero/bootloader_samd21x18.ld b/bootloaders/zero/bootloader_samd21x18.ld index b08198203..a52db613e 100644 --- a/bootloaders/zero/bootloader_samd21x18.ld +++ b/bootloaders/zero/bootloader_samd21x18.ld @@ -58,7 +58,7 @@ MEMORY * __StackLimit * __StackTop * __stack - * __app_start_address + * __sketch_stackptr */ ENTRY(Reset_Handler) @@ -144,7 +144,7 @@ SECTIONS */ __etext = .; - PROVIDE(__app_start_address = ORIGIN(FLASH) + LENGTH(FLASH)); + PROVIDE(__sketch_stackptr = ORIGIN(FLASH) + LENGTH(FLASH)); .data : AT (__etext) diff --git a/bootloaders/zero/main.c b/bootloaders/zero/main.c index 3bb9fdc01..89bc17b69 100644 --- a/bootloaders/zero/main.c +++ b/bootloaders/zero/main.c @@ -70,10 +70,12 @@ #include "sam_ba_usb.h" #include "sam_ba_cdc.h" -extern uint32_t __app_start_address; +extern uint32_t __sketch_stackptr; // 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; @@ -105,7 +107,9 @@ static void check_start_application(void) /* First tap */ BOOT_DOUBLE_TAP_DATA = DOUBLE_TAP_MAGIC; - /* Wait 0.5sec to see if the user tap reset again */ + /* 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__(""); @@ -115,51 +119,71 @@ static void check_start_application(void) } #endif - uint32_t app_start_address; +#if (!defined DEBUG) || ((defined DEBUG) && (DEBUG == 0)) +uint32_t* pulSketch_Start_Address; +#endif - /* Load the Reset Handler address of the application */ - app_start_address = *(uint32_t *)(&__app_start_address + 4); + /* + * Test sketch stack pointer @ &__sketch_stackptr + * Stay in SAM-BA if value @ (&__sketch_stackptr) == 0xFFFFFFFF (Erased flash cell value) + */ + if (__sketch_stackptr == 0xFFFFFFFF) + { + /* Stay in bootloader */ + return; + } + + /* + * Load the sketch Reset Handler address + * __sketch_stackptr 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_stackptr ; + pulSketch_Start_Address++ ; - /** - * Test reset vector of application @__app_start_address+4 - * Stay in SAM-BA if *(__app_start_address+0x4) == 0xFFFFFFFF - * Application erased condition + /* + * Test reset vector of sketch @ &__sketch_stackptr+4 + * Stay in SAM-BA if this function is not aligned enough, ie not valid + * The value 0x01 is the 'Thumb mode' bit added by linker. */ - if (app_start_address == 0xFFFFFFFF) + if ( (*pulSketch_Start_Address & ~SCB_VTOR_TBLOFF_Msk) != 0x01 ) { /* 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 */ + // 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 */ + // Read the BOOT_LOAD_PIN status boot_en = (boot_port->IN.reg) & BOOT_PIN_MASK; - /* Check the bootloader enable condition */ + // Check the bootloader enable condition if (!boot_en) { - /* Stay in bootloader */ + // Stay in bootloader return; } #endif +*/ LED_on(); /* Rebase the Stack Pointer */ - __set_MSP(*(uint32_t *) &__app_start_address); + __set_MSP( (uint32_t)(*(pulSketch_Start_Address-1)) ); /* Rebase the vector table base address */ - SCB->VTOR = ((uint32_t) &__app_start_address & SCB_VTOR_TBLOFF_Msk); + SCB->VTOR = ((uint32_t)(pulSketch_Start_Address-1) & SCB_VTOR_TBLOFF_Msk); /* Jump to application Reset Handler in the application */ - asm("bx %0"::"r"(app_start_address)); + asm("bx %0"::"r"(*pulSketch_Start_Address)); } #if DEBUG_ENABLE diff --git a/bootloaders/zero/samd21_sam_ba.bin b/bootloaders/zero/samd21_sam_ba.bin index e23e7b9889f3f3904a2541ef4eb3507a023604ba..c8b37a3d42a60c5fdc2e974509f5583a4fed88ac 100644 GIT binary patch delta 597 zcmXZXQD{<87zgn4U32QyIZe&09OI}-PHA*?qh^f7s*Tjq(_RL`l_lMW!S+y54~2sT z?rnA$v?2&1dI*Ac5gN1@L_Nf4ld*>pYr^PF=%L^arrkbA7k+%_eD}|H&T01j>07)B zQni!>>0Q+a@K$>b-2h*BO_+g4JZ4&jxVCSa5K7cfh^v;!l_QUZr^;k8o~6`%45ms$D~1kN=e`adlzE(1-c1<(B1Fn^8k|YGYOowsI@p=xk5(1Dl+l z_L9!W9-=b3iWr5kp*LHHYwM$~nmK3AM-@Z=dcB7 zBeMDkS;xA8gja^KgLS_1R9v4xyZm|2C*K}+_t6=ga6Azc2mFq!1V8w9R{{3;pt~2o z@hNu^PHCUr+d}`Kn~(w;M^*F&4V)xo$V13o!pM!O+l*agsq^vxkyDveIwN1;8(t|; U5DB@Dme4BN`Cr>w+dCut0}qa~VgLXD delta 588 zcmXZWUuaTM7y$6^TyyGO=5_66x-&ZdS<^L5x4A;-&s={%4G9u9L%6by98s&N@Fm*F z2Ym=yr-v=*sYcM-x;Y9OMD=QE5d{%#)muFjD-34cKB0%-`Of#9@0|1f415b*8z<82 z#10}Y&dP+`Q|}TpAy0W(m?AU0OZSL))Q`H9kZHF8NM&z)+I3yHsid>pV_T^;Ph8gh zU2$-MPpr|LJ9Z;VYIa3laVX9hi9k=I=1^GNF=?mAs92r$+z|@dj@*?sV^MR@4?E)X zigZ}3JJtD?J*2hwZ>Z?amF{cxVZLfOVOaaas8(-NlSWQVg@$*fnY#E_Q;3Z7PSI}v z-uS)z$Mp%fqSarlGwRG~^~XFZc9MPkl-ME9G+2HMc5M`ZNo7N#`NmOxOZ0b3 z4MwHqX8larm}sGln(=JsI=JVe`YOwXXbmiZ2kv$^Z_j)kO3ZIe2#<#O{-um;I#v|-+*d- z!SYOggVndlgM$@N5j)=VOVR}S#6L?JvdV|7KJtp6v}VaBwPJlOTna@FpARP#&s|B1%fytq(p$T=qg%7mH+V< e#^Xch#xG2so{Ef&rZd>NDEBUG - - - - Optimize for size (-Os) True True @@ -81,16 +77,8 @@ libm - - - - True -Tsamd21j18a_flash.ld - - - - @@ -107,10 +95,6 @@ DEBUG - - - - Optimize (-O1) True Maximum (-g3) @@ -120,17 +104,9 @@ libm - - - - True -Tsamd21j18a_flash.ld Default (-g) - - - - Default (-Wa,-g) @@ -241,4 +217,4 @@ - + \ No newline at end of file From 2cdd455259622205afe7cb1ad1a1f65e78c2b96b Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Sat, 10 Oct 2015 15:24:26 +0200 Subject: [PATCH 11/22] [bl] Updating USB descriptors --- bootloaders/zero/sam_ba_usb.c | 93 +++++++++++++++++++++++++++++------ bootloaders/zero/sam_ba_usb.h | 10 ++++ 2 files changed, 89 insertions(+), 14 deletions(-) diff --git a/bootloaders/zero/sam_ba_usb.c b/bootloaders/zero/sam_ba_usb.c index b40c12843..0de14499e 100644 --- a/bootloaders/zero/sam_ba_usb.c +++ b/bootloaders/zero/sam_ba_usb.c @@ -31,21 +31,26 @@ const char devDescriptor[] = /* Device descriptor */ 0x12, // bLength 0x01, // bDescriptorType - 0x10, // bcdUSBL - 0x01, // + 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, // idVendorL - 0x23, // - USB_PID_LOW, // idProductL - USB_PID_HIGH, // - 0x10, // bcdDeviceL - 0x01, // - 0x00, // iManufacturer // 0x01 + 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 - 0x00, // SerialNumber +#endif // 0 + 0x00, // SerialNumber, should be based on product unique ID 0x01 // bNumConfigs }; @@ -145,6 +150,13 @@ char cfgDescriptor[] = 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; @@ -177,22 +189,50 @@ void sam_ba_usb_CDC_Enumerate(P_USB_CDC pCdc) switch ((bRequest << 8) | bmRequestType) { case STD_GET_DESCRIPTOR: - if (wValue == (STD_GET_DESCRIPTOR_DEVICE<<8)) + 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 == (STD_GET_DESCRIPTOR_CONFIGURATION<<8)) + 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 { - /* Stall the request */ - USB_SendStall(pUsb, true); +#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; @@ -388,3 +428,28 @@ P_USB_CDC usb_init(void) 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 index d1ee0db9d..48725b10c 100644 --- a/bootloaders/zero/sam_ba_usb.h +++ b/bootloaders/zero/sam_ba_usb.h @@ -65,6 +65,12 @@ #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)) @@ -89,6 +95,10 @@ 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; From 82d20c102a60fe3edb657382c36fc133b0abc4d3 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Sat, 10 Oct 2015 15:34:07 +0200 Subject: [PATCH 12/22] [bl] removing useless old file --- bootloaders/zero/board_init.c.old | 89 ------------------------------- 1 file changed, 89 deletions(-) delete mode 100644 bootloaders/zero/board_init.c.old diff --git a/bootloaders/zero/board_init.c.old b/bootloaders/zero/board_init.c.old deleted file mode 100644 index 1bcca3d18..000000000 --- a/bootloaders/zero/board_init.c.old +++ /dev/null @@ -1,89 +0,0 @@ -/* - 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 -*/ - -void system_init(void) -{ - /* 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 -} From c8095fdfa9bdb3699d4186dec86b1bed44b85c23 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Sat, 10 Oct 2015 15:42:09 +0200 Subject: [PATCH 13/22] [bl] updating Makefile --- bootloaders/zero/Makefile | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/bootloaders/zero/Makefile b/bootloaders/zero/Makefile index 956b758d1..a8303f9d1 100644 --- a/bootloaders/zero/Makefile +++ b/bootloaders/zero/Makefile @@ -1,3 +1,4 @@ +# 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 @@ -20,14 +21,18 @@ 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 @@ -69,8 +74,7 @@ CFLAGS+=-g3 -O1 -DDEBUG=1 else CFLAGS+=-Os -DDEBUG=0 endif -#CFLAGS_EXTRA?=-D__SAMD21G18A__ -DUSB_PID_LOW=0x4D -DUSB_PID_HIGH=0x00 -CFLAGS_EXTRA?=-D__SAMD21J18A__ -DUSB_PID_LOW=0x01 -DUSB_PID_HIGH=0xE0 +CFLAGS_EXTRA?=-D__SAMD21G18A__ -DUSB_PID_LOW=0x4D -DUSB_PID_HIGH=0x00 INCLUDES=-I"$(MODULE_PATH)/tools/CMSIS/4.0.0-atmel/CMSIS/Include/" -I"$(MODULE_PATH)/tools/CMSIS/4.0.0-atmel/Device/ATMEL/" # ----------------------------------------------------------------------------- @@ -99,7 +103,8 @@ DEPS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.d)) NAME=samd21_sam_ba ELF=$(NAME).elf -EXECUTABLE=$(NAME).bin +BIN=$(NAME).bin +HEX=$(NAME).hex ifneq "test$(AVRSTUDIO_EXE_PATH)" "test" AS_BUILD=copy_for_atmel_studio @@ -110,7 +115,7 @@ AS_CLEAN= endif -all: print_info $(SOURCES) $(EXECUTABLE) $(AS_BUILD) +all: print_info $(SOURCES) $(BIN) $(HEX) $(AS_BUILD) $(ELF): Makefile $(BUILD_PATH) $(OBJECTS) @echo ---------------------------------------------------------- @@ -119,11 +124,16 @@ $(ELF): Makefile $(BUILD_PATH) $(OBJECTS) "$(NM)" "$(BUILD_PATH)/$(ELF)" >"$(BUILD_PATH)/$(NAME)_symbols.txt" "$(SIZE)" --format=sysv -t -x $(BUILD_PATH)/$(ELF) -$(EXECUTABLE): $(ELF) +$(BIN): $(ELF) @echo ---------------------------------------------------------- @echo Creating flash binary "$(OBJCOPY)" -O binary $(BUILD_PATH)/$< $@ +$(HEX): $(ELF) + @echo ---------------------------------------------------------- + @echo Creating flash binary + "$(OBJCOPY)" -O ihex $(BUILD_PATH)/$< $@ + $(BUILD_PATH)/%.o: %.c @echo ---------------------------------------------------------- @echo Compiling $< to $@ @@ -140,13 +150,13 @@ print_info: @echo Compiling bootloader using @echo BASE PATH = $(MODULE_PATH) @echo GCC PATH = $(ARM_GCC_PATH) - @echo OS = $(OS) - @echo SHELL = $(SHELL) - @echo TERM = $(TERM) +# @echo OS = $(OS) +# @echo SHELL = $(SHELL) +# @echo TERM = $(TERM) # "$(CC)" -v # env -copy_for_atmel_studio: $(EXECUTABLE) +copy_for_atmel_studio: $(BIN) $(HEX) @echo ---------------------------------------------------------- @echo Atmel Studio detected, copying ELF to project root for debug cp $(BUILD_PATH)/$(ELF) . @@ -154,14 +164,14 @@ copy_for_atmel_studio: $(EXECUTABLE) clean_for_atmel_studio: @echo ---------------------------------------------------------- @echo Atmel Studio detected, cleaning ELF from project root -# -$(RM) $(BUILD_PATH)/$(ELF) -$(RM) ./$(ELF) clean: $(AS_CLEAN) @echo ---------------------------------------------------------- @echo Cleaning project - -$(RM) $(EXECUTABLE) + -$(RM) $(BIN) + -$(RM) $(HEX) -$(RM) $(BUILD_PATH)/*.* -rmdir $(BUILD_PATH) -.phony: clean print_info $(BUILD_PATH) $(AS_BUILD) $(AS_CLEAN) +.phony: print_info $(BUILD_PATH) From 455cd9b6e3871cc63db294329c9ba631e1cfd39a Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Sat, 10 Oct 2015 15:48:15 +0200 Subject: [PATCH 14/22] [bl] Fixing bug in jump to application --- bootloaders/zero/bootloader_samd21x18.ld | 5 +- bootloaders/zero/main.c | 40 ++++----- bootloaders/zero/samd21_sam_ba.bin | Bin 6004 -> 5972 bytes bootloaders/zero/samd21_sam_ba.cproj | 102 +++++++++++++---------- 4 files changed, 79 insertions(+), 68 deletions(-) diff --git a/bootloaders/zero/bootloader_samd21x18.ld b/bootloaders/zero/bootloader_samd21x18.ld index a52db613e..2a8b056d3 100644 --- a/bootloaders/zero/bootloader_samd21x18.ld +++ b/bootloaders/zero/bootloader_samd21x18.ld @@ -1,5 +1,6 @@ /* 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 @@ -58,7 +59,7 @@ MEMORY * __StackLimit * __StackTop * __stack - * __sketch_stackptr + * __sketch_vectors_ptr */ ENTRY(Reset_Handler) @@ -144,7 +145,7 @@ SECTIONS */ __etext = .; - PROVIDE(__sketch_stackptr = ORIGIN(FLASH) + LENGTH(FLASH)); + PROVIDE(__sketch_vectors_ptr = ORIGIN(FLASH) + LENGTH(FLASH)); .data : AT (__etext) diff --git a/bootloaders/zero/main.c b/bootloaders/zero/main.c index 89bc17b69..d344985e1 100644 --- a/bootloaders/zero/main.c +++ b/bootloaders/zero/main.c @@ -1,5 +1,6 @@ /* 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 @@ -30,7 +31,7 @@ * * USB : D-:PA24 D+:PA25 * - * Pins Usage + * Pins Usage (*outdated as of 2015/10/10*) * -------------------- * The following pins are used by the program : * PA25 : input/output @@ -42,7 +43,7 @@ * 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 + * Clock system (*outdated as of 2015/10/10*) * -------------------- * CPU clock source (GCLK_GEN_0) - 8MHz internal oscillator (OSC8M) * SERCOM5 core GCLK source (GCLK_ID_SERCOM5_CORE) - GCLK_GEN_0 (i.e., OSC8M) @@ -54,10 +55,10 @@ * 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 + * 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 + * application code is taking care of this. * */ @@ -70,7 +71,7 @@ #include "sam_ba_usb.h" #include "sam_ba_cdc.h" -extern uint32_t __sketch_stackptr; // Exported value from linker script +extern uint32_t __sketch_vectors_ptr; // Exported value from linker script extern void board_init(void); #if (defined DEBUG) && (DEBUG == 1) @@ -85,8 +86,8 @@ static volatile bool main_b_cdc_enable = false; */ static void check_start_application(void) { - LED_init(); - LED_off(); +// LED_init(); +// LED_off(); #if defined(BOOT_DOUBLE_TAP_ADDRESS) #define DOUBLE_TAP_MAGIC 0x07738135 @@ -124,30 +125,29 @@ uint32_t* pulSketch_Start_Address; #endif /* - * Test sketch stack pointer @ &__sketch_stackptr - * Stay in SAM-BA if value @ (&__sketch_stackptr) == 0xFFFFFFFF (Erased flash cell value) + * Test sketch stack pointer @ &__sketch_vectors_ptr + * Stay in SAM-BA if value @ (&__sketch_vectors_ptr) == 0xFFFFFFFF (Erased flash cell value) */ - if (__sketch_stackptr == 0xFFFFFFFF) + if (__sketch_vectors_ptr == 0xFFFFFFFF) { /* Stay in bootloader */ return; } - - /* + + /* * Load the sketch Reset Handler address - * __sketch_stackptr is exported from linker script and point on first 32b word of sketch vector table + * __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_stackptr ; + pulSketch_Start_Address = &__sketch_vectors_ptr ; pulSketch_Start_Address++ ; /* - * Test reset vector of sketch @ &__sketch_stackptr+4 + * Test vector table address of sketch @ &__sketch_vectors_ptr * Stay in SAM-BA if this function is not aligned enough, ie not valid - * The value 0x01 is the 'Thumb mode' bit added by linker. */ - if ( (*pulSketch_Start_Address & ~SCB_VTOR_TBLOFF_Msk) != 0x01 ) + if ( ((uint32_t)(&__sketch_vectors_ptr) & ~SCB_VTOR_TBLOFF_Msk) != 0x00) { /* Stay in bootloader */ return; @@ -174,13 +174,13 @@ uint32_t* pulSketch_Start_Address; #endif */ - LED_on(); +// LED_on(); /* Rebase the Stack Pointer */ - __set_MSP( (uint32_t)(*(pulSketch_Start_Address-1)) ); + __set_MSP( (uint32_t)(__sketch_vectors_ptr) ); /* Rebase the vector table base address */ - SCB->VTOR = ((uint32_t)(pulSketch_Start_Address-1) & SCB_VTOR_TBLOFF_Msk); + 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)); diff --git a/bootloaders/zero/samd21_sam_ba.bin b/bootloaders/zero/samd21_sam_ba.bin index c8b37a3d42a60c5fdc2e974509f5583a4fed88ac..76052986033a3d160ff41a398af7cf345a085af6 100644 GIT binary patch delta 1000 zcmXYve`p(J7{{OYvbO1EB}tofNqTKBch#opT9U@f$k=Ev(yd8r6dAM|h0Ilnj&1F* zdL6o6rRdck(Cz)hZqrebs(*;Gg)2-b28OUdL@(kWGNb13j}>GRe_&>J-T5T!;PXDu z^Zh>ezR!EyKm9-SuS_%dS}!~w#`W4o4CX8&qS?kU9E@?FRAXezhH87R*)v zm)4a6!7mfhKP05sf-fs1S0qyKXFR1qhEI|>gv~-A(~05d%D4X8#eJ0Jxz$50DF_jr2!WY^4B>~bTh*weB753 z6fTuIib`-4-okvsXecg*U({a@pVpNy=ua8brA6`B0$fJ(ixS)xjl6iJRwazpR8t3lsu@SIh7{6SO=WtXp8mGKAN#&Yfb?GhB*jW=ug zR_Tpu)V)SbJvn=~6jR$+(rYjH9BQ)=%2J8^$f_5wpC2vOET)%+?Hvu)PId2&T-r{_ zsTDI+s+RpbU8VfUI{^G5@(Lm&uOjCW#s)x;AP?|i5TgJv=7H+NpF!xa61?d#@D zo^x$h^%>1RR?qQV6MFmagSaZy>3lZIg|VKbf3kc0-KchRk8!IKtHa&~y@wOHeR$F^ z4LV|t3Qo9;Q+<=0a(rha8QSNJkvu)_+|&0yT3;hqku78m`3zy!Elb0=RJ{=9yO0}n z-FefyiRxEK7Y??BsMv9nzUF$4{6T+nO_95F*xf^Zp(owPnSVXGZ{2ImZeSRIpT%2k1qJ#00)phWEOcF@iqgrw*b71zj*q@OMEoK4@9Da5FLyU#NyEiOt4Kbi5vwH z*Ml(7AE|!$11z8nFo#@1w1@F$jK_x0PS3q?`b>Oc^5_)y23-<=BC?e0^d4dU2fKbp A`Tzg` delta 1032 zcmXYve{2(F7{{OY%2>H>^g3F)b}!qt$6VLJSX&oI3A(j&&~|e{Ljqlvbb_QtltTP* zHDYgM#Dn<9*oCkk|I832#stEePBCJdkobpL^s18hW0Px)AyE>VXsklV`LyAZ&-;Cz z=lk6IKJVpz=>EHV`Y6+Ezi`Zp>-8BcAy>0kNFyO%DLLi@IjgiAZV*rQj^QAap>_Z+ z=Z#738D>5apYTK}wTQ%R>FuSbFw`;9U=us!l5}6LX-r-TPZjb?wBLlOrvzO z8c%+|M7r35BrGtOCno2*6(P7%CyD)3O+{QycAA5`wPh|u+C0ZIqf!E;w7=sB4+8kv{`Oq zf?-zbcZW`1+5gcfBld|Ok2Wz(xS4()g2IB)aQ%G zv`Jws1M_HJ*Wl;&VqRFNWzQDpV$~`w_7|sx7BU|iRBfxO@C&+bReoGqtmU9~7kR3e zJ&$~{CwXp3FF*6Bvv|Jteno@TwxV2%|Ips6s%kF=xVpbCH3-W$}V;r z*`tiGEwW!-#U4-PzGl;VE~sT2JMS!y7428`0}}2*PZrPUVw6 z>cu>w6j-~%j@1tOB%KYhD(t9NJE@!Y;YmJ)m;##?al&&r)xGRq)3*j9DUId;(UbwR zediZw{f>Nz7;OM~)D?vJP}gsxPE{|2@do54<*fOZZ4Ik;knK3w6e45CZ^}6L68TlR z#f_6S#bxOv-zYK51hdtay=qxx8aToL^bZI`h0oSL&-`!LF@Z&5%8o7wvKyE+Qb=0we dQ%B!;`Lz?lLx7.0 com.Atmel.ARMGCC.C dce6c7e3-ee26-4d79-826b-08594b9ad897 - ATSAMD21J18A + ATSAMD21G18A none Executable C @@ -55,60 +55,70 @@ 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 + + + 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 + True + True + True + True + + + DEBUG + + + Optimize (-O1) + True + Maximum (-g3) + True + + + libm + + + True + -Tsamd21j18a_flash.ld + Default (-g) + Default (-Wa,-g) + True From 6abaae18f1e737c1fc7766c548df49fafbd92b8f Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Sat, 10 Oct 2015 15:51:12 +0200 Subject: [PATCH 15/22] [bl] Removing useless files --- bootloaders/zero/Makefile | 2 -- bootloaders/zero/sam_ba_led.c | 0 bootloaders/zero/sam_ba_led.h | 0 3 files changed, 2 deletions(-) delete mode 100644 bootloaders/zero/sam_ba_led.c delete mode 100644 bootloaders/zero/sam_ba_led.h diff --git a/bootloaders/zero/Makefile b/bootloaders/zero/Makefile index a8303f9d1..683404506 100644 --- a/bootloaders/zero/Makefile +++ b/bootloaders/zero/Makefile @@ -93,11 +93,9 @@ board_startup.c \ main.c \ sam_ba_usb.c \ sam_ba_cdc.c \ -sam_ba_led.c \ sam_ba_monitor.c \ sam_ba_serial.c - OBJECTS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.o)) DEPS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.d)) diff --git a/bootloaders/zero/sam_ba_led.c b/bootloaders/zero/sam_ba_led.c deleted file mode 100644 index e69de29bb..000000000 diff --git a/bootloaders/zero/sam_ba_led.h b/bootloaders/zero/sam_ba_led.h deleted file mode 100644 index e69de29bb..000000000 From 7c83f8c639467218c0e25fc5752d004968c58caa Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Sat, 10 Oct 2015 15:57:00 +0200 Subject: [PATCH 16/22] [bl] Updating copyrights --- bootloaders/zero/board_definitions.h | 1 + bootloaders/zero/board_driver_led.c | 19 +++++++++++++++++++ bootloaders/zero/board_driver_led.h | 19 +++++++++++++++++++ bootloaders/zero/board_driver_serial.c | 1 + bootloaders/zero/board_driver_serial.h | 1 + bootloaders/zero/board_driver_usb.c | 23 ++++++++++++++++++++--- bootloaders/zero/board_driver_usb.h | 1 + bootloaders/zero/board_init.c | 1 + bootloaders/zero/board_startup.c | 1 + bootloaders/zero/sam_ba_cdc.c | 1 + bootloaders/zero/sam_ba_cdc.h | 1 + bootloaders/zero/sam_ba_monitor.c | 1 + bootloaders/zero/sam_ba_monitor.h | 1 + bootloaders/zero/sam_ba_serial.c | 1 + bootloaders/zero/sam_ba_serial.h | 1 + bootloaders/zero/sam_ba_usb.c | 1 + bootloaders/zero/sam_ba_usb.h | 1 + 17 files changed, 72 insertions(+), 3 deletions(-) diff --git a/bootloaders/zero/board_definitions.h b/bootloaders/zero/board_definitions.h index e986dde42..458e1b0a7 100644 --- a/bootloaders/zero/board_definitions.h +++ b/bootloaders/zero/board_definitions.h @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/board_driver_led.c b/bootloaders/zero/board_driver_led.c index 9adf7f634..1a2430aff 100644 --- a/bootloaders/zero/board_driver_led.c +++ b/bootloaders/zero/board_driver_led.c @@ -1,3 +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 index f4954df35..6f1fd7580 100644 --- a/bootloaders/zero/board_driver_led.h +++ b/bootloaders/zero/board_driver_led.h @@ -1,3 +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 +*/ + #ifndef _BOARD_DRIVER_LED_ #define _BOARD_DRIVER_LED_ diff --git a/bootloaders/zero/board_driver_serial.c b/bootloaders/zero/board_driver_serial.c index a7c2bc0f9..7a0f57581 100644 --- a/bootloaders/zero/board_driver_serial.c +++ b/bootloaders/zero/board_driver_serial.c @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/board_driver_serial.h b/bootloaders/zero/board_driver_serial.h index 44e070f61..c752d977d 100644 --- a/bootloaders/zero/board_driver_serial.h +++ b/bootloaders/zero/board_driver_serial.h @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/board_driver_usb.c b/bootloaders/zero/board_driver_usb.c index ff5a29f98..6534fa338 100644 --- a/bootloaders/zero/board_driver_usb.c +++ b/bootloaders/zero/board_driver_usb.c @@ -1,3 +1,21 @@ +/* + 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" @@ -155,12 +173,12 @@ uint32_t USB_Write(Usb *pUsb, const char *pData, uint32_t length, uint8_t ep_num 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); + 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) )); + while ( (pUsb->DEVICE.DeviceEndpoint[ep_num].EPINTFLAG.bit.TRCPT & (1<<1)) == 0 ); return length; } @@ -347,4 +365,3 @@ void USB_Configure(Usb *pUsb) 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 index 27d17d94e..4e71b8c1a 100644 --- a/bootloaders/zero/board_driver_usb.h +++ b/bootloaders/zero/board_driver_usb.h @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/board_init.c b/bootloaders/zero/board_init.c index d6063459a..c08aedaae 100644 --- a/bootloaders/zero/board_init.c +++ b/bootloaders/zero/board_init.c @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/board_startup.c b/bootloaders/zero/board_startup.c index 747a3576a..aaa5a019f 100644 --- a/bootloaders/zero/board_startup.c +++ b/bootloaders/zero/board_startup.c @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/sam_ba_cdc.c b/bootloaders/zero/sam_ba_cdc.c index 494ac3b6d..fc5efe348 100644 --- a/bootloaders/zero/sam_ba_cdc.c +++ b/bootloaders/zero/sam_ba_cdc.c @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/sam_ba_cdc.h b/bootloaders/zero/sam_ba_cdc.h index 385fcd696..49b7643cf 100644 --- a/bootloaders/zero/sam_ba_cdc.h +++ b/bootloaders/zero/sam_ba_cdc.h @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/sam_ba_monitor.c b/bootloaders/zero/sam_ba_monitor.c index 6096eda05..7daeb3067 100644 --- a/bootloaders/zero/sam_ba_monitor.c +++ b/bootloaders/zero/sam_ba_monitor.c @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/sam_ba_monitor.h b/bootloaders/zero/sam_ba_monitor.h index 977b3d5e6..e72582bcf 100644 --- a/bootloaders/zero/sam_ba_monitor.h +++ b/bootloaders/zero/sam_ba_monitor.h @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/sam_ba_serial.c b/bootloaders/zero/sam_ba_serial.c index 50496fd53..a06de01dc 100644 --- a/bootloaders/zero/sam_ba_serial.c +++ b/bootloaders/zero/sam_ba_serial.c @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/sam_ba_serial.h b/bootloaders/zero/sam_ba_serial.h index 5bc5a99d6..cb69f459e 100644 --- a/bootloaders/zero/sam_ba_serial.h +++ b/bootloaders/zero/sam_ba_serial.h @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/sam_ba_usb.c b/bootloaders/zero/sam_ba_usb.c index 0de14499e..090375c7f 100644 --- a/bootloaders/zero/sam_ba_usb.c +++ b/bootloaders/zero/sam_ba_usb.c @@ -1,5 +1,6 @@ /* 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 diff --git a/bootloaders/zero/sam_ba_usb.h b/bootloaders/zero/sam_ba_usb.h index 48725b10c..42c0d608f 100644 --- a/bootloaders/zero/sam_ba_usb.h +++ b/bootloaders/zero/sam_ba_usb.h @@ -1,5 +1,6 @@ /* 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 From 0b77c5719e08a799f9685b5e074f72b178718ef9 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Sat, 10 Oct 2015 15:58:33 +0200 Subject: [PATCH 17/22] [bl] adding all binaries coresponding to current code --- bootloaders/zero/samd21_sam_ba.bin | Bin 5972 -> 5972 bytes bootloaders/zero/samd21_sam_ba.elf | Bin 0 -> 647224 bytes bootloaders/zero/samd21_sam_ba.hex | 376 +++++++++++++++++++++++++++++ 3 files changed, 376 insertions(+) create mode 100644 bootloaders/zero/samd21_sam_ba.elf create mode 100644 bootloaders/zero/samd21_sam_ba.hex diff --git a/bootloaders/zero/samd21_sam_ba.bin b/bootloaders/zero/samd21_sam_ba.bin index 76052986033a3d160ff41a398af7cf345a085af6..d727d0707f3031f1eb86ed72e76749ef1a997fa7 100644 GIT binary patch delta 18 acmcbjcSUc*dJ$Grb1M_m&09nkFaZEX>;|a- delta 18 acmcbjcSUc*dJ$G5V=F_0&09nkFaZEXcLtgO 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/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 From 23565f386ed6f71dfffd2f68028c2a2ffa382e9a Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Fri, 30 Oct 2015 10:48:59 +0100 Subject: [PATCH 18/22] [BL] Updating project documentation --- bootloaders/zero/README.md | 52 ++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/bootloaders/zero/README.md b/bootloaders/zero/README.md index 8c760449e..84c42bca9 100644 --- a/bootloaders/zero/README.md +++ b/bootloaders/zero/README.md @@ -1,21 +1,47 @@ -1- Prerequisites +# Arduino Zero Bootloader +# ----------------------- -IAR Embedded Workbench for ARM 7.30 +## 1- Prerequisites -2- Selecting between USB and UART interface +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 + +### 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 Makefile-based project is present at project root, just open samd21_sam_ba.atsln file. + +### 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 +* 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 +## 3- Behaviour -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. +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. -Currently, BOOT_LOAD_PIN is PA15 of SAMD21G18A, pin 5 of Arduino Zero board. +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. From 789595c334ac25112a47c99987f049f3252073fb Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Fri, 30 Oct 2015 10:49:32 +0100 Subject: [PATCH 19/22] [BL] Removing useless build parameter --- bootloaders/zero/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/bootloaders/zero/Makefile b/bootloaders/zero/Makefile index 683404506..13de72f2d 100644 --- a/bootloaders/zero/Makefile +++ b/bootloaders/zero/Makefile @@ -67,7 +67,6 @@ SIZE=$(ARM_GCC_PATH)size # ----------------------------------------------------------------------------- # Compiler options -#-w 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 From 6ef81c4f1986c30d5cd76650aa55c2979e21d4f4 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Fri, 30 Oct 2015 10:50:16 +0100 Subject: [PATCH 20/22] [BL] Removing non used files from AS project --- bootloaders/zero/samd21_sam_ba.cproj | 102 ++++++++++++--------------- 1 file changed, 45 insertions(+), 57 deletions(-) diff --git a/bootloaders/zero/samd21_sam_ba.cproj b/bootloaders/zero/samd21_sam_ba.cproj index 4104a33be..70ee7e93a 100644 --- a/bootloaders/zero/samd21_sam_ba.cproj +++ b/bootloaders/zero/samd21_sam_ba.cproj @@ -69,56 +69,56 @@ - True - True - True - True - True - - - NDEBUG - - - Optimize for size (-Os) - True - True - - - libm - - - True - -Tsamd21j18a_flash.ld - + 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 + True + True + True + True + + + DEBUG + + + Optimize (-O1) + True + Maximum (-g3) + True + + + libm + + + True + -Tsamd21j18a_flash.ld + Default (-g) + Default (-Wa,-g) + True @@ -175,14 +175,6 @@ compile sam_ba_cdc.h - - compile - sam_ba_led.c - - - compile - sam_ba_led.h - compile sam_ba_monitor.c @@ -209,10 +201,6 @@ - - compile - board_init.c.old - compile Makefile From 9181fb11b3a1aa7f79bbf60677f5cf0d02cbe4f1 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Fri, 30 Oct 2015 12:23:20 +0100 Subject: [PATCH 21/22] [bl] Updating project documentation --- bootloaders/zero/README.md | 39 +++++++++++++++++++++++++++------ bootloaders/zero/main.c | 45 -------------------------------------- 2 files changed, 32 insertions(+), 52 deletions(-) diff --git a/bootloaders/zero/README.md b/bootloaders/zero/README.md index 84c42bca9..e0e19b96f 100644 --- a/bootloaders/zero/README.md +++ b/bootloaders/zero/README.md @@ -1,5 +1,4 @@ # Arduino Zero Bootloader -# ----------------------- ## 1- Prerequisites @@ -8,16 +7,18 @@ 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: +* Native command line Make binary can be obtained here: http://gnuwin32.sourceforge.net/packages/make.htm -* Cygwin/MSys/MSys2/Babun/etc...: +* Cygwin/MSys/MSys2/Babun/etc... It is available natively in all distributions. -* Atmel Studio: -An Atmel Studio Makefile-based project is present at project root, just open samd21_sam_ba.atsln file. +* Atmel Studio +An Atmel Studio **7** Makefile-based project is present at project root, just open samd21_sam_ba.atsln file in AS7. ### Linux @@ -37,11 +38,35 @@ Set the define SAM_BA_INTERFACE to * 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. +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/main.c b/bootloaders/zero/main.c index d344985e1..3b18872a8 100644 --- a/bootloaders/zero/main.c +++ b/bootloaders/zero/main.c @@ -17,51 +17,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * -------------------- - * 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 (*outdated as of 2015/10/10*) - * -------------------- - * 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 (*outdated as of 2015/10/10*) - * -------------------- - * 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 (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. - * -*/ - #include #include #include "sam_ba_monitor.h" From 97cda8353f94b06aaf6cbda634296304442805a1 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Fri, 30 Oct 2015 12:24:24 +0100 Subject: [PATCH 22/22] [bl] Updating documentation presentation --- bootloaders/zero/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bootloaders/zero/README.md b/bootloaders/zero/README.md index e0e19b96f..44f4e4e02 100644 --- a/bootloaders/zero/README.md +++ b/bootloaders/zero/README.md @@ -49,6 +49,7 @@ The USART in use is the one available on pins D0/D1, labelled respectively RX/TX ## 4- Description **Pinmap** + The following pins are used by the program : PA25 : input/output (USB DP) PA24 : input/output (USB DM) @@ -60,7 +61,9 @@ The application board shall avoid driving the PA25, PA24, PB23 and PB22 signals **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**