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.

ADS1256: Can't get right values of conversion

Part Number: ADS1256

Hello,

I have a  ADS1256 that I would like to interface via SPI to the microcontroller STM32F107RCT6.

I wrote the driver, but still can't get right result of conversion.

First of all, my schematic:

R1-R4 is voltage divider with coef. 8.

R5-R6 & C1-C3 - antialiasing filter.

Other elements are in accordance with datasheet.

SPI and MCU config:

And driver code:

/**
  ******************************************************************************
  * File Name          : main.c
  * Description        : Main program body
  ******************************************************************************
  ** This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * COPYRIGHT(c) 2018 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_hal.h"
#include "stdio.h"

/* USER CODE BEGIN Includes */
#define CS_ON() 			HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET) // Enable CS
#define CS_OFF() 			HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET) // Disable CS
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi3;
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t spiTxBuf[10], spiRxBuf[3]; // Transmit and receive buffers
int32_t result; // Variable for conversion result
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI3_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

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_SPI3_Init();

  /* USER CODE BEGIN 2 */
  	  CS_ON(); // Enable CS
  	  spiTxBuf[0]=0xFE; // Set RESET command address
  	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
  	  CS_OFF(); // Disable CS
  	  
  	  CS_ON(); // Enable CS
  	  spiTxBuf[0]=0x0F; // Set SDATAC command address
  	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
  	  CS_OFF(); // Disable CS
  	  
  	  CS_ON(); // Enable CS
  	  spiTxBuf[0]=0x50; // Set WREG command address + address of STATUS register
  	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
  	  spiTxBuf[0]=3; // Set number of registers to be written
  	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
  	  spiTxBuf[0]=0x00; // STATUS - MSB; Disable auto-calibration; Disable buffer; DRDY
  	  spiTxBuf[1]=0x01; // MUX - AIN0 as POSITIVE, AIN1 as NEGATIVE
  	  spiTxBuf[2]=0x00; // ADCON - Clock out disable; Sensor detect disable; PGA = 1
  	  spiTxBuf[3]=0xF0; // DRATE - 30000 SPS
  	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 4, 50); // Transmit buffer via SPI
  	  CS_OFF(); // Disable CS
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
	  CS_ON(); // Enable CS
	  spiTxBuf[0]=0xFC; // Set SYNC command address
	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
	  CS_OFF(); // Disable CS
	  
	  CS_ON(); // Enable CS
	  spiTxBuf[0]=0x00; // Set WAKEUP command address
	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50);
	  CS_OFF(); // Disable CS

	  CS_ON(); // Enable CS
	  spiTxBuf[0]=0x01; // Set RDATA command address
	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
	  HAL_Delay(1); // Delay 1 ms
	  HAL_SPI_Receive(&hspi3, spiRxBuf, 3, 50); // Receive result of conversion via SPI
	  CS_OFF(); // Disable CS

	  result = spiRxBuf[0];
	  result = result << 8;
	  result = spiRxBuf[1];
	  result = result << 8;
	  result = spiRxBuf[2];

	  HAL_Delay(100);
  }
  /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV5;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.Prediv1Source = RCC_PREDIV1_SOURCE_PLL2;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  RCC_OscInitStruct.PLL2.PLL2State = RCC_PLL2_ON;
  RCC_OscInitStruct.PLL2.PLL2MUL = RCC_PLL2_MUL8;
  RCC_OscInitStruct.PLL2.HSEPrediv2Value = RCC_HSE_PREDIV2_DIV5;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Initializes the CPU, AHB and APB busses 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(__FILE__, __LINE__);
  }

    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

    /**Configure the Systick interrupt time 
    */
  __HAL_RCC_PLLI2S_ENABLE();

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* SPI3 init function */
static void MX_SPI3_Init(void)
{

  /* SPI3 parameter configuration*/
  hspi3.Instance = SPI3;
  hspi3.Init.Mode = SPI_MODE_MASTER;
  hspi3.Init.Direction = SPI_DIRECTION_2LINES;
  hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi3.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi3.Init.NSS = SPI_NSS_SOFT;
  hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
  hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi3.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi3) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
