Demi C Reference

Writes to a circular buffer of 8-byte demis. This is stored in an NFC readable EEPROM e.g. the NXP NT3H2111.

An EEPROM block is 16 bytes long. Demi is short for demi-block; it is 8 bytes long. A majority of transactions write 3 demis:

  • Demi0: Two base64 encoded pairs (pair_t) comprised of 4x sensor readings.

  • Demis1 and 2: Circular buffer endstop (endstop_t).

Demis are written to an EEPROM location given by _cursordemi:

  • Even values of _cursordemi start at byte 0 of an EEPROM block.

  • Odd values of _cursordemi start at byte 8 of an EEPROM block. A demi always fits completely into one EEPROM block, it never stradles two.

The function demi_movecursor() adds 1 to _cursordemi or resets it to 0 if the end of the circular buffer _enddemi has been reached.

There is no need to move the cursor after every write; the same 3 demis can be overwritten. If only one of the two available pairs in Demi0 changes at a time, the cursor is only moved after both have been produced. This applies if the format specifies OnePairPerSample (see CODEC_FEAT_42).

Sometimes only one demi needs to be overwritten: Demi2 contains minutes elapsed since the previous sample (::markerb64). This is overwritten every minute between samples. For this only one EEPROM block needs to be modified with demi_commit2(). This saves power, because writing to an I2C EEPROM is slow.

When all 3 demis are modified, 4 demis (two EEPROM blocks) must be written with demi_commit4().

Whilst the code allows for 1,2 or 3 demis to be edited locally, the EEPROM must be read and written in multiples of 2 demis i.e. one block at a time. Two blocks of EEPROM are buffered at all times. This buffer must be updated:

This preserves data in the extra demi, which will either be after demi2 or before demi0. The buffer update is done with demi_readcursor(). It deduces which EEPROM blocks to copy into the local buffer based on _cursordemi.



Write first demi after the cursor.


Write second demi after cursor.


Write third demi after the cursor.


typedef enum DemiState DemiState_t

Structure to describe the state of the EEPROM circular buffer.


enum DemiState

Structure to describe the state of the EEPROM circular buffer.


enumerator ds_consecutive

_cursorblk is not 0 and _nextblk is located at the next EEPROM block.

enumerator ds_looparound

_cursorblk is at the end of the circular buffer and _nextblk is at the beginning. Data are overwritten from the first time this occurs.

enumerator ds_newloop

_cursorblk is 0 and _nextblk is 1. A new loop of the circular buffer has started.



Maps a demi to its EEPROM block.


Returns 1 if x is ODD and 0 if x is EVEN.


void fram_write_enable(void)

Enable writes to FRAM. Should be defined in the processor-specific cuplTag project.

void fram_write_disable(void)

Disable writes to FRAM. Should be defined in the processor-specific cuplTag project.

static void demi_read4(void)

Copy 4 demis from EEPROM into RAM.

This is 2 demis from _cursorblk and 2 demis from the block after it _nextblk. If _cursorblk is at the end of the buffer, then _nextblk will be at the start. This makes the buffer circular.

static void demi_shift2read2(void)

Right shift the RAM buffer by 2 demis and append 2 demis read from the _nextblk.

First: RAM buffer is right shifted by one block, overwriting the previous cursor block with the new cursor block. Second: New contents of _nextblk are copied out of EEPROM into the vacant RAM buffer block.

The right shift saves a slow and unnecessary read of _cursorblk from EEPROM.

void demi_commit4(void)

Copy 4 demis from RAM to EEPROM.

void demi_commit2(void)

Write the last 2 demis from RAM to the EEPROM.

Some functions only need to modify the last 2 demis so this saves time and energy over writing 4.

void demi_init(const int startblk, const int lenblks)

Initialise the EEPROM circular buffer.

Reads the first 4 demis in RAM.

  • startblk – EEPROM block to start the circular buffer.

  • lenblks – Length of circular buffer in EEPROM blocks.

int demi_write(int offsetdemis, char *demidata)

Overwrite one demi in the RAM buffer.

The function to modify the RAM buffer eep_cp() requires a byte index relative to _cursorblk.

  • When _cursordemi is EVEN, nothing is needs to be done because it lies on a block boundary.

  • When _cursordemi is ODD then it is offset from the block boundary by one demi. Therefore one is added to offsetdemis.

  • offset – Demi index to overwrite, relative to _cursordemi. Must be 0, 1 or 2.

  • demidata – Pointer to an 8 byte array of new demi data.

DemiState_t demi_movecursor(void)
void demi_readcursor(void)

Update RAM buffer to contain the 4 demis after _cursordemi.

This function must be called each time the cursor position is changed.

When _cursordemi is 0 it is assumed that the RAM buffer is empty, so all 4 demis are read. When _cursordemi is not 0, it is assumed that the RAM buffer has been populated before. It is also assumed that _cursordemi has only moved once since the previous time this function was called. Therefore it is not necessary to read 4 more demis out of the EEPROM.

int demi_getendmarkerpos(void)


int _endblk = 0

Last EEPROM block in the circular buffer.

int _startblk = 0

First EEPROM block in the circular buffer.

int _cursorblk = 0

Cursor address in terms of 16-byte EEPROM blocks. Must be >= _startblk and <= _endblk.

int _nextblk = 0

Address of the next EEPROM block after cursor block. The buffer is circular, so it can be < _cursorblk.

int _enddemi = 0

Largest possible value of _cursordemi. Always an odd integer.

int _cursordemi = 0

Cursor in terms of 8-byte demis. Must be >= 0 and <= _enddemi.