├── .gitignore ├── .gitmodules ├── COPYRIGHT ├── boot.h ├── common ├── util.h ├── board.h ├── timer.c ├── nvm.h ├── analog.c ├── sercom.c ├── clock.c ├── dma.c ├── samd21g18a_firmware_partition.ld ├── hw.h └── startup_samd21.c ├── my_customizations.c ├── LICENSE-MIT ├── Readme.md ├── Makefile ├── main.c ├── link-script.ld ├── usb.c └── LICENSE-APACHE /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .tags 3 | 4 | # targets 5 | dafu.elf 6 | dafu.hex 7 | dafu.bin 8 | dafu.sym 9 | dafu.lss 10 | dafu.o 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/usb"] 2 | path = deps/usb 3 | url = https://github.com/opendime/USB-XMEGA.git 4 | [submodule "deps/sam0"] 5 | path = deps/sam0 6 | url = https://github.com/avrxml/sam0.git 7 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Portions (c) 2015 Copyright by Coinkite Inc for Opendime project. 2 | 3 | Portions 2015 copyright by Technical Machine, Inc. 4 | 5 | Licensed under the Apache License, Version 2.0 6 | or the MIT 8 | license , 9 | at your option. Files in the project may not be copied, 10 | modified, or distributed except according to those terms. 11 | -------------------------------------------------------------------------------- /boot.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Technical Machine, Inc. See the COPYRIGHT 2 | // file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | #pragma once 11 | #include "class/dfu/dfu.h" 12 | 13 | #include "common/board.h" 14 | 15 | #define GCLK_SYSTEM 0 16 | #define DFU_INTF 0 17 | #define DFU_TRANSFER_SIZE (FLASH_PAGE_SIZE * 4) 18 | -------------------------------------------------------------------------------- /common/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | typedef uint8_t u8; 6 | typedef uint16_t u16; 7 | typedef uint32_t u32; 8 | 9 | typedef uint8_t DmaChan; 10 | typedef uint8_t SercomId; 11 | typedef uint8_t TimerId; 12 | typedef struct Pin { 13 | u8 mux; 14 | u8 group; 15 | u8 pin; 16 | u8 chan; 17 | } Pin; 18 | 19 | #define SERCOM_HANDLER_(ID) SERCOM ## ID ## _Handler() 20 | #define SERCOM_HANDLER(ID) SERCOM_HANDLER_(ID) 21 | 22 | #define TC_HANDLER_(ID) TC ## ID ## _Handler() 23 | #define TC_HANDLER(ID) TC_HANDLER_(ID) 24 | 25 | #define TCC_HANDLER_(ID) TCC ## ID ## _Handler() 26 | #define TCC_HANDLER(ID) TCC_HANDLER_(ID) 27 | 28 | inline static void invalid() { 29 | __asm__("bkpt"); 30 | } 31 | -------------------------------------------------------------------------------- /common/board.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common/util.h" 3 | #include "common/hw.h" 4 | 5 | // Memory Layout 6 | // - first 4k reserved for DAFU Bootloader 7 | // - remainder of flash for main firmware 8 | // 9 | #define FLASH_BOOT_START 0 10 | #define FLASH_BOOT_SIZE 4096 11 | 12 | // Calcuated at runtime, based on chip's report of it's size. 13 | extern uint32_t total_flash_size; 14 | 15 | #define FLASH_FW_START FLASH_BOOT_SIZE 16 | #define FLASH_FW_SIZE (total_flash_size - FLASH_BOOT_SIZE) 17 | 18 | #define FLASH_BOOT_ADDR FLASH_BOOT_START 19 | #define FLASH_FW_ADDR FLASH_FW_START 20 | 21 | #define BOOT_MAGIC 0 22 | 23 | // USB pins 24 | const static Pin PIN_USB_DM = {.group = 0, .pin = 24, .mux = MUX_PA24G_USB_DM }; 25 | const static Pin PIN_USB_DP = {.group = 0, .pin = 25, .mux = MUX_PA25G_USB_DP }; 26 | 27 | -------------------------------------------------------------------------------- /my_customizations.c: -------------------------------------------------------------------------------- 1 | // Board customization. 2 | // 3 | // Enable any of these function if you need more or different setup code. 4 | // Placeholder version of same functions already weak-linked. 5 | // 6 | #include 7 | 8 | #if 0 9 | void board_setup_early(void) 10 | { 11 | // called immediately once we decide to go the DFU route 12 | volatile int a = 34; 13 | } 14 | #endif 15 | 16 | #if 0 17 | void board_setup_late(void) 18 | { 19 | // called after NVM and some other chip modules are init'ed 20 | } 21 | #endif 22 | 23 | #if 0 24 | void board_reset_cleanup(void) 25 | { 26 | // called after DFU has been loaded and we're going to run 27 | // the new firmware; might undo various setup that was in place. 28 | } 29 | #endif 30 | 31 | #if 0 32 | bool button_pressed(void) 33 | { 34 | // Return T to do DFU rather than run normal firmware. 35 | return false; 36 | } 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /common/timer.c: -------------------------------------------------------------------------------- 1 | #include "common/hw.h" 2 | 3 | void timer_clock_enable(TimerId id) { 4 | PM->APBCMASK.reg |= 1 << (PM_APBCMASK_TCC0_Pos + id); 5 | 6 | GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | 7 | GCLK_CLKCTRL_GEN(0) | 8 | GCLK_CLKCTRL_ID(TCC0_GCLK_ID + id/2); 9 | } 10 | 11 | // Starts timer countdown 12 | void tcc_delay_start(TimerId id, u32 ticks) { 13 | tcc(id)->PER.reg = ticks; 14 | tcc(id)->CTRLBSET.reg = TCC_CTRLBSET_CMD_RETRIGGER; 15 | } 16 | 17 | // disables timer delay 18 | void tcc_delay_disable(TimerId id) { 19 | tcc(id)->INTENCLR.reg = TC_INTENSET_OVF; 20 | tcc(id)->CTRLA.bit.ENABLE = 0; 21 | } 22 | 23 | // sets up a timer to count down in one-shot mode. 24 | void tcc_delay_enable(TimerId id) { 25 | timer_clock_enable(id); 26 | 27 | tcc(id)->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV256; 28 | tcc(id)->CTRLBSET.reg = TCC_CTRLBSET_DIR | TCC_CTRLBSET_ONESHOT; 29 | 30 | while (tcc(id)->SYNCBUSY.reg > 0); 31 | 32 | tcc(id)->CTRLA.bit.ENABLE = 1; 33 | tcc(id)->INTENSET.reg = TCC_INTENSET_OVF; 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Coinkite, Inc 2 | Copyright (c) 2015 Technical Machine, Inc 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /common/nvm.h: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #define NVM_MEMORY ((volatile uint16_t *)FLASH_ADDR) 4 | 5 | uint32_t nvm_flash_size() { 6 | return NVMCTRL->PARAM.bit.NVMP*FLASH_PAGE_SIZE; 7 | } 8 | 9 | void nvm_init() { 10 | NVMCTRL->CTRLB.bit.MANW = 1; 11 | } 12 | 13 | void nvm_address(uint32_t addr) { 14 | NVMCTRL->ADDR.reg = addr >> 1; 15 | } 16 | 17 | void nvm_wait() { 18 | while (!NVMCTRL->INTFLAG.bit.READY); 19 | } 20 | 21 | void nvm_command(uint32_t command) { 22 | NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD(command); 23 | nvm_wait(); 24 | } 25 | 26 | void nvm_erase_row(uint32_t addr) { 27 | nvm_address(addr); 28 | nvm_command(NVMCTRL_CTRLA_CMD_ER); 29 | } 30 | 31 | void nvm_write_page(uint32_t addr, uint8_t* buf, uint8_t len) { 32 | uint32_t nvm_addr = addr/2; 33 | 34 | // NVM must be accessed as a series of 16-bit words 35 | for (uint16_t i = 0; i < len; i += 2) { 36 | uint16_t data = buf[i]; 37 | if (i < (len - 1)) data |= (buf[i + 1] << 8); 38 | 39 | NVM_MEMORY[nvm_addr++] = data; 40 | } 41 | 42 | /* Perform a manual NVM write when the length of data to be programmed is 43 | * less than page size */ 44 | nvm_command(NVMCTRL_CTRLA_CMD_WP); 45 | } 46 | 47 | void nvm_invalidate_cache() { 48 | nvm_command(NVMCTRL_CTRLA_CMD_INVALL); 49 | } 50 | -------------------------------------------------------------------------------- /common/analog.c: -------------------------------------------------------------------------------- 1 | #include "hw.h" 2 | 3 | void adc_init(u8 channel, u8 refctrl) { 4 | // set up clock 5 | PM->APBCMASK.reg |= PM_APBCMASK_ADC; 6 | 7 | // divide prescaler by 512 (93.75KHz), max adc freq is 2.1MHz 8 | ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV512; 9 | 10 | // enable clock adc channel 11 | GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | 12 | GCLK_CLKCTRL_GEN(channel) | 13 | GCLK_CLKCTRL_ID(ADC_GCLK_ID); 14 | 15 | ADC->CALIB.reg = 16 | ADC_CALIB_BIAS_CAL( 17 | (*(uint32_t *)ADC_FUSES_BIASCAL_ADDR >> ADC_FUSES_BIASCAL_Pos) 18 | ) | 19 | ADC_CALIB_LINEARITY_CAL( 20 | (*(uint64_t *)ADC_FUSES_LINEARITY_0_ADDR >> ADC_FUSES_LINEARITY_0_Pos) 21 | ); 22 | 23 | ADC->REFCTRL.reg = refctrl; 24 | 25 | ADC->CTRLA.reg = ADC_CTRLA_ENABLE; // enable 26 | while(ADC->STATUS.reg & ADC_STATUS_SYNCBUSY); 27 | } 28 | 29 | u16 adc_sample() { 30 | ADC->SWTRIG.reg = ADC_SWTRIG_START; 31 | while(!(ADC->INTFLAG.reg & ADC_INTFLAG_RESRDY)); // wait until result is ready 32 | return ADC->RESULT.reg; 33 | } 34 | 35 | u16 adc_read(Pin p, u32 gain) { 36 | // switch pin mux to analog in 37 | pin_analog(p); 38 | 39 | ADC->INPUTCTRL.reg = (ADC_INPUTCTRL_MUXPOS(p.chan) // select from proper pin 40 | | ADC_INPUTCTRL_MUXNEG_GND // 0 = gnd 41 | | gain); 42 | 43 | return adc_sample(); 44 | } 45 | 46 | void dac_init(u8 channel) { 47 | // hook up clk 48 | PM->APBCMASK.reg |= PM_APBCMASK_DAC; 49 | GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | 50 | GCLK_CLKCTRL_GEN(channel) | 51 | GCLK_CLKCTRL_ID(DAC_GCLK_ID); 52 | } 53 | 54 | void dac_write(Pin p, u16 val) { 55 | // switch dac pinmux. this must be PA02 56 | pin_analog(p); 57 | 58 | // disable 59 | DAC->CTRLA.reg &= ~DAC_CTRLA_ENABLE; 60 | 61 | // set vcc as reference voltage 62 | DAC->CTRLB.reg = DAC_CTRLB_EOEN |DAC_CTRLB_REFSEL_AVCC; 63 | 64 | // enable 65 | DAC->CTRLA.reg = DAC_CTRLA_ENABLE; 66 | 67 | DAC->DATA.reg = val; 68 | } 69 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # DAFU Boot 3 | ## DFU Bootloader for Atmel ARM parts 4 | _for at least the Atmel SAM D21 and similar_ 5 | 6 | Based on [t2-firmware/boot/](https://github.com/tessel/t2-firmware) 7 | 8 | Compatible with [DFU Utils](http://dfu-util.sourceforge.net/) 9 | 10 | ## Background 11 | 12 | This is 4k of binary code that will turn a typical D21 board into a DFU target. 13 | It makes as few assumptions as possible about the other hardware on the board, 14 | but it could be customized if needed. 15 | 16 | ### Project Goals 17 | 18 | - generalized so can run on any D21 (and maybe others) ideally without pre-configuration 19 | - make it easy to rebrand and/or be generic 20 | - minimalist and self-contained Makefile 21 | - make it easy to link into other projects as a linkable object 22 | - compile-time option for a secure mode that blocks any reads 23 | - support pre and post boot customization options 24 | - stay under 4k and open-source 25 | 26 | 27 | ## Installation 28 | 29 | Requirements: 30 | 31 | - GCC for ARM toolchain. This is expected to be installed with prefix "arm-none-eabi-" 32 | - gnu make 33 | 34 | Steps: 35 | 36 | Get the submodules. This will populate `deps/sam0` and `deps/usb` 37 | 38 | git submodule init 39 | git submodule update 40 | 41 | To build, run make: 42 | 43 | make 44 | 45 | Main binaries will be in these files: 46 | 47 | dafu.elf 48 | dafu.bin 49 | 50 | Other useful files: 51 | 52 | dafu.lss - Detailed listing 53 | dafu.hex - Intel-format hex file 54 | dafu.o - See next section 55 | 56 | ## Usage 57 | 58 | If there seems to be a valid program in flash at 0x1000, this code will run it. That's 59 | the normal boot sequence in the field. If your mainline code resets because of the watchdog 60 | timeout, the DAFU code will start instead. Once DAFU is running, then you should see 61 | a USB device enumerated with the PID/VID values from the Makefile. 62 | 63 | Install your code via this command: 64 | 65 | dfu-util -aFlash -D foo.bin 66 | 67 | Your binary should start at memory address 0x1000 (4k) and the first few words 68 | should be the reset vector that points to your mainline code. In other words, if 69 | DAFU is normally pre-pended to your code, you should remove it before uploading with 70 | DFU util. 71 | 72 | ## Linked Object File (dafu.o) 73 | 74 | You can include the `dafu.o` object file into your main project Makefile. 75 | 76 | If you're using the standard linker scripts that Atmel provides, 77 | and you list this object file before others in the link step, it 78 | should end up positioned at offset zero. Because it's 4k (0x1000) 79 | in size, your normal exception table (interrupt vector table) will 80 | start at 0x1000 which is where it needs to be. The linker will 81 | adjust your code to be at 0x4000. 82 | 83 | This relies on a section called ".vectors" being hardcoded to the 84 | start of flash memory. 85 | 86 | You can also just load the DAFU binary at offset zero (by any means), 87 | and link your main program to load and run at 0x1000. 88 | 89 | # Todo List 90 | 91 | - check that DFU cannot write to "NVM User Row" 92 | 93 | 94 | -------------------------------------------------------------------------------- /common/sercom.c: -------------------------------------------------------------------------------- 1 | #include "common/hw.h" 2 | 3 | void sercom_clock_enable(SercomId id, uint32_t clock_channel, u8 divider) { 4 | // prevent this clock write from changing any other clocks 5 | PM->APBCMASK.reg |= 1 << (PM_APBCMASK_SERCOM0_Pos + id); 6 | 7 | if (clock_channel != 0) { 8 | // clock generators 3-8 have 8 division factor bits - DIV[7:0] 9 | gclk_enable(clock_channel, GCLK_SOURCE_DFLL48M, divider); 10 | } 11 | 12 | // attach clock 13 | GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | 14 | GCLK_CLKCTRL_GEN(clock_channel) | 15 | GCLK_CLKCTRL_ID(SERCOM0_GCLK_ID_CORE + id); 16 | } 17 | 18 | inline void sercom_reset(SercomId id) { 19 | sercom(id)->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_SWRST; 20 | while(sercom(id)->SPI.CTRLA.reg & SERCOM_SPI_CTRLA_SWRST); 21 | } 22 | 23 | void sercom_spi_slave_init(SercomId id, u32 dipo, u32 dopo, bool cpol, bool cpha) { 24 | sercom_reset(id); 25 | sercom(id)->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE_SPI_SLAVE; 26 | 27 | sercom(id)->SPI.CTRLB.reg 28 | = SERCOM_SPI_CTRLB_RXEN 29 | | SERCOM_SPI_CTRLB_SSDE 30 | | SERCOM_SPI_CTRLB_PLOADEN; 31 | 32 | sercom(id)->SPI.CTRLA.reg 33 | = SERCOM_SPI_CTRLA_ENABLE 34 | | SERCOM_SPI_CTRLA_MODE_SPI_SLAVE 35 | | SERCOM_SPI_CTRLA_DIPO(dipo) 36 | | SERCOM_SPI_CTRLA_DOPO(dopo) 37 | | (cpol ? SERCOM_SPI_CTRLA_CPOL : 0) 38 | | (cpha ? SERCOM_SPI_CTRLA_CPHA : 0); 39 | } 40 | 41 | void sercom_spi_master_init(SercomId id, u32 dipo, u32 dopo, bool cpol, bool cpha, u8 baud) { 42 | sercom_reset(id); 43 | sercom(id)->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE_SPI_MASTER; 44 | 45 | sercom(id)->SPI.CTRLB.reg 46 | = SERCOM_SPI_CTRLB_RXEN 47 | | SERCOM_SPI_CTRLB_SSDE; 48 | 49 | sercom(id)->SPI.BAUD.reg = baud; 50 | 51 | sercom(id)->SPI.CTRLA.reg 52 | = SERCOM_SPI_CTRLA_ENABLE 53 | | SERCOM_SPI_CTRLA_MODE_SPI_MASTER 54 | | SERCOM_SPI_CTRLA_DIPO(dipo) 55 | | SERCOM_SPI_CTRLA_DOPO(dopo) 56 | | (cpol ? SERCOM_SPI_CTRLA_CPOL : 0) 57 | | (cpha ? SERCOM_SPI_CTRLA_CPHA : 0); 58 | 59 | } 60 | 61 | void sercom_i2c_master_init(SercomId id, u8 baud) { 62 | sercom_reset(id); 63 | sercom(id)->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_MODE_I2C_MASTER; 64 | sercom(id)->I2CM.BAUD.reg = baud; 65 | sercom(id)->I2CM.CTRLA.reg 66 | = SERCOM_I2CM_CTRLA_ENABLE 67 | | SERCOM_I2CM_CTRLA_MODE_I2C_MASTER; 68 | sercom(id)->I2CM.STATUS.reg = SERCOM_I2CM_STATUS_BUSSTATE(1); 69 | } 70 | 71 | void sercom_uart_init(SercomId id, u32 rxpo, u32 txpo, u32 baud) { 72 | sercom_reset(id); 73 | sercom(id)->USART.CTRLA.reg = SERCOM_USART_CTRLA_MODE_USART_INT_CLK; 74 | sercom(id)->USART.BAUD.reg = baud; 75 | sercom(id)->USART.CTRLB.reg 76 | = SERCOM_USART_CTRLB_RXEN 77 | | SERCOM_USART_CTRLB_TXEN; 78 | sercom(id)->USART.CTRLA.reg 79 | = SERCOM_USART_CTRLA_ENABLE 80 | | SERCOM_USART_CTRLA_MODE_USART_INT_CLK 81 | | SERCOM_SPI_CTRLA_DORD 82 | | SERCOM_USART_CTRLA_TXPO(txpo) 83 | | SERCOM_USART_CTRLA_RXPO(rxpo); 84 | } 85 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # DAFU Makefile 3 | # 4 | # Targets: 5 | # all - make everything, look for dafu.elf inparticular 6 | # clean - delete intermediates 7 | # clobber - delete all build products 8 | # 9 | # 10 | # 11 | 12 | # Toolchain 13 | CC = arm-none-eabi-gcc 14 | OBJDUMP = arm-none-eabi-objdump 15 | OBJCOPY = arm-none-eabi-objcopy 16 | NM = arm-none-eabi-nm 17 | SIZE = arm-none-eabi-size 18 | 19 | # Basename of targets 20 | TARGET_NAME = dafu 21 | 22 | # Hardware configuration. Not so critical. I suspect binary would not change 23 | # for any value here in the D21 family. 24 | PART = SAMD21J18A 25 | 26 | # Compiler flags. 27 | CFLAGS = -Wall --std=gnu99 -Os -g3 \ 28 | -flto -fdata-sections -ffunction-sections -funsigned-char -funsigned-bitfields \ 29 | -mcpu=cortex-m0plus -mthumb -D __$(PART)__ -I . 30 | 31 | # USB PID/VID and other branding values 32 | CFLAGS += \ 33 | -D USB_PRODUCT_ID=0x7551 \ 34 | -D USB_VENDOR_ID=0x1209 \ 35 | -D USB_MANUFACTURER_STR='"Nobody"' \ 36 | -D USB_PRODUCT_STR='"DAFU Bootloader"' \ 37 | -D COPYRIGHT_NOTE='"Visit https://githib.com/opendime/DAFU"' \ 38 | -D USE_CORE_RESET 39 | 40 | # Header file search path 41 | PRJ_PATH = deps 42 | INC_PATHS = \ 43 | usb \ 44 | sam0/cmsis \ 45 | sam0/include \ 46 | sam0/cmsis/samd21/include \ 47 | sam0/cmsis/samd21/source 48 | 49 | CFLAGS += $(foreach INC,$(addprefix $(PRJ_PATH)/,$(INC_PATHS)),-I$(INC)) 50 | 51 | # Specialized linker-script here. Not the standard one! 52 | # 53 | LINKER_SCRIPT = link-script.ld 54 | 55 | LDFLAGS += -flto -Wl,--gc-sections --specs=nano.specs -Wl,-T$(LINKER_SCRIPT) 56 | 57 | C_SRCS = \ 58 | common/startup_samd21.c \ 59 | main.c \ 60 | usb.c \ 61 | common/clock.c \ 62 | my_customizations.c \ 63 | deps/usb/class/dfu/dfu.c \ 64 | deps/usb/samd/usb_samd.c \ 65 | deps/usb/usb_requests.c 66 | 67 | OBJS = $(addsuffix .o, $(basename $(C_SRCS) $(ASM_SRCS))) 68 | 69 | TARGET_ELF = $(TARGET_NAME).elf 70 | TARGETS = $(TARGET_NAME).hex $(TARGET_NAME).lss $(TARGET_NAME).bin $(TARGET_NAME).sym $(TARGET_NAME).o 71 | 72 | all: $(TARGETS) 73 | 74 | # recompile on any change, because with a small project like this... 75 | $(OBJS): Makefile $(C_SRCS) $(ASM_SRCS) 76 | 77 | $(TARGETS): $(TARGET_ELF) Makefile 78 | 79 | # link step 80 | $(TARGET_ELF): $(OBJS) $(LINKER_SCRIPT) Makefile 81 | $(CC) $(CFLAGS) -o $(TARGET_ELF) $(LDFLAGS) $(OBJS) 82 | $(SIZE) -Ax $@ 83 | 84 | # detailed listing, very handy 85 | %.lss: $(TARGET_ELF) 86 | $(OBJDUMP) -h -S $< > $@ 87 | 88 | # symbol dump, meh 89 | %.sym: $(TARGET_ELF) 90 | $(NM) -n $< > $@ 91 | 92 | # intel HEX format 93 | %.hex: $(TARGET_ELF) 94 | $(OBJCOPY) -O ihex $< $@ 95 | 96 | # raw binary 97 | %.bin: $(TARGET_ELF) 98 | $(OBJCOPY) -O binary $< $@ 99 | 100 | # a binary of just the ROM area, ready to be linked into another program. 101 | $(TARGET_NAME).o: $(TARGET_ELF) 102 | $(OBJCOPY) --rename-section .text=.vectors.bootloader \ 103 | --prefix-symbols=dafu_ \ 104 | --pad-to 0x1000 --gap-fill 0xff \ 105 | $(TARGET_ELF) $@ 106 | $(OBJDUMP) -h $@ 107 | $(SIZE) -Ax $@ 108 | 109 | clean: 110 | $(RM) $(OBJS) 111 | 112 | clobber: clean 113 | $(RM) $(TARGETS) 114 | 115 | debug: 116 | @echo CFLAGS = $(CFLAGS) 117 | @echo 118 | @echo C_SRCS = $(C_SRCS) 119 | @echo 120 | @echo OBJS = $(OBJS) 121 | 122 | tags: 123 | ctags -f .tags *.[ch] -R deps/sam0 deps/usb common 124 | -------------------------------------------------------------------------------- /common/clock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common/hw.h" 3 | 4 | #define NVM_DFLL_COARSE_POS 58 5 | #define NVM_DFLL_COARSE_SIZE 6 6 | #define NVM_DFLL_FINE_POS 64 7 | #define NVM_DFLL_FINE_SIZE 10 8 | 9 | uint32_t dfll_nvm_val() { 10 | uint32_t coarse = ( *((uint32_t *)(NVMCTRL_OTP4) 11 | + (NVM_DFLL_COARSE_POS / 32)) 12 | >> (NVM_DFLL_COARSE_POS % 32)) 13 | & ((1 << NVM_DFLL_COARSE_SIZE) - 1); 14 | if (coarse == 0x3f) { 15 | coarse = 0x1f; 16 | } 17 | uint32_t fine = ( *((uint32_t *)(NVMCTRL_OTP4) 18 | + (NVM_DFLL_FINE_POS / 32)) 19 | >> (NVM_DFLL_FINE_POS % 32)) 20 | & ((1 << NVM_DFLL_FINE_SIZE) - 1); 21 | if (fine == 0x3ff) { 22 | fine = 0x1ff; 23 | } 24 | 25 | return SYSCTRL_DFLLVAL_COARSE(coarse) | SYSCTRL_DFLLVAL_FINE(fine); 26 | } 27 | 28 | void dfll_wait_for_sync() { 29 | while (!SYSCTRL->PCLKSR.bit.DFLLRDY); 30 | } 31 | 32 | void gclk_enable(uint32_t id, uint32_t src, uint32_t div) { 33 | GCLK->GENDIV.reg = GCLK_GENDIV_ID(id) | GCLK_GENDIV_DIV(div); 34 | GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(id) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC(src); 35 | } 36 | 37 | void gclk_init() { 38 | // Various bits in the INTFLAG register can be set to one at startup. 39 | SYSCTRL->INTFLAG.reg = SYSCTRL_INTFLAG_BOD33RDY | SYSCTRL_INTFLAG_BOD33DET | 40 | SYSCTRL_INTFLAG_DFLLRDY; 41 | 42 | NVMCTRL->CTRLB.bit.RWS = 2; 43 | 44 | // Initialize GCLK 45 | PM->APBAMASK.reg |= PM_APBAMASK_GCLK; 46 | GCLK->CTRL.reg = GCLK_CTRL_SWRST; 47 | while (GCLK->CTRL.reg & GCLK_CTRL_SWRST); 48 | 49 | // SERCOM slow clock (Shared by all SERCOM) 50 | GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | 51 | GCLK_CLKCTRL_GEN(0) | 52 | GCLK_CLKCTRL_ID(SERCOM0_GCLK_ID_SLOW); 53 | } 54 | 55 | // Configure DFLL in USB recovery mode 56 | const uint32_t dfll_ctrl_usb 57 | = SYSCTRL_DFLLCTRL_ENABLE 58 | | SYSCTRL_DFLLCTRL_CCDIS 59 | | SYSCTRL_DFLLCTRL_BPLCKC 60 | | SYSCTRL_DFLLCTRL_USBCRM 61 | | SYSCTRL_DFLLCTRL_ONDEMAND; 62 | 63 | void clock_init_usb(u8 clk_system) { 64 | gclk_init(); 65 | 66 | // Disable ONDEMAND mode while writing configurations (errata 9905) 67 | SYSCTRL->DFLLCTRL.reg = dfll_ctrl_usb & ~SYSCTRL_DFLLCTRL_ONDEMAND; 68 | dfll_wait_for_sync(); 69 | SYSCTRL->DFLLVAL.reg = dfll_nvm_val(); 70 | dfll_wait_for_sync(); 71 | SYSCTRL->DFLLCTRL.reg = dfll_ctrl_usb; 72 | 73 | gclk_enable(clk_system, GCLK_SOURCE_DFLL48M, 1); 74 | while (GCLK->STATUS.bit.SYNCBUSY); 75 | } 76 | 77 | void clock_init_crystal(u8 clk_system, u8 clk_32k) { 78 | gclk_init(); 79 | 80 | SYSCTRL->XOSC32K.reg 81 | = SYSCTRL_XOSC32K_ENABLE 82 | | SYSCTRL_XOSC32K_XTALEN 83 | | SYSCTRL_XOSC32K_EN32K 84 | | SYSCTRL_XOSC32K_AAMPEN 85 | | SYSCTRL_XOSC32K_RUNSTDBY; 86 | 87 | gclk_enable(clk_32k, GCLK_SOURCE_XOSC32K, 1); 88 | 89 | GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | 90 | GCLK_CLKCTRL_GEN(clk_32k) | 91 | GCLK_CLKCTRL_ID(SYSCTRL_GCLK_ID_DFLL48); 92 | 93 | SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE; 94 | dfll_wait_for_sync(); 95 | SYSCTRL->DFLLVAL.reg = dfll_nvm_val(); 96 | dfll_wait_for_sync(); 97 | SYSCTRL->DFLLMUL.reg 98 | = SYSCTRL_DFLLMUL_MUL(1465) // round(48000000 / 32768) 99 | | SYSCTRL_DFLLMUL_CSTEP((0x1f / 4)) 100 | | SYSCTRL_DFLLMUL_FSTEP((0xff / 4)); 101 | dfll_wait_for_sync(); 102 | SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE | SYSCTRL_DFLLCTRL_MODE; 103 | dfll_wait_for_sync(); 104 | SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE | SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_ONDEMAND; 105 | 106 | gclk_enable(clk_system, GCLK_SOURCE_DFLL48M, 1); 107 | while (GCLK->STATUS.bit.SYNCBUSY); 108 | } 109 | -------------------------------------------------------------------------------- /common/dma.c: -------------------------------------------------------------------------------- 1 | #include "common/hw.h" 2 | #include 3 | 4 | DMA_DESC_ALIGN DmacDescriptor dma_descriptors[12]; 5 | DMA_DESC_ALIGN DmacDescriptor dma_descriptors_wb[12]; 6 | 7 | void dma_init() { 8 | memset(&dma_descriptors, 0, sizeof(dma_descriptors)); 9 | memset(&dma_descriptors_wb, 0, sizeof(dma_descriptors_wb)); 10 | 11 | PM->AHBMASK.reg |= PM_AHBMASK_DMAC; 12 | PM->APBBMASK.reg |= PM_APBBMASK_DMAC; 13 | 14 | DMAC->CTRL.bit.DMAENABLE = 0; 15 | DMAC->CTRL.bit.SWRST = 1; 16 | 17 | DMAC->BASEADDR.reg = (unsigned) &dma_descriptors; 18 | DMAC->WRBADDR.reg = (unsigned) &dma_descriptors_wb; 19 | 20 | DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf); 21 | } 22 | 23 | void dma_abort(DmaChan chan) { 24 | DMAC->CHID.reg = chan; 25 | DMAC->CHCTRLA.reg = 0; 26 | } 27 | 28 | u32 dma_remaining(DmaChan chan) { 29 | return dma_descriptors_wb[chan].BTCNT.reg; 30 | } 31 | 32 | const u8 dummy_tx = 0x99; 33 | void dma_fill_sercom_tx(DmacDescriptor* desc, SercomId id, u8 *src, unsigned size) { 34 | // doesn't matter if this is SPI.DATA or USART.DATA. both are in the same address 35 | desc->DSTADDR.reg = (unsigned) &sercom(id)->SPI.DATA; 36 | desc->BTCNT.reg = size; 37 | if (src != NULL) { 38 | desc->SRCADDR.reg = (unsigned) src + size; 39 | desc->BTCTRL.reg = DMAC_BTCTRL_VALID | DMAC_BTCTRL_SRCINC; 40 | } else { 41 | desc->SRCADDR.reg = (unsigned) &dummy_tx; 42 | desc->BTCTRL.reg = DMAC_BTCTRL_VALID; 43 | } 44 | } 45 | 46 | 47 | u8 dummy_rx = 0; 48 | void dma_fill_sercom_rx(DmacDescriptor* desc, SercomId id, u8 *dst, unsigned size) { 49 | // doesn't matter if this is SPI.DATA or USART.DATA. both are in the same address 50 | desc->SRCADDR.reg = (unsigned) &sercom(id)->SPI.DATA; 51 | desc->BTCNT.reg = size; 52 | if (dst != NULL) { 53 | desc->DSTADDR.reg = (unsigned) dst + size; 54 | desc->BTCTRL.reg = DMAC_BTCTRL_VALID | DMAC_BTCTRL_DSTINC | DMAC_BTCTRL_EVOSEL_BEAT; 55 | } else { 56 | desc->DSTADDR.reg = (unsigned) &dummy_rx; 57 | desc->BTCTRL.reg = DMAC_BTCTRL_VALID; 58 | } 59 | } 60 | 61 | void dma_sercom_configure_tx(DmaChan chan, SercomId id) { 62 | DMAC->CHID.reg = chan; 63 | DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST; 64 | DMAC->CHCTRLB.reg = DMAC_CHCTRLB_TRIGACT_BEAT | DMAC_CHCTRLB_TRIGSRC(id*2 + 2); 65 | } 66 | 67 | void dma_sercom_configure_rx(DmaChan chan, SercomId id) { 68 | DMAC->CHID.reg = chan; 69 | DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST; 70 | DMAC->CHCTRLB.reg = DMAC_CHCTRLB_TRIGACT_BEAT | DMAC_CHCTRLB_TRIGSRC(id*2 + 1); 71 | } 72 | 73 | void dma_link_chain(DmacDescriptor* chain, u32 count) { 74 | for (u32 i = 0; iCHID.reg = chan; 82 | DMAC->CHCTRLA.reg = 0; 83 | memcpy(&dma_descriptors[chan], &chain[0], sizeof(DmacDescriptor)); 84 | DMAC->CHCTRLA.reg = DMAC_CHCTRLA_ENABLE; 85 | } 86 | 87 | void dma_sercom_start_tx(DmaChan chan, SercomId id, u8* src, unsigned size) { 88 | DMAC->CHID.reg = chan; 89 | DMAC->CHCTRLA.reg = 0; 90 | dma_fill_sercom_tx(&dma_descriptors[chan], id, src, size); 91 | dma_descriptors[chan].DESCADDR.reg = 0; 92 | DMAC->CHCTRLA.reg = DMAC_CHCTRLA_ENABLE; 93 | } 94 | 95 | void dma_sercom_start_rx(DmaChan chan, SercomId id, u8* dst, unsigned size) { 96 | DMAC->CHID.reg = chan; 97 | DMAC->CHCTRLA.reg = 0; 98 | dma_fill_sercom_rx(&dma_descriptors[chan], id, dst, size); 99 | dma_descriptors[chan].DESCADDR.reg = 0; 100 | DMAC->CHCTRLA.reg = DMAC_CHCTRLA_ENABLE; 101 | } 102 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Technical Machine, Inc. See the COPYRIGHT 2 | // file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | #include "common/util.h" 11 | #include "samd/usb_samd.h" 12 | 13 | #include 14 | #include 15 | 16 | #include "boot.h" 17 | #include "common/nvm.h" 18 | 19 | __attribute__ ((section(".copyright"))) 20 | __attribute__ ((used)) 21 | const char copyright_note[] = COPYRIGHT_NOTE; 22 | 23 | volatile bool exit_and_jump = 0; 24 | 25 | // set at runtime 26 | uint32_t total_flash_size; 27 | 28 | // Board customization. You may define these functions in another file 29 | // and that new code will replace the stubs defined here. 30 | void board_setup_early(void) __attribute__((weak, alias("noopFunction"))); 31 | void board_setup_late(void) __attribute__((weak, alias("noopFunction"))); 32 | void board_reset_cleanup(void) __attribute__((weak, alias("noopFunction"))); 33 | bool button_pressed(void) __attribute__((weak)); 34 | 35 | 36 | /*** SysTick ***/ 37 | 38 | volatile uint32_t g_msTicks; 39 | 40 | /* SysTick IRQ handler */ 41 | void SysTick_Handler(void) { 42 | g_msTicks++; 43 | } 44 | 45 | void delay_ms(unsigned ms) { 46 | unsigned start = g_msTicks; 47 | while (g_msTicks - start <= ms) { 48 | __WFI(); 49 | } 50 | } 51 | 52 | void init_systick(void) { 53 | if (SysTick_Config(48000000 / 1000)) { /* Setup SysTick Timer for 1 msec interrupts */ 54 | while (1) {} /* Capture error */ 55 | } 56 | NVIC_SetPriority(SysTick_IRQn, 0x0); 57 | g_msTicks = 0; 58 | } 59 | 60 | /*** USB / DFU ***/ 61 | 62 | void dfu_cb_dnload_block(uint16_t block_num, uint16_t len) { 63 | if (usb_setup.wLength > DFU_TRANSFER_SIZE) { 64 | dfu_error(DFU_STATUS_errUNKNOWN); 65 | return; 66 | } 67 | 68 | if (block_num * DFU_TRANSFER_SIZE > FLASH_FW_SIZE) { 69 | dfu_error(DFU_STATUS_errADDRESS); 70 | return; 71 | } 72 | 73 | nvm_erase_row(FLASH_FW_START + block_num * DFU_TRANSFER_SIZE); 74 | } 75 | 76 | void dfu_cb_dnload_packet_completed(uint16_t block_num, uint16_t offset, uint8_t* data, uint16_t length) { 77 | unsigned addr = FLASH_FW_START + block_num * DFU_TRANSFER_SIZE + offset; 78 | nvm_write_page(addr, data, length); 79 | } 80 | 81 | unsigned dfu_cb_dnload_block_completed(uint16_t block_num, uint16_t length) { 82 | return 0; 83 | } 84 | 85 | void dfu_cb_manifest(void) { 86 | exit_and_jump = 1; 87 | } 88 | 89 | void noopFunction(void) 90 | { 91 | // Placeholder function for code that isn't needed. Keep empty! 92 | } 93 | 94 | static void hardware_detect(void) 95 | { 96 | // what kind of chip are we installed on? 97 | // .. don't care 98 | 99 | // how big is the flash tho 100 | uint16_t page_size = 1 << (NVMCTRL->PARAM.bit.PSZ + 3); 101 | 102 | total_flash_size = NVMCTRL->PARAM.bit.NVMP * page_size; 103 | } 104 | 105 | void bootloader_main(void) 106 | { 107 | // Hook here for very early hardware init that some boards need 108 | board_setup_early(); 109 | 110 | hardware_detect(); 111 | 112 | clock_init_usb(GCLK_SYSTEM); 113 | init_systick(); 114 | nvm_init(); 115 | 116 | // Hook here for "early" hardware init that some boards need 117 | board_setup_late(); 118 | 119 | __enable_irq(); 120 | 121 | pin_mux(PIN_USB_DM); 122 | pin_mux(PIN_USB_DP); 123 | usb_init(); 124 | usb_attach(); 125 | 126 | while(!exit_and_jump) { 127 | __WFI(); /* conserve power */ 128 | } 129 | 130 | delay_ms(25); 131 | 132 | usb_detach(); 133 | nvm_invalidate_cache(); 134 | 135 | delay_ms(100); 136 | 137 | // Hook: undo any special setup that board_setup_late might be needed to 138 | // undo the setup the bootloader code has done. 139 | board_reset_cleanup(); 140 | 141 | #ifdef USE_CORE_RESET 142 | jump_to_flash(FLASH_FW_ADDR, 0); 143 | #elif 144 | NVIC_SystemReset(); 145 | #endif 146 | } 147 | 148 | bool flash_valid() { 149 | unsigned sp = ((unsigned *)FLASH_FW_ADDR)[0]; 150 | unsigned ip = ((unsigned *)FLASH_FW_ADDR)[1]; 151 | 152 | return sp > 0x20000000 153 | && ip >= 0x00001000 154 | && ip < 0x00400000; 155 | } 156 | 157 | 158 | bool button_pressed(void) 159 | { 160 | // Repalce this function (in another file) if you want to 161 | // test for a pin or button being pressed during boot time 162 | // to get into DFU mode. 163 | return false; 164 | } 165 | 166 | bool bootloader_sw_triggered(void) 167 | { 168 | // Was reset caused by watchdog timer (WDT)? 169 | return PM->RCAUSE.reg & PM_RCAUSE_WDT; 170 | } 171 | 172 | void main_bl(void) { 173 | if (!flash_valid() || button_pressed() || bootloader_sw_triggered()) { 174 | bootloader_main(); 175 | } 176 | 177 | jump_to_flash(FLASH_FW_ADDR, 0); 178 | } 179 | -------------------------------------------------------------------------------- /common/samd21g18a_firmware_partition.ld: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * 4 | * \brief Linker script for running in internal FLASH on the SAMD21G15A 5 | * 6 | * Copyright (c) 2014 Atmel Corporation. All rights reserved. 7 | * 8 | * \asf_license_start 9 | * 10 | * \page License 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * 1. Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * 2. Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * 3. The name of Atmel may not be used to endorse or promote products derived 23 | * from this software without specific prior written permission. 24 | * 25 | * 4. This software may only be redistributed and used in connection with an 26 | * Atmel microcontroller product. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR 32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 | * POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * \asf_license_stop 41 | * 42 | */ 43 | 44 | 45 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 46 | OUTPUT_ARCH(arm) 47 | SEARCH_DIR(.) 48 | 49 | /* Memory Spaces Definitions */ 50 | MEMORY 51 | { 52 | rom (rx) : ORIGIN = 0x00001000, LENGTH = 0x0003efff 53 | ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00001000 54 | } 55 | 56 | /* The stack size used by the application. NOTE: you need to adjust according to your application. */ 57 | STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x200; 58 | 59 | /* Section Definitions */ 60 | SECTIONS 61 | { 62 | .text : 63 | { 64 | . = ALIGN(4); 65 | _sfixed = .; 66 | KEEP(*(.vectors .vectors.*)) 67 | *(.text .text.* .gnu.linkonce.t.*) 68 | *(.glue_7t) *(.glue_7) 69 | *(.rodata .rodata* .gnu.linkonce.r.*) 70 | *(.ARM.extab* .gnu.linkonce.armextab.*) 71 | 72 | /* Support C constructors, and C destructors in both user code 73 | and the C library. This also provides support for C++ code. */ 74 | . = ALIGN(4); 75 | KEEP(*(.init)) 76 | . = ALIGN(4); 77 | __preinit_array_start = .; 78 | KEEP (*(.preinit_array)) 79 | __preinit_array_end = .; 80 | 81 | . = ALIGN(4); 82 | __init_array_start = .; 83 | KEEP (*(SORT(.init_array.*))) 84 | KEEP (*(.init_array)) 85 | __init_array_end = .; 86 | 87 | . = ALIGN(4); 88 | KEEP (*crtbegin.o(.ctors)) 89 | KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) 90 | KEEP (*(SORT(.ctors.*))) 91 | KEEP (*crtend.o(.ctors)) 92 | 93 | . = ALIGN(4); 94 | KEEP(*(.fini)) 95 | 96 | . = ALIGN(4); 97 | __fini_array_start = .; 98 | KEEP (*(.fini_array)) 99 | KEEP (*(SORT(.fini_array.*))) 100 | __fini_array_end = .; 101 | 102 | KEEP (*crtbegin.o(.dtors)) 103 | KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) 104 | KEEP (*(SORT(.dtors.*))) 105 | KEEP (*crtend.o(.dtors)) 106 | 107 | . = ALIGN(4); 108 | _efixed = .; /* End of text section */ 109 | } > rom 110 | 111 | /* .ARM.exidx is sorted, so has to go in its own output section. */ 112 | PROVIDE_HIDDEN (__exidx_start = .); 113 | .ARM.exidx : 114 | { 115 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 116 | } > rom 117 | PROVIDE_HIDDEN (__exidx_end = .); 118 | 119 | . = ALIGN(4); 120 | _etext = .; 121 | 122 | .relocate : AT (_etext) 123 | { 124 | . = ALIGN(4); 125 | _srelocate = .; 126 | *(.ramfunc .ramfunc.*); 127 | *(.data .data.*); 128 | . = ALIGN(4); 129 | _erelocate = .; 130 | } > ram 131 | 132 | /* .bss section which is used for uninitialized data */ 133 | .bss (NOLOAD) : 134 | { 135 | . = ALIGN(4); 136 | _sbss = . ; 137 | _szero = .; 138 | *(.bss .bss.*) 139 | *(COMMON) 140 | . = ALIGN(4); 141 | _ebss = . ; 142 | _ezero = .; 143 | } > ram 144 | 145 | /* stack section */ 146 | .stack (NOLOAD): 147 | { 148 | . = ALIGN(8); 149 | _sstack = .; 150 | . = . + STACK_SIZE; 151 | . = ALIGN(8); 152 | _estack = .; 153 | } > ram 154 | 155 | . = ALIGN(4); 156 | _end = . ; 157 | } 158 | -------------------------------------------------------------------------------- /link-script.ld: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * 4 | * ORIGINALLY Linker script for running in internal FLASH on the SAMD21E15A 5 | * 6 | * BUT NOW: a specialized bootloader linker script: 7 | * - limits itself to first 4k of device. 8 | * - assumes only a small amount of ram is available. 9 | * - tries to work on all devices in the family 10 | * 11 | * Copyright (c) 2014 Atmel Corporation. All rights reserved. 12 | * 13 | * \asf_license_start 14 | * 15 | * \page License 16 | * 17 | * Redistribution and use in source and binary forms, with or without 18 | * modification, are permitted provided that the following conditions are met: 19 | * 20 | * 1. Redistributions of source code must retain the above copyright notice, 21 | * this list of conditions and the following disclaimer. 22 | * 23 | * 2. Redistributions in binary form must reproduce the above copyright notice, 24 | * this list of conditions and the following disclaimer in the documentation 25 | * and/or other materials provided with the distribution. 26 | * 27 | * 3. The name of Atmel may not be used to endorse or promote products derived 28 | * from this software without specific prior written permission. 29 | * 30 | * 4. This software may only be redistributed and used in connection with an 31 | * Atmel microcontroller product. 32 | * 33 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 34 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 35 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 36 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR 37 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 41 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 42 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 43 | * POSSIBILITY OF SUCH DAMAGE. 44 | * 45 | * \asf_license_stop 46 | * 47 | */ 48 | 49 | 50 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 51 | OUTPUT_ARCH(arm) 52 | SEARCH_DIR(.) 53 | 54 | /* Memory Spaces Definitions */ 55 | MEMORY 56 | { 57 | rom (rx) : ORIGIN = 0x00000000, LENGTH = 0x00001000 58 | ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00001000 59 | } 60 | 61 | /* The stack size used by the bootloader. 62 | 63 | When the real app runs the SP will be changed to suit it's needs, so this 64 | value here is set to match the smallest part, so should never need to change here. 65 | */ 66 | STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x400; 67 | 68 | /* Section Definitions */ 69 | SECTIONS 70 | { 71 | .text : 72 | { 73 | . = ALIGN(4); 74 | _sfixed = .; 75 | KEEP(*(.vectors .vectors.*)) 76 | KEEP(*(.copyright)) 77 | *(.text .text.* .gnu.linkonce.t.*) 78 | *(.glue_7t) *(.glue_7) 79 | *(.rodata .rodata* .gnu.linkonce.r.*) 80 | *(.ARM.extab* .gnu.linkonce.armextab.*) 81 | 82 | /* Support C constructors, and C destructors in both user code 83 | and the C library. This also provides support for C++ code. */ 84 | . = ALIGN(4); 85 | KEEP(*(.init)) 86 | . = ALIGN(4); 87 | __preinit_array_start = .; 88 | KEEP (*(.preinit_array)) 89 | __preinit_array_end = .; 90 | 91 | . = ALIGN(4); 92 | __init_array_start = .; 93 | KEEP (*(SORT(.init_array.*))) 94 | KEEP (*(.init_array)) 95 | __init_array_end = .; 96 | 97 | . = ALIGN(4); 98 | KEEP (*crtbegin.o(.ctors)) 99 | KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) 100 | KEEP (*(SORT(.ctors.*))) 101 | KEEP (*crtend.o(.ctors)) 102 | 103 | . = ALIGN(4); 104 | KEEP(*(.fini)) 105 | 106 | . = ALIGN(4); 107 | __fini_array_start = .; 108 | KEEP (*(.fini_array)) 109 | KEEP (*(SORT(.fini_array.*))) 110 | __fini_array_end = .; 111 | 112 | KEEP (*crtbegin.o(.dtors)) 113 | KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) 114 | KEEP (*(SORT(.dtors.*))) 115 | KEEP (*crtend.o(.dtors)) 116 | 117 | . = ALIGN(4); 118 | _efixed = .; /* End of text section */ 119 | } > rom 120 | 121 | /* .ARM.exidx is sorted, so has to go in its own output section. */ 122 | PROVIDE_HIDDEN (__exidx_start = .); 123 | .ARM.exidx : 124 | { 125 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 126 | } > rom 127 | PROVIDE_HIDDEN (__exidx_end = .); 128 | 129 | . = ALIGN(4); 130 | _etext = .; 131 | 132 | .relocate : AT (_etext) 133 | { 134 | . = ALIGN(4); 135 | _srelocate = .; 136 | *(.ramfunc .ramfunc.*); 137 | *(.data .data.*); 138 | . = ALIGN(4); 139 | _erelocate = .; 140 | } > ram 141 | 142 | /* if you initialize a global var to some non-zero value, then that data ends up 143 | in .relocate as read-only data and used briefly at startup (when copied to RAM). 144 | We don't want to support that, so we're checking here that hasn't happened. 145 | */ 146 | ASSERT(_srelocate == _erelocate, 147 | "DAFU: Sorry, no initialized data support! Set to zero or remove.") 148 | 149 | /* .bss section which is used for uninitialized data */ 150 | .bss (NOLOAD) : 151 | { 152 | . = ALIGN(4); 153 | _sbss = . ; 154 | _szero = .; 155 | *(.bss .bss.*) 156 | *(COMMON) 157 | . = ALIGN(4); 158 | _ebss = . ; 159 | _ezero = .; 160 | } > ram 161 | 162 | /* stack section */ 163 | .stack (NOLOAD): 164 | { 165 | . = ALIGN(8); 166 | _sstack = .; 167 | . = . + STACK_SIZE; 168 | . = ALIGN(8); 169 | _estack = .; 170 | } > ram 171 | 172 | . = ALIGN(4); 173 | _end = . ; 174 | } 175 | -------------------------------------------------------------------------------- /common/hw.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "common/util.h" 5 | 6 | const extern char *git_version; 7 | 8 | inline static void pin_mux(Pin p) { 9 | if (p.pin & 1) { 10 | PORT->Group[p.group].PMUX[p.pin/2].bit.PMUXO = p.mux; 11 | } else { 12 | PORT->Group[p.group].PMUX[p.pin/2].bit.PMUXE = p.mux; 13 | } 14 | 15 | PORT->Group[p.group].PINCFG[p.pin].bit.PMUXEN = 1; 16 | } 17 | 18 | // all adc functions are on peripherial B (0x01) 19 | inline static void pin_analog(Pin p) { 20 | if (p.pin & 1) { 21 | PORT->Group[p.group].PMUX[p.pin/2].bit.PMUXO = 0x1; 22 | } else { 23 | PORT->Group[p.group].PMUX[p.pin/2].bit.PMUXE = 0x1; 24 | } 25 | 26 | PORT->Group[p.group].PINCFG[p.pin].bit.PMUXEN = 1; 27 | } 28 | 29 | inline static void pin_gpio(Pin p) { 30 | PORT->Group[p.group].PINCFG[p.pin].bit.PMUXEN = 0; 31 | } 32 | 33 | inline static void pin_out(Pin p) { 34 | pin_gpio(p); 35 | PORT->Group[p.group].DIRSET.reg = (1<Group[p.group].DIRSET.reg = (1<Group[p.group].DIRCLR.reg = (1<Group[p.group].OUTSET.reg = (1<Group[p.group].OUTCLR.reg = (1<Group[p.group].OUTTGL.reg = (1<Group[p.group].OUTSET.reg = (1<Group[p.group].OUTCLR.reg = (1<Group[p.group].PINCFG[p.pin].bit.INEN = 1; 69 | PORT->Group[p.group].DIRCLR.reg = (1<Group[p.group].PINCFG[p.pin].bit.PULLEN = 1; 75 | pin_high(p); 76 | } 77 | 78 | inline static void pin_pull_down(Pin p) { 79 | pin_in(p); 80 | PORT->Group[p.group].PINCFG[p.pin].bit.PULLEN = 1; 81 | pin_low(p); 82 | } 83 | 84 | inline static void pin_float(Pin p) { 85 | pin_in(p); 86 | PORT->Group[p.group].PINCFG[p.pin].bit.PULLEN = 0; 87 | } 88 | 89 | inline static bool pin_read(Pin p) { 90 | return (PORT->Group[p.group].IN.reg & (1<Group[p.group].PMUX[p.pin/2].bit.PMUXO = 0; 96 | } else { 97 | PORT->Group[p.group].PMUX[p.pin/2].bit.PMUXE = 0; 98 | } 99 | 100 | PORT->Group[p.group].PINCFG[p.pin].bit.PMUXEN = 1; 101 | } 102 | 103 | inline static void eic_init() { 104 | PM->APBAMASK.reg |= PM_APBAMASK_EIC; 105 | 106 | GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | 107 | GCLK_CLKCTRL_GEN(0) | 108 | GCLK_CLKCTRL_ID(EIC_GCLK_ID); 109 | 110 | EIC->CTRL.reg = EIC_CTRL_ENABLE; 111 | } 112 | 113 | inline static u8 pin_extint(Pin p) { 114 | return p.pin % 16; 115 | } 116 | 117 | #define EIC_CONFIG_SENSE_NONE 0x0u /**< \brief (EIC_CONFIG) No detection */ 118 | #define EIC_CONFIG_SENSE_RISE 0x1u /**< \brief (EIC_CONFIG) Rising edge detection */ 119 | #define EIC_CONFIG_SENSE_FALL 0x2u /**< \brief (EIC_CONFIG) Falling edge detection */ 120 | #define EIC_CONFIG_SENSE_BOTH 0x3u /**< \brief (EIC_CONFIG) Both edges detection */ 121 | #define EIC_CONFIG_SENSE_LEVEL 0x4u /**< \brief (EIC_CONFIG) High level detection */ 122 | #define EIC_CONFIG_SENSE_HIGH 0x4u /**< \brief (EIC_CONFIG) High level detection */ 123 | #define EIC_CONFIG_SENSE_LOW 0x5u /**< \brief (EIC_CONFIG) Low level detection */ 124 | 125 | inline static void eic_config(Pin p, u8 config) { 126 | u8 i = pin_extint(p); 127 | u8 pos = (i % 8) * 4; 128 | EIC->CONFIG[i/8].reg = (EIC->CONFIG[i/8].reg & ~(0xf << pos)) | (config << pos); 129 | } 130 | 131 | inline static u8 eic_read_config(Pin p) { 132 | u8 i = pin_extint(p); 133 | u8 pos = (i % 8) * 4; 134 | return (EIC->CONFIG[i/8].reg >> pos) & 0xf; 135 | } 136 | 137 | inline static void evsys_init() { 138 | PM->APBCMASK.reg |= PM_APBCMASK_EVSYS; 139 | } 140 | 141 | #define EVSYS_USER_NONE -1 142 | 143 | inline static void evsys_config(u8 channel, u8 source, u8 user) { 144 | GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | 145 | GCLK_CLKCTRL_GEN(0) | 146 | GCLK_CLKCTRL_ID(EVSYS_GCLK_ID_0 + channel); 147 | 148 | EVSYS->CHANNEL.reg = EVSYS_CHANNEL_CHANNEL(channel) 149 | | EVSYS_CHANNEL_EVGEN(source) 150 | | EVSYS_CHANNEL_PATH_SYNCHRONOUS | EVSYS_CHANNEL_EDGSEL_RISING_EDGE; 151 | 152 | if (user != EVSYS_USER_NONE) { 153 | EVSYS->USER.reg = EVSYS_USER_CHANNEL(channel + 1) | EVSYS_USER_USER(user); 154 | } 155 | } 156 | 157 | #define EVSYS_EVD(N) ((N)<=7 ? (1<<((N) + 8)) : (1 << (24 + (N) - 8))) 158 | 159 | // analog.c 160 | void adc_init(u8 channel, u8 refctrl); 161 | u16 adc_sample(); 162 | u16 adc_read(Pin p, u32 gain); 163 | void dac_init(u8 channel); 164 | void dac_write(Pin p, u16 val); 165 | 166 | 167 | // clock.c 168 | void gclk_enable(uint32_t id, uint32_t src, uint32_t div); 169 | void clock_init_usb(u8 clk_system); 170 | void clock_init_crystal(u8 clk_system, u8 clk_32k); 171 | 172 | // dma.c 173 | #define DMA_DESC_ALIGN __attribute__((aligned(16))) 174 | 175 | void dma_init(); 176 | void dma_sercom_start_tx(DmaChan chan, SercomId id, u8* src, unsigned size); 177 | void dma_sercom_start_rx(DmaChan chan, SercomId id, u8* dst, unsigned size); 178 | void dma_abort(DmaChan chan); 179 | void dma_fill_sercom_tx(DmacDescriptor* desc, SercomId id, u8 *src, unsigned size); 180 | void dma_fill_sercom_rx(DmacDescriptor* desc, SercomId id, u8 *dst, unsigned size); 181 | void dma_sercom_configure_tx(DmaChan chan, SercomId id); 182 | void dma_sercom_configure_rx(DmaChan chan, SercomId id); 183 | void dma_link_chain(DmacDescriptor* chain, u32 count); 184 | void dma_start_descriptor(DmaChan chan, DmacDescriptor* chain); 185 | u32 dma_remaining(DmaChan chan); 186 | 187 | 188 | // sercom.c 189 | 190 | inline static Sercom* sercom(SercomId id) { 191 | return (Sercom*) (0x42000800U + id * 1024); 192 | } 193 | 194 | #define SERCOM_SPI_BAUD_8MHZ 2 195 | #define SERCOM_SPI_BAUD_12MHZ 1 196 | #define SERCOM_SPI_BAUD_24MHZ 0 197 | void sercom_clock_enable(SercomId id, uint32_t clock_channel, u8 div); 198 | void sercom_reset(SercomId id); 199 | void sercom_spi_slave_init(SercomId id, u32 dipo, u32 dopo, bool cpol, bool cpha); 200 | void sercom_spi_master_init(SercomId id, u32 dipo, u32 dopo, bool cpol, bool cpha, u8 baud); 201 | void sercom_i2c_master_init(SercomId id, u8 baud); 202 | void sercom_uart_init(SercomId id, u32 rxpo, u32 txpo, u32 baud); 203 | 204 | inline static void jump_to_flash(uint32_t addr_p, uint32_t r0_val) { 205 | uint32_t *addr = (void*) addr_p; 206 | __disable_irq(); 207 | 208 | // Disable SysTick 209 | SysTick->CTRL = 0; 210 | 211 | // TODO: reset peripherals 212 | 213 | // Switch to the the interrupt vector table in flash 214 | SCB->VTOR = (uint32_t) addr; 215 | 216 | // Set up the stack and jump to the reset vector 217 | uint32_t sp = addr[0]; 218 | uint32_t pc = addr[1]; 219 | register uint32_t r0 __asm__ ("r0") = r0_val; 220 | __asm__ volatile("mov sp, %0; bx %1" :: "r" (sp), "r" (pc), "r" (r0)); 221 | (void) r0_val; 222 | } 223 | 224 | // timer 225 | 226 | inline static Tc* tc(TimerId id) { 227 | return (Tc*) (0x42002C00U + (id - 3) * 1024); 228 | } 229 | 230 | inline static Tcc* tcc(TimerId id) { 231 | return (Tcc*) (0x42002000U + (id) * 1024); 232 | } 233 | 234 | void timer_clock_enable(TimerId id); 235 | 236 | void tcc_delay_start(TimerId id, u32 ticks); 237 | void tcc_delay_disable(TimerId id); 238 | void tcc_delay_enable(TimerId id); 239 | 240 | // wdt 241 | 242 | inline static void wdt_reset(u32 clock_channel) { 243 | GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | 244 | GCLK_CLKCTRL_GEN(clock_channel) | 245 | GCLK_CLKCTRL_ID(WDT_GCLK_ID); 246 | WDT->CONFIG.reg = 0x7; // 31ms 247 | WDT->CTRL.reg = WDT_CTRL_ENABLE; 248 | } 249 | -------------------------------------------------------------------------------- /usb.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Tessel See the COPYRIGHT 2 | // file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | #include "boot.h" 11 | #include "usb.h" 12 | #include "samd/usb_samd.h" 13 | 14 | // Return a ptr to a descriptor, perhaps made with usb_string_to_descriptor() 15 | // that contains a unique serial number for this board. 16 | void* get_serial_number_string_descriptor(); 17 | 18 | USB_ENDPOINTS(1); 19 | 20 | const USB_DeviceDescriptor device_descriptor = { 21 | .bLength = sizeof(USB_DeviceDescriptor), 22 | .bDescriptorType = USB_DTYPE_Device, 23 | 24 | .bcdUSB = 0x0200, 25 | .bDeviceClass = 0, 26 | .bDeviceSubClass = USB_CSCP_NoDeviceSubclass, 27 | .bDeviceProtocol = USB_CSCP_NoDeviceProtocol, 28 | 29 | .bMaxPacketSize0 = 64, 30 | .idVendor = 0x1209, 31 | .idProduct = 0x7551, 32 | .bcdDevice = 0x0002, 33 | 34 | .iManufacturer = 0x01, 35 | .iProduct = 0x02, 36 | .iSerialNumber = 0x03, 37 | 38 | .bNumConfigurations = 1 39 | }; 40 | 41 | typedef struct ConfigDesc { 42 | USB_ConfigurationDescriptor Config; 43 | USB_InterfaceDescriptor dfu_intf_flash; 44 | DFU_FunctionalDescriptor dfu_desc_flash; 45 | USB_InterfaceDescriptor dfu_intf_ram; 46 | DFU_FunctionalDescriptor dfu_desc_ram; 47 | } ConfigDesc; 48 | 49 | const ConfigDesc configuration_descriptor = { 50 | .Config = { 51 | .bLength = sizeof(USB_ConfigurationDescriptor), 52 | .bDescriptorType = USB_DTYPE_Configuration, 53 | .wTotalLength = sizeof(ConfigDesc), 54 | .bNumInterfaces = 1, 55 | .bConfigurationValue = 1, 56 | .iConfiguration = 0, 57 | .bmAttributes = USB_CONFIG_ATTR_BUSPOWERED, 58 | .bMaxPower = USB_CONFIG_POWER_MA(500) 59 | }, 60 | .dfu_intf_flash = { 61 | .bLength = sizeof(USB_InterfaceDescriptor), 62 | .bDescriptorType = USB_DTYPE_Interface, 63 | .bInterfaceNumber = 0, 64 | .bAlternateSetting = 0, 65 | .bNumEndpoints = 0, 66 | .bInterfaceClass = DFU_INTERFACE_CLASS, 67 | .bInterfaceSubClass = DFU_INTERFACE_SUBCLASS, 68 | .bInterfaceProtocol = DFU_INTERFACE_PROTOCOL, 69 | .iInterface = 0x10 70 | }, 71 | .dfu_desc_flash = { 72 | .bLength = sizeof(DFU_FunctionalDescriptor), 73 | .bDescriptorType = DFU_DESCRIPTOR_TYPE, 74 | .bmAttributes = DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_WILL_DETACH, 75 | .wDetachTimeout = 0, 76 | .wTransferSize = DFU_TRANSFER_SIZE, 77 | .bcdDFUVersion = 0x0101, 78 | }, 79 | .dfu_intf_ram = { 80 | .bLength = sizeof(USB_InterfaceDescriptor), 81 | .bDescriptorType = USB_DTYPE_Interface, 82 | .bInterfaceNumber = 0, 83 | .bAlternateSetting = 1, 84 | .bNumEndpoints = 0, 85 | .bInterfaceClass = DFU_INTERFACE_CLASS, 86 | .bInterfaceSubClass = DFU_INTERFACE_SUBCLASS, 87 | .bInterfaceProtocol = DFU_INTERFACE_PROTOCOL, 88 | .iInterface = 0x11 89 | }, 90 | .dfu_desc_ram = { 91 | .bLength = sizeof(DFU_FunctionalDescriptor), 92 | .bDescriptorType = DFU_DESCRIPTOR_TYPE, 93 | .bmAttributes = DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_WILL_DETACH, 94 | .wDetachTimeout = 0, 95 | .wTransferSize = DFU_TRANSFER_SIZE, 96 | .bcdDFUVersion = 0x0101, 97 | }, 98 | }; 99 | 100 | const USB_StringDescriptor language_string = { 101 | .bLength = USB_STRING_LEN(1), 102 | .bDescriptorType = USB_DTYPE_String, 103 | .bString = {USB_LANGUAGE_EN_US}, 104 | }; 105 | 106 | const USB_StringDescriptor msft_os = { 107 | .bLength = 18, 108 | .bDescriptorType = USB_DTYPE_String, 109 | .bString = {'M','S','F','T','1','0','0',0xee}, 110 | }; 111 | 112 | const USB_MicrosoftCompatibleDescriptor msft_compatible = { 113 | .dwLength = sizeof(USB_MicrosoftCompatibleDescriptor) + sizeof(USB_MicrosoftCompatibleDescriptor_Interface), 114 | .bcdVersion = 0x0100, 115 | .wIndex = 0x0004, 116 | .bCount = 1, 117 | .reserved = {0, 0, 0, 0, 0, 0, 0}, 118 | .interfaces = { 119 | { 120 | .bFirstInterfaceNumber = 0, 121 | .reserved1 = 0, 122 | .compatibleID = "WINUSB\0\0", 123 | .subCompatibleID = {0, 0, 0, 0, 0, 0, 0, 0}, 124 | .reserved2 = {0, 0, 0, 0, 0, 0}, 125 | } 126 | } 127 | }; 128 | 129 | uint16_t usb_cb_get_descriptor(uint8_t type, uint8_t index, const uint8_t** ptr) { 130 | const void* address = NULL; 131 | uint16_t size = 0; 132 | 133 | switch (type) { 134 | case USB_DTYPE_Device: 135 | address = &device_descriptor; 136 | size = sizeof(USB_DeviceDescriptor); 137 | break; 138 | case USB_DTYPE_Configuration: 139 | address = &configuration_descriptor; 140 | size = sizeof(ConfigDesc); 141 | break; 142 | case USB_DTYPE_String: 143 | switch (index) { 144 | case 0x00: 145 | address = &language_string; 146 | break; 147 | case 0x01: 148 | address = usb_string_to_descriptor(USB_MANUFACTURER_STR); 149 | break; 150 | case 0x02: 151 | address = usb_string_to_descriptor(USB_PRODUCT_STR); 152 | break; 153 | case 0x03: 154 | address = get_serial_number_string_descriptor(); 155 | break; 156 | case 0x10: 157 | address = usb_string_to_descriptor("Flash"); 158 | break; 159 | case 0x11: 160 | address = usb_string_to_descriptor("SRAM"); 161 | break; 162 | case 0xf0: 163 | address = usb_string_to_descriptor(""); 164 | break; 165 | case 0xee: 166 | address = &msft_os; 167 | break; 168 | } 169 | size = (((USB_StringDescriptor*)address))->bLength; 170 | break; 171 | } 172 | 173 | *ptr = address; 174 | return size; 175 | } 176 | 177 | void usb_cb_reset(void) { 178 | } 179 | 180 | bool usb_cb_set_configuration(uint8_t config) { 181 | if (config <= 1) { 182 | return true; 183 | } 184 | return false; 185 | } 186 | 187 | void usb_cb_control_setup(void) { 188 | uint8_t recipient = usb_setup.bmRequestType & USB_REQTYPE_RECIPIENT_MASK; 189 | if (recipient == USB_RECIPIENT_DEVICE) { 190 | if (usb_setup.bRequest == 0xee) { 191 | return usb_handle_msft_compatible(&msft_compatible); 192 | } 193 | } else if (recipient == USB_RECIPIENT_INTERFACE) { 194 | if (usb_setup.wIndex == DFU_INTF) { 195 | return dfu_control_setup(); 196 | } 197 | } 198 | return usb_ep0_stall(); 199 | } 200 | 201 | void usb_cb_control_in_completion(void) { 202 | uint8_t recipient = usb_setup.bmRequestType & USB_REQTYPE_RECIPIENT_MASK; 203 | if (recipient == USB_RECIPIENT_INTERFACE) { 204 | if (usb_setup.wIndex == DFU_INTF) { 205 | dfu_control_in_completion(); 206 | } 207 | } 208 | } 209 | 210 | void usb_cb_control_out_completion(void) { 211 | uint8_t recipient = usb_setup.bmRequestType & USB_REQTYPE_RECIPIENT_MASK; 212 | if (recipient == USB_RECIPIENT_INTERFACE) { 213 | if (usb_setup.wIndex == DFU_INTF) { 214 | dfu_control_out_completion(); 215 | } 216 | } 217 | } 218 | 219 | void usb_cb_completion(void) { 220 | 221 | } 222 | 223 | bool usb_cb_set_interface(uint16_t interface, uint16_t altsetting) { 224 | if (interface == DFU_INTF) { 225 | if (altsetting == 0) { 226 | dfu_reset(); 227 | return true; 228 | } 229 | } 230 | return false; 231 | } 232 | 233 | // Return a string descriptor containing a unique serial number. 234 | // 235 | void *get_serial_number_string_descriptor() 236 | { 237 | #if 0 238 | char buf[27]; 239 | 240 | const unsigned char* id = (unsigned char*) 0x0080A00C; 241 | for (int i=0; i<26; i++) { 242 | unsigned idx = (i*5)/8; 243 | unsigned pos = (i*5)%8; 244 | unsigned val = ((id[idx] >> pos) | (id[idx+1] << (8-pos))) & ((1<<5)-1); 245 | buf[i] = "0123456789ABCDFGHJKLMNPQRSTVWXYZ"[val]; 246 | } 247 | buf[26] = 0; 248 | #endif 249 | 250 | // 251 | // Read and save the device serial number as normal Base32. 252 | // 253 | 254 | // Documented in section 9.3.3 of D21 datasheet, page 32 (rev G), but no header file, 255 | // these are not contiguous addresses. 256 | const uint32_t *ser[4] = { 257 | (uint32_t *)0x0080A00C, 258 | (uint32_t *)0x0080A040, (uint32_t *)0x0080A044, (uint32_t *)0x0080A048 }; 259 | 260 | uint32_t copy[4]; 261 | copy[0] = *ser[0]; 262 | copy[1] = *ser[1]; 263 | copy[2] = *ser[2]; 264 | copy[3] = *ser[3]; 265 | 266 | uint8_t *tmp = (uint8_t *)copy; 267 | 268 | int count = 0; 269 | int next = 1; 270 | int buffer = tmp[0]; 271 | int bitsLeft = 8; 272 | 273 | const int length = 16; 274 | char buf[27]; 275 | 276 | while(bitsLeft > 0 || next < length) { 277 | if(bitsLeft < 5) { 278 | if(next < length) { 279 | buffer <<= 8; 280 | buffer |= tmp[next++] & 0xff; 281 | bitsLeft += 8; 282 | } else { 283 | int pad = 5 - bitsLeft; 284 | buffer <<= pad; 285 | bitsLeft += pad; 286 | } 287 | } 288 | bitsLeft -= 5; 289 | int index = (buffer >> bitsLeft) & 0x1f; 290 | buf[count++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[index]; 291 | } 292 | buf[count] = 0; 293 | 294 | return usb_string_to_descriptor(buf); 295 | } 296 | 297 | -------------------------------------------------------------------------------- /common/startup_samd21.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | * 4 | * \brief gcc starttup file for SAMD21 5 | * 6 | * Copyright (c) 2013-2014 Atmel Corporation. All rights reserved. 7 | * 8 | * \asf_license_start 9 | * 10 | * \page License 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * 1. Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * 2. Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * 3. The name of Atmel may not be used to endorse or promote products derived 23 | * from this software without specific prior written permission. 24 | * 25 | * 4. This software may only be redistributed and used in connection with an 26 | * Atmel microcontroller product. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR 32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 | * POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * \asf_license_stop 41 | * 42 | */ 43 | 44 | #include "samd21.h" 45 | 46 | /* Initialize segments */ 47 | extern uint32_t _sfixed; 48 | extern uint32_t _efixed; 49 | extern uint32_t _etext; 50 | extern uint32_t _srelocate; 51 | extern uint32_t _erelocate; 52 | extern uint32_t _szero; 53 | extern uint32_t _ezero; 54 | extern uint32_t _sstack; 55 | extern uint32_t _estack; 56 | 57 | /** \cond DOXYGEN_SHOULD_SKIP_THIS */ 58 | int main_bl(void); 59 | /** \endcond */ 60 | 61 | void __libc_init_array(void); 62 | 63 | /* Default empty handler */ 64 | void Dummy_Handler(void); 65 | 66 | /* Cortex-M0+ core handlers */ 67 | void NMI_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 68 | void HardFault_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 69 | void SVC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 70 | void PendSV_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 71 | void SysTick_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 72 | 73 | /* Peripherals handlers */ 74 | void PM_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 75 | void SYSCTRL_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 76 | void WDT_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 77 | void RTC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 78 | void EIC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 79 | void NVMCTRL_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 80 | void DMAC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 81 | void USB_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 82 | void EVSYS_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 83 | void SERCOM0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 84 | void SERCOM1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 85 | void SERCOM2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 86 | void SERCOM3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 87 | void SERCOM4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 88 | void SERCOM5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 89 | void TCC0_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 90 | void TCC1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 91 | void TCC2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 92 | void TC3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 93 | void TC4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 94 | void TC5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 95 | void TC6_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 96 | void TC7_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 97 | void ADC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 98 | void AC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 99 | void DAC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 100 | void PTC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 101 | void I2S_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler"))); 102 | 103 | /* Exception Table */ 104 | __attribute__ ((section(".vectors"))) 105 | __attribute__ ((used)) 106 | const DeviceVectors exception_table = { 107 | 108 | /* Configure Initial Stack Pointer, using linker-generated symbols */ 109 | (void*) (&_estack), 110 | 111 | (void*) Reset_Handler, 112 | (void*) NMI_Handler, 113 | (void*) HardFault_Handler, 114 | (void*) (0UL), /* Reserved */ 115 | (void*) (0UL), /* Reserved */ 116 | (void*) (0UL), /* Reserved */ 117 | (void*) (0UL), /* Reserved */ 118 | (void*) (0UL), /* Reserved */ 119 | (void*) (0UL), /* Reserved */ 120 | (void*) (0UL), /* Reserved */ 121 | (void*) SVC_Handler, 122 | (void*) (0UL), /* Reserved */ 123 | (void*) (0UL), /* Reserved */ 124 | (void*) PendSV_Handler, 125 | (void*) SysTick_Handler, 126 | 127 | /* Configurable interrupts */ 128 | (void*) PM_Handler, /* 0 Power Manager */ 129 | (void*) SYSCTRL_Handler, /* 1 System Control */ 130 | (void*) WDT_Handler, /* 2 Watchdog Timer */ 131 | (void*) RTC_Handler, /* 3 Real-Time Counter */ 132 | (void*) EIC_Handler, /* 4 External Interrupt Controller */ 133 | (void*) NVMCTRL_Handler, /* 5 Non-Volatile Memory Controller */ 134 | (void*) DMAC_Handler, /* 6 Direct Memory Access Controller */ 135 | (void*) USB_Handler, /* 7 Universal Serial Bus */ 136 | (void*) EVSYS_Handler, /* 8 Event System Interface */ 137 | (void*) SERCOM0_Handler, /* 9 Serial Communication Interface 0 */ 138 | (void*) SERCOM1_Handler, /* 10 Serial Communication Interface 1 */ 139 | (void*) SERCOM2_Handler, /* 11 Serial Communication Interface 2 */ 140 | (void*) SERCOM3_Handler, /* 12 Serial Communication Interface 3 */ 141 | (void*) SERCOM4_Handler, /* 13 Serial Communication Interface 4 */ 142 | (void*) SERCOM5_Handler, /* 14 Serial Communication Interface 5 */ 143 | (void*) TCC0_Handler, /* 15 Timer Counter Control 0 */ 144 | (void*) TCC1_Handler, /* 16 Timer Counter Control 1 */ 145 | (void*) TCC2_Handler, /* 17 Timer Counter Control 2 */ 146 | (void*) TC3_Handler, /* 18 Basic Timer Counter 0 */ 147 | (void*) TC4_Handler, /* 19 Basic Timer Counter 1 */ 148 | (void*) TC5_Handler, /* 20 Basic Timer Counter 2 */ 149 | (void*) TC6_Handler, /* 21 Basic Timer Counter 3 */ 150 | (void*) TC7_Handler, /* 22 Basic Timer Counter 4 */ 151 | (void*) ADC_Handler, /* 23 Analog Digital Converter */ 152 | (void*) AC_Handler, /* 24 Analog Comparators */ 153 | (void*) DAC_Handler, /* 25 Digital Analog Converter */ 154 | (void*) PTC_Handler, /* 26 Peripheral Touch Controller */ 155 | (void*) I2S_Handler /* 27 Inter-IC Sound Interface */ 156 | }; 157 | 158 | /** 159 | * \brief This is the code that gets called on processor reset. 160 | * To initialize the device, and call the main() routine. 161 | */ 162 | void Reset_Handler(void) 163 | { 164 | uint32_t *pSrc, *pDest; 165 | 166 | /* Initialize the relocate segment */ 167 | pSrc = &_etext; 168 | pDest = &_srelocate; 169 | 170 | #if 0 171 | // See link-script.ld which makes sure we dont need this. 172 | 173 | if (pSrc != pDest) { 174 | for (; pDest < &_erelocate;) { 175 | *pDest++ = *pSrc++; 176 | } 177 | } 178 | #endif 179 | 180 | /* Clear the zero segment */ 181 | for (pDest = &_szero; pDest < &_ezero;) { 182 | *pDest++ = 0; 183 | } 184 | 185 | /* Set the vector table base address */ 186 | pSrc = (uint32_t *) & _sfixed; 187 | SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk); 188 | 189 | /* Initialize the C library */ 190 | __libc_init_array(); 191 | 192 | /* Branch to main function */ 193 | main_bl(); 194 | 195 | /* Infinite loop */ 196 | while (1); 197 | } 198 | 199 | /** 200 | * \brief Default interrupt handler for unused IRQs. 201 | */ 202 | void Dummy_Handler(void) 203 | { 204 | while (1) { 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------