int flashPageErase(flashpage_t page){ /* Only write on pages in the user area */ if (!(FLASH_IS_ADDRESS_USERSPACE(FLASH_ADDRESS_OF_PAGE(page)))) return FLASH_RETURN_NO_PERMISSION; /* Unlock flash for write access */ if(flashUnlock() == CH_FAILED) return FLASH_RETURN_NO_PERMISSION; /* Wait for any busy flags. */ flashWaitWhileBusy(); /* Start deletion of page. */ FLASH->CR |= FLASH_CR_PER; FLASH->AR = FLASH_ADDRESS_OF_PAGE(page); FLASH->CR |= FLASH_CR_STRT; /* Wait until it's finished. */ flashWaitWhileBusy(); /* Page erase flag does not clear automatically. */ FLASH->CR &= !FLASH_CR_PER; /* Lock flash again */ flashLock(); /* Check deleted page for errors */ if(flashPageCheckErased(page) == FALSE) return FLASH_RETURN_BADFLASH; /* Page is not empty despite the erase cycle! */ /* Successfully deleted page */ return FLASH_RETURN_SUCCESS; }
int flashSectorErase(flashsector_t sector) { /* Unlock flash for write access */ if (flashUnlock() == CH_FAILED) return FLASH_RETURN_NO_PERMISSION; /* Wait for any busy flags. */ flashWaitWhileBusy(); /* Setup parallelism before any program/erase */ FLASH->CR &= ~FLASH_CR_PSIZE_MASK; FLASH->CR |= FLASH_CR_PSIZE_VALUE; /* Start deletion of sector. * SNB(3:1) is defined as: * 0000 sector 0 * 0001 sector 1 * ... * 1011 sector 11 * others not allowed */ FLASH->CR &= ~(FLASH_CR_SNB_0 | FLASH_CR_SNB_1 | FLASH_CR_SNB_2 | FLASH_CR_SNB_3); if (sector & 0x1) FLASH->CR |= FLASH_CR_SNB_0; if (sector & 0x2) FLASH->CR |= FLASH_CR_SNB_1; if (sector & 0x4) FLASH->CR |= FLASH_CR_SNB_2; if (sector & 0x8) FLASH->CR |= FLASH_CR_SNB_3; FLASH->CR |= FLASH_CR_SER; FLASH->CR |= FLASH_CR_STRT; /* Wait until it's finished. */ flashWaitWhileBusy(); /* Sector erase flag does not clear automatically. */ FLASH->CR &= ~FLASH_CR_SER; /* Lock flash again */ flashLock() ; /* Check deleted sector for errors */ if (flashIsErased(flashSectorBegin(sector), flashSectorSize(sector)) == FALSE) return FLASH_RETURN_BAD_FLASH; /* Sector is not empty despite the erase cycle! */ /* Successfully deleted sector */ return FLASH_RETURN_SUCCESS; }
void upgradeFwWriteSegments(uint8 *buf, uint8 len) { uint8 i; flashUnlock(); flashEnableWrite(); for (i=0; i<len; i++) { *g_firmwareWritePtr = buf[i]; while(flashWriteBusy()); g_firmwareWritePtr++; } flashDisableWrite(); while(flashBusy()); flashLock(); return ; }
int flashPageWrite(flashpage_t page, const flashdata_t* buffer){ volatile flashdata_t* const pageAddr = (flashdata_t*) FLASH_ADDRESS_OF_PAGE(page); /* Only write on pages in the user area */ if (!(FLASH_IS_ADDRESS_USERSPACE(FLASH_ADDRESS_OF_PAGE(page)))) return FLASH_RETURN_NO_PERMISSION; unsigned int pos; /* Unlock flash for write access */ if(flashUnlock() == CH_FAILED) return FLASH_RETURN_NO_PERMISSION; flashWaitWhileBusy(); for(pos = 0; pos < FLASH_PAGE_SIZE / sizeof(flashdata_t); pos++) { /* Enter flash programming mode. */ FLASH->CR |= FLASH_CR_PG; /* Write half-word to flash. */ pageAddr[pos] = buffer[pos]; /* Wait for completion */ flashWaitWhileBusy(); /* Exit flash programming mode. */ FLASH->CR &= ~FLASH_CR_PG; /* Check for flash error. */ if (pageAddr[pos] != buffer[pos]) return FLASH_RETURN_BADFLASH; } flashLock(); return 0; }
bool dfuUpdateByRequest(void) { /* were using the global pInformation struct from usb_lib here, see comment in maple_dfu.h around DFUEvent struct */ dfuBusy = TRUE; u8 startState = dfuAppStatus.bState; dfuAppStatus.bStatus = OK; /* often leaner to nest if's then embed a switch/case */ if (startState == dfuIDLE) { /* device running inside DFU mode */ dfuBusy = TRUE; // signals the main loop to defer to the dfu write-loop if (pInformation->USBbRequest == DFU_DNLOAD) { if (pInformation->USBwLengths.w > 0) { userFirmwareLen = 0; dfuAppStatus.bState = dfuDNLOAD_SYNC; if (pInformation->Current_AlternateSetting == 1) { userAppAddr = USER_CODE_FLASH; userFlash = TRUE; /* make sure the flash is setup properly, unlock it */ setupFLASH(); flashUnlock(); } else { userAppAddr = USER_CODE_RAM; userFlash = FALSE; } } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errNOTDONE; } } else if (pInformation->USBbRequest == DFU_UPLOAD) { dfuAppStatus.bState = dfuUPLOAD_IDLE; } else if (pInformation->USBbRequest == DFU_ABORT) { dfuAppStatus.bState = dfuIDLE; dfuAppStatus.bStatus = OK; /* are we really ok? we were just aborted */ } else if (pInformation->USBbRequest == DFU_GETSTATUS) { dfuAppStatus.bState = dfuIDLE; } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuIDLE; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else if (startState == dfuDNLOAD_SYNC) { /* device received block, waiting for DFU_GETSTATUS request */ if (pInformation->USBbRequest == DFU_GETSTATUS) { /* todo, add routine to wait for last block write to finish */ if (userFlash) { if (code_copy_lock==WAIT) { code_copy_lock=BEGINNING; dfuAppStatus.bwPollTimeout0 = 0xFF; /* is this enough? */ dfuAppStatus.bwPollTimeout1 = 0x01; /* is this enough? */ dfuAppStatus.bState=dfuDNBUSY; } else if (code_copy_lock==BEGINNING) { dfuAppStatus.bState=dfuDNLOAD_SYNC; } else if (code_copy_lock==MIDDLE) { dfuAppStatus.bState=dfuDNLOAD_SYNC; } else if (code_copy_lock==END) { dfuAppStatus.bwPollTimeout0 = 0x00; code_copy_lock=WAIT; dfuAppStatus.bState=dfuDNLOAD_IDLE; } } else { dfuAppStatus.bState = dfuDNLOAD_IDLE; dfuCopyBufferToExec(); } } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuDNLOAD_SYNC; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else if (startState == dfuDNBUSY) { /* if were actually done writing, goto sync, else stay busy */ if (code_copy_lock == END) { dfuAppStatus.bwPollTimeout0 = 0x00; code_copy_lock=WAIT; dfuAppStatus.bState = dfuDNLOAD_IDLE; } else { dfuAppStatus.bState= dfuDNBUSY; } } else if (startState == dfuDNLOAD_IDLE) { /* device is expecting dfu_dnload requests */ if (pInformation->USBbRequest == DFU_DNLOAD) { if (pInformation->USBwLengths.w > 0) { dfuAppStatus.bState = dfuDNLOAD_SYNC; } else { /* todo, support "disagreement" if device expects more data than this */ dfuAppStatus.bState = dfuMANIFEST_SYNC; /* relock the flash */ flashLock(); } } else if (pInformation->USBbRequest == DFU_ABORT) { dfuAppStatus.bState = dfuIDLE; } else if (pInformation->USBbRequest == DFU_GETSTATUS) { dfuAppStatus.bState = dfuIDLE; } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuIDLE; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else if (startState == dfuMANIFEST_SYNC) { /* device has received last block, waiting DFU_GETSTATUS request */ if (pInformation->USBbRequest == DFU_GETSTATUS) { dfuAppStatus.bState = dfuMANIFEST_WAIT_RESET; dfuAppStatus.bStatus = OK; } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuMANIFEST_SYNC; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else if (startState == dfuMANIFEST) { /* device is in manifestation phase */ /* should never receive request while in manifest! */ dfuAppStatus.bState = dfuMANIFEST_WAIT_RESET; dfuAppStatus.bStatus = OK; } else if (startState == dfuMANIFEST_WAIT_RESET) { /* device has programmed new firmware but needs external usb reset or power on reset to run the new code */ /* consider timing out and self-resetting */ dfuAppStatus.bState = dfuMANIFEST_WAIT_RESET; } else if (startState == dfuUPLOAD_IDLE) { /* device expecting further dfu_upload requests */ if (pInformation->USBbRequest == DFU_UPLOAD) { /* todo, add routine to wait for last block write to finish */ dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } else if (pInformation->USBbRequest == DFU_ABORT) { dfuAppStatus.bState = dfuIDLE; } else if (pInformation->USBbRequest == DFU_GETSTATUS) { dfuAppStatus.bState = dfuUPLOAD_IDLE; } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuUPLOAD_IDLE; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else if (startState == dfuERROR) { /* status is in error, awaiting DFU_CLRSTATUS request */ if (pInformation->USBbRequest == DFU_GETSTATUS) { /* todo, add routine to wait for last block write to finish */ dfuAppStatus.bState = dfuERROR; } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuERROR; } else if (pInformation->USBbRequest == DFU_CLRSTATUS) { /* todo handle any cleanup we need here */ dfuAppStatus.bState = dfuIDLE; dfuAppStatus.bStatus = OK; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else { /* some kind of error... */ dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } if (dfuAppStatus.bStatus == OK) { return TRUE; } else { return FALSE; } }
bool dfuUpdateByRequest(void) { /* were using the global pInformation struct from usb_lib here, see comment in maple_dfu.h around DFUEvent struct */ dfuBusy = TRUE; u8 startState = dfuAppStatus.bState; dfuAppStatus.bStatus = OK; /* often leaner to nest if's then embed a switch/case */ if (startState == dfuIDLE) { /* device running inside DFU mode */ dfuBusy = TRUE; // signals the main loop to defer to the dfu write-loop if (pInformation->USBbRequest == DFU_DNLOAD) { if (pInformation->USBwLengths.w > 0) { userFirmwareLen = 0; dfuAppStatus.bState = dfuDNLOAD_SYNC; if (pInformation->Current_AlternateSetting == 1) { userAppAddr = USER_CODE_FLASH; userFlash = TRUE; /* make sure the flash is setup properly, unlock it */ setupFLASH(); flashUnlock(); } else { userAppAddr = USER_CODE_RAM; userFlash = FALSE; } } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errNOTDONE; } } else if (pInformation->USBbRequest == DFU_UPLOAD) { dfuAppStatus.bState = dfuUPLOAD_IDLE; /* record length of first block for calculating target address from wValue in consecutive blocks */ uploadBlockLen = pInformation->USBwLengths.w; thisBlockLen = uploadBlockLen; /* for this first block as well */ /* calculate where the data should be copied from */ userFirmwareLen = uploadBlockLen * pInformation->USBwValue; if (pInformation->Current_AlternateSetting == 1) { userAppAddr = USER_CODE_FLASH; userAppEnd = FLASH_END; } else { userAppAddr = USER_CODE_RAM; userAppEnd = RAM_END; } } else if (pInformation->USBbRequest == DFU_ABORT) { dfuAppStatus.bState = dfuIDLE; dfuAppStatus.bStatus = OK; /* are we really ok? we were just aborted */ } else if (pInformation->USBbRequest == DFU_GETSTATUS) { dfuAppStatus.bState = dfuIDLE; } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuIDLE; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else if (startState == dfuDNLOAD_SYNC) { /* device received block, waiting for DFU_GETSTATUS request */ if (pInformation->USBbRequest == DFU_GETSTATUS) { /* todo, add routine to wait for last block write to finish */ if (userFlash) { if (code_copy_lock == WAIT) { code_copy_lock = BEGINNING; dfuAppStatus.bwPollTimeout0 = 0x20; /* 32 ms */ dfuAppStatus.bwPollTimeout1 = 0x00; dfuAppStatus.bState = dfuDNBUSY; } else if (code_copy_lock == BEGINNING) { dfuAppStatus.bState = dfuDNLOAD_SYNC; } else if (code_copy_lock == MIDDLE) { dfuAppStatus.bState = dfuDNLOAD_SYNC; } else if (code_copy_lock == END) { dfuAppStatus.bwPollTimeout0 = 0x00; code_copy_lock = WAIT; dfuAppStatus.bState = dfuDNLOAD_IDLE; } } else { dfuAppStatus.bState = dfuDNLOAD_IDLE; dfuCopyBufferToExec(); } } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuDNLOAD_SYNC; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else if (startState == dfuDNBUSY) { /* if were actually done writing, goto sync, else stay busy */ if (code_copy_lock == END) { dfuAppStatus.bwPollTimeout0 = 0x00; code_copy_lock = WAIT; dfuAppStatus.bState = dfuDNLOAD_IDLE; } else { dfuAppStatus.bState = dfuDNBUSY; } } else if (startState == dfuDNLOAD_IDLE) { /* device is expecting dfu_dnload requests */ if (pInformation->USBbRequest == DFU_DNLOAD) { if (pInformation->USBwLengths.w > 0) { dfuAppStatus.bState = dfuDNLOAD_SYNC; } else { /* todo, support "disagreement" if device expects more data than this */ dfuAppStatus.bState = dfuMANIFEST_SYNC; /* relock the flash */ flashLock(); } } else if (pInformation->USBbRequest == DFU_ABORT) { dfuAppStatus.bState = dfuIDLE; } else if (pInformation->USBbRequest == DFU_GETSTATUS) { dfuAppStatus.bState = dfuIDLE; } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuIDLE; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else if (startState == dfuMANIFEST_SYNC) { /* device has received last block, waiting DFU_GETSTATUS request */ if (pInformation->USBbRequest == DFU_GETSTATUS) { dfuAppStatus.bState = dfuMANIFEST_WAIT_RESET; dfuAppStatus.bStatus = OK; } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuMANIFEST_SYNC; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else if (startState == dfuMANIFEST) { /* device is in manifestation phase */ /* should never receive request while in manifest! */ dfuAppStatus.bState = dfuMANIFEST_WAIT_RESET; dfuAppStatus.bStatus = OK; } else if (startState == dfuMANIFEST_WAIT_RESET) { /* device has programmed new firmware but needs external usb reset or power on reset to run the new code */ /* consider timing out and self-resetting */ dfuAppStatus.bState = dfuMANIFEST_WAIT_RESET; } else if (startState == dfuUPLOAD_IDLE) { /* device expecting further dfu_upload requests */ if (pInformation->USBbRequest == DFU_UPLOAD) { if (pInformation->USBwLengths.w > 0) { /* check that this is not the last possible block */ userFirmwareLen = uploadBlockLen * pInformation->USBwValue; if (userAppAddr + userFirmwareLen + uploadBlockLen <= userAppEnd) { thisBlockLen = uploadBlockLen; dfuAppStatus.bState = dfuUPLOAD_IDLE; } else { /* if above comparison was just equal, thisBlockLen becomes zero next time when USBWValue has been increased by one */ thisBlockLen = userAppEnd - userAppAddr - userFirmwareLen; /* check for overflow due to USBwValue out of range */ if (thisBlockLen >= pInformation->USBwLengths.w) { thisBlockLen = 0; } dfuAppStatus.bState = dfuIDLE; } } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errNOTDONE; } } else if (pInformation->USBbRequest == DFU_ABORT) { dfuAppStatus.bState = dfuIDLE; } else if (pInformation->USBbRequest == DFU_GETSTATUS) { dfuAppStatus.bState = dfuUPLOAD_IDLE; } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuUPLOAD_IDLE; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else if (startState == dfuERROR) { /* status is in error, awaiting DFU_CLRSTATUS request */ if (pInformation->USBbRequest == DFU_GETSTATUS) { /* todo, add routine to wait for last block write to finish */ dfuAppStatus.bState = dfuERROR; } else if (pInformation->USBbRequest == DFU_GETSTATE) { dfuAppStatus.bState = dfuERROR; } else if (pInformation->USBbRequest == DFU_CLRSTATUS) { /* todo handle any cleanup we need here */ dfuAppStatus.bState = dfuIDLE; dfuAppStatus.bStatus = OK; } else { dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } } else { /* some kind of error... */ dfuAppStatus.bState = dfuERROR; dfuAppStatus.bStatus = errSTALLEDPKT; } if (dfuAppStatus.bStatus == OK) { return TRUE; } else { return FALSE; } }
int flashWrite(flashaddr_t address, const char* buffer, size_t size) { /* Unlock flash for write access */ if (flashUnlock() == CH_FAILED) return FLASH_RETURN_NO_PERMISSION; /* Wait for any busy flags */ flashWaitWhileBusy(); /* Setup parallelism before any program/erase */ FLASH->CR &= ~FLASH_CR_PSIZE_MASK; FLASH->CR |= FLASH_CR_PSIZE_VALUE; /* Check if the flash address is correctly aligned */ size_t alignOffset = address % sizeof(flashdata_t); // print("flash alignOffset=%d\r\n", alignOffset); if (alignOffset != 0) { /* Not aligned, thus we have to read the data in flash already present * and update them with buffer's data */ /* Align the flash address correctly */ flashaddr_t alignedFlashAddress = address - alignOffset; /* Read already present data */ flashdata_t tmp = *(volatile flashdata_t*) alignedFlashAddress; /* Compute how much bytes one must update in the data read */ size_t chunkSize = sizeof(flashdata_t) - alignOffset; if (chunkSize > size) chunkSize = size; // this happens when both address and address + size are not aligned /* Update the read data with buffer's data */ memcpy((char*) &tmp + alignOffset, buffer, chunkSize); /* Write the new data in flash */ flashWriteData(alignedFlashAddress, tmp); /* Advance */ address += chunkSize; buffer += chunkSize; size -= chunkSize; } /* Now, address is correctly aligned. One can copy data directly from * buffer's data to flash memory until the size of the data remaining to be * copied requires special treatment. */ while (size >= sizeof(flashdata_t)) { // print("flash write size=%d\r\n", size); flashWriteData(address, *(const flashdata_t*) buffer); address += sizeof(flashdata_t); buffer += sizeof(flashdata_t); size -= sizeof(flashdata_t); } /* Now, address is correctly aligned, but the remaining data are to * small to fill a entier flashdata_t. Thus, one must read data already * in flash and update them with buffer's data before writing an entire * flashdata_t to flash memory. */ if (size > 0) { flashdata_t tmp = *(volatile flashdata_t*) address; memcpy(&tmp, buffer, size); flashWriteData(address, tmp); } /* Lock flash again */ flashLock() ; return FLASH_RETURN_SUCCESS; }