Skocz do zawartości

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


Pomocna odpowiedź

Podczas obsługi przerwania blokowane jest przyjmowanie kolejnych o priorytecie niżym lub równym aktualnemu. Więc nic się złego nie stanie, jeśli kolejne zostanie zgłoszone podczas wykonywania procedury obsługi poprzedniego.

  • 1 miesiąc później...

Gratuluję autorowi kursu, posiada on "talent" do przekazywania wiedzy. Fajnie że potrafi on również zaciekawić czytelników szczególnymi przypadkami, pobudza to umysł.

 

Osobiście nie podoba mi się funkcja 'HAL_UART_Transmit_IT'. W tekście jest przedstawiona jako konkurent dla "bez_IT", wykorzystująca przerwania. Jednakże zgodnie z ideą przerwania, przerwanie zaczyna i kończy się w tym samym miejscu. Program główny nie ma prawa "ruszyć" się teraz nawet o 1 krok. Dlaczego więc możemy powiedzieć że 'HAL_UART_Transmit_IT' wysyła "dane w tle" wykorzystując przerwania ?  

Przecież gdy przerwanie trwa, jednostka zostawia program. Potem wykonuje przerwanie i wraca do głównej pracy. Dlaczego więc musimy się martwić co się dzieje za funkcją "przerwaniową" ?

Czy na pewno możemy w tym przypadku powiedzieć że dane od 'HAL_UART_Transmit_IT' są wysyłane przy wykorzystaniu przerwań ? Czy nie są to mechanizmy o innej nazwie ?

 

 

Dziękuję za miłe słowa, przygotowanie tego kursu wymagało mnóstwa pracy od całego zespołu, tym milej jest słyszeć, albo raczej czytać, że praca nie poszła na marne 🙂

Natomiast co do przerwań i funkcji HAL_UART_Transmit_IT to chyba zaszło pewne nieporozumienie. Ta funkcja nie wysyła wszystkich danych natychmiast. Zamiast tego wstawia do rejestrów modułu UART pierwszy fragment danych i kończy działanie. Przerwanie zostanie wywołane gdy moduł UART wyśle dane i będzie oczekiwał na kolejne. W międzyczasie program główny będzie dalej wykonywany, więc dane będą przesyłane niejako w tle. Program będzie na chwilę zatrzymywany kiedy kolejne fragmenty danych będą przesyłane z bufora nadawczego do rejestrów układu, ale poza tym będzie działał normalnie.

Warto też wspomnieć, że po obsłudze przerwania nie zawsze program jest wznawiany w miejscu gdzie przerwanie się pojawiło. Tak jest najczęściej i jest to najprostszy przypadek, ale jeśli używamy FreeRTOS-a, albo piszemy program w bardzo nietypowy sposób, to wcale tak być nie musi.

  • Lubię! 2
  • 1 miesiąc później...
(edytowany)

Nie wiem co robię nie tak, ale nie działa u mnie HAL_UART_Receive_IT. Wykonuje się 2 razy i później już nic się nie dzieje.

Próbowałem na innym przykładzie i to samo. Po drugim razie nic się nie dzieje.

Czy ktoś miał podobny problem?

Edytowano przez heniu79

@heniu79 Dziś postaram się sprawdzić co może powodować problemy. Jesteś w stanie podać jeszcze jakieś szczegóły? Jakbyś mógł wkleić plik main, jak czy coś jeszcze jest wypisywane w terminalu, co w ogóle wypisujesz?

(edytowany)

Cześć, Gieneq to jest to co wpisałem w maina:

/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define LINE_MAX_LENGHT 80

static char line_buffer[LINE_MAX_LENGHT +1];

/* USER CODE END PTD */





/* USER CODE BEGIN PV */

uint8_t uart_rx_buffer;

static uint32_t line_length;
/* USER CODE END PV */





/* USER CODE BEGIN 0 */
int __io_putchar(int ch)
{
    if(ch == '\n'){
        __io_putchar('\r');
    }

    HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
    return 1;
}

void line_append(uint8_t value)
{
    if(value=='\r' || value=='\n')
    {
        if(line_length > 0){
            line_buffer[line_length] = '\0';

            HAL_UART_Transmit_IT(&huart2, (uint8_t*)line_buffer, strlen(line_buffer));

        line_length = 0;
        }
    }
    else
    {
        if(line_length >= LINE_MAX_LENGHT)
        {
            line_length = 0;
        }

        line_buffer[line_length++] = value;
    }
}