*/
static void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin : CS_Pin */
  GPIO_InitStruct.Pin = CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(CS_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void _Error_Handler(char * file, int line)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  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

/**
  * @}
  */ 

/**
  * @}
*/ 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

Code of HAL_SPI_Transmit:

/**
  * @brief  Transmit an amount of data in blocking mode
  * @param  hspi: pointer to a SPI_HandleTypeDef structure that contains
  *                the configuration information for SPI module.
  * @param  pData: pointer to data buffer
  * @param  Size: amount of data to be sent
  * @param  Timeout: Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{

  if(hspi->State == HAL_SPI_STATE_READY)
  {
    if((pData == NULL ) || (Size == 0)) 
    {
      return  HAL_ERROR;
    }

    /* Check the parameters */
    assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction));

    /* Process Locked */
    __HAL_LOCK(hspi);

    /* Configure communication */
    hspi->State = HAL_SPI_STATE_BUSY_TX;
    hspi->ErrorCode   = HAL_SPI_ERROR_NONE;

    hspi->pTxBuffPtr  = pData;
    hspi->TxXferSize  = Size;
    hspi->TxXferCount = Size;

    /*Init field not used in handle to zero */
    hspi->TxISR = 0;
    hspi->RxISR = 0;
    hspi->pRxBuffPtr  = NULL;
    hspi->RxXferSize  = 0;
    hspi->RxXferCount = 0;

    /* Reset CRC Calculation */
    if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
    {
      SPI_RESET_CRC(hspi);
    }

    if(hspi->Init.Direction == SPI_DIRECTION_1LINE)
    {
      /* Configure communication direction : 1Line */
      SPI_1LINE_TX(hspi);
    }

    /* Check if the SPI is already enabled */ 
    if((hspi->Instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE)
    {
      /* Enable SPI peripheral */
      __HAL_SPI_ENABLE(hspi);
    }

    /* Transmit data in 8 Bit mode */
    if(hspi->Init.DataSize == SPI_DATASIZE_8BIT)
    {
      if((hspi->Init.Mode == SPI_MODE_SLAVE)|| (hspi->TxXferCount == 0x01))
      {
        hspi->Instance->DR = (*hspi->pTxBuffPtr++);
        hspi->TxXferCount--;
      }

      while(hspi->TxXferCount > 0)
      {
        /* Wait until TXE flag is set to send data */
        if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_TXE, RESET, Timeout) != HAL_OK)
        { 
          return HAL_TIMEOUT;
        }
        hspi->Instance->DR = (*hspi->pTxBuffPtr++);
        hspi->TxXferCount--;
      }
      /* Enable CRC Transmission */
      if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) 
      {
        SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
      }
    }
    /* Transmit data in 16 Bit mode */
    else
    {
      if((hspi->Init.Mode == SPI_MODE_SLAVE) || (hspi->TxXferCount == 0x01))
      {
        hspi->Instance->DR = *((uint16_t*)hspi->pTxBuffPtr);
        hspi->pTxBuffPtr+=2;
        hspi->TxXferCount--;
      }

      while(hspi->TxXferCount > 0)
      {
        /* Wait until TXE flag is set to send data */
        if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_TXE, RESET, Timeout) != HAL_OK)
        { 
          return HAL_TIMEOUT;
        }
        hspi->Instance->DR = *((uint16_t*)hspi->pTxBuffPtr);
        hspi->pTxBuffPtr+=2;
        hspi->TxXferCount--;
      }
      /* Enable CRC Transmission */
      if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) 
      {
        SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
      }
    }

    /* Wait until TXE flag is set to send data */
    if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_TXE, RESET, Timeout) != HAL_OK)
    {
      SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG);
      return HAL_TIMEOUT;
    }

    /* Wait until Busy flag is reset before disabling SPI */
    if(SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_BSY, SET, Timeout) != HAL_OK)
    { 
      SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG);
      return HAL_TIMEOUT;
    }

    /* Clear OVERUN flag in 2 Lines communication mode because received is not read */
    if(hspi->Init.Direction == SPI_DIRECTION_2LINES)
    {
      __HAL_SPI_CLEAR_OVRFLAG(hspi);
    }

    hspi->State = HAL_SPI_STATE_READY; 

    /* Process Unlocked */
    __HAL_UNLOCK(hspi);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

Code of HAL_SPI_Receive:

