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.

[参考译文] ADS8691:实现用于数据采集的转换器

Guru**** 2361250 points
Other Parts Discussed in Thread: ADS8691
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/data-converters-group/data-converters/f/data-converters-forum/1527361/ads8691-implementation-of-the-converter-for-data-acquisition

器件型号:ADS8691

工具/软件:

您好、我写信给您、询问是否有人可以帮助我解决我遇到的问题、我被卡住了。 我将通过 SPI 使用 STM32G431CBU MCU 驱动 ADS8691。 我使用的是双极+和 — 10V 直流连接,有内部基准,所以它被配置成这样,我想?!..
因此、我将这些寄存器初始化如下:  
void ADS8691_Init(uint8_t adc_num)
{
     // 1. Plage d’entrée : Bipolaire ±10.24V 0x0001 dans le registre 0x14
     ADS8691_WriteRegister(adc_num, REG_INPUT_RANGE, RANGE_BIPOLAR_10V24);

     // 2. Référence interne activée en permanence 0x0003 dans le registre 0x3C
     ADS8691_WriteRegister(adc_num, REG_REF_CTRL, REF_INTERNAL_ALWAYS_ON);

    // 3. Configuration ligne SDI : mode normal 0x000 dans le registre 0x3E
    ADS8691_WriteRegister(adc_num, REG_SDI_CTRL, SDI_DEFAULT);

     // 4. Configuration ligne SDO : toujours activée 0x000 dans le registre 0x3F
     ADS8691_WriteRegister(adc_num, REG_SDO_CTRL, SDO_DEFAULT);
}


