英文:
STM32 HAL I2C DMA not triggering callback function
问题
I try to read and write data to a sensor via i2c with DMA1 in an STM32 Nucleo F401 board where a FreeRTOS is running.
我尝试通过DMA1在运行FreeRTOS的STM32 Nucleo F401板上使用I2C读取和写入传感器数据。
My project is written in C++ and using the stm32 HAL libraries as extern "C".
我的项目是用C++编写的,并将stm32 HAL库作为extern "C"使用。
I can read the sensor data with polling method, and next to the I2C an UART is running with the DMA2 correctly. I have checked and the MX_DMA_Init is running before the MX_I2C1_Init.
我可以使用轮询方法读取传感器数据,并且UART与DMA2正确运行。我已经检查过,MX_DMA_Init在MX_I2C1_Init之前运行。
When I try to write to the sensor as a master with DMA(HAL_I2C_Master_Transmit_DMA) with the "i2c1 event interrupt" and "i2c1 error interrupt" disabled in the FreeRTOS the parallel tasks are just running fine just the callback HAL_I2C_MasterTxCpltCallback is not triggered.
当我尝试使用DMA(HAL_I2C_Master_Transmit_DMA)作为主机写入传感器时,FreeRTOS中禁用了“i2c1事件中断”和“i2c1错误中断”,并行任务正常运行,只是回调HAL_I2C_MasterTxCpltCallback没有触发。
And when I am enabling the "i2c1 event interrupt" and "i2c1 error interrupt" from the CubeMX two parallel task in the FreeRTOS are running at once and then no more parallel scheduling is happening and the HAL_I2C_EV_IRQHandler function is called periodically and leaving the function in the last else branch where the /* Do nothing */ is commented.
当我从CubeMX启用“i2c1事件中断”和“i2c1错误中断”时,在FreeRTOS中有两个并行任务同时运行,然后不再进行并行调度,HAL_I2C_EV_IRQHandler函数定期调用,并在最后一个else分支中离开函数,其中/不执行任何操作/被注释掉。
Could you please suggest what could I try to use the i2c with DMA?
您能否建议我尝试使用DMA来使用I2C的方法?
I tried to enable and disable the i2c1 event interrupt from CubeMX and expected to trigger the HAL_I2C_MasterTxCpltCallback callback. But only the HAL_I2C_EV_IRQHandler was triggered periodically.
我尝试从CubeMX启用和禁用i2c1事件中断,并期望触发HAL_I2C_MasterTxCpltCallback回调。但只有HAL_I2C_EV_IRQHandler被定期触发。
I tried to use the I2C with polling method and it was working correctly.
我尝试使用轮询方法使用I2C,并且它正常工作。
I tried to use the UART with DMA and it was working correctly too.
我尝试使用DMA进行UART,也正常工作。
I tried to check the order of MX_DMA_Init and MX_I2C1_Init, but the order was correct.
我尝试检查MX_DMA_Init和MX_I2C1_Init的顺序,但顺序是正确的。
I tried if any other I2C callback is triggered, but none other I2C callback is triggered.
我尝试查看是否触发了其他I2C回调,但没有触发其他I2C回调。
I tried to update the Cube MX version from F4 V1.26.2 to F4 V27.1, but I have not found any improvement.
我尝试将Cube MX版本从F4 V1.26.2更新到F4 V27.1,但没有发现任何改进。
I tried to have all the HAL implementation and callback functions embedded in extern "C". No change has occurred.
我尝试将所有HAL实现和回调函数嵌入extern "C"中,但没有发生任何变化。
I switched to STM32 H723ZG board where at least the first transfer of the I2C data happened with DMA FIRST I2C Data transfer. But happens only for 1 cycle and the DMA fails with error code 1. What is the Transfer error.
我切换到STM32 H723ZG板,至少I2C数据的第一次传输使用DMA进行了 FIRST I2C Data transfer。但仅发生了1个周期,DMA出现错误代码1。什么是传输错误。
#define HAL_DMA_ERROR_TE (0x00000001U) /*!< Transfer error /
#define HAL_DMA_ERROR_TE (0x00000001U) /!< 传输错误 */
I have seen that in the h= series I need to align the data given to the DMA to be able to send and I tried to apply the fix for this.
我发现在h系列中,我需要对传递给DMA的数据进行对齐,以便能够发送,并尝试应用此修复。
My code now looks like this:
我的代码现在看起来像这样:
#define TX_LENGTH (16)
uint8_t i2cData[TX_LENGTH];
void I2C_Write8(uint8_t ADDR, uint8_t data)
{
i2cData[0] = ADDR;
i2cData[1] = data;
uint8_t MPUADDR = (MPU_ADDR<<1);
/* Clean D-cache /
/ Make sure the address is 32-byte aligned and add 32-bytes to length, in case it overlaps cacheline /
SCB_CleanDCache_by_Addr((uint32_t)(((uint32_t)i2cData) & ~(uint32_t)0x1F), TX_LENGTH+32);
HAL_I2C_Master_Transmit_DMA(&i2cHandler, MPUADDR, i2cData, TX_LENGTH);
//HAL_Delay(100);
}
The I2C Init:
I2C初始化:
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.Timing = 0x60404E72;
hi2c2.Init.OwnAddress1 = 0;
hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c2.Init.DualAddress
英文:
I try to read and write data to a sensor via i2c with DMA1 in an STM32 Nucleo F401 board where a FreeRTOS is running.
My project is written in C++ and using the stm32 HAL libraries as extern "C".
I can read the sensor data with polling method, and next to the I2C an UART is running with the DMA2 correctly. I have checked and the MX_DMA_Init is running before the MX_I2C1_Init.
When I try to write to the sensor as a master with DMA(HAL_I2C_Master_Transmit_DMA) with the "i2c1 event interrupt" and "i2c1 error interrupt" disabled in the FreeRTOS the parallel tasks are just running fine just the callback HAL_I2C_MasterTxCpltCallback is not triggered.
And when i am enabling the" i2c1 event interrupt" and "i2c1 error interrupt" from the CubeMX two parallel task in the Free RTOS are running at once and then no more parallel scheduling is happening and the HAL_I2C_EV_IRQHandler function is called periodically and leaving the function in the last else branch where the /* Do nothing */ is commented.
" i2c1 event interrupt" and "i2c1 error interrupt" enabled
UART DMA configuration
I2C DMA confuguration
Could you please suggest what could I try to use the i2c with DMA?
I tried to enable and disable the i2c1 event interrupt from CubeMX and expected to trigger the HAL_I2C_MasterTxCpltCallback callback. But only the HAL_I2C_EV_IRQHandler was triggered periodically.
I tried to use the I2C with polling method and it was working correctly.
I tried to use the UART with DMA and it was working correctly too.
I tried to check order of MX_DMA_Init and MX_I2C1_Init, but the order was correct.
I tried if any other I2C callback is triggered, but none other I2C callback is triggered.
I tried to update the Cube MX version from F4 V1.26.2 to F4 V27.1, but i have not found any improvement.
I tried to have all the HAL implementation and callback functions embedded in extern"C". No change has occurred.
I switched to STM32 H723ZG board where at lest the first transfer of the I2C data happened with DMA [FIRST I2C Data transfer][1][1]: https://i.stack.imgur.com/4wsxk.png. But happenes only for 1 cycle and the DMA failes with error code 1. What is the Transfer error.
#define HAL_DMA_ERROR_TE (0x00000001U) /*!< Transfer error */
[DMA Registers]
[2]: https://i.stack.imgur.com/4SH7Z.png
I have seen that in the h= series i need to align the data given to the DMA to be able to send and i tryed to apply the fix for this.
My code now looks like this:
#define TX_LENGTH (16)
uint8_t i2cData[TX_LENGTH];
void I2C_Write8(uint8_t ADDR, uint8_t data)
{
i2cData[0] = ADDR;
i2cData[1] = data;
uint8_t MPUADDR = (MPU_ADDR<<1);
/* Clean D-cache */
/* Make sure the address is 32-byte aligned and add 32-bytes to length, in case it overlaps cacheline */
SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)i2cData) & ~(uint32_t)0x1F), TX_LENGTH+32);
HAL_I2C_Master_Transmit_DMA(&i2cHandler, MPUADDR, i2cData, TX_LENGTH);
//HAL_Delay(100);
}
The I2C Init:
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.Timing = 0x60404E72;
hi2c2.Init.OwnAddress1 = 0;
hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c2.Init.OwnAddress2 = 0;
hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
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 */
}
The DMA Init:
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Stream0_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
/* DMA1_Stream1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
}
The initialization from the main:
/* 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_DMA_Init();
MX_USART3_UART_Init();
MX_USB_OTG_HS_USB_Init();
MX_SPI1_Init();
MX_ETH_Init();
MX_I2C2_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Init scheduler */
osKernelInitialize();
Could you please suggest what I am doing wrongly?
答案1
得分: 0
以下是您要翻译的部分:
- 交付的数据: 交付的数据必须是DMA的全局变量,否则当我离开函数/或调用对象的析构函数时,内存被释放,DMA中断中止。
- 在我的情况下,传递目标必须不是原始结构/对象的副本,因为回调函数的地址是根据原始对象进行并行中断检查的,并在调用HAL_I2C_Master_Transmit_DMA函数中更新。如果不正确地结束在HAL_I2C_EV_IRQHandler中形成循环,因为hi2c->XferISR始终为NULL。
要检查的内容:在函数中的中断处理程序中,I2C处理程序是否与名称完全相同,还是名称不同,但新的处理程序只使用旧处理程序的指针。在我的情况下,它们与我的调用hi2c1的主要对象和函数i2cHandler不同。
解决方案对我来说是只使用指针的副本,而不是处理程序的内容。
- 使用STM32 H7开发板存在内存分配问题,下面的文章中提供了解决方案。
https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices
英文:
Finally found the solution. I summarise some issues I had:
HAL_I2C_Master_Transmit_DMA(i2cHandler, MPUADDR, i2cData, 2);
- The Deliverable data: The deliverable data must be global variable for DMA, otherwise when I am leaving the function/ or calling a destructor of the object the memory is freed and the DMA aburts.
- The delivery target in my case the i2cHandler must not be the copy of the original structure/objetc, because the callback function addresses are checked from parallel interrupts based on the original object and updated in the caling HAL_I2C_Master_Transmit_DMA function. If incorrect ending up in a loop in the HAL_I2C_EV_IRQHandler because teh hi2c->XferISR is alvais NULL.
What to check: If the I2C handler is exacly the same in the interrupt handler from the function or the name is different, but the new one only uses a pointer to the old one. In my case thy where not the same from the myin called hi2c1 and the function i2cHandler.
[Name from the main]https://i.stack.imgur.com/OhqJT.png
The solution for me was to use the copy of the pointer only not the contant of the hendler.[Copy of the struct]https://i.stack.imgur.com/JgmTU.png
- With the STM32 H7 boards there is a memory allocation issue which is explaind with the solution in the below article.
https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论