2025-06-06 3:02 PM - edited 2025-06-06 3:09 PM
Hi,
I am trying to establish I2C communication between STM32C011 (Master) and STM32C031 Nucleo Board (Slave).
I transmit a message from the master, however, the slave side sees that the master wants to write to the slave (using HAL_I2C_AddrCallback) however, the HAL_I2C_SlaveRxCpltCallback is never called.
In another post, I see that the buffer length may be an issue, so I tried to transmit just one character but to no avail.
ChatGPT suggested I shouldn't re-arm the HAL_I2C_Slave_Receive_IT function as it can cause it to get stuck. I tried it with and without but same result.
I see "Master wants to write to slave" only once upon power up/reset of the slave MCU.
Master Side:
#include "main.h"
#define SLAVE_ADDR 0x42 << 1
I2C_HandleTypeDef hi2c1;
SPI_HandleTypeDef hspi1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
static void MX_I2C1_Init(void);
uint8_t TX_Buffer [] = "A";
//uint8_t TX_Buffer [] = "MasterToSlave"; // DATA to send
uint8_t RX_Buffer [14];
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
MX_I2C1_Init();
toggleRED(4,4,100);
while (1)
{
master_send_receive();
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_FLASH_SET_LATENCY(FLASH_LATENCY_1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x10805D88;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
}
static void MX_SPI1_Init(void)
{
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOC, Bank2RED_Pin|Bank1RED_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, Bank1Latch_Pin|Bank2Latch_Pin|Bank3Latch_Pin|Bank4Latch_Pin
|Bank34WHT_Pin, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = Bank2RED_Pin|Bank1RED_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = Bank1Latch_Pin|Bank2Latch_Pin|Bank3Latch_Pin|Bank4Latch_Pin
|Bank34WHT_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = Bank4BTN_Pin|Bank3BTN_Pin|Bank1BTN_Pin|Bank2BTN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
}
void master_send_receive(void)
{
HAL_Delay(1000);
//if (HAL_I2C_IsDeviceReady (&hi2c1, SLAVE_ADDR, 3, 1000) == HAL_OK)
{
toggleRED(1,4,100);
if (HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDR, TX_Buffer, strlen((char*)TX_Buffer), 1000) == HAL_OK)
{
toggleRED(3,1,1000);
}
if (HAL_I2C_Master_Receive(&hi2c1, SLAVE_ADDR, RX_Buffer, sizeof(RX_Buffer), 1000) == HAL_OK)
{
toggleRED(4,2,100);
if ((RX_Buffer[0] != 0)||(RX_Buffer[1] != 0)||(RX_Buffer[2] != 0)||(RX_Buffer[3] != 0)||(RX_Buffer[4] != 0)||(RX_Buffer[5] != 0)||(RX_Buffer[6] != 0))
{
HAL_GPIO_TogglePin(RED_GPIO_PORT[1], RED_GPIO_PIN[1]);
}
}
}
}
void toggleRED(uint8_t bank, uint8_t blinks, uint16_t msDelay)
{
for(uint8_t i=0; i<blinks; i++)
{
HAL_GPIO_TogglePin(RED_GPIO_PORT[bank], RED_GPIO_PIN[bank]);
HAL_Delay(msDelay);
HAL_GPIO_TogglePin(RED_GPIO_PORT[bank], RED_GPIO_PIN[bank]);
HAL_Delay(msDelay/2);
}
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif
Slave Side:
#include "main.h"
#include <stdio.h>
I2C_HandleTypeDef hi2c1;
TIM_HandleTypeDef htim3;
UART_HandleTypeDef huart2;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_TIM3_Init(void);
static void MX_USART2_UART_Init(void);
uint8_t Slave_TX_Buffer [] = "SlaveToMaster";
uint8_t Slave_RX_Buffer [1];
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_TIM3_Init();
MX_USART2_UART_Init();
HAL_TIM_Base_Start_IT(&htim3);
__enable_irq();
toggleLED(4,100);
if (HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
printf("Failed to enable I2C listen mode\r\n");
}
while (1)
{
//HAL_Delay(1000);
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_FLASH_SET_LATENCY(FLASH_LATENCY_1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x10805D88;
hi2c1.Init.OwnAddress1 = 132;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
}
static void MX_TIM3_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim3.Instance = TIM3;
htim3.Init.Prescaler = 47999;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 9999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
static void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 57600;
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;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
HAL_GPIO_WritePin(GRNLED_GPIO_Port, GRNLED_Pin, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = BLUBTN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(BLUBTN_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GRNLED_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GRNLED_GPIO_Port, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
}
int __io_putchar(int ch)
{
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
HAL_GPIO_TogglePin(GRNLED_GPIO_Port, GRNLED_Pin);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
printf("10 Seconds Elapsed\r\n");
}
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
if (hi2c->Instance == I2C1)
{
if (TransferDirection == I2C_DIRECTION_TRANSMIT)
{
printf("Master wants to write to slave\r\n");
HAL_I2C_Slave_Receive_IT(hi2c, Slave_RX_Buffer, sizeof(Slave_RX_Buffer));
}
else if (TransferDirection == I2C_DIRECTION_RECEIVE)
{
printf("Master wants to read from slave\r\n");
HAL_I2C_Slave_Transmit_IT(hi2c, Slave_TX_Buffer, sizeof(Slave_TX_Buffer));
}
}
}
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
if (hi2c->Instance == I2C1)
{
printf("Listen complete. Re-enabling listen mode.\r\n");
HAL_I2C_EnableListen_IT(hi2c);
}
}
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
{
printf("SlaveRxCpltCallback triggered. Data: %s\r\n", Slave_RX_Buffer);
toggleLED(1,1000);
HAL_I2C_Slave_Receive_IT(&hi2c1, Slave_RX_Buffer, sizeof(Slave_RX_Buffer));
}
}
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
if (hi2c->Instance == I2C1)
{
printf("SlaveRxCpltCallback triggered. Data: %s\r\n", Slave_RX_Buffer);
HAL_GPIO_WritePin(GRNLED_GPIO_Port, GRNLED_Pin, GPIO_PIN_SET);
printf("I2C message sent from tx callback interrupt.\r\n");
HAL_I2C_Slave_Transmit_IT(&hi2c1, Slave_TX_Buffer, sizeof(Slave_TX_Buffer));
}
}
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
if (hi2c->Instance == I2C1)
{
printf("I2C error occurred. Re-arming receive.\r\n");
HAL_I2C_Slave_Receive_IT(&hi2c1, Slave_RX_Buffer, sizeof(Slave_RX_Buffer));
}
}
void toggleLED(uint8_t blinks, uint16_t msDelay)
{
for(uint8_t i=0; i<blinks; i++)
{
HAL_GPIO_TogglePin(GRNLED_GPIO_Port, GRNLED_Pin);
HAL_Delay(msDelay);
HAL_GPIO_TogglePin(GRNLED_GPIO_Port, GRNLED_Pin);
HAL_Delay(msDelay/2);
}
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif
2025-06-06 3:39 PM
Did you enable the NVIC?
2025-06-09 6:38 AM
Yes, on the slave side (STM32C0 Nucleo Board) where I use interrupts, I have enabled the NVIC.
2025-06-09 11:37 AM
I'm not seeing the pins actually being set up for Alternate Functionality. I assume that's just missing? (Or I'm blind.) Do you have scope traces or logic analyzer traces? Is the master timing out perhaps because of the printf statements going on in the slave? I can't remember if these printf's are happening in an ISR or not, but they don't seem like a good idea to me. Maybe don't do that.
2025-06-09 2:52 PM - edited 2025-06-09 2:53 PM
The pins are set up in hal_msp.c file
Master:
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
if(hi2c->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_I2C1;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
__HAL_RCC_GPIOB_CLK_ENABLE();
/**I2C1 GPIO Configuration
PB7 ------> I2C1_SDA
PB6 ------> I2C1_SCL
*/
GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
/* I2C1 interrupt Init */
HAL_NVIC_SetPriority(I2C1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C1_IRQn);
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
Slave:
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
if(hi2c->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_I2C1;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
__HAL_RCC_GPIOB_CLK_ENABLE();
/**I2C1 GPIO Configuration
PB8 ------> I2C1_SCL
PB9 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
/* I2C1 interrupt Init */
HAL_NVIC_SetPriority(I2C1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C1_IRQn);
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
I removed the printf statements, however, it did not change the result; it is still not calling HAL_I2C_SlaveRxCpltCallback.
Below is the waveform when I do not have the slave connected:
Once I connect the slave, the waveform disappears:
The master side never receives (HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDR, TX_Buffer, strlen((char*)TX_Buffer), 1000) == HAL_OK).
2025-06-09 3:50 PM
Do you have external pullups on the SDA and SCL lines? Internal pullups might suffice at slow speeds, but you don't have those enabled.
> Once I connect the slave, the waveform disappears:
If both SDA and SCL are held low, this indicates a hardware issue or a serious software issue. Ensure things are powered. Ensure SDA/SCL go high on both the master and slave when they are separated.
2025-06-11 7:25 AM
Hello @HPate.12
Please refer to the example below: