Forum: Mikrocontroller und Digitale Elektronik STM32f767zi: FreeRTOS und TIM


von Frank B. (fbergemann)


Lesenswert?

Ich mache gerade meine ersten Schritte mit dem STM32F767ZI board 
(https://www.st.com/en/evaluation-tools/nucleo-f767zi.html).
Dabei habe ich Probleme, unter FreeRTOS den TIM3 mit HAL unterzubringen.

Siehe hier: https://github.com/FBergemann/STM32-FreeRTOS-TIM

In 
https://github.com/FBergemann/STM32-FreeRTOS-TIM/blob/master/Core/Inc/Init/Init_Global.h 
habe ich:
1
// #define TASK_LED2_USE_NEW_VERSION
2
#undef TASK_LED2_USE_NEW_VERSION
3
4
// #define TASK_LED2_USE_NEW_VERSION_ENABLE_IRQ
5
#undef TASK_LED2_USE_NEW_VERSION_ENABLE_IRQ
Damit werden #3 LEDs einfach nur über eine einfache loop getoggled:
1
  while (1)
2
  {
3
    HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
4
    osDelay(250);
5
  }
Aber wenn ich verwende:
1
#define TASK_LED2_USE_NEW_VERSION
2
//#undef TASK_LED2_USE_NEW_VERSION
3
4
// #define TASK_LED2_USE_NEW_VERSION_ENABLE_IRQ
5
#undef TASK_LED2_USE_NEW_VERSION_ENABLE_IRQ
dann blinkt LED2 nicht mehr, weil ich dafür benötige:
1
#define TASK_LED2_USE_NEW_VERSION
2
//#undef TASK_LED2_USE_NEW_VERSION
3
4
#define TASK_LED2_USE_NEW_VERSION_ENABLE_IRQ
5
// #undef TASK_LED2_USE_NEW_VERSION_ENABLE_IRQ
Damit wird in 
https://github.com/FBergemann/STM32-FreeRTOS-TIM/blob/master/Core/Src/stm32f7xx_hal_msp.c 
aktiviert:
1
#ifdef TASK_LED2_USE_NEW_VERSION_ENABLE_IRQ
2
  /* Enable the TIMx global Interrupt */
3
  HAL_NVIC_EnableIRQ(TIMx_IRQn);
4
#endif
Aber damit komme ich nicht mehr durch die Initialisierung durch.
Ich habe schon rumgesucht, ob und wie HAL_TIM mit FreeRTOS verheiratet 
werden kann. Aber bis jetzt bin ich damit nur gegen die Wand gelaufen.

Kann mir da eine von euch helfen?

Grüsse,
Frank

von Harry L. (mysth)


Lesenswert?

Vielleicht solltest du mal erklären, was dein Timer überhaupt machen 
soll.

Ansonsten solltest du den Timer in CubeMX initialisieren, wie auch die 
zugehörigen Interrupts.

Einschalten musst du den dann immer noch, aber das kannst du dann 
natürlich auch innerhalb eines Task mit den HAL-Funktionen machen.

von Frank B. (fbergemann)


Lesenswert?

Der Timer soll über einen callback die LED2 togglen:
https://github.com/FBergemann/STM32-FreeRTOS-TIM/blob/master/Core/Src/Run/Run_Task_Led2.c
1
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
2
{
3
  HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
4
}
5
6
void Run_Task_Led2(void const * argument)
7
{
8
  printf("start Task_Led2...\n\t");
9
10
  while (1)
11
  {
12
    osDelay(1000);
13
  }
14
}
Initialisiert wird über 
https://github.com/FBergemann/STM32-FreeRTOS-TIM/blob/master/Core/Src/Init/Tasks/Init_Task_Led2.c
1
static GPIO_InitTypeDef GPIO_InitStruct;
2
static TIM_HandleTypeDef TimHandle;
3
static __IO uint32_t uwPrescalerValue = 0;
4
5
void Init_Task_Led2()
6
{
7
  // init LED ------------------------------------------------
8
  __HAL_RCC_GPIOB_CLK_ENABLE();
9
  GPIO_InitStruct.Pin  = LD2_Pin;
10
  GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;
11
  GPIO_InitStruct.Pull  = GPIO_PULLUP;
12
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
13
  HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
14
15
  // init Timer ----------------------------------------------
16
  /* Compute the prescaler value to have TIMx counter clock equal to 10000 Hz */
17
  uwPrescalerValue = (uint32_t)((SystemCoreClock/ 2) / 10000) - 1;
18
19
  /* Set TIMx instance */
20
  TimHandle.Instance = TIMx;
21
22
  /* Initialize TIMx peripheral as follows:
23
       + Period = 10000 - 1
24
       + Prescaler = ((SystemCoreClock / 2)/10000) - 1
25
       + ClockDivision = 0
26
       + Counter direction = Up
27
  */
28
  TimHandle.Init.Period            = 10000 - 1;
29
  TimHandle.Init.Prescaler         = uwPrescalerValue;
30
  TimHandle.Init.ClockDivision     = 0;
31
  TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
32
  TimHandle.Init.RepetitionCounter = 0;
33
  TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
34
  if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
35
  {
36
    /* Initialization Error */
37
    Error_Handler();
38
  }
39
40
  /*##-2- Start the TIM Base generation in interrupt mode ####################*/
41
  /* Start Channel1 */
42
  if (HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK)
43
  {
44
    /* Starting Error */
45
    Error_Handler();
46
  }
47
}

Vertragen sich HAL Timer mit dem FreeRTOS überhaupt?

Oder kollidiert da irgendwas?

[Nachtrag] ich sehe gerade, dass ich ignoriert habe:
"- When RTOS is used, it is strongly recommended to use a HAL timebase 
source other than the Systick.   The HAL timebase source can be changed 
from the Pinout tab under SYS"

Das blöde ist, man kann das im Nachhinein nicht mehr so einfach ändern. 
Wenn die Code-Generierung dafür anläuft, dann werden relevant source 
files einfach wieder überschrieben.

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Frank B. schrieb:
> Vertragen sich HAL Timer mit dem FreeRTOS überhaupt?
>
> Oder kollidiert da irgendwas?
Das hat schlicht nichts miteinander zu tun.

Du kannst die LED wahlweise via Task mit osDelay() oder über deinen 
Timer-Callback blinken lassen.

Das sind aber 2 kompl. unterschiedliche Paar Schuhe.

von Frank B. (fbergemann)


Lesenswert?

Ich weiss, ich wollte ja auch verschiedene Varianten ausprobieren.
Für LED2 halt via Timer anstatt über osDelay().

von Johannes S. (Gast)


Lesenswert?

das Programm landet im DefaultHandler weil nix ISR für TIM3 IRQ 
vorhanden ist. Dank der weak Technik sucht man sich da jedesmal einen 
Wolf...

füge den hinzu und siehe es blinken:
1
static GPIO_InitTypeDef GPIO_InitStruct;
2
static TIM_HandleTypeDef TimHandle;
3
static __IO uint32_t uwPrescalerValue = 0;
4
5
/**
6
  * @brief This function handles TIM3 global interrupt.
7
  */
8
void TIM3_IRQHandler(void)
9
{
10
  /* USER CODE BEGIN TIM3_IRQn 0 */
11
12
  /* USER CODE END TIM3_IRQn 0 */
13
  HAL_TIM_IRQHandler(&TimHandle);
14
  /* USER CODE BEGIN TIM3_IRQn 1 */
15
16
  /* USER CODE END TIM3_IRQn 1 */
17
}

oder wie Harry schon schrieb, besser per Cube generieren lassen.

von Frank B. (fbergemann)


Lesenswert?

Super!
Da fehlt nur der
1
void TIM3_IRQHandler(void)
D.h. das framework bindet da still und heimlich ein NOP ein, wenn man es 
nicht definitiert? (weak)

> oder wie Harry schon schrieb, besser per Cube generieren lassen.

Das muss man aber wirklich schon von Anfang an genau und komplett 
wissen, welche Resourcen man verwenden will. Nachträglich irgendetwas 
ändern geht nicht, weil die Code-Generierung dann immer alles wieder 
übermangelt.

- Danke!

von Johannes S. (Gast)


Lesenswert?

Frank B. schrieb:
> D.h. das framework bindet da still und heimlich ein NOP ein, wenn man es
> nicht definitiert? (weak)

Im Startup sind die Vektoren und die Handler als weak definiert. Die 
werden überschrieben wenn es andere gibt und weak verhindert dann das 
der Linker meckert. Wenn der richtige Handler fehlt oder falsch 
geschrieben ist oder durch C++ Kompilierung vermangelt ist, dann meckert 
keiner weil das Symbol ja vorhanden ist.

Frank B. schrieb:
> Nachträglich irgendetwas ändern geht nicht, weil die Code-Generierung
> dann immer alles wieder übermangelt.

Doch, man muss nur brav in den User Sektionen bleiben. Vorher ein commit 
ist trotzdem sicherer.

von Harry L. (mysth)


Lesenswert?

Frank B. schrieb:
> Das muss man aber wirklich schon von Anfang an genau und komplett
> wissen, welche Resourcen man verwenden will. Nachträglich irgendetwas
> ändern geht nicht, weil die Code-Generierung dann immer alles wieder
> übermangelt.

Natürlich geht das!

Du darfst, wenn du generierte Dateien ändesrt- deinen Code allerdings 
nur zwischen die markierten UserCode-Sections schreiben.

Diese Teile werden beim Code-generieren nicht angefasst und bleiben 
erhalten.
1
/* USER CODE BEGIN 1 */
2
3
// dein code - der bleibt erhalten
4
5
/*  USER CODE END 1 */

[edit] Jojo war schneller...
[Mod-Edit: Codeformatierungstag]

: Bearbeitet durch Moderator
von Frank B. (fbergemann)


Lesenswert?

Aha, die entsprechenden Kommentare schützen die Bereiche.

Ich glaube, ich sollte mir doch ein paar der online Kurs von STM antun 
:-)

