implement msc with internal_flash api

Note: only work with SD is disabled.
This commit is contained in:
hathach 2018-07-05 16:19:04 +07:00
parent 3564e98181
commit 0365912e28
5 changed files with 83 additions and 153 deletions

@ -1 +1 @@
Subproject commit fc139b009f4c49d4fdbf1b80097c94c8dabb1ee1
Subproject commit 40de723d417e253e3346b58cd2ce8b5dbf60d0ac

5
main.c
View File

@ -230,11 +230,6 @@ bool start_mp(safe_mode_t safe_mode) {
serial_connected_before_animation = serial_connected();
tick_rgb_status_animation(&animation);
#ifdef NRF52840_XXAA
extern void tusb_task(void);
tusb_task();
#endif
}
}

View File

@ -36,16 +36,34 @@
#include "lib/oofatfs/ff.h"
#include "supervisor/shared/rgb_led_status.h"
#include "nrf.h"
#include "nrf_nvmc.h"
#ifdef BLUETOOTH_SD
#include "nrf_sdm.h"
#endif
/*------------------------------------------------------------------*/
/* VARIABLES
*------------------------------------------------------------------*/
// defined in linker
extern uint32_t __fatfs_flash_start_addr[];
extern uint32_t __fatfs_flash_length[];
#define NO_CACHE 0xffffffff
#define FL_PAGE_SZ 4096
uint8_t _fl_cache[FL_PAGE_SZ] __attribute__((aligned(4)));
uint32_t _fl_pg_addr = NO_CACHE;
/*------------------------------------------------------------------*/
/* Internal Flash API
*------------------------------------------------------------------*/
static inline uint32_t lba2addr(uint32_t block) {
return ((uint32_t)__fatfs_flash_start_addr) + block * FILESYSTEM_BLOCK_SIZE;
}
void internal_flash_init(void) {
// Activity LED for flash writes.
#ifdef MICROPY_HW_LED_MSC
@ -67,101 +85,63 @@ uint32_t internal_flash_get_block_count(void) {
return ((uint32_t) __fatfs_flash_length) / FILESYSTEM_BLOCK_SIZE ;
}
// TODO support flashing with SD enabled
void internal_flash_flush(void) {
}
if (_fl_pg_addr == NO_CACHE) return;
void flash_flush(void) {
internal_flash_flush();
}
static uint32_t convert_block_to_flash_addr(uint32_t block) {
return ((uint32_t)__fatfs_flash_start_addr) + block * FILESYSTEM_BLOCK_SIZE;
}
bool internal_flash_write_block(const uint8_t *src, uint32_t block) {
uint8_t sd_en = 0;
#ifdef MICROPY_HW_LED_MSC
port_pin_set_output_level(MICROPY_HW_LED_MSC, true);
#endif
temp_status_color(ACTIVE_WRITE);
// non-MBR block, copy to cache
uint32_t dest = convert_block_to_flash_addr(block);
uint32_t pagenum = dest / FLASH_PAGE_SIZE;
uint32_t* flash_align = (uint32_t*) (pagenum*FLASH_PAGE_SIZE);
// Read back current page to update only 512 portion
__ALIGN(4) uint8_t buf[FLASH_PAGE_SIZE];
memcpy(buf, flash_align, FLASH_PAGE_SIZE);
memcpy(buf + (dest%FLASH_PAGE_SIZE), src, FILESYSTEM_BLOCK_SIZE);
#ifdef BLUETOOTH_SD
(void) sd_softdevice_is_enabled(&sd_en);
if (sd_en) {
if (NRF_SUCCESS != sd_flash_page_erase(pagenum)) {
return false;
// Skip if data is the same
if (memcmp(_fl_cache, (void *)_fl_pg_addr, FL_PAGE_SZ) != 0) {
// _is_flashing = true;
nrf_nvmc_page_erase(_fl_pg_addr);
nrf_nvmc_write_words(_fl_pg_addr, (uint32_t *)_fl_cache, FL_PAGE_SZ / sizeof(uint32_t));
}
if (NRF_SUCCESS != sd_flash_write(flash_align, (uint32_t*) buf, FLASH_PAGE_SIZE / sizeof(uint32_t))) {
return false;
}
}
#endif
if (!sd_en) {
// Erase
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos);
while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
NRF_NVMC->ERASEPAGE = dest;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
// Write
uint32_t *p_src = (uint32_t*) buf;
uint32_t *p_dest = flash_align;
uint32_t i = 0;
while (i < (FLASH_PAGE_SIZE / sizeof(uint32_t))) {
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
*p_dest++ = *p_src++;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
++i;
}
}
clear_temp_status();
#ifdef MICROPY_HW_LED_MSC
port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
#endif
return true;
_fl_pg_addr = NO_CACHE;
}
mp_uint_t internal_flash_read_blocks(uint8_t *dest, uint32_t block, uint32_t num_blocks) {
uint32_t src = convert_block_to_flash_addr(block);
memcpy(dest, (uint8_t*) src, FILESYSTEM_BLOCK_SIZE*num_blocks);
return 0; // success
uint32_t src = lba2addr(block);
memcpy(dest, (uint8_t*) src, FILESYSTEM_BLOCK_SIZE*num_blocks);
return 0; // success
}
mp_uint_t internal_flash_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
for (size_t i = 0; i < num_blocks; i++) {
if (!internal_flash_write_block(src + i * FILESYSTEM_BLOCK_SIZE, block_num + i)) {
return 1; // error
mp_uint_t internal_flash_write_blocks(const uint8_t *src, uint32_t lba, uint32_t num_blocks) {
#ifdef MICROPY_HW_LED_MSC
port_pin_set_output_level(MICROPY_HW_LED_MSC, true);
#endif
while (num_blocks) {
uint32_t const addr = lba2addr(lba);
uint32_t const page_addr = addr & ~(FL_PAGE_SZ - 1);
uint32_t count = 8 - (lba%8); // up to page boundary
count = MIN(num_blocks, count);
if (page_addr != _fl_pg_addr) {
internal_flash_flush();
// 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;
_fl_pg_addr = page_addr;
memcpy(_fl_cache, (void *)page_addr, FL_PAGE_SZ);
}
memcpy(_fl_cache + (addr & (FL_PAGE_SZ - 1)), src, count*FILESYSTEM_BLOCK_SIZE);
// adjust for next run
lba += count;
src += count*FILESYSTEM_BLOCK_SIZE;
num_blocks -= count;
}
}
return 0; // success
#ifdef MICROPY_HW_LED_MSC
port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
#endif
return 0; // success
}
/******************************************************************************/
@ -241,3 +221,7 @@ void flash_init_vfs(fs_user_mount_t *vfs) {
vfs->u.ioctl[0] = (mp_obj_t)&internal_flash_obj_ioctl_obj;
vfs->u.ioctl[1] = (mp_obj_t)&internal_flash_obj;
}
void flash_flush(void) {
internal_flash_flush();
}

View File

@ -44,8 +44,6 @@ uint32_t internal_flash_get_block_size(void);
uint32_t internal_flash_get_block_count(void);
void internal_flash_irq_handler(void);
void internal_flash_flush(void);
bool internal_flash_read_block(uint8_t *dest, uint32_t block);
bool internal_flash_write_block(const uint8_t *src, uint32_t block);
// these return 0 on success, non-zero on error
mp_uint_t internal_flash_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks);

View File

@ -37,7 +37,7 @@
#ifdef NRF52840_XXAA
#include "tusb.h"
#include "nrf_nvmc.h"
#include "internal_flash.h"
/*------------------------------------------------------------------*/
/* MACRO TYPEDEF CONSTANT ENUM
@ -71,11 +71,6 @@ static scsi_mode_parameters_t const msc_dev_mode_para =
/*
*------------------------------------------------------------------*/
static inline uint32_t lba2addr(uint32_t lba)
{
return MSC_FLASH_ADDR_START + lba*MSC_FLASH_BLOCK_SIZE;
}
//--------------------------------------------------------------------+
// tinyusb callbacks
//--------------------------------------------------------------------+
@ -141,72 +136,30 @@ int32_t tud_msc_scsi_cb (uint8_t rhport, uint8_t lun, uint8_t const scsi_cmd[16]
return len;
}
/*------------------------------------------------------------------*/
/* Internal Flash
*------------------------------------------------------------------*/
#define NO_CACHE 0xffffffff
uint8_t _fl_cache[FL_PAGE_SZ] ATTR_ALIGNED(4);
uint32_t _fl_addr = NO_CACHE;
static void fl_flush() {
if (_fl_addr == NO_CACHE) return;
// Skip if data is the same
if (memcmp(_fl_cache, (void *)_fl_addr, FL_PAGE_SZ) != 0) {
// _is_flashing = true;
nrf_nvmc_page_erase(_fl_addr);
nrf_nvmc_write_words(_fl_addr, (uint32_t *)_fl_cache, FL_PAGE_SZ / sizeof(uint32_t));
}
_fl_addr = NO_CACHE;
}
static bool fl_write(uint32_t addr, uint8_t* buf, uint16_t bufsize)
{
uint32_t new_addr = addr & ~(FL_PAGE_SZ - 1);
if (new_addr != _fl_addr) {
fl_flush();
// 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;
_fl_addr = new_addr;
memcpy(_fl_cache, (void *)new_addr, FL_PAGE_SZ);
}
memcpy(_fl_cache + (addr & (FL_PAGE_SZ - 1)), buf, bufsize);
return true;
}
/*------------------------------------------------------------------*/
/* Tinyusb Flash READ10 & WRITE10
*------------------------------------------------------------------*/
int32_t tud_msc_read10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
(void) rhport;
(void) lun;
(void) rhport; (void) lun; (void) offset;
uint32_t addr = lba2addr(lba) + offset;
memcpy(buffer, (uint8_t*) addr, bufsize);
uint32_t const block_count = bufsize/MSC_FLASH_BLOCK_SIZE;
return bufsize;
internal_flash_read_blocks(buffer, lba, block_count);
return block_count*MSC_FLASH_BLOCK_SIZE;
}
int32_t tud_msc_write10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
(void) rhport; (void) lun;
uint32_t addr = lba2addr(lba) + offset;
(void) rhport; (void) lun; (void) offset;
uint32_t const block_count = bufsize/MSC_FLASH_BLOCK_SIZE;
// bufsize <= CFG_TUD_MSC_BUFSIZE (4096)
fl_write(addr, buffer, bufsize);
internal_flash_write_blocks(buffer, lba, block_count);
return bufsize;
return block_count*MSC_FLASH_BLOCK_SIZE;
}
void tud_msc_write10_complete_cb(uint8_t rhport, uint8_t lun)
@ -214,7 +167,7 @@ void tud_msc_write10_complete_cb(uint8_t rhport, uint8_t lun)
(void) rhport; (void) lun;
// flush pending cache when write10 is complete
fl_flush();
internal_flash_flush();
}
#endif