fix(ads1256): 修复 SPI 无波形问题,添加 PDWN 引脚控制

PDWN 浮空导致 ADS1256 进入 power-down 模式,DRDY 无响应且 SPI 总线
无输出。同时将 CS 管理从手动 GPIO 改为 SPIM 驱动自动控制,消除引脚
所有权冲突;读寄存器和读数据改用 spi_transceive 保证单次 CS 内完成。
This commit is contained in:
2026-05-21 15:01:26 +08:00
parent 6770f35a07
commit ec1ba14e46
2 changed files with 40 additions and 48 deletions
+4 -4
View File
@@ -46,21 +46,21 @@
/ {
aliases {
ads-cs = &ads_cs_pin;
ads-drdy = &ads_drdy_pin;
ads-reset = &ads_reset_pin;
ads-pdwn = &ads_pdwn_pin;
};
ads1256_control {
compatible = "gpio-keys";
ads_cs_pin: ads_cs {
gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
};
ads_drdy_pin: ads_drdy {
gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
};
ads_reset_pin: ads_reset {
gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
};
ads_pdwn_pin: ads_pdwn {
gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
};
};
};
+35 -43
View File
@@ -35,9 +35,10 @@ LOG_MODULE_REGISTER(ads1256, LOG_LEVEL_INF);
/* --- 硬件资源 --- */
static struct spi_config spi_cfg;
static const struct device *spi_dev;
static const struct gpio_dt_spec cs_spec = GPIO_DT_SPEC_GET(DT_ALIAS(ads_cs), gpios);
static const struct gpio_dt_spec cs_spec = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(ads1256));
static const struct gpio_dt_spec drdy_spec = GPIO_DT_SPEC_GET(DT_ALIAS(ads_drdy), gpios);
static const struct gpio_dt_spec reset_spec = GPIO_DT_SPEC_GET(DT_ALIAS(ads_reset), gpios);
static const struct gpio_dt_spec pdwn_spec = GPIO_DT_SPEC_GET(DT_ALIAS(ads_pdwn), gpios);
struct ads1256_reg_snapshot {
uint8_t status;
@@ -82,12 +83,10 @@ int ads1256_wait_drdy(uint16_t timeout_ms) {
*/
void ads1256_write_reg(uint8_t reg, uint8_t val) {
ads1256_wait_drdy(50);
gpio_pin_set_dt(&cs_spec, 1);
uint8_t tx_buf[3] = { CMD_WREG | reg, 0x00, val };
struct spi_buf tx = { .buf = tx_buf, .len = 3 };
struct spi_buf_set tx_set = { .buffers = &tx, .count = 1 };
spi_write(spi_dev, &spi_cfg, &tx_set);
gpio_pin_set_dt(&cs_spec, 0);
/* t11: WREG 后至少 4 × tCLKIN ≈ 0.5µs */
k_busy_wait(2);
}
@@ -95,25 +94,25 @@ void ads1256_write_reg(uint8_t reg, uint8_t val) {
/**
* @brief 从 ADS1256 读单个寄存器。
*
* ADS1256 RREG 时序要求:命令+数据在同一次 CS 拉低内完成,
* 中间需 t6 延时。这里用单次 transceive 保证 CS 不释放。
*
* @param reg 目标寄存器地址。
*
* @return 读取到的寄存器值。
*/
uint8_t ads1256_read_reg(uint8_t reg) {
ads1256_wait_drdy(50);
gpio_pin_set_dt(&cs_spec, 1);
uint8_t tx_buf[2] = { CMD_RREG | reg, 0x00 };
struct spi_buf tx = { .buf = tx_buf, .len = 2 };
/* tx: [RREG|reg, 0x00, dummy_for_t6, dummy_read]
* rx: [x, x, x, data] — 前 3 字节是命令+延时期间的垃圾 */
uint8_t tx_buf[4] = { CMD_RREG | reg, 0x00, 0xFF, 0xFF };
uint8_t rx_buf[4] = { 0 };
struct spi_buf tx = { .buf = tx_buf, .len = 4 };
struct spi_buf_set tx_set = { .buffers = &tx, .count = 1 };
spi_write(spi_dev, &spi_cfg, &tx_set);
/* t6: RREG 后至少 50 × tCLKIN ≈ 6.5µs */
k_busy_wait(10);
uint8_t rx_val = 0;
struct spi_buf rx = { .buf = &rx_val, .len = 1 };
struct spi_buf rx = { .buf = rx_buf, .len = 4 };
struct spi_buf_set rx_set = { .buffers = &rx, .count = 1 };
spi_read(spi_dev, &spi_cfg, &rx_set);
gpio_pin_set_dt(&cs_spec, 0);
return rx_val;
spi_transceive(spi_dev, &spi_cfg, &tx_set, &rx_set);
return rx_buf[3];
}
/**
@@ -188,31 +187,23 @@ static void ads1256_log_snapshot_delta(
*/
void ads1256_write_cmd(uint8_t cmd) {
ads1256_wait_drdy(50);
gpio_pin_set_dt(&cs_spec, 1);
struct spi_buf tx = { .buf = &cmd, .len = 1 };
struct spi_buf_set tx_set = { .buffers = &tx, .count = 1 };
spi_write(spi_dev, &spi_cfg, &tx_set);
gpio_pin_set_dt(&cs_spec, 0);
}
/**
* @brief 发送 SYNC + WAKEUP 命令,触发一次同步采样。
*
* @return 无返回值
* SYNC 和 WAKEUP 必须在同一次 CS 内完成,用单次 transceive 保持 CS
* 中间插入 dummy 字节满足 t11 延时 (24 × tCLKIN ≈ 3.1µs)。
*/
void ads1256_sync_wakeup(void) {
uint8_t cmd_sync = CMD_SYNC;
uint8_t cmd_wakeup = CMD_WAKEUP;
struct spi_buf tx_s = { .buf = &cmd_sync, .len = 1 };
struct spi_buf tx_w = { .buf = &cmd_wakeup, .len = 1 };
struct spi_buf_set set_s = { .buffers = &tx_s, .count = 1 };
struct spi_buf_set set_w = { .buffers = &tx_w, .count = 1 };
gpio_pin_set_dt(&cs_spec, 1);
spi_write(spi_dev, &spi_cfg, &set_s);
/* t11: SYNC 后至少 24 × tCLKIN ≈ 3.1µs */
k_busy_wait(4);
spi_write(spi_dev, &spi_cfg, &set_w);
gpio_pin_set_dt(&cs_spec, 0);
/* [SYNC, dummy(延时), WAKEUP] — 500kHz 下每字节 16µs1 字节 dummy 远超 3.1µs */
uint8_t tx_buf[3] = { CMD_SYNC, 0xFF, CMD_WAKEUP };
struct spi_buf tx = { .buf = tx_buf, .len = 3 };
struct spi_buf_set tx_set = { .buffers = &tx, .count = 1 };
spi_write(spi_dev, &spi_cfg, &tx_set);
}
/**
@@ -235,22 +226,21 @@ int ads1256_hwreset(void) {
/**
* @brief 读取当前 24 位转换结果,符号扩展为 int32_t。
*
* RDATA 命令后需 t6 延时再读 3 字节数据,全部在同一次 CS 内完成。
*
* @return 当前 ADC 转换原始值。
*/
int32_t ads1256_read_data(void) {
uint8_t cmd = CMD_RDATA;
uint8_t rx_buf[3] = { 0 };
gpio_pin_set_dt(&cs_spec, 1);
struct spi_buf tx = { .buf = &cmd, .len = 1 };
/* tx: [RDATA, dummy(t6延时), MSB, MID, LSB]
* rx: [x, x, MSB, MID, LSB] */
uint8_t tx_buf[5] = { CMD_RDATA, 0xFF, 0xFF, 0xFF, 0xFF };
uint8_t rx_buf[5] = { 0 };
struct spi_buf tx = { .buf = tx_buf, .len = 5 };
struct spi_buf_set tx_set = { .buffers = &tx, .count = 1 };
spi_write(spi_dev, &spi_cfg, &tx_set);
/* t6: RDATA 后至少 50 × tCLKIN ≈ 6.5µs */
k_busy_wait(10);
struct spi_buf rx = { .buf = rx_buf, .len = 3 };
struct spi_buf rx = { .buf = rx_buf, .len = 5 };
struct spi_buf_set rx_set = { .buffers = &rx, .count = 1 };
spi_read(spi_dev, &spi_cfg, &rx_set);
gpio_pin_set_dt(&cs_spec, 0);
int32_t val = ((int32_t)rx_buf[0] << 16) | ((int32_t)rx_buf[1] << 8) | rx_buf[2];
spi_transceive(spi_dev, &spi_cfg, &tx_set, &rx_set);
int32_t val = ((int32_t)rx_buf[2] << 16) | ((int32_t)rx_buf[3] << 8) | rx_buf[4];
if (val & 0x800000) val |= 0xFF000000;
return -val;
}
@@ -265,16 +255,18 @@ int32_t ads1256_read_data(void) {
*/
int ads1256_init(void) {
/* GPIO */
/* CS 加内部上拉:EMI 干扰时维持高电平,阻止 ADS1256 误收命令 */
gpio_pin_configure_dt(&cs_spec, GPIO_OUTPUT_INACTIVE | GPIO_PULL_UP);
/* PDWN 低有效:配为 INACTIVE(物理高电平) 保持芯片正常运行 */
gpio_pin_configure_dt(&pdwn_spec, GPIO_OUTPUT_INACTIVE);
gpio_pin_configure_dt(&reset_spec, GPIO_OUTPUT_INACTIVE);
gpio_pin_configure_dt(&drdy_spec, GPIO_INPUT);
/* SPI */
/* SPI — CS 由 SPIM 驱动自动管理 */
spi_dev = DEVICE_DT_GET(DT_NODELABEL(spi1));
spi_cfg.operation = SPI_OP;
spi_cfg.frequency = 500000;
spi_cfg.slave = 0;
spi_cfg.cs.gpio = cs_spec;
spi_cfg.cs.delay = 0;
if (!device_is_ready(spi_dev)) {
LOG_ERR("SPI device not ready");