/**************************************************************************//** \brief Function to do an erase-write on one page in the flash. \note The maximum pageAddress must not be exceeded. The maximum number of pages can be found in the datasheet. \param[in] pageAddress Page address to the page to erase/write. ******************************************************************************/ static void flashEraseWritePage(uint16_t pageAddress) { // Calculate actual start address of the page. uint32_t tableAddress = (uint32_t)pageAddress * (uint32_t)FLASH_PAGE_SIZE; // Perform page erase. SP_EraseApplicationPage(tableAddress); // Wait for SPM to finish. flashWaitForSPM(); // Perform page write. SP_WriteApplicationPage(tableAddress); // Wait for SPM to finish. flashWaitForSPM(); // enable rww section SP_RWWSectionEnable(); // Wait for SPM to finish. flashWaitForSPM(); }
void pollEndpoint(void){ if (USB_ep_out_received(1)){ pageOffs += EP1_SIZE; if (pageOffs == APP_SECTION_PAGE_SIZE){ // Write a page to flash SP_LoadFlashPage(pageBuf); NVM.CMD = NVM_CMD_NO_OPERATION_gc; SP_WriteApplicationPage(page*APP_SECTION_PAGE_SIZE); SP_WaitForSPM(); NVM.CMD = NVM_CMD_NO_OPERATION_gc; page++; pageOffs = 0; } if (page * APP_SECTION_PAGE_SIZE < APP_SECTION_END){ // If there's remaining room in flash, configure the endpoint to accept more data USB_ep_out_start(1, &pageBuf[pageOffs]); } } }
/************************************************************************************************** * Handle received HID set feature reports */ void HID_set_feature_report_out(uint8_t *report) { uint8_t response[UDI_HID_REPORT_OUT_SIZE]; response[0] = report[0] | 0x80; response[1] = report[1]; response[2] = report[2]; uint16_t addr; addr = *(uint16_t *)(report+1); switch(report[0]) { // no-op case CMD_NOP: break; // write to RAM page buffer case CMD_RESET_POINTER: page_ptr = 0; return; // read from RAM page buffer case CMD_READ_BUFFER: memcpy(response, &page_buffer[page_ptr], UDI_HID_REPORT_OUT_SIZE); page_ptr += UDI_HID_REPORT_OUT_SIZE; page_ptr &= APP_SECTION_PAGE_SIZE-1; break; // erase entire application section case CMD_ERASE_APP_SECTION: SP_WaitForSPM(); SP_EraseApplicationSection(); return; // calculate application and bootloader section CRCs case CMD_READ_FLASH_CRCS: SP_WaitForSPM(); *(uint32_t *)&response[3] = SP_ApplicationCRC(); *(uint32_t *)&response[7] = SP_BootCRC(); break; // read MCU IDs case CMD_READ_MCU_IDS: response[3] = MCU.DEVID0; response[4] = MCU.DEVID1; response[5] = MCU.DEVID2; response[6] = MCU.REVID; break; // read fuses case CMD_READ_FUSES: response[3] = SP_ReadFuseByte(0); response[4] = SP_ReadFuseByte(1); response[5] = SP_ReadFuseByte(2); response[6] = 0xFF; response[7] = SP_ReadFuseByte(4); response[8] = SP_ReadFuseByte(5); break; // write RAM page buffer to application section page case CMD_WRITE_PAGE: if (addr > (APP_SECTION_SIZE / APP_SECTION_PAGE_SIZE)) // out of range { response[1] = 0xFF; response[2] = 0xFF; break; } SP_WaitForSPM(); SP_LoadFlashPage(page_buffer); SP_WriteApplicationPage(APP_SECTION_START + ((uint32_t)addr * APP_SECTION_PAGE_SIZE)); page_ptr = 0; break; // read application page to RAM buffer and return first 32 bytes case CMD_READ_PAGE: if (addr > (APP_SECTION_SIZE / APP_SECTION_PAGE_SIZE)) // out of range { response[1] = 0xFF; response[2] = 0xFF; } else { memcpy_P(page_buffer, (const void *)(APP_SECTION_START + (APP_SECTION_PAGE_SIZE * addr)), APP_SECTION_PAGE_SIZE); memcpy(&response[3], page_buffer, 32); page_ptr = 0; } break; // erase user signature row case CMD_ERASE_USER_SIG_ROW: SP_WaitForSPM(); SP_EraseUserSignatureRow(); break; // write RAM buffer to user signature row case CMD_WRITE_USER_SIG_ROW: SP_WaitForSPM(); SP_LoadFlashPage(page_buffer); SP_WriteUserSignatureRow(); break; // read user signature row to RAM buffer and return first 32 bytes case CMD_READ_USER_SIG_ROW: if (addr > (USER_SIGNATURES_PAGE_SIZE - 32)) { response[1] = 0xFF; response[2] = 0xFF; } else { memcpy_P(page_buffer, (const void *)(USER_SIGNATURES_START + addr), USER_SIGNATURES_SIZE); memcpy(&response[3], page_buffer, 32); page_ptr = 0; } break; case CMD_READ_SERIAL: { uint8_t i; uint8_t j = 3; uint8_t b; for (i = 0; i < 6; i++) { b = SP_ReadCalibrationByte(offsetof(NVM_PROD_SIGNATURES_t, LOTNUM0) + i); response[j++] = hex_to_char(b >> 4); response[j++] = hex_to_char(b & 0x0F); } response[j++] = '-'; b = SP_ReadCalibrationByte(offsetof(NVM_PROD_SIGNATURES_t, LOTNUM0) + 6); response[j++] = hex_to_char(b >> 4); response[j++] = hex_to_char(b & 0x0F); response[j++] = '-'; for (i = 7; i < 11; i++) { b = SP_ReadCalibrationByte(offsetof(NVM_PROD_SIGNATURES_t, LOTNUM0) + i); response[j++] = hex_to_char(b >> 4); response[j++] = hex_to_char(b & 0x0F); } response[j] = '\0'; break; } case CMD_READ_BOOTLOADER_VERSION: response[3] = BOOTLOADER_VERSION; break; case CMD_RESET_MCU: reset_do_soft_reset(); response[1] = 0xFF; // failed break; case CMD_READ_EEPROM: if (addr > (EEPROM_SIZE - 32)) { response[1] = 0xFF; response[2] = 0xFF; } else { EEP_EnableMapping(); memcpy_P(page_buffer, (const void *)(MAPPED_EEPROM_START + addr), APP_SECTION_PAGE_SIZE); EEP_DisableMapping(); memcpy(&response[3], page_buffer, 32); page_ptr = 0; } break; case CMD_WRITE_EEPROM: if (addr > (EEPROM_SIZE / EEPROM_PAGE_SIZE)) { response[1] = 0xFF; response[2] = 0xFF; } else { EEP_LoadPageBuffer(&report[3], EEPROM_PAGE_SIZE); EEP_AtomicWritePage(addr); } break; // unknown command default: response[0] = 0xFF; break; } udi_hid_generic_send_report_in(response); }