I'm doing a project where I want to record IMU (Inertial Measurement Unit) readings. I want to use pretty high sampling frequency and I'm using Raspberry Pi Zero W to send PWM signal of 800Hz to control the sampling frequency. The Raspberry is connected to the sensor via SPI and logs data to SD card. First I thought that the data logging works just fine but I noticed that something doesn't add up. For example, I know that an event that I'm recording lasts quite accurately 4.5 seconds. However, the IMU readings suggest that the event lasts only 4.2 seconds. Thus, I'm missing some data. I added a time stamp every time when I collect data using Raspberry's clock_gettime -function. The time stamp revealed that about every second there is something happening, which messes up the data logging (figures below). I tried with different sampling frequencies (200-800Hz) but the same thing happened. I connected the Raspberry's PWM pin straight to a pin, which detects when the data is ready to be transferred (so I removed the sensor out of the circuit). Still about every second I miss some PWM signals. Then I generated a square signal from signal generator to ensure that the problem is not in the PWM signal that the Raspberry is generating. It is not.
So I'm asking if there is some background program running in Raspberry Pi that causes the delay or if somebody know why this is happening?
I attached a code and some plots about the time differences between samples with couple different sampling frequencies.
#include <bcm2835.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#define DR 24 //DR pin number
#define STALL 50 //delay microseconds to make sure that the code runs without problems
#define SYNC 13 //SYNC pin number(PWM)
#define PWM_CHANNEL 1 //Controlled by PWM channel 1
#define RANGE 6 //Max range of the PWM signal
#define CLOCK_DIVIDER 4000 //clock divider for PWM
int initialize(void){
if (!bcm2835_init()){
printf("bcm2835_init failed. Are you running as root??\n");
return -1;
}
bcm2835_gpio_fsel(DR, BCM2835_GPIO_FSEL_INPT); //setting DR as an input pin
bcm2835_gpio_fsel(13,BCM2835_GPIO_FSEL_ALT0 ); //Set the output pin to Alt Fun 0, to allow PWM channel 1 to be output there
bcm2835_pwm_set_clock(CLOCK_DIVIDER); // Set PWM clock divider 19.2 MHz / 4000 = 4800 Hz
bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1); // PWM channel, MARKSPACE mode, true
bcm2835_pwm_set_range(PWM_CHANNEL, RANGE); // 4800 Hz / RANGE (6) = 800 Hz
bcm2835_pwm_set_data(PWM_CHANNEL, RANGE/2); // Set pulse ratio to 50/50
return 0;
}
int main(int argc, char **argv){
int suc = initialize();
FILE *filePointer; // create pointer to a file
struct timespec ts; // time stamp for data
if (suc!=0){ //checking to see if the settings were successfully applied
printf("Reboot");
return -1;
}
else{
char fileName[64]; //filename space
printf("Please enter filename where you want to store the data\n"); // ask for the file name
scanf("%s",&fileName); // copy the text to filename
filePointer = fopen(("%s",fileName), "w"); // open the file
}
if (filePointer != NULL){
int i = 1;
while (i <= 8000){ // gather data for 10 seconds
if (bcm2835_gpio_lev(DR) == 1){ // detects if DR pin is high
clock_gettime(CLOCK_MONOTONIC_RAW, &ts); // storing time stamp
fprintf(filePointer, "%ld\t %ld\n", ts.tv_sec, ts.tv_nsec); // write the data to the file
i++;
while (bcm2835_gpio_lev(DR) == 1){
bcm2835_delayMicroseconds(1); // wait till DR pin is low
}
}
}
printf("\n");
fclose(filePointer); //close the file
bcm2835_spi_end(); //end spi mode on rpi
}
else{
printf("Error, file was not created correctly.");
}
return 0;
}