pulse D13 LED during bootloader active

This commit is contained in:
ladyada 2015-10-31 00:52:54 -04:00 committed by dean
parent a62ef21615
commit f8481c1ae9
4 changed files with 348 additions and 186 deletions

View file

@ -1,105 +1,3 @@
<<<<<<< HEAD
# Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved.
# Copyright (c) 2015 Arduino LLC. All right reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# -----------------------------------------------------------------------------
# Paths
ifeq ($(OS),Windows_NT)
# Are we using mingw/msys/msys2/cygwin?
ifeq ($(TERM),xterm)
T=$(shell cygpath -u $(LOCALAPPDATA))
MODULE_PATH?=$(T)/Arduino15/packages/arduino
RM=rm
SEP=/
else
MODULE_PATH?=$(LOCALAPPDATA)/Arduino15/packages/arduino
RM=rm
SEP=\\
endif
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
MODULE_PATH?=$(HOME)/.arduino15/packages/arduino
RM=rm
SEP=/
endif
ifeq ($(UNAME_S),Darwin)
MODULE_PATH?=$(HOME)/Library/Arduino15/packages/arduino/
RM=rm
SEP=/
endif
endif
ARM_GCC_PATH?=$(MODULE_PATH)/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi-
BUILD_PATH=build
# -----------------------------------------------------------------------------
# Tools
CC=$(ARM_GCC_PATH)gcc
OBJCOPY=$(ARM_GCC_PATH)objcopy
NM=$(ARM_GCC_PATH)nm
SIZE=$(ARM_GCC_PATH)size
# -----------------------------------------------------------------------------
# Boards definitions
BOARD_ID?=arduino_zero
NAME?=samd21_sam_ba
# -----------------------------------------------------------------------------
# Compiler options
CFLAGS_EXTRA=-D__SAMD21G18A__ -DBOARD_ID_$(BOARD_ID)
CFLAGS=-mthumb -mcpu=cortex-m0plus -Wall -c -std=gnu99 -ffunction-sections -fdata-sections -nostdlib -nostartfiles --param max-inline-insns-single=500
ifdef DEBUG
CFLAGS+=-g3 -O1 -DDEBUG=1
else
CFLAGS+=-Os -DDEBUG=0
endif
ELF=$(NAME).elf
BIN=$(NAME).bin
HEX=$(NAME).hex
INCLUDES=-I"$(MODULE_PATH)/tools/CMSIS/4.5.0/CMSIS/Include/" -I"$(MODULE_PATH)/tools/CMSIS-Atmel/1.1.0/CMSIS/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_i2c.c \
board_driver_led.c \
board_driver_pmic.c \
board_driver_serial.c \
board_driver_usb.c \
board_init.c \
board_startup.c \
main.c \
sam_ba_usb.c \
sam_ba_cdc.c \
sam_ba_monitor.c \
sam_ba_serial.c
=======
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
@ -109,7 +7,6 @@ BLD_EXTA_FLAGS=-D__SAMD21G18A__
BUILD_PATH=build
INCLUDES=-I$(IDE_PATH)/hardware/tools/CMSIS/CMSIS/Include/ -I$(IDE_PATH)/hardware/tools/CMSIS/Device/ATMEL/ -I./drivers/ -I./utils/ -I./utils/preprocessor/ -I./utils/interrupt
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
>>>>>>> fix makefile for easier programming
OBJECTS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.o))
DEPS=$(addprefix $(BUILD_PATH)/, $(SOURCES:.c=.d))
@ -121,75 +18,11 @@ else
AS_CLEAN=
endif
<<<<<<< HEAD
LD_SCRIPT=bootloader_samd21x18.ld
=======
NAME=samd21_sam_ba
EXECUTABLE=$(NAME).bin
>>>>>>> fix makefile for easier programming
all: print_info $(SOURCES) $(BIN) $(HEX) $(AS_BUILD)
<<<<<<< HEAD
$(ELF): Makefile $(BUILD_PATH) $(OBJECTS)
@echo ----------------------------------------------------------
@echo Creating ELF binary
"$(CC)" -L. -L$(BUILD_PATH) $(LDFLAGS) -Os -Wl,--gc-sections -save-temps -T$(LD_SCRIPT) -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)
$(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 $@
"$(CC)" $(CFLAGS) $(CFLAGS_EXTRA) $(INCLUDES) $< -o $@
@echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
$(BUILD_PATH):
@echo ----------------------------------------------------------
@echo Creating build folder
-mkdir $(BUILD_PATH)
print_info:
@echo ----------------------------------------------------------
@echo Compiling bootloader using
@echo BASE PATH = $(MODULE_PATH)
@echo GCC PATH = $(ARM_GCC_PATH)
# @echo OS = $(OS)
# @echo SHELL = $(SHELL)
# @echo TERM = $(TERM)
# "$(CC)" -v
# env
copy_for_atmel_studio: $(BIN) $(HEX)
@echo ----------------------------------------------------------
@echo Atmel Studio detected, copying ELF to project root for debug
cp $(BUILD_PATH)/$(ELF) .
clean_for_atmel_studio:
@echo ----------------------------------------------------------
@echo Atmel Studio detected, cleaning ELF from project root
-$(RM) ./$(ELF)
clean: $(AS_CLEAN)
@echo ----------------------------------------------------------
@echo Cleaning project
-$(RM) $(BIN)
-$(RM) $(HEX)
-$(RM) $(BUILD_PATH)/*.*
-rmdir $(BUILD_PATH)
.phony: print_info $(BUILD_PATH)
=======
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
@ -202,4 +35,3 @@ $(BUILD_PATH)/%.o: %.c
clean:
del $(EXECUTABLE) $(subst /,\,$(OBJECTS)) $(subst /,\,$(BUILD_PATH)/$(NAME).*)
>>>>>>> fix makefile for easier programming

View file

@ -191,22 +191,16 @@ int main(void)
#if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES
pCdc = usb_init();
#endif
DEBUG_PIN_LOW;
DEBUG_PIN_LOW;
// output on D13 (PA.17)
LED_PORT.PINCFG[LED_PIN].reg &= ~ (uint8_t)(PORT_PINCFG_INEN);
LED_PORT.DIRSET.reg = (uint32_t)(1 << LED_PIN);
/* Initialize LEDs */
LED_init();
LEDRX_init();
LEDRX_off();
LEDTX_init();
LEDTX_off();
/* Wait for a complete enum on usb or a '#' char on serial line */
while (1) {
pulse_led(1); // while we're waiting, blink the D13
/* Start the sys tick (1 ms) */
SysTick_Config(1000);
/* 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)
{
@ -246,3 +240,28 @@ void SysTick_Handler(void)
sam_ba_monitor_sys_tick();
}
// We'll have the D13 LED slowly pulse on and off with bitbang PWM
// for a nice 'hey we're in bootload mode' indication! -ada
static uint8_t pulse_tick=0;
static int8_t pulse_dir=1;
static int16_t pulse_pwm;
void pulse_led(int8_t speed) {
// blink D13
pulse_tick++;
if (pulse_tick==0) {
pulse_pwm += pulse_dir * speed;
if (pulse_pwm > 255) {
pulse_pwm = 255;
pulse_dir = -1;
}
if (pulse_pwm < 0) {
pulse_pwm = 0;
pulse_dir = +1;
}
LED_ON;
}
if (pulse_tick==pulse_pwm)
LED_OFF;
}

69
bootloaders/zero/main.h Normal file
View file

@ -0,0 +1,69 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2011-2012, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following condition is met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
#pragma once
// Gently pulse the D13 LED
#define LED_PIN 17
#define PORTA PORT->Group[0]
#define LED_PORT PORTA
#define LED_ON LED_PORT.OUTSET.reg = (uint32_t)(1 << LED_PIN);
#define LED_OFF LED_PORT.OUTCLR.reg = (uint32_t)(1 << LED_PIN);
/*
* If BOOT_DOUBLE_TAP_ADDRESS is defined the bootloader is started by
* quickly tapping two times on the reset button.
* BOOT_DOUBLE_TAP_ADDRESS must point to a free SRAM cell that must not
* be touched from the loaded application.
*/
#define BOOT_DOUBLE_TAP_ADDRESS 0x20007FFC
#define BOOT_DOUBLE_TAP_DATA (*((volatile uint32_t *) BOOT_DOUBLE_TAP_ADDRESS))
/*
* If BOOT_LOAD_PIN is defined the bootloader is started if the selected
* pin is tied LOW.
*/
//#define BOOT_LOAD_PIN PIN_PA21 // Pin 7
//#define BOOT_LOAD_PIN PIN_PA15 // Pin 5
#define BOOT_PIN_MASK (1U << (BOOT_LOAD_PIN & 0x1f))
#define CPU_FREQUENCY 8000000
#define APP_START_ADDRESS 0x00002000
#define FLASH_WAIT_STATES 1
#define BOOT_USART_MODULE SERCOM0
//#define BOOT_USART_MODULE SERCOM5
#define BOOT_USART_MUX_SETTINGS UART_RX_PAD3_TX_PAD2
//#define BOOT_USART_PAD3 PINMUX_PB23D_SERCOM5_PAD3
//#define BOOT_USART_PAD2 PINMUX_PB22D_SERCOM5_PAD2
#define BOOT_USART_PAD3 PINMUX_PA11C_SERCOM0_PAD3
#define BOOT_USART_PAD2 PINMUX_PA10C_SERCOM0_PAD2
#define BOOT_USART_PAD1 PINMUX_UNUSED
#define BOOT_USART_PAD0 PINMUX_UNUSED

View file

@ -527,11 +527,253 @@ static void sam_ba_monitor_loop(void)
void sam_ba_monitor_sys_tick(void)
{
/* Check whether the TX or RX LED one-shot period has elapsed. if so, turn off the LED */
if (txLEDPulse && !(--txLEDPulse))
LEDTX_off();
if (rxLEDPulse && !(--rxLEDPulse))
LEDRX_off();
pulse_led(3);
length = ptr_monitor_if->getdata(data, SIZEBUFMAX);
ptr = data;
for (i = 0; i < length; i++, ptr++)
{
if (*ptr == 0xff) continue;
if (*ptr == '#')
{
if (b_terminal_mode)
{
ptr_monitor_if->putdata("\n\r", 2);
}
if (command == 'S')
{
//Check if some data are remaining in the "data" buffer
if(length>i)
{
//Move current indexes to next avail data (currently ptr points to "#")
ptr++;
i++;
//We need to add first the remaining data of the current buffer already read from usb
//read a maximum of "current_number" bytes
u32tmp=min((length-i),current_number);
memcpy(ptr_data, ptr, u32tmp);
i += u32tmp;
ptr += u32tmp;
j = u32tmp;
}
//update i with the data read from the buffer
i--;
ptr--;
//Do we expect more data ?
if(j<current_number)
ptr_monitor_if->getdata_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*) &current_number, 2);
}
else if (command == 'w')
{
current_number = *((uint32_t *) ptr_data);
sam_ba_putdata_term((uint8_t*) &current_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) && i<size; i++) {
dst_addr[i] = src_addr[i];
}
// Execute "WP" Write Page
//NVMCTRL->ADDR.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; i<size; i++)
crc = add_crc(*data++, crc);
// Send response
ptr_monitor_if->putdata("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;
}
}
}
}
/**