2
\$\begingroup\$

I have a PCB with ΣΔ ADC ADS112C04IPW, which communicates with the MCU via the I2C interface. The purpose of the PCB is to be an evaluation board, on which I want to try some of the features before I use it for some more advanced designs. All the parts are taken from the datasheet.

  1. Capacitors are chosen as 100 nF from section 5 Pin Configuration and Functions.
  2. Pull-up resistors for I2C are not specified (see section 9.1.1 Interface Connections). I chose $$R_2 = R_3 = 3.3,円\text{k}\Omega$$ as compromise.
  3. RESET and DRDY are connected to 3V3 with resistors $$R_1 = R_4 = 10,円\text{k}\Omega.$$ Considering the section 9.1.3 Unused Inputs and Outputs, I might have made a mistake with the RESET pin, which might not require a pull-up at all.
  4. Following the instructions in 9.1.3 Unused Inputs and Outputs for analog pins, I have left them unconnected.
  5. The selected I2C address should be 100 000, with A0 and A1 being connected to DGND, see section 8.5.1.1 I2C Address.
  6. The layout of the board is taken from section 11.2 Layout Example. The stack-up is a 4-layer board with two middle layers dedicated to GND and the other one to 3V3.

Evaluation board for ADS112C04IPW schematic.

Here is the layout. Layout of the evaluation board.

I am using NUCLEO-F401RE as the MCU.

In addition to the default peripheries, I have added one external interrupt at PA9, which I am planning to use for detecting the DRDY signal. I2C1 with SDA at PB7 and SCL at PB6.

Nucleo pinout.

Here is the interconnection between the MCU and the ADC. Interconnection between ADC and Nucleo.

And here is the code. No interrupt callbacks are set yet. Therefore, I am not including the stm32f4xx_it.c file. The code itself aims to do the following.

  1. Initialize peripheries.
  2. Send a testing message on UART2.
  3. Send a RESET command to ADS112C04IPW; this should be the easiest test, see section 8.5.3.2 RESET (0000 011x).
  4. Check if the transmission was successful.

The code.

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file : main.c
 * @brief : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2025 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"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.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 ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
uint8_t message[256];
uint8_t message_length;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_I2C1_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* 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 */
 HAL_Delay(10);
 /* USER CODE END SysInit */
 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_USART2_UART_Init();
 MX_I2C1_Init();
 /* USER CODE BEGIN 2 */
 message_length = snprintf((char *) message, 256, "%s\r\n", "Transmission initialized.");
 HAL_UART_Transmit(&huart2, message, message_length, 20);
 uint8_t command = 0b00000110;
 uint8_t address = 0b1000000;
 uint8_t status = HAL_I2C_Master_Transmit(&hi2c1, address, &command, 1, 1000);
 message_length = snprintf((char *) message, 256, "HAL STATUS = %d\t Address = %d\r\n", status, address);
 HAL_UART_Transmit(&huart2, message, message_length, 20);
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
 /* USER CODE END WHILE */
 /* 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};
 /** Configure the main internal regulator output voltage
 */
 __HAL_RCC_PWR_CLK_ENABLE();
 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
 /** Initializes the RCC Oscillators according to the specified parameters
 * in the RCC_OscInitTypeDef structure.
 */
 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
 RCC_OscInitStruct.HSIState = RCC_HSI_ON;
 RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
 RCC_OscInitStruct.PLL.PLLM = 16;
 RCC_OscInitStruct.PLL.PLLN = 336;
 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
 RCC_OscInitStruct.PLL.PLLQ = 7;
 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();
 }
}
/**
 * @brief I2C1 Initialization Function
 * @param None
 * @retval None
 */
