Tool/software:
The DRDY of ADS1256 has always been at high level, using STM32 hardware SPI. After troubleshooting the hardware, there should be no problem. Could you please help check if there is a problem with the software? If there are any problems, please provide specific modification suggestions. In addition, if there are relevant detailed software settings reference materials, they can also be provided. Thank you!
#include <stdint.h>
#include <rtthread.h>
#include "spi.h"
#include "gpio.h"
#include "ads1256.h"
#define DEBUG_ADS1255
uint8_t ADS125X_Init(ADS125X_t *ads, SPI_HandleTypeDef *hspi, uint8_t drate, uint8_t gain, uint8_t buffer_en)
{
ads->hspix = hspi;
ads->pga = 1 << gain;
ADS125X_CS(ads, 1);
ADS125X_CMD_Send(ads, ADS125X_CMD_REST);
rt_thread_mdelay(5);
ADS125X_CMD_Send(ads, ADS125X_CMD_SDATAC);
uint8_t tmp[5]; // buffer
#ifdef DEBUG_ADS1255
ADS125X_Register_Read(ads, ADS125X_REG_STATUS, tmp, 1);
rt_kprintf("STATUS: %#.2x\n", tmp[0]);
#endif
// enable clockout | ADS125X_PGA1
ADS125X_Register_Write(ads, ADS125X_REG_ADCON, ADS125X_CLKOUT_1 | gain); // enable clockout = clkin/1
#ifdef DEBUG_ADS1255
ADS125X_Register_Read(ads, ADS125X_REG_ADCON, tmp, 1);
rt_kprintf("ADCON: %#.2x\n", tmp[0]);
#endif
ADS125X_Register_Write(ads, ADS125X_REG_DRATE, drate);
#ifdef DEBUG_ADS1255
ADS125X_Register_Read(ads, ADS125X_REG_DRATE, tmp, 1);
rt_kprintf("DRATE: %#.2x\n", tmp[0]);
#endif
ADS125X_Register_Write(ads, ADS125X_REG_IO, 0x00); // all GPIOs are outputs (do not leave floating) - D0 is CLKOUT
#ifdef DEBUG_ADS1255
ADS125X_Register_Read(ads, ADS125X_REG_IO, tmp, 1);
rt_kprintf("IO : %#.2x\n", tmp[0]);
#endif
ADS125X_CMD_Send(ads, ADS125X_CMD_SELFCAL);
ADS125X_CS(ads, 0);
ADS125X_DRDY_Wait(ads); // wait ADS1256 to settle after self calibration
return 0;
}
uint8_t ADS125X_DRDY_Wait(ADS125X_t *ads)
{
while(HAL_GPIO_ReadPin(ads->drdyPort, ads->drdyPin) == GPIO_PIN_SET);
return 0;
}
uint8_t ADS125X_CS(ADS125X_t *ads, uint8_t on)
{
HAL_GPIO_WritePin(ads->csPort, ads->csPin, ((on) ? GPIO_PIN_RESET : GPIO_PIN_SET));
return 0;
}
void ADS125X_ADC_Code2Volt (ADS125X_t *ads, int32_t *pCode, float *pVolt, uint16_t size)
{
for (uint8_t i = 0; i < size; i++)
{
// Vin = Code * 2 * (Vrefp - Vrefn) / ( PGA * 0x7FFFFF )
if (pCode[i] & 0x800000) pCode[i] |= 0xff000000; // fix 2's complement
// do all calculations in float. don't change the order of factors --> (adsCode/0x7fffff) will always return 0
pVolt[i] = ( (float)pCode[i] * (2.0f * ads->vref) ) / ( ads->pga * 8388607.0f ); // 0x7fffff = 8388607.0f
}
}
float ADS125X_ADC_ReadVolt (ADS125X_t *ads)
{
uint8_t spiRx[3] = {0, 0, 0};
spiRx[0] = ADS125X_CMD_RDATA;
ADS125X_CS(ads, 1);
HAL_SPI_Transmit(ads->hspix, spiRx, 1, 10);
rt_thread_mdelay(1);
ADS125X_DRDY_Wait(ads);
HAL_SPI_Receive(ads->hspix, spiRx, 3, 10);
ADS125X_CS(ads, 0);
#ifdef DEBUG_ADS1255
rt_kprintf("RDATA: %#.2x%.2x%.2x\n", spiRx[0], spiRx[1], spiRx[2]);
#endif
// must be signed integer for 2's complement to work
int32_t adsCode = (spiRx[0] << 16) | (spiRx[1] << 8) | (spiRx[2]);
if(adsCode & 0x800000) adsCode |= 0xff000000; // fix 2's complement
// do all calculations in float. don't change the order of factors --> (adsCode/0x7fffff) will always return 0
return ( (float)adsCode * (2.0f * ads->vref) ) / ( ads->pga * 8388607.0f ); // 0x7fffff = 8388607.0f
}
uint8_t ADS125X_Register_Read(ADS125X_t *ads, uint8_t reg, uint8_t* pData, uint8_t n)
{
uint8_t spiTx[2];
spiTx[0] = ADS125X_CMD_RREG | reg; // 1st command byte
spiTx[1] = n-1; // 2nd command byte = bytes to be read -1
ADS125X_CS(ads, 1);
ADS125X_DRDY_Wait(ads);
HAL_SPI_Transmit(ads->hspix, spiTx, 2, 1);
rt_thread_mdelay(1); // t6 delay (50*tCLKIN)
HAL_SPI_Receive(ads->hspix, pData, n, 1);
rt_thread_mdelay(1); // t11 delay
ADS125X_CS(ads, 0);
return 0;
}
uint8_t ADS125X_Register_Write(ADS125X_t *ads, uint8_t reg, uint8_t data)
{
uint8_t spiTx[3];
spiTx[0] = ADS125X_CMD_WREG | reg; // 1st command byte
spiTx[1] = 0; // 2nd command byte = payload length = 1 bytes -1 = 0
spiTx[2] = data;
ADS125X_CS(ads, 1);
ADS125X_DRDY_Wait(ads);
HAL_SPI_Transmit(ads->hspix, spiTx, 3, 10);
rt_thread_mdelay(1);
ADS125X_CS(ads, 0);
return 0;
}
uint8_t ADS125X_CMD_Send(ADS125X_t *ads, uint8_t cmd)
{
uint8_t spiTx = cmd;
ADS125X_CS(ads, 1);
//ADS125X_DRDY_Wait(ads);
HAL_SPI_Transmit(ads->hspix, &spiTx, 1, 1);
ADS125X_CS(ads, 0);
return 0;
}
void ADS125X_Channel_Set(ADS125X_t *ads, int8_t channel)
{
ADS125X_ChannelDiff_Set(ads, channel, ADS125X_MUXN_AINCOM);
}
uint8_t ADS125X_ChannelDiff_Set(ADS125X_t *ads, int8_t p_chan, int8_t n_chan)
{
// uint8_t channels = ((p_chan << 4)&0xF0) | (n_chan & 0x0F);
ADS125X_Register_Write(ads, ADS125X_REG_MUX, p_chan | n_chan);
ADS125X_CMD_Send(ads, ADS125X_CMD_SYNC);
ADS125X_CMD_Send(ads, ADS125X_CMD_WAKEUP);
#ifdef DEBUG_ADS1255
uint8_t tmp = 0;
ADS125X_Register_Read(ads, ADS125X_REG_MUX, &tmp, 1);
rt_kprintf("MUX : %#.2x\n", tmp);
#endif
// ADS125X_CMD_Send(ads, ADS125X_CMD_SYNC);
// ADS125X_CMD_Send(ads, ADS125X_CMD_WAKEUP);
return 0;
}
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <rtthread.h>
#include "ads1256.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
ADS125X_t ads1256;
float volt[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
// HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
// SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
// MX_GPIO_Init();
// MX_USART1_UART_Init();
// MX_SPI2_Init();
/* USER CODE BEGIN 2 */
ads1256.csPort = SPI2_CS_GPIO_Port;
ads1256.csPin = SPI2_CS_Pin;
ads1256.drdyPort = ADS1256_READY_GPIO_Port;
ads1256.drdyPin = ADS1256_READY_Pin;
ads1256.vref = 2.5f;
ads1256.oscFreq = ADS125X_OSC_FREQ;
ADS125X_Init(&ads1256, &hspi2, ADS125X_DRATE_10SPS, ADS125X_GAIN_1, 0);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
rt_kprintf("Hello Quectel\r\n");
rt_thread_mdelay(1000);
ADS125X_ChannelDiff_Set(&ads1256, ADS125X_MUXP_AIN0, ADS125X_MUXN_AIN1);
volt[0] = ADS125X_ADC_ReadVolt(&ads1256);
rt_kprintf("volt0 = %f\n", volt[0]);
ADS125X_ChannelDiff_Set(&ads1256, ADS125X_MUXP_AIN1, ADS125X_MUXN_AIN2);
volt[1] = ADS125X_ADC_ReadVolt(&ads1256);
rt_kprintf("volt1 = %f\n", volt[1]);
ADS125X_ChannelDiff_Set(&ads1256, ADS125X_MUXP_AIN2, ADS125X_MUXN_AIN3);
// ADS125X_CMD_Send(&ads1256, ADS125X_CMD_SYNC);
volt[2] = ADS125X_ADC_ReadVolt(&ads1256);
rt_kprintf("volt2 = %f\n", volt[2]);
ADS125X_ChannelDiff_Set(&ads1256, ADS125X_MUXP_AIN3, ADS125X_MUXN_AIN4);
volt[3] = ADS125X_ADC_ReadVolt(&ads1256);
rt_kprintf("volt3 = %f\n", volt[3]);
ADS125X_ChannelDiff_Set(&ads1256, ADS125X_MUXP_AIN4, ADS125X_MUXN_AIN5);
volt[4] = ADS125X_ADC_ReadVolt(&ads1256);
rt_kprintf("volt4 = %f\n", volt[4]);
ADS125X_ChannelDiff_Set(&ads1256, ADS125X_MUXP_AIN5, ADS125X_MUXN_AIN6);
volt[5] = ADS125X_ADC_ReadVolt(&ads1256);
rt_kprintf("volt5 = %f\n", volt[5]);
ADS125X_ChannelDiff_Set(&ads1256, ADS125X_MUXP_AIN6, ADS125X_MUXN_AIN7);
volt[6] = ADS125X_ADC_ReadVolt(&ads1256);
rt_kprintf("volt6 = %f\n", volt[6]);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief Period elapsed callback in non blocking mode
* @note This function is called when TIM1 interrupt took place, inside
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
* a global variable "uwTick" used as application time base.
* @param htim : TIM handle
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM1) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
/* USER CODE END Callback 1 */
}
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file spi.c
* @brief This file provides code for the configuration
* of the SPI instances.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "spi.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
SPI_HandleTypeDef hspi2;
/* SPI2 init function */
void MX_SPI2_Init(void)
{
/* USER CODE BEGIN SPI2_Init 0 */
/* USER CODE END SPI2_Init 0 */
/* USER CODE BEGIN SPI2_Init 1 */
/* USER CODE END SPI2_Init 1 */
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI2_Init 2 */
/* USER CODE END SPI2_Init 2 */
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(spiHandle->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */
/* USER CODE END SPI2_MspInit 0 */
/* SPI2 clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI2 GPIO Configuration
PB13 ------> SPI2_SCK
PB14 ------> SPI2_MISO
PB15 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN SPI2_MspInit 1 */
/* USER CODE END SPI2_MspInit 1 */
}
}
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{
if(spiHandle->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspDeInit 0 */
/* USER CODE END SPI2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_SPI2_CLK_DISABLE();
/**SPI2 GPIO Configuration
PB13 ------> SPI2_SCK
PB14 ------> SPI2_MISO
PB15 ------> SPI2_MOSI
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15);
/* USER CODE BEGIN SPI2_MspDeInit 1 */
/* USER CODE END SPI2_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */