cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 - Using ADC with DMA is corrupting memory.

Stou.1
Associate II

I'm having trouble using ADC with DMA. It is working correct, I'm getting the correct result. But DMA is corrupting another data which is not related with DMA in runtime. I'm also using Ethernet, because of it, I can not disable D-Cache.

I do my Ethernet, DMA, MPU configurations according to the following article (without RTOS)

https://community.st.com/s/article/How-to-create-project-for-STM32H7-with-Ethernet-and-LwIP-stack-working

And also I read

https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices

But like I say, I do not want to disable d-cache.

I use example in STM32Cube repository to use ADC with DMA:

void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
	if(hadc == &hadc1)
	{
		/* Invalidate Data Cache to get the updated content of the SRAM on the first half of the ADC converted data buffer: 32 bytes */
		SCB_InvalidateDCache_by_Addr((uint32_t *) &adc1.m_rawResult[0], 7);
	}
	if(hadc == &hadc3)
	{
		/* Invalidate Data Cache to get the updated content of the SRAM on the first half of the ADC converted data buffer: 32 bytes */
		SCB_InvalidateDCache_by_Addr((uint32_t *) &adc2.m_rawResult[0], 8);
	}
}
 
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if(hadc == &hadc1)
	{
		/* Invalidate Data Cache to get the updated content of the SRAM on the first half of the ADC converted data buffer: 32 bytes */
		SCB_InvalidateDCache_by_Addr((uint32_t *) &adc1.m_rawResult[4], 7);
	}
	if(hadc == &hadc3)
	{
		/* Invalidate Data Cache to get the updated content of the SRAM on the first half of the ADC converted data buffer: 32 bytes */
		SCB_InvalidateDCache_by_Addr((uint32_t *) &adc2.m_rawResult[4], 8);
	}
}

Thank you!

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

Put the buffer in its own array and use the aligned directive:

uint32_t aligned_array[16] __attribute__ ((aligned (32)));

You can verify in the map file that it gets aligned to a 32-byte boundary

                0x00000000200000e0                aligned_array

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

7 REPLIES 7
TDK
Guru

Is adc1.m_rawResult aligned to 32-byte cache boundary and is there nothing else within that 32-bytes?

If you feel a post has answered your question, please click "Accept as Solution".
TDK
Guru

Note that the address you pass to SCB_InvalidateDCache_by_Addr needs to be aligned, which yours can't be (since you pass addresses 16 bytes away from each other.

/**
  \brief   D-Cache Invalidate by address
  \details Invalidates D-Cache for the given address
  \param[in]   addr    address (aligned to 32-byte boundary)
  \param[in]   dsize   size of memory block (in number of bytes)
*/
__STATIC_INLINE void SCB_InvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize)

If you feel a post has answered your question, please click "Accept as Solution".
Stou.1
Associate II

Thanks a lot for your answer. I'm unexperienced to use of cache. How can I align it to 32-byte boundary. I was just define it as unsigned short m_rawResult[CHANNEL_SIZE];

TDK
Guru

Put the buffer in its own array and use the aligned directive:

uint32_t aligned_array[16] __attribute__ ((aligned (32)));

You can verify in the map file that it gets aligned to a 32-byte boundary

                0x00000000200000e0                aligned_array

If you feel a post has answered your question, please click "Accept as Solution".
Stou.1
Associate II

Thank you so much :) But I missed a point. You said 'since you pass addresses 16 bytes away from each other' why? May you suggest from which document/source can I access the information about this?

TDK
Guru

> You said 'since you pass addresses 16 bytes away from each other' why?

Two of your lines are as follows:

SCB_InvalidateDCache_by_Addr((uint32_t *) &adc2.m_rawResult[0], 8);
...
SCB_InvalidateDCache_by_Addr((uint32_t *) &adc2.m_rawResult[4], 8);

Since m_rawResult is an array of uint32_t (4 bytes each), these two addresses are 4*4=16 bytes away from each other. Thus, they cannot both be aligned to a 32-byte boundary.

If your buffer is exactly 32 bytes, you could invalidate the entire buffer on each call.

If you feel a post has answered your question, please click "Accept as Solution".
Stou.1
Associate II

It was so clear. I'm very thankful.