stm32g0xx_fdcan example project updated with eeprom storage routines#109
stm32g0xx_fdcan example project updated with eeprom storage routines#109TheCitrusMan wants to merge 7 commits into
Conversation
Modified Canopen files: CO_app_STM32.c : > updated include references > CO_storageBlank_init replaced by CO_storageEeprom_init > uint32_t storageInitError moved to global scope CO_driver_target.h : > #undef CO_CONFIG_STORAGE_ENABLE commented out > CO_storage_entry_t added extra parameters CO_eeprom_STM32.c and CO_eeprom_STM32.h added to project. These files contain the main eeprom storage routines and are based on the PIC32 example. CO_storageBlank.c and CO_storageBlank.h removed from project. eeprom.c and eeprom.h files added to project. These files contain the low level eeprom routines. i2c.h in core project: > added a couple of defines
|
@CANopenNode @HamedJafarzadeh is this OK to merge? |
|
A little comment on function CO_eeprom_init() in CO_eeprom_STM32.c : This funcion initializes the EEPROM storage. The chosen EEPROM types contain a fixed serial number. This number is placed in OD_PERSIST_COMM.x1018_identity.serialNumber. What it also does is to check the status of a predefined I/O pin of the microcontroller. When this pin is active high (in this case), (part of) the eeprom storage is erased, invalidating the contents of PERSIST_COMM. I have found that such functionality can be very handy when a project is still under development and the number of parameters in PERSIST_COMM changes. It seems that, when parameters are added to or removed from PERSIST_COMM after parameters were successfully written to eeprom, the old eeprom storage is still considered valid by canopennode. I haven't put any time in figuring this out yet, I opted for a simple "config mode" option instead. In this demo project I have connected this "config mode" to the "joystick down" button. The idea is to press this button during power up of the device. |
There was a problem hiding this comment.
Pull request overview
This PR updates the stm32g0xx_fdcan example integration to use EEPROM-backed CANopen Object Dictionary storage (via CO_storageEeprom) instead of the previous blank storage stub, adding STM32-specific EEPROM access routines.
Changes:
- Switch CANopen app initialization from
CO_storageBlank_*toCO_storageEeprom_*and enable storage configuration. - Add STM32 EEPROM discovery + low-level I2C EEPROM access (
eeprom.c/.h) and a CANopen storage EEPROM adapter (CO_eeprom_STM32.c/.h). - Add example-level I2C helper defines used by the new EEPROM code.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| examples/stm32g0xx_fdcan/Core/Inc/i2c.h | Adds I2C timeout + handle macro used by EEPROM routines |
| CANopenNode_STM32/eeprom.h | Adds EEPROM public API + exported device/layout globals |
| CANopenNode_STM32/eeprom.c | Adds EEPROM device detection (ST/Microchip) and layout setup |
| CANopenNode_STM32/CO_storageBlank.h | Removes blank storage stub (header) |
| CANopenNode_STM32/CO_storageBlank.c | Removes blank storage stub (implementation) |
| CANopenNode_STM32/CO_eeprom_STM32.h | Adds STM32 EEPROM adapter header (currently minimal) |
| CANopenNode_STM32/CO_eeprom_STM32.c | Adds CO_storageEeprom ↔ STM32 EEPROM adapter implementation |
| CANopenNode_STM32/CO_driver_target.h | Enables storage config and extends CO_storage_entry_t with EEPROM fields |
| CANopenNode_STM32/CO_app_STM32.c | Switches to CO_storageEeprom_init and adjusts storage init handling |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| while (len > 0) | ||
| { | ||
| size_t len_x = len; | ||
| if (len_x > page_size) | ||
| len_x = page_size; | ||
|
|
||
| if (HAL_I2C_Mem_Write(HI2C, device_i2c_address << 1, eepromAddr, 2, (uint8_t *) data + idx, len_x, | ||
| I2C_TIMEOUT_MS) != HAL_OK) | ||
| { | ||
| // write command error | ||
| return false; | ||
| } | ||
|
|
||
| eepromAddr += page_size; | ||
| idx += page_size; | ||
|
|
||
| if (len > page_size) | ||
| len -= page_size; | ||
| else | ||
| len = 0; | ||
|
|
||
| /* wait for completion of the write operation */ | ||
| while (HAL_I2C_IsDeviceReady(HI2C, device_i2c_address << 1, 3, I2C_TIMEOUT_MS) != HAL_OK); | ||
| } |
| /* update crc from data part */ | ||
| HAL_I2C_Mem_Read(HI2C, device_i2c_address << 1, eepromAddr, 2, buf, subLen, I2C_TIMEOUT_MS); | ||
| crc = crc16_ccitt(buf, subLen, crc); | ||
| eepromAddr += BUF_SIZE; | ||
| len -= subLen; | ||
| } |
| #include "storage/CO_storage.h" | ||
| #include "storage/CO_eeprom.h" | ||
| #include "301/crc16-ccitt.h" | ||
| #include "CO_app_STM32.h" | ||
| #include "OD.h" | ||
|
|
||
| #include "i2c.h" | ||
| #include "eeprom.h" | ||
| #include "CO_eeprom_STM32.h" |
| bool_t CO_eeprom_init(void *storageModule) | ||
| { | ||
| // initialize canopen eeprom storage | ||
| if (!Eeprom_Init_CO()) | ||
| { | ||
| return false; | ||
| } |
| bool eeprom_initialized = false; | ||
|
|
||
| uint16_t device_size = 0; | ||
| size_t page_size = 0; | ||
| uint16_t device_i2c_address = EEP_MEM_I2C_ADDR; | ||
| uint32_t device_serial_number = 0; | ||
|
|
||
| uint16_t data_storage_start = 0; | ||
| uint16_t data_storage_size = 0; | ||
|
|
||
| size_t device_start_co_auto = 0; | ||
| size_t device_start_co_prot = 0; | ||
| size_t device_size_co = 0; |
| /* USER CODE BEGIN Includes */ | ||
| #include "main.h" | ||
|
|
||
| bool Eeprom_Init(); | ||
| bool Eeprom_Init_CO(); | ||
|
|
||
| extern uint16_t device_size; | ||
| extern size_t page_size; | ||
| extern uint16_t device_i2c_address; | ||
| extern uint32_t device_serial_number; | ||
|
|
||
| extern uint16_t data_storage_start; | ||
| extern uint16_t data_storage_size; | ||
|
|
||
| extern size_t device_start_co_auto; | ||
| extern size_t device_start_co_prot; | ||
| extern size_t device_size_co; | ||
|
|
| if (err != CO_ERROR_NO && err != CO_ERROR_DATA_CORRUPT) | ||
| { | ||
| log_printf("Error: Storage %ld\n", storageInitError); | ||
| return 2; |
|
After a quick look it seems OK to me. I can't test the code. I ran copilot AI review and it showed some suggestions. @TheCitrusMan, please check, if they make sense. Then I suggest to merge. |
the Github Copilot code review : CO_eeprom_STM32.c : > #include <string.h> added > HAL_I2C_IsDeviceReady() timeout eeprom.c : > replaced size_t by uint32_t / uint16_t specifiers > removed support for m24m01e-u and m24m02e-u eeprom types > as they cannot be fully adressed by 16-bit adresses eeprom.h : > adjusted type specifiers for external variables > #include <stdbool.h> added main.c : > #include "eeprom.h" added > Added missing Eeprom_Init()
Made some changes. Eeprom initialisation in main() was still missing. Removed the support for the largest eeprom types as they cannot be simply addressed with 2-byte addresses and I don't plan adding code for that as 32Kbytes or 64KBytes eeproms are already plenty large. |
Modified Canopen files:
CO_app_STM32.c :
CO_driver_target.h :
CO_eeprom_STM32.c and CO_eeprom_STM32.h added to project. These files contain the main eeprom storage routines and are based on the PIC32 example.
CO_storageBlank.c and CO_storageBlank.h removed from project.
eeprom.c and eeprom.h files added to project. These files contain the low level eeprom routines.
i2c.h in core project: