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.

[参考译文] ADS131M08EVM:使用 STM32.Need C 样例驱动程序代码从 ADS131M08EVM 读取数据时出现问题

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

https://e2e.ti.com/support/data-converters-group/data-converters/f/data-converters-forum/1068276/ads131m08evm-issues-reading-data-from-ads131m08evm-with-stm32-need-c-sample-driver-code

部件号:ADS131M08EVM
“线程”中讨论的其它部件: ADS131M08ADS131M06

大家好,希望你们做得好!

我和我的团队正在开发一个能量计,使用具有 HAL 库的 MCU STM32F756ZG 和一个 ADS131M08EVM 来获取信号。

我们能够启动 STM32和 ADSADS131M08EVM 之间的通信,并将 OSR 更改为128,然后看到对 DRDY 引脚的监控发生了变化。 ´re 我们发现了一些问题:

第一个问题是,当我们向 ADSADS131M08EVM 发送命令时,答案 第一次不正确。 例如,当我们发送命令“状态”时,我们希望得到“0x500”的答案,我们 只在几次之后才收到这一答案。 我们正在尝试“状态”和“时钟”命令。 我们只能更改将命令置于 while 循环中的时钟,我们发送命令直到收到正确的答案。

第二个问题,也是主要问题,是我们无法读取 ADS131M08EVM 通道的数据,我们可以在 IDE 中看到 SPI 的数据,但数据与实际值不符。

 您是否有使用 MCU STM32和 ADS131M08EVM 的示例 C 代码?

如果需要,我可以共享我的.C 和.H 代码。

此致

