ArduinoSTM32 source code
ArduinoSTM32 source code
/*
SPI default pins:
MOSI - PA7 // DIN
MISO - PA6 // DOUT
SCK - PA5 // SCLK
SS - PA4 // CS
--------------------
MOSI: Master OUT Slave IN -> DIN
MISO: Master IN Slave OUT -> DOUT
--------------------
Other pins
RST - PA3
DRDY - PA2 // this is an interrupt pin
PDWN/SYNC - +3.3 V or PA1
*/
//--------------------------------------------------------------------------------
//Clock rate
/*
f_CLKIN = 7.68 MHz
tau = 130.2 ns
*/
//--------------------------------------------------------------------------------
void setup()
{
Serial.begin(115200);
delay(1000);
initialize_ADS1256();
delay(1000);
reset_ADS1256();
userDefaultRegisters();
//printInstructions();
attachInterrupt(digitalPinToInterrupt(PA2), checkDReady, FALLING); //FALLING -
DRDY goes low
}
//--------------------------------------------------------------------------------
//Variables
//Booleans
volatile boolean dataReady; //It is very important to have it defined as volatile!
double VREF = 2.50; //VREF for converting the raw data to human-readable voltage
//Pins
const byte CS_pin = PA4; //goes to CS on ADS1256
const byte DRDY_pin = PA2; //goes to DRDY on ADS1256
const byte RESET_pin = PA3; //goes to RST on ADS1256
//const byte PDWN_PIN = PA1; //Goes to the PDWN pin - Alternatively can be
permanently tied to 3.3 V
byte outputBuffer[3]; //3-byte (24-bit) buffer for the fast acquisition - Single-
channel, continuous
byte differentialBuffer[12]; //4x3-byte buffer for the fast differential-channel
acquisition -
byte singleBuffer[24]; //8x3-byte buffer for the fast single-ended-channel
acquisition
//float StartTime; //This only serves test purposes
//--------------------------------------------------------------------------------
void loop()
{
if (Serial.available() > 0)
{
char commandCharacter = Serial.read(); //we use characters (letters) for
controlling the switch-case
switch (commandCharacter) //based on the command character, we decide what to
do
{
case 'r': //this case is used to READ the value of a register
while (!Serial.available()); //wait for the serial
registerAddress = Serial.parseInt(); //parse the address of the register
/*
//Wait for the input
while (!Serial.available());
Text before the print
PrintMessage = "*Value of register " + String(registerAddress) + " is " +
String(readRegister(registerAddress));
Serial.println(PrintMessage);
PrintMessage = ""; //resetting value
*/
break;
case 't': //this case is used to print a message to the serial terminal. Just
to test the connection...etc.
Serial.println("*Test message triggered by serial command");
break;
case 'O': //this case is used to read a single value from the AD converter
readSingle();
break;
case 'A': //Single channel continous reading - MUX is manual, can be single
and differential too
readSingleContinuous();
break;
digitalWrite(CS_pin, LOW); //CS must stay LOW during the entire sequence [Ref:
P34, T24]
return registerValueR;
}
digitalWrite(CS_pin, LOW); //CS must stay LOW during the entire sequence [Ref:
P34, T24]
SPI.transfer(0x00);
SPI.transfer(registerValueW);
digitalWrite(CS_pin, HIGH);
SPI.endTransaction();
}
void reset_ADS1256()
{
SPI.beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); // initialize
SPI with clock, MSB first, SPI Mode1
digitalWrite(CS_pin, LOW);
delayMicroseconds(7);
SPI.transfer(0x0F); //Issue SDATAC (any 8-bit value would complete the RESET
command)
delayMicroseconds(100);
digitalWrite(CS_pin, HIGH);
SPI.endTransaction();
}
//DRDY
pinMode(DRDY_pin, INPUT);
//Reset
pinMode(RESET_pin, OUTPUT);
//We do a manual chip reset on the ADS1256 - Datasheet Page 27/ RESET
digitalWrite(RESET_pin, LOW);
delay(100);
digitalWrite(RESET_pin, HIGH); //RESET is set to high
delay(500);
SPI.begin();
}
void readSingle() //Reading a single value ONCE using the RDATA command
{
registerData = 0; // every time we call this function, this should be 0 in the
beginning!
SPI.beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1));
digitalWrite(CS_pin, LOW); //REF: P34: "CS must stay low during the entire
command sequence"
while (dataReady == false) {} //Wait until DRDY does low, then issue the command
SPI.transfer(B00000011); //Issue RDATAC (0000 0011) command after DRDY goes low
delayMicroseconds(7); //Wait t6 time (~6.51 us) REF: P34, FIG:30.
/*
//These variables only serve test purposes!
loopcounter++;
//if(micros() - StartTime >= 5000000) //5 s
if(loopcounter >= 150000)
{
Serial.print(" Loops: ");
Serial.println(loopcounter++);
Serial.println(micros() - StartTime);
break; //exit the whole thing
}
*/
}
SPI.transfer(B00001111); //SDATAC stops the RDATAC - the received 's' just breaks
the while(), this stops the acquisition
digitalWrite(CS_pin, HIGH); //We finished the command sequence, so we switch it
back to HIGH
SPI.endTransaction();
}
void cycleSingleEnded()
{
int cycle = 0;
SPI.beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1));
digitalWrite(CS_pin, LOW); //CS must stay LOW during the entire sequence [Ref:
P34, T24]
while (Serial.read() != 's')
{
for (cycle = 0; cycle < 8; cycle++)
{
//we cycle through all the 8 single-ended channels with the RDATAC
//INFO:
//RDATAC = B00000011
//SYNC = B11111100
//WAKEUP = B11111111
//---------------------------------------------------------------------------
------------------
/*Some comments regarding the cycling:
When we start the ADS1256, the preconfiguration already sets the MUX to
[AIN0+AINCOM].
When we start the RDATAC (this function), the default MUX ([AIN0+AINCOM])
will be included in the
cycling which means that the first readout will be the [AIN0+AINCOM]. But,
before we read the data
from the [AIN0+AINCOM], we have to switch to the next register already,
then start RDATA. This is
demonstrated in Figure 19 on Page 21.
\ CH1 | CH2 CH3 CH4 CH5 CH6 CH7 CH8 \ CH1 | CH2 CH3 ...
case 1: //Channel 3
SPI.transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
SPI.transfer(0x00);
SPI.transfer(B00101000); //AIN2+AINCOM
break;
case 2: //Channel 4
SPI.transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
SPI.transfer(0x00);
SPI.transfer(B00111000); //AIN3+AINCOM
break;
case 3: //Channel 5
SPI.transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
SPI.transfer(0x00);
SPI.transfer(B01001000); //AIN4+AINCOM
break;
case 4: //Channel 6
SPI.transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
SPI.transfer(0x00);
SPI.transfer(B01011000); //AIN5+AINCOM
break;
case 5: //Channel 7
SPI.transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
SPI.transfer(0x00);
SPI.transfer(B01101000); //AIN6+AINCOM
break;
case 6: //Channel 8
SPI.transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
SPI.transfer(0x00);
SPI.transfer(B01111000); //AIN7+AINCOM
break;
case 7: //Channel 1
SPI.transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
SPI.transfer(0x00);
SPI.transfer(B00001000); //AIN0+AINCOM
break;
}
//Step 2.
SPI.transfer(B11111100); //SYNC
delayMicroseconds(4); //t11 delay 24*tau = 3.125 us //delay should be larger,
so we delay by 4 us
SPI.transfer(B11111111); //WAKEUP
//Step 3.
//Issue RDATA (0000 0001) command
SPI.transfer(B00000001);
delayMicroseconds(7); //Wait t6 time (~6.51 us) REF: P34, FIG:30.
switch (cycle)
{
case 0: //Channel 2
SPI.transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
SPI.transfer(0x00);
SPI.transfer(B00100011); //AIN2+AIN3
break;
case 1: //Channel 3
SPI.transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
SPI.transfer(0x00);
SPI.transfer(B01000101); //AIN4+AIN5
break;
case 2: //Channel 4
SPI.transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
SPI.transfer(0x00);
SPI.transfer(B01100111); //AIN6+AIN7
break;
case 3: //Channel 1
SPI.transfer(0x50 | 1); // 0x50 = WREG //1 = MUX
SPI.transfer(0x00);
SPI.transfer(B00000001); //AIN0+AIN1
break;
}
SPI.transfer(B11111100); //SYNC
delayMicroseconds(4); //t11 delay 24*tau = 3.125 us //delay should be larger,
so we delay by 4 us
SPI.transfer(B11111111); //WAKEUP
//Step 3.
SPI.transfer(B00000001); //Issue RDATA (0000 0001) command
delayMicroseconds(7); //Wait t6 time (~6.51 us) REF: P34, FIG:30.
SPI.endTransaction();
}
void userDefaultRegisters()
{
// This function is "manually" updating the values of the registers then reads
them back.
// This function can be used in the setup() after performing an initialization-
reset process
/*
REG VAL USE
0 54 Status Register, Everyting Is Default, Except Auto - Cal
1 1 Multiplexer Register, AIN0 POS, AIN1 POS
2 0 ADCON, Everything is OFF, PGA = 0
3 132 DataRate = 100 SPS
*/
//We update the 4 registers that we are going to use
delay(500);
writeRegister(0x00, B00110110); //STATUS: bit1: bufen=1; bit2: acal=1; rest is
not important or factory default
delay(200);
writeRegister(0x01, B00000001); //MUX AIN0+AIN1
delay(200);
writeRegister(0x02, B00000000); //ADCON - PGA = 0 (+/- 5 V)
delay(200);
writeRegister(0x03, B10000100); //100SPS
delay(500);
sendDirectCommand(B11110000); //Offset and self-gain calibration
}
void printInstructions()
{
//This function should be in the setup() and it shows the commands - not used
PrintMessage = "*Use the following letters to send a command to the device:" +
String("\n")
+ "*r - Read a register. Example: 'r1' - reads the register 1" +
String("\n")
+ "*w - Write a register. Example: 'w1 8' - changes the value of
the 1st register to 8." + String("\n")
+ "*O - Single readout. Example: 'O' - Returns a single value from
the ADS1256." + String("\n")
+ "*A - Single, continuous reading with manual MUX setting." +
String("\n")
+ "*C - Cycling the ADS1256 Input multiplexer in single-ended mode
(8 channels). " + String("\n")
+ "*D - Cycling the ADS1256 Input multiplexer in differential mode
(4 channels). " + String("\n")
+ "*R - Reset ADS1256. Example: 'R' - Resets the device,
everything is set to default." + String("\n")
+ "*s - SDATAC: Stop Read Data Continously." + String("\n")
+ "*U - User Default Registers." + String("\n")
+ "*d - Send direct command.";
Serial.println(PrintMessage);
PrintMessage = ""; //Reset (empty) variable.
}