Skip to content

Commit 73f4574

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 afb9b6d commit 73f4574

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
@@ -2146,34 +2146,45 @@ struct picoboot_memory_access : public memory_access {
21462146
vector<uint8_t> write_data; // used when erasing flash
21472147
if (flash == get_memory_type(address, model)) {
21482148
connection.exit_xip();
2149-
if (erase) {
2150-
// Do automatically erase flash, and make it aligned
2151-
// we have to erase in whole pages
2152-
range aligned_range(address & ~(FLASH_SECTOR_ERASE_SIZE - 1),
2153-
((address + size) & ~(FLASH_SECTOR_ERASE_SIZE - 1)) + FLASH_SECTOR_ERASE_SIZE);
2154-
assert(aligned_range.contains(address));
2155-
assert(aligned_range.contains(address + size));
2156-
2157-
uint32_t pre_len = address - aligned_range.from;
2158-
uint32_t post_len = aligned_range.to - (address + size);
2159-
assert(pre_len + size + post_len == aligned_range.len());
2160-
2161-
// save data before the changing data
2162-
write_data.resize(pre_len);
2163-
if (pre_len) read(aligned_range.from, write_data.data(), write_data.size(), false);
2164-
// now add the data that is changing
2165-
write_data.insert(write_data.end(), buffer, buffer + size);
2166-
// save data after the changing data
2167-
write_data.resize(aligned_range.len());
2168-
if (post_len) read(address + size, write_data.data() + pre_len + size, post_len, false);
2169-
2170-
// Do the erase
2171-
connection.flash_erase(aligned_range.from, aligned_range.len());
2172-
2173-
// Update what will now be written
2174-
address = aligned_range.from;
2175-
buffer = write_data.data();
2176-
size = aligned_range.len();
2149+
// Flash Translation Layer - auto-erase, and only write changed data
2150+
if (enable_ftl) {
2151+
// Check what's there already
2152+
write_data.resize(size);
2153+
read(address, write_data.data(), size, false);
2154+
// Check if we even need to write
2155+
if (std::equal(write_data.cbegin(), write_data.cend(), buffer)) {
2156+
return;
2157+
}
2158+
// Check if we need to erase (ie check for non 0xff)
2159+
if (!std::all_of(write_data.cbegin(), write_data.cend(), [](uint8_t v) { return v == 0xff; })) {
2160+
// Do automatically erase flash, and make it aligned
2161+
// we have to erase in whole pages
2162+
range aligned_range(address & ~(FLASH_SECTOR_ERASE_SIZE - 1),
2163+
((address + size) & ~(FLASH_SECTOR_ERASE_SIZE - 1)) + FLASH_SECTOR_ERASE_SIZE);
2164+
assert(aligned_range.contains(address));
2165+
assert(aligned_range.contains(address + size));
2166+
2167+
uint32_t pre_len = address - aligned_range.from;
2168+
uint32_t post_len = aligned_range.to - (address + size);
2169+
assert(pre_len + size + post_len == aligned_range.len());
2170+
2171+
// save data before the changing data
2172+
write_data.resize(pre_len);
2173+
if (pre_len) read(aligned_range.from, write_data.data(), write_data.size(), false);
2174+
// now add the data that is changing
2175+
write_data.insert(write_data.end(), buffer, buffer + size);
2176+
// save data after the changing data
2177+
write_data.resize(aligned_range.len());
2178+
if (post_len) read(address + size, write_data.data() + pre_len + size, post_len, false);
2179+
2180+
// Do the erase
2181+
connection.flash_erase(aligned_range.from, aligned_range.len());
2182+
2183+
// Update what will now be written
2184+
address = aligned_range.from;
2185+
buffer = write_data.data();
2186+
size = aligned_range.len();
2187+
}
21772188
}
21782189
}
21792190
if (is_transfer_aligned(address, model) && is_transfer_aligned(address + size, model)) {
@@ -2192,7 +2203,8 @@ struct picoboot_memory_access : public memory_access {
21922203
write(addr, (uint8_t *)v.data(), v.size() * sizeof(typename raw_type_mapping<T>::access_type));
21932204
}
21942205

2195-
bool erase = false;
2206+
// Enable Flash Translation Layer, which performs automatic erase, and only writes changed data
2207+
bool enable_ftl = false;
21962208
private:
21972209
picoboot::connection& connection;
21982210
vector<std::tuple<uint32_t,uint32_t,vector<uint8_t>>> flash_cache;
@@ -4187,7 +4199,7 @@ bool config_command::execute(device_map &devices) {
41874199
picoboot::connection connection(std::get<2>(handles), std::get<0>(handles));
41884200
picoboot_memory_access access(connection);
41894201
// Enable auto-erase
4190-
access.erase = true;
4202+
access.enable_ftl = true;
41914203
auto partitions = get_partitions(connection);
41924204
vector<uint32_t> starts;
41934205
if (partitions) {
@@ -5471,7 +5483,12 @@ void setup_bdevfs(picoboot::connection con) {
54715483
string s = ss.str();
54725484
fos << "embedded drive: " << s << "\n";
54735485

5474-
bdevfs_setup.base_addr = bi_bdev.address;
5486+
if (bi_bdev.address < FLASH_START) {
5487+
// Some devices have the block device address relative to the start of flash
5488+
bdevfs_setup.base_addr = bi_bdev.address + FLASH_START;
5489+
} else {
5490+
bdevfs_setup.base_addr = bi_bdev.address;
5491+
}
54755492
bdevfs_setup.size = bi_bdev.size;
54765493
});
54775494
visitor.visit(access, hdr);
@@ -5528,15 +5545,17 @@ DWORD get_fattime (void) {
55285545
return fattime;
55295546
}
55305547

5548+
static_assert(FF_MAX_SS == FF_MIN_SS, "FF_MAX_SS must be equal to FF_MIN_SS");
5549+
#define SECTOR_SIZE FF_MAX_SS
55315550

55325551
DRESULT disk_read (void *drv, BYTE* buff, DWORD sector, UINT count) {
5533-
bdevfs_setup.access->read(bdevfs_setup.base_addr + (sector * FF_MAX_SS), (uint8_t*)buff, count * FF_MAX_SS, false);
5552+
bdevfs_setup.access->read(bdevfs_setup.base_addr + (sector * SECTOR_SIZE), (uint8_t*)buff, count * SECTOR_SIZE, false);
55345553
return RES_OK;
55355554
}
55365555

55375556
DRESULT disk_write (void *drv, const BYTE* buff, DWORD sector, UINT count) {
55385557
if (bdevfs_setup.writeable) {
5539-
bdevfs_setup.access->write(bdevfs_setup.base_addr + (sector * FF_MAX_SS), (uint8_t*)buff, count * FF_MAX_SS);
5558+
bdevfs_setup.access->write(bdevfs_setup.base_addr + (sector * SECTOR_SIZE), (uint8_t*)buff, count * SECTOR_SIZE);
55405559
return RES_OK;
55415560
} else {
55425561
fail(ERROR_NOT_POSSIBLE, "This block device is not writeable");
@@ -5550,11 +5569,15 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
55505569
return RES_OK;
55515570

55525571
case GET_SECTOR_COUNT:
5553-
*(DWORD*)buff = bdevfs_setup.size / FF_MAX_SS;
5572+
*(DWORD*)buff = bdevfs_setup.size / SECTOR_SIZE;
5573+
return RES_OK;
5574+
5575+
case GET_SECTOR_SIZE:
5576+
*(DWORD*)buff = SECTOR_SIZE;
55545577
return RES_OK;
55555578

55565579
case GET_BLOCK_SIZE:
5557-
*(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / FF_MAX_SS;
5580+
*(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / SECTOR_SIZE;
55585581
return RES_OK;
55595582

55605583
case IOCTL_INIT:
@@ -5564,6 +5587,24 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
55645587
return RES_OK;
55655588
}
55665589

5590+
case CTRL_TRIM: {
5591+
if (bdevfs_setup.writeable) {
5592+
DWORD* p = (DWORD*)buff;
5593+
uint32_t start = (*p * SECTOR_SIZE) + bdevfs_setup.base_addr;
5594+
uint32_t end = (*(p + 1) * SECTOR_SIZE) + bdevfs_setup.base_addr;
5595+
// Only trim complete flash sectors
5596+
if (start % FLASH_SECTOR_ERASE_SIZE) start += FLASH_SECTOR_ERASE_SIZE - (start % FLASH_SECTOR_ERASE_SIZE);
5597+
end -= end % FLASH_SECTOR_ERASE_SIZE;
5598+
for (uint32_t addr = start; addr < end; addr += FLASH_SECTOR_ERASE_SIZE) {
5599+
bdevfs_setup.con->flash_erase(addr, FLASH_SECTOR_ERASE_SIZE);
5600+
}
5601+
return RES_OK;
5602+
} else {
5603+
fail(ERROR_NOT_POSSIBLE, "This block device is not writeable");
5604+
return RES_WRPRT;
5605+
}
5606+
}
5607+
55675608
default:
55685609
fail(ERROR_NOT_POSSIBLE, "Unknown ioctl %d", cmd);
55695610
return RES_PARERR;
@@ -5635,14 +5676,14 @@ void do_fatfs_op(fatfs_op_fn fatfs_op) {
56355676
FATFS fatfs;
56365677

56375678
// Enable auto-erase, as FatFS has no Flash Translation Layer
5638-
bdevfs_setup.access->erase = true;
5679+
bdevfs_setup.access->enable_ftl = true;
56395680

56405681
int err = f_mount(&fatfs);
56415682
if (err == FR_NO_FILESYSTEM) {
56425683
if (settings.bdev.format) {
56435684
if (bdevfs_setup.formattable) {
56445685
fos << "Formatting FatFS file system\n";
5645-
uint8_t work_buf[FF_MAX_SS];
5686+
uint8_t work_buf[SECTOR_SIZE];
56465687
err = f_mkfs(&fatfs, FM_ANY | FM_SFD, 0, work_buf, sizeof(work_buf));
56475688
if (err) {
56485689
fail(ERROR_CONNECTION, "FatFS Format Error %d", err);

0 commit comments

Comments
 (0)