Okay, so here's my full code - sorry, I'm still using binary at the moment. The device isn't connected to the O2 sensor yet, so I'm expecting a fault code on the serial monitor.
/*
This code segment is written to test functionality of the CJ125 O2 interface hardware
It is not intended to be used as working code, ONLY for hardware testing purposes
as there are multiple routes into a never ending such as a fault flag print for example
Notes:
- use PID gains of Kp = 80, Ki = 25 for LSU 4.2
- DIAG_REG = 0x78 = 01111000
- IDENT_REG = 0x48 = 01001000
- INIT_REG1 RD = 0x6C = 01101100
- INIT_REG1 WR = 0x56 = 01010110
- INIT_REG2 RD = 0x7E = 01111110
- INIT_REG2 WR = 0x5A = 01011010
TODO
*/
#include <PID_v1.h>
#include <SPI.h>
#include <EEPROM.h>
#include <EEPROMAnything.h>
// define constants that won't change, such as assigning names to pin numbers
const int UR_pin = A0;
const int UA_pin = A1;
const int heater_pin = 3;
const byte chip_select = 10;
// define sampling timers
unsigned long fault_current_millis = 0;
unsigned long fault_previous_millis = 0;
unsigned long fault_interval_millis = 2000;
unsigned long pumpprint_current_millis = 0;
unsigned long pumpprint_previous_millis = 0;
unsigned long pumpprint_interval_millis = 100;
// define variables that will change
double UR_c = 0;
double UA_c = 0;
double UR_m = 0;
double UA_m = 0;
double heater_duty = 0;
int cold_threshold = 990;
double IP = 0;
boolean fault = false;
boolean cold_start = false;
byte ident_reg_contents = B00000000;
byte diag_reg_contents = B00000000;
PID heater_PID(&UR_m, &heater_duty, &UR_c, 80, 25, 0, DIRECT);
void setup()
{
Serial.begin(9600);
// assign pinModes - only outputs need to be set, defaults are input
pinMode(chip_select, OUTPUT);
digitalWrite(chip_select, HIGH); // set CS high, as CS is active low
pinMode(heater_pin, OUTPUT);
// initialise SPI bus
SPI.begin();
SPI.setBitOrder(MSBFIRST); // sets SPI data transfer to MSB first
SPI.setDataMode(SPI_MODE1); // sets SPI mode to MODE1
SPI.setClockDivider(SPI_CLOCK_DIV8); // sets shared clock rate to 16Mhz / 8 = 2Mhz
/*read calibration values from EEPROM to allow heater PID and pump current
calculations to function without recalibration or from hot start */
UR_c = EEPROM_readAnything(0, UR_c);
UA_c = EEPROM_readAnything(8, UA_c);
// select chip
digitalWrite(chip_select, LOW);
// identify CJ125
SPI.transfer(B01001000);
ident_reg_contents = SPI.transfer(B00000000);
if (ident_reg_contents != B00000000)
{
Serial.println("");
Serial.println("SPI comms successful!");
Serial.println("");
Serial.print("CJ125 Device ID - ");
Serial.print(ident_reg_contents);
}
else
Serial.println("SPI comms failed!");
Serial.print(ident_reg_contents);
// enable diagnostics and set reference pump current
SPI.transfer(B01011010);
SPI.transfer(B00010010);
// read diagnoses registers
SPI.transfer(B01111000);
diag_reg_contents = SPI.transfer(B00000000);
// is there a fault? set fault boolean and print to serial
if (diag_reg_contents != B11111111)
{
fault = true;
}
// deselect chip
digitalWrite(chip_select, HIGH);
// check probe temperature, set cold start boolean
UR_m = analogRead(UR_pin);
if (UR_m >= cold_threshold)
{
cold_start = true;
}
// enable heater PID, define sample time and set output limits
heater_PID.SetMode(AUTOMATIC);
heater_PID.SetSampleTime(100);
heater_PID.SetOutputLimits(0, 255);
}
void probe_warmup()
{
// heat up probe (assumes 20degC cold start, ramps from 8v effective duty at 0.4v/s to 100% duty. ~ 15sec)
Serial.println("Probe Heating");
for (heater_duty = 145; heater_duty <= 255; heater_duty++)
{
analogWrite(heater_pin, heater_duty);
delay(138);
}
Serial.println("Probe Heat Complete");
// set cold start flag to false
cold_start = false;
}
void loop()
{
if (fault == false && cold_start == true)
{
// enter calibration mode
SPI.transfer(B01010110); // INIT_REG1 WR
SPI.transfer(B00010100); // sets RA & LA to 1
// sample calibration values of UR & UA
UR_c = analogRead(UR_pin);
UR_c = map(UR_c, 0, 5, 0, 255);
UA_c = analogRead(UA_pin);
UA_c = map(UA_c, 0, 5, 0, 255);
// save UR_c & UA_c to EEPROM (flash in actual board, EEPROM for test)
EEPROM_writeAnything(0, UR_c);
EEPROM_writeAnything(8, UA_c);
// warm up probe
probe_warmup();
// enter measurement mode - LA bit controls pump current offset cal, PA controls whether pump current can flow
SPI.transfer(B01010110); // INIT_REG1 WR
SPI.transfer(B00000000); // sets RA & LA to 0
}
else if (fault == false)
{
// run loop code here to update heater PID and calculate pump current periodically
UR_m = analogRead(UR_pin);
UR_m = map(UR_m, 0, 5, 0, 255);
heater_PID.Compute();
analogWrite(3, heater_duty);
UA_m = analogRead(UA_pin);
UA_m = map(UA_m, 0, 5, 0, 255);
unsigned long pumpprint_current_millis = millis();
if (pumpprint_current_millis - pumpprint_previous_millis > pumpprint_interval_millis)
{
pumpprint_previous_millis = pumpprint_current_millis;
IP = (UA_m - UA_c) / (8 * 61.9); // check this will actually conform BODMAS style
Serial.print("Pump Current = ");
Serial.print(IP);
Serial.println("");
}
}
else
{
// print fault flag to serial every 2 sec
unsigned long fault_current_millis = millis();
if (fault_current_millis - fault_previous_millis > fault_interval_millis)
{
fault_previous_millis = fault_current_millis;
Serial.println("");
Serial.print("Fault Code = ");
Serial.print(diag_reg_contents);
}
}
}
...and here's what I get on the serial monitor.
SPI comms successful!
CJ125 Device ID - 9999
Fault Code = 0
Fault Code = 0
So, it looks like it is working, sort of - however, is looks like there is a problem printing binary bytes to the serial monitor? Do I have to do some conversion here?
I am expecting the identity to be 01100xxx, where xxx are unknown to me yet. I'm also expecting an 8 bit number for the diagnosis register.