logo elektroda
logo elektroda
X
logo elektroda

[STM32F4] [HAL] Getting data from multiple ADC channels from DMA does not work

Azahiel113 6753 10
ADVERTISEMENT
Treść została przetłumaczona polish » english Zobacz oryginalną wersję tematu
  • #1 16943121
    Azahiel113
    Level 2  
    Hello hope to find some solution to my problem. Namely, I use the HAL, cubeMX and STM Studio libraries (I tried to cover the registers, but I would like to leave it for the future). I measure on two ADC channels and use DMA to save 256 elements in two arrays. When I write data to a table from a single channel, everything works as it should, and when I use two, in STM studio I see that the measurements are taking place normally, but when I look at the values in the tables, they are not updated.
    My question is, is it possible that STM Studio is not comfortable with displaying data, or whether the reason is in the operation of the program itself, the whole thing is very simple and looks like this.
    Declared variables:
    
    uint32_t PomiarADC[2];
    uint32_t sygnalL[200], sygnalR[200];
    int i = 0;
    

    Starting ADC measurements by DMA:
    HAL_ADC_Start_DMA(&hadc1, PomiarADC, 2);


    And the same interrupt where I would like to rewrite the values
    
    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    
    	sygnalL[i] = PomiarADC[0];
    	sygnalR[i] = PomiarADC[1];
    	if (i >= 200)
    		i = 0;
    	else
    		i++;
    }
    

    I am adding the ADC and DMA configuration generated by Cuba, but I do not know if the program itself has a chance to work
    
    static void MX_ADC1_Init(void)
    {
    
    ADC_ChannelConfTypeDef sConfig;
    
    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
    */
    hadc1.Instance = ADC1;
    hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
    hadc1.Init.Resolution = ADC_RESOLUTION_12B;
    hadc1.Init.ScanConvMode = ENABLE;
    hadc1.Init.ContinuousConvMode = ENABLE;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.NbrOfConversion = 2;
    hadc1.Init.DMAContinuousRequests = ENABLE;
    hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
    if (HAL_ADC_Init(&hadc1) != HAL_OK)
    {
    _Error_Handler(__FILE__, __LINE__);
    }
    
    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
    */
    sConfig.Channel = ADC_CHANNEL_1;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    {
    _Error_Handler(__FILE__, __LINE__);
    }
    
    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
    */
    sConfig.Channel = ADC_CHANNEL_2;
    sConfig.Rank = 2;
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    {
    _Error_Handler(__FILE__, __LINE__);
    }
    
    }
    
    /** 
    * Enable DMA controller clock
    */
    static void MX_DMA_Init(void) 
    {
    /* DMA controller clock enable */
    __HAL_RCC_DMA2_CLK_ENABLE();
    
    /* DMA interrupt init */
    /* DMA2_Stream0_IRQn interrupt configuration */
    HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
    
    }
    
    

    I've read a lot about it, but it's a bit overwhelming for me to quit HAL and Cuba at the moment, so I'd be grateful for any information that might help me understand why it's not working as it should.
    I can add that I plan to take audio signals from two microphones and perform a cross-correlation algorithm to determine the direction from which the sound comes. Ultimately, after crossing the trigger threshold, I would like to make a few more measurements and then determine for which shift the correlation is the greatest. If it turned out that I overestimated my abilities, I would not despise some alternative way of achieving it.
  • ADVERTISEMENT
  • #2 16943302
    Freddie Chopin
    MCUs specialist
    Using DMA to read as many as two values is completely pointless - if you have a problem with DMA then eliminate the unknowns by skipping DMA and using an ADC interrupt.

    In any case, the fact that you don't see variables changing in the debugger may be due to the lack of a magic modifier starting with 'v' and ending with 'e' - if these arrays are not used elsewhere in the code then the compiler will simply put them in skips at all (with optimization enabled).

    And by the way, the types of these arrays should be uint16_t rather than uint32_t.
  • ADVERTISEMENT
  • #3 16943311
    czareqpl
    Level 33  
    See if there is anything helpful here:

    Code: C / C++
    Log in, to see the code



    It works fine for me, but on a different microcontroller.
    Remember that when starting DMA, you must enter the address, not the value of your array.
  • ADVERTISEMENT
  • #4 16943328
    Freddie Chopin
    MCUs specialist
    czareqpl wrote:
    Remember that when starting DMA, you must enter the address, not the value of your array.

    And that's exactly what the code does.
  • ADVERTISEMENT
  • #5 16943782
    czareqpl
    Level 33  
    You have:
    HAL_ADC_Start_DMA (& hadc1, Measure ADC, 2);

    It should be like this in my opinion:
    HAL_ADC_Start_DMA (& hadc1, & ADC Measure [0], 2);
  • #6 16943795
    grko
    Level 33  
    @czareqpl It just so happens that both entries are equivalent.
  • #7 16943802
    tronics
    Level 38  
    Quote:
    & PomiarADC [0]

    Measure ADC is the name of an array, so also a pointer to its beginning, ergo & Measure ADC [0] extracting the address of the zero element of this array does the same.
    edit. you beat me
  • #9 16944033
    Azahiel113
    Level 2  
    Generally, as far as I know, in order not to actually make too large variables, I can set the Measure ADC variable to uint16_t and give a record when starting adc
    HAL_ADC_Start_DMA (& hadc1, (uint32_t *) ADC measurement, 2); , but both this and giving variables a "magic modifier" ;) volatile did not change my results. Maybe it is actually worth giving up the DMA, but in the end I would like to make 4 measurements and here it could be useful. However, staying with the interrupt, in order to save both values, I would have to save the measurement result from one channel and only in the second interrupt from the other, because from what I think the ADC can only store one measurement at a time, is it correct? My point is that the program itself would need to add conditions-
    
    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    if (indeks ==0) pomiarL[i]=HAL_ADC_GetValue(&hadc1);
    else {
    pomiarR[i]=HAL_ADC_GetValue(&hadc1);
    indeks=0;
    i++;
    }

    If not, I would be grateful for some help, because I still have problems with making many measurements other than with DMA.

    In general, thank you for such a quick interest in the topic :)
  • #10 16944046
    Freddie Chopin
    MCUs specialist
    Azahiel113 wrote:
    Maybe it is actually worth giving up DMA, but in the end I would like to make 4 measurements and here it could be useful.

    First you run without, then add DMA.

    Azahiel113 wrote:
    However, staying with the interrupt, in order to save both values, I would have to save the measurement result from one channel and only in the second interrupt from the other, because from what I think the ADC can only store one measurement at a time, is it correct?

    That's right, the stop would have to be every single measurement.
  • #11 16944406
    Azahiel113
    Level 2  
    Ok, I'll test this solution. And when analyzing my code, is there a probability that everything works as it should, but for some reason I cannot view the data, or should I be more focused on some error in the transmission of information resulting from a wrong converter configuration?

Topic summary

The discussion revolves around issues encountered when using DMA to read data from multiple ADC channels on an STM32F4 microcontroller with HAL and CubeMX libraries. The user reports that while single-channel data acquisition works correctly, the values from two channels do not update in STM Studio. Responses suggest troubleshooting by first eliminating DMA and using ADC interrupts to verify functionality. It is noted that the data types of the arrays should be uint16_t instead of uint32_t, and the importance of using the 'volatile' keyword to prevent compiler optimization issues is emphasized. The user is advised to check the ADC configuration and consider that the ADC can only store one measurement at a time, necessitating careful handling of interrupts for multiple channels.
Summary generated by the language model.
ADVERTISEMENT