ADS1256 DAC8532 树莓派5 适配
AD C 程序 最优采集 接近15Kads1256_capture_1s.c#include errno.h #include fcntl.h #include linux/spi/spidev.h #include lgpio.h #include stdint.h #include stdio.h #include stdlib.h #include string.h #include sys/ioctl.h #include time.h #include unistd.h #define RST_PIN 18 #define CS_PIN 22 #define CS1_PIN 23 #define DRDY_PIN 17 #define GPIO_CHIP 0 #define SPI_DEVICE /dev/spidev0.0 #define SPI_SPEED_HZ 3000000 #define SAMPLE_COUNT 30000 #define VREF 5.0 #define REG_STATUS 0 #define REG_MUX 1 #define REG_ADCON 2 #define REG_DRATE 3 #define CMD_WAKEUP 0x00 #define CMD_RDATAC 0x03 #define CMD_SDATAC 0x0F #define CMD_RREG 0x10 #define CMD_WREG 0x50 #define CMD_SYNC 0xFC #define ADS1256_GAIN_1 0x00 #define ADS1256_30000SPS 0xF0 static int gpio_handle -1; static int spi_fd -1; typedef struct { int32_t raw; double voltage; } Sample; static int64_t monotonic_ns(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC_RAW, ts); return (int64_t)ts.tv_sec * 1000000000LL ts.tv_nsec; } static void delay_ms(unsigned int ms) { usleep(ms * 1000); } static int gpio_write(int pin, int value) { return lgGpioWrite(gpio_handle, pin, value ? 1 : 0); } static int gpio_read(int pin) { return lgGpioRead(gpio_handle, pin); } static uint8_t spi_transfer_byte(uint8_t value) { uint8_t rx 0xff; struct spi_ioc_transfer tr; memset(tr, 0, sizeof(tr)); tr.tx_buf (unsigned long)value; tr.rx_buf (unsigned long)rx; tr.len 1; tr.speed_hz SPI_SPEED_HZ; tr.bits_per_word 8; if (ioctl(spi_fd, SPI_IOC_MESSAGE(1), tr) 0) { fprintf(stderr, spi transfer failed: %s\n, strerror(errno)); } return rx; } static int spi_transfer_buf(const uint8_t *tx, uint8_t *rx, size_t len) { struct spi_ioc_transfer tr; memset(tr, 0, sizeof(tr)); tr.tx_buf (unsigned long)tx; tr.rx_buf (unsigned long)rx; tr.len len; tr.speed_hz SPI_SPEED_HZ; tr.bits_per_word 8; return ioctl(spi_fd, SPI_IOC_MESSAGE(1), tr); } static int wait_drdy_low(void) { for (int i 0; i 4000000; i) { if (gpio_read(DRDY_PIN) 0) { return 0; } } return 1; } static void ads_write_cmd(uint8_t cmd) { gpio_write(CS_PIN, 0); spi_transfer_byte(cmd); gpio_write(CS_PIN, 1); } static void ads_write_reg(uint8_t reg, uint8_t value) { gpio_write(CS_PIN, 0); spi_transfer_byte(CMD_WREG | reg); spi_transfer_byte(0x00); spi_transfer_byte(value); gpio_write(CS_PIN, 1); } static uint8_t ads_read_reg(uint8_t reg) { uint8_t value; gpio_write(CS_PIN, 0); spi_transfer_byte(CMD_RREG | reg); spi_transfer_byte(0x00); delay_ms(1); value spi_transfer_byte(0xff); gpio_write(CS_PIN, 1); return value; } static void ads_reset(void) { gpio_write(RST_PIN, 1); delay_ms(200); gpio_write(RST_PIN, 0); delay_ms(200); gpio_write(RST_PIN, 1); } static int32_t read_continuous_sample(void) { uint8_t tx[3] {0xff, 0xff, 0xff}; uint8_t rx[3] {0xff, 0xff, 0xff}; uint32_t raw; gpio_write(CS_PIN, 0); if (spi_transfer_buf(tx, rx, sizeof(tx)) 0) { fprintf(stderr, spi sample read failed: %s\n, strerror(errno)); } gpio_write(CS_PIN, 1); raw ((uint32_t)rx[0] 16) | ((uint32_t)rx[1] 8) | rx[2]; if (raw 0x800000) { raw | 0xff000000; } return (int32_t)raw; } static int init_gpio_spi(void) { gpio_handle lgGpiochipOpen(GPIO_CHIP); if (gpio_handle 0) { fprintf(stderr, lgGpiochipOpen failed: %d\n, gpio_handle); return 1; } if (lgGpioClaimOutput(gpio_handle, 0, RST_PIN, 1) 0 || lgGpioClaimOutput(gpio_handle, 0, CS_PIN, 1) 0 || lgGpioClaimOutput(gpio_handle, 0, CS1_PIN, 1) 0 || lgGpioClaimInput(gpio_handle, LG_SET_PULL_UP, DRDY_PIN) 0) { fprintf(stderr, claim GPIO failed; check no other ADC program is running\n); return 1; } spi_fd open(SPI_DEVICE, O_RDWR); if (spi_fd 0) { fprintf(stderr, open %s failed: %s\n, SPI_DEVICE, strerror(errno)); return 1; } uint8_t mode SPI_MODE_1; uint8_t bits 8; uint32_t speed SPI_SPEED_HZ; if (ioctl(spi_fd, SPI_IOC_WR_MODE, mode) 0 || ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, bits) 0 || ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, speed) 0) { fprintf(stderr, configure spi failed: %s\n, strerror(errno)); return 1; } return 0; } static void cleanup(void) { if (spi_fd 0) { close(spi_fd); spi_fd -1; } if (gpio_handle 0) { lgGpiochipClose(gpio_handle); gpio_handle -1; } } static void ads_config_30ksps_channel0(void) { uint8_t status (0 3) | (1 2) | (0 1); uint8_t mux (0 4) | (1 3); uint8_t adcon ADS1256_GAIN_1; wait_drdy_low(); gpio_write(CS_PIN, 0); spi_transfer_byte(CMD_WREG | REG_STATUS); spi_transfer_byte(0x03); spi_transfer_byte(status); spi_transfer_byte(mux); spi_transfer_byte(adcon); spi_transfer_byte(ADS1256_30000SPS); gpio_write(CS_PIN, 1); delay_ms(1); ads_write_reg(REG_MUX, mux); ads_write_cmd(CMD_SYNC); ads_write_cmd(CMD_WAKEUP); wait_drdy_low(); ads_write_cmd(CMD_RDATAC); } static int save_csv(const char *path, const Sample *samples, int count, double elapsed) { FILE *fp fopen(path, w); if (!fp) { fprintf(stderr, open output %s failed: %s\n, path, strerror(errno)); return 1; } fprintf(fp, # ADS1256 one-second voltage capture\n); fprintf(fp, # channel,AIN0\n); fprintf(fp, # configured_sps,30000\n); fprintf(fp, # captured_samples,%d\n, count); fprintf(fp, # elapsed_seconds,%.9f\n, elapsed); fprintf(fp, # actual_sps,%.3f\n, count / elapsed); fprintf(fp, index,raw,voltage\n); for (int i 0; i count; i) { fprintf(fp, %d,%d,%.9f\n, i, samples[i].raw, samples[i].voltage); } fclose(fp); return 0; } int main(int argc, char **argv) { int64_t program_start monotonic_ns(); const char *output_path argc 1 ? argv[1] : ads1256_ain0_1s.csv; Sample *samples calloc(SAMPLE_COUNT, sizeof(Sample)); if (!samples) { fprintf(stderr, calloc failed\n); return 1; } if (init_gpio_spi() ! 0) { cleanup(); free(samples); return 1; } printf(ADS1256 one-second voltage capture\n); printf(Channel: AIN0, requested samples: %d, data rate register: 0x%02X\n, SAMPLE_COUNT, ADS1256_30000SPS); printf(SPI: %s mode1 %d Hz\n, SPI_DEVICE, SPI_SPEED_HZ); ads_reset(); if (wait_drdy_low() ! 0) { fprintf(stderr, DRDY timeout before ID read\n); cleanup(); free(samples); return 1; } uint8_t id ads_read_reg(REG_STATUS) 4; printf(Chip ID: %u %s\n, id, id 3 ? (OK) : (unexpected)); if (id ! 3) { cleanup(); free(samples); return 1; } ads_config_30ksps_channel0(); delay_ms(100); int64_t start monotonic_ns(); int captured 0; for (int i 0; i SAMPLE_COUNT; i) { if (wait_drdy_low() ! 0) { fprintf(stderr, DRDY timeout at sample %d\n, i); break; } samples[i].raw read_continuous_sample(); samples[i].voltage samples[i].raw * VREF / 8388607.0; captured; } int64_t end monotonic_ns(); ads_write_cmd(CMD_SDATAC); double elapsed (end - start) / 1000000000.0; double actual_sps captured / elapsed; printf(Captured: %d real ADC voltage samples\n, captured); printf(Elapsed: %.6f sec\n, elapsed); printf(Actual capture rate: %.1f samples/sec\n, actual_sps); printf(First voltage: %.9f V\n, captured 0 ? samples[0].voltage : 0.0); printf(Last voltage: %.9f V\n, captured 0 ? samples[captured - 1].voltage : 0.0); int64_t save_start monotonic_ns(); if (save_csv(output_path, samples, captured, elapsed) 0) { int64_t save_end monotonic_ns(); printf(Saved CSV after capture: %s\n, output_path); printf(Save elapsed: %.6f sec\n, (save_end - save_start) / 1000000000.0); } int64_t program_end monotonic_ns(); printf(Program total elapsed: %.6f sec\n, (program_end - program_start) / 1000000000.0); cleanup(); free(samples); return 0; }MakefileCC gcc CFLAGS -O2 -Wall -I/home/pi/lg LDFLAGS -L/home/pi/lg -Wl,-rpath,/home/pi/lg LIBS -llgpio -lm TARGET ads1256_capture_1s SRC ads1256_capture_1s.c all: $(TARGET) $(TARGET): $(SRC) $(CC) $(CFLAGS) $(SRC) -o $(TARGET) $(LDFLAGS) $(LIBS) clean: rm -f $(TARGET) *.oDAC8532 最优DA输出dac8532_max_da.c#define _GNU_SOURCE #include errno.h #include fcntl.h #include gpiod.h #include linux/spi/spidev.h #include stdint.h #include stdio.h #include stdlib.h #include string.h #include sys/ioctl.h #include time.h #include unistd.h #define DAC8532_CHANNEL_A 0x30 #define DAC8532_CHANNEL_B 0x34 #define DEFAULT_SPI_DEV /dev/spidev0.0 #define DEFAULT_GPIO_CHIP gpiochip0 #define DEFAULT_CS_LINE 23 #define DEFAULT_SPI_HZ 24000000U #define DEFAULT_SECONDS 5.0 #define DEFAULT_VREF 3.3 static double now_seconds(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC_RAW, ts); return (double)ts.tv_sec (double)ts.tv_nsec / 1000000000.0; } static uint16_t volts_to_code(double volts, double vref) { if (volts 0.0) return 0; if (volts vref) return 65535; return (uint16_t)((volts * 65535.0 / vref) 0.5); } static int spi_write_dac(int spi_fd, struct gpiod_line *cs, uint32_t speed_hz, uint8_t channel, uint16_t code) { uint8_t tx[3] { channel, (uint8_t)(code 8), (uint8_t)(code 0xff) }; struct spi_ioc_transfer tr; memset(tr, 0, sizeof(tr)); tr.tx_buf (uintptr_t)tx; tr.len sizeof(tx); tr.speed_hz speed_hz; tr.bits_per_word 8; if (gpiod_line_set_value(cs, 0) 0) return -1; if (ioctl(spi_fd, SPI_IOC_MESSAGE(1), tr) 1) return -1; if (gpiod_line_set_value(cs, 1) 0) return -1; return 0; } static void usage(const char *argv0) { printf(Usage: sudo %s [seconds] [spi_hz] [channel] [vref]\n, argv0); printf( seconds : test duration, default %.1f\n, DEFAULT_SECONDS); printf( spi_hz : SPI clock, default %u\n, DEFAULT_SPI_HZ); printf( channel : A or B, default A\n); printf( vref : DAC reference voltage, default %.3f V\n, DEFAULT_VREF); } int main(int argc, char **argv) { double seconds DEFAULT_SECONDS; uint32_t speed_hz DEFAULT_SPI_HZ; uint8_t channel DAC8532_CHANNEL_A; const char *channel_name A; double vref DEFAULT_VREF; if (argc 1) { if (!strcmp(argv[1], -h) || !strcmp(argv[1], --help)) { usage(argv[0]); return 0; } seconds atof(argv[1]); } if (argc 2) speed_hz (uint32_t)strtoul(argv[2], NULL, 10); if (argc 3) { if (argv[3][0] B || argv[3][0] b) { channel DAC8532_CHANNEL_B; channel_name B; } } if (argc 4) vref atof(argv[4]); if (seconds 0.0 || speed_hz 0 || vref 0.0) { usage(argv[0]); return 2; } int spi_fd open(DEFAULT_SPI_DEV, O_RDWR); if (spi_fd 0) { fprintf(stderr, open %s failed: %s\n, DEFAULT_SPI_DEV, strerror(errno)); return 1; } uint8_t mode SPI_MODE_1; uint8_t bits 8; if (ioctl(spi_fd, SPI_IOC_WR_MODE, mode) 0 || ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, bits) 0 || ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, speed_hz) 0) { fprintf(stderr, SPI setup failed: %s\n, strerror(errno)); close(spi_fd); return 1; } struct gpiod_chip *chip gpiod_chip_open_by_name(DEFAULT_GPIO_CHIP); if (!chip) { fprintf(stderr, open %s failed: %s\n, DEFAULT_GPIO_CHIP, strerror(errno)); close(spi_fd); return 1; } struct gpiod_line *cs gpiod_chip_get_line(chip, DEFAULT_CS_LINE); if (!cs || gpiod_line_request_output(cs, dac8532_max_da, 1) 0) { fprintf(stderr, request GPIO%d failed: %s\n, DEFAULT_CS_LINE, strerror(errno)); gpiod_chip_close(chip); close(spi_fd); return 1; } uint16_t low volts_to_code(0.0, vref); uint16_t high volts_to_code(vref, vref); printf(DAC8532 maximum DA update proof\n); printf(SPI : %s mode1 %u Hz\n, DEFAULT_SPI_DEV, speed_hz); printf(CS : %s line GPIO%d\n, DEFAULT_GPIO_CHIP, DEFAULT_CS_LINE); printf(Channel : %s\n, channel_name); printf(Voltage : 0.000 V - %.3f V\n, vref); printf(Duration : %.3f sec\n, seconds); fflush(stdout); if (spi_write_dac(spi_fd, cs, speed_hz, channel, low) 0 || spi_write_dac(spi_fd, cs, speed_hz, channel, high) 0) { fprintf(stderr, DAC warm-up write failed: %s\n, strerror(errno)); gpiod_line_release(cs); gpiod_chip_close(chip); close(spi_fd); return 1; } uint64_t updates 0; double start now_seconds(); double end_at start seconds; while (now_seconds() end_at) { if (spi_write_dac(spi_fd, cs, speed_hz, channel, low) 0 || spi_write_dac(spi_fd, cs, speed_hz, channel, high) 0) { fprintf(stderr, DAC write failed after %llu updates: %s\n, (unsigned long long)updates, strerror(errno)); break; } updates 2; } double end now_seconds(); double elapsed end - start; double updates_per_sec (double)updates / elapsed; double square_wave_hz updates_per_sec / 2.0; spi_write_dac(spi_fd, cs, speed_hz, channel, low); printf(Result : %llu DAC updates in %.6f sec\n, (unsigned long long)updates, elapsed); printf(DA rate : %.1f updates/sec\n, updates_per_sec); printf(Wave proof: %.1f Hz square wave on DAC %s output\n, square_wave_hz, channel_name); printf(Note : this is real SPI writes to DAC8532, not a software counter only.\n); FILE *report fopen(dac8532_max_da_report.txt, w); if (report) { fprintf(report, DAC8532 maximum DA update proof\n); fprintf(report, spi%s mode1 speed_hz%u cs_gpio%d channel%s vref%.6f\n, DEFAULT_SPI_DEV, speed_hz, DEFAULT_CS_LINE, channel_name, vref); fprintf(report, updates%llu elapsed_sec%.9f da_updates_per_sec%.3f square_wave_hz%.3f\n, (unsigned long long)updates, elapsed, updates_per_sec, square_wave_hz); fclose(report); } gpiod_line_release(cs); gpiod_chip_close(chip); close(spi_fd); return 0; }MakefileCC : gcc CFLAGS : -O3 -Wall -Wextra LDLIBS : -lgpiod TARGET : dac8532_max_da .PHONY: all clean run all: $(TARGET) $(TARGET): dac8532_max_da.c $(CC) $(CFLAGS) $ -o $ $(LDLIBS) run: $(TARGET) sudo ./$(TARGET) clean: rm -f $(TARGET) dac8532_max_da_report.txt