Skip to content

Commit ba574e8

Browse files
committed
Fix support for CircuitPython block device (Fat) and add full Flash Translation Layer (prevents doing lots of erases)
Change Fat sector size back to 512, and consequently add in flash translation error - wasn't needed before with 4096 sector size Also enable LFN support
1 parent 693f3b3 commit ba574e8

File tree

4 files changed

+85
-42
lines changed

4 files changed

+85
-42
lines changed

lib/oofatfs/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cc_library(
44
name = "fatfs",
55
srcs = [
66
"src/ff.c",
7+
"src/ffunicode.c",
78
],
89
hdrs = [
910
"src/ff.h",

lib/oofatfs/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_library(fatfs INTERFACE)
22

33
target_sources(fatfs INTERFACE
4-
${CMAKE_CURRENT_LIST_DIR}/src/ff.c)
4+
${CMAKE_CURRENT_LIST_DIR}/src/ff.c
5+
${CMAKE_CURRENT_LIST_DIR}/src/ffunicode.c)
56

67
target_include_directories(fatfs INTERFACE ${CMAKE_CURRENT_LIST_DIR}/src)

lib/oofatfs/src/ffconf.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
*/
106106

107107

108-
#define FF_USE_LFN 0
108+
#define FF_USE_LFN 1
109109
#define FF_MAX_LFN 255
110110
/* The FF_USE_LFN switches the support for LFN (long file name).
111111
/
@@ -198,8 +198,8 @@
198198
/ funciton will be available. */
199199

200200

201-
#define FF_MIN_SS 4096
202-
#define FF_MAX_SS 4096
201+
#define FF_MIN_SS 512
202+
#define FF_MAX_SS 512
203203
/* This set of options configures the range of sector size to be supported. (512,
204204
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
205205
/ harddisk. But a larger value may be required for on-board flash memory and some
@@ -208,7 +208,7 @@
208208
/ GET_SECTOR_SIZE command. */
209209

210210

211-
#define FF_USE_TRIM 0
211+
#define FF_USE_TRIM 1
212212
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
213213
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
214214
/ disk_ioctl() function. */

main.cpp

Lines changed: 78 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,34 +2083,45 @@ struct picoboot_memory_access : public memory_access {
20832083
vector<uint8_t> write_data; // used when erasing flash
20842084
if (flash == get_memory_type(address, model)) {
20852085
connection.exit_xip();
2086-
if (erase) {
2087-
// Do automatically erase flash, and make it aligned
2088-
// we have to erase in whole pages
2089-
range aligned_range(address & ~(FLASH_SECTOR_ERASE_SIZE - 1),
2090-
((address + size) & ~(FLASH_SECTOR_ERASE_SIZE - 1)) + FLASH_SECTOR_ERASE_SIZE);
2091-
assert(aligned_range.contains(address));
2092-
assert(aligned_range.contains(address + size));
2093-
2094-
uint32_t pre_len = address - aligned_range.from;
2095-
uint32_t post_len = aligned_range.to - (address + size);
2096-
assert(pre_len + size + post_len == aligned_range.len());
2097-
2098-
// save data before the changing data
2099-
write_data.resize(pre_len);
2100-
if (pre_len) read(aligned_range.from, write_data.data(), write_data.size(), false);
2101-
// now add the data that is changing
2102-
write_data.insert(write_data.end(), buffer, buffer + size);
2103-
// save data after the changing data
2104-
write_data.resize(aligned_range.len());
2105-
if (post_len) read(address + size, write_data.data() + pre_len + size, post_len, false);
2106-
2107-
// Do the erase
2108-
connection.flash_erase(aligned_range.from, aligned_range.len());
2109-
2110-
// Update what will now be written
2111-
address = aligned_range.from;
2112-
buffer = write_data.data();
2113-
size = aligned_range.len();
2086+
// Flash Translation Layer - auto-erase, and only write changed data
2087+
if (enable_ftl) {
2088+
// Check what's there already
2089+
write_data.resize(size);
2090+
read(address, write_data.data(), size, false);
2091+
// Check if we even need to write
2092+
if (std::equal(write_data.cbegin(), write_data.cend(), buffer)) {
2093+
return;
2094+
}
2095+
// Check if we need to erase (ie check for non 0xff)
2096+
if (!std::all_of(write_data.cbegin(), write_data.cend(), [](uint8_t v) { return v == 0xff; })) {
2097+
// Do automatically erase flash, and make it aligned
2098+
// we have to erase in whole pages
2099+
range aligned_range(address & ~(FLASH_SECTOR_ERASE_SIZE - 1),
2100+
((address + size) & ~(FLASH_SECTOR_ERASE_SIZE - 1)) + FLASH_SECTOR_ERASE_SIZE);
2101+
assert(aligned_range.contains(address));
2102+
assert(aligned_range.contains(address + size));
2103+
2104+
uint32_t pre_len = address - aligned_range.from;
2105+
uint32_t post_len = aligned_range.to - (address + size);
2106+
assert(pre_len + size + post_len == aligned_range.len());
2107+
2108+
// save data before the changing data
2109+
write_data.resize(pre_len);
2110+
if (pre_len) read(aligned_range.from, write_data.data(), write_data.size(), false);
2111+
// now add the data that is changing
2112+
write_data.insert(write_data.end(), buffer, buffer + size);
2113+
// save data after the changing data
2114+
write_data.resize(aligned_range.len());
2115+
if (post_len) read(address + size, write_data.data() + pre_len + size, post_len, false);
2116+
2117+
// Do the erase
2118+
connection.flash_erase(aligned_range.from, aligned_range.len());
2119+
2120+
// Update what will now be written
2121+
address = aligned_range.from;
2122+
buffer = write_data.data();
2123+
size = aligned_range.len();
2124+
}
21142125
}
21152126
}
21162127
if (is_transfer_aligned(address, model) && is_transfer_aligned(address + size, model)) {
@@ -2128,7 +2139,8 @@ struct picoboot_memory_access : public memory_access {
21282139
write(addr, (uint8_t *)v.data(), v.size() * sizeof(typename raw_type_mapping<T>::access_type));
21292140
}
21302141

2131-
bool erase = false;
2142+
// Enable Flash Translation Layer, which performs automatic erase, and only writes changed data
2143+
bool enable_ftl = false;
21322144
private:
21332145
picoboot::connection& connection;
21342146
};
@@ -4122,7 +4134,7 @@ bool config_command::execute(device_map &devices) {
41224134
picoboot::connection connection(std::get<2>(handles), std::get<0>(handles));
41234135
picoboot_memory_access access(connection);
41244136
// Enable auto-erase
4125-
access.erase = true;
4137+
access.enable_ftl = true;
41264138
auto partitions = get_partitions(connection);
41274139
vector<uint32_t> starts;
41284140
if (partitions) {
@@ -5395,7 +5407,12 @@ void setup_bdevfs(picoboot::connection con) {
53955407
string s = ss.str();
53965408
fos << "embedded drive: " << s << "\n";
53975409

5398-
bdevfs_setup.base_addr = bi_bdev.address;
5410+
if (bi_bdev.address < FLASH_START) {
5411+
// Some devices have the block device address relative to the start of flash
5412+
bdevfs_setup.base_addr = bi_bdev.address + FLASH_START;
5413+
} else {
5414+
bdevfs_setup.base_addr = bi_bdev.address;
5415+
}
53995416
bdevfs_setup.size = bi_bdev.size;
54005417
});
54015418
visitor.visit(access, hdr);
@@ -5452,15 +5469,17 @@ DWORD get_fattime (void) {
54525469
return fattime;
54535470
}
54545471

5472+
static_assert(FF_MAX_SS == FF_MIN_SS, "FF_MAX_SS must be equal to FF_MIN_SS");
5473+
#define SECTOR_SIZE FF_MAX_SS
54555474

54565475
DRESULT disk_read (void *drv, BYTE* buff, DWORD sector, UINT count) {
5457-
bdevfs_setup.access->read(bdevfs_setup.base_addr + (sector * FF_MAX_SS), (uint8_t*)buff, count * FF_MAX_SS, false);
5476+
bdevfs_setup.access->read(bdevfs_setup.base_addr + (sector * SECTOR_SIZE), (uint8_t*)buff, count * SECTOR_SIZE, false);
54585477
return RES_OK;
54595478
}
54605479

54615480
DRESULT disk_write (void *drv, const BYTE* buff, DWORD sector, UINT count) {
54625481
if (bdevfs_setup.writeable) {
5463-
bdevfs_setup.access->write(bdevfs_setup.base_addr + (sector * FF_MAX_SS), (uint8_t*)buff, count * FF_MAX_SS);
5482+
bdevfs_setup.access->write(bdevfs_setup.base_addr + (sector * SECTOR_SIZE), (uint8_t*)buff, count * SECTOR_SIZE);
54645483
return RES_OK;
54655484
} else {
54665485
fail(ERROR_NOT_POSSIBLE, "This block device is not writeable");
@@ -5474,11 +5493,15 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
54745493
return RES_OK;
54755494

54765495
case GET_SECTOR_COUNT:
5477-
*(DWORD*)buff = bdevfs_setup.size / FF_MAX_SS;
5496+
*(DWORD*)buff = bdevfs_setup.size / SECTOR_SIZE;
5497+
return RES_OK;
5498+
5499+
case GET_SECTOR_SIZE:
5500+
*(DWORD*)buff = SECTOR_SIZE;
54785501
return RES_OK;
54795502

54805503
case GET_BLOCK_SIZE:
5481-
*(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / FF_MAX_SS;
5504+
*(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / SECTOR_SIZE;
54825505
return RES_OK;
54835506

54845507
case IOCTL_INIT:
@@ -5488,6 +5511,24 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
54885511
return RES_OK;
54895512
}
54905513

5514+
case CTRL_TRIM: {
5515+
if (bdevfs_setup.writeable) {
5516+
DWORD* p = (DWORD*)buff;
5517+
uint32_t start = (*p * SECTOR_SIZE) + bdevfs_setup.base_addr;
5518+
uint32_t end = (*(p + 1) * SECTOR_SIZE) + bdevfs_setup.base_addr;
5519+
// Only trim complete flash sectors
5520+
if (start % FLASH_SECTOR_ERASE_SIZE) start += FLASH_SECTOR_ERASE_SIZE - (start % FLASH_SECTOR_ERASE_SIZE);
5521+
end -= end % FLASH_SECTOR_ERASE_SIZE;
5522+
for (uint32_t addr = start; addr < end; addr += FLASH_SECTOR_ERASE_SIZE) {
5523+
bdevfs_setup.con->flash_erase(addr, FLASH_SECTOR_ERASE_SIZE);
5524+
}
5525+
return RES_OK;
5526+
} else {
5527+
fail(ERROR_NOT_POSSIBLE, "This block device is not writeable");
5528+
return RES_WRPRT;
5529+
}
5530+
}
5531+
54915532
default:
54925533
fail(ERROR_NOT_POSSIBLE, "Unknown ioctl %d", cmd);
54935534
return RES_PARERR;
@@ -5559,14 +5600,14 @@ void do_fatfs_op(fatfs_op_fn fatfs_op) {
55595600
FATFS fatfs;
55605601

55615602
// Enable auto-erase, as FatFS has no Flash Translation Layer
5562-
bdevfs_setup.access->erase = true;
5603+
bdevfs_setup.access->enable_ftl = true;
55635604

55645605
int err = f_mount(&fatfs);
55655606
if (err == FR_NO_FILESYSTEM) {
55665607
if (settings.bdev.format) {
55675608
if (bdevfs_setup.formattable) {
55685609
fos << "Formatting FatFS file system\n";
5569-
uint8_t work_buf[FF_MAX_SS];
5610+
uint8_t work_buf[SECTOR_SIZE];
55705611
err = f_mkfs(&fatfs, FM_ANY | FM_SFD, 0, work_buf, sizeof(work_buf));
55715612
if (err) {
55725613
fail(ERROR_CONNECTION, "FatFS Format Error %d", err);

0 commit comments

Comments
 (0)