Skocz do zawartości

Kurs STM32L4 – #7 – przerwania sprzętowe, obsługa błędów


Pomocna odpowiedź

Witam. Mam kłopot z priorytetami. Mimo nadaniu niższego priorytetu, program cały czas zawiesza się po wciśnięciu przycisku (tymczasowo dla pętli i permanentnie dla HAL_Delay). Oto moje przerwanie:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
	if (GPIO_Pin == UB_Pin) {
		counter++;
		//HAL_Delay(100);
		for (int i=0;i<10000000;i++) {}
	}
}

W kodzie funkcji MX_GPIO_Init widzę takie linijki:

  HAL_NVIC_SetPriority(EXTI15_10_IRQn, 8, 0);
  HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

Więc domyślam się, że konfiguracja jest prawidłowa. Czy jest jeszcze coś co powinienem sprawdzić? Jak ewentualnie zdebugować taki problem?

Link do komentarza
Share on other sites

Ok, problem solved. Winowajca znajdował się w pliku stm32l4xx_hal_conf.h i wyglądał tak:

#define  TICK_INT_PRIORITY            15U    /*!< tick interrupt priority */

Z jakiegoś powodu u mnie domyślnie (we wszystkich projektach) priorytet przerwania SysTick jest ustawiony na 15. Zmiana na 0 rozwiązuje problem.

Link do komentarza
Share on other sites

Robiąc ten rozdział od razu przyszło mi do głowy, że przydałoby się, gdyby można było wysyłać dowolne wiadomości, a nie tylko te predefiniowane w send_next_message - chociażby wiadomości o tym, ile razy został wciśnięty przycisk. W tym celu napisałem funkcję send_message, która wpycha tekst do bufora, a bufor jest sukcesywnie opróżniany przez HAL_UART_Transmit_IT. Wyszło mi coś takiego: 

char buffer[1024];
char tmp[1024];
uint8_t busy = 0;

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
	if (huart==&huart2) {
		busy = 0;
		if  (strlen(buffer)>0) {
			busy = 1;
			strcpy(tmp,buffer);
			buffer[0] = '\0';
			HAL_UART_Transmit_IT(&huart2, (uint8_t*)tmp, strlen(tmp));
		}
	}
}

void send_message(char * message) {
	if (strlen(buffer)+strlen(message)>1023) return;
	strcat(buffer,message);
	if (!busy) HAL_UART_TxCpltCallback(&huart2);
}

Ogólnie działa wyśmienicie. Można sekwencyjnie wywołać send_message wielokrotnie  z dowolnymi tekstami i wszystko się wysyła; podczas testów nie zauważyłem żadnego problemu. Niemniej, jako że jestem zupełnie zielony jeśli chodzi o programowanie asynchroniczne (nie wiem jak używać volatile itp.; btw. jestem też zielony jeśli chodzi o operacje na stringach w C i ogólnie C bez dwóch plusów), będę wdzięczny za krytyczne uwagi, bo na pewno coś skopsałem.

Dodatkowo, dorobiłem jeszcze funkcję echo tak, żeby tekst wpisywany do terminala od razu się wyświetlał. Wygląda to tak:

char rxb[2];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
	if (huart==&huart2) {
		send_message(rxb);
		if (rxb[0]=='\r') send_message("\n");
		HAL_UART_Receive_IT(&huart2,rxb,1);
	}
}

Też działa jak złoto. Nawet można skopiować i wkleić do terminala kawałek tekstu i zostanie on w całości odebrany i wyświetlony. Oczywiście trzeba to zainicjować wrzucając HAL_UART_Receive_IT(&huart2,rxb,1); przed pętlą główną (o czym jak widziałem w poście powyżej nie tylko mnie udało się na początku zapomnieć). Jak wyżej, krytyczne uwagi mile widziane. 

  • Lubię! 2
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

Próbuje zrobić zadanie domowe 7.2 i rozwiązać problem drgania styków cyfrowo, ale utknąłem 😞

 

Drugi guzik podłączony mam do do GND, dodatkowo włączyłem w CubeMX rezystor pull-up żeby mi cały układ nie szalał. Staram się w przerwaniach umieszczać jak najmniej kodu wiec obsługa przerwań z przycisków wygląda aktualnie tak:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if (GPIO_Pin == USER_BUTTON_Pin)
	{
		push_counter++;
	}

	if (GPIO_Pin == USER_BUTTON2_Pin)
	{
		push_counter2++;
    }

dodatkowo w pętli głównej programu dodałem nieskończona pętle while żeby pozbyć się efektu drgania styków na zewnętrznym guziku:

