Bizarre: Initialising or updating array breaks other functions

Hi guys, I’m wondering if someone here would be able to help me with a strange problem I’m having with my code.

I’ve been writing code to create a persistence of vision display. I’m pretty much there, when I spin up my system it displays a bitmap that is parsed in my mapping function. The remaining work I have to do is calculate the exact period of rotation and implement a lookup table/array that indexes the columns as they spin, returning the correct amount of delay (micros) in order to stabilise the image. At the moment my bitmaps alias around the screen surface.

I have written functions to:

  • Get the period from using an ISR triggered by a hall effect sensor which my LEDs pass on each rotation
  • Update the time step array according to the current period of rotation
  • Initialise my bitmap and my time step array

My problem is that my time step array seems to be causing my code to malfunction.
This is my initialisation function which is called during set up.

void init_indices()
{
  for (int i = 1; i < columnSize; i++)
      timeIndices[i] = 0;
}

This is the updating function

void updateTimeIndices(double period)
{
    //Time taken to traverse arc that represents the screen width  
    screenWidth = 0.312795 * period;
    for (int i = 1; i < columnSize; i++)
        timeIndices[i] = 1000000 * ( (i * screenWidth) / columnSize );

   updated = true;

}

Finally this is my loop, I’ve cut down everything else that happens in it for debugging purposes. I’ve done this step by step until I have isolated what seems to be the issue I’m coming to everyone here with

void loop()
{
    if(updated != true)
       updateTimeIndices(0.04);

    Serial.println("mapping");
    mapToScreen(image);
    Serial.println("mapped");

}

When init_indices() is called within setup() or updateTimeIndices is called within loop(), my mapping function breaks.
There are no data dependencies between the mapping function and these other functions.

Analysing the serial monitor when my indices functions are commented out, I see mapping/mapped being printed in a loop.
However when I try to call either function, even just init_indices() in setup() by itself with updateTimeIndices() removed from loop() - mapToScreen() breaks (the pixels are off or remain frozen in their last position if they were previously flashing).
At this point the serial monitor appears to suggest it gets stuck in this function. Indeed, as annotated in the comments below, my code gets stuck in the inner for loop

//Translates an array of RGB pixel values to 'screen buffer'
void mapToScreen(unsigned int bitmap[32][24])
{
    
    for(int i = 1; i < columnSize; i++){  
        delayMicroseconds(500);
        for(int j = 0; j <= rowSize; j++)
        {
            //Introduce delay corresponding to column i
            strip.setPixelColor(j, bitmap[j][i]);
            Serial.println("Inner for");    // prints
        }
        strip.show();
        Serial.println("Outer for");    // This never prints 
    }
    Serial.println("End of function");   // This never prints
}

I’m really stumped with this, I’m thinking I’ve made some trivial error and managed to overlook it, I’ve missed some intricacy of the language or I’ve been careless with memory management and something has gone awry there.

array run from 0 not 1

Mark

Sorry yes, I’ve realised this now. :sweat_smile:

Initially, I didn’t have an initialisation function for array. It originally was filled when updateTimeIndices() were called.

When initialising the array because I was using the index ‘i’ in an operation so I started indexing from 1;

timeIndices[i] = 1000000 * ( (i * screenWidth) / columnSize );

I realise this skips the first element, I was being stupid. Thanks for pointing it out.

I’ve changed my code to deal with this, however the problem persists. The symptoms are exactly the same, although now the print statements seem to be moving through mapToScreen() fine although they are printing odd characters.

void init_indices()
{
  for (int i = 0; i < columnSize; i++)
    timeIndices[i] = 0; 
}
void updateTimeIndices(double period)
{
    //Time taken to traverse arc that represents the screen width  
    screenWidth = 0.312795 * period;
    for (int i = 0; i < columnSize; i++)
    {
      if(i == 0)
        timeIndices[i] = 1000000 * ( (1 * screenWidth) / columnSize );
      else
        timeIndices[i] = 1000000 * ( (i * screenWidth) / columnSize );
    }
    
    updated = true;

}

So you've probably run out of RAM - you haven't indicated which Arduino, nor have you
posted the entire sketch so can only guess. 32 x 24 unsigned int's is ambitious unless
you're on something like the Due with sensible amounts of RAM.

Hmmm I think you're probably right. I feared that.
I'm on Arduino UNO so it's pretty skimpy.

My ultimate intention was to stream this bitmap data over a wifi connection from an android app I've been writing. I haven't reached that stage yet however so I've had to use the RAM.
I notice on my wifi shield there is an SD card, is it possible to use this for extended memory? As I mentioned I haven't gotten this far yet so I've not looked into the full in's and out's of the shield's functionality.

You haven’t shown a declaration for timeIndices. Your second bit of code there has a pretty dodgy calculation to put into it.

Okay so I went and did some memory analysis and saw that I was using 98% of my SRAM. After some optimisation I managed to knock this down a little, however it wasn’t enough.

I did a little searching into storing the static bitmap data into the flash memory and came across a nice library that provides some convenient data structures to do just that.

http://arduiniana.org/libraries/flash/

With having done this my SRAM usage is down to ~30% however, strangely simply declaring my table at the start of my code breaks the strip. I have a function to test the most fundamental functionality - setting the colours then turning the pixels on. This only works when the declaration of the table is commented out.

I’d really like to work with this flash memory for storing my image since I don’t have the means to get a better chip at the moment. My last resort here is perhaps to implement an algorithm to convert my RGB to 8 bit colour or indexed colour. I would prefer to keep my full colour space though.

Any pointers?

I’ll post my full code since I seem to be obscuring things with snippets here in there. It’s just quite long that’s all.

#include <Adafruit_NeoPixel.h>
#include <avr/interrupt.h>
#include <Flash.h>

#define PIN 6
// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(32, PIN, NEO_GRB + NEO_KHZ800);

uint32_t r = strip.Color(255, 0, 0);
uint32_t b = strip.Color(0, 0, 255);
uint32_t orange = strip.Color(255, 100, 0);
uint32_t yellow = strip.Color(255, 255, 0);
uint32_t green = strip.Color(0, 255, 0);
uint32_t purple = strip.Color(255, 0, 255);
uint32_t pink = strip.Color(105, 0, 255);

//uint32_t colours[] = {r, yellow, green, b, purple, pink};


const int columnSize = 24;
const int rowSize = 32;

unsigned long startTime;

volatile int revs;
int prevRevs = 0;
int revsThisLoop;

double timeIndices[columnSize];

FLASH_TABLE(unsigned int, image, 24, /*Table Width*/
  {r, r, r, r, r, r, r, r, r, r, r, r, r, r, r, r},
  {r, r, r, r, r, r, r, r, r, r, r, r, r, r, r, r},
  {r, r, r, r, r, r, r, r, r, r, r, r, r, r, r, r},
  {b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b},
  {b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b},  
  {b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b},  
  {b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b},  
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, b, b, b, b, r, r, r, r, r, r},
  {r, r, b, b, b, b, b, b, b, b, r, r, r, r, r, r},
  {r, r, b, b, b, b, b, b, b, b, r, r, r, r, r, r},
  {r, r, b, b, b, b, b, b, b, b, r, r, r, r, r, r},
  {r, r, b, b, b, b, b, b, b, b, r, r, r, r, r, r},
  {r, r, r, r, r, r, r, r, r, r, r, r, r, r, r, r},
  {r, r, r, r, r, r, r, r, r, r, r, r, r, r, r, r} );

//unsigned int image[rowSize][columnSize];
int i, j;
boolean updated;


//Interrupt Service Routine called when Hall Effect Sensor goes high
//Counts number of revolutions
void revCount()
{
  revs++;
}


void setup() 
{
    Serial.begin(9600);
    
    
    strip.begin();
    //Initialize all pixels to 'off'
    strip.show();
    
    //Initialize the hall effect sensor pin as an input:
    //pinMode(0, INPUT); 
    
    //Trigger interrupt routine 'revCount' on rising edge of hall reading
    //attachInterrupt(0, revCount, FALLING);
    
    
    //revs = 0;
    startTime = 0; 
    updated = false;
    
    init_indices();
    //drawImage();    
}

void init_indices()
{
  for (i = 0; i < columnSize; i++)
      timeIndices[i] = 0; 
}


//Translates an array of RGB pixel values to 'screen buffer'
void mapToScreen(_FLASH_TABLE<unsigned int> &bitmap)
{
    
    for(i = 0; i < columnSize; i++){  
        //Introduce delay corresponding to column i
        delayMicroseconds(500);
        for(j = 0; j < rowSize; j++)
        {
          strip.setPixelColor(j, bitmap[j][i]);
        }
        strip.show();
    }
}

void loop()
{
    //Note the time the previous iteration of loop ran
    //startTime = millis()   
    
    //Revolutions per loop
    //revsThisLoop = (int)revs - prevRevs;
    
    //Note revs this loop for future calculations
    //prevRevs = revs;
    
    
    if(updated != true)
    {
       //updateTimeIndices(0.05);
       //updateTimeIndices( getPeriod((millis() - startTime), revsThisLoop) );
    }
    
    //Tests strip functionality by lighting up pixels in a novel fashion
    rainbowFlag(5);
    
    //mapToScreen(image);

  
}

void updateTimeIndices(double period)
{
    //Time taken to traverse arc that represents the screen width  
    double screenWidth = 0.312795 * period;
    for (i = 0; i < columnSize; i++)
    {
        if(i == 0)
            timeIndices[i] = 1000000 * ( (1 * screenWidth) / columnSize );
        else
            timeIndices[i] = 1000000 * ( (i * screenWidth) / columnSize );
    }
    
    updated = true;

}



double getPeriod(unsigned long loopTime, int noOfRevs)
{
   //Period is number of revs per loop / time taken per loop (s)
   return (double)noOfRevs / ((double)loopTime / 1000);
}

//
//void drawImage() //Draws a smiley face sprite
//{
//   for(i = 0; i <= columnSize; i++){
//        for(j = 0; j <= rowSize; j++)
//        {
//            switch(i)
//            {
//              case 5:
//              case 20:
//                if(j >= 16 && j <=22)
//                  image[j][i] = b;
//                else
//                  image[j][i] = r;
//                break;
//               case 6:
//               case 19:
//                 if(j == 15 || j == 23)
//                   image[j][i] = b;
//                 else
//                   image[j][i] = r;
//                 break;
//               case 7:
//               case 18:
//                 if(j == 14 || j == 24)
//                   image[j][i] = b;
//                 else
//                   image[j][i] = r;
//                 break;
//               case 8:
//               case 17:
//                 if(j == 13 || j == 17 || j == 25)
//                   image[j][i] = b;
//                 else
//                   image[j][i] = r;
//                 break;
//               case 9:
//               case 16: 
//                 if(j == 13 || j == 16 || j == 21 || j == 22 || j == 25)
//                   image[j][i] =  b;
//                 else
//                   image[j][i] =  r; 
//                 break;
//               case 10:
//               case 15: 
//                 if(j == 12 || j == 15 || j == 21 || j == 22 || j == 26)
//                   image[j][i] = b;
//                 else 
//                   image[j][i] = r;
//                 break;
//               case 11:
//               case 12:
//               case 13:
//               case 14: 
//                 if(j == 12 || j == 14 || j == 26 )
//                   image[j][i] = b;
//                 else
//                   image[j][i] = r; 
//                 break;
//               default:
//                 image[j][i] = r;
//                 break;
//            }//switch
//        }//inner for
//   }//outer for
   
//}//draw image


void rainbowFlag(uint8_t wait)
{
   for (int i = 0; i <= 31; i++) // update strip once
  {
    if(i <= 5) //red
    {
      delay(wait);
      strip.setPixelColor(i, r);
      strip.show();
      delay(wait);
    }
    if(i > 5 && i <= 10) //orange
    {
      delay(wait);
      strip.setPixelColor(i, orange);
      strip.show();
      delay(wait);
    }
    if(i > 10 && i <=15) // yellow
    {
      delay(wait);
      strip.setPixelColor(i, yellow);
      strip.show();
      delay(wait);
    }
    if(i > 15 && i <=20) // green
    {
      delay(wait);
      strip.setPixelColor(i, green);
      strip.show();
      delay(wait);
    }
    if(i > 20 && i <=25) // blue
    {
      delay(wait);
      strip.setPixelColor(i, b);
      strip.show();
      delay(wait);
    }
    if(i > 25 && i <=31) //purple
    {
      delay(wait);
      strip.setPixelColor(i, purple);
      strip.show();
      delay(wait);
    }
    
  }//strip updated 
}

Thanks in advance