Files
esp32_ads8688/ads8688_esp32_fixed.ino

322 lines
8.1 KiB
C++

/*
* ESP32 WROOM32D + ADS8688 Test Code
* Based on working Orange Pi 5 SPI implementation
*
* Connections:
* ESP32 VSPI Pins:
* - SCLK: GPIO18
* - MISO: GPIO19
* - MOSI: GPIO23
* - CS: GPIO5
* - RST: GPIO17
*/
#include <SPI.h>
// SPI 핀 정의
#define ADS8688_CS 5 // Chip Select
#define ADS8688_RST 17 // Reset
// ADS8688 명령어 레지스터 (Orange Pi 코드 참조)
#define NO_OP 0x00 // Continue operation in previous mode
#define STDBY 0x82 // Device is placed into standby mode
#define PWR_DN 0x83 // Device is powered down
#define RST 0x85 // Program register is reset to default
#define AUTO_RST 0xA0 // Auto mode enabled following a reset
#define MAN_Ch_0 0xC0 // Channel 0 input is selected
#define MAN_Ch_1 0xC4 // Channel 1 input is selected
#define MAN_Ch_2 0xC8 // Channel 2 input is selected
#define MAN_Ch_3 0xCC // Channel 3 input is selected
#define MAN_Ch_4 0xD0 // Channel 4 input is selected
#define MAN_Ch_5 0xD4 // Channel 5 input is selected
#define MAN_Ch_6 0xD8 // Channel 6 input is selected
#define MAN_Ch_7 0xDC // Channel 7 input is selected
// 레지스터 주소
#define AUTO_SEQ_EN 0x01 // Auto Sequencing Enable
#define CH_PWR_DN 0x02 // Channel Power Down
// 범위 선택 레지스터
#define RG_Ch_0 0x05
#define RG_Ch_1 0x06
#define RG_Ch_2 0x07
#define RG_Ch_3 0x08
#define RG_Ch_4 0x09
#define RG_Ch_5 0x0A
#define RG_Ch_6 0x0B
#define RG_Ch_7 0x0C
// 전압 범위 설정
#define R0 0x00 // ±10.24V
#define R1 0x01 // ±5.12V
#define R2 0x02 // ±2.56V
#define R3 0x03 // ±1.28V
SPIClass *vspi = NULL;
// 샘플링 설정
#define SAMPLING_RATE_HZ 500
#define SAMPLE_INTERVAL_US 2000
#define SAMPLES_PER_SECOND 500
// 8채널 데이터 버퍼
uint32_t channelSum[8];
uint16_t sampleCount = 0;
static float vref = 4.096;
// 함수 선언
void resetADS8688();
void initADS8688();
void writeRegister(uint8_t reg, uint8_t value);
uint8_t readRegister(uint8_t reg);
uint16_t cmdRegister(uint8_t cmd);
uint16_t noOp();
void setChannelRange(uint8_t ch, uint8_t range);
void setGlobalRange(uint8_t range);
void setChannelSPD(uint8_t flag);
uint16_t powerDown();
uint16_t standBy();
uint16_t reset();
uint16_t autoRst();
float adcValueToVoltage(uint16_t adcValue);
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n=== ADS8688 Test Started ===");
Serial.println("Sampling Rate: 500Hz");
Serial.println("Based on Orange Pi 5 working code\n");
// VSPI 초기화
vspi = new SPIClass(VSPI);
vspi->begin();
// CS, RST 핀 설정
pinMode(ADS8688_CS, OUTPUT);
pinMode(ADS8688_RST, OUTPUT);
digitalWrite(ADS8688_CS, HIGH);
digitalWrite(ADS8688_RST, HIGH);
// ADS8688 초기화 (Orange Pi 코드 시퀀스 참조)
resetADS8688();
delay(1);
powerDown();
delayMicroseconds(1000);
standBy();
delayMicroseconds(1000);
reset();
delayMicroseconds(1000);
setChannelSPD(0xFF); // 모든 채널 활성화
setGlobalRange(R1); // ±5.12V 범위
delayMicroseconds(1000);
autoRst();
Serial.println("ADS8688 Initialized");
Serial.println("Starting data acquisition...\n");
// 채널 합계 초기화
for (int i = 0; i < 8; i++) {
channelSum[i] = 0;
}
}
void loop() {
unsigned long startTime = micros();
// 1초간 500개 샘플 수집
for (int sample = 0; sample < SAMPLES_PER_SECOND; sample++) {
unsigned long sampleStartTime = micros();
// 8개 채널 순차적으로 읽기 (Orange Pi 방식)
for (int ch = 0; ch < 8; ch++) {
uint16_t adcValue = noOp(); // NO_OP으로 이전 변환 결과 읽기
channelSum[ch] += adcValue;
}
sampleCount++;
// 다음 샘플까지 대기
unsigned long elapsed = micros() - sampleStartTime;
if (elapsed < SAMPLE_INTERVAL_US) {
delayMicroseconds(SAMPLE_INTERVAL_US - elapsed);
}
}
unsigned long totalTime = micros() - startTime;
// 1초간의 평균 계산 및 출력
Serial.println("========== 1-Second Average (500 samples @ 500Hz) ==========");
Serial.print("Actual sampling time: ");
Serial.print(totalTime / 1000.0, 2);
Serial.println(" ms");
Serial.println();
for (int ch = 0; ch < 8; ch++) {
float avgADC = (float)channelSum[ch] / sampleCount;
float avgVoltage = adcValueToVoltage((uint16_t)avgADC);
Serial.print("CH");
Serial.print(ch);
Serial.print(": Avg ADC = ");
Serial.print(avgADC, 2);
Serial.print(" (0x");
Serial.print((uint16_t)avgADC, HEX);
Serial.print(") | Avg Voltage = ");
Serial.print(avgVoltage, 4);
Serial.println(" V");
}
Serial.print("\nTotal samples collected: ");
Serial.println(sampleCount);
Serial.println("===========================================================\n");
// 다음 측정을 위해 리셋
for (int i = 0; i < 8; i++) {
channelSum[i] = 0;
}
sampleCount = 0;
delay(100);
}
// 하드웨어 리셋 (Orange Pi 방식)
void resetADS8688() {
digitalWrite(ADS8688_RST, HIGH);
delayMicroseconds(1000);
digitalWrite(ADS8688_RST, LOW);
delayMicroseconds(1000);
digitalWrite(ADS8688_RST, HIGH);
delayMicroseconds(1000);
}
// 레지스터 쓰기 (Orange Pi 코드 참조)
void writeRegister(uint8_t reg, uint8_t value) {
digitalWrite(ADS8688_CS, LOW);
vspi->beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE1));
vspi->transfer((reg << 1) | 0x01); // Write command
vspi->transfer(value);
vspi->transfer(0x00);
vspi->endTransaction();
digitalWrite(ADS8688_CS, HIGH);
delayMicroseconds(10);
}
// 레지스터 읽기 (Orange Pi 코드 참조)
uint8_t readRegister(uint8_t reg) {
digitalWrite(ADS8688_CS, LOW);
vspi->beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE1));
vspi->transfer((reg << 1) & 0xFE); // Read command
vspi->transfer(0x00);
vspi->transfer(0x00);
vspi->endTransaction();
digitalWrite(ADS8688_CS, HIGH);
delayMicroseconds(10);
// 더미 전송으로 데이터 읽기
digitalWrite(ADS8688_CS, LOW);
vspi->beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE1));
vspi->transfer(0x00);
vspi->transfer(0x00);
uint8_t value = vspi->transfer(0x00);
vspi->endTransaction();
digitalWrite(ADS8688_CS, HIGH);
return value;
}
// 명령 레지스터 실행 (Orange Pi cmdRegister 참조)
uint16_t cmdRegister(uint8_t cmd) {
uint16_t result = 0;
digitalWrite(ADS8688_CS, LOW);
vspi->beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE1));
vspi->transfer(cmd);
vspi->transfer(0x00);
uint8_t msb = vspi->transfer(0x00);
uint8_t lsb = vspi->transfer(0x00);
vspi->endTransaction();
digitalWrite(ADS8688_CS, HIGH);
delayMicroseconds(1);
result = (msb << 8) | lsb;
return result;
}
// NO_OP 명령 (데이터 읽기용)
uint16_t noOp() {
return cmdRegister(NO_OP);
}
// Power Down 명령
uint16_t powerDown() {
return cmdRegister(PWR_DN);
}
// Standby 명령
uint16_t standBy() {
return cmdRegister(STDBY);
}
// Reset 명령
uint16_t reset() {
return cmdRegister(RST);
}
// Auto Reset 명령
uint16_t autoRst() {
return cmdRegister(AUTO_RST);
}
// 채널 범위 설정
void setChannelRange(uint8_t ch, uint8_t range) {
uint8_t reg;
switch (ch) {
case 0: reg = RG_Ch_0; break;
case 1: reg = RG_Ch_1; break;
case 2: reg = RG_Ch_2; break;
case 3: reg = RG_Ch_3; break;
case 4: reg = RG_Ch_4; break;
case 5: reg = RG_Ch_5; break;
case 6: reg = RG_Ch_6; break;
case 7: reg = RG_Ch_7; break;
default: reg = RG_Ch_0; break;
}
writeRegister(reg, range);
}
// 모든 채널 범위 설정
void setGlobalRange(uint8_t range) {
for (uint8_t i = 0; i < 8; i++) {
setChannelRange(i, range);
}
}
// 채널 시퀀스 및 파워 설정
void setChannelSPD(uint8_t flag) {
writeRegister(AUTO_SEQ_EN, flag);
writeRegister(CH_PWR_DN, (uint8_t)~flag);
}
// ADC 값을 전압으로 변환 (±5.12V 범위 - R1)
float adcValueToVoltage(uint16_t adcValue) {
// ADS8688은 16비트 ADC, 양극성 모드
// 0x0000 = -5.12V, 0x8000 = 0V, 0xFFFF = +5.12V
float voltage = ((float)adcValue / 65535.0) * 10.24 - 5.12;
return voltage;
}