Skip to main content
MLuis.1
Associate III
May 29, 2023
Question

STM32H7's I2C4 using BDMA not triggering Complete Callbacks.

  • May 29, 2023
  • 3 replies
  • 3521 views

I'm using an STM32H725 to communicate with an i2c sensor. I'm using the I2C4 bus with the HAL DMA functions. I also enabled the BDMA channels for the rx and tx and respective interrupts. The problem is that the complete rx/tx callbacks are not triggered.

I found that this could be related to the problem described here: https://st.my.site.com/community/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices

Any solutions to this problem?

3 replies

Foued_KH
ST Employee
May 30, 2023

Hello @MLuis.1​ ,

First, make sure that you are using the correct address and the correct frequency for the I²C communication.

The take an oscilloscope to check the I2C_SDA and I2C_SCL behavior to define the error source.

Foued

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
MLuis.1
MLuis.1Author
Associate III
May 30, 2023

The I2C communications work fine as long as I use the IT functions or polling functions.

The problem only occurs when using DMA.

Foued_KH
ST Employee
May 30, 2023

You should place the buffer for transmission or reception in the SRAM4.

SRAM4 region : 0x38000000 - 0x38003FFF

Foued

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
haleecaero.1
Associate II
April 9, 2025

The easiest way may be to manage the memory yourself, e.g.: 

uint8_t* ramd3 = 0x38000000;

now, as long as the linker doesn't put anything there, you can  manage those 64K of ramd3 for yourself (I got the offset and size from the .ld file, so double check it there for your platform). To prevent the linker from placing stuff in there inadvertently, you could remove the RAM_D3 entry from the .ld file.

If instead you want to do it the proper way, using `__attribute((section.(..)))__` , you need to add a SECTION (hence the name) to the .ld file, e.g.: inside the existing SECTIONS block, add:

.ramd3 :
{
KEEP(*(.RAM_D3_SECTION))
} >RAM_D3

Then you can declare your variables as 

uint8_t __attribute__((section(".RAM_D3_SECTION"))) Tx_I2C[1];

 

Should the HAL report this error in a better way? I think so https://github.com/STMicroelectronics/STM32CubeH7/issues/315

 

Note that if you use objcopy to create binaries you need to explicitly exclude this section or you'll get an 800 MB binary:

arm-none-eabi-objcopy -O binary -R .ramd3 FILE.elf FILE.bin
Visitor II
December 11, 2025

First time posting a solution, so hope this helps and the format is acceptable.

To get the callbacks to work in the simplest format, as specified in the updated link:
https://community.st.com/t5/stm32-mcus/dma-is-not-working-on-stm32h7-devices/ta-p/49498

The problem is the BDMA controller is only allowed to access the SRAM4 region. Using the default setup that would typically work on standard DMA will cause transmit errors, if you use the HAL_I2C_ErrorCallback() this is shown by the hi2c->ErrorCode returning (int)16 value, which in the stm32h7xx_hal_i2c.h translates to HAL_I2C_ERROR_DMA. 

It also gives more specific details about the error type on the DMA through hi2c->hdmatx and hi2c->hdmarx. To fix it just move the global variables created for the BDMA to the SRAM4 region, as mentioned (sort of) in the article. Tod do this in STM32CubeIDE find the STM32H7A3ZITXQ_FLASH.ld and STM32H7A3ZITXQ_RAM.ld files, or whatever the FLASH.Id and RAM.Id files are called. In both files add:

.dma_buf (NOLOAD) :
{
. = ALIGN(4);
KEEP(*(.dma_buf))
. = ALIGN(4);
} >RAM_SRD

Ensure that the >RAM_SRD region described at the top of the files matches the BDMA SRAM region for the microcontroller, for stm32h7a3zi it will. Once added to both files, include the following definition in the file where the BDMA code is implemented:

#define DMA_BUFFER __attribute__((section(".dma_buf")))

Then declare all BDMA related global variables using the define, e.g: DMA_BUFFER uint8_t TxBuffer[32];

You can confirm that the variable have been moved by looking in the Project > Debug > ProjectName.list file where this allocation should be visible:

9 .dma_buf        00000024   38000000   38000000   00019000   2**2
                          ALLOC

Before doing the above, the STM tries to allocate the data to the standard .data SRAM region which is inaccessible to the BDMA and will cause the I2C transmission/reception to fail.