cancel
Showing results for 
Search instead for 
Did you mean: 

Help with HPDMA + ADC on STM32H7S3L8

chintal
Associate II

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:

chintal_1-1736421059030.png

These are the DMA register contents :

chintal_0-1736419377359.png

The following are the bits set in the DMA registers:

  • CR : EN, TCIE, Priority of 0b11
  • TR1:
    • SDW_LOG2 : 0x1 (2 bytes)
    • SBL_1: 0x0 (single)
    • SAP: 1 (AHB Port)
    • DDW_LOG2: 0x2 (4 bytes)
    • DBL_1: 0x0 (single, though I do want to increase this later)
    • DAP: 1 (AHB Port, writing to DTCM)
  • TR2
    • REQSEL: 0x08 (adc1_dma)
    • TRIGM: 0x3 (trig for every burst, though this should not matter)
    • TRIGSEL and TRIGPOL : 0x00
    • TCEM : 0x2 (TC for every LLI)
  • BR1: BNDT 0x0280 (640 bytes. 10 channel * 32 samples * 2 bytes each)
  • SAR : 0x4022040 (ADC1 DR)
  • DAR: Start address of buffer in DTCM

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.

 

 

 

2 REPLIES 2
chintal
Associate II

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.

 

 

itsjimwill
Visitor

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:

  • DMA Request Configuration: Ensure that the ADC is correctly configured to generate DMA requests. Verify that the correct trigger source is selected for the DMA in the ADC configuration.
  • Trigger Source: Make sure that the timer triggering the ADC is properly configured and that it is indeed generating events as expected.
  • Buffer Setup: Ensure that your target buffer is correctly allocated and accessible by the DMA controller.

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.