Vielen Dank noch einmal für eure Hilfe!

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Frank B. schrieb:
> Ich glaube, ich sollte mir doch ein paar der online Kurs von STM antun
> :-)
Dann fang doch direkt mal mit Diesem an:
https://www.youtube.com/watch?v=QGVAayFI5ZQ&t=8s&ab_channel=STMicroelectronicsSTMicroelectronics

Hat mir beim Einstieg in FreeRTOS sehr geholfen, auch, wenn der Typ 
furchtbar nuschelt, und das Audio teilweise zusätzlich sehr leise ist.

von Frank B. (fbergemann)


Lesenswert?

Falls noch mal jemand darüber stolpert - hier noch ein link, wie man das 
mit STM32CubeIDE aufsetzt:

"Getting Started with STM32 and Nucleo Part 6: Timers and Timer 
Interrupts | Digi-Key Electronics"

https://www.youtube.com/watch?v=VfbW6nfG4kw

von Frank B. (fbergemann)


Lesenswert?

Das project ist umbenannt und umstrukturiert worden nach:
https://github.com/FBergemann/STM32-FreeRTOS-Framework

von Harry L. (mysth)


Lesenswert?

Ich habs kurz mal überflogen, aber das hier:
1
 /* USER CODE BEGIN RTOS_TIMERS */
