I am using the RPi to continuously acquire voltage data from an external ADC. I am using MCP3201 ADC (12 bit, 10k SPS) in a bit banging approach to get voltage data to Raspberry Pi and write it to a USB disk. Unfortunately the data acquired has unaccounted gaps in it.
I am unable to figure out the reasons for this. Any ideas? We need to have a continuous data acquisition to happen.
The power supplied to the RPi is through a 230V AC to 5V DC adapter with decent filtering.
Here's the code script used to get the data
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include <fcntl.h> // open
#include <inttypes.h> // uint8_t, etc
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <linux/i2c-dev.h>
#include <asm-generic/errno-base.h>
#include <wiringPi.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
#define GPSET0 7
#define GPSET1 8
#define GPCLR0 10
#define GPCLR1 11
#define GPLEV0 13
#define GPLEV1 14
#define GPPUD 37
#define GPPUDCLK0 38
#define GPPUDCLK1 39
unsigned piModel;
unsigned piRev;
static volatile uint32_t *gpioReg = MAP_FAILED;
#define PI_BANK (gpio>>5)
#define PI_BIT (1<<(gpio&0x1F))
/* gpio modes. */
#define PI_INPUT 0
#define PI_OUTPUT 1
#define PI_ALT0 4
#define PI_ALT1 5
#define PI_ALT2 6
#define PI_ALT3 7
#define PI_ALT4 3
#define PI_ALT5 2
void gpioSetMode(unsigned gpio, unsigned mode)
{
int reg, shift;
reg = gpio/10;
shift = (gpio%10) * 3;
gpioReg[reg] = (gpioReg[reg] & ~(7<<shift)) | (mode<<shift);
}
int gpioGetMode(unsigned gpio)
{
int reg, shift;
reg = gpio/10;
shift = (gpio%10) * 3;
return (*(gpioReg + reg) >> shift) & 7;
}
/* Values for pull-ups/downs off, pull-down and pull-up. */
#define PI_PUD_OFF 0
#define PI_PUD_DOWN 1
#define PI_PUD_UP 2
void gpioSetPullUpDown(unsigned gpio, unsigned pud)
{
*(gpioReg + GPPUD) = pud;
usleep(20);
*(gpioReg + GPPUDCLK0 + PI_BANK) = PI_BIT;
usleep(20);
*(gpioReg + GPPUD) = 0;
*(gpioReg + GPPUDCLK0 + PI_BANK) = 0;
}
int gpioRead(unsigned gpio)
{
if ((*(gpioReg + GPLEV0 + PI_BANK) & PI_BIT) != 0) return 1;
else return 0;
}
void gpioWrite(unsigned gpio, unsigned level)
{
if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
}
void gpioTrigger(unsigned gpio, unsigned pulseLen, unsigned level)
{
if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
usleep(pulseLen);
if (level != 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
}
/* Bit (1<<x) will be set if gpio x is high. */
uint32_t gpioReadBank1(void) { return (*(gpioReg + GPLEV0)); }
uint32_t gpioReadBank2(void) { return (*(gpioReg + GPLEV1)); }
/* To clear gpio x bit or in (1<<x). */
void gpioClearBank1(uint32_t bits) { *(gpioReg + GPCLR0) = bits; }
void gpioClearBank2(uint32_t bits) { *(gpioReg + GPCLR1) = bits; }
/* To set gpio x bit or in (1<<x). */
void gpioSetBank1(uint32_t bits) { *(gpioReg + GPSET0) = bits; }
void gpioSetBank2(uint32_t bits) { *(gpioReg + GPSET1) = bits; }
unsigned gpioHardwareRevision(void)
{
static unsigned rev = 0;
FILE * filp;
char buf[512];
char term;
int chars=4; /* number of chars in revision string */
if (rev) return rev;
piModel = 0;
filp = fopen ("/proc/cpuinfo", "r");
if (filp != NULL)
{
while (fgets(buf, sizeof(buf), filp) != NULL)
{
if (piModel == 0)
{
if (!strncasecmp("model name", buf, 10))
{
if (strstr (buf, "ARMv6") != NULL)
{
piModel = 1;
chars = 4;
}
else if (strstr (buf, "ARMv7") != NULL)
{
piModel = 2;
chars = 6;
}
}
}
if (!strncasecmp("revision", buf, 8))
{
if (sscanf(buf+strlen(buf)-(chars+1),
"%x%c", &rev, &term) == 2)
{
if (term != '\n') rev = 0;
}
}
}
fclose(filp);
}
return rev;
}
int gpioInitialise(void)
{
int fd;
piRev = gpioHardwareRevision(); /* sets piModel and piRev */
fd = open("/dev/gpiomem", O_RDWR | O_SYNC) ;
if (fd < 0)
{
fprintf(stderr, "failed to open /dev/gpiomem\n");
return -1;
}
gpioReg = (uint32_t *)mmap(NULL, 0xB4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
if (gpioReg == MAP_FAILED)
{
fprintf(stderr, "Bad, mmap failed\n");
return -1;
}
return 0;
}
int main()
{
FILE * DataFile;
FILE * TESTDEVFILE1;
uint32_t TimerValUSec = micros(); // Store the time elapsed (in u sec) from the beginning of the program execution. Max Val of 71 min
time_t rawtime;
struct tm * timeinfo;
int16_t val; // Stores the 16 bit value of our ADC conversion
int i;
int j;
int fd;
int USBAvl;
int USBRem;
int StatSDA1;
int StatSDB1;
int StatSDC1;
int I2CFile;
int Idx = 0;
int Count = 0;
int ADS_address = 0x48; // Address of our device on the I2C bus
int ADCAmpCoded;
int ADCVoltCoded;
char SrcPath[100];
char FileName[100];
char DestPath[100];
char FileCpyStr[100];
char FileDelStr[100];
if (gpioInitialise() < 0) return 1;
/* Pin connection for interfacing (GPIO numbers are in BCM format)
# Clock : GPIO4 : Output
# Data : GPIO17 : Input
# Chip select (V) : GPIO27 : Output
# Chip select (I) : GPIO22 : Output
# Red LED : GPIO23 : Output
# Green LED : GPIO24 : Output
*/
/* Configure the output pins */
gpioSetMode( 4, 1);
gpioSetMode(27, 1);
gpioSetMode(22, 1);
// gpioSetMode(18, 1);
gpioSetMode(23, 1);
gpioSetMode(24, 1);
/* Configure the input pins */
gpioSetMode(17, 0);
gpioWrite(27, 1); // Set CS to HIGH to disable the ADC for voltage
gpioWrite(22, 1); // Set CS to HIGH to disable the ADC for current
gpioWrite( 4, 1); // Set the clock pin to HIGH
strcpy (SrcPath, "cp --no-preserve=mode,ownership ");
strcpy (DestPath," /mnt/usb1/"); // Location to mount the detected USB device
while (1)
{
Idx = 0;
USBAvl = 0;
USBRem = 0;
printf("\n Searching for device ");
printf("...");
while (USBAvl == 0)
{
/* Search for SDA1, SDB1 and SDC1 in root/dev. If found then exit this loop */
/* Check if SDA1 file is detected in device directory */
fd = open("/dev/sda1", O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0)
{
if (errno == EEXIST)
{ system("sudo mount -t vfat -o uid=pi,gid=pi /dev/sda1 /mnt/usb1/"); USBAvl = 1;}
}
/* Check if SDB1 file is detected in device directory */
fd = open("/dev/sdb1", O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0)
{
if (errno == EEXIST)
{ system("sudo mount -t vfat -o uid=pi,gid=pi /dev/sdb1 /mnt/usb1/"); USBAvl = 1;}
}
/* Check if SDC1 file is detected in device directory */
fd = open("/dev/sdc1", O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0)
{
if (errno == EEXIST)
{ system("sudo mount -t vfat -o uid=pi,gid=pi /dev/sdc1 /mnt/usb1/"); USBAvl = 1;}
}
}
// New USB Installed
/* ########################## */
gpioWrite(23, 1); /* Set RED LED to indicate writing to USB has begun */
gpioWrite(24, 0); /* Reset GREEN LED to indicate writing to USB has begun */
while (Idx < 150) //Number of files
{
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(FileName,100 ,"/home/pi/C_Code/CurrentDataFile%Y%b%d_%H%M%S.txt",timeinfo);
strcpy(FileCpyStr, SrcPath);
strcat(FileCpyStr, FileName);
strcat(FileCpyStr, DestPath);
strcpy(FileDelStr, "rm ");
strcat(FileDelStr, FileName);
DataFile = fopen(FileName,"w"); // Open the data file which will store the data
Count = 0;
while(Count++ < 1000000) //Number of samples per file
{
gpioWrite(27, 0); // Set CS to LOW to enable the voltage ADC
ADCVoltCoded = 0;
for (i=0; i<15; i++)
{
gpioWrite(4, 0); // Bring clock to LOW
for (j=0;j<10;j++); // Delay to stabilize the charging value
gpioWrite(4, 1); // Bring clock to HIGH
for (j=0;j<10;j++); // Delay to stabilize the charging value
ADCVoltCoded = (ADCVoltCoded<<1)|(gpioRead(17));
}
gpioWrite(27, 1); // Set CS to HIGH to disable the voltage ADC
for (j=0;j<10;j++); // Delay to stabilize the charging value
gpioWrite(22, 0); // Set CS to LOW to enable the current ADC
ADCAmpCoded = 0;
for (i=0; i<15; i++)
{
gpioWrite(4, 0); // Bring clock to LOW
for (j=0;j<10;j++); // Delay to stabilize the charging value
gpioWrite(4, 1); // Bring clock to HIGH
for (j=0;j<10;j++); // Delay to stabilize the charging value
ADCAmpCoded = (ADCAmpCoded<<1)|(gpioRead(17));
}
gpioWrite(22, 1); // Set CS to HIGH to disable the current ADC
ADCVoltCoded = ADCVoltCoded & 0xFFF;
ADCAmpCoded = ADCAmpCoded & 0xFFF;
//printf ("\n Time : %d \t Voltage : %d \t Current : %d",TimerValUSec, ADCVoltCoded, ADCAmpCoded);
TimerValUSec = micros();
fprintf(DataFile, "\n %u , %d, %d", TimerValUSec, ADCVoltCoded, ADCAmpCoded);
for (j=0;j<6000;j++); //Dummy Loop to control samples per second which can be changed
}
fclose(DataFile);
system(FileCpyStr);
system(FileDelStr);
Idx++;
}
system(" sudo umount /mnt/usb1/");
gpioWrite(23, 0); // Switch Off RED : USB Writing Done
gpioWrite(24, 1); // Switch On Green : USB Full
// wait until usb is removed
printf("\n Device Full, please remove it...");
printf("\n");
while (USBRem == 0)
{
/* Check if SDA1 is present in device directory */
fd = open("/dev/sda1", O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
StatSDA1 = ((fd < 0) && (errno == EEXIST)) ? 1 : 0;
/* Check if SDB1 is present in device directory */
fd = open("/dev/sdb1", O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
StatSDB1 = ((fd < 0) && (errno == EEXIST)) ? 1 : 0;
/* Check if SDC1 is present in device directory */
fd = open("/dev/sdc1", O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
StatSDC1 = ((fd < 0) && (errno == EEXIST)) ? 1 : 0;
/* If none of SDA1, SDB1 or SDC1 is found, then exit the loop */
if ((StatSDA1 == 0) && (StatSDB1 == 0) && (StatSDC1 == 0))
{
USBRem = 1;
printf("\n Device removed successfully...");
}
}
printf("\n CONFIRMED");
}
return 0;
}