void ADS8691_WriteRegister(uint8_t adc_num, uint8_t reg, uint16_t value)
{
    uint32_t cmd = CMD_WRITE_REGISTER | ((reg & 0x3F) << 16) | (value & 0xFFFF);
    uint8_t tx[4] = {
        (cmd >> 24) & 0xFF,
        (cmd >> 16) & 0xFF,
        (cmd >> 8)  & 0xFF,
        (cmd >> 0)  & 0xFF
    };

    GPIO_TypeDef* sync_port = (adc_num == 1) ? ADC1_SYNC_GPIO_Port : ADC2_SYNC_GPIO_Port;
    uint16_t sync_pin        = (adc_num == 1) ? ADC1_SYNC_Pin        : ADC2_SYNC_Pin;

    sync_port->BSRR = (uint32_t)sync_pin << 16; // SYNC LOW
    HAL_SPI_Transmit(&hspi2, tx, 4, HAL_MAX_DELAY);
    sync_port->BSRR = sync_pin;                 // SYNC HIGH

    HAL_Delay(1);
}
目前、我的转换值​​没有正确变化、
我尝试验证初始寄存器写入、但无法读取数据。
我尝试从 clk、sdi、sdo 和 sync 振荡命令、似乎对我来说是正确的、但如果我应该在 32 位帧的最后两个字节上有寄存器数据、则什么也没有。
显然、我检查了专用于电压范围 0x14 的寄存器以及 0x00 处的 ID、但其他... 因此我无法获取数据... 因此我不知道它们是否配置正确。
我可以看到 ADS8691 正在做出响应、因为它在 SDO 中使用与 SDI 中查询的寄存器相关的相同数据进行响应?...
float ADS8691_ReadVoltageFast(uint8_t adc_num, float offset_correction)
{
    GPIO_TypeDef* sync_port;
    uint16_t sync_pin;

    if (adc_num == 1) {
        sync_port = ADC1_SYNC_GPIO_Port;
        sync_pin = ADC1_SYNC_Pin;
    } else {
        sync_port = ADC2_SYNC_GPIO_Port;
        sync_pin = ADC2_SYNC_Pin;
    }

    uint8_t tx_buf[4] = {0x00, 0x00, 0x00, 0x00};  // NOP
    uint8_t rx_buf[4] = {0};

    // SYNC LOW
    sync_port->BSRR = (uint32_t)sync_pin << 16;

    HAL_SPI_TransmitReceive(&hspi2, tx_buf, rx_buf, 4, HAL_MAX_DELAY);

    // SYNC HIGH
    sync_port->BSRR = sync_pin;

    uint32_t raw = ((uint32_t)rx_buf[0] << 24) |
                   ((uint32_t)rx_buf[1] << 16) |
                   ((uint32_t)rx_buf[2] << 8)  |
                   ((uint32_t)rx_buf[3]);

    // Sign-extended 18-bit value extraction
    int32_t code = ((int32_t)(raw << 2)) >> 14;

    float voltage = code * 0.000078125f;

    return voltage + offset_correction;
}
感谢你的帮助
此致
Laurent Ifergane
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Laurent:

    SDI 与 SDO 的屏幕截图能更清晰吗?  也许放大 0x28 屏幕截图以更清楚地了解 SPI 接口的设置方式?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好汤姆,并感谢你的宝贵的帮助,因为我在这里有一个困难的时间...
    我附加了一个放大图像、在其中您可以看到在 SDO 中、在 SDI 中寻址的寄存器会重复、但不会将其值返回给我?... 因此、我无法确认最初启动的正确配置、尤其是当我通过在寄存器 0x14 中输入 0x0001 以及内部基准来查询+/–10VDC 的所需双极电压范围时。

    首先、似乎考虑地址寄存器、因为它在 SDO 中引用、但数据始终为 00…… 这是因为它真的是在 00 还是不?...

    哈、是的、我忘记了读取寄存器的功能  

    uint16_t ADS8691_ReadRegister(uint8_t adc_num, uint16_t reg_addr)
    {
        GPIO_TypeDef* sync_port;
        uint16_t sync_pin;
    
        if (adc_num == 1) {
            sync_port = ADC1_SYNC_GPIO_Port;
            sync_pin = ADC1_SYNC_Pin;
        } else {
            sync_port = ADC2_SYNC_GPIO_Port;
            sync_pin = ADC2_SYNC_Pin;
        }
    
        uint8_t cmd_byte = 0xC8 | ((reg_addr >> 7) & 0x03);
        uint8_t addr_byte = reg_addr & 0xFF;
    
        uint8_t tx_buf[4] = { cmd_byte, addr_byte, 0x00, 0x00 };
        uint8_t rx_buf[4] = {0};
    
        // SYNC LOW
        sync_port->BSRR = (uint32_t)sync_pin << 16;
    
        // 1) Envoi commande lecture
        HAL_SPI_Transmit(&hspi2, tx_buf, 4, HAL_MAX_DELAY);
    
        // 2) Envoi 4 octets dummy + lecture donnée
        uint8_t dummy[4] = {0,0,0,0};
        HAL_SPI_TransmitReceive(&hspi2, dummy, rx_buf, 4, HAL_MAX_DELAY);
    
        // SYNC HIGH
        sync_port->BSRR = sync_pin;
    
        // Retourne les 2 derniers octets (valeur du registre)
        return ((uint16_t)rx_buf[2] << 8) | rx_buf[3];
    }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Laurent:

    我希望你可以放大时基与欧斯科 — 也许只是前 16 个时钟左右?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    抱歉、我进行了另一次测量。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    更好!

    仔细观察会发现、SDI 和 SDO 的相位关系并未对齐。  SDO 在上升 SCLK (CPHA=0) 上有效、而 SDI 在下降时钟沿 (CPHA=1) 上有效。  请尝试更改 控制器以使用 CPOL=0、CPHA=0、然后查看这样是否解决了您的问题。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Tom、感谢您的快速响应。

    我已将 CPOL 和 CPHA 对齐设置为 0、并且我还详细查看了寄存器读取和写入命令。

    如果我理解正确、要进行写入、请在 MSB 中插入命令:
    D0h、D2h、D4h
    读取:
    C8h 或 48h

    我更正了写入和读取函数。

    此外、在我的 init 函数中、除了在 14h 内用于+/–10VDC 电压范围 0001b 的寄存器外、我还记得 SDI 和 SDO 寄存器、以便放置以下内容:
    08h 寄存器中的 0x0
    0Ch 寄存器中的 0x0

    因此我发送:
    0xD0140001 表示电压
    0xD0080000 用于 SDI
    0xD00C0000(对于 SDO)
    如果正确考虑了这一点?...

    发送数据通过示波器上的观察结果确认。

    但是、在读取寄存器、尤其是选择 14h 电压范围时、我仍然看不到其中的内容?...
    在 SDO 中、我可以看到寄存器重复并查询数据的步骤?...

    是否有必要知道我是写正确还是读正确?...

    我写入寄存器 14h

        

    我读了  

    但我看不到数据 0001 后? 16 位

    实际上、除非我弄错了、就好像我请求使用 MSB 中的 48h 命令返回寄存器、而实际上是发送 C8h 只是为了获取数据。

    uint16_t ADS8691_ReadRegister(uint8_t adc_num, uint16_t reg_addr)
    {
        GPIO_TypeDef* sync_port;
        uint16_t sync_pin;
    
        if (adc_num == 1) {
            sync_port = ADC1_SYNC_GPIO_Port;
            sync_pin = ADC1_SYNC_Pin;
        } else {
            sync_port = ADC2_SYNC_GPIO_Port;
            sync_pin = ADC2_SYNC_Pin;
        }
    
        uint8_t cmd_byte = 0xC8 | ((reg_addr >> 7) & 0x03);
        uint8_t addr_byte = reg_addr & 0xFF;
    
        uint8_t tx_buf[4] = { cmd_byte, addr_byte, 0x00, 0x00 };
        uint8_t rx_buf[4] = {0};
    
        // SYNC LOW
        sync_port->BSRR = (uint32_t)sync_pin << 16;
    
        // 1) Envoi commande lecture
        HAL_SPI_Transmit(&hspi2, tx_buf, 4, HAL_MAX_DELAY);
    
        // 2) Envoi 4 octets dummy + lecture donnée
        uint8_t dummy[4] = {0,0,0,0};
        HAL_SPI_TransmitReceive(&hspi2, dummy, rx_buf, 4, HAL_MAX_DELAY);
    
        // SYNC HIGH
        sync_port->BSRR = sync_pin;
    
        // Retourne les 2 derniers octets (valeur du registre)
        return ((uint16_t)rx_buf[2] << 8) | rx_buf[3];
    }

    此致

    Laurent Ifergane

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Laurent:

    请查看数据表第 41 页的最后一段。  是否可以在第一次和第二次 32 位传输之间插入 CONVST/CS 高电平?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    哦、好的、我要测试一下...

    不过、虽然我还没有设法读取寄存器、但我查看了​​ADC 在调试模式下转换后的电压值、经过检查后、在模拟输入端得到了 19.7Vdc、大约 9.5Vdc。 在没有任何逻辑或推理的情况下,我本能地从我的转换中减去了读函数的结果 10 ,所以我从大约 19.7 Vdc 到 9.7 Vdc。 检查其他输入电压值、结果表明这些值​​对应于+10V 到–10V?...
    现在,我不能解释它吗?. 但我会深入研究这个…

    float ADS8691_ReadVoltageFast(uint8_t adc_num, float offset_correction)
    {
        GPIO_TypeDef* sync_port;
        uint16_t sync_pin;
    
        if (adc_num == 1) {
            sync_port = ADC1_SYNC_GPIO_Port;
            sync_pin = ADC1_SYNC_Pin;
        } else {
            sync_port = ADC2_SYNC_GPIO_Port;
            sync_pin = ADC2_SYNC_Pin;
        }
    
        uint8_t tx_buf[4] = {0x00, 0x00, 0x00, 0x00};  // NOP
        uint8_t rx_buf[4] = {0};
    
        // SYNC LOW
        sync_port->BSRR = (uint32_t)sync_pin << 16;
    
        HAL_SPI_TransmitReceive(&hspi2, tx_buf, rx_buf, 4, HAL_MAX_DELAY);
    
        // SYNC HIGH
        sync_port->BSRR = sync_pin;
    
    
    
        //uint32_t raw = ((uint32_t)rx_buf[0] << 24) |
        //               ((uint32_t)rx_buf[1] << 16) |
        //               ((uint32_t)rx_buf[2] << 8)  |
        //               ((uint32_t)rx_buf[3]);
        uint32_t raw = ((uint32_t)rx_buf[0] << 24) | ((uint32_t)rx_buf[1] << 16) |
                       ((uint32_t)rx_buf[2] << 8) | ((uint32_t)rx_buf[3]);
    
    
        code_brut32 = raw ; // test code brut sur 32bit
    
        // Sign-extended 18-bit value extraction
        //int32_t code = ((int32_t)(raw << 2)) >> 14;
    
        int32_t code = (int32_t)(raw >> 14);  // ou (raw >> 14) & 0x3FFFF pour 18 bits signés
    
    
    
        code_brut18 = code ; //test code brut sur 18bit
    
       // float voltage = code * 0.000078125f;
        float voltage = (code * 0.000078125f)-10;
    
        return voltage + offset_correction;
    }

    n 同时、我更正了​​相关寄存器上的读写命令值。

    #define CMD_WRITE4_REGISTER       0xD4000000  // Seulement LSB de 16 bits de données sont écrit
    #define CMD_WRITE0_REGISTER       0xD0000000  //
    #define CMD_WRITE2_REGISTER       0xD2000000  // Seulement les 2 octets de poids fort (MSB) des données de 16 bits
    
    #define CMD_READ4_REGISTER       0x48000000   //read
    #define CMD_READC_REGISTER       0xC8000000   //read_hword
    
    // le registre configure la game de tension et ref interne
    #define REG_INPUT_RANGE  0x14
    #define RANGE_BIPOLAR_10V24     0x1
    
    #define REG_SDI_CTRL             0x08   
    #define SDI_DEFAULT              0x0  // SDI active normal
    
    #define REG_SDO_CTRL             0x0C
    #define SDO_DEFAULT              0x0  // SDO enabled always

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    好的、告诉我您找到了什么。