This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ADS131M02: DRDY引脚时钟处于高电平状态,无法得到ADC的输出。

Part Number: ADS131M02

我在初步尝试在arduino内进行编程并使用该模块,目前通过串口我可以得到ID号,我想这说明目前的MCU和adc是可以正常进行SPI通信的。但我遇到的问题是,在我利用信号发生器产生一个±500mv的50hz正弦差分信号输入到ADC的通道1后,ADC的输出始终是一个恒定的值。通过示波器和status寄存器我发现drdy引脚时钟处于高电平状态未发生改变,请问这是什么原因。我已经附上了我的寄存器配置值供您查看。我已经验证过目前的寄存器值被正确写入,因为我通过读取寄存器得到了相应的值与我写入的值相符合。同时我还附上了我的arduino编程代码和相应的库文件,很希望得到您的帮助,十分感激。

.ino
#include <SPI.h>
#include "ADS131M04.h"
#include "registerDefinitions.h"

#define CS_PIN    WB_SPI_CS   // 你的 CS 引脚
#define DRDY_PIN   WB_IO1         // 你把 DRDY 接到哪,就填哪

// SPI 命令定义(参考 ADS131M0x 手册)
#define CMD_RESET    0x11
#define CMD_START    0x33
#define CMD_STOP     0x0A

ADS131M04 adc(CS_PIN, -1, &SPI);
int8_t channelIds[2] = {0, 1};

void sendCommand(uint16_t cmd) {
  
  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE1));
  digitalWrite(CS_PIN, LOW);
    SPI.transfer16(cmd);
  digitalWrite(CS_PIN, HIGH);
  SPI.endTransaction();
}

