Skocz do zawartości

ADC DMA Problem z wykonywaniem programu


Bornhartt

Pomocna odpowiedź

Dzień dobry,

Korzystam z STM32F103C8, oprogramowanie CUBEIDE, debugowanie st-link v2.

Problem polega na tym, że dobrze działające DMA w circular mode zawiesza program gdy dodaję do niego 4 linie obliczeń (sinusy, cosinusy, arcusy), #include <math.h> wpisałem.

obliczenia z wyłączoną konwersją również wykonują się poprawnie

/* USER CODE BEGIN 0 */
void set_coordinate (void)
{
		ST=hour+(4*(18-15));
		D = 23.45f*sinf(360*((284.f+day_of_year)/365)*rad)*rad;//////////////////////////////////blad
		Height = asinf(sinf(D)*sinf(W)+cosf(D)*cosf(W)*cosf((15*(hour-12))*rad))*rad;// nie dochodzi do tych obliczen
		A = acosf((sinf(D)-sinf(Height)*sinf(W))/(cosf(Height)*cosf(W)))*deg;
		H=Height*deg;
}

/* USER CODE BEGIN 2 */


  HAL_ADC_Start_DMA(&hadc1, adc_val, 4);


  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  //
	  set_coordinate();
	  motor_rad_1 = adc_val[0]/13.65;//podzielic przez zakres 4095/300 stopni
	  motor_rad_2 = adc_val[1]/13.65;
	  

	  
  }
  /* USER CODE END 3 */
}

hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 4;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel 
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}

/* Enable DMA controller clock
  */
static void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

}

Z kodu wyciąłem tylko najważniejsze rzeczy, mogę zamieścić dodatkowo screeny z konfiguracji ADC,DMA

Nie wyskakuje żaden błąd, tylko program zawiesza się na liniach obliczeń.

Dlaczego obliczenia zawieszają program? Czy to nie jest tak, że DMA nie korzysta z procesora?

Moim pomysłem byłoby zastosowanie wyzwalania konwersji przez licznik, wykonywanie jej co 200 ms, ale nie wiem, czy ma to sens, drugim pomysłem jest odczyt ADC zaraz po obliczeniach, ale nie mam pojęcia jak się do tego zabrać.

z góry dziękuję za odpowiedź

 

Edytowano przez Bornhartt
brak pewnej informacji
Link do komentarza
Share on other sites

(edytowany)

Prosiłbym tylko o odpowiedź czy to możliwe, że DMA może zawiesić wykonywanie obliczeń i czy wydłużenie odczytu danych do np. 100 ms załatwi sprawę ? (wyzwalanie za pomocą licznika)

EDIT: program zawiesza się na obliczeniach arcusów i w tym tkwi sęk

Edytowano przez Bornhartt
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

1 godzinę temu, Bornhartt napisał:

Prosiłbym tylko o odpowiedź czy to możliwe, że DMA może zawiesić wykonywanie obliczeń i

Tak działa DMA, zatrzymuje CPU. Jak DMA często "dobiera" się do danych to CPU prawie stoi. Dział co prawda (w STM32, nie wiem jak w innych) mechanizm karuzeli ale to moze znaczać w skrajnym przypadku, że CPU prawie nic nie ma szanys zrobić. Naturalnie jest to ewidentny błąd programisty.

Link do komentarza
Share on other sites

DMA nie zawiesza wykonywania obliczeń, ale w pewnych warunkach może mieć wpływ na czas działania procesora oraz wykonywanie programu. O ile sam mechanizm działa niezależnie od CPU, to w przypadku dostępu do tego samego modułu jak np. pamięci RAM możliwe jest spowolnienie działania procesora. Oba moduły master, czyli w tym wypadku CPU oraz DMA konkurują o dostęp do jednego układu podrzędnego (slave). Oznacza to, że gdy np. DMA zapisuje wyniki, CPU musi poczekać. Jednak to oczekiwanie to raptem jeden, a maksymalnie kilka cykli magistrali AHB. Co więcej spowalniane są tylko dostępy do pamięci, a procesor większość operacji np. arytmetycznych i tak wykonuje na rejestrach.

W przypadku ADC problem jest jeszcze mniejszy - DMA zapisuje wyniki dopiero po zakończeniu konwersji A/C. Więc "zatrzymanie" CPU następuje bardzo, bardzo rzadko.

Moim zdaniem problem wynika z zupełnie innej przyczyny, natomiast wpływ DMA jest raczej pomijalny.

Nie ma natomiast możliwości, że DMA zupełnie zablokuje działanie CPU. Program nawet w najgorszym przypadku będzie wykonywany, chociaż z nieco mniejszą prędkością - niestety nie ma nic za darmo.

Edytowano przez Elvis
  • Lubię! 1
Link do komentarza
Share on other sites

