Konwersja STM32 ADC za pomocą HAL

10

Próbuję nauczyć się korzystać z „nowej” biblioteki HAL ze stm32.
Kiedy próbuję wykonać prostą konwersję ADC, działa to tylko raz, ale potem przestaje konwertować. Przypuszczam, że flaga końca konwersji nie została ustawiona. Korzystam z płyty Discovery STM32f429I, która ma na pokładzie STM32f429ZI.
Zauważ, że wiem o tym, że sprintf jest złym ćwiczeniem, a robienie adc z przerwaniem jest lepsze. Wiem, że nie zaznaczaj tego, to nie ma znaczenia dla pytania, właśnie testuję tutaj HAL.
Pytanie brzmi zatem, dlaczego flaga EOC nie jest ustawiona lub co mogę zrobić, aby działała? Googling niewiele pomaga, ponieważ niewiele jest dobrych materiałów na temat HAL.

Oto kod:

__IO uint16_t ADCValue=0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc);

int main(void)
{
  char str[15];

  /* Various initializations */

  HAL_ADC_Start(&hadc1);
  while (1)
  {

        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
            sprintf(str, "%d", ADCValue);
            BSP_LCD_DisplayStringAt(130,30, (uint8_t*)str, LEFT_MODE);
        }

  }

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    ADCValue = HAL_ADC_GetValue(&hadc1);
}

Stworzyłem również projekt z CubeMX, konfiguracja ADC jest następująca: wprowadź opis zdjęcia tutaj

EDYCJA 1
Próbowałem wszystko debugować i wydaje się, że program utknął w sprawdzaniu flagi EOC - widzi, że nie jest pokazywany, a zatem wystawia czas oczekiwania na pojawienie się EOC (ale nigdy się nie ustawia) Oto kod, w którym utknął w debuggerze:

/* Check End of conversion flag */
  while(!(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)))
  {
    /* Check for the Timeout */
    if(Timeout != HAL_MAX_DELAY)
    {
      if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout))
      {
        hadc->State= HAL_ADC_STATE_TIMEOUT;
        /* Process unlocked */
        __HAL_UNLOCK(hadc);
        return HAL_TIMEOUT;
      }
    }
ScienceSamovar
źródło

Odpowiedzi:

6

W swoim oryginalnym kodzie ustaw opcję Wybór końca konwersji na wyłączoną.

 hadc1.Init.EOCSelection = DISABLE;

Okazało się, że #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)wartość jest równa DISABLE. Tak więc EOCSelection powinien być skonfigurowany jako: aby móc sondować ADC wiele razy.wprowadź opis zdjęcia tutaj

Następnie możesz czytać ADC w sposób ciągły, bez zatrzymywania i uruchamiania ADC:

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    ConfigureADC();

    HAL_ADC_Start(&hadc1);
    while(1)
    {
        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
        }
    }
}

W ten sposób działało dla mnie dobrze.

Ponieważ HAL jest całkiem nową biblioteką, nie ma zbyt wielu zasobów do znalezienia, ale nie jest to niemożliwe. Wiele się nauczyłem z tego samouczka , który pokazuje krok po kroku wszystkie możliwe zastosowania ADC; od prostego odpytywania, po używanie przerwań i DMA.

Bence Kaulics
źródło
hm ... wyłączenie EOCSelection sprawia, że ​​działa, ale z jego definicji mówi - Określa, czy flaga EOC jest ustawiona na końcu konwersji pojedynczego kanału czy na końcu wszystkich konwersji. Wyłączenie tego nie powinno z definicji pomóc ... ale pomaga .... mylące. Czy wiesz, dlaczego to dokładne wyłączenie powoduje, że działa? dzięki za odpowiedź i tak
ScienceSamovar
Uczę się też HAL, więc nie znam jeszcze powodu. To tylko doświadczenie. Przekonałem się, że HAL może wywoływać wiele problemów.
Bence Kaulics,
Sprawdziłem zdefiniowane wartości, #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)które są takie same jak wyłączone, więc wyłączone jest tak naprawdę ADC_EOC_SEQ_CONV.
Bence Kaulics
1
och, ok, więc to nie jest dosłownie wyłączone. Ma to sens, wcześniej było to ADC_EOC_SINGLE_CONV, co prawdopodobnie oznacza właśnie to - konwertuje tylko jeden raz, a ADC_EOC_SEQ_CONV jest konwersją ciągłą. Jeszcze jedna tajemnica rozwiązana :) Dzięki!
ScienceSamovar,
Tak, tak powinno być. :)
Bence Kaulics
2

Hm ... Znalazłem kilka samouczków, które wykorzystywały HAL_ADC_Stop (& hadc1) do zakończenia konwersji ... Patrzyłem już na te samouczki i pomyślałem, że to raczej barbarzyński sposób, wygląda na to, że całkowicie wyłącza ADC, więc pomyślałem, że powinno być inna metoda. Ale wydaje się, że to faktycznie działa dobrze.
Zachęcamy do opublikowania odpowiedzi, jeśli istnieje bardziej elegancki sposób na zrobienie tego, ponieważ myślę, że użycie HAL_ADC_Stop () jest dość okropne, ale może być wykorzystane do celów edukacyjnych.

while (1)
  {
        HAL_ADC_Start(&hadc1);
        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
                        sprintf(str, "%d", ADCValue);
                        BSP_LCD_DisplayStringAt(130,30, (uint8_t*)str, LEFT_MODE);
        }
        HAL_ADC_Stop(&hadc1);

  }
ScienceSamovar
źródło
Cześć, znalazłem problem z tą metodą, ogranicza ona maksymalną częstotliwość próbkowania, którą możesz uzyskać DUŻO, nie jest zalecane stosowanie tej metody, jeśli potrzebujesz szybkich konwersji ADC.
Richard Bamford,
2

Chciałbym dodać, że dla mojej konfiguracji (nukleo-h743) nie wystarczyło ustawić:

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

Musiałem również włączyć ustawienie przekroczenia:

hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

Bez tego HAL_ADC_PollForConversion nadal blokował. Nie do końca rozumiem, dlaczego było to konieczne, ale pozwala mi na sondowanie w trybie ciągłym.

biglotusturtle
źródło
0

To działa dla mnie, mam nadzieję, że pomoże:

if (HAL_ADC_Start(&hadc) != HAL_OK)
{
    /* Start Conversation Error */
    // Error_Handler();
}
if (HAL_ADC_PollForConversion(&hadc, 500) != HAL_OK)
{
    /* End Of Conversion flag not set on time */
    // Error_Handler();
    ADCValue=-1;
}
else
{
    /* ADC conversion completed */
    /*##-5- Get the converted value of regular channel ########################*/
    ADCValue = HAL_ADC_GetValue(&hadc);
}
HAL_ADC_Stop(&hadc);
Janów Maor
źródło