commit 7622fe89fc0a0de7f7f1b02292286f8e19f9c8ef Author: byun Date: Fri Oct 24 20:51:55 2025 +0000 테스트 완료 8ch 정상작동 diff --git a/ads8688_esp32_fixed.ino b/ads8688_esp32_fixed.ino new file mode 100644 index 0000000..88eef1b --- /dev/null +++ b/ads8688_esp32_fixed.ino @@ -0,0 +1,321 @@ +/* + * 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; +}