Skip to main content
LCE
Principal II
March 16, 2026
Solved

H723..H735: functions in ITCM, strange behaviour

  • March 16, 2026
  • 5 replies
  • 209 views

Heyho,

I recently found that I'm not using ITCM RAM at all, then started to put heap and stack there.

No problems so far.

Then I copied some functions there, and all went well - until I found some strange behaviour:

  • 1..4 SAI RX DMA transfers running, circular mode
  • when all these transfers are complete for each SAI, a function is called to copy the complete DMA buffer from internal AXI SRAM into the big buffer in HyperRAM
  • also in this function a packet counter (a global u32 in DTCM) is incremented once
  • but when this function is in ITCM, this packet counter increments for each SAI active, but there are no extra packets

 

Further info:

- instruction cache: in use

- data cache: not used

 

Is there any guideline what to put in ITCM, what are the limits, etcpp. ?

Best answer by FBL

Hi  @LCE 

Few checks that might help narrow it down:

  • Is it invoked in the SAI/DMA transfer complete callback for each SAI? Are you perhaps using the same callback for multiple SAI/DMA handles, so the counter is effectively updated once per active SAI rather than once per packet?
  • With the function executing faster in ITCM, another SAI/DMA interrupt might enter it again before it returns. You could add a simple volatile flag and a breakpoint (or maybe GPIO toggle) inside the function to detect whether it is being re-entered.

5 replies

LCE
LCEAuthor
Principal II
March 16, 2026

... and yes, I checked AN4891, but that's more about benchmarks.

Not really clear about any requirements, but it looks like a function in ITCM doesn't have any restrictions about variable locations.

TDK
Super User
March 16, 2026

There are no restrictions with putting code into ITCM. It will run faster which can expose some bugs in the code, much the same as switching between Debug and Release can do.

Variables can't live in ITCM since it is dedicated for instructions. They are never put there in a normal workflow, you would have to be explicitly mixing code and data in the same section.

"If you feel a post has answered your question, please click ""Accept as Solution""."
LCE
LCEAuthor
Principal II
March 17, 2026

It will run faster which can expose some bugs in the code,
> much the same as switching between Debug and Release can do.

 

This is something I actually like very much about Release / Debug / Optimization On/Off.

But in this case it's so crazy simple - but maybe there's something I just don't see. I'll go check once more...

FBLBest answer
Technical Moderator
March 18, 2026

Hi  @LCE 

Few checks that might help narrow it down:

  • Is it invoked in the SAI/DMA transfer complete callback for each SAI? Are you perhaps using the same callback for multiple SAI/DMA handles, so the counter is effectively updated once per active SAI rather than once per packet?
  • With the function executing faster in ITCM, another SAI/DMA interrupt might enter it again before it returns. You could add a simple volatile flag and a breakpoint (or maybe GPIO toggle) inside the function to detect whether it is being re-entered.
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.Best regards,FBL
LCE
LCEAuthor
Principal II
March 18, 2026

@FBL thanks, yes, there was a multiple DMA interrupt race condition.

I already used __disable_irq(); to prevent this, but in the callback it was "too late", as there's done too much in the HAL interrupt handler (which for DMA is one of the better / faster HAL interrupt handlers, which I usually avoid using).

Still need to have another look at it...

This way it works:

/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* SAI DMA interrupt handlers
 * 	the global HAL_DMA_IRQHandler()
 *		- resets all flags
 *		- calls the half- / complete callback functions
 */

/* SAI 1 A as ADC */
void DMA1_Stream0_IRQHandler(void)
{
	__disable_irq();
	HAL_DMA_IRQHandler(&hDMA_Sai_1_A);
	__enable_irq();
}

/* SAI 1 B as ADC */
void DMA1_Stream1_IRQHandler(void)
{
	__disable_irq();
	HAL_DMA_IRQHandler(&hDMA_Sai_1_B);
	__enable_irq();
}

/* SAI 4 A as ADC */
void BDMA_Channel0_IRQHandler(void)
{
	__disable_irq();
	HAL_DMA_IRQHandler(&hDMA_Sai_4_A);
	__enable_irq();
}

/* SAI 4 B as ADC */
void BDMA_Channel1_IRQHandler(void)
{
	__disable_irq();
	HAL_DMA_IRQHandler(&hDMA_Sai_4_B);
	__enable_irq();
}