/* * 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 핀 정의 #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; }