atmel-samd: Rework mass storage interaction with underlying block
storage to use micropython's VFS interface. This makes mass storage work with any VFS implementation rather than a single one.
This commit is contained in:
parent
6fe8c7b32c
commit
306c921ed1
@ -143,6 +143,7 @@ SRC_ASF = $(addprefix asf/sam0/,\
|
||||
)
|
||||
|
||||
SRC_C = \
|
||||
access_vfs.c \
|
||||
builtin_open.c \
|
||||
fatfs_port.c \
|
||||
main.c \
|
||||
@ -156,9 +157,8 @@ SRC_C = \
|
||||
modutime.c \
|
||||
mphalport.c \
|
||||
pin_named_pins.c \
|
||||
rom_fs.c \
|
||||
samdneopixel.c \
|
||||
storage.c \
|
||||
$(FLASH_IMPL) \
|
||||
asf/common/services/sleepmgr/samd/sleepmgr.c \
|
||||
asf/common/services/storage/ctrl_access/ctrl_access.c \
|
||||
asf/common/services/usb/class/cdc/device/udi_cdc.c \
|
||||
|
@ -24,10 +24,16 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "rom_fs.h"
|
||||
#include "access_vfs.h"
|
||||
|
||||
#include "asf/common/services/usb/class/msc/device/udi_msc.h"
|
||||
#include "storage.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
#include "lib/fatfs/diskio.h"
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "py/misc.h"
|
||||
|
||||
#define VFS_INDEX 0
|
||||
|
||||
//! This function tests memory state, and starts memory initialization
|
||||
//! @return Ctrl_status
|
||||
@ -35,9 +41,17 @@
|
||||
//! Memory unplug -> CTRL_NO_PRESENT
|
||||
//! Not initialized or changed -> CTRL_BUSY
|
||||
//! An error occurred -> CTRL_FAIL
|
||||
Ctrl_status rom_fs_test_unit_ready(void)
|
||||
Ctrl_status vfs_test_unit_ready(void)
|
||||
{
|
||||
return CTRL_GOOD;
|
||||
if (VFS_INDEX >= MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) {
|
||||
return CTRL_FAIL;
|
||||
}
|
||||
DSTATUS status = disk_status(VFS_INDEX);
|
||||
if (status == STA_NOINIT) {
|
||||
return CTRL_NO_PRESENT;
|
||||
}
|
||||
|
||||
return CTRL_GOOD;
|
||||
}
|
||||
|
||||
//! This function returns the address of the last valid sector
|
||||
@ -47,9 +61,11 @@ Ctrl_status rom_fs_test_unit_ready(void)
|
||||
//! Memory unplug -> CTRL_NO_PRESENT
|
||||
//! Not initialized or changed -> CTRL_BUSY
|
||||
//! An error occurred -> CTRL_FAIL
|
||||
Ctrl_status rom_fs_read_capacity(uint32_t *uint32_t_nb_sector)
|
||||
Ctrl_status vfs_read_capacity(uint32_t *uint32_t_nb_sector)
|
||||
{
|
||||
*uint32_t_nb_sector = storage_get_block_count();
|
||||
if (disk_ioctl(VFS_INDEX, GET_SECTOR_COUNT, uint32_t_nb_sector) != RES_OK) {
|
||||
return CTRL_FAIL;
|
||||
}
|
||||
return CTRL_GOOD;
|
||||
}
|
||||
|
||||
@ -57,20 +73,26 @@ Ctrl_status rom_fs_read_capacity(uint32_t *uint32_t_nb_sector)
|
||||
//!
|
||||
//! @return true if the memory is protected
|
||||
//!
|
||||
bool rom_fs_wr_protect(void)
|
||||
bool vfs_wr_protect(void)
|
||||
{
|
||||
return false;
|
||||
DSTATUS status = disk_status(VFS_INDEX);
|
||||
return status == STA_NOINIT || status == STA_PROTECT;
|
||||
}
|
||||
|
||||
//! This function informs about the memory type
|
||||
//!
|
||||
//! @return true if the memory is removable
|
||||
//!
|
||||
bool rom_fs_removal(void)
|
||||
bool vfs_removal(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vfs_unload(bool unload)
|
||||
{
|
||||
return unload;
|
||||
}
|
||||
|
||||
// TODO(tannewt): Transfer more than a single sector at a time if we need more
|
||||
// speed.
|
||||
//! This function transfers the memory data to the USB MSC interface
|
||||
@ -84,11 +106,17 @@ bool rom_fs_removal(void)
|
||||
//! Not initialized or changed -> CTRL_BUSY
|
||||
//! An error occurred -> CTRL_FAIL
|
||||
//!
|
||||
Ctrl_status rom_fs_usb_read_10(uint32_t addr, volatile uint16_t nb_sector)
|
||||
Ctrl_status vfs_usb_read_10(uint32_t addr, volatile uint16_t nb_sector)
|
||||
{
|
||||
uint8_t sector_buffer[FLASH_BLOCK_SIZE];
|
||||
for (uint16_t sector = 0; sector < nb_sector; sector++) {
|
||||
storage_read_block(sector_buffer, addr + sector);
|
||||
DRESULT result = disk_read(VFS_INDEX, sector_buffer, addr + sector, 1);
|
||||
if (result == RES_PARERR) {
|
||||
return CTRL_NO_PRESENT;
|
||||
}
|
||||
if (result == RES_ERROR) {
|
||||
return CTRL_FAIL;
|
||||
}
|
||||
if (!udi_msc_trans_block(true, sector_buffer, FLASH_BLOCK_SIZE, NULL)) {
|
||||
return CTRL_FAIL; // transfer aborted
|
||||
}
|
||||
@ -108,14 +136,18 @@ Ctrl_status rom_fs_usb_read_10(uint32_t addr, volatile uint16_t nb_sector)
|
||||
//! Not initialized or changed -> CTRL_BUSY
|
||||
//! An error occurred -> CTRL_FAIL
|
||||
//!
|
||||
Ctrl_status rom_fs_usb_write_10(uint32_t addr, uint16_t nb_sector)
|
||||
Ctrl_status vfs_usb_write_10(uint32_t addr, uint16_t nb_sector)
|
||||
{
|
||||
uint8_t sector_buffer[FLASH_BLOCK_SIZE];
|
||||
for (uint16_t sector = 0; sector < nb_sector; sector++) {
|
||||
if (!udi_msc_trans_block(false, sector_buffer, FLASH_BLOCK_SIZE, NULL)) {
|
||||
return CTRL_FAIL; // transfer aborted
|
||||
}
|
||||
if (!storage_write_block(sector_buffer, addr + sector)) {
|
||||
DRESULT result = disk_write(VFS_INDEX, sector_buffer, addr + sector, 1);
|
||||
if (result == RES_PARERR) {
|
||||
return CTRL_NO_PRESENT;
|
||||
}
|
||||
if (result == RES_ERROR) {
|
||||
return CTRL_FAIL;
|
||||
}
|
||||
}
|
@ -24,17 +24,20 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// This adapts the ASF access API to MicroPython's VFS API so we can expose all
|
||||
// VFS block devices as Lun's over USB mass storage control.
|
||||
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_ROM_FS_H__
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_ROM_FS_H__
|
||||
|
||||
#include "asf/common/services/storage/ctrl_access/ctrl_access.h"
|
||||
|
||||
|
||||
Ctrl_status rom_fs_test_unit_ready(void);
|
||||
Ctrl_status rom_fs_read_capacity(uint32_t *u32_nb_sector);
|
||||
bool rom_fs_wr_protect(void);
|
||||
bool rom_fs_removal(void);
|
||||
Ctrl_status rom_fs_usb_read_10(uint32_t addr, uint16_t nb_sector);
|
||||
Ctrl_status rom_fs_usb_write_10(uint32_t addr, uint16_t nb_sector);
|
||||
Ctrl_status vfs_test_unit_ready(void);
|
||||
Ctrl_status vfs_read_capacity(uint32_t *u32_nb_sector);
|
||||
bool vfs_wr_protect(void);
|
||||
bool vfs_removal(void);
|
||||
bool vfs_unload(bool);
|
||||
Ctrl_status vfs_usb_read_10(uint32_t addr, uint16_t nb_sector);
|
||||
Ctrl_status vfs_usb_write_10(uint32_t addr, uint16_t nb_sector);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_ATMEL_SAMD_ROM_FS_H__
|
@ -68,15 +68,15 @@
|
||||
/*! \name LUN 0 Definitions
|
||||
*/
|
||||
//! @{
|
||||
#define LUN_0_INCLUDE "rom_fs.h"
|
||||
#define Lun_0_test_unit_ready rom_fs_test_unit_ready
|
||||
#define Lun_0_read_capacity rom_fs_read_capacity
|
||||
#define Lun_0_unload NULL /* Can not be unloaded */
|
||||
#define Lun_0_wr_protect rom_fs_wr_protect
|
||||
#define Lun_0_removal rom_fs_removal
|
||||
#define Lun_0_usb_read_10 rom_fs_usb_read_10
|
||||
#define Lun_0_usb_write_10 rom_fs_usb_write_10
|
||||
#define LUN_0_NAME "\"On-Chip ROM\""
|
||||
#define LUN_0_INCLUDE "access_vfs.h"
|
||||
#define Lun_0_test_unit_ready vfs_test_unit_ready
|
||||
#define Lun_0_read_capacity vfs_read_capacity
|
||||
#define Lun_0_unload NULL
|
||||
#define Lun_0_wr_protect vfs_wr_protect
|
||||
#define Lun_0_removal vfs_removal
|
||||
#define Lun_0_usb_read_10 vfs_usb_read_10
|
||||
#define Lun_0_usb_write_10 vfs_usb_write_10
|
||||
#define LUN_0_NAME "\"MicroPython VFS[0]\""
|
||||
//! @}
|
||||
|
||||
#define MEM_USB LUN_USB
|
||||
|
@ -1,3 +1,5 @@
|
||||
LD_FILE = boards/samd21x18-bootloader.ld
|
||||
USB_VID = 0x2341
|
||||
USB_PID = 0x824D
|
||||
|
||||
FLASH_IMPL = internal_flash.c
|
||||
|
@ -1,3 +1,5 @@
|
||||
LD_FILE = boards/samd21x18-bootloader.ld
|
||||
USB_VID = 0x239A
|
||||
USB_PID = 0x8015
|
||||
|
||||
FLASH_IMPL = internal_flash.c
|
||||
|
@ -34,35 +34,35 @@
|
||||
|
||||
#include "asf/sam0/drivers/nvm/nvm.h"
|
||||
|
||||
#include "storage.h"
|
||||
#include "internal_flash.h"
|
||||
|
||||
#define TOTAL_FLASH_SIZE 0x010000
|
||||
#define TOTAL_INTERNAL_FLASH_SIZE 0x010000
|
||||
|
||||
#define FLASH_MEM_SEG1_START_ADDR (0x00040000 - TOTAL_FLASH_SIZE)
|
||||
#define FLASH_PART1_START_BLOCK (0x100)
|
||||
#define FLASH_PART1_NUM_BLOCKS (TOTAL_FLASH_SIZE / FLASH_BLOCK_SIZE)
|
||||
#define INTERNAL_FLASH_MEM_SEG1_START_ADDR (0x00040000 - TOTAL_INTERNAL_FLASH_SIZE)
|
||||
#define INTERNAL_FLASH_PART1_START_BLOCK (0x100)
|
||||
#define INTERNAL_FLASH_PART1_NUM_BLOCKS (TOTAL_INTERNAL_FLASH_SIZE / INTERNAL_FLASH_BLOCK_SIZE)
|
||||
|
||||
static bool flash_is_initialised = false;
|
||||
static bool internal_flash_is_initialised = false;
|
||||
|
||||
void storage_init(void) {
|
||||
if (!flash_is_initialised) {
|
||||
void internal_flash_init(void) {
|
||||
if (!internal_flash_is_initialised) {
|
||||
struct nvm_config config_nvm;
|
||||
nvm_get_config_defaults(&config_nvm);
|
||||
config_nvm.manual_page_write = false;
|
||||
nvm_set_config(&config_nvm);
|
||||
flash_is_initialised = true;
|
||||
internal_flash_is_initialised = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t storage_get_block_size(void) {
|
||||
return FLASH_BLOCK_SIZE;
|
||||
uint32_t internal_flash_get_block_size(void) {
|
||||
return INTERNAL_FLASH_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
uint32_t storage_get_block_count(void) {
|
||||
return FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS;
|
||||
uint32_t internal_flash_get_block_count(void) {
|
||||
return INTERNAL_FLASH_PART1_START_BLOCK + INTERNAL_FLASH_PART1_NUM_BLOCKS;
|
||||
}
|
||||
|
||||
void storage_flush(void) {
|
||||
void internal_flash_flush(void) {
|
||||
}
|
||||
|
||||
static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) {
|
||||
@ -102,16 +102,16 @@ static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_blo
|
||||
}
|
||||
|
||||
static uint32_t convert_block_to_flash_addr(uint32_t block) {
|
||||
if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) {
|
||||
if (INTERNAL_FLASH_PART1_START_BLOCK <= block && block < INTERNAL_FLASH_PART1_START_BLOCK + INTERNAL_FLASH_PART1_NUM_BLOCKS) {
|
||||
// a block in partition 1
|
||||
block -= FLASH_PART1_START_BLOCK;
|
||||
return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE;
|
||||
block -= INTERNAL_FLASH_PART1_START_BLOCK;
|
||||
return INTERNAL_FLASH_MEM_SEG1_START_ADDR + block * INTERNAL_FLASH_BLOCK_SIZE;
|
||||
}
|
||||
// bad block
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool storage_read_block(uint8_t *dest, uint32_t block) {
|
||||
bool internal_flash_read_block(uint8_t *dest, uint32_t block) {
|
||||
//printf("RD %u\n", block);
|
||||
if (block == 0) {
|
||||
// fake the MBR so we can decide on our own partition table
|
||||
@ -120,7 +120,7 @@ bool storage_read_block(uint8_t *dest, uint32_t block) {
|
||||
dest[i] = 0;
|
||||
}
|
||||
|
||||
build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, FLASH_PART1_NUM_BLOCKS);
|
||||
build_partition(dest + 446, 0, 0x01 /* FAT12 */, INTERNAL_FLASH_PART1_START_BLOCK, INTERNAL_FLASH_PART1_NUM_BLOCKS);
|
||||
build_partition(dest + 462, 0, 0, 0, 0);
|
||||
build_partition(dest + 478, 0, 0, 0, 0);
|
||||
build_partition(dest + 494, 0, 0, 0, 0);
|
||||
@ -140,7 +140,7 @@ bool storage_read_block(uint8_t *dest, uint32_t block) {
|
||||
enum status_code error_code;
|
||||
// A block is made up of multiple pages. Read each page
|
||||
// sequentially.
|
||||
for (int i = 0; i < FLASH_BLOCK_SIZE / NVMCTRL_PAGE_SIZE; i++) {
|
||||
for (int i = 0; i < INTERNAL_FLASH_BLOCK_SIZE / NVMCTRL_PAGE_SIZE; i++) {
|
||||
do
|
||||
{
|
||||
error_code = nvm_read_buffer(src + i * NVMCTRL_PAGE_SIZE,
|
||||
@ -152,7 +152,7 @@ bool storage_read_block(uint8_t *dest, uint32_t block) {
|
||||
}
|
||||
}
|
||||
|
||||
bool storage_write_block(const uint8_t *src, uint32_t block) {
|
||||
bool internal_flash_write_block(const uint8_t *src, uint32_t block) {
|
||||
if (block == 0) {
|
||||
// can't write MBR, but pretend we did
|
||||
return true;
|
||||
@ -184,7 +184,7 @@ bool storage_write_block(const uint8_t *src, uint32_t block) {
|
||||
|
||||
// A block is made up of multiple pages. Write each page
|
||||
// sequentially.
|
||||
for (int i = 0; i < FLASH_BLOCK_SIZE / NVMCTRL_PAGE_SIZE; i++) {
|
||||
for (int i = 0; i < INTERNAL_FLASH_BLOCK_SIZE / NVMCTRL_PAGE_SIZE; i++) {
|
||||
do
|
||||
{
|
||||
error_code = nvm_write_buffer(dest + i * NVMCTRL_PAGE_SIZE,
|
||||
@ -199,18 +199,18 @@ bool storage_write_block(const uint8_t *src, uint32_t block) {
|
||||
}
|
||||
}
|
||||
|
||||
mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
|
||||
mp_uint_t internal_flash_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
|
||||
for (size_t i = 0; i < num_blocks; i++) {
|
||||
if (!storage_read_block(dest + i * FLASH_BLOCK_SIZE, block_num + i)) {
|
||||
if (!internal_flash_read_block(dest + i * INTERNAL_FLASH_BLOCK_SIZE, block_num + i)) {
|
||||
return 1; // error
|
||||
}
|
||||
}
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
|
||||
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 (!storage_write_block(src + i * FLASH_BLOCK_SIZE, block_num + i)) {
|
||||
if (!internal_flash_write_block(src + i * INTERNAL_FLASH_BLOCK_SIZE, block_num + i)) {
|
||||
return 1; // error
|
||||
}
|
||||
}
|
||||
@ -223,68 +223,68 @@ mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t
|
||||
// Expose the flash as an object with the block protocol.
|
||||
|
||||
// there is a singleton Flash object
|
||||
STATIC const mp_obj_base_t flash_obj = {&flash_type};
|
||||
STATIC const mp_obj_base_t internal_flash_obj = {&internal_flash_type};
|
||||
|
||||
STATIC mp_obj_t flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t internal_flash_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
|
||||
// return singleton object
|
||||
return (mp_obj_t)&flash_obj;
|
||||
return (mp_obj_t)&internal_flash_obj;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t flash_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
STATIC mp_obj_t internal_flash_obj_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
|
||||
mp_uint_t ret = storage_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
|
||||
mp_uint_t ret = internal_flash_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
|
||||
return MP_OBJ_NEW_SMALL_INT(ret);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(flash_readblocks_obj, flash_readblocks);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(internal_flash_obj_readblocks_obj, internal_flash_obj_readblocks);
|
||||
|
||||
STATIC mp_obj_t flash_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
STATIC mp_obj_t internal_flash_obj_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
mp_uint_t ret = storage_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
|
||||
mp_uint_t ret = internal_flash_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
|
||||
return MP_OBJ_NEW_SMALL_INT(ret);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(flash_writeblocks_obj, flash_writeblocks);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(internal_flash_obj_writeblocks_obj, internal_flash_obj_writeblocks);
|
||||
|
||||
STATIC mp_obj_t flash_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) {
|
||||
STATIC mp_obj_t internal_flash_obj_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) {
|
||||
mp_int_t cmd = mp_obj_get_int(cmd_in);
|
||||
switch (cmd) {
|
||||
case BP_IOCTL_INIT: storage_init(); return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_DEINIT: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly
|
||||
case BP_IOCTL_SYNC: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(storage_get_block_count());
|
||||
case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(storage_get_block_size());
|
||||
case BP_IOCTL_INIT: internal_flash_init(); return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_DEINIT: internal_flash_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly
|
||||
case BP_IOCTL_SYNC: internal_flash_flush(); return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(internal_flash_get_block_count());
|
||||
case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(internal_flash_get_block_size());
|
||||
default: return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(flash_ioctl_obj, flash_ioctl);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(internal_flash_obj_ioctl_obj, internal_flash_obj_ioctl);
|
||||
|
||||
STATIC const mp_map_elem_t flash_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readblocks), (mp_obj_t)&flash_readblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writeblocks), (mp_obj_t)&flash_writeblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ioctl), (mp_obj_t)&flash_ioctl_obj },
|
||||
STATIC const mp_map_elem_t internal_flash_obj_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readblocks), (mp_obj_t)&internal_flash_obj_readblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writeblocks), (mp_obj_t)&internal_flash_obj_writeblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ioctl), (mp_obj_t)&internal_flash_obj_ioctl_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(flash_locals_dict, flash_locals_dict_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(internal_flash_obj_locals_dict, internal_flash_obj_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t flash_type = {
|
||||
const mp_obj_type_t internal_flash_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Flash,
|
||||
.make_new = flash_make_new,
|
||||
.locals_dict = (mp_obj_t)&flash_locals_dict,
|
||||
.name = MP_QSTR_InternalFlash,
|
||||
.make_new = internal_flash_obj_make_new,
|
||||
.locals_dict = (mp_obj_t)&internal_flash_obj_locals_dict,
|
||||
};
|
||||
|
||||
void flash_init_vfs(fs_user_mount_t *vfs) {
|
||||
vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL;
|
||||
vfs->readblocks[0] = (mp_obj_t)&flash_readblocks_obj;
|
||||
vfs->readblocks[1] = (mp_obj_t)&flash_obj;
|
||||
vfs->readblocks[2] = (mp_obj_t)storage_read_blocks; // native version
|
||||
vfs->writeblocks[0] = (mp_obj_t)&flash_writeblocks_obj;
|
||||
vfs->writeblocks[1] = (mp_obj_t)&flash_obj;
|
||||
vfs->writeblocks[2] = (mp_obj_t)storage_write_blocks; // native version
|
||||
vfs->u.ioctl[0] = (mp_obj_t)&flash_ioctl_obj;
|
||||
vfs->u.ioctl[1] = (mp_obj_t)&flash_obj;
|
||||
vfs->readblocks[0] = (mp_obj_t)&internal_flash_obj_readblocks_obj;
|
||||
vfs->readblocks[1] = (mp_obj_t)&internal_flash_obj;
|
||||
vfs->readblocks[2] = (mp_obj_t)internal_flash_read_blocks; // native version
|
||||
vfs->writeblocks[0] = (mp_obj_t)&internal_flash_obj_writeblocks_obj;
|
||||
vfs->writeblocks[1] = (mp_obj_t)&internal_flash_obj;
|
||||
vfs->writeblocks[2] = (mp_obj_t)internal_flash_write_blocks; // native version
|
||||
vfs->u.ioctl[0] = (mp_obj_t)&internal_flash_obj_ioctl_obj;
|
||||
vfs->u.ioctl[1] = (mp_obj_t)&internal_flash_obj;
|
||||
}
|
53
atmel-samd/internal_flash.h
Normal file
53
atmel-samd/internal_flash.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H__
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H__
|
||||
|
||||
#include "mpconfigport.h"
|
||||
|
||||
#define INTERNAL_FLASH_BLOCK_SIZE (512)
|
||||
|
||||
#define INTERNAL_FLASH_SYSTICK_MASK (0x1ff) // 512ms
|
||||
#define INTERNAL_FLASH_IDLE_TICK(tick) (((tick) & INTERNAL_FLASH_SYSTICK_MASK) == 2)
|
||||
|
||||
void internal_flash_init(void);
|
||||
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);
|
||||
mp_uint_t internal_flash_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks);
|
||||
|
||||
extern const struct _mp_obj_type_t internal_flash_type;
|
||||
|
||||
struct _fs_user_mount_t;
|
||||
void flash_init_vfs(struct _fs_user_mount_t *vfs);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_ATMEL_SAMD_INTERNAL_FLASH_H__
|
@ -23,7 +23,6 @@
|
||||
|
||||
#include "mpconfigboard.h"
|
||||
#include "modmachine_pin.h"
|
||||
#include "storage.h"
|
||||
|
||||
fs_user_mount_t fs_user_mount_flash;
|
||||
|
||||
@ -72,6 +71,8 @@ static const char fresh_readme_txt[] =
|
||||
"Please visit http://micropython.org/help/ for further help.\r\n"
|
||||
;
|
||||
|
||||
extern void flash_init_vfs(fs_user_mount_t *vfs);
|
||||
|
||||
// we don't make this function static because it needs a lot of stack and we
|
||||
// want it to be executed without using stack within main() function
|
||||
void init_flash_fs() {
|
||||
|
@ -37,7 +37,6 @@
|
||||
#include "modmachine_dac.h"
|
||||
#include "modmachine_pin.h"
|
||||
#include "modmachine_pwm.h"
|
||||
#include "storage.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE
|
||||
// TODO(tannewt): Add the machine_ prefix to all types so that we don't risk
|
||||
@ -49,7 +48,6 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pwm_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&flash_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) },
|
||||
};
|
||||
|
||||
|
@ -72,6 +72,8 @@
|
||||
#define MICROPY_FSUSERMOUNT (1)
|
||||
#define MICROPY_FATFS_MAX_SS (4096)
|
||||
|
||||
#define FLASH_BLOCK_SIZE (512)
|
||||
|
||||
#define MICROPY_VFS_FAT (1)
|
||||
#define MICROPY_PY_MACHINE (1)
|
||||
#define MICROPY_MODULE_WEAK_LINKS (1)
|
||||
|
299
atmel-samd/spi_flash.c
Normal file
299
atmel-samd/spi_flash.c
Normal file
@ -0,0 +1,299 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asf/sam0/drivers/sercom/spi/spi.h"
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
|
||||
#include "asf/sam0/drivers/nvm/nvm.h"
|
||||
|
||||
#include "spi_flash.h"
|
||||
|
||||
#define TOTAL_SPI_FLASH_SIZE 0x010000
|
||||
|
||||
#define SPI_FLASH_MEM_SEG1_START_ADDR (0x00040000 - TOTAL_SPI_FLASH_SIZE)
|
||||
#define SPI_FLASH_PART1_START_BLOCK (0x100)
|
||||
#define SPI_FLASH_PART1_NUM_BLOCKS (TOTAL_SPI_FLASH_SIZE / SPI_FLASH_BLOCK_SIZE)
|
||||
|
||||
static bool spi_flash_is_initialised = false;
|
||||
|
||||
struct spi_module spi_flash_instance;
|
||||
|
||||
void spi_flash_init(void) {
|
||||
if (!spi_flash_is_initialised) {
|
||||
struct spi_config config_spi_master;
|
||||
spi_get_config_defaults(&config_spi_master);
|
||||
config_spi_master.mux_setting = SPI_FLASH_MUX_SETTING;
|
||||
config_spi_master.pinmux_pad0 = SPI_FLASH_PAD0_PINMUX;
|
||||
config_spi_master.pinmux_pad1 = SPI_FLASH_PAD1_PINMUX;
|
||||
config_spi_master.pinmux_pad2 = SPI_FLASH_PAD2_PINMUX;
|
||||
config_spi_master.pinmux_pad3 = SPI_FLASH_PAD3_PINMUX;
|
||||
config_spi_master.mode_specific.master.baudrate = SPI_FLASH_BAUDRATE;
|
||||
spi_init(&spi_flash_instance, SPI_FLASH_SERCOM, &config_spi_master);
|
||||
spi_enable(&spi_flash_instance);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t spi_flash_get_block_size(void) {
|
||||
return SPI_FLASH_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
uint32_t spi_flash_get_block_count(void) {
|
||||
return SPI_FLASH_PART1_START_BLOCK + SPI_FLASH_PART1_NUM_BLOCKS;
|
||||
}
|
||||
|
||||
void spi_flash_flush(void) {
|
||||
}
|
||||
|
||||
static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) {
|
||||
buf[0] = boot;
|
||||
|
||||
if (num_blocks == 0) {
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
} else {
|
||||
buf[1] = 0xff;
|
||||
buf[2] = 0xff;
|
||||
buf[3] = 0xff;
|
||||
}
|
||||
|
||||
buf[4] = type;
|
||||
|
||||
if (num_blocks == 0) {
|
||||
buf[5] = 0;
|
||||
buf[6] = 0;
|
||||
buf[7] = 0;
|
||||
} else {
|
||||
buf[5] = 0xff;
|
||||
buf[6] = 0xff;
|
||||
buf[7] = 0xff;
|
||||
}
|
||||
|
||||
buf[8] = start_block;
|
||||
buf[9] = start_block >> 8;
|
||||
buf[10] = start_block >> 16;
|
||||
buf[11] = start_block >> 24;
|
||||
|
||||
buf[12] = num_blocks;
|
||||
buf[13] = num_blocks >> 8;
|
||||
buf[14] = num_blocks >> 16;
|
||||
buf[15] = num_blocks >> 24;
|
||||
}
|
||||
|
||||
static uint32_t convert_block_to_flash_addr(uint32_t block) {
|
||||
if (SPI_FLASH_PART1_START_BLOCK <= block && block < SPI_FLASH_PART1_START_BLOCK + SPI_FLASH_PART1_NUM_BLOCKS) {
|
||||
// a block in partition 1
|
||||
block -= SPI_FLASH_PART1_START_BLOCK;
|
||||
return SPI_FLASH_MEM_SEG1_START_ADDR + block * SPI_FLASH_BLOCK_SIZE;
|
||||
}
|
||||
// bad block
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool spi_flash_read_block(uint8_t *dest, uint32_t block) {
|
||||
//printf("RD %u\n", block);
|
||||
if (block == 0) {
|
||||
// fake the MBR so we can decide on our own partition table
|
||||
|
||||
for (int i = 0; i < 446; i++) {
|
||||
dest[i] = 0;
|
||||
}
|
||||
|
||||
build_partition(dest + 446, 0, 0x01 /* FAT12 */, SPI_FLASH_PART1_START_BLOCK, SPI_FLASH_PART1_NUM_BLOCKS);
|
||||
build_partition(dest + 462, 0, 0, 0, 0);
|
||||
build_partition(dest + 478, 0, 0, 0, 0);
|
||||
build_partition(dest + 494, 0, 0, 0, 0);
|
||||
|
||||
dest[510] = 0x55;
|
||||
dest[511] = 0xaa;
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// non-MBR block, get data from flash memory
|
||||
uint32_t src = convert_block_to_flash_addr(block);
|
||||
if (src == -1) {
|
||||
// bad block number
|
||||
return false;
|
||||
}
|
||||
enum status_code error_code;
|
||||
// A block is made up of multiple pages. Read each page
|
||||
// sequentially.
|
||||
for (int i = 0; i < SPI_FLASH_BLOCK_SIZE / NVMCTRL_PAGE_SIZE; i++) {
|
||||
do
|
||||
{
|
||||
error_code = nvm_read_buffer(src + i * NVMCTRL_PAGE_SIZE,
|
||||
dest + i * NVMCTRL_PAGE_SIZE,
|
||||
NVMCTRL_PAGE_SIZE);
|
||||
} while (error_code == STATUS_BUSY);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool spi_flash_write_block(const uint8_t *src, uint32_t block) {
|
||||
if (block == 0) {
|
||||
// can't write MBR, but pretend we did
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// non-MBR block, copy to cache
|
||||
volatile uint32_t dest = convert_block_to_flash_addr(block);
|
||||
if (dest == -1) {
|
||||
// bad block number
|
||||
return false;
|
||||
}
|
||||
enum status_code error_code;
|
||||
// A block is formed by two rows of flash. We must erase each row
|
||||
// before we write back to it.
|
||||
do
|
||||
{
|
||||
error_code = nvm_erase_row(dest);
|
||||
} while (error_code == STATUS_BUSY);
|
||||
if (error_code != STATUS_OK) {
|
||||
return false;
|
||||
}
|
||||
do
|
||||
{
|
||||
error_code = nvm_erase_row(dest + NVMCTRL_ROW_SIZE);
|
||||
} while (error_code == STATUS_BUSY);
|
||||
if (error_code != STATUS_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// A block is made up of multiple pages. Write each page
|
||||
// sequentially.
|
||||
for (int i = 0; i < SPI_FLASH_BLOCK_SIZE / NVMCTRL_PAGE_SIZE; i++) {
|
||||
do
|
||||
{
|
||||
error_code = nvm_write_buffer(dest + i * NVMCTRL_PAGE_SIZE,
|
||||
src + i * NVMCTRL_PAGE_SIZE,
|
||||
NVMCTRL_PAGE_SIZE);
|
||||
} while (error_code == STATUS_BUSY);
|
||||
if (error_code != STATUS_OK) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
mp_uint_t spi_flash_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
|
||||
for (size_t i = 0; i < num_blocks; i++) {
|
||||
if (!spi_flash_read_block(dest + i * SPI_FLASH_BLOCK_SIZE, block_num + i)) {
|
||||
return 1; // error
|
||||
}
|
||||
}
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
mp_uint_t spi_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 (!spi_flash_write_block(src + i * SPI_FLASH_BLOCK_SIZE, block_num + i)) {
|
||||
return 1; // error
|
||||
}
|
||||
}
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings
|
||||
//
|
||||
// Expose the flash as an object with the block protocol.
|
||||
|
||||
// there is a singleton Flash object
|
||||
STATIC const mp_obj_base_t spi_flash_obj = {&spi_flash_type};
|
||||
|
||||
STATIC mp_obj_t spi_flash_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
|
||||
// return singleton object
|
||||
return (mp_obj_t)&spi_flash_obj;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t spi_flash_obj_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
|
||||
mp_uint_t ret = spi_flash_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
|
||||
return MP_OBJ_NEW_SMALL_INT(ret);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(spi_flash_obj_readblocks_obj, spi_flash_obj_readblocks);
|
||||
|
||||
STATIC mp_obj_t spi_flash_obj_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
mp_uint_t ret = spi_flash_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE);
|
||||
return MP_OBJ_NEW_SMALL_INT(ret);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(spi_flash_obj_writeblocks_obj, spi_flash_obj_writeblocks);
|
||||
|
||||
STATIC mp_obj_t spi_flash_obj_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) {
|
||||
mp_int_t cmd = mp_obj_get_int(cmd_in);
|
||||
switch (cmd) {
|
||||
case BP_IOCTL_INIT: spi_flash_init(); return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_DEINIT: spi_flash_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly
|
||||
case BP_IOCTL_SYNC: spi_flash_flush(); return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(spi_flash_get_block_count());
|
||||
case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(spi_flash_get_block_size());
|
||||
default: return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(spi_flash_obj_ioctl_obj, spi_flash_obj_ioctl);
|
||||
|
||||
STATIC const mp_map_elem_t spi_flash_obj_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readblocks), (mp_obj_t)&spi_flash_obj_readblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writeblocks), (mp_obj_t)&spi_flash_obj_writeblocks_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ioctl), (mp_obj_t)&spi_flash_obj_ioctl_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(spi_flash_obj_locals_dict, spi_flash_obj_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t spi_flash_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_SPIFlash,
|
||||
.make_new = spi_flash_obj_make_new,
|
||||
.locals_dict = (mp_obj_t)&spi_flash_obj_locals_dict,
|
||||
};
|
||||
|
||||
void flash_init_vfs(fs_user_mount_t *vfs) {
|
||||
vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL;
|
||||
vfs->readblocks[0] = (mp_obj_t)&spi_flash_obj_readblocks_obj;
|
||||
vfs->readblocks[1] = (mp_obj_t)&spi_flash_obj;
|
||||
vfs->readblocks[2] = (mp_obj_t)spi_flash_read_blocks; // native version
|
||||
vfs->writeblocks[0] = (mp_obj_t)&spi_flash_obj_writeblocks_obj;
|
||||
vfs->writeblocks[1] = (mp_obj_t)&spi_flash_obj;
|
||||
vfs->writeblocks[2] = (mp_obj_t)spi_flash_write_blocks; // native version
|
||||
vfs->u.ioctl[0] = (mp_obj_t)&spi_flash_obj_ioctl_obj;
|
||||
vfs->u.ioctl[1] = (mp_obj_t)&spi_flash_obj;
|
||||
}
|
@ -23,31 +23,31 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_STORAGE_H__
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_STORAGE_H__
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_SPI_FLASH_H__
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_SPI_FLASH_H__
|
||||
|
||||
#include "mpconfigport.h"
|
||||
|
||||
#define FLASH_BLOCK_SIZE (512)
|
||||
#define SPI_FLASH_BLOCK_SIZE (512)
|
||||
|
||||
#define STORAGE_SYSTICK_MASK (0x1ff) // 512ms
|
||||
#define STORAGE_IDLE_TICK(tick) (((tick) & STORAGE_SYSTICK_MASK) == 2)
|
||||
#define SPI_FLASH_SYSTICK_MASK (0x1ff) // 512ms
|
||||
#define SPI_FLASH_IDLE_TICK(tick) (((tick) & SPI_FLASH_SYSTICK_MASK) == 2)
|
||||
|
||||
void storage_init(void);
|
||||
uint32_t storage_get_block_size(void);
|
||||
uint32_t storage_get_block_count(void);
|
||||
void storage_irq_handler(void);
|
||||
void storage_flush(void);
|
||||
bool storage_read_block(uint8_t *dest, uint32_t block);
|
||||
bool storage_write_block(const uint8_t *src, uint32_t block);
|
||||
void spi_flash_init(void);
|
||||
uint32_t spi_flash_get_block_size(void);
|
||||
uint32_t spi_flash_get_block_count(void);
|
||||
void spi_flash_irq_handler(void);
|
||||
void spi_flash_flush(void);
|
||||
bool spi_flash_read_block(uint8_t *dest, uint32_t block);
|
||||
bool spi_flash_write_block(const uint8_t *src, uint32_t block);
|
||||
|
||||
// these return 0 on success, non-zero on error
|
||||
mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks);
|
||||
mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks);
|
||||
mp_uint_t spi_flash_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks);
|
||||
mp_uint_t spi_flash_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks);
|
||||
|
||||
extern const struct _mp_obj_type_t flash_type;
|
||||
extern const struct _mp_obj_type_t spi_flash_type;
|
||||
|
||||
struct _fs_user_mount_t;
|
||||
void flash_init_vfs(struct _fs_user_mount_t *vfs);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_ATMEL_SAMD_STORAGE_H__
|
||||
#endif // __MICROPY_INCLUDED_ATMEL_SAMD_SPI_FLASH_H__
|
@ -24,6 +24,9 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "py/obj.h"
|
||||
|
||||
// these are the values for fs_user_mount_t.flags
|
||||
#define FSUSER_NATIVE (0x0001) // readblocks[2]/writeblocks[2] contain native func
|
||||
#define FSUSER_FREE_OBJ (0x0002) // fs_user_mount_t obj should be freed on umount
|
||||
|
@ -90,7 +90,7 @@ DSTATUS disk_initialize (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive nmuber (0..) */
|
||||
BYTE pdrv /* Physical drive number (0..) */
|
||||
)
|
||||
{
|
||||
fs_user_mount_t *vfs = disk_get_device(pdrv);
|
||||
@ -110,7 +110,7 @@ DSTATUS disk_status (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||
BYTE pdrv, /* Physical drive number (0..) */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
DWORD sector, /* Sector address (LBA) */
|
||||
UINT count /* Number of sectors to read (1..128) */
|
||||
|
Loading…
Reference in New Issue
Block a user