forked from jappel/VersaMCU
Vendored and trimmed from microsoft/uf2-samdx1, adapted to the actual ATSAMD21G17D (128 KiB flash / 16 KiB RAM), fixing the flash/RAM-size mismatch that the previously commented-out SAM-BA bootloader target had (it assumed a 256 KiB SAMD21G18A). Builds as a standalone PlatformIO environment (bootloader/platformio.ini), no python2/make dependency. Compiles clean, fits in the 8 KiB bootloader region (7292/8192 bytes). Not yet flashed/verified on real hardware.
300 lines
11 KiB
C
300 lines
11 KiB
C
/* ----------------------------------------------------------------------------
|
|
* SAM Software Package License
|
|
* ----------------------------------------------------------------------------
|
|
* Copyright (c) 2011-2014, Atmel Corporation
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following condition is met:
|
|
*
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the disclaimer below.
|
|
*
|
|
* Atmel's name may not be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "uf2.h"
|
|
|
|
static const char fullVersion[] = "v" SAM_BA_VERSION " [Arduino:XYZ] " __DATE__ " " __TIME__ "\n\r";
|
|
|
|
/* b_terminal_mode mode (ascii) or hex mode */
|
|
#if USE_CDC_TERMINAL
|
|
volatile bool b_terminal_mode = false;
|
|
#endif
|
|
volatile bool b_sam_ba_interface_usart = false;
|
|
|
|
void sam_ba_monitor_init(uint8_t com_interface) {
|
|
#if USE_UART
|
|
// Selects the requested interface for future actions
|
|
if (com_interface == SAM_BA_INTERFACE_USART) {
|
|
b_sam_ba_interface_usart = true;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* \brief This function allows data rx by USART
|
|
*
|
|
* \param *data Data pointer
|
|
* \param length Length of the data
|
|
*/
|
|
void sam_ba_putdata_term(uint8_t *data, uint32_t length) {
|
|
#if USE_CDC_TERMINAL
|
|
uint8_t temp, buf[12], *data_ascii;
|
|
uint32_t i, int_value;
|
|
|
|
if (b_terminal_mode) {
|
|
if (length == 4)
|
|
int_value = *(uint32_t *)(void *)data;
|
|
else if (length == 2)
|
|
int_value = *(uint16_t *)(void *)data;
|
|
else
|
|
int_value = *(uint8_t *)(void *)data;
|
|
|
|
data_ascii = buf + 2;
|
|
data_ascii += length * 2 - 1;
|
|
|
|
for (i = 0; i < length * 2; i++) {
|
|
temp = (uint8_t)(int_value & 0xf);
|
|
|
|
if (temp <= 0x9)
|
|
*data_ascii = temp | 0x30;
|
|
else
|
|
*data_ascii = temp + 0x37;
|
|
|
|
int_value >>= 4;
|
|
data_ascii--;
|
|
}
|
|
buf[0] = '0';
|
|
buf[1] = 'x';
|
|
buf[length * 2 + 2] = '\n';
|
|
buf[length * 2 + 3] = '\r';
|
|
cdc_write_buf(buf, length * 2 + 4);
|
|
} else
|
|
#endif
|
|
cdc_write_buf(data, length);
|
|
return;
|
|
}
|
|
|
|
volatile uint32_t sp;
|
|
void call_applet(uint32_t address) {
|
|
uint32_t app_start_address;
|
|
|
|
/* Save current Stack Pointer */
|
|
sp = __get_MSP();
|
|
|
|
/* Rebase the Stack Pointer */
|
|
__set_MSP(*(uint32_t *)address);
|
|
|
|
/* Load the Reset Handler address of the application */
|
|
app_start_address = *(uint32_t *)(address + 4);
|
|
|
|
/* Jump to application Reset Handler in the application */
|
|
asm("blx %0" ::"r"(app_start_address):"r0","r1","r2","r3","lr");
|
|
|
|
/* Rebase the Stack Pointer */
|
|
__set_MSP(sp);
|
|
}
|
|
|
|
uint32_t current_number;
|
|
uint32_t i, length;
|
|
uint8_t command, *ptr_data, *ptr, data[SIZEBUFMAX + 1];
|
|
uint8_t j;
|
|
uint32_t u32tmp;
|
|
|
|
// Prints a 32-bit integer in hex.
|
|
void put_uint32(uint32_t n) {
|
|
char buff[8];
|
|
writeNum(buff, n, true);
|
|
cdc_write_buf(buff, 8);
|
|
}
|
|
|
|
/**
|
|
* \brief This function starts the SAM-BA monitor.
|
|
*/
|
|
void sam_ba_monitor_run(void) {
|
|
ptr_data = NULL;
|
|
command = 'z';
|
|
|
|
// Start waiting some cmd
|
|
while (1) {
|
|
process_msc();
|
|
length = cdc_read_buf(data, SIZEBUFMAX);
|
|
data[length] = 0;
|
|
if (length) {
|
|
logwrite("SERIAL:");
|
|
logmsg(data);
|
|
led_signal();
|
|
}
|
|
ptr = data;
|
|
for (i = 0; i < length; i++) {
|
|
if (*ptr != 0xff) {
|
|
if (*ptr == '#') {
|
|
#if USE_CDC_TERMINAL
|
|
if (b_terminal_mode) {
|
|
cdc_write_buf("\n\r", 2);
|
|
}
|
|
#endif
|
|
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 = (length - i) < current_number ? (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)
|
|
cdc_read_buf_xmd(ptr_data, current_number - j);
|
|
|
|
__asm("nop");
|
|
} else if (command == 'R') {
|
|
cdc_write_buf_xmd(ptr_data, current_number);
|
|
} else if (command == 'O') {
|
|
*ptr_data = (char)current_number;
|
|
} else if (command == 'H') {
|
|
*((uint16_t *)(void *)ptr_data) = (uint16_t)current_number;
|
|
} else if (command == 'W') {
|
|
// detect BOSSA resetting us
|
|
if ((uint32_t)ptr_data == 0xE000ED0C)
|
|
RGBLED_set_color(COLOR_LEAVE);
|
|
*((int *)(void *)ptr_data) = current_number;
|
|
} else if (command == 'o') {
|
|
sam_ba_putdata_term(ptr_data, 1);
|
|
} else if (command == 'h') {
|
|
current_number = *((uint16_t *)(void *)ptr_data);
|
|
sam_ba_putdata_term((uint8_t *)¤t_number, 2);
|
|
} else if (command == 'w') {
|
|
current_number = *((uint32_t *)(void *)ptr_data);
|
|
sam_ba_putdata_term((uint8_t *)¤t_number, 4);
|
|
} else if (command == 'G') {
|
|
call_applet(current_number);
|
|
if (b_sam_ba_interface_usart) {
|
|
cdc_write_buf("\x06", 1);
|
|
}
|
|
} else if (command == 'T') {
|
|
#if USE_CDC_TERMINAL
|
|
b_terminal_mode = 1;
|
|
cdc_write_buf("\n\r", 2);
|
|
#endif
|
|
} else if (command == 'N') {
|
|
#if USE_CDC_TERMINAL
|
|
if (b_terminal_mode == 0) {
|
|
cdc_write_buf("\n\r", 2);
|
|
}
|
|
b_terminal_mode = 0;
|
|
#endif
|
|
} else if (command == 'V') {
|
|
cdc_write_buf(fullVersion, sizeof(fullVersion));
|
|
} else if (command == 'X') {
|
|
// Syntax: X[ADDR]#
|
|
// Erase the flash memory starting from ADDR to the end
|
|
// of flash.
|
|
|
|
flash_erase_to_end((uint32_t *) current_number);
|
|
|
|
// Notify command completed
|
|
cdc_write_buf("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 = (void *)ptr_data;
|
|
|
|
} else {
|
|
flash_write_words((void *)ptr_data, src_buff_addr, current_number / 4);
|
|
}
|
|
|
|
// Notify command completed
|
|
cdc_write_buf("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
|
|
cdc_write_buf("Z", 1);
|
|
put_uint32(crc);
|
|
cdc_write_buf("#\n\r", 3);
|
|
}
|
|
|
|
command = 'z';
|
|
current_number = 0;
|
|
#if USE_CDC_TERMINAL
|
|
if (b_terminal_mode) {
|
|
cdc_write_buf(">", 1);
|
|
}
|
|
#endif
|
|
} 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;
|
|
}
|
|
}
|
|
ptr++;
|
|
}
|
|
}
|
|
}
|
|
}
|