Program memory interactions - Abathargh/avr_io GitHub Wiki

The avr_io/progmem module provides utilities to interact with program memory in AVR chips. This module provides primitives useful to store data in program memory, retrieve it and manipulate it.

Storing data in program memory

The progmem macro allows the user to store many kinds of data into program memory. Note that a let statement is required. The type of the data is inferred from the first element when using arrays.

let
  testFloat {.progmem.} = 11.23'f32               # floats
  testInt1  {.progmem.} = 12'u8                   # 8-bit integers
  testInt2  {.progmem.} = 13'u16                  # 16-bit integers
  testInt3  {.progmem.} = 14'u32                  # 32-bit integers
  testStr   {.progmem.} = "test progmem string\n" # strings
  testArr   {.progmem.} = [116'u8, 101, 115, 116, # arrays
                           32, 97, 114, 114, 97, 
                           121, 10]

Objects can also be stored in program memory:

type 
  foo = object
    f1: int16
    f2: float32

  bar = object
    b1: bool
    b2: cstring # in objects, we must use cstring

  foobar = object
    fb1: bool
    fb2: foo

  barfoo = object
    bf1: int
    bf2: bar

  arr_elem = object
    i: int
    f: float

let 
  testObj1   {.progmem.} = foo(f1: 42'i16, f2: 45.67)
  testObj2   {.progmem.} = bar(b1: true, b2: "test string in object\n")
  testObj3   {.progmem.} = foobar(fb1: false, fb2: foo(f1: 21, f2: 77.0))
  testObj4   {.progmem.} = barfoo(bf1: 69, bf2: bar(b1: false, b2: "inner\n"))
  testArrObj {.progmem.} = [arr_elem(i: 1, f: 0.1), arr_elem(i: 2, f: 0.2)]

You can also reserve a block of program memory of size size, containing objects of type type, using the progmem_array(type, size) macro. This is particularly useful when wanting to embed metadata within your binaries.

progmem_array(testNonInitArr, uint8, 10)

Note: usage of {.progmem.} are type-checked, and only plain, non-managed value types are accepted by the library.

Accessing data stored in program memory

Data stored in program memory can be accessed in different ways depending on the type of data.

To get the contents of a progmem variable, you just dereference said variable through the [] operator:

# sendData sends data through uart as its ASCII representation

sendData(testFloat[])
sendData(testInt1[])
sendData((testInt3[])

The same applies for progmem objects:

sendData(testObj1[].f1)
sendData(testObj1[].f2)
sendData(testObj2[].b1)
sendData(testObj2[].b2)

Progmem array utilities

Progmem arrays can be accessed in a variety of ways. You can dereference them and get a copy of the whole array:

sendData(testArr[])
sendData(testNonInitArr[])

This works for progmem strings too: dereferencing one will yield an object of array[S, cchar] type:

sendData(testStr[]) 

Progmem arrays can also be indexed, by using an offset as when indexing normal arrays:

sendData(testArr[0])
sendData(testArr[1])
sendData(testArr[2])
sendData(testArr[3])

Finally, they can also be iterated, which makes them easier and safer to use:

for num in progmemIter(testArr):
  sendData(num)