From 07053ab8232315352de18ac2be763d0d42d02d10 Mon Sep 17 00:00:00 2001 From: alexcekay Date: Mon, 30 Mar 2026 18:17:42 +0200 Subject: [PATCH] v6s: support EEPROM-only boards alongside FRAM variants --- boards/auterion/fmu-v6s/src/board_config.h | 3 + boards/auterion/fmu-v6s/src/init.c | 136 +++++++++++++++++++-- boards/auterion/fmu-v6s/src/mtd.cpp | 76 +++++++++--- 3 files changed, 192 insertions(+), 23 deletions(-) diff --git a/boards/auterion/fmu-v6s/src/board_config.h b/boards/auterion/fmu-v6s/src/board_config.h index 4e40de72eb..beb33051d5 100644 --- a/boards/auterion/fmu-v6s/src/board_config.h +++ b/boards/auterion/fmu-v6s/src/board_config.h @@ -202,6 +202,9 @@ extern void stm32_spiinitialize(void); extern void board_peripheral_reset(int ms); +/* Initialise the FRAM MTD. */ +extern void board_configure_fram(void); + #include #endif /* __ASSEMBLY__ */ diff --git a/boards/auterion/fmu-v6s/src/init.c b/boards/auterion/fmu-v6s/src/init.c index 39cfe5c914..784ce509a1 100644 --- a/boards/auterion/fmu-v6s/src/init.c +++ b/boards/auterion/fmu-v6s/src/init.c @@ -55,10 +55,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -70,10 +72,14 @@ #include #include #include +#include #include -#include +#include #include #include +#include +#include +#include /**************************************************************************** * Pre-Processor Definitions @@ -158,6 +164,80 @@ stm32_boardinitialize(void) px4_gpio_init(gpio, arraySize(gpio)); } +#if !defined(BOOTLOADER) +/**************************************************************************** + * Name: eeprom_read_and_check_mft + * + * Description: + * Read an mtd_mft_v0_t from the EEPROM at the given byte offset and + * validate its CRC. Returns true if the record has a recognised version + * field and a matching CRC16. + ****************************************************************************/ + +static bool eeprom_read_and_check_mft(struct i2c_master_s *i2c, uint16_t address) +{ + uint8_t addr_write[2] = { (uint8_t)(address >> 8), (uint8_t)(address & 0xFF) }; + mtd_mft_v0_t mft = {}; + struct i2c_msg_s msgs[2] = { + { .frequency = 400000, .addr = 0x50, .flags = 0, .buffer = addr_write, .length = sizeof(addr_write) }, + { .frequency = 400000, .addr = 0x50, .flags = I2C_M_READ, .buffer = (uint8_t *) &mft, .length = sizeof(mft) }, + }; + + int retries = 5; + + while (I2C_TRANSFER(i2c, msgs, 2) != OK) { + if (--retries == 0) { + syslog(LOG_WARNING, "[boot] EEPROM I2C comm failed\n"); + return false; + } + } + + if (mft.version.id != MTD_MFT_v0) { return false; } + + uint16_t computed = crc16_signature(CRC16_INITIAL, sizeof(mft) - sizeof(mft.crc), (const uint8_t *)&mft); + return computed == mft.crc; +} + +/**************************************************************************** + * Name: detect_layout_is_fram + * + * Description: + * Determine which EEPROM layout is present by reading MTD_MFT_VER from + * the two possible byte offsets and validating its CRC. + ****************************************************************************/ + +static bool detect_layout_is_fram(void) +{ + struct i2c_master_s *i2c = px4_i2cbus_initialize(4); + bool ret; + + if (!i2c) { + syslog(LOG_WARNING, "[boot] EEPROM I2C init failed, defaulting to FRAM layout\n"); + ret = true; + goto out; + } + + /* FRAM-variant: MTD_MFT_VER after MTD_CALDATA (224 blocks x 32 B). */ + if (eeprom_read_and_check_mft(i2c, 224u * 32u)) { + ret = true; + goto out; + } + + /* EEPROM-only: MTD_MFT_VER is the first partition (0 blocks x 32 B)*/ + if (eeprom_read_and_check_mft(i2c, 0u)) { + ret = false; + goto out; + } + + /* Neither offset contains a valid record, default to FRAM layout. */ + ret = true; + +out: + px4_i2cbus_uninitialize(i2c); + return ret; +} +#endif /* !defined(BOOTLOADER) */ + /**************************************************************************** * Name: board_app_initialize * @@ -187,15 +267,19 @@ __EXPORT int board_app_initialize(uintptr_t arg) { #if !defined(BOOTLOADER) /* Need hrt running before using the ADC */ - px4_platform_init(); - // Use the default HW_VER_REV(0x0,0x0) for Ramtron - + /* First SPI init. HW version is not enabled yet, so only always-enabled + * buses/devices can be used. */ stm32_spiinitialize(); - /* Configure the HW based on the manifest */ + bool fram_available = detect_layout_is_fram(); + if (fram_available) { + board_configure_fram(); + } + + /* Configure the HW based on the manifest */ px4_platform_configure(); if (OK == board_determine_hw_info()) { @@ -206,14 +290,24 @@ __EXPORT int board_app_initialize(uintptr_t arg) syslog(LOG_ERR, "[boot] Failed to read HW revision and version\n"); } - /* Configure the Actual SPI interfaces (after we determined the HW version) */ + /* EEPROM-only boards use a 128Kbit chip: 512 pages × 32 B = 16 KB. + * FRAM boards use a 64Kbit EEPROM: 256 pages × 32 B = 8 KB. + * Always use 32-byte page writes (safe for 64-byte page chips too). */ + unsigned int mtd_count = 0; + mtd_instance_s **instances = px4_mtd_get_instances(&mtd_count); + uint16_t eeprom_npages = fram_available ? 256 : 512; + /* instances[0] is always EEPROM on both board variants. */ + if (mtd_count > 0 && instances[0]->mtd_dev != NULL) { + px4_at24c_set_npages(instances[0]->mtd_dev, eeprom_npages); + } + + /* Second SPI init. Now HW version is determined and complete init can be done. */ stm32_spiinitialize(); board_spi_reset(10, 0xffff); /* Configure the DMA allocator */ - if (board_dma_alloc_init() < 0) { syslog(LOG_ERR, "[boot] DMA alloc FAILED\n"); } @@ -234,7 +328,33 @@ __EXPORT int board_app_initialize(uintptr_t arg) led_on(LED_RED); } - if (nx_mount("/dev/mtdblock0", "/fs/microsd", "littlefs", 0, "autoformat") != 0) { + /* Mount LittleFS as /fs/microsd: + * FRAM boards: EEPROM->mtdblock0-4, FRAM->mtdblock5 (LittleFS). + * EEPROM-only: EEPROM->mtdblock0-2, FTL on free EEPROM region mtdblock3 (LittleFS). */ + const char *lfs_dev; + + if (fram_available) { + lfs_dev = "/dev/mtdblock5"; + + } else { + if (mtd_count > 0 && instances[0]->mtd_dev != NULL) { + FAR struct mtd_dev_s *eeprom_fs = mtd_partition(instances[0]->mtd_dev, 3, eeprom_npages - 3); + + if (!eeprom_fs || ftl_initialize(3, eeprom_fs) != 0) { + syslog(LOG_ERR, "[boot] EEPROM: FTL init failed\n"); + led_on(LED_RED); + } + + } else { + syslog(LOG_ERR, "[boot] EEPROM not found\n"); + led_on(LED_RED); + } + + lfs_dev = "/dev/mtdblock3"; + } + + if (nx_mount(lfs_dev, "/fs/microsd", "littlefs", 0, "autoformat") != 0) { + syslog(LOG_ERR, "[boot] failed to mount /fs/microsd\n"); led_on(LED_RED); } diff --git a/boards/auterion/fmu-v6s/src/mtd.cpp b/boards/auterion/fmu-v6s/src/mtd.cpp index 97a2f3f88d..1f45a7a8f5 100644 --- a/boards/auterion/fmu-v6s/src/mtd.cpp +++ b/boards/auterion/fmu-v6s/src/mtd.cpp @@ -37,16 +37,15 @@ #include #include -static const px4_mft_device_t spi4 = { // FM25V02A on FMUM native: 128K X 8, emulated as (1024 Blocks of 32) +static const px4_mft_device_t spi4 = { // MB85RS1MT on FMUM native: 1Mbit, emulated as (1024 Blocks of 32) .bus_type = px4_mft_device_t::SPI, .devid = SPIDEV_FLASH(0) }; -static const px4_mft_device_t i2c4 = { // 24LC64T 8K 32 X 256 +static const px4_mft_device_t i2c4 = { // 24LC64T 8K 32 X 256 or 16K for EEPROM only boards .bus_type = px4_mft_device_t::I2C, .devid = PX4_MK_I2C_DEVID(4, 0x50) }; - static const px4_mtd_entry_t fmum_fram = { .device = &spi4, .npart = 1, @@ -59,7 +58,36 @@ static const px4_mtd_entry_t fmum_fram = { }, }; +/* EEPROM layout for EEPROM-only boards (128Kbit, 512 pages x 32B = 16KB). */ +static constexpr uint32_t kEepromParts = 3; + static const px4_mtd_entry_t fmum_eeprom = { + .device = &i2c4, + .npart = kEepromParts, + .partd = { + { + .type = MTD_MFT_VER, + .path = "/fs/mtd_mft_ver", + .nblocks = 1 + }, + { + .type = MTD_MFT_REV, + .path = "/fs/mtd_mft_rev", + .nblocks = 1 + }, + { + .type = MTD_NET, + .path = "/fs/mtd_net", + .nblocks = 1 + } + }, +}; +static_assert(kEepromParts == 3, + "EEPROM partition count changed: update init.c accordingly"); + +/* EEPROM layout for FRAM boards (64Kbit, 256 pages x 32B = 8KB). + * Matches existing layout for backwards compatibility reasons. */ +static const px4_mtd_entry_t fmum_eeprom_fram = { .device = &i2c4, .npart = 5, .partd = { @@ -81,22 +109,24 @@ static const px4_mtd_entry_t fmum_eeprom = { { .type = MTD_ID, .path = "/fs/mtd_id", - .nblocks = 8 // 256 = 32 * 8 + .nblocks = 8 }, { .type = MTD_NET, .path = "/fs/mtd_net", - .nblocks = 8 // 256 = 32 * 8 + .nblocks = 8 } }, }; static const px4_mtd_manifest_t board_mtd_config = { - .nconfigs = 2, - .entries = { - &fmum_fram, - &fmum_eeprom - } + .nconfigs = 1, + .entries = { &fmum_eeprom } +}; + +static const px4_mtd_manifest_t board_mtd_config_fram = { + .nconfigs = 2, + .entries = { &fmum_eeprom_fram, &fmum_fram } }; static const px4_mft_entry_s mtd_mft = { @@ -104,20 +134,36 @@ static const px4_mft_entry_s mtd_mft = { .pmft = (void *) &board_mtd_config, }; +static const px4_mft_entry_s mtd_mft_fram = { + .type = MTD, + .pmft = (void *) &board_mtd_config_fram, +}; + static const px4_mft_entry_s mft_mft = { .type = MFT, .pmft = (void *) system_query_manifest, }; +/* Manifest for EEPROM only boards */ static const px4_mft_s mft = { .nmft = 2, - .mfts = { - &mtd_mft, - &mft_mft, - } + .mfts = { &mtd_mft, &mft_mft } }; +/* Manifest for EEPROM + FRAM boards */ +static const px4_mft_s mft_fram = { + .nmft = 2, + .mfts = { &mtd_mft_fram, &mft_mft } +}; + +static const px4_mft_s *g_manifest = &mft; + const px4_mft_s *board_get_manifest(void) { - return &mft; + return g_manifest; +} + +void board_configure_fram(void) +{ + g_manifest = &mft_fram; }