/* USER CODE END 0 */





/* USER CODE BEGIN 2 */

  HAL_UART_Receive_IT(&huart2, &uart_rx_buffer, 1);

  /* USER CODE END 2 */





/* USER CODE BEGIN 4 */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart == &huart2)
    {
        line_append(uart_rx_buffer);
        HAL_UART_Receive_IT(&huart2, &uart_rx_buffer, 1);
    }
}
/* USER CODE END 4 */

 

 

Chciałbym żeby wyświetliło to co wpisałem w terminal. Teraz czyta tylko 2 pierwsze znaki ale pozniej juz nic sie nie dzieje.

Z góry dziękuję za pomoc

 

Edytowano przez Gieneq
Zachęcam do korzystania z bloku kodu programu
  • 2 tygodnie później...

@heniu79 przepraszam że późno odpisuję, ale nie miałem okazji usiąść do L4. Nie wiem czy wiele to pomoże, ale u mnie działa...

Sprawdź czy masz ustawione przerwanie i dodaną diodę pod nazwą LD2.

image.thumb.png.be812ff695918568e08e9caf7b651cc1.pngimage.thumb.png.9b9028b1751d94b07d5e8c1016d48587.png

Mam wgraną najnowszą wersję IDE, ST-link i nowy projekt. Kod programu to 3 miejsca:

/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */

tu:

/* USER CODE BEGIN PV */
uint8_t uart_rx_buffer;
int __io_putchar(int ch)
{
  if (ch == '\n') {
    __io_putchar('\r');
  }

  HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, HAL_MAX_DELAY);

  return 1;
}

#define LINE_MAX_LENGTH 80

static char line_buffer[LINE_MAX_LENGTH + 1];
static uint32_t line_length;

void line_append(uint8_t value)
{
  if (value == '\r' || value == '\n') {
    // odebraliśmy znak końca linii
    if (line_length > 0) {
      // dodajemy 0 na końcu linii
      line_buffer[line_length] = '\0';
      // przetwarzamy dane
      if (strcmp(line_buffer, "on") == 0) {
        HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
      } else if (strcmp(line_buffer, "off") == 0) {
        HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
      }

      // zaczynamy zbieranie danych od nowa
      line_length = 0;
    }
  }
  else {
    if (line_length >= LINE_MAX_LENGTH) {
      // za dużo danych, usuwamy wszystko co odebraliśmy dotychczas
      line_length = 0;
    }
    // dopisujemy wartość do bufora
    line_buffer[line_length++] = value;
  }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart == &huart2) {
    line_append(uart_rx_buffer);
    HAL_UART_Receive_IT(&huart2, &uart_rx_buffer, 1);
  }
}
/* USER CODE END PV */

i to z pustą pętlą główną:

  /* USER CODE BEGIN WHILE */
  HAL_UART_Receive_IT(&huart2, &uart_rx_buffer, 1);

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

i to u mnie działa. W Tera term piszesz (bez echa czyli bez widocznych znaków) i dioda się świeci lub gaśnie. Możesz też skorzystać z menu-edit i użyć wklejenia (paste):

image.thumb.png.0ac26be1f6eadf1c6717906bd279d323.png

  • Lubię! 1

Niestety nadal to samo. Jak sprawdzam w debuggerze to w HAL_UART_RxCpltCallback() tak jakby za drugim razem ignorował HAL_UART_Receive_IT(). To tak na szybko jak znajdę więcej czasu to sprawdze dokładniej.

Dzięki za odpowiedź.

@atm320 chyba najlepszą literaturą (jeżeli tak można to określić...) są dokumentacje. Masz tam opisane wszystko - sprzęt, dostępne funkcje, składnię jeżyka. Tylko przebrnięcie przez nie to spore wyzwanie, bo to nawet kilka tyś stron. Autor kursu tego dokonał, więc da się 🙂 

  • 4 tygodnie później...

Jestem początkujący i mam takie pytanie co mogę robić źle jeśli po kolei wykonuje wszystko z opisów ale gdy doszedłem do podrozdziału odbieranie danych z uart przez przerwania i chce przetestować funkcję przerwaniową void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) ustawiam breakpoint na ta funkcję jednak jak wprowadzam jakiś znak z terminala to tak naprawde nic się nie dzieje i mikrokontroler nie reaguje. Dodam , że reszta programu działa poprawnie oraz komunikacja z teraterm również jest poprawna.

Pomożcie 

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...