Write serial number#
In the production line, the devices should be programmed with the identical firmware image. The object entry 1018 holds optionally a serial number which sould be unique for each device. We need a one-time programmable object entry.
Example Goal#
The main idea is a manufacturer specific data type, which allows writing into a FLASH memory area if the current FLASH memory area is empty.
Object Type Idea#
The main idea is an object entry, which is directly mapped to FLASH cells. The type checks on a write access for empty FLASH cells and allows writing with a FLASH write algorithm if FLASH cells are empty.
Object Entry Definitions#
We define some manufacturer specific entries in the object dictionary:
Index | Subindex | Type | Access | Value | Description |
---|---|---|---|---|---|
1018h | 4 | UNSIGNED32 | Const | FFFFFFFF | Serial No. |
The key to get the wanted functionality is the object type for the entry at subindex 4. This object type accepts a single permanent write access if the current value is 0xFFFFFFFF
.
Implement Object Type#
Lets implement the one time programmable (OTP) user type as shown in the CANopen Usage: User Object:
const uint32_t serialNo = 0xFFFFFFFFu; /* locate this variable to FLASH and initialize with empty cell value */
const CO_OBJ_TYPE COTOtp = { 0, 0, 0, OtpWrite };
#define CO_TOTP ((CO_OBJ_TYPE*)&COTOtp)
The write function is called, when the CAN network writes to the related object entry via a SDO request. Now we want to allow the write algorithm for the constant FLASH value after a serial-no is written to the object entry at subindex 4.
int16_t OtpWrite(CO_OBJ *obj, struct CO_NODE_T *node, void *buf, uint32_t size)
{
uint32_t value = *((uint32_t *)buf);
uint32_t serial = *((uinter_t *)obj->Data);
CO_ERR result = CO_ERR_TYPE_WR;
if (serial == 0xFFFFFFFF) {
/* call your hardware specific FLASH algorithm with
* - start address in FLASH
* - new serial value
* - length of constant
*/
HwFlashWriteAlgorithm(obj->Data, value, 4);
}
return result;
}
Implement Object Entries#
We use our user type to define the calibration object entry:
const CO_OBJ ExampleObjDir[] = {
:
{ CO_KEY(0x1018, 4, CO_UNSIGNED32|CO_OBJ_D__R_), CO_TOTP, (CO_DATA)&serialNo },
:
};
Now we have a one time programmable object entry for the serial number. This concept shows how to integrate application specific logic to specific object entry access.