Arduino Uno aborts ChibiOS datalogger early

ChibiOS public support forum for topics related to the Atmel AVR family of micro-controllers.

Moderator: tfAteba

Post Reply
jmayse7501
Posts: 1
Joined: Wed Feb 25, 2015 4:31 pm

Arduino Uno aborts ChibiOS datalogger early

Post by jmayse7501 »

Hello all,

It's a long one, fair warning. Sorry in advance for those of you who read my code...

I recently adapted the chFIFODataLogger sketch for the Uno for a specific purpose of mine. I made some relatively minor changes and everything was working fine...until it wasn't. Last night, I changed the script so that, instead of logging the data from my sensors (using IR break beams) every few milliseconds, I would log data only whenever the state of my sensors changed. In other words, I wrote a little conditional to check if the state of any pin (I have 7 sensors) had changed from one sample to the next; if so, then write the data. This obviously saves a ton of space on my SD cards and makes the process a bit less cumbersome, but now I am having a weird problem. My code is pasted below and I'm also pasting the Serial monitor output. Right now, because my SD cards are in the mail, I am outputting the data to the Serial monitor instead of an SD card.

What is happening is this: I run the sketch, and everything works. For 77 records. The size of the buffer I am using is 50 records; it fills to 50, dumps the buffer, then fills to 27 - and starts over from the beginning. Here is what my Serial output looks like with some notation from me. For these samples I am literally wiggling the IR LED in front of a single sensor, tripping the beam on and off to test the code.

Serial monitor output:

5 (Minutes the code will run for)
Input mouse name (Prompt for user input)
Filename: E:\Dir\Dir\Mouse (Readout of user input)

Type Start to Start (Prompt for user input)
Delay, Sensor 1, Sensor 2, Sensor 3, Sensor 4, Sensor 5, Sensor 6, Sensor 7, Time, Error (Header)
2958948,0,0,0,1,0,0,0,2959,0 (Sensor readout - Delay between samples, value of Sensors 1-7, Timestamp in MS, and overrun error counter)
1 (Number of records in buffer - this is displayed only for debugging the current problem)
1136640,0,0,0,0,0,0,0,4096,0
2
5120,0,0,0,1,0,0,0,4101,0
3
2283520,0,0,0,0,0,0,0,6385,0
4
66560,0,0,0,1,0,0,0,6451,0
5
250880,0,0,0,0,0,0,0,6702,0
6
174080,0,0,0,1,0,0,0,6876,0
7
204800,0,0,0,0,0,0,0,7081,0
8
117760,0,0,0,1,0,0,0,7199,0
9
199680,0,0,0,0,0,0,0,7398,0
10
122884,0,0,0,1,0,0,0,7521,0
11
209920,0,0,0,0,0,0,0,7731,0
12
133116,0,0,0,1,0,0,0,7864,0
13
194560,0,0,0,0,0,0,0,8059,0
14
107520,0,0,0,1,0,0,0,8166,0
15
179204,0,0,0,0,0,0,0,8346,0
16
117756,0,0,0,1,0,0,0,8463,0
17
199684,0,0,0,0,0,0,0,8663,0
18
76796,0,0,0,1,0,0,0,8740,0
19
209920,0,0,0,0,0,0,0,8950,0
20
102400,0,0,0,1,0,0,0,9052,0
21
168960,0,0,0,0,0,0,0,9221,0
22
117760,0,0,0,1,0,0,0,9339,0
23
174084,0,0,0,0,0,0,0,9513,0
24
102396,0,0,0,1,0,0,0,9615,0
25
204800,0,0,0,0,0,0,0,9820,0
26
143360,0,0,0,1,0,0,0,9963,0
27
143364,0,0,0,0,0,0,0,10107,0
28
133116,0,0,0,1,0,0,0,10240,0
29
107520,0,0,0,0,0,0,0,10347,0
30
158720,0,0,0,1,0,0,0,10506,0
31
107520,0,0,0,0,0,0,0,10614,0
32
148480,0,0,0,1,0,0,0,10762,0
33
97280,0,0,0,0,0,0,0,10859,0
34
143364,0,0,0,1,0,0,0,11003,0
35
102396,0,0,0,0,0,0,0,11105,0
36
133124,0,0,0,1,0,0,0,11238,0
37
112636,0,0,0,0,0,0,0,11351,0
38
138240,0,0,0,1,0,0,0,11489,0
39
107520,0,0,0,0,0,0,0,11597,0
40
174084,0,0,0,1,0,0,0,11771,0
41
66560,0,0,0,0,0,0,0,11837,0
42
168960,0,0,0,1,0,0,0,12006,0
43
107520,0,0,0,0,0,0,0,12114,0
44
419836,0,0,0,1,0,0,0,12534,0
45
51200,0,0,0,0,0,0,0,12585,0
46
327680,0,0,0,1,0,0,0,12913,0
47
51200,0,0,0,0,0,0,0,12964,0
48
133120,0,0,0,1,0,0,0,13097,0
49 (Buffer is full)
76800,0,0,0,0,0,0,0,13174,0
0 (So start over)
230400,0,0,0,1,0,0,0,13404,0
1
128000,0,0,0,0,0,0,0,13532,0
2
163844,0,0,0,1,0,0,0,13696,0
3
87040,0,0,0,0,0,0,0,13783,0
4
102396,0,0,0,1,0,0,0,13885,0
5
66560,0,0,0,0,0,0,0,13952,0
6
839680,0,0,0,1,0,0,0,14792,0
7
97284,0,0,0,0,0,0,0,14889,0
8
143356,0,0,0,1,0,0,0,15032,0
9
578560,0,0,0,0,0,0,0,15611,0
10
15360,0,0,0,1,0,0,0,15626,0
11
199680,0,0,0,0,0,0,0,15826,0
12
51204,0,0,0,1,0,0,0,15877,0
13
204796,0,0,0,0,0,0,0,16082,0
14
61440,0,0,0,1,0,0,0,16143,0
15
363524,0,0,0,0,0,0,0,16507,0
16
61436,0,0,0,1,0,0,0,16568,0
17
122880,0,0,0,0,0,0,0,16691,0
18
40960,0,0,0,1,0,0,0,16732,0
19
143364,0,0,0,0,0,0,0,16875,0
20
20476,0,0,0,1,0,0,0,16896,0
21
143360,0,0,0,0,0,0,0,17039,0
22
40960,0,0,0,1,0,0,0,17080,0
23
133120,0,0,0,0,0,0,0,17213,0
24
66560,0,0,0,1,0,0,0,17280,0
25
117760,0,0,0,0,0,0,0,17398,0
26
97280,0,0,0,1,0,0,0,17495,0
27 (Buffer is NOT full)
102400,0,0,0, (So start over?)

