Skip to main content
Associate
April 15, 2026
Question

DMA2D Transfer Complete (TCIF=1) but destination AXI SRAM is always 0

  • April 15, 2026
  • 2 replies
  • 129 views

Hi everyone,

I am currently developing an image capture project using the STM32N657 (Cortex-M55) and have encountered an extremely bizarre DMA2D write issue (a silent failure).

  • Goal: Use DMA2D (M2M_PFC) to convert an RGB565 buffer to RGB888 and write it to CPUAXI_RAM1 (0x34080000).

[Problem Description] I wrote a "minimal isolation test" to bypass all camera/GPDMA variables. I forced the CPU to fill the source buffer with pure white (0xFFFFFFFF), and then manually triggered the DMA2D to transfer it to the destination buffer. The Result: The DMA2D finishes successfully. The DMA2D->ISR register reads 0x00000002 (the TCIF Transfer Complete Interrupt Flag is set, and there are NO Transfer Errors). However, the destination buffer remains completely filled with 0x00000000.

[Troubleshooting Done] To isolate the issue, I have verified the following, but the problem persists:

  1. CPU Read/Write Test (Pass): Before triggering the DMA2D, I forced the CPU to write 0xDEADBEEF to the destination address and read it back. It worked perfectly. This proves the AXI SRAM clock is enabled and the physical memory is alive.

  2. MPU & Cache (Verified): The destination address is covered by MPU Region 15 configured as Non-cacheable. To be absolutely certain, I am calling SCB_CleanInvalidateDCache_by_Addr() on both buffers before the transfer, and SCB_InvalidateDCache_by_Addr() after the transfer to force the CPU to read physical memory.

  3. RIF/RISAF Security Framework (Configured): * I configured the DMA2D's RIMC attributes to NSEC | PRIV to align with the memory access level.

    • I set the RISAF (SRAM firewall) filtering to DISABLE (and also tried setting Read/Write Whitelist to 0xFF), ensuring the hardware firewall is not blocking the write.

  4. Register State (Verified): By pausing the program right after the transfer, I verified that OMAR and FGMAR contain the exact, correctly aligned physical addresses of my buffers. No pointer casting issues are present.

Despite the hardware reporting a successful transfer and all permissions seemingly being granted, absolutely no data is written to the AXI SRAM by the DMA2D.

Are there any hidden AXI Interconnect mechanisms, TrustZone/RIF blind spots, or Cortex-M55 specific coherency rules in the STM32N6 architecture that would cause a DMA2D write to be "silently dropped" while still returning a TCIF?

1. Buffer Declarations & DMA2D Init (dma2d.c):

uint32_t full_frame_buf[57600] __attribute__((section(".noncacheable"), aligned(32)));
uint32_t line_buf[2560] __attribute__((section(".non_cacheable_data"), aligned(32)));

// DMA2D configured as M2M_PFC, Output: RGB888, Input: RGB565
hdma2d.Init.Mode = DMA2D_M2M_PFC;
hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB888;
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565;
hdma2d.LayerCfg[1].InputAlpha = 0xff;

2. Isolation Test inside main():

// ================= Ultimate Isolation Test =================
__disable_irq();

// 1. Force source buffer to white
for(int i = 0; i < 2560; i++) {
 line_buf[i] = 0xFFFFFFFF;
}
SCB_CleanInvalidateDCache();

// 2. Clear BUSY lock and start DMA2D
hdma2d.State = HAL_DMA2D_STATE_READY;
DMA2D->CR &= ~DMA2D_CR_START;
uint32_t test_src=(uint32_t)&line_buf[0];
uint32_t test_dest = (uint32_t)full_frame_buf;
volatile HAL_StatusTypeDef start_res = HAL_DMA2D_Start(&hdma2d, test_src, test_dest, 320, 8);

// 3. Wait for hardware transfer to finish
while((DMA2D->CR & DMA2D_CR_START) != 0) {
 __NOP();
}

// 4. Check ISR (Result is 2 -> TCIF is set!)
volatile uint32_t debug_isr = DMA2D->ISR; 

// 5. Explicitly invalidate D-Cache
SCB_InvalidateDCache_by_Addr((uint32_t *)full_frame_buf, 7680);

// 6. Read result (Truth value is still 0x00000000)
volatile uint32_t truth_val = full_frame_buf[0];

__NOP();
__enable_irq();
// ===========================================================

 

3. RIF/RISAF & MPU Configurations:

/* RIMC Configuration for DMA2D */
RIMC_MasterConfig_t RIMC_master = {0};
RIMC_master.MasterCID = RIF_CID_0;
RIMC_master.SecPriv = RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV;
HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_DMA2D, &RIMC_master);

/* RISAF Configuration for AXI RAM */
RISAF_BaseRegionConfig_t risaf_base_config;
risaf_base_config.EndAddress = 0x3ffff;
risaf_base_config.Filtering = RISAF_FILTER_ENABLE;
risaf_base_config.ReadWhitelist = 255;
risaf_base_config.WriteWhitelist = 255;
risaf_base_config.Secure = RIF_ATTRIBUTE_SEC;
risaf_base_config.PrivWhitelist = 255;
risaf_base_config.StartAddress = 0x0000;
HAL_RIF_RISAF_ConfigBaseRegion(RISAF3, RISAF_REGION_1, &risaf_base_config); // CPUAXI_RAM1
HAL_RIF_RISAF_ConfigBaseRegion(RISAF2, RISAF_REGION_1, &risaf_base_config); // CPUAXI_RAM0

/* MPU Configuration */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER15;
MPU_InitStruct.BaseAddress = 0x34080000;
MPU_InitStruct.LimitAddress = 0x340C0000;
MPU_InitStruct.AttributesIndex = MPU_ATTRIBUTES_NUMBER0;
MPU_InitStruct.AccessPermission = MPU_REGION_ALL_RW;
// MPU Attribute 0 is configured as INNER_OUTER(MPU_NOT_CACHEABLE)

Any guidance on why DMA2D successfully completes but leaves the physical SRAM empty would be greatly appreciated. Thank you!

2 replies

KDJEM.1
Technical Moderator
April 20, 2026

Hello @Jason32 ,

 

Do you get the same behavior when using DMA2D_MemToMemWithPFC example?

 

Thank you.

Kaouthar

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.
ST Employee
April 21, 2026

Hello all, 

The issue is most likely the DMA2D CID, not DMA2D itself and not AXISRAM1.

On STM32N6, AXI transactions carry a compartment ID, or CID, and RISAF filters memory accesses based on that CID. The CPU always issues AXI accesses with CID = 1, but DMA2D is a separate AXI initiator, so its CID comes from the RIMC configuration. That means it is entirely possible for CPU writes to the destination buffer to work as you have noticed while DMA2D writes to the same buffer are blocked.

In the reported code, DMA2D was configured with RIF_CID_0. In my reproduction, changing DMA2D to RIF_CID_1 made the transfer work. That matches RM0486 section 3.5.4 Multi-tenancy: the memory-access policy on that path is accepting CID = 1 traffic, while DMA2D was emitting CID = 0 traffic. So DMA2D could run and report transfer complete, but the AXI fabric could still reject its writes to the destination RAM.

Please let us know how it works out for you,

Kind regards, 

DHIF Khaled

 

"Please mark my answer as best by clicking on the “Accept as solution"" button if it fully answered your question. This will help other users find this solution faster.​"