Accessing array elements inside structs

Hi,

I hope someone more familiar with C can give me some guidance.

I’m writing a program which will read a number of temperature “probes”. Each probe consists of upto twelve DS18B20 temperature sensors to be accessed over OneWire bus. There may be up to 32 Probes in the whole system. Hence, maximal possible number of sensors is 12 per probe * 32 probes = 384 sensors. Each sensor requires a hard coded 8 byte address, hence 384*8 bytes = 3072 bytes of data just for storing the addresses.

I have tried a few different implementations in order to use flash (PROGMEM) for storing these addresses, but they seem to always eat into SRAM (accroding to avr-size) and hence I quickly run out of SRAM with all the other code running. Ultimately this will go into an Arduino Mega2560.

Finally, I am trying yet another implementation which I hope will work. I have stripped the example to the bare minimum needed to present here.

Namely, there are const uint8_t[8] arrays that hold each address, then these arrays are put into Probe structures (which include some other volatile and non-volatile variables), and finally all Probe structs are collected into a Probes array. This organisation will ultimately allow me to for-loop through all the probes and sensors efficiently, but I first need to get the data organisation working.

The stripped down code is presented below:

#include <avr/pgmspace.h>
#define PROBES_NUM 2
#define PROBES_MAX 2

// PROBE 00
const prog_uint8_t PROGMEM S00N00[8] = {0x28, 0x92, 0x2C, 0xB9, 0x05, 0x00, 0x00, 0x2F}; // LEVEL 00
const prog_uint8_t PROGMEM S00N01[8] = {0x28, 0x47, 0x4D, 0xB9, 0x05, 0x00, 0x00, 0xDC}; // LEVEL 01
const prog_uint8_t PROGMEM S00N02[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 02
const prog_uint8_t PROGMEM S00N03[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 03
const prog_uint8_t PROGMEM S00N04[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 04
const prog_uint8_t PROGMEM S00N05[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 05
const prog_uint8_t PROGMEM S00N06[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 06
const prog_uint8_t PROGMEM S00N07[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 07
const prog_uint8_t PROGMEM S00N08[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 08
const prog_uint8_t PROGMEM S00N09[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 09
const prog_uint8_t PROGMEM S00N10[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 10
const prog_uint8_t PROGMEM S00N11[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 11

// PROBE 01
const prog_uint8_t PROGMEM S01N00[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // LEVEL 00
const prog_uint8_t PROGMEM S01N01[8] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB}; // LEVEL 01
const prog_uint8_t PROGMEM S01N02[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 02
const prog_uint8_t PROGMEM S01N03[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 03
const prog_uint8_t PROGMEM S01N04[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 04
const prog_uint8_t PROGMEM S01N05[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 05
const prog_uint8_t PROGMEM S01N06[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 06
const prog_uint8_t PROGMEM S01N07[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 07
const prog_uint8_t PROGMEM S01N08[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 08
const prog_uint8_t PROGMEM S01N09[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 09
const prog_uint8_t PROGMEM S01N10[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 10
const prog_uint8_t PROGMEM S01N11[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // LEVEL 11

typedef struct {
	const char PROGMEM name[9];
	const int PROGMEM numLevels;
	const prog_uint8_t *levels[12];
	float temperatures[12];
	OneWire *line;
} PROGMEM Probe;

// PROBE 00
Probe PROGMEM Probe00Struct = {
	"TestS00",                                        // Name of Probe (Max 8 chars)
	2,                                                // Num of levels
	S00N00,                                           // Level 1
	S00N01,                                           // Level 2
	S00N02,                                           // Level 3
	S00N03,                                           // Level 4
	S00N04,                                           // Level 5
	S00N05,                                           // Level 6
	S00N06,                                           // Level 7
	S00N07,                                           // Level 8
	S00N08,                                           // Level 9
	S00N09,                                           // Level 10
	S00N10,                                           // Level 11
	S00N11,                                           // Level 12
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,               // Temperatures
	0                                                 // OneWire Line
};

// PROBE 01
Probe PROGMEM Probe01Struct = {
	"TestS00",                                        // Name of Probe (Max 8 karaktera)
	2,                                                // Num of levles
	S01N00,                                           // Level 1
	S01N01,                                           // Level 2
	S01N02,                                           // Level 3
	S01N03,                                           // Level 4
	S01N04,                                           // Level 5
	S01N05,                                           // Level 6
	S01N06,                                           // Level 7
	S01N07,                                           // Level 8
	S01N08,                                           // Level 9
	S01N09,                                           // Level 10
	S01N10,                                           // Level 11
	S01N11,                                           // Level 12
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,               // Temperatures
	0                                                 // OneWire Line
};

and the main file is:

#include <OneWire.h>
#include "DataStructs.h"


// Instantiation of OneWire protocol
OneWire S0(10); //Pin 10
OneWire S1(11); //Pin 11

Probe *probes[PROBES_NUM] = {&Probe00Struct, &Probe01Struct};

void printAddress(const prog_uint8_t* addr) 
{
 int i;
 for (i = 0; i < 8; i++) {
   if (addr[i] < 16) Serial.print("0");
   Serial.print(addr[i], HEX);
   Serial.print(" ");
 }
 Serial.println(); 
}

void setup(void) 
{
  Serial.begin(9600); 
  
  Serial.println("Print some info");
  // Assign OneWire instances to Probe Structs
  probes[0]->line = &S0;
  Serial.print("Name of Probe: "); 
  Serial.println(probes[0]->name);
  Serial.print("Number of Levels: ");
  Serial.println(probes[0]->numLevels);
  
  printAddress(probes[0]->levels[0]);
  
  // Try accessing OneWire object inside a probe
  probes[0]->line->reset(); // DOES NOT WORK BUT COMPILES
}


void loop(void) 
{

}

The code compiles, but running the code I get random gibberish and not what I expect. For instance, I get the following:

Print some info
Name of Probe: 
Number of Levels: 514
05 01 01 02 00 00 00 00

While I would expect:

Print some info
Name of Probe: TestS00
Number of Levels: 2
28 92 2C B9 05 00 00 0x2F

I’m pretty sure I am not accessing the structures correctly or perhaps I have built a structure different than what I think it should be. I would greatly appreciate if someone could give me some pointers and perhaps note whether this will actually keep all the addresses in Flash and keep them out of SRAM?

Thanks in advance!

You have to remember that SRAM and PROGMEM are two separate address spaces and the compiler does NOTHING to keep track of which address go with which address space. If you want anything to be fetched from PROGMEM you have to A) Remember that you put the data in PROGMEM, and B) explicitly call a function to fetch it from PROGMEM, otherwise you will get whatever is in the same address in SRAM.

One solution would be to keep your onewire address ID's in a file on an sd card and then read them one at a time instead of trying to keep all 3000 ID's in memory.

You could also purchase one of the onewire product company's eproms to store the addresses of the temperature sensors in.

There should be plenty of space for the addresses in PROGMEM, and that should work fine once you get the code right. However, you will need to discover the addresses and type them into your code; with that many addresses it seems like quite a tedious approach. Have you considered the possibility of accessing them by device index instead? It will be a lot slower, but I don't know whether that will matter to you. Either way I suspect you're going to need some scheme for autodiscovery and maintenance of the addresses of the currently-connected devices.

Hence, maximal possible number of sensors is 12 per probe * 32 probes = 384 sensors. Each sensor requires a hard coded 8 byte address, hence 384*8 bytes = 3072 bytes of data just for storing the addresses.

Just on a note of storage. I noticed in the datasheet the 64 bit address is stored as: 8 bit CRC, 48 bit serial, 8 bit family code.

The only data you need to store is the serial, right? The family code is always 28h and can be ignored. Its just to verify the type of device. The CRC just increases the resolution for universal addresses, however the serial should be unique for that particular device.

It at least cuts the data to 2304 bytes.

If all your devices are within a range, you might find you only need 9 bits to uniquely identify them if the first 39 are all the same. Then the data goes down to 432 bytes.