Dit onderwerp is min of meer ontstaan uit dit onderwerp: topic
Daaruit kwam een behoefte om ahw een circulaire buffer (array) te maken waardoor je altijd de laatste (array grootte aantal) entries kan uitlezen. In ram is dit allemaal niet zo'n probleem. Echter dan ben je beperkt tot de hoeveelheid ruimte (RAM) die er beschikbaar is.
Een poging om een SD kaartje als geheugen te gebruiken lukte ten dele. Het werkte op zich prima. Echter na wat testen wilde de SD niet meer schrijven. Het gebruikte SD kaartje (heel oud) haalde hooguit 10.000 schrijf operaties. Ik schreef 1.000.000 x.
Nu kwam ik recentelijk F-RAM ic's tegen. Deze IC's hebben een interface met I2C of SPI (tot 20-40 Mhz). Daarnaast is er op dit moment al 1Mbyte (8MBits) beschikbaar.
Op dit moment heb ik een class gemaakt die prima met RAM werkt. Gaat binnenkort naar Github als library.
Als het meezit komt dit weekend een 32Kbyte F-RAM binnen en kan ik kijken of ik een array met redelijke performance daarop kan maken zonder dat je, je daar verder druk over hoeft te maken in de programma code.
Voor hen die niet kunnen wachten:
Hier is de class die je in een .h bestand kan maken:
/*
* Array.h
*
* Created on: 14 dec. 2018
* Author: nicoverduin
*/
#ifndef ARRAY_H_
#define ARRAY_H_
//
// Generic catch-all implementation for determining type of variable
// with thanks to http://arduino.stackexchange.com/questions/3079/how-to-retrieve-the-data-type-of-a-variable
//
template <typename T_ty> struct TypeInfo { static const char * name; };
template <typename T_ty> const char * TypeInfo<T_ty>::name = "unknown";
//
// Handy macro to make querying stuff easier.
//
#define TYPE_NAME(var) TypeInfo< typeof(var) >::name
//
// Handy macro to make defining stuff easier.
//
#define MAKE_TYPE_INFO(type) template <> const char * TypeInfo<type>::name = #type;
//
// Type-specific implementations. Only float and double need to be tested
//
MAKE_TYPE_INFO( float )
MAKE_TYPE_INFO( double )
// test defines
#define DEBUG
enum {
RAM, // in memory array
FRAM // array in F-RAM
};
template<class T>
class Array {
protected:
bool loopAround; // loop around has taken place if true
uint32_t beginIndex; // virtual start of array
uint32_t endIndex; // virtual end of array
uint32_t arraySize; // number of array entries
uint32_t lastIndex; // used for operator overloading
T value; // temporary field used for reading
T * array = NULL; // points to our array
uint8_t storageType; // determines where the array is stored
// functions
public:
/*
* @name init
* @param uint32_t size of array in entry count
* @param uint8_t storageType determines where the array will be stored
* @brief initializes andcreates an array of size T types number of entries
*/
void init(uint32_t size, uint8_t storage = RAM) {
// initialize our variables
beginIndex = 0;
endIndex = 0;
arraySize = size;
loopAround = false;
storageType = storage;
if (storageType == RAM) {
// allocate our array
array = (T *)malloc(size * sizeof(T));
}
#ifdef DEBUG
if (array != NULL) {
Serial.println("Array allocated");
} else {
Serial.println("Array allocation failed!!!");
return;
}
#endif
// initialize our array
for (uint32_t i = 0; i < arraySize; i++) {
if (strcmp(TYPE_NAME(T), "double") == 0 || strcmp(TYPE_NAME(T), "float") == 0) {
if (storageType == RAM) {
array[i] = 0.0;
}
} else {
if (storage == RAM) {
array[i] = 0;
}
}
}
#ifdef DEBUG
printArray(10);
#endif
}
/**
* @name printArray
* @param uint8_t number of elements on row to print
* @brief prints the array in rows of 10 elements each
*/
void printArray(uint8_t noOfElements) {
uint8_t elementsCtr = 0; // number of element per row counter
if (storageType == RAM) {
if (array != NULL) { // only print if there is an array
for (uint8_t i = 0; i < arraySize; i++) {
Serial.print(array[i]);
Serial.print(" ");
elementsCtr++;
if (elementsCtr == noOfElements) {
Serial.println();
elementsCtr = 0;
}
}
}
// extra line after last row
Serial.println();
}
}
/*
* @name addEntry
* @param value variable of type T to be added to at endIndex
* @brief adds the passed variable to the current endIndex subscript
*/
void addEntry(T value) {
// check if we need to do a loop around
if (endIndex == arraySize) { // the array is full so we need to
loopAround = true; // loop around
}
endIndex = endIndex % arraySize; // calculate the new offset
if (storageType == RAM) {
// add our value
array[endIndex] = value;
}
// raise our subscript for the next time
endIndex++;
// move the begin index one up if array is full
if (loopAround) {
beginIndex++;
// and calculate our new substript
beginIndex = beginIndex % arraySize;
}
}
/*
* @name getEntry
* @param index subscript of which we want our value
* @returns T
* @brief returns the value of type T based on virtual subscript
*/
T getEntry(uint32_t index) {
// calculate our virtual index within the array
uint32_t virtualIndex = beginIndex + index;
// calculate the real subscript
virtualIndex = virtualIndex % arraySize;
// return our value
if (storageType == RAM) {
return array[virtualIndex];
}
}
/*
* @name setEntry
* @param index virtual subscript in which we want our value
* @param value T type value to be stored in array
* @returns none
* @brief returns the value of type T based on virtual subscript
*/
void setEntry(uint32_t index, const T value) {
// calculate our virtual index within the array
uint32_t virtualIndex = beginIndex + index;
// calculate the real subscript
virtualIndex = virtualIndex % arraySize;
// store our value
if (storageType == RAM) {
array[virtualIndex] = value;
}
}
/*
* @name operator []
* @param index 32 bit unsigned int that references an array entry
* @returns variable T virtually referenced in array
* @brief returns the value of type T based on virtual subscript
*/
T& operator[](uint32_t index) {
// calculate our virtual index within the array
uint32_t virtualIndex = beginIndex + index;
// calculate the real subscript
virtualIndex = virtualIndex % arraySize;
// return our value
if (storageType == RAM) {
return array[virtualIndex];
}
}
/**
* @name wipe
* @brief deletes the memory allocated to the array
*/
void wipe(){
if (storageType == RAM) {
free(array);
}
}
};
#endif /* ARRAY_H_ */
En hier een eenvoudige sketch hoe je ermee kan werken
/*
Name: Ringbuffer.ino
Created: 14-12-2018 08:41:43
Author: nico verduin
Brief: Eenvoudige manier om met een array een ringbuffer te maken
*/
// includes
#include "Array.h"
// program defines
#define ARRAY_SIZE 100
#define COLUMNS_PER_ROW 10
#define ARRAY_TYPE double
// global variables
// create an array of type uint32
Array <ARRAY_TYPE> myArray;
/*
* @name setup()
* @brief Initializes the program
*/
void setup()
{
// initialiseer Serial
Serial.begin(115200);
// allocate an initialize our array
myArray.init(ARRAY_SIZE);
for (uint8_t i = 0; i < ARRAY_SIZE; i++) {
myArray.addEntry((ARRAY_TYPE)i);
}
// change the virtual indxes
myArray.addEntry(1000);
myArray.addEntry(2000);
// now see what has happened
myArray.printArray(COLUMNS_PER_ROW);
Serial.println(myArray[12]);
myArray[12] = 10000;
Serial.println(myArray[12]);
// delete allocated memory
myArray.wipe();
}
// Add the main program code into the continuous loop() function
void loop()
{
}
Met ARRAY_TYPE definieer je het soort array (int, uint32_t, double etc)
de rest spreekt voor zichzelf