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?