static void MX_I2C1_Init(void)
{
 /* USER CODE BEGIN I2C1_Init 0 */
 /* USER CODE END I2C1_Init 0 */
 /* USER CODE BEGIN I2C1_Init 1 */
 /* USER CODE END I2C1_Init 1 */
 hi2c1.Instance = I2C1;
 hi2c1.Init.ClockSpeed = 100000;
 hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
 hi2c1.Init.OwnAddress1 = 0;
 hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
 hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
 hi2c1.Init.OwnAddress2 = 0;
 hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
 hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
 if (HAL_I2C_Init(&hi2c1) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN I2C1_Init 2 */
 /* USER CODE END I2C1_Init 2 */
}
/**
 * @brief USART2 Initialization Function
 * @param None
 * @retval None
 */
static void MX_USART2_UART_Init(void)
{
 /* USER CODE BEGIN USART2_Init 0 */
 /* USER CODE END USART2_Init 0 */
 /* USER CODE BEGIN USART2_Init 1 */
 /* USER CODE END USART2_Init 1 */
 huart2.Instance = USART2;
 huart2.Init.BaudRate = 115200;
 huart2.Init.WordLength = UART_WORDLENGTH_8B;
 huart2.Init.StopBits = UART_STOPBITS_1;
 huart2.Init.Parity = UART_PARITY_NONE;
 huart2.Init.Mode = UART_MODE_TX_RX;
 huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
 huart2.Init.OverSampling = UART_OVERSAMPLING_16;
 if (HAL_UART_Init(&huart2) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN USART2_Init 2 */
 /* USER CODE END USART2_Init 2 */
}
/**
 * @brief GPIO Initialization Function
 * @param None
 * @retval None
 */
static void MX_GPIO_Init(void)
{
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 /* GPIO Ports Clock Enable */
 __HAL_RCC_GPIOC_CLK_ENABLE();
 __HAL_RCC_GPIOH_CLK_ENABLE();
 __HAL_RCC_GPIOA_CLK_ENABLE();
 __HAL_RCC_GPIOB_CLK_ENABLE();
 /*Configure GPIO pin Output Level */
 HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
 /*Configure GPIO pin : B1_Pin */
 GPIO_InitStruct.Pin = B1_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
 /*Configure GPIO pin : LD2_Pin */
 GPIO_InitStruct.Pin = LD2_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
 /*Configure GPIO pin : DRDY_Pin */
 GPIO_InitStruct.Pin = DRDY_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(DRDY_GPIO_Port, &GPIO_InitStruct);
 /* EXTI interrupt init*/
 HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
 HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
 * @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 */

Nevertheless, the transmission always fails. By debugging the code, I was able to find that the controller is unable to connect to the address 100 000. I have tried all the addresses from the section 8.5.1.1 I2C Address, but without success. The MCU does not receive the ACK from the ADS112C04IPW when communicating the address.

Here is what I have tried so far.

  1. There is a library for this ADC on GitHub. I went through it, and it seems that the code I am using should be correct.
  2. The ADC supports broadcast RESET, see section 8.5.1.6 I2C General Call (Software Reset). I have tried to send a RESET at the address 000 0000, which seemingly resulted in successful transmission (HAL_OK). To verify this, I disconnected the SDA line from the ADC and tried to send a RESET on this address, which resulted in HAL_ERROR.
  3. I have hand-soldered all components. This is another shady region where errors can occur. I tried to make a connectivity test between all pins with a multimeter, but did not find anything suspicious. 3V3 voltage is present as well.

UPDATE: I have tried to change to I2C3, but with no success as well.

asked Aug 14 at 9:18
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Humphrey Appleby - Hi, Do you have an oscilloscope to be able to view the I2C signals during the attempt to communicate with the ADC? If so, please add those scope traces to the question. TY \$\endgroup\$ Commented Aug 14 at 9:27
  • \$\begingroup\$ I have access to it, but not until next week. \$\endgroup\$ Commented Aug 14 at 9:38

1 Answer 1

2
\$\begingroup\$

You are trying to communicate with wrong I2C address.

Sure, the address is 0x40 like the datasheet says. In 7-bit notation without the read/write bit.

The STM32 HAL wants the address in 8-bit notation that includes the read/write bit at the LSB.

So try again with address 0x80 given to HAL, i.e. shift the 7-bit address left by one bit.

answered Aug 14 at 10:08
\$\endgroup\$
1
  • \$\begingroup\$ This did the trick. I misinterpreted the library documentation about the 7-bit address. \$\endgroup\$ Commented Aug 14 at 20:16

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.