Administrative

Projects

Active

Future

Finished

Reference

Abandoned

Project: HomeAutomation

Accessing an array of arrays in program memory in AVR-GCC

The bus logic modules needed a way to retrieve and send (through the ATxmega USART) a string identifier found by an index into a string table. The table is stored in program memory, because it is already large (for microcontroller means of "large"), and may grow in the future.

There was a nice how-to guide at github, which boils down to this (with a bit tweaking to avoid compiler warnings about lost qualifiers)::

Storing the array

pgmstrings.c

#include <avr/pgmspace.h>

const char cs_module_ident_0[] PROGMEM = "unknown module id 0\0";
const char cs_module_ident_1[] PROGMEM = "HA-B01 multi-channel digital input\0";
const char cs_module_ident_2[] PROGMEM = "HA-B02 dual-CAN/USB control PC interface\0";
const char cs_module_ident_3[] PROGMEM = "multi-channel digital switch controller\0";
const char cs_module_ident_4[] PROGMEM = "multi-channel dimmer output controller\0";
const char cs_module_ident_5[] PROGMEM = "iod_can_emulator dummy device\0";
const char cs_module_ident_6[] PROGMEM = "HA-B06 modular CAN-I/O bus module\0";
const char cs_module_ident_7[] PROGMEM = "HA-B07 16-way controller interface\0";
const char cs_module_ident_8[] PROGMEM = "HA-B08 16-way input interface\0";

const char * const cs_module_idents[] PROGMEM = {
    cs_module_ident_0,
    cs_module_ident_1,
    cs_module_ident_2,
    cs_module_ident_3,
    cs_module_ident_4,
    cs_module_ident_5,
    cs_module_ident_6,
    cs_module_ident_7,
    cs_module_ident_8,
};

pgmstrings.h

#define CS_MODULE_IDENTS_MAX 8
extern const char *cs_module_idents[];

Using the array

uart.c

#include <avr/pgmspace.h>
#include "pgmstrings.h"

void uart_send_modident(const uint8_t i) {
    uart_send_pstring((char *) pgm_read_word(&cs_module_idents[i]));
}

void uart_send_pstring(const char *s) {
    uint8_t c;
    extern USART_data_t usart_data;

    while ((c = (uint8_t) pgm_read_byte(s))) {
        while (!(usart_tx_bufspace(&usart_data)))
            ;
        usart_tx_byte(&usart_data, c);
        s++;
    }
}

This actually needs a few more include files to access the USART, and initialization, of course. Please see the various tutorials, application notes, and datasheets for details of basic USART usage.

main.c

uart_send_modident(mod_info.mod_type);