23#include "px_uf2_defs.h"
30static const char px_uf2_file_content_info[] =
36const char px_uf2_file_content_index_htm[] =
49 {.name =
"INFO_UF2TXT", .content = px_uf2_file_content_info},
50 {.name =
"INDEX HTM", .content = px_uf2_file_content_index_htm},
51 {.name =
"CURRENT UF2", .content =
NULL},
55#define PX_UF2_MEDIA_SECTORS 16000
57#define PX_UF2_SECTOR_SIZE 512
59#define PX_UF2_PAYLOAD_SIZE 256
61#define PX_UF2_FILES PX_SIZEOF_ARRAY(px_uf2_file)
63#define PX_UF2_DIR_ENTRIES (PX_UF2_FILES + 1)
66#define PX_UF2_FILE_SIZE (PX_UF2_CFG_FLASH_SIZE * 2)
68#define PX_UF2_FILE_SIZE_SECTORS (PX_UF2_FILE_SIZE / PX_UF2_SECTOR_SIZE)
70#define PX_UF2_FIRST_SECTOR (PX_UF2_FILES + 1)
72#define PX_UF2_LAST_SECTOR (PX_UF2_FIRST_SECTOR + PX_UF2_FILE_SIZE_SECTORS - 1)
75#define PX_UF2_RESERVED_SECTORS 1
77#define PX_UF2_SECTORS_PER_FAT PX_UDIV_ROUNDUP(PX_UF2_MEDIA_SECTORS * 2, PX_UF2_SECTOR_SIZE)
79#define PX_UF2_ROOT_DIR_SECTORS 4
81#define PX_UF2_DIR_ENTRIES_PER_SECTOR (PX_UF2_SECTOR_SIZE / sizeof(px_uf2_fat_dir_entry_t))
84#define PX_UF2_START_FAT0 PX_UF2_RESERVED_SECTORS
86#define PX_UF2_START_FAT1 (PX_UF2_START_FAT0 + PX_UF2_SECTORS_PER_FAT)
88#define PX_UF2_START_ROOT_DIR (PX_UF2_START_FAT1 + PX_UF2_SECTORS_PER_FAT)
90#define PX_UF2_START_CLUSTERS (PX_UF2_START_ROOT_DIR + PX_UF2_ROOT_DIR_SECTORS)
96 .jmp_boot = {0xeb, 0x3c, 0x90},
97 .oem_name =
"UF2 UF2 ",
98 .bytes_per_sector = PX_UF2_SECTOR_SIZE,
99 .sectors_per_cluster = 1,
100 .res_sector_count = PX_UF2_RESERVED_SECTORS,
102 .root_dir_entry_count = PX_UF2_ROOT_DIR_SECTORS * PX_UF2_DIR_ENTRIES_PER_SECTOR,
103 .total_sectors_16 = PX_UF2_MEDIA_SECTORS - 2,
105 .fat_sectors_16 = PX_UF2_SECTORS_PER_FAT,
106 .sectors_per_track = 1,
109 .total_sectors_32 = 0,
113 .volume_id = 0x00420042,
115 .file_system_type =
"FAT16 ",
118#define UF2_MAX_BLOCKS (PX_UF2_CFG_FLASH_SIZE / 256 + 100)
121 uint32_t nr_of_blocks;
122 uint32_t num_written;
123 uint8_t written_mask[UF2_MAX_BLOCKS / 8 + 1];
143static void px_uf2_padded_memcpy(
char * dst,
const char * src,
int len)
145 for(
int i = 0; i < len; i++)
163 px_uf2_on_wr_flash_block = on_wr_flash_block;
164 px_uf2_on_wr_flash_done = on_wr_flash_done;
169 uint32_t section_index = sector_adr;
172 memset(buf, 0, PX_UF2_SECTOR_SIZE);
178 memcpy(buf, &px_uf2_fat_boot_block,
sizeof(px_uf2_fat_boot_block));
185 else if(sector_adr < PX_UF2_START_ROOT_DIR)
188 section_index -= PX_UF2_START_FAT0;
190 if(section_index >= PX_UF2_SECTORS_PER_FAT)
193 section_index -= PX_UF2_SECTORS_PER_FAT;
197 if(section_index == 0)
203 buf[0] = px_uf2_fat_boot_block.media;
204 for(
int i = 1; i < (PX_UF2_FILES * 2 + 4); i++)
210 for(
int i = 0; i < 256; i++)
212 uint32_t cluster = section_index * 256 + i;
214 if( (cluster >= PX_UF2_FIRST_SECTOR)
215 &&(cluster <= PX_UF2_LAST_SECTOR ) )
218 if(cluster != PX_UF2_LAST_SECTOR)
221 ((uint16_t *)buf)[i] = cluster + 1;
226 ((uint16_t *)buf)[i] = 0xffff;
233 else if(sector_adr < PX_UF2_START_CLUSTERS)
236 section_index -= PX_UF2_START_ROOT_DIR;
238 if(section_index == 0)
243 px_uf2_padded_memcpy(dir_entry->name, (
char *)px_uf2_fat_boot_block.volume_label, 11);
244 dir_entry->attrs = PX_UF2_FAT_DIR_ATTR_VOLUME_ID | PX_UF2_FAT_DIR_ATTR_ARCHIVE;
246 for(
int i = 0; i < PX_UF2_FILES; i++)
251 if(file->content !=
NULL)
253 dir_entry->size = strlen(file->content);
257 dir_entry->size = PX_UF2_FILE_SIZE;
259 dir_entry->start_cluster = i + 2;
260 px_uf2_padded_memcpy(dir_entry->name, file->name, 11);
261 dir_entry->create_date = 0x4d99;
262 dir_entry->update_date = 0x4d99;
271 section_index -= PX_UF2_START_CLUSTERS;
273 if(section_index < PX_UF2_FILES - 1)
277 px_uf2_file[section_index].content,
278 strlen(px_uf2_file[section_index].content));
283 section_index -= PX_UF2_FILES - 1;
284 uint32_t addr = section_index * 256;
290 bl->magic_start0 = PX_UF2_MAGIC_START0;
291 bl->magic_start1 = PX_UF2_MAGIC_START1;
293 bl->target_addr = addr;
294 bl->payload_size = 256;
295 bl->block_nr = section_index;
297 bl->flags |= PX_UF2_FLAG_FAMILYID_PRESENT;
299 memcpy(bl->data, (
void *)addr, bl->payload_size);
300 bl->magic_end = PX_UF2_MAGIC_END;
311 if( (bl->magic_start0 != PX_UF2_MAGIC_START0)
312 ||(bl->magic_start1 != PX_UF2_MAGIC_START1)
313 ||(bl->magic_end != PX_UF2_MAGIC_END ) )
320 if( ((bl->flags & PX_UF2_FLAG_FAMILYID_PRESENT) == 0)
328 if( (bl->flags & PX_UF2_FLAG_NOFLASH )
329 ||(bl->payload_size != PX_UF2_PAYLOAD_SIZE )
330 ||(bl->target_addr & (PX_UF2_PAYLOAD_SIZE - 1) )
336 PX_LOG_E(
"Invalid target address 0x%08X", bl->target_addr);
340 PX_LOG_D(
"Write 0x%08X %u bytes", bl->target_addr, bl->payload_size);
341 (*px_uf2_on_wr_flash_block)(bl->data, bl->target_addr, bl->payload_size);
344 if(bl->nr_of_blocks == 0)
350 if(px_uf2_write_state.nr_of_blocks != bl->nr_of_blocks)
352 if(bl->nr_of_blocks >= UF2_MAX_BLOCKS || px_uf2_write_state.nr_of_blocks)
355 px_uf2_write_state.nr_of_blocks = 0xffffffff;
360 px_uf2_write_state.nr_of_blocks = bl->nr_of_blocks;
365 if(bl->block_nr < UF2_MAX_BLOCKS)
367 uint32_t pos = bl->block_nr / 8;
368 uint8_t mask = 1 << (bl->block_nr % 8);
371 if(!(px_uf2_write_state.written_mask[pos] & mask))
374 px_uf2_write_state.written_mask[pos] |= mask;
376 px_uf2_write_state.num_written++;
378 if(px_uf2_write_state.num_written >= px_uf2_write_state.nr_of_blocks)
382 (*px_uf2_on_wr_flash_done)();
#define NULL
NULL pointer.
#define PX_LOG_D(format,...)
Macro to display a formatted DEBUG message.
#define PX_LOG_NAME(name)
Macro to declare a log name string once for each file to reduce code size.
#define PX_LOG_E(format,...)
Macro to display a formatted ERROR message.
#define PX_UF2_CFG_INFO_VERSION
Info file version text.
void px_uf2_on_wr_sector(uint32_t sector_adr, const uint8_t *buf)
Function that must be called when a 512 byte sector is written over USB Mass Storage.
void px_uf2_on_rd_sector(uint32_t sector_adr, uint8_t *buf)
Function that must be called when a 512 byte sector is read over USB Mass Storage.
#define PX_UF2_CFG_INDEX_URL
index.htm file URL
void px_uf2_init(px_uf2_on_wr_flash_block_t on_wr_flash_block, px_uf2_on_wr_flash_done_t on_wr_flash_done)
Initialise UF2 module.
#define PX_UF2_CFG_INFO_BOARD_ID
Info file board ID text.
#define PX_UF2_CFG_FAMILY_ID
Family ID.
#define PX_UF2_CFG_INFO_MODEL
Info file model text.
#define PX_UF2_CFG_FLASH_START_ADR
Start address of flash to write to (reserved space for bootloader)
#define PX_UF2_CFG_VOLUME_LABEL
FAT16 volume label.
void(* px_uf2_on_wr_flash_done_t)(void)
Definition of a pointer to a function that will be called when last block has been written.
#define PX_UF2_CFG_FLASH_SIZE
Flash size.
void(* px_uf2_on_wr_flash_block_t)(const uint8_t *data, uint32_t adr, size_t nr_of_bytes)
Definition of a pointer to a function that will be called to write a block of data to flash.