Wyłączając odczyt z ADC obliczenia na arcusach wykonują się bezproblemowo, jeżeli włączę odczyt ADC i usunę arcusy to nadal reszta obliczeń wykonuje się.

Jeżeli CPU i DMA konkurują tylko o dostęp do rejestrów to CPU powinno w tym czasie wykonywać obliczenia, dobrze rozumiem?

Naprawdę nie wiem gdzie może znajdować się błąd, ale czy jest możliwość wykonania odczytu ADC po wykonaniu obliczeń na arcusach, a nie w trybie continuous?

W sieci nie mogę znaleźć żadnego poradnika jak to wykonać

Dziękuję za odpowiedzi, pozdrawiam

Link do komentarza
Share on other sites

CPU i DMA konkurują o dostęp do pamięci - dokładniej DMA co jakiś czasu zapisuje do pamięci wyniki z przetwornika A/C. Ale skoro w programie masz:

  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;

to ten zapis nie następuje zbyt często. Mawet nie wnikając czy ADC jest taktowane wolniej niż CPU, na jeden zapis przez DMA masz setki cykli CPU.

Wiec teoretycznie program działa wolniej, ale pewnie nikt tego nie zauważy.

Natomiast w programie masz pewnie inny błąd, który daje podobne efekty. Ciężko jest tak "zdalnie" zdiagnozować przyczynę problemów, ale z tego co przychodzi mi do głowy:

1) jesli wyłączysz ADC to funkcje arytmetyczne działają na stałych danych, może coś się psuje jak pojawią się określone wartości - coś gdzieś dzieli przez zero, liczy tangens z pi-pół itd.

2) może po wyłączeniu DMA optymalizator usuwa jakieś fragmenty kodu i całość działa względnie poprawnie

3) na zrzucie ekranu, który wstawiałeś wcześniej program  zatrzymywał się w procedurze obsługi przerwania. Może problem nie wynika z samego DMA, ale złego sposobu obsługi przerwania od DMA? np. nie jest zerowana jakaś flaga i przerwanie wywoływane jest "w pętli", co faktycznie może uniemożliwiać działanie programu?

To tylko pomysły, bo jak napisałem ciężko jest diagnozować przyczynę problemu na odległość. W każdym razie DMA nie ma prawa zatrzymać programu, może go spowolnić, ale nie zatrzymać całkiem.

  • Lubię! 1
Link do komentarza
Share on other sites

Piszesz, że

18 godzin temu, Bornhartt napisał:

program zawiesza się na obliczeniach arcusów i w tym tkwi sęk

a na wcześniejszym screenie, ze niby wisi w przerwaniu od DMA. W końcu jak jest? Program nie może wisieć na jakimś "if", może "wisieć" (kręcić się) w jakiejś pętli.

Musisz jasno określić gdzie program "wisi". Jak go zatrzymasz to zrób kilka kroków i dowiesz się czegoś konkretnego.

 

  • Lubię! 1
Link do komentarza
Share on other sites

dwa pierwsze punkty sprawdziłem i to nie był ten problem, ustaliłem, że acos/asin blokuje wykonanie programu jeżeli korzysta z jakiejkolwiek zmiennej float, uint itd. (A=acosf(Az);),

dodatkowo wyskoczył mi nowy komunikat, także dotyczący przerwania więc to pewnie jest problem tylko nie mam pojęcia jak go rozwiązać, tematem zajmuję się od niedawna.

Mógłbym wrzucić tutaj całą paczkę z projektem 

Przechwytywanie.PNG

Link do komentarza
Share on other sites

2 godziny temu, Bornhartt napisał:

dodatkowo wyskoczył mi nowy komunikat, także dotyczący przerwania więc to pewnie jest problem

HardFault to np odwołanie do nieistniejącego obszaru adresowego. Może deklarujesz dynamiczną zmienną (tablicę) o wielkości większej niż wielkość sterty zadeklarowanej w kompilatorze wtedy przepełniasz stos i program ląduje w HardFault .

Link do komentarza
Share on other sites

Pomogło przypadkowe ustawienie BOOT 1 na 1, nie wiem czy to jest dobre rozwiązanie i czy mogło być związane z tym przepełnianiem stosu, możecie mi to zjawisko wytłumaczyć jeśli jeszcze macie chęci 🙂

Tak czy inaczej dziękuję bardzo za poświęcony czas i dużo porad

Przechwytywanie.PNG

Link do komentarza
Share on other sites

Nie sądzę żeby zmiana BOOT1 na 1 była choćby odrobinę dobrym rozwiązaniem. To nawet ciekawe na czym polega problem, jeśli umieścisz gdzieś kompletny projekt może będzie łatwiej poszukać przyczyny problemu. Bo zarówno DMA, jak i BOOT1 to raczej leczenie objawowe.

  • Lubię! 1
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.