/********************************************************** * Writes one word to flash. * * @param addr * Address to write to. Must be a valid flash address. * * @param data * Word to write **********************************************************/ static void pgmWord( uint32_t addr, uint32_t data ) { MSC->ADDRB = addr; MSC->WRITECMD = MSC_WRITECMD_LADDRIM; MSC->WDATA = data; doFlashCmd( MSC_WRITECMD_WRITEONCE ); }
/********************************************************** * Erases on page of flash. * * @param addr * Address of page. Must be a valid flash address. * * @param pagesize * Size of one page in bytes **********************************************************/ static void eraseSector( uint32_t addr, uint32_t pagesize ) { uint32_t *p = (uint32_t*)addr, result; /* Check if page already is erased. If so we can * simply return. */ do { result = *p++; pagesize -= 4; } while ( pagesize && ( result == 0xFFFFFFFF ) ); if ( result != 0xFFFFFFFF ) { /* Erase the page */ MSC->ADDRB = addr; MSC->WRITECMD = MSC_WRITECMD_LADDRIM; doFlashCmd( MSC_WRITECMD_ERASEPAGE ); } }
uint32_t flashSize(void) { return doFlashCmd(AVR32_FLASHC_CMD_SIZE); }
void main(void) { uint8_t *pBuff; uint32_t addr, burst, pageMask, byteCount; /* Relocate vector table */ SCB->VTOR = 0x20000000; /* Disable interrupts */ __disable_irq(); /* Signal setup */ state.flashLoaderStatus = FLASHLOADER_STATUS_NOT_READY; state.debuggerStatus = DEBUGGERCMD_NOT_CONNECTED; /* Get device info including memory size */ setupEFM32(); /* Calculate size of available buffers. Two buffers are * used. Each buffer will fill up half of the remaining RAM. * Round down to nearest word boundry */ state.bufferSize = (state.sramSize - ((uint32_t) &flashBuffer - 0x20000000)) / 2; /* Only use full 4 bytes (1 word) */ state.bufferSize = state.bufferSize & 0xFFFFFFFC; /* Set the address of both buffers */ state.bufferAddress1 = (uint32_t) &flashBuffer; state.bufferAddress2 = ((uint32_t) &flashBuffer) + state.bufferSize; /* Signal setup complete. Ready to accept commands from programmer. */ state.flashLoaderStatus = FLASHLOADER_STATUS_READY; /* Poll debuggerStatus field to listen for commands * from programmer */ while(1) { /* Erase page(s) command */ if (state.debuggerStatus == DEBUGGERCMD_ERASE_PAGE) { /* Clear the flag to indicate that we are busy */ state.flashLoaderStatus = FLASHLOADER_STATUS_NOT_READY; state.debuggerStatus = DEBUGGERCMD_NONE; /* Enable flash writes */ MSC->WRITECTRL |= MSC_WRITECTRL_WREN; /* Get address of first page to erase */ uint32_t writeAddress = state.writeAddress1; /* Erase all pages in the given range */ for (addr = writeAddress; addr < writeAddress + state.numBytes1; addr += state.pageSize) { eraseSector( addr, state.pageSize ); } /* Disable flash writes */ MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; /* Operation complete. Set flag to ready again. */ state.flashLoaderStatus = FLASHLOADER_STATUS_READY; } /* Mass erase command */ if (state.debuggerStatus == DEBUGGERCMD_MASS_ERASE) { /* Clear the flag to indicate that we are busy */ state.flashLoaderStatus = FLASHLOADER_STATUS_NOT_READY; state.debuggerStatus = DEBUGGERCMD_NONE; /* Enable flash writes */ MSC->WRITECTRL |= MSC_WRITECTRL_WREN; /* Unlock Mass Erase */ MSC->MASSLOCK = 0x631A; /* Erase entire flash */ doFlashCmd(MSC_WRITECMD_ERASEMAIN0 | MSC_WRITECMD_ERASEMAIN1); /* Reset lock */ MSC->MASSLOCK = 0; /* Disable flash writes again */ MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; /* Operation complete. Set flag to ready again. */ state.flashLoaderStatus = FLASHLOADER_STATUS_READY; } /* Write command */ if (state.debuggerStatus == DEBUGGERCMD_WRITE_DATA1 || state.debuggerStatus == DEBUGGERCMD_WRITE_DATA2 ) { /* Select buffer based on write command */ bool useBuffer1 = state.debuggerStatus == DEBUGGERCMD_WRITE_DATA1 ? true : false; /* Clear the flag to indicate that we are busy */ state.flashLoaderStatus = FLASHLOADER_STATUS_NOT_READY; state.debuggerStatus = DEBUGGERCMD_NONE; pageMask = ~(state.pageSize - 1); /* Set up buffer, size and destination */ pBuff = useBuffer1 ? (uint8_t *)state.bufferAddress1 : (uint8_t *)state.bufferAddress2; byteCount = useBuffer1 ? state.numBytes1 : state.numBytes2; addr = useBuffer1 ? state.writeAddress1 : state.writeAddress2; /* Enable flash writes */ MSC->WRITECTRL |= MSC_WRITECTRL_WREN; /* Use double word writes if available */ if ( ( byteCount > 7 ) && writeDouble ) { if ( addr & 7 ) /* Start address not on 8 byte boundary ? */ { pgmWord( addr, *(uint32_t*)pBuff ); pBuff += 4; addr += 4; byteCount -= 4; } /* Enable double word writes */ MSC->WRITECTRL |= MSC_WRITECTRL_WDOUBLE; /* Writes as many words as possible using double word writes */ while ( byteCount > 7 ) { /* Max burst len is up to next flash page boundary. */ burst = MIN( byteCount, ( ( addr + state.pageSize ) & pageMask ) - addr ); /* Write data to flash */ burst -= pgmBurstDouble( addr, (uint32_t*)pBuff, burst ); pBuff += burst; addr += burst; byteCount -= burst; } /* Wait until operations are complete */ mscStatusWait( MSC_STATUS_BUSY, 0 ); /* Disable double word writes */ MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE; } /* Writes all remaining bytes */ while ( byteCount ) { /* Max burst len is up to next flash page boundary. */ burst = MIN( byteCount, ( ( addr + state.pageSize ) & pageMask ) - addr ); /* Write data to flash */ pgmBurst( addr, (uint32_t*)pBuff, burst ); pBuff += burst; addr += burst; byteCount -= burst; } /* Wait until operations are complete */ mscStatusWait( MSC_STATUS_BUSY, 0 ); /* Disable flash writes */ MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; /* Operation complete. Set flag to ready again. */ state.flashLoaderStatus = FLASHLOADER_STATUS_READY; } } }