7 years, 8 months ago.

coding help: could not find out the error while printing from the buffer

Hello, I'm trying to print the senor readings from the bufeer. Values are perfect without buffer but errors with buffer. Somewhere I'm missing the logic.

Normal printing:

double readings[3] = {0, 0, 0};

accelerometer.getOutput(readings);
printf("\r\n %i ,%i,%i",(int16_t)readings[0], (int16_t)readings[1], (int16_t)readings[2]);

printing from buffer

#define bufferSize 512
double sensorReading[bufferSize];
unsigned int readPointer = 0;
volatile unsigned int writePointer = 0;

void onAccTick(void)
{
   accelerometer.getOutput(readings);
   sensorReading[writePointer++] = (int16_t)readings[0], (int16_t)readings[1], (int16_t)readings[2];
    if (writePointer == bufferSize)
        writePointer = 0;
    if (writePointer == readPointer) {
 
    }
}

main()
{
    pc.baud(115200);

while (true) {
 
        while (writePointer != readPointer) {
        pc.printf("\r\n %i ",sensorReading[readPointer++]);
            if (readPointer == bufferSize)
                readPointer = 0;
        }
 }
}

Thank you.

1 Answer

7 years, 8 months ago.

The reason for the gibberish is that your buffer is of type double but you are trying to display the data as if it's a signed 16 bit integer. Either change the %i to %f or move the cast to int16 to the printf rather than when you put the values in the buffer and you'll get meaningful numbers .

You will still only get the x value because you're adding 3 values to the buffer and then increasing the index by 1 so two of the values will be overwritten but at least it'll be the correct x value.

Also the variable readings is undefined.