while (1)
  {



	  if(old_push_counter != push_counter)
	  {
		  printf("Button 1 pressed : %ld times \n",push_counter);
		  old_push_counter = push_counter;
	  }

	  if(old_push_counter2 != push_counter2)
	  	  {
	  		  printf("Button 2 pressed : %ld times \n",push_counter2);
	  		  old_push_counter2 = push_counter2;
        
        		while(HAL_GPIO_ReadPin(USER_BUTTON2_GPIO_Port, USER_BUTTON2_Pin) == 0)
					{

					}
	  	  }



    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

Jednak nic to nie daje, wydaje mi się, że rozumiem dlaczego, pętla while hamuje jedynie dodatkowe wyświetlanie printfa, jednak same przerwania dalej są rejestrowane "w tle" co owocuje tym, ze czasami mam przeskok o kilka wartości:

obraz.png.887079ce4adb9f476f03a88b3d834c13.png

 

co jeszcze mogę zrobić cyfrowo, aby wyeliminować ten problem, proszę o naprowadzenie 😄

Link do komentarza
Share on other sites

Dnia 25.11.2022 o 17:12, vadmae napisał:

jednak same przerwania dalej są rejestrowane "w tle" co owocuje tym, ze czasami mam przeskok o kilka wartości:

Taka jest właśnie główna zaleta przerwań sprzętowych 😉 

Dnia 25.11.2022 o 17:12, vadmae napisał:

proszę o naprowadzenie

Rozwiązań tego problemu jest wiele, praktycznie każde bazuje na tym, że stan przycisku trzeba sprawdzić dwa razy w krótkim odstępie czasu (kilka milisekund) lub po pierwszym wykryciu przycisku trzeba ignorować następne przez kilka następnych milisekund. Nie uda Ci się tego zrobić bazując wyłącznie na na sprawdzaniu aktualnych/poprzednich stanów.

PS Zadbaj trochę o formatowanie kodu, bo program krótki, a już zaczyna się rozjeżdżać 😉

Link do komentarza
Share on other sites

Mam dziwną sytuację. Podczas przerabiania części rozdziału o priorytetach przerwań, wszedłem w system core->nvic, ale preemtion priority przerwania time base wynosi 15, a nie jak w kursie, 0. Wydaje mi się, że w tym projekcie robiłem tylko to, co jest w tej części kursu. To możliwe, czy musiałem coś zepsuć?

Link do komentarza
Share on other sites

9 minut temu, Treker napisał:

@StefanekP nie mam teraz dostępu do Cube, więc nie sprawdzę, ale może była tam jakaś aktualizacja. Czy priorytet 15 masz ustawiony tylko dla tego przerwania, czy dla wszystkich?

Tylko dla tego jednego, dla wszystkich pozostałych jest 0.

Link do komentarza
Share on other sites

@StefanekP ok, to postaram się sprawdzić to u siebie, ale najszybciej pewnie w środę. Jak będziesz miał taką możliwość to spróbuj wcześniej zrobić test na nowym projekcie, będzie szybciej sprawa rozwiązana 😉

Link do komentarza
Share on other sites

Dnia 26.12.2022 o 12:44, StefanekP napisał:

Sprawdziłem, w pustym projekcie też priorytet time base jest ustawiony domyślnie na 15. Więc wygląda na to, że to jest kwestia nowej wersji cubemx.

Tak to nowa wersja wstawia tam 15. Pytanie czy to bug czy ficzer bo z tego co rozumiem to SySTick jest dosyć ważnym przerwaniem, a wychodzi na to ze ma najniższy priorytet?

Edytowano przez dudoxx
dodałem cytowanie
  • Lubię! 1
Link do komentarza
Share on other sites

@dudoxx niezależnie od domyślnych ustawień Cube i tak zawsze powinno się sprawdzić priorytety przerwań, jeśli tylko z nimi działamy. Przy okazji warto wyrobić sobie nawyk pamiętania o temacie priorytetów i ewentualnej korekty. To taka dobra rada, ale oczywiście ta zmiana w działaniu Cube może być zastanawiająca - wysłałem zapytanie do inżyniera pracującego w ST. Wrócę z aktualizacją tematu, gdy uzyskam odpowiedź 🙂

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

Dziękuję wszystkim za cierpliwość w sprawie domyślnych priorytetów. Trochę to trwało, ale uzyskałem odpowiedź bezpośrednio od producenta. W skrócie: zmiana tego priorytetu to nie jest błąd tylko celowe działanie. Osoby odpowiedzialne za rozwój bibliotek uznały, że konieczna jest aktualizacja domyślnego priorytetu dla timebase) bez względu na to czy korzystamy z systemu operacyjnego, czy nie). Warto pamiętać, że może to wpływać na działanie programu (np. funkcje HAL do opóźnień mogą nie działać wewnątrz przerwań). Jest to również opisane w dokumentacji:

Cytat

Care must be taken if HAL_Delay() is called from a peripheral ISR process, The SysTick interrupt must have higher priority (numerically lower) than the peripheral interrupt. Otherwise the caller ISR process will be blocked.

Niezależnie od tego potwierdza się moja wcześniejsza rada - zamiast wierzyć w domyślne ustawienia warto jednak kontrolować samodzielnie priorytety (i nie tylko to) 😉 Dopisuję tę zmianę do mojej listy i naniosę później odpowiednią adnotację do kursu.

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

Cześć wszystkim, pytanie mam pewnie lekko głupawe, lecz nie mogę tego zrozumieć.

Udało mi się wykonać pierwsze dwa zadania z tej części kursu, jednakże przy trzecim utknąłem. O ile wstawienie printa w funkcji "SysTick_Handler", aby wyświetlać aktualną wartość timera systemowego podzieloną przez 1000 działa, to wyświetlanie szaleje i chciałbym aby wyświetlała się wartość, jedynie po jej zmianie. Tak jak było to zrealizowane przy zliczaniu naciśnięć przycisku. Zrealizowałem to w taki sposób i nie rozumiem, dlaczego to nie działa. Będę bardzo wdzięczny, jeżeli ktoś wytłumaczy mi dlaczego to nie działa i naprowadzi delikatnie na prawidłowe rozwiązanie 🙂

 

 

Przy okazji chciałbym dopytać, czy w ogóle dobrze zrozumiałem zadanie i chodzi, jedynie o wpisanie printa do SysTick_Handler, czy powinienem to zrealizować, np. wywołując tam funkcję, która to zrealizuje? Btw. czy takie rozwiązanie jest gorsze, czy lepsze?

void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

	static int value, old_value;
	value = HAL_GetTick()/1000;

	if (old_value =! value)
	{
		old_value = value;
		printf("%d\n", old_value);
	}

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

 

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • 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.