拉斐尔·克塞西

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

    拉斐尔

    我们在 STM32的度量学库中没有示例代码,因为它不是 TI 处理器。 但是,我们过去曾有客户将此库移植到 STM32。 请发送以下标题文件以了解您的配置:

    • emeter 应用程序/metrology-template.h
    • 电子度量衡/metrology-template.h

    另外,请发送 SPI 传输的逻辑分析器输出,以了解 SPI 总线上发送和接收的值。

    需要考虑的几件事:

    • 确保已定义 ADS131M08_configuration,以便将适当数量的通道用于 SPI 传输。 在发行代码上,如果设置了 xTIDA010225_connections,则定义此值。
    • 确保向 ADS131M08发送有效时钟,并在 metrology-template.h 中选择适当的采样率,并将输入时钟速率与 ADS131M08对应。

    此致,
    佩德罗

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

    您好,佩德罗,谢谢您的快速回答。

    我和我的同事交谈过,但我们没有找到 TIDA010225,您能否向我们发送此文档?

    下面是我们的代码:

    头文件:

    /*
     * ads131m06.h
     *
     *  Created on: 10 de nov de 2021
     *      Author: rsk
     */
    
    #ifndef INC_ADS131M06_H_
    #define INC_ADS131M06_H_
    
    // C Standard Libraries
    #include <assert.h>
    #include <stdint.h>
    
    #include "main.h"
    #include "spi.h"
    #include "gpio.h"
    
    
    
    //****************************************************************************
    //
    //  GENERAL DEFINITIONS
    //
    //****************************************************************************
    
    #define ADS131M06_NUM_CHANNELS 		8		//	!!!!MODIFICAR PARA O ADS DE 6 CANAIS!!!!
    #define ADS131M06_WORD_SIZE 		3
    
    typedef struct _ADS131M06Data_t_
    {
    	int32_t Ch0;
    	int32_t Ch1;
    	int32_t Ch2;
    	int32_t Ch3;
    	int32_t Ch4;
    	int32_t Ch5;
    	int32_t Ch6;			//	!!!!MODIFICAR PARA O ADS DE 6 CANAIS!!!!
    	int32_t Ch7;			//	!!!!MODIFICAR PARA O ADS DE 6 CANAIS!!!!
    	uint16_t Status;
    	uint16_t Checksum;
    } ADS131M06Data_t;
    
    extern ADS131M06Data_t ADSChannelData;
    
    //****************************************************************************
    //
    //  ADS131M08 COMMANDS
    //
    //****************************************************************************
    //System Commands
    #define ADS131M06_CMD_NULL						((uint16_t) 0x0000)
    #define ADS131M06_CMD_RESET						((uint16_t) 0x0011)
    #define ADS131M06_CMD_STANDBY					((uint16_t) 0x0022)
    #define ADS131M06_CMD_WAKEUP					((uint16_t) 0x0033)
    #define ADS131M06_CMD_LOCK						((uint16_t) 0x0555)
    #define ADS131M06_CMD_UNLOCK					((uint16_t) 0x0655)
    
    //Registers Read/Write Commands
    #define ADS131M06_CMD_RREG						((uint16_t) 0xA000)
    #define ADS131M06_CMD_RREGS						((uint16_t) 0xA000)
    #define ADS131M06_CMD_WREG						((uint16_t) 0x6000)
    #define ADS131M06_CMD_WREGS						((uint16_t) 0x6000)
    
    
    
    //****************************************************************************
    //
    //  ADS131M08 REGISTERS
    //
    //****************************************************************************
    
    /* Register 0x00 (ID) definition - READ ONLY */
    #define ID_ADDRESS                              ((uint8_t)  0x00)
    #define ID_DEFAULT                              ((uint16_t) 0x2000 | (ADS131M06_NUM_CHANNELS << 8))
    /* Register 0x01 (STATUS) definition - READ ONLY */
    #define STATUS_ADDRESS                          ((uint8_t)  0x01)
    #define STATUS_DEFAULT                          ((uint16_t) 0x0500)
    /* Register 0x02 (MODE) definition */
    #define MODE_ADDRESS                            ((uint8_t)  0x02)
    #define MODE_DEFAULT                            ((uint16_t) 0x0510)
    /* Register 0x03 (CLOCK) definition */
    #define CLOCK_ADDRESS                           ((uint8_t)  0x03)
    #define CLOCK_DEFAULT                           ((uint16_t) 0xFF02)	//OSR = 128 -> 32 kHz sample frequency
    
    
    
    
    //****************************************************************************
    //
    //  FUNCTION PROTOTYPES
    //
    //****************************************************************************
    
    // Low level
    void 	 ADS131M06Reset(void);
    void 	 ADS131M06SetCS (uint8_t state);
    void 	 ADS131M06XferWord(uint8_t* txData, uint8_t* rxData);
    uint16_t ADS131M06SendCmd(uint16_t cmd);
    
    // Higher level
    uint16_t ADS131M06WriteRegister(uint8_t reg, uint8_t data);
    void	 ADS131M06Init(void);
    void	 ADS131M06GetChannels(void);
    void 	 ADS_Init(void);
    
    #endif /* INC_ADS131M06_H_ */

    和 C 代码。

    #include "ads131m06.h"
    #include "calcFunctions.h"
    #include "spi.h"
    #include "gpio.h"
    
    
    
    
    extern SPI_HandleTypeDef hspi4;
    uint8_t emptyTxBuffer[ADS131M06_WORD_SIZE*(ADS131M06_NUM_CHANNELS+1)] = {0};
    uint8_t ADS131M06_DataBuf[ADS131M06_WORD_SIZE*(ADS131M06_NUM_CHANNELS+1)];
    volatile uint8_t ADS131M06_Ready_flag = 0;
    uint8_t ADS131M06_Init_Done = 0;
    float verFS = FS;
    
    ADS131M06Data_t ADSChannelData;
    
    
    //****************************************************************************
    //
    //  LOW LEVEL FUNCTIONS
    //
    //****************************************************************************
    
    // Transmit/Receive data (write/read register)
    void ADS131M06XferWord(uint8_t* txData, uint8_t* rxData)
    {
    
    	//HAL_SPI_TransmitReceive_IT(&hspi4, txData, rxData, ADS131M06_WORD_SIZE);
    	HAL_SPI_TransmitReceive(&hspi4, txData, rxData, ADS131M06_WORD_SIZE,1);
    
    }
    
    // Transmit/Receive system command
    uint16_t ADS131M06SendCmd(uint16_t cmd)
    {
    
    	uint8_t txData[ADS131M06_WORD_SIZE] = {0};
    	static uint8_t rxData[ADS131M06_WORD_SIZE];
    	uint16_t res = 0;
    
    	//split 16bit cmd in 8bit array
    	txData[1] = (cmd & 0xff);
    	txData[0] = (cmd >> 8);
    
    	//Send the command
    	ADS131M06XferWord(txData, rxData);
    
    	//The response of the previous cmd is in the next response
    	//So send another empty cmd to get the response
    	//Collapse response
    	res = (((uint16_t)rxData[0] << 8) | rxData[1]);
    
    	return res;
    
    }
    
    
    
    //****************************************************************************
    //
    //  HIGH LEVEL FUNCTIONS
    //
    //****************************************************************************
    
    // Write single register function
    uint16_t ADS131M06WriteRegister(uint8_t addr, uint8_t data)
    {
    
    	uint16_t word = (ADS131M06_CMD_WREG | (addr<<7));
    
    	uint16_t value = ADS131M06SendCmd(word);
    	word = (0xff << 8) | data;
    	value = ADS131M06SendCmd(word);
    
    	return value;
    
    }
    
    // Check the status and set the sampling rate to 32 kSPS -> 32 kHz
    void ADS131M06Init(void)
    {
    
    	uint16_t status = ADS131M06SendCmd((uint16_t) 0x0000);
    
    	while(status != 0x0500){
    		status = ADS131M06SendCmd(0x0000);
    	}
    	HAL_GPIO_TogglePin(blueLed);
    	uint16_t responseWREG = ADS131M06WriteRegister(CLOCK_ADDRESS, 0xFF02);
    
    	while(responseWREG != 0x4180){
    		responseWREG = ADS131M06WriteRegister(CLOCK_ADDRESS, 0xFF02);//CLOCK_DEFAULT);
    	}
    	HAL_GPIO_TogglePin(greenLed);
    }
    
    // Concatenate to result in 24bit read
    void ADS131M06GetChannels(void)
    {
    
    	ADSChannelData.Status = ADS131M06_DataBuf[0]<<8 | ADS131M06_DataBuf[1];
    	ADSChannelData.Ch0 = (ADS131M06_DataBuf[4] << 16) | (ADS131M06_DataBuf[5] << 8) | (ADS131M06_DataBuf[6]);
    	
    
    	ADSChannelData.Ch1 = (ADS131M06_DataBuf[8] << 16) | (ADS131M06_DataBuf[9] << 8) | (ADS131M06_DataBuf[10]);
    	ADSChannelData.Ch2 = (ADS131M06_DataBuf[12] << 16) | (ADS131M06_DataBuf[13] << 8) | (ADS131M06_DataBuf[14]);
    	ADSChannelData.Ch3 = (ADS131M06_DataBuf[16] << 16) | (ADS131M06_DataBuf[17] << 8) | (ADS131M06_DataBuf[18]);
    	ADSChannelData.Ch4 = (ADS131M06_DataBuf[20] << 16) | (ADS131M06_DataBuf[21] << 8) | (ADS131M06_DataBuf[22]);
    	ADSChannelData.Ch5 = (ADS131M06_DataBuf[24] << 16) | (ADS131M06_DataBuf[25] << 8) | (ADS131M06_DataBuf[26]);
    
    
    	ADSChannelData.Ch6 = (ADS131M06_DataBuf[28] << 16) | (ADS131M06_DataBuf[29] << 8) | (ADS131M06_DataBuf[30]);
    	ADSChannelData.Ch7 = (ADS131M06_DataBuf[32] << 16) | (ADS131M06_DataBuf[33] << 8) | (ADS131M06_DataBuf[34]);
    
    }
    
    // Initializes ADS and after that, enable the DRDY_Pin interruption to get ADC data
    void ADS_Init(void)
    {
    
    	ADS131M06Init();
    	CalcFunctions_Reset();
    	CalcFunctions_Init();
    
    
    	ADS131M06_Init_Done = 1;
    
    	// EXTI interrupt init
    	HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
    	HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
    
    }
    
    // DRDY interruption
    // Executes every DRDY_GPIO_PIN interruption = 32 kHz
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    	if(GPIO_Pin == DRDY_ADS_Pin && ADS131M06_Init_Done == 1)
    	{
    		//SPI Interrupt
    		HAL_NVIC_SetPriority(SPI4_IRQn, 0, 0);
    	    HAL_NVIC_EnableIRQ(SPI4_IRQn);
    		//ADS131M06_Ready_flag = 1;
    	
    		/* Read ADS registers via SPI */
    
    		HAL_SPI_TransmitReceive_IT(&hspi4, &emptyTxBuffer[0], &ADS131M06_DataBuf, ADS131M06_WORD_SIZE*(ADS131M06_NUM_CHANNELS+1));
    		CalcFunctions_Run(ADSChannelData);
    
    	
    
    	}
    }
    
    void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef * hspi)
    {
    	HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_11);
    	ADS131M06GetChannels();
    
    
    }
    
    
    //****************************************************************************
    //
    //  EXAMPLE OF DATA FRAME
    //
    //****************************************************************************
    
    /*
     * Set OSR = 128 by writing in the COLCK register
     *
     * 011a aaaa annn nnnn 	= OPCODE_WREG 		= 0x6000 	= 0110 0000 0000 0000
     * a aaaa a 			= CLOCK_ADDRESS 	= 0x03 		= 0011
     * nnn nnnn				= NUMBER_REG - 1	= 0x00 		= 000 0000
     * 		 				= COMMAND			= 0x6180	= 0110 0001 1000 0000
     *														= 0100 0001 1000 0000
     * DATA					= CLOCK_DEFAULT		= 0xFF02	= 1111 1111 0000 0010 - OSR = 128
     *
     * dataTxX[0] = 0x61;
     * dataTxX[1] = 0x80;
     * dataTxX[2] = 0xFF;
     * dataTxX[3] = 0x02;
     * spiSendReceiveArrays(dataTxX, dataRxX, 4);
     */
    

    逻辑分析器的输出和 SPI 数据我明天将能够发送给您。

    感谢你的帮助。

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

    拉斐尔

    我误解了你最初提出的问题的一部分。 我假设您已经下载 了能源计量库。 该库具有电表,配电装置(PDU)和断路器的代码。 它还 包括用于 ADS131M0x 设备的硬件抽象驱动程序。 它已针对 MSP432P 处理器进行了编译,但客户已使用随附的 CMSIS SPI 驱动程序移植到 STM32。 如果代码是使用 IAR IDE 编译的 ,则将使用 CMSIS 驱动程序,因为它定义了__ICCARM__。

    ADS131M0x C 代码位于 ADC/adchal.c 和 ADC/ads131m0x.C 文件夹中

    此外   ,ADS131M0x 示例 C 代码中还有一个具有类似驱动程序的 C 代码示例

    文件 ads131m0x.c 具有一个例程 buildSPIarray,用于显示如何创建命令字节。 注意 SPI 帧大小取决于设备中编程的单词大小。  通过对模式寄存器中的 WLENGTH[1:0]位进行编程,单词大小可配置为16位,24位或32位。  当 ADC 被禁用且 没有输出转换数据时,主机可以缩短数据帧。 有关人工缩短通信帧的详细信息,请参阅“短 SPI 帧”部分。 为了简化操作,我倾向于只使用固定 SPI 帧集,将其设置为正常长度的 SPI 帧。 简言之,SPI 帧大小为:

    NumberOfBytes =  (CommandWords + optionalCRCWord)* WLENGTH_Bytes

    因此,命令可能包含2,3或4个单词,每个单词为16位(2字节),24位(3字节)或32位(4字节)。

      在您的代码中,命令似乎仅为3个字节  

    UINT8_t txData[ADS131M06_WORD_SIZE]  

    #define ADS131M06_word_size 3.

    对于 某些命令来说,这可能太短。 使用时, 上述 NumberOfBytes 的定义将启用 CRC,并将设备编程为24位转换

    -对于 RREG,有1个命令字带有 opcode:

    opcode = opcode_RREG |((((uint16_t) address)<<7);

    NumberOfBytes =(1 + 1) * 3 = 6

    -对于 WREG,有两个命令字带有操作码:

    opcodes[0]= opcode_WREG |((((uint16_t) address)<<7);
    opcodes[1]=数据;

    NumberOfBytes =(2 + 1) * 3 = 9

    -对于其他命令,有两个命令字带有操作码:

    opcode =命令
    NumberOfBytes =(1 + 1) * 3 = 6

    使用, 上述 numberOfBytes 定义(不启用 CRC)和设备的定义被编程为24位转换

    -对于 RREG,有1个命令字带有 opcode:

    opcode = opcode_RREG |((((uint16_t) address)<<7);

    NumberOfBytes =(1 + 0) * 3 = 3

    -对于 WREG,有两个命令字带有操作码:

    opcodes[0]= opcode_WREG |((((uint16_t) address)<<7);
    opcodes[1]=数据;

    NumberOfBytes =(2 + 0) * 3 = 6

    -对于其他命令,有两个命令字带有操作码:

    opcode =命令
    NumberOfBytes =(1 + 0) * 3 = 3

    有关    更多示例,请参阅 ADS131M0x 示例 C 代码或能源计量库 C 代码。

    此致,
    佩德罗