feat(gml670-v2): 添加二进制协议定义与 ADS1256 SPI 驱动
- protocol.h: CoP/Encoder/Resistance/Spotter/Heartbeat 帧定义, GML670 50kg ADC→kg 标定参数 - ads1256: SPI 命令模式驱动,BUFEN=1 解决高阻抗负载误差, 3750 SPS 平衡精度与采样率,SELFCAL + 寄存器回读校验 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+190
@@ -0,0 +1,190 @@
|
||||
#include "ads1256.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/spi.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(ads1256, LOG_LEVEL_INF);
|
||||
|
||||
/* --- ADS1256 命令 --- */
|
||||
#define CMD_WAKEUP 0x00
|
||||
#define CMD_RDATA 0x01
|
||||
#define CMD_RREG 0x10
|
||||
#define CMD_WREG 0x50
|
||||
#define CMD_SELFCAL 0xF0
|
||||
#define CMD_SYNC 0xFC
|
||||
#define CMD_SDATAC 0x0F
|
||||
|
||||
/* --- ADS1256 寄存器地址 --- */
|
||||
#define REG_STATUS 0x00
|
||||
#define REG_MUX 0x01
|
||||
#define REG_ADCON 0x02
|
||||
#define REG_DRATE 0x03
|
||||
|
||||
#define SPI_OP (SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_LINES_SINGLE)
|
||||
|
||||
/* --- 硬件资源 --- */
|
||||
static const struct device *spi_dev;
|
||||
static struct spi_config spi_cfg;
|
||||
static const struct gpio_dt_spec cs_spec = GPIO_DT_SPEC_GET(DT_ALIAS(ads_cs), gpios);
|
||||
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);
|
||||
|
||||
void ads1256_wait_drdy(uint16_t timeout_ms) {
|
||||
/* drdy_spec 配了 GPIO_ACTIVE_LOW,逻辑 1 表示 DRDY 有效(物理拉低) */
|
||||
/* 用 k_usleep 代替 k_busy_wait,让出 CPU 给其他线程 */
|
||||
int64_t deadline = k_uptime_get() + timeout_ms;
|
||||
while (gpio_pin_get_dt(&drdy_spec) == 0) {
|
||||
k_usleep(10);
|
||||
if (k_uptime_get() >= deadline) {
|
||||
LOG_WRN("DRDY timeout (%u ms)", timeout_ms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 };
|
||||
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_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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void ads1256_hwreset(void) {
|
||||
/* reset_spec 配了 GPIO_ACTIVE_LOW:逻辑 1 = 物理 LOW = 断言复位 */
|
||||
gpio_pin_set_dt(&reset_spec, 1);
|
||||
/* t16: 最小复位脉宽 4 × tCLKIN ≈ 0.5µs,取 1ms 余量 */
|
||||
k_msleep(10);
|
||||
gpio_pin_set_dt(&reset_spec, 0);
|
||||
/* 复位释放后芯片执行自校准,等待完成 */
|
||||
k_msleep(10);
|
||||
ads1256_wait_drdy(500);
|
||||
}
|
||||
|
||||
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 };
|
||||
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_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];
|
||||
if (val & 0x800000) val |= 0xFF000000;
|
||||
return val;
|
||||
}
|
||||
|
||||
int ads1256_init(void) {
|
||||
/* GPIO */
|
||||
gpio_pin_configure_dt(&cs_spec, GPIO_OUTPUT_INACTIVE);
|
||||
gpio_pin_configure_dt(&reset_spec, GPIO_OUTPUT_INACTIVE);
|
||||
gpio_pin_configure_dt(&drdy_spec, GPIO_INPUT);
|
||||
|
||||
/* SPI */
|
||||
spi_dev = DEVICE_DT_GET(DT_NODELABEL(spi1));
|
||||
spi_cfg.operation = SPI_OP;
|
||||
spi_cfg.frequency = 500000;
|
||||
spi_cfg.slave = 0;
|
||||
|
||||
if (!device_is_ready(spi_dev)) {
|
||||
LOG_ERR("SPI device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ads1256_hwreset();
|
||||
|
||||
/* 关闭连续输出模式,进入命令模式 */
|
||||
ads1256_write_cmd(CMD_SDATAC);
|
||||
k_busy_wait(100);
|
||||
|
||||
/*
|
||||
* STATUS = 0x06: ORDER=MSB, ACAL=1(自动校准), BUFEN=1(开启输入缓冲)
|
||||
* GML670 50kg 传感器输出阻抗 1kΩ,Buffer OFF + PGA=64 时输入阻抗仅 ~8kΩ
|
||||
* (datasheet Table 10),导致 ~11% 负载误差。开 Buffer 后输入阻抗 >10MΩ。
|
||||
*/
|
||||
ads1256_write_reg(REG_STATUS, 0x06);
|
||||
ads1256_write_reg(REG_MUX, 0x01);
|
||||
/* ADCON: CLK_OUT=OFF, SDCS=OFF, PGA=64 */
|
||||
ads1256_write_reg(REG_ADCON, 0x07);
|
||||
/*
|
||||
* DRATE: 3750 SPS (0xC0)
|
||||
* 50Hz 循环 = 20ms 预算。4 通道各采 10 次均值:
|
||||
* 单通道 = t18(0.44ms) + 9 × 1/3750(0.27ms) = 2.87ms
|
||||
* 4 通道 = 11.5ms,余量 8.5ms
|
||||
* 相比 30kSPS: ENOB 从 16.5 → 17.4 bit (Buffer On, PGA=64)
|
||||
*/
|
||||
ads1256_write_reg(REG_DRATE, 0xC0);
|
||||
|
||||
/* 显式自校准:Buffer/PGA 变更后必须重新校准 (datasheet p25) */
|
||||
ads1256_write_cmd(CMD_SELFCAL);
|
||||
/* SELFCAL 完成后 DRDY 拉低 (datasheet: "Do not send additional commands
|
||||
after issuing this command until DRDY goes low") */
|
||||
ads1256_wait_drdy(500);
|
||||
|
||||
/* 回读关键寄存器验证 SPI 通信正确性 */
|
||||
uint8_t status = ads1256_read_reg(REG_STATUS);
|
||||
uint8_t adcon = ads1256_read_reg(REG_ADCON);
|
||||
uint8_t drate = ads1256_read_reg(REG_DRATE);
|
||||
LOG_INF("ADS1256 regs: STATUS=0x%02X ADCON=0x%02X DRATE=0x%02X", status, adcon, drate);
|
||||
|
||||
if (drate != 0xC0) {
|
||||
LOG_ERR("ADS1256 register verify failed (DRATE=0x%02X, expected 0xC0)", drate);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
LOG_INF("ADS1256 initialized (BUFEN=1, PGA=64, 3750SPS)");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user