Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update FatFs and add USB-MSC firmware update example #497

Merged
merged 7 commits into from
Nov 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@
[submodule "ext/hathach/tinyusb"]
path = ext/hathach/tinyusb
url = https://github.com/modm-ext/tinyusb-partial.git
[submodule "ext/chan/fatfs"]
path = ext/chan/fatfs
url = https://github.com/modm-ext/fatfs-partial.git
4 changes: 2 additions & 2 deletions examples/stm32f411ceu_mini_f411/blink/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ main()
{
Board::initialize();

LedGreen::set();
Led::set();

while (true)
{
LedGreen::toggle();
Led::toggle();
modm::delay(Button::read() ? 100ms : 500ms);
}

Expand Down
154 changes: 154 additions & 0 deletions examples/stm32f411ceu_mini_f411/usbfatfs/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* Copyright (c) 2020, Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#include <fatfs/ff.h>
#include <tusb.h>
#include <modm/board.hpp>
#include <modm/processing.hpp>
#include <modm/math/utils.hpp>

/* You can test this by updating this firmware with itself:
If you want to use the sanity check:
scons bin && \
cp ../../../build/stm32f411ceu_mini_f411/usb_fatfs/release/usbfatfs.bin . && \
echo -n "F411" >> usbfatfs.bin && \
crc32 usbfatfs.bin | xxd -r -p - >> usbfatfs.bin && \
mv usbfatfs.bin /Volumes/MODM_USB
Otherwise just copy the file as is and `#define WITH_SANITY_CHECK 0`
scons bin && \
cp ../../../build/stm32f411ceu_mini_f411/usb_fatfs/release/usbfatfs.bin /Volumes/MODM_USB
*/

#define WITH_SANITY_CHECK 1

// ----------------------------------------------------------------------------
modm_ramcode
void ram_apply(uint8_t pages, const uint8_t *image, uint32_t length)
{
modm::atomic::Lock l;
// ONLY RAMCODE FROM HERE ON!!!
for (auto page{0u}; page <= pages; page++)
Flash::erase(page);
for (uintptr_t ptr{0}; ptr < length; ptr += sizeof(Flash::MaxWordType))
Flash::program(Flash::OriginAddr + ptr, *(Flash::MaxWordType*)(image + ptr));
NVIC_SystemReset();
}

bool is_valid(FIL *fil, size_t size)
{
#if WITH_SANITY_CHECK
UINT read;
// Validate processor type string:
f_lseek(fil, size-8);
char type[5];
f_read(fil, type, 4, &read);
if (memcmp(type, "F411", 4))
return false;
// Validate CRC32 of the entire image
uint32_t file_crc;
f_read(fil, &file_crc, 4, &read);
file_crc = modm::swap(file_crc);
f_rewind(fil);
uint32_t crc{modm::math::crc32_init};
for (FSIZE_t offset{0}; offset < size-4; offset++)
{
uint8_t data;
f_read(fil, &data, 1, &read);
crc = modm::math::crc32_update(crc, data);
}
f_rewind(fil);
return (~crc == file_crc);
#else
return true;
#endif
}

void
check_for_update()
{
// FAT12 max filename length is 8.3, so this is the max:
static const char *firmware_name = "USBFATFS.BIN";
static constexpr uint8_t buffer_sector{7};
// Note: This allocates all FatFs buffers *ON THE STACK*!
// It may be desirable to allocate them statically for your code!
if (FATFS fs; f_mount(&fs, "", 0) == FR_OK)
{
DIR dj;
if (FILINFO fno; f_findfirst(&dj, &fno, "", firmware_name) == FR_OK and fno.fname[0])
{
if (FIL fil; f_open(&fil, firmware_name, FA_READ) == FR_OK)
{
if (is_valid(&fil, fno.fsize))
{
Board::Led::set();
// We first copy the file into the last Flash section of 128kB.
// It's not guaranteed that the file is stored in FatFs in *one*
// continous chunk and we cannot access FatFs code in ram_apply!!!
Flash::unlock();
Flash::erase(buffer_sector);
uint32_t dst_addr{uint32_t(Flash::getAddr(buffer_sector))};
for (FSIZE_t offset{0}; offset < fno.fsize;
offset += sizeof(Flash::MaxWordType),
dst_addr += sizeof(Flash::MaxWordType))
{
Flash::MaxWordType buffer; UINT read;
f_read(&fil, &buffer, sizeof(Flash::MaxWordType), &read);
Flash::program(dst_addr, buffer);
}
// Jump into RAM and copy from last flash page to first pages
ram_apply(Flash::getPage(fno.fsize), Flash::getAddr(buffer_sector), fno.fsize);
}
f_close(&fil);
}
}
f_closedir(&dj);
f_mount(NULL, "", 1);
}
}

void
initializeFatFs()
{
FATFS fs;
uint8_t fatfs_buffer[FF_MAX_SS];
f_mount(&fs, "", 0);

// initialize ramdisk with Fat12 file system
MKFS_PARM param{FM_FAT | FM_SFD, 0, 0, 0, 0};
f_mkfs("", &param, fatfs_buffer, sizeof(fatfs_buffer));
f_setlabel("MODM_USB");

f_mount(NULL, "", 1);
}

// ----------------------------------------------------------------------------
int
main()
{
Board::initialize();
Board::initializeUsbFs();
initializeFatFs();
tusb_init();

while (true)
{
tud_task();

static modm::PeriodicTimer tmr{1s};
if (tmr.execute()) check_for_update();
}
return 0;
}
15 changes: 15 additions & 0 deletions examples/stm32f411ceu_mini_f411/usbfatfs/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<library>
<extends>modm:mini-f411</extends>
<options>
<option name="modm:build:build.path">../../../build/stm32f411ceu_mini_f411/usb_fatfs</option>
<option name="modm:tinyusb:config">device.msc, device.cdc</option>
</options>
<modules>
<module>modm:processing:timer</module>
<module>modm:tinyusb</module>
<module>modm:fatfs</module>
<module>modm:platform:flash</module>
<module>modm:build:scons</module>
<module>modm:math:utils</module>
</modules>
</library>
103 changes: 103 additions & 0 deletions examples/stm32f411ceu_mini_f411/usbfatfs/ramdisk.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2020, Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#include <fatfs/ff.h>
#include <fatfs/diskio.h>
#include <string.h>
#include <modm/architecture/utils.hpp>

// ----------------------------------------------------------------------------
static constexpr uint32_t sector_size{512};
static constexpr uint32_t sector_count{230};
// Allocate giant array inside a NOLOAD heap section
modm_section(".heap1") uint8_t ram_disk[sector_count * sector_size];

DSTATUS disk_initialize(BYTE pdrv) { return pdrv ? STA_NOINIT : 0; }
DSTATUS disk_status(BYTE pdrv) { return pdrv ? STA_NOINIT : 0; }
DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count)
{
if (pdrv) return RES_NOTRDY;
memcpy(buff, ram_disk + sector * sector_size, count * sector_size);
return RES_OK;
}
DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count)
{
if (pdrv) return RES_NOTRDY;
memcpy(ram_disk + sector * sector_size, buff, count * sector_size);
return RES_OK;
}
DRESULT disk_ioctl(BYTE pdrv, BYTE ctrl, void *buff)
{
if (pdrv) return RES_NOTRDY;
switch (ctrl)
{
case CTRL_SYNC: return RES_OK;
case GET_SECTOR_COUNT: *(LBA_t*)buff = sector_count; return RES_OK;
case GET_SECTOR_SIZE: *(WORD*) buff = sector_size; return RES_OK;
case GET_BLOCK_SIZE: *(DWORD*)buff = 64; return RES_OK;
default: return RES_PARERR;
}
}

