Skip to content

Instantly share code, notes, and snippets.

@mvladic
Created January 22, 2017 00:07
Show Gist options
  • Save mvladic/a1646b103e838df03e1483e9dfaf724d to your computer and use it in GitHub Desktop.
Save mvladic/a1646b103e838df03e1483e9dfaf724d to your computer and use it in GitHub Desktop.
#include <SPI.h>
#include <stdlib.h>
////////////////////////////////////////////////////////////////////////////////
// BOARD
const uint8_t PWR_DIRECT = 55;
const uint8_t PWR_SSTART = 56;
const uint8_t WATCHDOG = 5;
const uint8_t BP_SELECT = 9;
const uint8_t BP_OE = 10;
const uint8_t RTC_SELECT = 8;
const uint8_t ETH_SELECT = 11;
const uint8_t LCD_CS = 39;
const uint8_t TOUCH_CS = 43;
void BOARD_setup() {
// disable WATCHDOG
pinMode(WATCHDOG, INPUT);
// Initialize serial communication
Serial.begin(9600);
// wait until the serial stream is not open
while (!Serial);
Serial.println("Serial com ready");
// Address issue with lack of proper SPI connection on PCB r1B9
pinMode(50, INPUT);
pinMode(51, INPUT);
pinMode(52, INPUT);
// BP setup
pinMode(BP_SELECT, OUTPUT);
pinMode(BP_OE, OUTPUT);
digitalWrite(BP_SELECT, HIGH); // Deselect TLC5925
digitalWrite(BP_OE, HIGH); // Deselect TLC5925 OE
// RTC setup
pinMode(RTC_SELECT, OUTPUT);
digitalWrite(RTC_SELECT, LOW); // Deselect PCA21125
// ETHERNET setup
pinMode(ETH_SELECT, OUTPUT);
digitalWrite(ETH_SELECT, HIGH); // Deselect ETHERNET
SPI.begin(); // wake up the SPI bus
// TFT
pinMode(LCD_CS, OUTPUT);
digitalWrite(LCD_CS, LOW); // deselect LCD
pinMode(TOUCH_CS, OUTPUT);
digitalWrite(TOUCH_CS, LOW); // deselect touch
// POWER on
pinMode(PWR_DIRECT, OUTPUT);
digitalWrite(PWR_DIRECT, LOW);
pinMode(PWR_SSTART, OUTPUT);
digitalWrite(PWR_SSTART, LOW);
digitalWrite(PWR_SSTART, HIGH);
delay(700);
digitalWrite(PWR_DIRECT, HIGH);
delay(100);
digitalWrite(PWR_SSTART, LOW);
}
////////////////////////////////////////////////////////////////////////////////
// FAN
#define FAN_SPEED 200
#define FAN_SPEED_MEASURMENT_INTERVAL 5000000L
#define FAN_NOMINAL_RPM 4500
const uint8_t FAN_PWM_PIN = 6;
const uint8_t FAN_SENSE_PIN = 13;
enum RpmMeasureState {
RPM_MEASURE_STATE_START,
RPM_MEASURE_STATE_MEASURE_T1,
RPM_MEASURE_STATE_MEASURE_T2,
RPM_MEASURE_STATE_MEASURED,
RPM_MEASURE_STATE_FINISHED
};
unsigned long FAN_usecLastMeasured;
volatile int FAN_rpm;
volatile unsigned long FAN_rpmMeasureT1;
volatile RpmMeasureState FAN_rpmMeasureState = RPM_MEASURE_STATE_FINISHED;
int FAN_intNum;
volatile unsigned long FAN_interruptCounter;
int FAN_dtToRpm(unsigned long dt) {
dt *= 2; // duty cycle is 50%
dt *= 2; // 2 impulse per revolution
return (int)(60L * 1000 * 1000 / dt);
}
void FAN_startMeasure() {
analogWrite(FAN_PWM_PIN, 255);
delay(2);
FAN_rpmMeasureState = RPM_MEASURE_STATE_START;
attachInterrupt(FAN_intNum, FAN_interruptHandler, CHANGE);
}
void FAN_interruptHandler() {
++FAN_interruptCounter;
if (FAN_rpmMeasureState != RPM_MEASURE_STATE_FINISHED && FAN_rpmMeasureState != RPM_MEASURE_STATE_MEASURED) {
// measure length of the square pulse
int x = digitalRead(FAN_SENSE_PIN);
if (FAN_rpmMeasureState == RPM_MEASURE_STATE_START && x) {
FAN_rpmMeasureState = RPM_MEASURE_STATE_MEASURE_T1;
} else if (FAN_rpmMeasureState == RPM_MEASURE_STATE_MEASURE_T1 && !x) {
// start is when signal goes from 1 to 0
FAN_rpmMeasureT1 = micros();
FAN_rpmMeasureState = RPM_MEASURE_STATE_MEASURE_T2;
} else if (FAN_rpmMeasureState == RPM_MEASURE_STATE_MEASURE_T2 && x) {
// stop is when signal goes from 0 to 1
unsigned long rpmMeasureT2 = micros();
int rpm = FAN_dtToRpm(rpmMeasureT2 - FAN_rpmMeasureT1);
if (rpm > (int)ceil(FAN_NOMINAL_RPM * 1.05)) {
// invalid RPM
} else {
FAN_rpm = rpm;
}
FAN_rpmMeasureState = RPM_MEASURE_STATE_MEASURED;
}
}
}
void FAN_finishMeasure() {
if (FAN_rpmMeasureState == RPM_MEASURE_STATE_MEASURED) {
analogWrite(FAN_PWM_PIN, FAN_SPEED);
FAN_rpmMeasureState = RPM_MEASURE_STATE_FINISHED;
detachInterrupt(FAN_intNum);
}
}
void FAN_setup() {
//
pinMode(FAN_PWM_PIN, OUTPUT);
pinMode(FAN_SENSE_PIN, INPUT);
//
FAN_intNum = digitalPinToInterrupt(FAN_SENSE_PIN);
// set FAN speed
analogWrite(FAN_PWM_PIN, FAN_SPEED);
}
void FAN_tick(unsigned long usec) {
if (usec - FAN_usecLastMeasured >= FAN_SPEED_MEASURMENT_INTERVAL) {
// start FAN speed measure every 5 seconds
FAN_usecLastMeasured = usec;
FAN_startMeasure();
} else {
// check measurement
RpmMeasureState rpmMeasureState = FAN_rpmMeasureState;
if (rpmMeasureState == RPM_MEASURE_STATE_MEASURED) {
// measurement finished
FAN_finishMeasure();
Serial.print("RPM=");
Serial.println(FAN_rpm);
} else if (rpmMeasureState != RPM_MEASURE_STATE_FINISHED) {
// measurement didn't finished in 50ms, declare measurement failure
if (usec - FAN_usecLastMeasured >= 50 * 1000L) {
// cleanup
FAN_rpmMeasureState = RPM_MEASURE_STATE_MEASURED;
FAN_rpm = 0;
FAN_finishMeasure();
Serial.println("RPM measurement failed!");
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
// ADC
SPISettings ADS1120_SPI(4000000, MSBFIRST, SPI_MODE1);
// ADC PINS
const uint8_t ISOLATOR_EN = 14;
const uint8_t ADC_SELECT_PIN = 15;
const uint8_t ADC_INTERRUPT_PIN = 21;
// ADC commands
const uint8_t ADC_RESET = 0B00000110;
const uint8_t ADC_START = 0B00001000;
const uint8_t ADC_RDATA = 0B00010000;
//
const uint8_t ADC_WR3S1 = 0B01000110;
const uint8_t ADC_WR1S0 = 0B01000000;
//
const uint8_t ADC_REG0_READ_U_MON = 0x91; // B10010001: [7:4] AINP = AIN1, AINN = AVSS, [3:1] Gain = 1, [0] PGA disabled and bypassed
/// How many times per second will ADC take snapshot value?
/// 0: 20 SPS, 1: 45 SPS, 2: 90 SPS, 3: 175 SPS, 4: 330 SPS, 5: 600 SPS, 6: 1000 SPS
const uint8_t ADC_SPS = 0;
const uint8_t ADC_REG1_VAL = (ADC_SPS << 5) | 0B00000000;
const uint8_t ADC_REG2_VAL = 0B01100000; // Register 02h: External Vref, 50Hz rejection, PSW off, IDAC off
const uint8_t ADC_REG3_VAL = 0B00000000; // Register 03h: IDAC1 disabled, IDAC2 disabled, dedicated DRDY
volatile int ADC_interruptHandlerCounter;
void ADC_start() {
SPI.beginTransaction(ADS1120_SPI);
digitalWrite(ISOLATOR_EN, HIGH);
digitalWrite(ADC_SELECT_PIN, LOW);
SPI.transfer(ADC_WR1S0);
SPI.transfer(ADC_REG0_READ_U_MON);
SPI.transfer(ADC_START);
digitalWrite(ADC_SELECT_PIN, HIGH);
digitalWrite(ISOLATOR_EN, LOW);
SPI.endTransaction();
}
int16_t ADC_read() {
SPI.beginTransaction(ADS1120_SPI);
digitalWrite(ISOLATOR_EN, HIGH);
digitalWrite(ADC_SELECT_PIN, LOW);
// Read conversion data
SPI.transfer(ADC_RDATA);
uint16_t dmsb = SPI.transfer(0);
uint16_t dlsb = SPI.transfer(0);
digitalWrite(ADC_SELECT_PIN, HIGH);
digitalWrite(ISOLATOR_EN, LOW);
SPI.endTransaction();
return (int16_t)((dmsb << 8) | dlsb);
}
void ADC_interruptHandler() {
++ADC_interruptHandlerCounter;
int16_t adc_data = ADC_read();
// ...
ADC_start();
}
void ADC_setup() {
//
pinMode(ADC_SELECT_PIN, OUTPUT);
digitalWrite(ADC_SELECT_PIN, HIGH); // Deselect ADS1120
//
int intNum = digitalPinToInterrupt(ADC_INTERRUPT_PIN);
SPI.usingInterrupt(intNum);
attachInterrupt(intNum, ADC_interruptHandler, FALLING);
// Send RESET command
SPI.beginTransaction(ADS1120_SPI);
digitalWrite(ISOLATOR_EN, HIGH);
digitalWrite(ADC_SELECT_PIN, LOW);
SPI.transfer(ADC_RESET);
delayMicroseconds(100); // Guard time
SPI.transfer(ADC_WR3S1);
SPI.transfer(ADC_REG1_VAL);
SPI.transfer(ADC_REG2_VAL);
SPI.transfer(ADC_REG3_VAL);
digitalWrite(ADC_SELECT_PIN, HIGH);
digitalWrite(ISOLATOR_EN, LOW);
SPI.endTransaction();
//
ADC_start();
}
////////////////////////////////////////////////////////////////////////////////
void setup() {
BOARD_setup();
FAN_setup();
ADC_setup();
}
unsigned long usecLast = 0;
void loop() {
unsigned long usec = micros();
FAN_tick(usec);
if (usec - usecLast > 1000000UL) {
Serial.print("FAN interrupt counter = ");
Serial.print(FAN_interruptCounter1);
FAN_interruptCounter = 0;
Serial.print(", ADC interrupt counter = ");
Serial.println(ADC_interruptHandlerCounter);
ADC_interruptHandlerCounter = 0;
usecLast = usec;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment