get uf2 writing works

This commit is contained in:
hathach 2018-06-25 16:00:42 +07:00
parent 3a2d350c88
commit 6e9ecad3c8
2 changed files with 113 additions and 130 deletions

View File

@ -68,6 +68,8 @@ enum { FL_PAGE_SIZE = 4096 };
/* UF2 /* UF2
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
void read_block(uint32_t block_no, uint8_t *data); void read_block(uint32_t block_no, uint8_t *data);
int write_block(uint32_t block_no, uint8_t *data, bool quiet/*, WriteState *state*/);
void ghostfat_init();
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* VARIABLES /* VARIABLES
@ -75,7 +77,7 @@ void read_block(uint32_t block_no, uint8_t *data);
static uint8_t _page_cached[FL_PAGE_SIZE] ATTR_ALIGNED(4); static uint8_t _page_cached[FL_PAGE_SIZE] ATTR_ALIGNED(4);
volatile static uint8_t _wr10_state; volatile static uint8_t _wr10_state;
static pstorage_handle_t _fat_psh = { .module_id = 0, .block_id = MSC_UF2_FLASH_ADDR_START } ;
static scsi_inquiry_data_t const mscd_inquiry_data = static scsi_inquiry_data_t const mscd_inquiry_data =
{ {
@ -124,44 +126,22 @@ static inline uint32_t lba2addr(uint32_t lba)
return MSC_UF2_FLASH_ADDR_START + lba*MSC_UF2_BLOCK_SIZE; return MSC_UF2_FLASH_ADDR_START + lba*MSC_UF2_BLOCK_SIZE;
} }
static void fat12_mkfs(void);
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
static void fat_pstorage_cb(pstorage_handle_t * p_handle, uint8_t op_code, uint32_t result, uint8_t * p_data, uint32_t data_len)
{
if ( result != NRF_SUCCESS )
{
_wr10_state = WRITE10_FAILED;
TU_ASSERT(false, );
}
if ( PSTORAGE_CLEAR_OP_CODE == op_code)
{
if ( WRITE10_ERASING == _wr10_state) _wr10_state = WRITE10_ERASED;
}
else if ( PSTORAGE_STORE_OP_CODE == op_code)
{
if ( WRITE10_WRITING == _wr10_state) _wr10_state = WRITE10_WRITTEN;
}
}
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* API /* API
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
void msc_uf2_init(void) void msc_uf2_init(void)
{ {
pstorage_module_param_t fat_psp = { .cb = fat_pstorage_cb}; ghostfat_init();
pstorage_register(&fat_psp, &_fat_psh);
} }
void msc_uf2_mount(void) void msc_uf2_mount(void)
{ {
_wr10_state = WRITE10_IDLE;
// reset every time it is plugged
} }
void msc_uf2_umount(void) void msc_uf2_umount(void)
@ -252,17 +232,7 @@ int32_t tud_msc_scsi_cb (uint8_t rhport, uint8_t lun, uint8_t const scsi_cmd[16]
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* Tinyusb Flash READ10 & WRITE10 /* Tinyusb Flash READ10 & WRITE10
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
static bool fl_page_erase(uint32_t addr)
{
_fat_psh.block_id = addr;
return NRF_SUCCESS == pstorage_clear(&_fat_psh, FL_PAGE_SIZE);
}
static bool fl_page_write(uint32_t addr, uint8_t* buf, uint16_t bufsize)
{
_fat_psh.block_id = addr;
return NRF_SUCCESS == pstorage_store(&_fat_psh, buf, bufsize, 0);
}
int32_t tud_msc_read10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) int32_t tud_msc_read10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{ {
@ -289,84 +259,18 @@ int32_t tud_msc_write10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t
{ {
(void) rhport; (void) lun; (void) rhport; (void) lun;
return bufsize; uint32_t count = 0;
int wr_ret;
uint32_t addr = lba2addr(lba) + offset; while ( (count < bufsize) && ((wr_ret = write_block(lba, buffer, false)) > 0) )
/* 0. Check if flash is the same as data -> skip if matches
* 1. queue flash erase pstorage_clear(), return 0 until erasing is done
* 2. queue flash writing, return 0 until writing is complete
* 3. return written bytes.
*
* Note since CFG_TUD_MSC_BUFSIZE is 4KB, bufsize is cap at 4KB
*/
switch(_wr10_state)
{ {
case WRITE10_IDLE: lba++;
{ buffer += 512;
// No need to write if flash's content matches with data count += 512;
if ( 0 == memcmp(buffer, (void*) addr, bufsize) ) return bufsize;
uint32_t page_addr = align4k(addr);
uint32_t off4k = offset4k(addr);
// Cache contents from start of page to current address
if ( off4k )
{
memcpy(_page_cached, (uint8_t*) page_addr, off4k);
} }
// Copy new data // Consider non-uf2 block write as successful
memcpy(_page_cached+off4k, buffer, bufsize); return (wr_ret < 0) ? bufsize : count;
// Cache contents after data to end of page
if ( off4k + bufsize < FL_PAGE_SIZE)
{
memcpy(_page_cached+off4k+bufsize, (uint8_t*) (addr+bufsize), FL_PAGE_SIZE - (off4k + bufsize ) );
}
// Start erasing
TU_ASSERT( fl_page_erase(align4k(addr)), -1);
_wr10_state = WRITE10_ERASING;
// Tell tinyusb that we are not ready to consume its data
// The stack will keep the data and call again
return 0;
}
break;
case WRITE10_ERASING:
// still erasing, nothing else to do
return 0;
break;
case WRITE10_ERASED:
// Start writing
TU_ASSERT( fl_page_write(align4k(addr), _page_cached, FL_PAGE_SIZE), -1);
_wr10_state = WRITE10_WRITING;
return 0;
break;
case WRITE10_WRITING:
return 0;
break;
case WRITE10_WRITTEN:
_wr10_state = WRITE10_IDLE; // back to idle
// positive return means we complete the operation, tinyusb can receiving next write10
return bufsize;
break;
case WRITE10_FAILED:
_wr10_state = WRITE10_IDLE;
return -1;
break;
default: return -1; break;
}
} }
#endif #endif

View File

@ -4,9 +4,10 @@
#include <string.h> #include <string.h>
#include "tusb.h" #include "tusb.h"
// to determine application size
#include "bootloader_settings.h" #include "bootloader_settings.h"
#include "bootloader.h" #include "bootloader.h"
#include "pstorage.h"
typedef struct { typedef struct {
uint8_t JumpInstruction[3]; uint8_t JumpInstruction[3];
@ -117,11 +118,19 @@ static const FAT_BootBlock BootBlock = {
#define NO_CACHE 0xffffffff #define NO_CACHE 0xffffffff
#define NRF_LOG_DEBUG(...) #define NRF_LOG_DEBUG(...)
#define NRF_LOG_WARNING(...)
uint32_t flashAddr = NO_CACHE; uint32_t flashAddr = NO_CACHE;
uint8_t flashBuf[FLASH_PAGE_SIZE] __attribute__((aligned(4))); uint8_t flashBuf[FLASH_PAGE_SIZE] __attribute__((aligned(4)));
bool firstFlush = true; bool firstFlush = true;
bool hadWrite = false; //bool hadWrite = false;
static WriteState uf2_wr_state = { 0 };
static WriteState* state = &uf2_wr_state;
volatile bool _is_flashing = false;
static pstorage_handle_t _fat_psh = { .module_id = 0, .block_id = USER_FLASH_END } ;
static uint32_t get_flash_size(void) static uint32_t get_flash_size(void)
@ -147,19 +156,59 @@ static uint32_t get_flash_size(void)
return flash_sz; return flash_sz;
} }
#if 0 void fat_pstorage_cb(pstorage_handle_t * p_handle, uint8_t op_code, uint32_t result, uint8_t * p_data, uint32_t data_len)
{
if ( result != NRF_SUCCESS )
{
TU_ASSERT(false, );
}
if ( PSTORAGE_CLEAR_OP_CODE == op_code)
{
// erase complete start writing
_fat_psh.block_id = p_handle->block_id;
TU_ASSERT( pstorage_store(&_fat_psh, flashBuf, FLASH_PAGE_SIZE, 0), );
}
else if ( PSTORAGE_STORE_OP_CODE == op_code)
{
// write completes
_is_flashing = false;
// whole uf2 file is written, inform bootloader to update setting and reset
if ( state->numWritten >= state->numBlocks )
{
dfu_update_status_t update_status;
memset(&update_status, 0, sizeof(dfu_update_status_t ));
update_status.status_code = DFU_UPDATE_APP_COMPLETE;
update_status.app_crc = 0; // skip CRC checking with uf2 upgrade
update_status.app_size = state->numBlocks*256;
bootloader_dfu_update_process(update_status);
}
}
}
void ghostfat_init(void)
{
pstorage_module_param_t fat_psp = { .cb = fat_pstorage_cb};
pstorage_register(&fat_psp, &_fat_psh);
}
void flushFlash() { void flushFlash() {
if (flashAddr == NO_CACHE) if (flashAddr == NO_CACHE)
return; return;
if (firstFlush) { if (firstFlush) {
firstFlush = false;
#if 0
if (sdRunning) { if (sdRunning) {
// disable SD - we need sync access to flash, and we might be also overwriting the SD // disable SD - we need sync access to flash, and we might be also overwriting the SD
nrf_sdh_disable_request(); nrf_sdh_disable_request();
nrf_dfu_settings_init(false); nrf_dfu_settings_init(false);
} }
firstFlush = false;
s_dfu_settings.write_offset = 0; s_dfu_settings.write_offset = 0;
s_dfu_settings.sd_size = 0; s_dfu_settings.sd_size = 0;
@ -170,17 +219,21 @@ void flushFlash() {
memset(&s_dfu_settings.bank_1, 0, sizeof(s_dfu_settings.bank_1)); memset(&s_dfu_settings.bank_1, 0, sizeof(s_dfu_settings.bank_1));
nrf_dfu_settings_write(NULL); nrf_dfu_settings_write(NULL);
#endif
} }
int32_t sz = flashAddr + FLASH_PAGE_SIZE; // int32_t sz = flashAddr + FLASH_PAGE_SIZE;
if (s_dfu_settings.bank_0.image_size < sz) // if (s_dfu_settings.bank_0.image_size < sz)
s_dfu_settings.bank_0.image_size = sz; // s_dfu_settings.bank_0.image_size = sz;
NRF_LOG_DEBUG("Flush at %x", flashAddr); NRF_LOG_DEBUG("Flush at %x", flashAddr);
if (memcmp(flashBuf, (void *)flashAddr, FLASH_PAGE_SIZE) != 0) { if (memcmp(flashBuf, (void *)flashAddr, FLASH_PAGE_SIZE) != 0) {
NRF_LOG_DEBUG("Write flush at %x", flashAddr); NRF_LOG_DEBUG("Write flush at %x", flashAddr);
nrf_nvmc_page_erase(flashAddr); _is_flashing = true;
nrf_nvmc_write_words(flashAddr, (uint32_t *)flashBuf, FLASH_PAGE_SIZE / sizeof(uint32_t));
// Writing to flash will be done in erase complete callback
_fat_psh.block_id = flashAddr;
TU_ASSERT ( pstorage_clear(&_fat_psh, FLASH_PAGE_SIZE), );
} }
flashAddr = NO_CACHE; flashAddr = NO_CACHE;
@ -191,16 +244,22 @@ void flushFlash() {
void flash_write(uint32_t dst, const uint8_t *src, int len) { void flash_write(uint32_t dst, const uint8_t *src, int len) {
uint32_t newAddr = dst & ~(FLASH_PAGE_SIZE - 1); uint32_t newAddr = dst & ~(FLASH_PAGE_SIZE - 1);
hadWrite = true; // hadWrite = true;
if (newAddr != flashAddr) { if (newAddr != flashAddr) {
flushFlash(); flushFlash();
// writing previous cached data, skip current data until flashing is done
// tinyusb stack will invoke write_block() with the same parameters later on
if ( _is_flashing ) return;
flashAddr = newAddr; flashAddr = newAddr;
memcpy(flashBuf, (void *)newAddr, FLASH_PAGE_SIZE); memcpy(flashBuf, (void *)newAddr, FLASH_PAGE_SIZE);
} }
memcpy(flashBuf + (dst & (FLASH_PAGE_SIZE - 1)), src, len); memcpy(flashBuf + (dst & (FLASH_PAGE_SIZE - 1)), src, len);
} }
#if 0
void uf2_timer(void *p_context) { void uf2_timer(void *p_context) {
UNUSED_PARAMETER(p_context); UNUSED_PARAMETER(p_context);
if (hadWrite) { if (hadWrite) {
@ -229,6 +288,9 @@ void padded_memcpy(char *dst, const char *src, int len) {
} }
/*------------------------------------------------------------------*/
/*
*------------------------------------------------------------------*/
void read_block(uint32_t block_no, uint8_t *data) { void read_block(uint32_t block_no, uint8_t *data) {
memset(data, 0, 512); memset(data, 0, 512);
uint32_t sectionIdx = block_no; uint32_t sectionIdx = block_no;
@ -290,16 +352,25 @@ void read_block(uint32_t block_no, uint8_t *data) {
} }
} }
#if 0 /** Write an block
void write_block(uint32_t block_no, uint8_t *data, bool quiet, WriteState *state) { *
* @return number of bytes processed, only 3 following values
* -1 : if not an uf2 block
* 512 : write is successful
* 0 : is busy with flashing, tinyusb stack will call write_block again with the same parameters later on
*/
int write_block(uint32_t block_no, uint8_t *data, bool quiet/*, WriteState *state*/) {
UF2_Block *bl = (void *)data; UF2_Block *bl = (void *)data;
// NRF_LOG_DEBUG("Write magic: %x", bl->magicStart0); NRF_LOG_DEBUG("Write magic: %x", bl->magicStart0);
if (!is_uf2_block(bl)) { if (!is_uf2_block(bl)) {
return; return -1;
} }
// still busy with flashing previous blocks
if ( _is_flashing ) return 0;
if ((bl->flags & UF2_FLAG_NOFLASH) || bl->payloadSize > 256 || (bl->targetAddr & 0xff) || if ((bl->flags & UF2_FLAG_NOFLASH) || bl->payloadSize > 256 || (bl->targetAddr & 0xff) ||
bl->targetAddr < USER_FLASH_START || bl->targetAddr + bl->payloadSize > USER_FLASH_END) { bl->targetAddr < USER_FLASH_START || bl->targetAddr + bl->payloadSize > USER_FLASH_END) {
#if USE_DBG_MSC #if USE_DBG_MSC
@ -315,7 +386,10 @@ void write_block(uint32_t block_no, uint8_t *data, bool quiet, WriteState *state
flash_write(bl->targetAddr, bl->data, bl->payloadSize); flash_write(bl->targetAddr, bl->data, bl->payloadSize);
} }
bool isSet = false; // flash_write cause a flush to write previous cached data, this write data is not consumed yet
if ( _is_flashing ) return 0;
// bool isSet = false;
if (state && bl->numBlocks) { if (state && bl->numBlocks) {
if (state->numBlocks != bl->numBlocks) { if (state->numBlocks != bl->numBlocks) {
@ -336,16 +410,21 @@ void write_block(uint32_t block_no, uint8_t *data, bool quiet, WriteState *state
// wait a little bit before resetting, to avoid Windows transmit error // wait a little bit before resetting, to avoid Windows transmit error
// https://github.com/Microsoft/uf2-samd21/issues/11 // https://github.com/Microsoft/uf2-samd21/issues/11
if (!quiet) { if (!quiet) {
uf2_timer_start(30); // uf2_timer_start(30);
isSet = true; // isSet = true;
} }
// flush last blocks
flushFlash();
} }
} }
NRF_LOG_DEBUG("wr %d=%d (of %d)", state->numWritten, bl->blockNo, bl->numBlocks); NRF_LOG_DEBUG("wr %d=%d (of %d)", state->numWritten, bl->blockNo, bl->numBlocks);
} }
if (!isSet && !quiet) { // if (!isSet && !quiet) {
// uf2_timer_start(500); // // uf2_timer_start(500);
} // }
return 512;
} }
#endif