Skip to content

Commit

Permalink
write image to flash
Browse files Browse the repository at this point in the history
  • Loading branch information
robert committed Nov 27, 2023
1 parent 2a25e44 commit 2263f3f
Show file tree
Hide file tree
Showing 10 changed files with 627 additions and 5 deletions.
32 changes: 30 additions & 2 deletions examples/nxp/rt1060-evk-make-baremetal-builtin/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ void mg_random(void *buf, size_t len) { // Use on-board RNG
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
}
}

static void timer_fn(void *arg) {
gpio_toggle(LED); // Blink LED
struct mg_tcpip_if *ifp = arg; // And show
Expand All @@ -32,15 +33,42 @@ static void timer_fn(void *arg) {
}

int main(void) {
gpio_output(LED); // Setup blue LED
gpio_output(LED); // Setup green LED
uart_init(UART_DEBUG, 115200); // Initialise debug printf
ethernet_init(); // Initialise ethernet pins

#ifdef MQTT_DASHBOARD
// User can customise the MQTT url, device ID or the root topic below
#define DEVICE_ID "RT1060"
g_url = MQTT_SERVER_URL;
g_device_id = DEVICE_ID;
g_root_topic = DEFAULT_ROOT_TOPIC;
#endif

MG_INFO(("Starting, CPU freq %g MHz", (double) SystemCoreClock / 1000000));

struct mg_mgr mgr; // Initialise
mg_mgr_init(&mgr); // Mongoose event manager
mg_log_set(MG_LL_DEBUG); // Set log level

//mg_ota_boot(); // Call bootloader: continue to load, or boot another FW

#if MG_OTA == MG_OTA_FLASH
// Demonstrate the use of mg_flash_{load/save} functions for keeping device
// configuration data on flash. Increment boot count on every boot.
struct deviceconfig {
uint32_t boot_count;
char some_other_data[40];
};
uint32_t key = 0x12345678; // A unique key, one per data type
struct deviceconfig dc = {}; // Initialise to some default values
mg_flash_load(NULL, key, &dc, sizeof(dc)); // Load from flash
dc.boot_count++; // Increment boot count
mg_flash_save(NULL, key, &dc, sizeof(dc)); // And save back
MG_INFO(("Boot count: %u", dc.boot_count));
#endif

// Initialise Mongoose network stack
// Initialise Mongoose network stack
struct mg_tcpip_driver_imxrt_data driver_data = {.mdc_cr = 24, .phy_addr = 2};
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(),
Expand All @@ -65,6 +93,6 @@ int main(void) {
for (;;) {
mg_mgr_poll(&mgr, 0);
}

return 0;
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

// See https://mongoose.ws/documentation/#build-options
#define MG_ARCH MG_ARCH_NEWLIB
#define MG_OTA MG_OTA_EXTERNAL_FLASH
#define MG_DEVICE MG_DEVICE_RT1060_QUAD_NOR

#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_DRIVER_IMXRT 1
Expand Down
2 changes: 1 addition & 1 deletion examples/nxp/rt1060-evk-make-baremetal-builtin/net.c
2 changes: 1 addition & 1 deletion examples/nxp/rt1060-evk-make-baremetal-builtin/net.h
298 changes: 297 additions & 1 deletion mongoose.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,201 @@ bool mg_flash_load(void *sector, uint32_t key, void *buf, size_t len) {
}
#endif

#ifdef MG_ENABLE_LINES
#line 1 "src/device_rt1060_quad_nor.c"
#endif



#if MG_DEVICE == MG_DEVICE_RT1060_QUAD_NOR

typedef struct {
char memCfg[448];
uint32_t pageSize;
uint32_t sectorSize;
uint32_t ipCmdSerialClkFreq;
char reserved[55];
} flexspi_nor_config_t;

typedef struct _serial_nor_config_option
{
union
{
struct
{
uint32_t max_freq : 4; //!< Maximum supported Frequency
uint32_t misc_mode : 4; //!< miscellaneous mode
uint32_t quad_mode_setting : 4; //!< Quad mode setting
uint32_t cmd_pads : 4; //!< Command pads
uint32_t query_pads : 4; //!< SFDP read pads
uint32_t device_type : 4; //!< Device type
uint32_t option_size : 4; //!< Option size, in terms of uint32_t, size = (option_size + 1) * 4
uint32_t tag : 4; //!< Tag, must be 0x0E
} B;
uint32_t U;
} option0;
union
{
struct
{
uint32_t dummy_cycles : 8; //!< Dummy cycles before read
uint32_t reserved0 : 8; //!< Reserved for future use
uint32_t pinmux_group : 4; //!< The pinmux group selection
uint32_t reserved1 : 8; //!< Reserved for future use
uint32_t flash_connection : 4; //!< Flash connection option: 0 - Single Flash connected to port A
} B;
uint32_t U;
} option1;
} serial_nor_config_option_t;

typedef int status_t;

typedef enum _FlexSPIOperationType
{
kFlexSpiOperation_Command, //!< FlexSPI operation: Only command, both TX and
//! RX buffer are ignored.
kFlexSpiOperation_Config, //!< FlexSPI operation: Configure device mode, the
//! TX FIFO size is fixed in LUT.
kFlexSpiOperation_Write, //!< FlexSPI operation: Write, only TX buffer is
//! effective
kFlexSpiOperation_Read, //!< FlexSPI operation: Read, only Rx Buffer is
kFlexSpiOperation_End = kFlexSpiOperation_Read,
} flexspi_operation_t;

typedef struct _FlexSpiXfer
{
flexspi_operation_t operation; //!< FlexSPI operation
uint32_t baseAddress; //!< FlexSPI operation base address
uint32_t seqId; //!< Sequence Id
uint32_t seqNum; //!< Sequence Number
bool isParallelModeEnable; //!< Is a parallel transfer
uint32_t *txBuffer; //!< Tx buffer
uint32_t txSize; //!< Tx size in bytes
uint32_t *rxBuffer; //!< Rx buffer
uint32_t rxSize; //!< Rx size in bytes
} flexspi_xfer_t;

typedef struct
{
uint32_t version;
status_t (*init)(uint32_t instance, flexspi_nor_config_t *config);
status_t (*program)(uint32_t instance, flexspi_nor_config_t *config, uint32_t
dst_addr, const uint32_t *src);
status_t (*erase_all)(uint32_t instance, flexspi_nor_config_t *config);
status_t (*erase)(uint32_t instance, flexspi_nor_config_t *config, uint32_t start,
uint32_t lengthInBytes);
status_t (*read)(
uint32_t instance, flexspi_nor_config_t *config, uint32_t *dst, uint32_t addr,
uint32_t lengthInBytes);
void (*clear_cache)(uint32_t instance);
status_t (*xfer)(uint32_t instance, flexspi_xfer_t *xfer);
status_t (*update_lut)(uint32_t instance, uint32_t seqIndex, const uint32_t
*lutBase, uint32_t seqNumber);
status_t (*get_config)(uint32_t instance, flexspi_nor_config_t *config,
serial_nor_config_option_t *option);
} flexspi_nor_driver_interface_t;

typedef struct
{
const uint32_t version; //!< Bootloader version number
const char *copyright; //!< Bootloader Copyright
void (*runBootloader)(void *arg); //!< Function to start the bootloader executing
const uint32_t *reserved0; //!< Reserved
const flexspi_nor_driver_interface_t *flexSpiNorDriver; //!< FlexSPI NOR Flash API
const uint32_t *reserved1[2]; //!< Reserved
/*const rtwdog_driver_interface_t *rtwdogDriver;
const wdog_driver_interface_t *wdogDriver;
const uint32_t *reserved2;*/
} bootloader_api_entry_t;

#define bootloader (*(bootloader_api_entry_t**)(0x0020001c))
#define flexspi_nor (*(flexspi_nor_driver_interface_t**) ((char*) bootloader + 4*sizeof(uint32_t)))

static flexspi_nor_config_t s_config;
static serial_nor_config_option_t s_option;
static uint32_t s_instance;

void *mg_flash_start(void) {
return (void *) 0x0;
}
size_t mg_flash_size(void) {
return 256 * 1024; // 256k
}
size_t mg_flash_sector_size(void) {
return 4 * 1024; // 4k
}
size_t mg_flash_write_align(void) {
return 256;
}
int mg_flash_bank(void) {
return 0;
}

static bool flash_page_start(volatile uint32_t *dst) {
char *base = (char *) mg_flash_start(), *end = base + mg_flash_size();
volatile char *p = (char *) dst;
return p >= base && p < end && ((p - base) % mg_flash_sector_size()) == 0;
}

uint32_t mg_flash_init() {
uint32_t status = 0;
s_option.option0.U = 0xc0000008;
status = flexspi_nor->get_config(s_instance, &s_config, &s_option);
if (status != 0) {
MG_DEBUG(("Failed to get flexspi configuration"));
return status;
}

status = flexspi_nor->init(s_instance, &s_config);
return status;
}

bool mg_flash_erase(void *addr) {
bool ok = false;
if (flash_page_start(addr) == false) {
MG_ERROR(("%p is not on a sector boundary", addr));
} else {
uint32_t status = flexspi_nor->erase(s_instance, &s_config, (uint32_t) addr, mg_flash_sector_size());
if (status == 0) ok = true;
}
if (ok) {
MG_DEBUG(("Successfully erased sector starting at %p", addr));
} else {
MG_DEBUG(("Failed to erase sector starting at %p", addr));
}
return ok;
}

bool mg_flash_swap_bank() {
return false;
}

bool mg_flash_write(void *addr, const void *buf, size_t len) {
if ((len % mg_flash_write_align()) != 0) {
MG_ERROR(("%lu is not aligned to %lu", len, mg_flash_write_align()));
return false;
}
uint32_t *dst = (uint32_t *) addr;
uint32_t *src = (uint32_t *) buf;
uint32_t *end = (uint32_t *) ((char *) buf + len);
bool ok = true;
while (ok && src < end) {
if (flash_page_start(dst) && mg_flash_erase(dst) == false) break;
uint32_t status = flexspi_nor->program(s_instance, &s_config, (uint32_t) dst, src);
src = (uint32_t *) ((char *) src + mg_flash_write_align());
dst = (uint32_t *) ((char *) dst + mg_flash_write_align());
if (status != 0) ok = false;
}
MG_DEBUG(("Flash write %lu bytes @ %p: %s.", len, dst,
ok ? "ok" : "fail"));
return ok;
}

void mg_device_reset(void) {
*(volatile unsigned long *) 0xe000ed0c = 0x5fa0004;
}
#endif

#ifdef MG_ENABLE_LINES
#line 1 "src/device_stm32h5.c"
#endif
Expand Down Expand Up @@ -5700,6 +5895,107 @@ MG_IRAM void mg_ota_boot(void) {
mg_device_reset();
}
}

#elif MG_OTA == MG_OTA_EXTERNAL_FLASH

static char *s_addr; // Current address to write to
static size_t s_size; // Firmware size to flash. In-progress indicator
static uint32_t s_crc32; // Firmware checksum

struct mg_otadata {
uint32_t crc32, size, timestamp, status;
};

bool mg_ota_begin(size_t new_firmware_size) {
bool ok = false;
if (s_size) {
MG_ERROR(("OTA already in progress. Call mg_ota_end()"));
} else {
if (new_firmware_size > mg_flash_size()) {
MG_ERROR(("Firmware exceeds flash size"));
return false;
}
s_size = new_firmware_size;
uint32_t flash_init_status = mg_flash_init();
if (flash_init_status) {
MG_ERROR(("Error initialising the flash structure"));
return false;
} else {
ok = true;
}
}
return ok;
}

bool mg_ota_write(const void *buf, size_t len) {
bool ok = false;
if (s_size == 0) {
MG_ERROR(("OTA is not started, call mg_ota_begin()"));
} else {
size_t align = mg_flash_write_align();
size_t len_aligned_down = MG_ROUND_DOWN(len, align);
if (len_aligned_down) ok = mg_flash_write(s_addr, buf, len_aligned_down);
if (len_aligned_down < len) {
size_t left = len - len_aligned_down;
char tmp[align];
memset(tmp, 0xff, sizeof(tmp));
memcpy(tmp, (char *) buf + len_aligned_down, left);
ok = mg_flash_write(s_addr + len_aligned_down, tmp, sizeof(tmp));
}
s_crc32 = mg_crc32(s_crc32, (char *) buf, len); // Update CRC
MG_DEBUG(("%#x %p %lu -> %d", s_addr, buf, len, ok));
s_addr += len;
}
return ok;
}

bool mg_ota_end(void) {
bool ok = true;
size_t size = (size_t) s_addr;
uint32_t crc32 = mg_crc32(0, (char *) 0x60000000, size);
MG_DEBUG(("CRC: %x/%x, size: %lu/%lu, status: %s", s_crc32, crc32, s_size,
size, s_crc32 == crc32 ? "ok" : "fail"));
s_addr = 0;
s_size = 0;
MG_INFO(("Finishing OTA: %s", ok ? "ok" : "fail"));
return ok;
}

static struct mg_otadata mg_otadata(int fw) {
(void) fw;
struct mg_otadata od = {};
return od;
}

int mg_ota_status(int fw) {
struct mg_otadata od = mg_otadata(fw);
return od.status;
}

uint32_t mg_ota_crc32(int fw) {
struct mg_otadata od = mg_otadata(fw);
return od.crc32;
}

uint32_t mg_ota_timestamp(int fw) {
struct mg_otadata od = mg_otadata(fw);
return od.timestamp;
}

size_t mg_ota_size(int fw) {
struct mg_otadata od = mg_otadata(fw);
return od.size;
}

MG_IRAM bool mg_ota_commit(void) {
return false;
}

bool mg_ota_rollback(void) {
MG_DEBUG(("Rolling firmware not supported yet"));
return false;
}

#endif

#ifdef MG_ENABLE_LINES
Expand Down Expand Up @@ -9309,7 +9605,7 @@ void ETH_IRQHandler(void) {
}
}
#ifdef __riscv
ETH->DMASR = ~0; // TODO: do more fine-grained flag cleanup
ETH->DMASR = ~0; // TODO: do more fine-grained flag cleanup
#else
ETH->DMASR = MG_BIT(7); // Clear possible RBUS while processing
#endif
Expand Down
Loading

0 comments on commit 2263f3f

Please sign in to comment.