2
  /* start timers, add new ones, ... */
3
4
  HAL_TIM_Base_Start_IT(&htim14);
5
6
  /* USER CODE END RTOS_TIMERS */

ist Quatsch!
Ein RTOS-Timer ist etwas vollkommen Anderes als ein Hardware-Timer.
Der Timer-Start gehört hierhin:
1
  MX_TIM14_Init();
2
  /* USER CODE BEGIN 2 */
3
  HAL_TIM_Base_Start_IT(&htim14);
4
5
  /* USER CODE END 2 */

Das osDelay in Zeile 159 kannst du löschen.
Der Teil des Code wird nie ausgeführt.

von Frank B. (fbergemann)


Lesenswert?

1
HAL_TIM_Base_Start_IT(&htim14);
habe ich entsprechend verschoben.

> Das osDelay in Zeile 159 kannst du löschen.
> Der Teil des Code wird nie ausgeführt.

Da wird's ein bisschen philosophisch.

Ich habe das 'osDelay(1000)' entfernt, weil hier der FreeRTOS 
task-manager nicht mehr läuft. Stattdessen habe ich ein 
'HAL_Delay(1000);' eingebaut, weil dass ja immer noch verfügbar sein 
sollte.

Wenn der code sowieso nicht läuft, warum dann die Schleife?
1
while (1) {}
Und wenn schon Schleife, dann nicht als CPU consuming busy-loop.

Oder übersehe ich hier etwas?

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.