// ----------------------------------------------------------------------------
// TinyUSB MSC callbacks also accessing the same RAM disk
#include <tusb.h>

void tud_msc_inquiry_cb(uint8_t, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
{
const char vid[] = "TinyUSB";
const char pid[] = "Mass Storage";
const char rev[] = "1.0";
memcpy(vendor_id , vid, strlen(vid));
memcpy(product_id , pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
}
bool tud_msc_test_unit_ready_cb(uint8_t) { return true; }
bool tud_msc_start_stop_cb(uint8_t, uint8_t, bool, bool) { return true; }
void tud_msc_capacity_cb(uint8_t, uint32_t* block_count, uint16_t* block_size)
{
*block_count = sector_count;
*block_size = sector_size;
}
int32_t tud_msc_read10_cb(uint8_t, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
uint8_t const* addr = ram_disk + sector_size * lba + offset;
memcpy(buffer, addr, bufsize);
return bufsize;
}
int32_t tud_msc_write10_cb(uint8_t, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
uint8_t* addr = ram_disk + sector_size * lba + offset;
memcpy(addr, buffer, bufsize);
return bufsize;
}

int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{
void const* response = NULL;
uint16_t resplen = 0;
bool in_xfer = true;
switch (scsi_cmd[0])
{
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
resplen = 0;
break;

default:
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
resplen = -1;
break;
}
if (resplen > bufsize) resplen = bufsize;
if (response and (resplen > 0) and in_xfer)
memcpy(buffer, response, resplen);
return resplen;
}
1 change: 1 addition & 0 deletions ext/chan/fatfs
Submodule fatfs added at 4680e8
Loading