void setup() {
  Serial.begin(115200);
  while (!Serial);

  pinMode(CS_PIN, OUTPUT);
  digitalWrite(CS_PIN, HIGH);
  pinMode(DRDY_PIN, INPUT);

  // 初始化 SPI
  SPI.begin();

  // 初始化 ADC(只做 SPI 设置,不会自动 START)
  adc.begin();
  Serial.println("ADC 初始化完成");

  // 先 RESET 一下,确保回到默认状态
  sendCommand(CMD_RESET);
  delay(10);

  

  //读一次 STATUS 寄存器
  uint16_t status = adc.readReg(STATUS);
  Serial.print("读取 STATUS 寄存器: 0x");
  Serial.println(status, HEX);

  //读一次 ID 寄存器
  uint16_t tmp;
  tmp = adc.readReg(ID);
  Serial.print("ID = 0x"); Serial.println(tmp, HEX);

  // 写寄存器配置
  adc.writeReg(GAIN1,      0x0000);  Serial.println("GAIN1 写入");
  adc.writeReg(CFG,        0x0600);  Serial.println("CFG 写入");
  adc.writeReg(MODE,       0x0514);  Serial.println("MODE 写入");
  adc.writeReg(CLOCK,      0x010E);  Serial.println("CLOCK 写入");
  adc.writeReg(THRSHLD_MSB,0x0000);  Serial.println("THRSHLD_MSB 写入");
  adc.writeReg(THRSHLD_LSB,0x0000);  Serial.println("THRSHLD_LSB 写入");
  adc.writeReg(CH0_CFG,    0x0000);  Serial.println("CH0_CFG 写入");
  adc.writeReg(CH0_OCAL_MSB,0x0000); Serial.println("CH0_OCAL_MSB 写入");
  adc.writeReg(CH0_OCAL_LSB,0x0000); Serial.println("CH0_OCAL_LSB 写入");
  adc.writeReg(CH0_GCAL_MSB,0x0000); Serial.println("CH0_GCAL_MSB 写入");
  adc.writeReg(CH0_GCAL_LSB,0x0000); Serial.println("CH0_GCAL_LSB 写入");
  adc.writeReg(REGMAP_CRC,  0x0000);  Serial.println("REGMAP_CRC 写入");
  adc.writeReg(RESERVED,    0x0000);  Serial.println("RESERVED 写入");

  // 再次读寄存器验证
  Serial.println("\n寄存器回读:");
  #define RD(reg) \
    tmp = adc.readReg(reg); \
    Serial.print(#reg); Serial.print(" = 0x"); Serial.println(tmp, HEX);
  RD(GAIN1); RD(CFG); RD(MODE); RD(CLOCK);
  RD(THRSHLD_MSB); RD(THRSHLD_LSB);
  RD(CH0_CFG); RD(CH0_OCAL_MSB); RD(CH0_OCAL_LSB);
  RD(CH0_GCAL_MSB); RD(CH0_GCAL_LSB);
  RD(REGMAP_CRC); RD(RESERVED);
  #undef RD

  // 最后发送 START 命令,开始连续转换
  sendCommand(CMD_START);
  delay(10);
  Serial.println("发送 START,开始转换");
}

void loop() {
  // 等待 DRDY 低电平(新数据准备好)
  if (digitalRead(DRDY_PIN) == LOW) {
    int32_t adcData[2] = {0};
    adc.rawChannels(channelIds, 2, adcData);
    Serial.print("ADC 数据:");
    for (uint8_t i = 0; i < 2; i++) {
      Serial.print("Ch"); Serial.print(channelIds[i]);
      Serial.print(" = "); Serial.print(adcData[i]);
      Serial.print("  ");
    }
    Serial.println();
  }
  // 如果想更精细地控制读取频率,可以在此加个小延时
  delay(1000);
}
ADS131M04.h
/* This is a library for the ADS131M04 4-channel ADC
   
   Product information:
   https://www.ti.com/product/ADS131M04

   Datasheet: 
   https://www.ti.com/lit/gpn/ads131m04

   This library was made for Imperial College London Rocketry
   Created by Daniele Valentino Bella
*/

#define CLKIN_SPD 8192000 // Clock speed for the CLKIN pin on the DAC
#define SCLK_SPD 4000000 // SPI frequency of DAC

#ifndef ADS131M04_H
#define ADS131M04_H

#include <Arduino.h>
#include <SPI.h>
#include "registerDefinitions.h"

class ADS131M04 {
  public:
    ADS131M04(int8_t _csPin, int8_t _clkoutPin, SPIClass* _spi, int8_t _clockCh = 1);
    void begin(void);
    void rawChannels(int8_t * channelArrPtr, int8_t channelArrLen, int32_t * outputArrPtr);
    int32_t rawChannelSingle(int8_t channel);
    uint16_t readReg(uint8_t reg);
    bool writeReg(uint8_t reg, uint16_t data);
    bool setGain(uint8_t log2Gain0 = 0, uint8_t log2Gain1 = 0, uint8_t log2Gain2 = 0, uint8_t log2Gain3 = 0);
    bool globalChop(bool enabled = false, uint8_t log2delay = 4);

  private:
    int8_t csPin, clkoutPin, clockCh;
    SPIClass* spi;
    bool initialised;
    
    void spiCommFrame(uint32_t * outputArray, uint16_t command = 0x0000);
    uint32_t spiTransferWord(uint16_t inputData = 0x0000);
    int32_t twoCompDeco(uint32_t data);
};

#endif
ADS131M04.cpp
/* This is a library for the ADS131M04 4-channel ADC
   
   Product information:
   https://www.ti.com/product/ADS131M04

   Datasheet: 
   https://www.ti.com/lit/gpn/ads131m04

   This library was made for Imperial College London Rocketry
   Created by Daniele Valentino Bella & Iris Clercq-Roques
*/

#include <Arduino.h>
#include <SPI.h>
#include "registerDefinitions.h"
#include "ADS131M04.h"

ADS131M04::ADS131M04(int8_t _csPin, int8_t _clkoutPin, SPIClass* _spi, int8_t _clockCh) {
  csPin = _csPin;
  clkoutPin = _clkoutPin;
  spi = _spi;
  clockCh = _clockCh;
  initialised = false;
}

void ADS131M04::begin(void) {
  pinMode(csPin, OUTPUT);
  digitalWrite(csPin, HIGH);

  spi->begin();

  // // Set CLKOUT on the ESP32 to give the correct frequency for CLKIN on the DAC
  // ledcSetup(clockCh, CLKIN_SPD, 2);
  // ledcAttachPin(clkoutPin, clockCh);
  // ledcWrite(clockCh, 2);

  initialised=true;
}

void ADS131M04::rawChannels(int8_t * channelArrPtr, int8_t channelArrLen, int32_t * outputArrPtr) {
  /* Writes data from the channels specified in channelArr, to outputArr,
     in the correct order.

     channelArr should have values from 0-3, and channelArrLen should be the
     length of that array, starting from 1.
  */
  
  uint32_t rawDataArr[6];

  // Get data
  spiCommFrame(&rawDataArr[0]);
  
  // Save the decoded data for each of the channels
  for (int8_t i = 0; i<channelArrLen; i++) {
    *outputArrPtr = twoCompDeco(rawDataArr[*channelArrPtr+1]);
    outputArrPtr++;
    channelArrPtr++;
  }
}

int32_t ADS131M04::rawChannelSingle(int8_t channel) {
  /* Returns raw value from a single channel
     channel input from 0-3
  */
  
  int32_t outputArr[1];
  int8_t channelArr[1] = {channel};

  rawChannels(&channelArr[0], 1, &outputArr[0]);

  return outputArr[0];
}

bool ADS131M04::globalChop(bool enabled, uint8_t log2delay) {
  /* Function to configure global chop mode for the ADS131M04.

     INPUTS:
     enabled - Whether to enable global-chop mode.
     log2delay   - Base 2 log of the desired delay in modulator clocks periods
     before measurment begins
     Possible values are between and including 1 and 16, to give delays
     between 2 and 65536 clock periods respectively
     For more information, refer to the datasheet.

     Returns true if settings were written succesfully.
  */

  uint8_t delayRegData = log2delay - 1;

  // Get current settings for current detect mode from the CFG register
  uint16_t currentDetSett = (readReg(CFG) << 8) >>8;
  
  uint16_t newRegData = (delayRegData << 12) + (enabled << 8) + currentDetSett;

  return writeReg(CFG, newRegData);
}

bool ADS131M04::writeReg(uint8_t reg, uint16_t data) {
  /* Writes the content of data to the register reg
     Returns true if successful
  */
  
  uint8_t commandPref = 0x06;

  // Make command word using syntax found in data sheet
  uint16_t commandWord = (commandPref<<12) + (reg<<7);

  digitalWrite(csPin, LOW);
  spi->beginTransaction(SPISettings(SCLK_SPD, MSBFIRST, SPI_MODE1));

  spiTransferWord(commandWord);
  
  spiTransferWord(data);

  // Send 4 empty words
  for (uint8_t i=0; i<4; i++) {
    spiTransferWord();
  }

  spi->endTransaction();
  digitalWrite(csPin, HIGH);

  // Get response
  uint32_t responseArr[6];
  spiCommFrame(&responseArr[0]);

  if ( ( (0x04<<12) + (reg<<7) ) == responseArr[0]) {
    return true;
  } else {
    return false;
  }
}

bool ADS131M04::setGain(uint8_t log2Gain0, uint8_t log2gainCommand, uint8_t log2Gain2, uint8_t log2Gain3) {
  /* Function to set the gain of the four channels of the ADC
     
     Inputs are the log base 2 of the desired gain to be applied to each
     channel.

     Returns true if gain was succesfully set.

     Function written by Iris Clercq-Roques
  */
  uint16_t gainCommand=log2Gain3<<4;
  gainCommand+=log2Gain2;
  gainCommand<<=8;
  gainCommand+=(log2gainCommand<<4);
  gainCommand+=log2Gain0;
  return writeReg(GAIN1, gainCommand);
}

uint16_t ADS131M04::readReg(uint8_t reg) {
  /* Reads the content of single register found at address reg
     Returns register value
  */
  
  uint8_t commandPref = 0x0A;

  // Make command word using syntax found in data sheet
  uint16_t commandWord = (commandPref << 12) + (reg << 7);

  uint32_t responseArr[6];

  // Use first frame to send command
  spiCommFrame(&responseArr[0], commandWord);

  // Read response
  spiCommFrame(&responseArr[0]);

  return responseArr[0] >> 16;
}

uint32_t ADS131M04::spiTransferWord(uint16_t inputData) {
  /* Transfer a 24 bit word
     Data returned is MSB aligned
  */ 

  uint32_t data = spi->transfer(inputData >> 8);
  data <<= 8;
  data |= spi->transfer((inputData<<8) >> 8);
  data <<= 8;
  data |= spi->transfer(0x00);

  return data << 8;
}

void ADS131M04::spiCommFrame(uint32_t * outPtr, uint16_t command) {
  // Saves all the data of a communication frame to an array with pointer outPtr

  digitalWrite(csPin, LOW);

  spi->beginTransaction(SPISettings(SCLK_SPD, MSBFIRST, SPI_MODE1));

  // Send the command in the first word
  *outPtr = spiTransferWord(command);

  // For the next 4 words, just read the data
  for (uint8_t i=1; i < 3; i++) {
    outPtr++;
    *outPtr = spiTransferWord() >> 8;
  }

  // Save CRC bits
  // outPtr++;
  // *outPtr = spiTransferWord();

  spi->endTransaction();

  digitalWrite(csPin, HIGH);
}

int32_t ADS131M04::twoCompDeco(uint32_t data) {
  // Take the two's complement of the data

  data <<= 8;
  int32_t dataInt = (int)data;

  return dataInt/pow(2,8);
}