/**
  * @brief  Receive an amount of data in blocking mode.
  * @param  hspi: pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pData: pointer to data buffer
  * @param  Size: amount of data to be received
  * @param  Timeout: Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
#if (USE_SPI_CRC != 0U)
  __IO uint16_t tmpreg = 0U;
#endif /* USE_SPI_CRC */
  uint32_t tickstart = 0U;
  HAL_StatusTypeDef errorcode = HAL_OK;

  if((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES))
  {
     hspi->State = HAL_SPI_STATE_BUSY_RX;
     /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */
    return HAL_SPI_TransmitReceive(hspi,pData,pData,Size,Timeout);
  }

  /* Process Locked */
  __HAL_LOCK(hspi);

  /* Init tickstart for timeout management*/
  tickstart = HAL_GetTick();

  if(hspi->State != HAL_SPI_STATE_READY)
  {
    errorcode = HAL_BUSY;
    goto error;
  }

  if((pData == NULL ) || (Size == 0U))
  {
    errorcode = HAL_ERROR;
    goto error;
  }

  /* Set the transaction information */
  hspi->State       = HAL_SPI_STATE_BUSY_RX;
  hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
  hspi->pRxBuffPtr  = (uint8_t *)pData;
  hspi->RxXferSize  = Size;
  hspi->RxXferCount = Size;

  /*Init field not used in handle to zero */
  hspi->pTxBuffPtr  = (uint8_t *)NULL;
  hspi->TxXferSize  = 0U;
  hspi->TxXferCount = 0U;
  hspi->RxISR       = NULL;
  hspi->TxISR       = NULL;

#if (USE_SPI_CRC != 0U)
  /* Reset CRC Calculation */
  if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
  {
    SPI_RESET_CRC(hspi);
    /* this is done to handle the CRCNEXT before the latest data */
    hspi->RxXferCount--;
  }
#endif /* USE_SPI_CRC */

  /* Configure communication direction: 1Line */
  if(hspi->Init.Direction == SPI_DIRECTION_1LINE)
  {
    SPI_1LINE_RX(hspi);
  }

  /* Check if the SPI is already enabled */
  if((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
  {
    /* Enable SPI peripheral */
    __HAL_SPI_ENABLE(hspi);
  }

    /* Receive data in 8 Bit mode */
  if(hspi->Init.DataSize == SPI_DATASIZE_8BIT)
  {
    /* Transfer loop */
    while(hspi->RxXferCount > 0U)
    {
      /* Check the RXNE flag */
      if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE))
      {
        /* read the received data */
        (* (uint8_t *)pData)= *(__IO uint8_t *)&hspi->Instance->DR;
        pData += sizeof(uint8_t);
        hspi->RxXferCount--;
      }
      else
      {
        /* Timeout management */
        if((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick()-tickstart) >=  Timeout)))
        {
          errorcode = HAL_TIMEOUT;
          goto error;
        }
      }
    }
  }
  else
  {
    /* Transfer loop */
    while(hspi->RxXferCount > 0U)
    {
      /* Check the RXNE flag */
      if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE))
      {
        *((uint16_t*)pData) = hspi->Instance->DR;
        pData += sizeof(uint16_t);
        hspi->RxXferCount--;
      }
      else
      {
        /* Timeout management */
        if((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick()-tickstart) >=  Timeout)))
        {
          errorcode = HAL_TIMEOUT;
          goto error;
        }
      }
    }
  }

#if (USE_SPI_CRC != 0U)
  /* Handle the CRC Transmission */
  if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
  {
    /* freeze the CRC before the latest data */
    SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);

    /* Read the latest data */
    if(SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SET, Timeout, tickstart) != HAL_OK)
    {
      /* the latest data has not been received */
      errorcode = HAL_TIMEOUT;
      goto error;
    }

    /* Receive last data in 16 Bit mode */
    if(hspi->Init.DataSize == SPI_DATASIZE_16BIT)
    {
      *((uint16_t*)pData) = hspi->Instance->DR;
    }
    /* Receive last data in 8 Bit mode */
    else
    {
      (*(uint8_t *)pData) = *(__IO uint8_t *)&hspi->Instance->DR;
    }

    /* Wait the CRC data */
    if(SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SET, Timeout, tickstart) != HAL_OK)
    {
      SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC);
      errorcode = HAL_TIMEOUT;
      goto error;
    }

    /* Read CRC to Flush DR and RXNE flag */
    tmpreg = hspi->Instance->DR;
    /* To avoid GCC warning */
    UNUSED(tmpreg);
  }
