diff --git a/bootloaders/zero/drivers/cdc_enumerate.c b/bootloaders/zero/drivers/cdc_enumerate.c index 3bb4fd6e587c7d4a2333e1afe65fe3b10f6c4708..5dda45ffb633d991179b387242511938e7ce4537 100644 --- a/bootloaders/zero/drivers/cdc_enumerate.c +++ b/bootloaders/zero/drivers/cdc_enumerate.c @@ -750,5 +750,16 @@ uint32_t cdc_read_buf_xmd(void* data, uint32_t length) return 0; /* Blocking read till specified number of bytes is received */ - return USB_Read_blocking(&pCdc, (char *)data, length); + // XXX: USB_Read_blocking is not reliable + // return USB_Read_blocking(&pCdc, (char *)data, length); + + char *dst = (char *)data; + uint32_t remaining = length; + while (remaining) { + uint32_t readed = USB_Read(&pCdc, (char *)dst, remaining); + remaining -= readed; + dst += readed; + } + + return length; } diff --git a/bootloaders/zero/sam_ba_monitor.c b/bootloaders/zero/sam_ba_monitor.c index 1df6d0437017094c0b635edf36406d9b36f9a24f..29c9d8566be932144130fa75d6422affe772a9c1 100644 --- a/bootloaders/zero/sam_ba_monitor.c +++ b/bootloaders/zero/sam_ba_monitor.c @@ -36,6 +36,7 @@ #include "cdc_enumerate.h" const char RomBOOT_Version[] = SAM_BA_VERSION; +const char RomBOOT_ExtendedCapabilities[] = "[Arduino:XYZ]"; /* Provides one common interface to handle both USART and USB-CDC */ typedef struct @@ -166,169 +167,288 @@ uint8_t command, *ptr_data, *ptr, data[SIZEBUFMAX]; uint8_t j; uint32_t u32tmp; +uint32_t PAGE_SIZE, PAGES, MAX_FLASH; /** * \brief This function starts the SAM-BA monitor. */ void sam_ba_monitor_run(void) { + uint32_t pageSizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024 }; + PAGE_SIZE = pageSizes[NVMCTRL->PARAM.bit.PSZ]; + PAGES = NVMCTRL->PARAM.bit.NVMP; + MAX_FLASH = PAGE_SIZE * PAGES; + ptr_data = NULL; command = 'z'; - - // Start waiting some cmd - while (1) + while (1) { + sam_ba_monitor_loop(); + } +} + +// Prints a 32-bit integer in hex. +void put_uint32(uint32_t n) { + char buff[8]; + int i; + for (i=0; i<8; i++) { + int d = n & 0XF; + n = (n >> 4); + + buff[7-i] = d > 9 ? 'A' + d - 10 : '0' + d; + } + ptr_monitor_if->putdata(buff, 8); +} + +void sam_ba_monitor_loop(void) +{ + length = ptr_monitor_if->getdata(data, SIZEBUFMAX); + ptr = data; + for (i = 0; i < length; i++, ptr++) { - length = ptr_monitor_if->getdata(data, SIZEBUFMAX); - ptr = data; - for (i = 0; i < length; i++) + if (*ptr == 0xff) continue; + + if (*ptr == '#') { - if (*ptr != 0xff) + if (b_terminal_mode) { - if (*ptr == '#') + ptr_monitor_if->putdata("\n\r", 2); + } + if (command == 'S') + { + //Check if some data are remaining in the "data" buffer + if(length>i) { - 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*) ¤t_number, 2); - } - else if (command == 'w') - { - current_number = *((uint32_t *) ptr_data); - sam_ba_putdata_term((uint8_t*) ¤t_number, 4); - } - else if (command == 'G') - { - call_applet(current_number); - /* Rebase the Stack Pointer */ - __set_MSP(sp); - cpu_irq_enable(); - if (b_sam_ba_interface_usart) { - ptr_monitor_if->put_c(0x6); - } - } - else if (command == 'T') - { - b_terminal_mode = 1; - ptr_monitor_if->putdata("\n\r", 2); - } - else if (command == 'N') - { - if (b_terminal_mode == 0) - { - ptr_monitor_if->putdata("\n\r", 2); - } - b_terminal_mode = 0; - } - else if (command == 'V') - { - ptr_monitor_if->putdata("v", 1); - ptr_monitor_if->putdata((uint8_t *) RomBOOT_Version, - strlen(RomBOOT_Version)); - ptr_monitor_if->putdata(" ", 1); - ptr = (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); - } + //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*) ¤t_number, 2); + } + else if (command == 'w') + { + current_number = *((uint32_t *) ptr_data); + sam_ba_putdata_term((uint8_t*) ¤t_number, 4); + } + else if (command == 'G') + { + call_applet(current_number); + /* Rebase the Stack Pointer */ + __set_MSP(sp); + cpu_irq_enable(); + if (b_sam_ba_interface_usart) { + ptr_monitor_if->put_c(0x6); + } + } + else if (command == 'T') + { + b_terminal_mode = 1; + ptr_monitor_if->putdata("\n\r", 2); + } + else if (command == 'N') + { + if (b_terminal_mode == 0) + { + ptr_monitor_if->putdata("\n\r", 2); + } + b_terminal_mode = 0; + } + else if (command == 'V') + { + ptr_monitor_if->putdata("v", 1); + ptr_monitor_if->putdata((uint8_t *) RomBOOT_Version, + strlen(RomBOOT_Version)); + ptr_monitor_if->putdata(" ", 1); + ptr_monitor_if->putdata((uint8_t *) RomBOOT_ExtendedCapabilities, + strlen(RomBOOT_ExtendedCapabilities)); + ptr_monitor_if->putdata(" ", 1); + ptr = (uint8_t*) &(__DATE__); + i = 0; + while (*ptr++ != '\0') + i++; + ptr_monitor_if->putdata((uint8_t *) &(__DATE__), i); + ptr_monitor_if->putdata(" ", 1); + i = 0; + ptr = (uint8_t*) &(__TIME__); + while (*ptr++ != '\0') + i++; + ptr_monitor_if->putdata((uint8_t *) &(__TIME__), i); + ptr_monitor_if->putdata("\n\r", 2); + } + else if (command == 'X') + { + // Syntax: X[ADDR]# + // Erase the flash memory starting from ADDR to the end of flash. - command = 'z'; - current_number = 0; + // 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. - if (b_terminal_mode) - { - ptr_monitor_if->putdata(">", 1); - } + 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 } - 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); + // 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. - } - else if (('a' <= *ptr) && (*ptr <= 'f')) - { - current_number = (current_number << 4) - | (*ptr - 'a' + 0xa); + // Syntax: Y[ADDR],0# + // Set the starting address of the SRAM buffer. - } - else if (*ptr == ',') - { - ptr_data = (uint8_t *) current_number; - current_number = 0; + // Syntax: Y[ROM_ADDR],[SIZE]# + // Write the first SIZE bytes from the SRAM buffer (previously set) into + // flash memory starting from address ROM_ADDR - } - else - { - command = *ptr; - current_number = 0; + 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; } } - ptr++; + + // 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; } } } } + + + + diff --git a/bootloaders/zero/samd21_sam_ba.bin b/bootloaders/zero/samd21_sam_ba.bin index 042c36320aa8edf90875b9cbc5ed4d23beebcac2..69ced0a312f83d769f7f62e0fe460551481eadce 100644 Binary files a/bootloaders/zero/samd21_sam_ba.bin and b/bootloaders/zero/samd21_sam_ba.bin differ diff --git a/bootloaders/zero/usart_sam_ba.c b/bootloaders/zero/usart_sam_ba.c index f17f319554a93d80831bc4d29340d97ac14089d0..645e725e953e661994c434bae14f541064aa60b7 100644 --- a/bootloaders/zero/usart_sam_ba.c +++ b/bootloaders/zero/usart_sam_ba.c @@ -203,24 +203,47 @@ uint32_t usart_getdata(void* data, uint32_t length) { return (1); } +static const uint16_t crc16Table[256] = { + 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, + 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, + 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, + 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, + 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, + 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, + 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, + 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, + 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, + 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, + 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, + 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, + 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, + 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, + 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, + 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, + 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, + 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, + 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, + 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, + 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, + 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, + 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, + 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, + 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, + 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, + 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, + 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, + 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, + 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, + 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, + 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 +}; + //*---------------------------------------------------------------------------- //* \fn add_crc //* \brief Compute the CRC //*---------------------------------------------------------------------------- unsigned short add_crc(char ptr, unsigned short crc) { - - unsigned short cmpt; - - crc = crc ^ (int) ptr << 8; - - for (cmpt = 0; cmpt < 8; cmpt++) { - if (crc & 0x8000) - crc = crc << 1 ^ CRC16POLY; - else - crc = crc << 1; - } - - return (crc & 0xFFFF); + return (crc << 8) ^ crc16Table[((crc >> 8) ^ ptr) & 0xff]; } //*---------------------------------------------------------------------------- diff --git a/bootloaders/zero/usart_sam_ba.h b/bootloaders/zero/usart_sam_ba.h index f319d049157428cb95a1e7494d75a42eeefe0f34..d498dc791f41739bea2d60e8b221524d7fd6e91a 100644 --- a/bootloaders/zero/usart_sam_ba.h +++ b/bootloaders/zero/usart_sam_ba.h @@ -142,13 +142,13 @@ uint32_t usart_putdata_xmd(void const* data, uint32_t length); //Send given data uint32_t usart_getdata_xmd(void* data, uint32_t length); //Get data from comm. device using xmodem (if necessary) /** - * \brief Gets data from usart line using Xmodem protocol + * \brief Compute the CRC * - * \param data pointer - * \param number of data to get - * \return value read on usart line + * \param Char to add to CRC + * \param Previous CRC + * \return The new computed CRC */ -unsigned short add_crc(char ptr, unsigned short crc); +unsigned short add_crc(char c, unsigned short crc); uint8_t getPacket(uint8_t *pData, uint8_t sno); diff --git a/platform.txt b/platform.txt index 6bca9e4c633d0b943fe97554ad984d4bda7b05c4..0f9ebb08285c40a1d135d3882d574315facdd7a2 100644 --- a/platform.txt +++ b/platform.txt @@ -80,7 +80,7 @@ recipe.size.regex=\.text\s+([0-9]+).* # tools.bossac.cmd=bossac tools.bossac.cmd.windows=bossac.exe -tools.bossac.path={runtime.ide.path}/hardware/tools/bossac-1.4-arduino +tools.bossac.path={runtime.ide.path}/hardware/tools/bossac-1.5-arduino tools.bossac.upload.params.verbose=-i -d tools.bossac.upload.params.quiet=