2024-08-28 04:24 AM
Hi guys,
I am trying to run a demo on STM32U083C-DK board.
This demo consists of LPTIMER generating PWM that is used for synchronization of I2C read from on-board temperature sensor. Rising edge writes the addres of read and falling edge reads data. The main issue I have encountered is that my synchronization setup works perfectly with UART transmit but with I2C no matter what I try I don't ever get transmit on the I2C bus.
What I checked:
- LPTIMER NVIC is on and is able to start UART synchronization
- I2C DMA works when software triggered. (with synchronization disabled)
DMA setup for I2C DMA:
LPTIMER config:
Logic analyzer output:
Where D0 is SDA, D1 is SCL and D2 is LPTIMER output
This is the main and initialisation of I2C:
I2C_HandleTypeDef hi2c1;
DMA_HandleTypeDef hdma_i2c1_tx;
DMA_HandleTypeDef hdma_i2c1_rx;
LPTIM_HandleTypeDef hlptim1;
union {
uint8_t temp_raw_8[2];
int16_t temp_raw_16;
}temp_raw;
uint8_t stts22h_temp_l_out = STTS22H_TEMP_L_OUT;
STTS22H_IO_t stts22h_io;
STTS22H_Object_t stts22h_obj;
int main(void)
{
MX_GPIO_Init();
MX_DMA_Init();
MX_USART2_UART_Init();
MX_I2C1_Init();
MX_LPTIM1_Init();
/* USER CODE BEGIN 2 */
HAL_I2C_Master_Transmit_DMA(&hi2c1, STTS22H_I2C_ADD_L, &stts22h_temp_l_out, 1);
HAL_I2C_Master_Receive_DMA(&hi2c1, STTS22H_I2C_ADD_L, &temp_raw.temp_raw_8[0], 2);
HAL_LPTIM_PWM_Start_IT(&hlptim1, LPTIM_CHANNEL_1);
/* USER CODE END 2 */
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
HAL_DMA_MuxSyncConfigTypeDef pSyncConfig;
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
PB8 ------> I2C1_SCL
*/
GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
/* I2C1 DMA Init */
/* I2C1_TX Init */
hdma_i2c1_tx.Instance = DMA1_Channel1;
hdma_i2c1_tx.Init.Request = DMA_REQUEST_I2C1_TX;
hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c1_tx.Init.Mode = DMA_CIRCULAR;
hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
if (HAL_DMA_Init(&hdma_i2c1_tx) != HAL_OK)
{
Error_Handler();
}
pSyncConfig.SyncSignalID = HAL_DMAMUX1_SYNC_LPTIM1_OUT;
pSyncConfig.SyncPolarity = HAL_DMAMUX_SYNC_RISING;
pSyncConfig.SyncEnable = ENABLE;
pSyncConfig.EventEnable = ENABLE;
pSyncConfig.RequestNumber = 1;
if (HAL_DMAEx_ConfigMuxSync(&hdma_i2c1_tx, &pSyncConfig) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hi2c,hdmatx,hdma_i2c1_tx);
/* I2C1_RX Init */
hdma_i2c1_rx.Instance = DMA1_Channel2;
hdma_i2c1_rx.Init.Request = DMA_REQUEST_I2C1_RX;
hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c1_rx.Init.Mode = DMA_CIRCULAR;
hdma_i2c1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
if (HAL_DMA_Init(&hdma_i2c1_rx) != HAL_OK)
{
Error_Handler();
}
pSyncConfig.SyncSignalID = HAL_DMAMUX1_SYNC_LPTIM1_OUT;
pSyncConfig.SyncPolarity = HAL_DMAMUX_SYNC_FALLING;
pSyncConfig.SyncEnable = ENABLE;
pSyncConfig.EventEnable = ENABLE;
pSyncConfig.RequestNumber = 2;
if (HAL_DMAEx_ConfigMuxSync(&hdma_i2c1_rx, &pSyncConfig) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hi2c,hdmarx,hdma_i2c1_rx);
/* 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 */
}
}
If I am missing something please let me know but I feel like I am either using wrong function to call I2C receive and transmit (which I doubt) or there is a bug.
Thank you in advance for answers.
Solved! Go to Solution.
2024-08-28 06:44 AM
The example you linked uses UART. You are using I2C which is more complicated in its usage. You will need to initiate each I2C transaction with a call to HAL_I2C_Master_Receive_DMA. Perhaps put this in a timer interrupt callback which is called periodically.
2024-08-28 06:13 AM
The basic premise of the program isn't valid. You can't use the HAL DMA routines like this. Look at the code within HAL_I2C_Master_Receive_DMA to see how it starts the transfer. Only after the transfer is started can DMA be used.
2024-08-28 06:33 AM
Could you please elaborate on your answer? How could I otherwise you the synchronization of I2C?
I am basically trying the same thing as in: https://github.com/STMicroelectronics/STM32CubeH7/tree/master/Projects/STM32H743I-EVAL/Examples/DMA/DMAMUX_SYNC
2024-08-28 06:44 AM
The example you linked uses UART. You are using I2C which is more complicated in its usage. You will need to initiate each I2C transaction with a call to HAL_I2C_Master_Receive_DMA. Perhaps put this in a timer interrupt callback which is called periodically.
2024-08-28 06:54 AM
Okay, thank you.
In my excercise I wanted to make I2C read to my memory completely automatic in the backround using DMA so it updates temperature values automatically without any MCU work and I can get the latest value in my code.
I will continue to work on my example and I will try to come up with a way to make it work