diff --git a/CANopenNode_STM32/CO_app_STM32.c b/CANopenNode_STM32/CO_app_STM32.c index ad93aa8..8096641 100644 --- a/CANopenNode_STM32/CO_app_STM32.c +++ b/CANopenNode_STM32/CO_app_STM32.c @@ -30,7 +30,7 @@ #include #include -#include "CO_storageBlank.h" +#include "storage/CO_storageEeprom.h" #include "OD.h" CANopenNodeSTM32* @@ -57,6 +57,7 @@ CO_t* CO = NULL; /* CANopen object */ // Global variables uint32_t time_old, time_current; CO_ReturnError_t err; +uint32_t storageInitError = 0; /* This function will basically setup the CANopen node */ int @@ -73,7 +74,6 @@ canopen_app_init(CANopenNodeSTM32* _canopenNodeSTM32) { .attr = CO_storage_cmd | CO_storage_restore, .addrNV = NULL}}; uint8_t storageEntriesCount = sizeof(storageEntries) / sizeof(storageEntries[0]); - uint32_t storageInitError = 0; #endif /* Allocate memory */ @@ -99,13 +99,15 @@ canopen_app_init(CANopenNodeSTM32* _canopenNodeSTM32) { canopenNodeSTM32->canOpenStack = CO; #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - err = CO_storageBlank_init(&storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters, - OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, storageEntriesCount, - &storageInitError); - - if (err != CO_ERROR_NO && err != CO_ERROR_DATA_CORRUPT) { - log_printf("Error: Storage %d\n", storageInitError); - return 2; + err = CO_storageEeprom_init(&storage, CO->CANmodule, NULL, + OD_ENTRY_H1010_storeParameters, + OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, + storageEntriesCount, &storageInitError); + + if (err != CO_ERROR_NO && err != CO_ERROR_DATA_CORRUPT) + { + log_printf("Error: Storage %" PRIu32 "\n", storageInitError); + return 2; } #endif diff --git a/CANopenNode_STM32/CO_driver_STM32.c b/CANopenNode_STM32/CO_driver_STM32.c index a39e3f6..3377f26 100644 --- a/CANopenNode_STM32/CO_driver_STM32.c +++ b/CANopenNode_STM32/CO_driver_STM32.c @@ -411,7 +411,7 @@ CO_CANclearPendingSyncPDOs(CO_CANmodule_t* CANmodule) { /******************************************************************************/ /* Get error counters from the module. If necessary, function may use * different way to determine errors. */ -static uint16_t rxErrors = 0, txErrors = 0, overflow = 0; +// static uint16_t rxErrors = 0, txErrors = 0, overflow = 0; void CO_CANmodule_process(CO_CANmodule_t* CANmodule) { diff --git a/CANopenNode_STM32/CO_driver_target.h b/CANopenNode_STM32/CO_driver_target.h index 90855ab..f3e8091 100644 --- a/CANopenNode_STM32/CO_driver_target.h +++ b/CANopenNode_STM32/CO_driver_target.h @@ -45,7 +45,8 @@ #error This STM32 Do not support CAN or FDCAN #endif -#undef CO_CONFIG_STORAGE_ENABLE // We don't need Storage option, implement based on your use case and remove this line from here +/* Enable CRC-16 calculation. Required by CO_storageEeprom / CO_eeprom_STM32. */ +#define CO_CONFIG_CRC16 (CO_CONFIG_CRC16_ENABLE) #ifdef CO_DRIVER_CUSTOM #include "CO_driver_custom.h" @@ -134,6 +135,11 @@ typedef struct { uint8_t attr; /* Additional variables (target specific) */ void* addrNV; + void * storageModule; + uint16_t crc; + size_t eepromAddrSignature; + size_t eepromAddr; + size_t offset; } CO_storage_entry_t; /* (un)lock critical section in CO_CANsend() */ diff --git a/CANopenNode_STM32/CO_eeprom_STM32.c b/CANopenNode_STM32/CO_eeprom_STM32.c new file mode 100644 index 0000000..7ea371a --- /dev/null +++ b/CANopenNode_STM32/CO_eeprom_STM32.c @@ -0,0 +1,218 @@ +/* + * Eeprom interface for use with CO_storageEeprom, STM32 specific + * + * @file CO_eeprom_STM32.c + * @author Marc Vandenhende + * @copyright 2025 Marc Vandenhende + * + * This file is part of CANopenNode, an opensource CANopen Stack. + * Project home page is . + * For more information on CANopen see . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "storage/CO_storage.h" +#include "storage/CO_eeprom.h" +#include "301/crc16-ccitt.h" +#include "CO_app_STM32.h" +#include "OD.h" + +#include "eeprom.h" +#include "CO_eeprom_STM32.h" + +#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) != 0 + +/* + * Eeprom is configured for auto storage variables. Second half of + * memory locations is used for storage on command. Below are two + * internal variables, used for indicating next free address in eeprom, one for + * autonomous storage and one for protected storage + */ +static size_t eepromAddrNextAuto = 0; +static size_t eepromAddrNextProt = 0; + +/******************************************************************************/ +bool_t CO_eeprom_init(void *storageModule) +{ + // initialize canopen eeprom storage + if (!Eeprom_Init()) + { + return false; + } + + eepromAddrNextAuto = device_start_co_auto; + eepromAddrNextProt = device_start_co_prot; + OD_PERSIST_COMM.x1018_identity.serialNumber = device_serial_number; + + /* If eeprom chip is OK, this will return "true" */ + return (HAL_I2C_IsDeviceReady(HI2C_EEPROM, device_i2c_address << 1, 3, I2C_TIMEOUT_MS) == HAL_OK); +} + +/******************************************************************************/ +size_t CO_eeprom_getAddr(void *storageModule, bool_t isAuto, size_t len, bool_t *overflow) +{ + size_t addr; + + if (isAuto) + { + /* auto storage is processed byte by byte, no alignment necessary */ + addr = eepromAddrNextAuto; + eepromAddrNextAuto += len; + if (eepromAddrNextAuto >= device_start_co_auto + (device_size_co / 2)) + { + *overflow = true; + } + } + else + { + /* addresses for storage on command must be page aligned */ + addr = eepromAddrNextProt; + size_t lenAligned = len & (~(page_size - 1)); + if (lenAligned < len) + { + lenAligned += page_size; + } + eepromAddrNextProt += lenAligned; + if (eepromAddrNextProt >= device_start_co_prot + (device_size_co / 2)) + { + *overflow = true; + } + } + + return addr; +} + +/******************************************************************************/ +void CO_eeprom_readBlock(void *storageModule, uint8_t *data, size_t eepromAddr, size_t len) +{ + HAL_I2C_Mem_Read(HI2C_EEPROM, device_i2c_address << 1, eepromAddr, 2, (uint8_t *) data, len, I2C_TIMEOUT_MS); +} + +/******************************************************************************/ +bool_t CO_eeprom_writeBlock(void *storageModule, uint8_t *data, size_t eepromAddr, size_t len) +{ + uint32_t idx = 0; + uint32_t eep_write_timer = 0; + + if (HAL_I2C_IsDeviceReady(HI2C_EEPROM, device_i2c_address << 1, 3, I2C_TIMEOUT_MS) != HAL_OK) + { + // device not ready + return false; + } + + while (len > 0) + { + size_t len_x = len; + if (len_x > page_size) + len_x = page_size; + + if (HAL_I2C_Mem_Write(HI2C_EEPROM, 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 */ + eep_write_timer = HAL_GetTick(); + while (HAL_I2C_IsDeviceReady(HI2C_EEPROM, device_i2c_address << 1, 3, I2C_TIMEOUT_MS) != HAL_OK) + { + // device not ready yet + if (HAL_GetTick() - eep_write_timer >= EEPROM_WRITE_TIME + 1) + // + 1 to compensate for HAL_GetTick() millisecond jitter + { + // time out + return false; + } + } + } + return true; +} + +/******************************************************************************/ +uint16_t CO_eeprom_getCrcBlock(void *storageModule, size_t eepromAddr, size_t len) +{ +#define BUF_SIZE 250 + + uint16_t crc = 0; + uint8_t buf[BUF_SIZE]; + uint8_t subLen; + + while (len > 0) + { + if (len <= BUF_SIZE) + subLen = len; + else + subLen = BUF_SIZE; + + /* update crc from data part */ + HAL_I2C_Mem_Read(HI2C_EEPROM, device_i2c_address << 1, eepromAddr, 2, buf, subLen, I2C_TIMEOUT_MS); + crc = crc16_ccitt(buf, subLen, crc); + eepromAddr += subLen; + len -= subLen; + } + + /* Return invalid CRC when CAN_CFG jumper is placed (input pulled LOW). This optional feature is only + * active on targets that define CAN_CFG_GPIO_Port/CAN_CFG_Pin (e.g. in main.h). */ +#if defined(CAN_CFG_GPIO_Port) && defined(CAN_CFG_Pin) + if (!HAL_GPIO_ReadPin(CAN_CFG_GPIO_Port, CAN_CFG_Pin)) + { + crc = ~crc; + } +#endif + return crc; +} + +/******************************************************************************/ +bool_t CO_eeprom_updateByte(void * storageModule, uint8_t data, + size_t eepromAddr) +{ + uint8_t buf; + + if (HAL_I2C_IsDeviceReady(HI2C_EEPROM, device_i2c_address << 1, 3, I2C_TIMEOUT_MS) + != HAL_OK) + { + return false; + } + + /* read data byte from eeprom */ + if (HAL_I2C_Mem_Read(HI2C_EEPROM, device_i2c_address << 1, eepromAddr, 2, &buf, 1, I2C_TIMEOUT_MS) != HAL_OK) + { + return false; + } + + /* If data in EEPROM differs, then write it to EEPROM. + * Don't wait for write to complete */ + if (buf != data) + { + if (HAL_I2C_Mem_Write(HI2C_EEPROM, device_i2c_address << 1, eepromAddr, 2, &data, 1, I2C_TIMEOUT_MS) != HAL_OK) + { + return false; + } + } + + return true; +} + +#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/CANopenNode_STM32/CO_eeprom_STM32.h b/CANopenNode_STM32/CO_eeprom_STM32.h new file mode 100644 index 0000000..719c792 --- /dev/null +++ b/CANopenNode_STM32/CO_eeprom_STM32.h @@ -0,0 +1,11 @@ +/* + * CO_eeprom_STM32.h + * + * Created on: 23 Nov 2025 + * Author: Marc Vandenhende + */ + +#ifndef CO_EEPROM_STM32_H_ +#define CO_EEPROM_STM32_H_ + +#endif /* CO_EEPROM_STM32_H_ */ diff --git a/CANopenNode_STM32/CO_storageBlank.c b/CANopenNode_STM32/CO_storageBlank.c deleted file mode 100644 index dc608e2..0000000 --- a/CANopenNode_STM32/CO_storageBlank.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * CANopen Object Dictionary storage object (blank example). - * - * @file CO_storageBlank.c - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "CO_storageBlank.h" - -#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE - -/* - * Function for writing data on "Store parameters" command - OD object 1010 - * - * For more information see file CO_storage.h, CO_storage_entry_t. - */ -static ODR_t -storeBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { - - /* Open a file and write data to it */ - /* file = open(entry->pathToFileOrPointerToMemory); */ - CO_LOCK_OD(CANmodule); - /* write(entry->addr, entry->len, file); */ - CO_UNLOCK_OD(CANmodule); - - return ODR_OK; -} - -/* - * Function for restoring data on "Restore default parameters" command - OD 1011 - * - * For more information see file CO_storage.h, CO_storage_entry_t. - */ -static ODR_t -restoreBlank(CO_storage_entry_t* entry, CO_CANmodule_t* CANmodule) { - - /* disable (delete) the file, so default values will stay after startup */ - - return ODR_OK; -} - -CO_ReturnError_t -CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, OD_entry_t* OD_1010_StoreParameters, - OD_entry_t* OD_1011_RestoreDefaultParam, CO_storage_entry_t* entries, uint8_t entriesCount, - uint32_t* storageInitError) { - CO_ReturnError_t ret; - - /* verify arguments */ - if (storage == NULL || entries == NULL || entriesCount == 0 || storageInitError == NULL) { - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* initialize storage and OD extensions */ - ret = CO_storage_init(storage, CANmodule, OD_1010_StoreParameters, OD_1011_RestoreDefaultParam, storeBlank, - restoreBlank, entries, entriesCount); - if (ret != CO_ERROR_NO) { - return ret; - } - - /* initialize entries */ - *storageInitError = 0; - for (uint8_t i = 0; i < entriesCount; i++) { - CO_storage_entry_t* entry = &entries[i]; - - /* verify arguments */ - if (entry->addr == NULL || entry->len == 0 || entry->subIndexOD < 2) { - *storageInitError = i; - return CO_ERROR_ILLEGAL_ARGUMENT; - } - - /* Open a file and read data from file to entry->addr */ - /* file = open(entry->pathToFileOrPointerToMemory); */ - /* read(entry->addr, entry->len, file); */ - } - - return ret; -} - -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ diff --git a/CANopenNode_STM32/CO_storageBlank.h b/CANopenNode_STM32/CO_storageBlank.h deleted file mode 100644 index c53f3af..0000000 --- a/CANopenNode_STM32/CO_storageBlank.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * CANopen data storage object (blank example) - * - * @file CO_storageBlank.h - * @author Janez Paternoster - * @copyright 2021 Janez Paternoster - * - * This file is part of CANopenNode, an opensource CANopen Stack. - * Project home page is . - * For more information on CANopen see . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CO_STORAGE_BLANK_H -#define CO_STORAGE_BLANK_H - -#include "storage/CO_storage.h" - -#if ((CO_CONFIG_STORAGE)&CO_CONFIG_STORAGE_ENABLE) || defined CO_DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is very basic example of implementing (object dictionary) data storage. - * Data storage is target specific. CO_storageBlank.h and .c files only shows - * the basic principle, but does nothing. For complete example of storage see: - * - CANopenPIC/PIC32 uses eeprom with CANopenNode/storage/CO_storage.h/.c, - * CANopenNode/storage/CO_storageEeprom.h/.c, CANopenNode/storage/CO_eeprom.h - * and CANopenPIC/PIC32/CO_eepromPIC32.c files. - * - CANopenLinux uses file system with CANopenNode/storage/CO_storage.h/.c and - * CANopenLinux/CO_storageLinux.h files. - */ - -CO_ReturnError_t CO_storageBlank_init(CO_storage_t* storage, CO_CANmodule_t* CANmodule, - OD_entry_t* OD_1010_StoreParameters, OD_entry_t* OD_1011_RestoreDefaultParam, - CO_storage_entry_t* entries, uint8_t entriesCount, uint32_t* storageInitError); - -uint32_t CO_storageBlank_auto_process(CO_storage_t* storage, bool_t closeFiles); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE */ - -#endif /* CO_STORAGE_BLANK_H */ diff --git a/CANopenNode_STM32/eeprom.c b/CANopenNode_STM32/eeprom.c new file mode 100644 index 0000000..0e5b998 --- /dev/null +++ b/CANopenNode_STM32/eeprom.c @@ -0,0 +1,198 @@ +/* + * eeprom.c + * + * Created on: 11 jun 2026 + * Author: Marc Vandenhende + */ + +#include "eeprom.h" +#include "CO_app_STM32.h" +#include "OD.h" + +/* + * Hardware definition + */ +#define CO_EEP_MAX_STORAGE 0x2000 // Max number of bytes reserved for CanOpen storage + +#define EEP_MEM_I2C_ADDR 0x50 // I2C address of eeprom device +#define EEP_UID_I2C_ADDR 0x58 // I2C address of ST eeprom UID + +#define ST_MFR_CODE 0x20 // ST manufacturer code +#define ST_BUS_PROTOCOL 0xE0 // ST bus protocol +#define ST_UID_SIZE 16 // ST UID size in #bytes + +#define MC_SERIAL_ADDR 0x7ffa // memory location of MC serial number +#define MC_MFR_CODE 0x29 // MC manufacturer code +#define MC_DEVICE_CODE 0x48 // MC device code +#define MC_EEP_SERIAL_SIZE 6 // MC Serial size in #bytes + +typedef struct +{ + uint8_t density; + uint32_t storage; + uint16_t page_size; +} eeprom_st_t; + +/* + * Eeprom device table + * For each recognized type, the table contains the maximum + * device capacity and the page size for eeprom writing + */ +const eeprom_st_t eeprom_st[] = +{ + {0x0c, 0x1000, 32}, // m24c32-u + {0x0d, 0x2000, 32}, // m24c64-u + {0x0e, 0x4000, 64}, // m24128-u + {0x0f, 0x8000, 64}, // m24256-u + {0x10, 0x10000, 128}, // m24512-u +}; + +uint32_t device_size = 0; +uint16_t page_size = 0; +uint16_t device_i2c_address = EEP_MEM_I2C_ADDR; +uint32_t device_serial_number = 0; + +uint32_t data_storage_start = 0; +uint32_t data_storage_size = 0; + +uint32_t device_start_co_auto = 0; +uint32_t device_start_co_prot = 0; +uint32_t device_size_co = 0; + +static bool_t eeprom_init_mc(); +static bool_t eeprom_init_st(); + +/* + * Main EEPROM initialization routine + * returns "true" if initialization is success + * returns "false" if initialization fails or no eeprom present + */ +bool Eeprom_Init() +{ + if (!eeprom_init_mc()) + { + if (!eeprom_init_st()) + { + // no EEPROM found + return false; + } + } + + /* If eeprom chip is OK, this will pass, otherwise timeout */ + return HAL_I2C_IsDeviceReady(HI2C_EEPROM, EEP_MEM_I2C_ADDR << 1, 3, I2C_TIMEOUT_MS) == HAL_OK;; +} + +/* + * Try to initialize ST eeprom + * Looks for the right device and sets parameters accordingly + * returns "true" if initialization is success + * returns "false" if no ST eeprom found + */ +static bool_t eeprom_init_st() +{ + uint8_t uid[ST_UID_SIZE]; + + /* If eeprom chip is OK, this will pass, otherwise timeout */ + if (HAL_I2C_IsDeviceReady(HI2C_EEPROM, EEP_UID_I2C_ADDR << 1, 3, I2C_TIMEOUT_MS) != HAL_OK) + return false; // return "false" if device not ready + + if (HAL_I2C_Mem_Read(HI2C_EEPROM, EEP_UID_I2C_ADDR << 1, 0, 2, uid, ST_UID_SIZE, I2C_TIMEOUT_MS) != HAL_OK) + return false; // return "false" if device does not respond + + // Check if STM EEPROM device + if ((uid[0] == ST_MFR_CODE) && (uid[1] == ST_BUS_PROTOCOL)) + { + // loop through table, set parameters when match found + for (int i = 0; i < sizeof(eeprom_st) / sizeof(eeprom_st_t); i++) + // loop through table, set parameters when match found + { + if (eeprom_st[i].density == uid[2]) + { + device_size = eeprom_st[i].storage; + page_size = eeprom_st[i].page_size; + + // set serial number + device_serial_number = (uint32_t) uid[12] << 24 + | (uint32_t) uid[13] << 16 + | (uint32_t) uid[14] << 8 + | (uint32_t) uid[15]; + + // If device > 8 kbytes, use first 8 kbytes of storage for CanOpen + if (device_size > CO_EEP_MAX_STORAGE) + { + // canopen device size values + device_size_co = CO_EEP_MAX_STORAGE; + device_start_co_auto = 0x0000; + device_start_co_prot = CO_EEP_MAX_STORAGE / 2; + + // general storage values + data_storage_start = CO_EEP_MAX_STORAGE; + data_storage_size = device_size - CO_EEP_MAX_STORAGE; + } + else + { + // canopen device size values + device_size_co = device_size; + device_start_co_auto = 0x0000; + device_start_co_prot = device_size_co / 2; + + // general storage values -> no storage available + data_storage_start = device_size_co; + data_storage_size = 0x0000; + } + + return true; + } + } + } + + return false; +} + +/* + * Try to initialize Microchip eeprom + * Check if device is 24AA256UID and sets parameters accordingly + * returns "true" if initialization is success + * returns "false" if no MC eeprom found + */ +static bool_t eeprom_init_mc() +{ + uint8_t serial[MC_EEP_SERIAL_SIZE]; + + /* If eeprom chip is OK, this will pass, otherwise timeout */ + if (HAL_I2C_IsDeviceReady(HI2C_EEPROM, EEP_MEM_I2C_ADDR << 1, 3, I2C_TIMEOUT_MS) != HAL_OK) + return false; // return "false" if device not ready + + if (HAL_I2C_Mem_Read(HI2C_EEPROM, EEP_MEM_I2C_ADDR << 1, MC_SERIAL_ADDR, 2, serial, MC_EEP_SERIAL_SIZE, + I2C_TIMEOUT_MS) != HAL_OK) + return false; // return "false" if device does not respond + + // Check if STM EEPROM device + if ((serial[0] == MC_MFR_CODE) && (serial[1] == MC_DEVICE_CODE)) + { + // set serial number + device_serial_number = (uint32_t) serial[2] << 24 + | (uint32_t) serial[3] << 16 + | (uint32_t) serial[4] << 8 + | (uint32_t) serial[5]; + + // device size is 32 kbytes (0x8000) + // but range 0x7000 -> 0x7fff not available for storage + // using first 8 kbytes of storage for CanOpen + device_size = 0x7000; + page_size = 64; + + // canopen device size values + device_size_co = CO_EEP_MAX_STORAGE; + device_start_co_auto = 0x0000; + device_start_co_prot = CO_EEP_MAX_STORAGE / 2; + + // general storage values + data_storage_start = CO_EEP_MAX_STORAGE; + data_storage_size = device_size - CO_EEP_MAX_STORAGE; + + return true; + } + + return false; +} diff --git a/CANopenNode_STM32/eeprom.h b/CANopenNode_STM32/eeprom.h new file mode 100644 index 0000000..5f0fd98 --- /dev/null +++ b/CANopenNode_STM32/eeprom.h @@ -0,0 +1,30 @@ +/* + * eeprom.h + * + * Created on: 11 jun 2026 + * Author: Marc Vandenhende + */ + +#ifndef INC_EEPROM_H_ +#define INC_EEPROM_H_ + +#include +#include "main.h" + +#define EEPROM_WRITE_TIME 5 // maximum write cycle time + +bool Eeprom_Init(); + +extern uint32_t device_size; +extern uint16_t page_size; +extern uint16_t device_i2c_address; +extern uint32_t device_serial_number; + +extern uint32_t data_storage_start; +extern uint32_t data_storage_size; + +extern uint32_t device_start_co_auto; +extern uint32_t device_start_co_prot; +extern uint32_t device_size_co; + +#endif /* INC_EEPROM_H_ */ diff --git a/examples/stm32f0xx_can/.cproject b/examples/stm32f0xx_can/.cproject index bfa9581..5560967 100644 --- a/examples/stm32f0xx_can/.cproject +++ b/examples/stm32f0xx_can/.cproject @@ -21,7 +21,8 @@