You either need to write 3 values (which could then cause sync issues, if you get a buffer overflow and your buffer isn't a multiple of 3 long then your x,y & z axes will swap) or you need to make each buffer entry 3 values.

#define bufferSize 256

struct accelReadings {
  double x;
  double y;
  double x;
};
struct accelReadings sensorReading[bufferSize];
unsigned int readPointer = 0;
volatile unsigned int writePointer = 0;
 
void onAccTick(void)
{
   double readings[3];
   accelerometer.getOutput(readings);
   sensorReading[writePointer].x = readings[0];
   sensorReading[writePointer].y = readings[1];
   sensorReading[writePointer].z = readings[2];
   writePointer++;
    if (writePointer == bufferSize)
        writePointer = 0;
    if (writePointer == readPointer) {
 // overflow
    }
}

main()
{
    pc.baud(115200);
 
while (true) {
 
        while (writePointer != readPointer) {
        pc.printf("\r\n %f %f %f ",sensorReading[readPointer].x,sensorReading[readPointer].y,sensorReading[readPointer].z);
        readPointer++;
            if (readPointer == bufferSize)
                readPointer = 0;
        }
 }
}

Accepted Answer

Thank you Andy. An extension to above topic. I would like to tick "onAccTick "@800 times in a second. Unfortunately i could only tick upto 250 times.i.e

AccTick.attach(&onAccTick,0.004);

If i incease it to 0.00125 i.e. 800 my program hangs up. I hope if statement making the delay. Do we have another alternative for if statement

if (writePointer == bufferSize)
        writePointer = 0;
    if (writePointer == readPointer) {
 // overflow
    }

thank you.

posted by Mohan gandhi Vinnakota 12 Jul 2016

What does accelerometer.getOutput(readings) do? Does it need to return doubles? They are very slow, if you can use floats or even better integers then that will be a massive speed up.

Also sensorReading[writePointer].x = readings[0]; sensorReading[writePointer].y = readings[1]; sensorReading[writePointer].z = readings[2]; will take at least 6 memory reads and writes, if get output put the data directly into the buffer that would speed things up.

Those if statements are the fastest parts of that function, they will only take one or two clock cycles. An int16 or int32 calculation will be a couple of clock cycles, a floating point calculation takes over 100 clock cycles, a double takes over 200.

posted by Andy A 12 Jul 2016

OK, I looked up the accelerometer you are using. It outputs 16 bit integers not doubles. In other words your "working" code shouldn't have worked and was only working because c lets you get away with things that are wrong on the assumption you know what you're doing.

struct accelReadings {
  int16_t x;
  int16_t y;
  int16_t z;
};

struct accelReadings sensorReading[bufferSize];
unsigned int readPointer = 0;
volatile unsigned int writePointer = 0;
 
void onAccTick(void)
{
   accelerometer.getOutput((char *) (sensorReading+writePointer));
   writePointer++;
    if (writePointer == bufferSize)
        writePointer = 0;
    if (writePointer == readPointer) {
 // overflow
    }
}
 
main()
{
    pc.baud(115200);
 
while (true) {
 
        while (writePointer != readPointer) {
        pc.printf("\r\n %i %i %i ",sensorReading[readPointer].x,sensorReading[readPointer].y,sensorReading[readPointer].z);
        readPointer++;
            if (readPointer == bufferSize)
                readPointer = 0;
        }
 }
}
posted by Andy A 12 Jul 2016

Yes this worked @800HZ. Initially my plan was storing all the sensors data to buffer and then to SD card. That is the reason I converted 3-axis sensor to double i.e. high precision. Later on I changed my view. Buffer using only for 3-axis and all other sensors printing directly to SD card as all other sensors running @1HZ. That seems OK.

A new problem is that in place of pc.printf I used fprintf to print to the SD card but program hangs up. Also above program is printing evrey new data coming to buffer rather printing whole buffer at a time.

I have modified whole code as below.

void onAccTick(void)
{
   int readings[3];
   accelerometer.getOutput(readings);
   sensorReading[writePointer].x = readings[0];
   sensorReading[writePointer].y = readings[1];
   sensorReading[writePointer].z = readings[2];
   writePointer++;
    if (writePointer == bufferSize)
        writePointer = 0;
       bufferfull = 0;
    if (writePointer == readPointer) {
 // overflow
    }
}

Above I have used

 bufferfull = 0;

This is used to know when the buffer is full. I used this one in while loop as below

while (true) {
 
       //while (writePointer != readPointer) {
         while (bufferfull == 0) {
   
        fprintf(logFile,"\r\n %i %i %i ",sensorReading[readPointer].x,sensorReading[readPointer].y,sensorReading[readPointer].z);
        readPointer++;
            if (readPointer == bufferSize)
                readPointer = 0;
        }     
 }

Output is fine when i run 3-axis @100HZ or more than 100HZ. But there are more zeros in first log file.

Up to here is also fine.

As per my requirement I need to run the logger after a button press and stop after another button press. Then I placed all tickers in button press function .Here unfortunately logger hangs up. Logger works when i comment out accelerometer ticker.

 void eventFunction() {
    if(!isPressed) {
   
   fileUpdate.attach(&onFileUpdate,20); // every 10 minute switch to a new log file.
   AccTick.attach(&onAccTick,0.01);
   TempTick.attach(&onTempTick,1);
   BaroTick.attach(&onBaroTick,1);
   LuxTick.attach(&onLuxTick,1);
   rtcTick.attach(&onrtcTick,1);
   LedTick.attach(&onLedTick,3);
   isPressed=1;
    } else {
       fileUpdate.detach();
       AccTick.detach();
       TempTick.detach();
       BaroTick.detach();
       LuxTick.detach();
       rtcTick.detach();
       LedTick.detach();
       isPressed=0;
        }
    }

storing to SD card using tickers is OK. But placing that ticker in another interrupt making the problem.

My whole program flow is below:

#include "mbed.h"
#include "ADXL345.h"
#include "SDFileSystem.h"
#include "SHT21_ncleee.h"
#include "ms5611.h"
#include "MAX44009.h"
#include "RTC8564.h"
 

ADXL345 accelerometer(PC_3,PC_2,D6,D7);
SDFileSystem sd(D11,D12,D13,D10, "sd"); // MOSI, MISO, SCLK, SSEL
ms5611 ms(D14, D15, ms5611::CSBpin_1);
I2C i2c(D14,D15);
MAX44009 max44009(&i2c, MAX_ADDR);
SHT21 sht(&i2c);
RTC8564     rtc8564(i2c);
DigitalOut led1(PA_13);
InterruptIn button(PC_8);

Ticker AccTick;
Ticker TempTick;
Ticker BaroTick;
Ticker LuxTick;
Ticker rtcTick;
Ticker LedTick;
FILE *logFile = NULL;
Ticker fileUpdate;
tm t;
time_t seconds;
char buf[40];

int isPressed;

Serial pc(D8,D2); 


#define bufferSize 256
 
//int16_t sensorReading[bufferSize];
unsigned int readPointer = 0;
volatile unsigned int writePointer = 0;
int bufferfull;

 struct accelReadings {
  int16_t x;
  int16_t y;
  int16_t z;
};
struct accelReadings sensorReading[bufferSize];
void onFileUpdate(void) 
    {    
        static int fileNumber = 0;
        if (logFile)
        fclose(logFile);
        char fileName[20];
        sprintf(fileName,"/sd/PCE-DL%03d.txt",fileNumber++);
        logFile = fopen(fileName,"w");
    }
    void onrtcTick(void)
 {  
    seconds = mktime(&t);
    rtc8564.get_time_rtc(&t);   // read RTC data
    strftime(buf, 40, "%I:%M:%S %p (%Y/%m/%d)", localtime(&seconds)); 
    fprintf(logFile,"\r\n %s", buf);
 } 
 
void onAccTick(void)
{
   int readings[3];
   accelerometer.getOutput(readings);
   sensorReading[writePointer].x = readings[0];
   sensorReading[writePointer].y = readings[1];
   sensorReading[writePointer].z = readings[2];
   writePointer++;
    if (writePointer == bufferSize)
        writePointer = 0;
       bufferfull = 0;
    if (writePointer == readPointer) {
 // overflow
    }
}

void onTempTick(void)
{
 float temperature = sht.readTemp();
 float humidity = sht.readHumidity();
 fprintf(logFile,"\r\n[%3.2f C ]",temperature);
 fprintf(logFile,"\r\n[%3.2f RH] \r\n\n", humidity);
 }
 void onBaroTick(void)
 {
      double Press = ms.calcPressure(); 
      fprintf(logFile,"\r\n%.1f mB ", Press);
 }
 
 void onLuxTick() {
 float LUX = max44009.getLUXReading();
 fprintf(logFile,"\r\n%f  ",LUX);
 
} 
 void onLedTick(void)
 {  
    led1 = 1;
    wait(0.5);
    led1 = 0;
 } 
 
 void eventFunction() {
    if(!isPressed) {
   
   fileUpdate.attach(&onFileUpdate,20); // every 10 minute switch to a new log file.
   TempTick.attach(&onTempTick,1);
   BaroTick.attach(&onBaroTick,1);
   LuxTick.attach(&onLuxTick,1);
   rtcTick.attach(&onrtcTick,1);
   LedTick.attach(&onLedTick,3);
   isPressed=1;
    } else {
       fileUpdate.detach();
       AccTick.detach();
       TempTick.detach();
       BaroTick.detach();
       LuxTick.detach();
       rtcTick.detach();
       LedTick.detach();
       isPressed=0;
        }
    }
 
int main()
{
    pc.baud(921600);
     pc.printf("Starting ADXL345 test...\n");
    pc.printf("Device ID is: 0x%02x\n", accelerometer.getDevId());

    //Go into standby mode to configure the device.
    accelerometer.setPowerControl(0x00);

    //Full resolution, +/-16g, 4mg/LSB.
    accelerometer.setDataFormatControl(0x0B);
    
    //3.2kHz data rate.
    accelerometer.setDataRate(ADXL345_800HZ);

    //Measurement mode.
    accelerometer.setPowerControl(0x08);
   onFileUpdate(); // open the first log file; 
   isPressed=0;
   button.rise(&eventFunction);
   //AccTick.attach(&onAccTick,0.01);
     
   
while (true) {
 
       //while (writePointer != readPointer) {
         while (bufferfull == 0) {
       // pc.printf("\r\n %i %i %i ",sensorReading[readPointer].x,sensorReading[readPointer].y,sensorReading[readPointer].z);
        fprintf(logFile,"\r\n %i %i %i ",sensorReading[readPointer].x,sensorReading[readPointer].y,sensorReading[readPointer].z);
       // pc.printf("\r\n %3.2f %3.2f %3.2f ",sensorReading[readPointer++],sensorReading[readPointer++],sensorReading[readPointer++]);
        readPointer++;
            if (readPointer == bufferSize)
                readPointer = 0;
        }     
 }
}

   

what is the solution to print accelerometer and all other sensors after a button press.

posted by Mohan gandhi Vinnakota 12 Jul 2016

I don't have time to fix all the problems with that code but here's the obvious problems with the first section:

void onAccTick(void)
{
   int readings[3]; 
   accelerometer.getOutput(readings);  // WRONG. GetOutput assumes 16 bit ints, int will probably default to 32 bit
   sensorReading[writePointer].x = readings[0]; // Why are you doing this when having getOutput write directly to the buffer is faster?
   sensorReading[writePointer].y = readings[1];
   sensorReading[writePointer].z = readings[2];
   writePointer++;
    if (writePointer == bufferSize)
        writePointer = 0;
       bufferfull = 0; // This is set to 0 every time the ticker is called.I can't see it ever being set to any other values.
    if (writePointer == readPointer) {
 // overflow
    }
}

And I have no idea why you want to wait until the buffer is full before writing to the SD card. If you do that you will get a buffer overflow unless you can write your entire buffer in less than one sample period. You write data as soon and as fast as you can and let the file system handle grouping things into blocks.

posted by Andy A 12 Jul 2016

Dear Andy,

void onAccTick(void)
{
  accelerometer.getOutput((int16_t *) (sensorReading+writePointer));
   writePointer++;
    if (writePointer == bufferSize)
        writePointer = 0;
    if (writePointer == readPointer) {
 // overflow
    } 
}

this is working fine now. Also could able to print on SD card. Now I'm failed to start logger after button press. I try to keep all these tickers inside a button press function.

int main()
{
    pc.baud(115200);
    pc.printf("\r\n Starting ADXL345 test...");
    wait(.001);
    pc.printf("\r\n Device ID is: 0x%02x", accelerometer.getDevId());
    wait(.001);
    
    accelerometer.setPowerControl(0x00);
    wait(.001);
    accelerometer.setDataFormatControl(0x0B);
    wait(.001);
    accelerometer.setDataRate(0x0F);
    wait(.001);
    accelerometer.setPowerControl(0x08);
    wait(.001);
    
   onFileUpdate(); // open the first log file; 
   isPressed=0;
   button.rise(&eventFunction);
    
while (true) {
 
       while (writePointer != readPointer) {
        fprintf(logFile,"\r\n %i %i %i ",sensorReading[readPointer].x,sensorReading[readPointer].y,sensorReading[readPointer].z);
        readPointer++;
            if (readPointer == bufferSize)
                readPointer = 0;
        }
 }
}

void eventFunction() {
    if(!isPressed) {
   fileUpdate.attach(&onFileUpdate,20); // every 10 minute switch to a new log file.
   AccTick.attach(&onAccTick,1);
   isPressed=1;
    } else {
       fileUpdate.detach();
       AccTick.detach();
       isPressed=0;
        }
    } 

This Acc ticker in void eventFunction(); making system hang. When I comment out ACCTicker then program works. What is the problem? Thank you.

posted by Mohan gandhi Vinnakota 13 Jul 2016

Is attaching the AccTick ticker causing the crash or is it crashing when it writes to the file?

Attaching the ticker isn't going to cause a crash, the code in the ticker or something that is triggered as a result of the ticker running could well cause a crash.

I don't see any point where you are checking that the file opened correctly, if it failed to open the log file you would get this crash.

Check the output file is open and if that doesn't fix it then add some debugging output to the serial port to figure out where it is crashing.

You also need to close the log file when you stop logging, currently the old log file is only closed when you start a new one.

posted by Andy A 13 Jul 2016