2020-06-09 07:12 PM
Hi everyone,
I've been working on a custom PCB with an STM32F427 and a TI audio amp (TAS5825M) that need to communicate using I2C. This is my first time using the STM32 line. I set up the project with STM32CubeMX with the appropriate settings for 100 kHz Master mode I2C on the I2C2 peripheral. Here's a picture of the pin configuration.
When I make the first call to the HAL_I2C_Master_Transmit, it runs until the address is sent and then fails. I believe that it fails because there is no clock signal and the receiving slave never acknowledges the presence of data, as shown in this capture of the scoped signals:
It just sends the address over and over as each message fails. In addition, notice how slow the data line is sending data! It takes about a second just to send an 8-bit address.
What am I doing wrong here, with respect to the clock and slow SDA speed?
Here's my code:
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdlib.h>
#include "i2c_cfg.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 hi2c2;
/* USER CODE BEGIN PV */
static const uint8_t TAS_I2C_ADDR = 0x4D << 1; // 8-bit address
// Variable declarations
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C2_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void transmit_registers(cfg_reg *r, int n);
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
// in main
/* 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_I2C2_Init();
/* USER CODE BEGIN 2 */
// Set up the TAS by sending I2C
// transmit_registers(registers, sizeof(registers)/sizeof(registers[0]));
transmit_registers(registers, sizeof(registers)/sizeof(registers[0]));
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// More unrelated code in here sends I2S audio data to the TI amp
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
/** Initializes the CPU, AHB and APB busses clocks
*/
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 = 192;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** 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_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
Error_Handler();
}
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
PeriphClkInitStruct.PLLI2S.PLLI2SN = 192;
PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief I2C2 Initialization Function
* @param None
* @retval None
*/
static void MX_I2C2_Init(void)
{
/* USER CODE BEGIN I2C2_Init 0 */
/* USER CODE END I2C2_Init 0 */
/* USER CODE BEGIN I2C2_Init 1 */
/* USER CODE END I2C2_Init 1 */
hi2c2.Instance = I2C2;
hi2c2.Init.ClockSpeed = 100000;
hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c2.Init.OwnAddress1 = 0;
hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c2.Init.OwnAddress2 = 0;
hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c2) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C2_Init 2 */
/* USER CODE END I2C2_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_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin : PD0 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
void transmit_registers(cfg_reg *r, int n) {
int i = 0;
while (i < n) {
switch (r[i].command) {
case CFG_META_SWITCH:
// Used in legacy applications. Ignored here.
break;
case CFG_META_DELAY:
HAL_Delay(r[i].param);
break;
case CFG_META_BURST:
HAL_I2C_Master_Transmit(&hi2c2, TAS_I2C_ADDR, (uint8_t *)&r[i+1], r[i].param, HAL_MAX_DELAY);
i += (r[i].param / 2) + 1;
break;
default:
HAL_I2C_Master_Transmit(&hi2c2, TAS_I2C_ADDR, (uint8_t *)&r[i], 2, HAL_MAX_DELAY);
break;
}
i++;
}
}
i2c_cfg.h contains a header file that defines an array of register writes to make to the TI amp. Here's an example of some elements of the array:
cfg_reg registers[] = {
{ 0x00, 0x00 },
{ 0x7f, 0x00 },
{ 0x03, 0x02 },
{ 0x01, 0x11 },
{ 0x00, 0x00 },
{ 0x00, 0x00 },
{ 0x00, 0x00 },
{ 0x00, 0x00 },
{ 0x00, 0x00 },
{ 0x00, 0x00 },
{ 0x7f, 0x00 },
{ 0x46, 0x09 },
etc...
Any help is appreciated!
Thanks,
Andrew
2020-06-09 07:59 PM
Bad solder joint on the SCK pin?
In debugger, check the respective GPIO settings. Then change the respective GPIO_MODER setting from AF to Out, wiggle the pin in GPIO_ODR and observe.
JW
2020-06-12 06:35 PM
Hello Jan,
Thank you for the reply. You are entirely correct. When I had initially probed for continuity I had only contacted the pad, not the MCU pin. I have since secured the SCK pin and it worked perfectly.
Thank you so much!!!
Best,
Andrew
2020-06-12 08:12 PM
And just for clarity - SDA was slow because of clock stretching feature. Turning it off would make it fast irrespective of actual clock signal.