Skip to content

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, (uintptr_t)&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.