#endif /* USE_SPI_CRC */

  /* Check the end of the transaction */
  if((hspi->Init.Mode == SPI_MODE_MASTER)&&((hspi->Init.Direction == SPI_DIRECTION_1LINE)||(hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY)))
  {
    /* Disable SPI peripheral */
    __HAL_SPI_DISABLE(hspi);
  }

#if (USE_SPI_CRC != 0U)
    /* Check if CRC error occurred */
    if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR) != RESET)
    {
      /* Check if CRC error is valid or not (workaround to be applied or not) */
      if (SPI_ISCRCErrorValid(hspi) == SPI_VALID_CRC_ERROR)
      {
        SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC);

        /* Reset CRC Calculation */
        SPI_RESET_CRC(hspi);
      }
      else
      {
        __HAL_SPI_CLEAR_CRCERRFLAG(hspi);
      }
    }
#endif /* USE_SPI_CRC */

  if(hspi->ErrorCode != HAL_SPI_ERROR_NONE)
  {
    errorcode = HAL_ERROR;
  }

error :
  hspi->State = HAL_SPI_STATE_READY;
  __HAL_UNLOCK(hspi);
  return errorcode;
}

As a result, the variable result is equal to 0, or showing randomly changing values.

What I'm doing wrong?

  • Hi Stanislav,

    Welcome to the TI E2E Forums!

    I'd be interested to see the output data, even if it does appear to be random. In some cases we can identify the problem from the erroneous data. Also, have you tried probing the SPI communication on an oscilloscope or logic analyzer?

    I didn't see any issues with schematic you shared. Do make sure that with a resistive input you enable the input buffer; otherwise, you may see a significant gain error from trying to sample the the unbuffered data.

    Give me day to look through your code to see if I can find any issues there, but I would still recommend trying to probe the SPI signals and possibly sharing those screenshots with us if you can...

    Best regards,
    Chris
  • Hello Chris,
    unfortunately I don't have an oscilloscope and a logic analyzer.
    I will try to run the device with enabled analog buffer and show few specific results.
  • Hi Stanislav,

    I looked through your code and found a couple of places that might be contributing to erroneous ADC readings...

    1. Reading data before a /DRDY interrupt occurs...

      	  CS_ON(); // Enable CS
      	  spiTxBuf[0]=0x00; // Set WAKEUP command address
      	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50);
      	  CS_OFF(); // Disable CS
      	  
      	  //[Chris] Wait here for /DRDY to go low before reading the data
      
      	  CS_ON(); // Enable CS
      	  spiTxBuf[0]=0x01; // Set RDATA command address
      	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
      	  HAL_Delay(1); // Delay 1 ms
      	  HAL_SPI_Receive(&hspi3, spiRxBuf, 3, 50); // Receive result of conversion via SPI
      	  CS_OFF(); // Disable CS
      Here in your code you are immediately trying to read data after the WAKEUP command. At this point in time, the ADC won't have had enough time to complete the conversion and the data will be invalid. Therefore, you'll need to poll or wait for a /DRDY falling edge interrupt before attempting to read the data.


    2. Bug with concatenating multiple ADC data bytes...

      	  result = spiRxBuf[0];
      	  result = result << 8;
      	  result = spiRxBuf[1];		// Perform '|=' here
      	  result = result << 8;
      	  result = spiRxBuf[2];		// Perform '|=' here
      This code currently overwrites the data stored in result. You will need to do a "|=" operation when trying to concatenate the "spiRxBuff[1]" and "spiRxBuff[0]" bytes into the result.

      Addition: Also keep in mind that you are storing a signed 24-bit number into a signed 32-bit datatype... Therefore, consider sign-extending the ADC's conversion result to account for negative numbers (otherwise the 32-bit number will appear to be positive when the 24-bit is actually negative).


    3. This may or may nor be an issue, but when you set /CS low you might need to insert a small delay in you code before sending any SPI data. Often if SPI communication occurs too soon after /CS goes low it may be misinterpreted by the ADC. Chances are the "HAL_SPI_Transmit()" function has a built-in delay that is sufficient to allow some time delay between /CS low and the first SCLK rising edge; however, if not you may need to add in the "t3" delay required by the ADS1256.

      Also, pay attention to the "t6" delay required between the "RDATA" command and when you clock out data. Again, the "HAL_SPI_Transmit()" function could be providing for this delay, but it might be safer to enforce this delay yourself.


    I hope that helps, please let me know if making any of the above changes resolves your issue!

    Best regards,
    Chris

  • Hello Chris,

    I added t6 and t3 delays. Bug with variable "result" was a typo, in test program I used "|=".

    What type of variable "result" should I use to get best performance?

    I wrote 2 different variants of code:

    in the first one DRDY is set as simple input, therefore main looks like this

    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_SPI3_Init();
    
      /* USER CODE BEGIN 2 */
      	  CS_ON(); // Enable CS
    delay(t3); // Delay t3 spiTxBuf[0]=0xFE; // Set RESET command address HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI CS_OFF(); // Disable CS CS_ON(); // Enable CS
    delay(t3); // Delay t3 spiTxBuf[0]=0x0F; // Set SDATAC command address HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI CS_OFF(); // Disable CS CS_ON(); // Enable CS
    delay(t3); // Delay t3 spiTxBuf[0]=0x50; // Set WREG command address + address of STATUS register HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI spiTxBuf[0]=3; // Set number of registers to be written HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI spiTxBuf[0]=0x00; // STATUS - MSB; Disable auto-calibration; Disable buffer; DRDY spiTxBuf[1]=0x01; // MUX - AIN0 as POSITIVE, AIN1 as NEGATIVE spiTxBuf[2]=0x00; // ADCON - Clock out disable; Sensor detect disable; PGA = 1 spiTxBuf[3]=0xF0; // DRATE - 30000 SPS HAL_SPI_Transmit(&hspi3, spiTxBuf, 4, 50); // Transmit buffer via SPI CS_OFF(); // Disable CS /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ CS_ON(); // Enable CS
    delay(t3); // Delay t3 spiTxBuf[0]=0xFC; // Set SYNC command address HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI CS_OFF(); // Disable CS CS_ON(); // Enable CS
    delay(t3); // Delay t3 spiTxBuf[0]=0x00; // Set WAKEUP command address HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); CS_OFF(); // Disable CS

    while(HAL_GPIO_ReadPin(DRDY_GPIO_Port, DRDY_Pin)==GPIO_PIN_SET) {} // Read level of DRDY pin, if it's set to HIGH - wait CS_ON(); // Enable CS
    delay(t3); // Delay t3 spiTxBuf[0]=0x01; // Set RDATA command address HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI delay(t6); // Delay t6 HAL_SPI_Receive(&hspi3, spiRxBuf, 3, 50); // Receive result of conversion via SPI CS_OFF(); // Disable CS result = spiRxBuf[0]; result = result << 8; result |= spiRxBuf[1]; result = result << 8; result |= spiRxBuf[2]; HAL_Delay(100); } /* USER CODE END 3 */ }


    For tests using infinite loop is ok, but I wanna perform conversion with external interrupts. In the second variant I configured DRDY like EXTI with falling edge.

    But I can't figure out, should I put SYNC+WAKEUP+RDATA in IRQ Handler or only RDATA and SYNC+WAKEUP in main?

    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_SPI3_Init();
    
      /* USER CODE BEGIN 2 */
      	  CS_ON(); // Enable CS
              delay(t3); // Delay t3
      	  spiTxBuf[0]=0xFE; // Set RESET command address
      	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
      	  CS_OFF(); // Disable CS
      	  
      	  CS_ON(); // Enable CS
              delay(t3); // Delay t3
      	  spiTxBuf[0]=0x0F; // Set SDATAC command address
      	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
      	  CS_OFF(); // Disable CS
      	  
      	  CS_ON(); // Enable CS
              delay(t3); // Delay t3
      	  spiTxBuf[0]=0x50; // Set WREG command address + address of STATUS register
      	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
      	  spiTxBuf[0]=3; // Set number of registers to be written
      	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
      	  spiTxBuf[0]=0x00; // STATUS - MSB; Disable auto-calibration; Disable buffer; DRDY
      	  spiTxBuf[1]=0x01; // MUX - AIN0 as POSITIVE, AIN1 as NEGATIVE
      	  spiTxBuf[2]=0x00; // ADCON - Clock out disable; Sensor detect disable; PGA = 1
      	  spiTxBuf[3]=0xF0; // DRATE - 30000 SPS
      	  HAL_SPI_Transmit(&hspi3, spiTxBuf, 4, 50); // Transmit buffer via SPI
      	  CS_OFF(); // Disable CS
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
    
      /* USER CODE END WHILE */
    
      /* USER CODE BEGIN 3 */
    
      }
      /* USER CODE END 3 */
    
    }
    /* USER CODE BEGIN 4 */
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
      /* Prevent unused argument(s) compilation warning */
      UNUSED(GPIO_Pin);
      /* NOTE: This function Should not be modified, when the callback is needed,
               the HAL_GPIO_EXTI_Callback could be implemented in the user file
       */
      
      CS_ON(); // Enable CS
      delay(t3); // Delay t3
      spiTxBuf[0]=0xFC; // Set SYNC command address
      HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
      CS_OFF(); // Disable CS
      
      CS_ON(); // Enable CS
      delay(t3); // Delay t3
      spiTxBuf[0]=0x00; // Set WAKEUP command address
      HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50);
      CS_OFF(); // Disable CS
    
      CS_ON(); // Enable CS
      delay(t3); // Delay t3
      spiTxBuf[0]=0x01; // Set RDATA command address
      HAL_SPI_Transmit(&hspi3, spiTxBuf, 1, 50); // Transmit buffer via SPI
      delay(t6);  // Delay t6
      HAL_SPI_Receive(&hspi3, spiRxBuf, 3, 50); // Receive result of conversion via SPI
      CS_OFF(); // Disable CS
    
      result = spiRxBuf[0];
      result = result << 8;
      result |= spiRxBuf[1];
      result = result << 8;
      result |= spiRxBuf[2];
    }

    I will make tests tomorrow.

  • Hi Stanislav,

    Did adding the additional delays improve the conversion results?

    Regarding the datatype you should use for "result", this is probably a matter of personal preference. I like using "int32_t" types because I can just sign extend the ADC code into the 32-bit data type. You can see an example of this here:
     

    Stanislav Osintsev said:

    For tests using infinite loop is ok, but I wanna perform conversion with external interrupts. In the second variant I configured DRDY like EXTI with falling edge.

    But I can't figure out, should I put SYNC+WAKEUP+RDATA in IRQ Handler or only RDATA and SYNC+WAKEUP in main?

    This is also up to you and how you want to structure your code. Generally, if you have lots of interrupts in your system it's a good idea to keep the IRQ handlers quick. The way I might go about doing this is to simply set a global flag in the interrupt to indicate that a /DRDY has occur, then in your main loop you can check for this flag and perform the SYNC + WAKEUP + RDATA commands. This type of implementation is similar to a state machine, and by allowing you main loop to decide what actions to take next, you avoid cases where your SPI communication is halted in the middle of a command or data read while a long IRQ Handler process is running.

    Best regards,
    Chris

  • Hello Chris.
    I apologize for being inactive for a week.
    I made a tests. With all changes, values at the output of the ADC are 85xx (32,96,56...).

    I noticed one thing,  from my point of view, for ads1256 I must use CPOL - 0 and CPHA - 1Edge, but with this configuration output value is always 0. But if I change CPOL to 1, then I receive 85xx values, which don't depend of the input voltage.

  • Hi Stanislav,

    You must use the correct SPI mode (mode 1) for communication. If you use clock polarity dwelling high on idle, all of your data will be incorrect. The best method of verifying your communication is to check it with an oscilloscope or logic analyzer. If this is not available to you, then you need to first be able to read the default settings of the ADS1256 registers. If the registers values are correct, then attempt to write the registers and then read them back and verify that the results are what you expect. Then you need to verify that what you thought you wrote to the registers is how the device is responding.

    If you are still having trouble, you really need to find an oscilloscope.

    Best regards,
    Bob B