I'm pretty perplexed, but I know it must be something simple I am missing...I have tried two different boards, and that is not the problem. I have tried increasing and decreasing the buffer size, baud rate, etc. and that has not solved it. Any input? I am quite new to ChibiOS and coding for Arduino's, so any input would be great...

Code:

Code: Select all

// Data logger based on a FIFO to decouple SD write latency from data
// acquisition timing.
//
// The FIFO uses two semaphores to synchronize between tasks.

#include <ChibiOS_AVR.h>
#include <SdFat.h>
//
// interval between points in units of 1024 usec
const uint16_t intervalTicks = 5;
String filename = "";
int startTime;
boolean timeIndex = true;
//5 minutes = 300000
//30 minutes = 1800000
#define runTime 300000 //Run time in milliseconds

//------------------------------------------------------------------------------
// SD file definitions
//const uint8_t sdChipSelect = SS;
//SdFat sd;
//SdFile file;
//------------------------------------------------------------------------------
// Fifo definitions

// size of fifo in records
const size_t FIFO_SIZE = 50;
// count of data records in fifo
SEMAPHORE_DECL(fifoData, 0);

// count of free buffers in fifo
SEMAPHORE_DECL(fifoSpace, FIFO_SIZE);

// data type for fifo item
struct FifoItem_t
{
  uint32_t usec;
  int IR1_value;
  int IR2_value;
  int IR3_value;
  int IR4_value;
  int IR5_value;
  int IR6_value;
  int IR7_value;
  boolean stateChange;
  int error;
};
#define IR1 4
#define IR2 5
#define IR3 6
#define IR4 7
#define IR5 8
#define IR6 9
#define IR7 10
// array of data items
FifoItem_t fifoArray[FIFO_SIZE];
//------------------------------------------------------------------------------
// Declare a stack with 32 bytes beyond task switch and interrupt needs.
static WORKING_AREA(waThread1, 32);

