2025-01-09 03:17 AM - edited 2025-01-09 03:19 AM
I've been trying to get DMA to work on the STM32H7S3L8 with bare metal code. As far as I can tell, I have everything set up correctly(?). I get no DMA error flags. The DMA complete flag is never set and the target buffer remains empty.
I have enabled 10 ADC channels and have set it up to trigger from a timer. This works fine without DMA, and the ADC EOC interrupts fire. I have toggled a GPIO in the ADC conversion complete interrupt handler which switches as expected, and clear the end of conversion flag also in the handler.
Both GPDMA and HPDMA work fine with software triggered memory-memory transfers. I suspect there is either something preventing the ADC DMA request from reaching the HPDMA or something to do with how the trigger is configured. I do not wish to have a separate trigger, just transfer when there is ADC data ready.
Both DMAEN and DMACFG are set to 1 in ADC1_CFGR, and these are the ADC register contents:
These are the DMA register contents :
The following are the bits set in the DMA registers:
I don't have NVIC enabled for HPDMA or GPDMA, and use the following code in an infinite while loop to check for errors:
void dma_process_events(HAL_BASE_t intfnum){
uint32_t sr = *(HAL_SFR_t *)(dma_chn_if[intfnum].hwif.base + OFS_DMA_Cx_SR);
HAL_SFR_t * fcr = (HAL_SFR_t *)(dma_chn_if[intfnum].hwif.base + OFS_DMA_Cx_FCR);
if (!sr){
return;
}
if ((sr & DMA_CSR_TCF) && !(dma_chn_if[intfnum].state->use_int)){
// Clear the flag.
*fcr |= DMA_CFCR_TCF;
switch (dma_chn_if[intfnum].hwif.type) {
case DMA_CHN_TYPE_LINEAR:
dma_process_tc_linear(intfnum);
break;
case DMA_CHN_TYPE_CIRCULAR:
dma_process_tc_circular(intfnum);
break;
default:
die();
}
}
// Half transfer with linked list isnt going to work. We
// dont actually know which lli is at its halfway point by
// the time we get here. Half transfer will probably need
// interrupt based handling.
// if (sr & DMA_CSR_HTF){
// *fcr |= DMA_CFCR_HTF;
// if (dma_chn_if[intfnum].state->ll_active->cb_hc){
// dma_chn_if[intfnum].state->ll_active->cb_hc();
// };
// }
if (sr & DMA_CSR_USEF){
// User Setting Error
die();
}
if (sr & DMA_CSR_TOF){
// Trigger Overrun
die();
}
if (sr & DMA_CSR_ULEF){
// Update Link Transfer Error
die();
}
if (sr & DMA_CSR_DTEF){
// Data Transfer Error
die();
}
Any suggestions about where to look would be helpful, though. This feels a lot like a one of those times I don't have RCC enabled for some peripheral or something similar.
The initialization code itself is a little horrible, spread across multiple files with many layers of #defines. I can try to trim it down to a minimal example if required.
2025-01-09 03:55 AM
I seem to have it working. I don't quite know why it was not. SBL and DBL were originally not actually 0 (single), instead they were 1 and 4.
Once they were changed to 0 and 0. There is some ADC data now appearing in the buffer, though it seems inaccurate at present. It also immediately caused a buffer overflow and nuked a number of additional variables. By changing the size to 20, the memory corruption is removed and I think I now see that the size calculations are incorrect.
2025-01-09 04:02 AM
It seems you're encountering issues with DMA not transferring ADC data on the STM32H7S3L8. Since the ADC works correctly without DMA and you're not seeing any error flags, the problem may lie in the configuration of the DMA request or trigger settings.Here are a few points to check:
If all configurations seem correct but you're still facing issues, consider testing with a simpler setup (e.g., a single ADC channel) to isolate the problem.