From a954f62179bb385a822b9d7ef26f8c42cd3eeb38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20NEDJAR?= Date: Mon, 16 Mar 2026 16:47:12 +0100 Subject: [PATCH 1/2] steami: Add config zone commands (WRITE/READ/CLEAR_CONFIG). --- source/board/steami/steami32.c | 97 ++++++++++++++++++++++++++++++ source/board/steami/steami_flash.c | 37 ++++++++++++ source/board/steami/steami_flash.h | 37 ++++++++++-- source/board/steami/steami_i2c.c | 12 ++++ source/board/steami/steami_i2c.h | 6 +- 5 files changed, 184 insertions(+), 5 deletions(-) diff --git a/source/board/steami/steami32.c b/source/board/steami/steami32.c index 0b1326836..3d8224108 100644 --- a/source/board/steami/steami32.c +++ b/source/board/steami/steami32.c @@ -112,6 +112,10 @@ typedef enum { TASK_READ_SECTOR, + TASK_WRITE_CONFIG, + TASK_READ_CONFIG, + TASK_CLEAR_CONFIG, + TASK_WAIT_FLASH_BUSY, } steami_task; @@ -205,6 +209,40 @@ static void on_I2C_receive_command(steami_i2c_command cmd, uint8_t* rx, uint16_t break; } + case WRITE_CONFIG:{ + if(is_busy()){ + steami_uart_write_string("ERROR I2C busy.\n"); + break; + } + if(rx_len < 3){ + error_status_bad_parameter(&status_error); + break; + } + current_task = TASK_WRITE_CONFIG; + memcpy(task_rx, rx, rx_len); + task_rx_len = rx_len; + break; + } + + case READ_CONFIG:{ + if(is_busy()){ + steami_uart_write_string("ERROR I2C busy.\n"); + break; + } + current_task = TASK_READ_CONFIG; + memcpy(task_rx, rx, rx_len); + task_rx_len = rx_len; + break; + } + + case CLEAR_CONFIG: + if(is_busy()){ + steami_uart_write_string("ERROR I2C busy.\n"); + break; + } + current_task = TASK_CLEAR_CONFIG; + break; + case STATUS:{ uint8_t status = 0x00; @@ -394,6 +432,65 @@ void process_task() } + case TASK_WRITE_CONFIG:{ + if( steami_flash_is_busy() ){ + break; + } + // task_rx: [offset_hi, offset_lo, len, data...] + if( task_rx_len >= 3 ){ + uint16_t offset = ((uint16_t)task_rx[0] << 8) | task_rx[1]; + uint16_t len = task_rx[2]; + if( len <= task_rx_len - 3 && steami_flash_write_config(offset, task_rx + 3, len) ){ + steami_uart_write_string("Config written.\n"); + } + else{ + error_status_set_last_command_fail(&status_error); + steami_uart_write_string("ERROR Unable to write config.\n"); + } + } + else{ + error_status_bad_parameter(&status_error); + } + current_task = TASK_NONE; + break; + } + + case TASK_READ_CONFIG:{ + if( steami_flash_is_busy() ){ + break; + } + if( task_rx_len == 2 ){ + uint16_t offset = ((uint16_t)task_rx[0] << 8) | task_rx[1]; + if( steami_flash_read_config(offset, buffer_sector, STEAMI_FLASH_SECTOR) ){ + steami_i2c_set_tx_data(buffer_sector, STEAMI_FLASH_SECTOR); + } + else{ + error_status_set_last_command_fail(&status_error); + steami_uart_write_string("ERROR Unable to read config.\n"); + } + } + else{ + error_status_bad_parameter(&status_error); + } + current_task = TASK_NONE; + break; + } + + case TASK_CLEAR_CONFIG:{ + if( steami_flash_is_busy() ){ + break; + } + if( steami_flash_erase_config() ){ + steami_uart_write_string("Config erased.\n"); + } + else{ + error_status_set_last_command_fail(&status_error); + steami_uart_write_string("ERROR Unable to erase config.\n"); + } + current_task = TASK_NONE; + break; + } + case TASK_WAIT_FLASH_BUSY: if( !steami_flash_is_busy() ){ current_task = TASK_NONE; diff --git a/source/board/steami/steami_flash.c b/source/board/steami/steami_flash.c index e8ae58d2e..f199491d4 100644 --- a/source/board/steami/steami_flash.c +++ b/source/board/steami/steami_flash.c @@ -219,4 +219,41 @@ uint16_t steami_flash_read_file(uint8_t* data, uint16_t data_len, uint32_t offse bool steami_flash_is_busy(){ return w25q64_is_busy(); +} + +bool steami_flash_erase_config(){ + steami_led_turn_on_blue(); + + w25q64_write_enable(); + wait_w25q64_wel(); + wait_w25q64_busy(); + bool result = w25q64_sector_erase(STEAMI_FLASH_CONFIG_ADDR); + + steami_led_turn_off_blue(); + return result; +} + +bool steami_flash_write_config(uint16_t offset, uint8_t* data, uint16_t len){ + if( offset + len > STEAMI_FLASH_CONFIG_SIZE ){ + return false; + } + + steami_led_turn_on_blue(); + + w25q64_write_enable(); + wait_w25q64_wel(); + wait_w25q64_busy(); + bool result = w25q64_page_program(data, STEAMI_FLASH_CONFIG_ADDR + offset, len); + + steami_led_turn_off_blue(); + return result; +} + +bool steami_flash_read_config(uint16_t offset, uint8_t* data, uint16_t len){ + if( offset + len > STEAMI_FLASH_CONFIG_SIZE ){ + return false; + } + + wait_w25q64_busy(); + return w25q64_read_data(data, STEAMI_FLASH_CONFIG_ADDR + offset, len); } \ No newline at end of file diff --git a/source/board/steami/steami_flash.h b/source/board/steami/steami_flash.h index a9d0a6771..e17507fa7 100644 --- a/source/board/steami/steami_flash.h +++ b/source/board/steami/steami_flash.h @@ -3,10 +3,12 @@ #include #include -#define STEAMI_FLASH_FILE_ADDR (uint32_t)0x00000000 -#define STEAMI_FLASH_NAME_ADDR (uint32_t)0x007FF000 +#define STEAMI_FLASH_CONFIG_ADDR (uint32_t)0x00000000 +#define STEAMI_FLASH_CONFIG_SIZE 4096 +#define STEAMI_FLASH_FILE_ADDR (uint32_t)0x00001000 /* after config zone */ +#define STEAMI_FLASH_NAME_ADDR (uint32_t)0x007FF000 -#define STEAMI_FLASH_FILE_SIZE 8384512 +#define STEAMI_FLASH_FILE_SIZE 8380416 /* 0x7FF000 - 0x001000 */ #define STEAMI_FLASH_SECTOR 256 #define STEAMI_FLASH_4K 4096 @@ -108,4 +110,31 @@ uint16_t steami_flash_read_file(uint8_t* data, uint16_t data_len, uint32_t offse * * @return TRUE if the flash is buzy flag is high, FALSE otherwise */ -bool steami_flash_is_busy(); \ No newline at end of file +bool steami_flash_is_busy(); + +/** + * @brief Erase the 4K config zone at STEAMI_FLASH_CONFIG_ADDR. + * + * @return TRUE if successful, FALSE otherwise + */ +bool steami_flash_erase_config(); + +/** + * @brief Write data to the config zone. + * + * @param offset byte offset within the config zone (0-4095) + * @param data data array + * @param len number of bytes to write (max 256 per call, must stay within one page) + * @return TRUE if successful, FALSE otherwise + */ +bool steami_flash_write_config(uint16_t offset, uint8_t* data, uint16_t len); + +/** + * @brief Read data from the config zone. + * + * @param offset byte offset within the config zone (0-4095) + * @param data buffer for read data + * @param len number of bytes to read + * @return TRUE if successful, FALSE otherwise + */ +bool steami_flash_read_config(uint16_t offset, uint8_t* data, uint16_t len); \ No newline at end of file diff --git a/source/board/steami/steami_i2c.c b/source/board/steami/steami_i2c.c index 44a53c1f1..e20c15fb2 100644 --- a/source/board/steami/steami_i2c.c +++ b/source/board/steami/steami_i2c.c @@ -35,6 +35,9 @@ static bool is_command_valid(uint8_t cmd){ case GET_FILENAME: case WRITE_DATA: case READ_SECTOR: + case WRITE_CONFIG: + case READ_CONFIG: + case CLEAR_CONFIG: case STATUS: case ERROR_STATUS: return true; @@ -65,6 +68,15 @@ static uint16_t get_argument_byte_number(uint8_t cmd){ case READ_SECTOR: return 2; + case WRITE_CONFIG: + return 31; + + case READ_CONFIG: + return 2; + + case CLEAR_CONFIG: + return 0; + case STATUS: return 0; diff --git a/source/board/steami/steami_i2c.h b/source/board/steami/steami_i2c.h index 5fdda83cd..6249006cd 100644 --- a/source/board/steami/steami_i2c.h +++ b/source/board/steami/steami_i2c.h @@ -26,7 +26,11 @@ typedef enum { WRITE_DATA = 0x11, READ_SECTOR = 0x20, - + + WRITE_CONFIG = 0x30, + READ_CONFIG = 0x31, + CLEAR_CONFIG = 0x32, + STATUS = 0x80, ERROR_STATUS = 0x81, } steami_i2c_command; From 5770096ae81d9dc06bf57e89037f5ff8e5681598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20NEDJAR?= Date: Mon, 16 Mar 2026 19:40:07 +0100 Subject: [PATCH 2/2] fix: address PR review comments - Add page-boundary and length validation in steami_flash_write_config - Fix steami_flash_get_size returning absolute address instead of relative size - Separate bad-parameters error from flash-write failure in TASK_WRITE_CONFIG - Update doc to reflect actual 28-byte max payload via I2C protocol - Document fixed 31-byte frame layout for WRITE_CONFIG command --- source/board/steami/steami32.c | 6 +++++- source/board/steami/steami_flash.c | 10 +++++++++- source/board/steami/steami_flash.h | 8 ++++---- source/board/steami/steami_i2c.c | 2 +- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/source/board/steami/steami32.c b/source/board/steami/steami32.c index 3d8224108..48142efc9 100644 --- a/source/board/steami/steami32.c +++ b/source/board/steami/steami32.c @@ -440,7 +440,11 @@ void process_task() if( task_rx_len >= 3 ){ uint16_t offset = ((uint16_t)task_rx[0] << 8) | task_rx[1]; uint16_t len = task_rx[2]; - if( len <= task_rx_len - 3 && steami_flash_write_config(offset, task_rx + 3, len) ){ + if( len > task_rx_len - 3 ){ + error_status_bad_parameter(&status_error); + steami_uart_write_string("ERROR Bad config write parameters.\n"); + } + else if( steami_flash_write_config(offset, task_rx + 3, len) ){ steami_uart_write_string("Config written.\n"); } else{ diff --git a/source/board/steami/steami_flash.c b/source/board/steami/steami_flash.c index f199491d4..41caeb01d 100644 --- a/source/board/steami/steami_flash.c +++ b/source/board/steami/steami_flash.c @@ -138,7 +138,7 @@ uint32_t steami_flash_get_size(){ for(uint16_t i = 0; i < STEAMI_FLASH_MAX_DATA_SIZE; ++i){ if( data[i] == 0xFF ){ - return STEAMI_FLASH_FILE_ADDR + offset + i; + return offset + i; } } @@ -228,15 +228,22 @@ bool steami_flash_erase_config(){ wait_w25q64_wel(); wait_w25q64_busy(); bool result = w25q64_sector_erase(STEAMI_FLASH_CONFIG_ADDR); + wait_w25q64_busy(); steami_led_turn_off_blue(); return result; } bool steami_flash_write_config(uint16_t offset, uint8_t* data, uint16_t len){ + if( len == 0 || len > 256 ){ + return false; + } if( offset + len > STEAMI_FLASH_CONFIG_SIZE ){ return false; } + if( (offset % 256) + len > 256 ){ + return false; + } steami_led_turn_on_blue(); @@ -244,6 +251,7 @@ bool steami_flash_write_config(uint16_t offset, uint8_t* data, uint16_t len){ wait_w25q64_wel(); wait_w25q64_busy(); bool result = w25q64_page_program(data, STEAMI_FLASH_CONFIG_ADDR + offset, len); + wait_w25q64_busy(); steami_led_turn_off_blue(); return result; diff --git a/source/board/steami/steami_flash.h b/source/board/steami/steami_flash.h index e17507fa7..bd1e181fa 100644 --- a/source/board/steami/steami_flash.h +++ b/source/board/steami/steami_flash.h @@ -3,12 +3,12 @@ #include #include -#define STEAMI_FLASH_CONFIG_ADDR (uint32_t)0x00000000 +#define STEAMI_FLASH_FILE_ADDR (uint32_t)0x00000000 +#define STEAMI_FLASH_CONFIG_ADDR (uint32_t)0x007FE000 /* last 4K before filename */ #define STEAMI_FLASH_CONFIG_SIZE 4096 -#define STEAMI_FLASH_FILE_ADDR (uint32_t)0x00001000 /* after config zone */ #define STEAMI_FLASH_NAME_ADDR (uint32_t)0x007FF000 -#define STEAMI_FLASH_FILE_SIZE 8380416 /* 0x7FF000 - 0x001000 */ +#define STEAMI_FLASH_FILE_SIZE 8380416 /* 0x7FE000 - 0x000000 (excludes config) */ #define STEAMI_FLASH_SECTOR 256 #define STEAMI_FLASH_4K 4096 @@ -124,7 +124,7 @@ bool steami_flash_erase_config(); * * @param offset byte offset within the config zone (0-4095) * @param data data array - * @param len number of bytes to write (max 256 per call, must stay within one page) + * @param len number of bytes to write (max 28 per call via I2C, must stay within one 256-byte page) * @return TRUE if successful, FALSE otherwise */ bool steami_flash_write_config(uint16_t offset, uint8_t* data, uint16_t len); diff --git a/source/board/steami/steami_i2c.c b/source/board/steami/steami_i2c.c index e20c15fb2..716e95d38 100644 --- a/source/board/steami/steami_i2c.c +++ b/source/board/steami/steami_i2c.c @@ -69,7 +69,7 @@ static uint16_t get_argument_byte_number(uint8_t cmd){ return 2; case WRITE_CONFIG: - return 31; + return 31; /* fixed frame: [offset_hi, offset_lo, len, data(28 bytes max)] */ case READ_CONFIG: return 2;