static msg_t Thread1(void *arg) {
  // index of record to be filled
  int previousState[7] = {0, 0, 0, 0, 0, 0, 0};
  size_t fifoHead = 0;
 
  //Initialize error counter
  int error = 0;
 
  while (1) {
    chThdSleep(intervalTicks);
    // get a buffer
   
    // NOTE: If I uncomment these lines, the code stays in this conditional indefinitely
    //    if (chSemWaitTimeout(&fifoSpace, TIME_IMMEDIATE) != RDY_OK) {
    //      // fifo full indicate missed point
    //      error++;
    //      continue;
    //    }
   
    FifoItem_t* p = &fifoArray[fifoHead];
    p->usec = micros();

    p->stateChange = false; // Default is no change occurred from previous sample
    // Read sensors
    p->IR1_value = digitalRead(IR1);
    p->IR2_value = digitalRead(IR2);
    p->IR3_value = digitalRead(IR3);
    p->IR4_value = digitalRead(IR4);
    p->IR5_value = digitalRead(IR5);
    p->IR6_value = digitalRead(IR6);
    p->IR7_value = digitalRead(IR7);
    // If any sensor's value has changed
    if (p->IR1_value != previousState[0] |
        p->IR2_value != previousState[1] |
        p->IR3_value != previousState[2] |
        p->IR4_value != previousState[3] |
        p->IR5_value != previousState[4] |
        p->IR6_value != previousState[5] |
        p->IR7_value != previousState[6])
    {
      p->stateChange = true; //Then there was a state change
    }
   
    //Store current sensor values as new previous state values
    previousState[0] = p->IR1_value;
    previousState[1] = p->IR2_value;
    previousState[2] = p->IR3_value;
    previousState[3] = p->IR4_value;
    previousState[4] = p->IR5_value;
    previousState[5] = p->IR6_value;
    previousState[6] = p->IR7_value;
   
    //If error, then count it
    p->error = error;
    error = 0;
   
    // If there was a state change
    if (p->stateChange == true)
    {
      // Then signal new data
      chSemSignal(&fifoData);

      // and advance FIFO index
      fifoHead = fifoHead < (FIFO_SIZE - 1) ? fifoHead + 1 : 0;
    }
  }
  return 0;
}
//------------------------------------------------------------------------------
void setup() {
  Serial.begin(115200); //115200 baud gives the fewer overrun errors at 2ms resolution; 57600 is ok for 5ms resolution
 
  //Define pins and set internal pull-down resistors - DO NOT CHANGE FROM HIGH STATE!!
  pinMode(IR1, INPUT);
  digitalWrite(IR1, HIGH);
  pinMode(IR2, INPUT);
  digitalWrite(IR2, HIGH);
  pinMode(IR3, INPUT);
  digitalWrite(IR3, HIGH);
  pinMode(IR4, INPUT);
  digitalWrite(IR4, HIGH);
  pinMode(IR5, INPUT);
  digitalWrite(IR5, HIGH);
  pinMode(IR6, INPUT);
  digitalWrite(IR6, HIGH);
  pinMode(IR7, INPUT);
  digitalWrite(IR7, HIGH);
 
  Serial.println(runTime/60000); //Show runTime in minutes
  String inData = ""; // String to hold input data.
  String inStart = ""; //String to hold input data
  // wait for USB Serial

  while (!Serial) // While serial is not ready.
  {
    ; // Waiting for serial to be ready.
  }

  Serial.println (F("Input mouse name")); //Prompt user for mouse ID

  int  breakIndex = 0; //Initialize index for line break
  // Read Mouse name from serial
  while (breakIndex == 0) //While the user has not entered /n
  {
    while (Serial.available () > 0) // (If)While there is data comming from the serial port...
    {
      int inChar = Serial.read (); // Read data from the serial port into inChar.
      inData += (char) inChar; // Concatenates the contents of inChar as char to the end of inData.
      delay (10); // Waits for 10 milliseconds between each byte read, so that we don't double read the incoming byte and allow the hardware some time to flush it.
      if ((char) inChar == '\n') // It the current read character is a new line...
      {
        Serial.print ("Filename: "); // Outputs "Echo: " to the Serial port, without a new line.
        filename = "E:\\Dir\\Dir\\" + inData; //Create filename (directory changed to Dir to mask my name!)
        Serial.println (filename); // Outputs the filename
        breakIndex = 1; //Exit while loop, we're done here
      }
    }
  }
  int inChar = -1;
 
  // I am testing this in the Serial monitor while waiting for my SD shield/cards to arrive in the mail...
  // open file
  //  if (!sd.begin(sdChipSelect)
  //    || !file.open(inData, O_CREAT | O_WRITE | O_TRUNC)) {
  //    Serial.println(F("SD problem"));
  //    sd.errorHalt();
  //  }
 
  Serial.println ("Type Start to Start"); //Prompt user for Start command
  breakIndex = 0; //Reset break index
  while (breakIndex == 0) //While the user has not entered the Start command
  {
    while (Serial.available () > 0) //While there is data in the Serial monitor
    {
      int inChar = Serial.read(); //Read the data
      inStart += (char) inChar; //Concatenate the array
      delay(10); //Wait for flush
      if (inStart == "Start") //If the user entered Start, then start the program
      {
        Serial.print("Delay");
        Serial.print(", ");
        Serial.print("Sensor 1");
        Serial.print(", ");
        Serial.print("Sensor 2");
        Serial.print(", ");
        Serial.print("Sensor 3");
        Serial.print(", ");
        Serial.print("Sensor 4");
        Serial.print(", ");
        Serial.print("Sensor 5");
        Serial.print(", ");
        Serial.print("Sensor 6");
        Serial.print(", ");
        Serial.print("Sensor 7");
        Serial.print(", ");
        Serial.print("Time");
        Serial.print(", ");
        Serial.println("Error");
        breakIndex = 1;
      }
    }
  }
  // start kernel
  // Now we have some critical info & the SD card is initialized, let's get started
  chBegin(mainThread);
  while (1);
}
//------------------------------------------------------------------------------
// main thread runs at NORMALPRIO
void mainThread() {
 
  // FIFO index for record to be written
  size_t fifoTail = 0;
 
  // time in micros of last point
  uint32_t last = 0; // Last time of sample
  uint32_t temp = 0; // Gotta love variables named "temp"
  bool overrunError = false; // Initialize overrun state as false

  // start producer thread
  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 1, Thread1, NULL);

  // start SD write loop
  if (timeIndex == true) //Capture immediate time to zero out run time clock
  {
    startTime = millis(); //Taking time here accounts for overhead in previous loops; this is out time 0
    //    runTime = (millis() - startTime) + runTime; //Adjust runTime for startTime - if we want 300000 milliseconds of runTime, then the appropriate runTime is 300000 + startTime
   
    timeIndex = false; //Don't enter this loop again
    temp = micros(); //More temp variables! This is used for the very first sampling time readout - just to make importing data easier later.
  }
  while ((millis() - startTime) < runTime) { //While we have not been running for the full run duration
    // wait for next data point
    chSemWait(&fifoData);

    FifoItem_t* p = &fifoArray[fifoTail];

    if (fifoTail >= FIFO_SIZE) fifoTail = 0;

    // print interval between points
    if (last) {
      Serial.print(p->usec - last);
    } else {
      Serial.print(micros() - temp);
    }
    last = p->usec;
    // Print sensor values
    Serial.write(',');
    Serial.print(p->IR1_value);
    Serial.write(',');
    Serial.print(p->IR2_value);
    Serial.write(',');
    Serial.print(p->IR3_value);
    Serial.write(',');
    Serial.print(p->IR4_value);
    Serial.write(',');
    Serial.print(p->IR5_value);
    Serial.write(',');
    Serial.print(p->IR6_value);
    Serial.write(',');
    Serial.print(p->IR7_value);
    Serial.write(',');
    Serial.print((millis() - startTime)); //Time in milliseconds
    Serial.write(',');
    Serial.println(p->error); //Print any errors

    // remember error
    if (p->error) overrunError = true;

    // release record
    chSemSignal(&fifoSpace);

    // advance FIFO index
    fifoTail = fifoTail < (FIFO_SIZE - 1) ? fifoTail + 1 : 0;
    Serial.println(fifoTail);
  }
  // close file, print stats and stop
  //  file.close();
  Serial.println(F("Done"));
  Serial.print(F("Thread1 unused stack: "));
  Serial.println(chUnusedStack(waThread1, sizeof(waThread1)));
  Serial.print(F("Heap/Main unused: "));
  Serial.println(chUnusedHeapMain());
  if (overrunError) {
    Serial.println();
    Serial.println(F("** overrun errors **"));
    while (1);
  }
}
//------------------------------------------------------------------------------
void loop() {
  // not used
}
Post Reply