Forum: Mikrocontroller und Digitale Elektronik STM32F07VG Discovery - Timer + Sleep


von Robin H. (robin_h319)


Lesenswert?

Hallo zusammen,

ich fange gerade an mich mit dem STM32F407 zu beschäftigen. Vorher habe 
ich öfters den MSP430G2553 und Arduino programmiert.

Ich bin gerade auf der Suche nach einem simplen Code Beispiel und blicke 
bei dem STM32 noch nicht ganz durch.

Ich möchte eigentlich etwas ähnliches wie ich es beim MSP430 oder 
Arduino umgesetzt habe:


init();
while(1){
  // programm laufen lassen
  // interrupts einschalten
  // enter sleep mode
  // interrupts ausschalten
  // ggf. flag bearbeiten
}

ISR(TIMERX_XY_vect){
  // flag setzen
  // ggf. LPMX_bits + GIE beim exit ausschalten
}

Interrupts alle x ms mit TIM3 hinbekommen ist kein Problem - dafür gibt 
es ja genügend Beispiele. Nur mit den Sleep Modes klappt es leider 
nicht.. Oder wird die Clock im Sleep Mode für den TIM3 ausgeschaltet?

Ich habe es mit PWR_EnterSTANDBYMode(); probiert.

Grüße,
Robin

von Robin H. (robin_h319)


Lesenswert?

Hier noch etwas Code dazu - ist im endeffekt eins der Examples zu TIM 
die man in der Atollic IDE findet. Das was fehlt, wäre das Betreten 
eines LPM
1
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
2
TIM_OCInitTypeDef  TIM_OCInitStructure;
3
__IO uint16_t CCR1_Val = 54618;
4
__IO bool TIM3_flag = false;
5
uint16_t PrescalerValue = 0;
6
7
void initTimer(void);
8
9
int main(void)
10
{
11
    // other init stuff
12
    initTimer();
13
    TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
14
    TIM_Cmd(TIM3, ENABLE);
15
16
    while (1)
17
    {
18
      if (TIM3_flag == true){
19
                // do stuff
20
        TIM3_flag = false;
21
      }
22
        // do stuff
23
24
    }
25
}
26
27
void initTimer(void){
28
  // Init GPIOD
29
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
30
  GPIO_InitTypeDef  GPIO_InitStructure;
31
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
32
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
33
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
34
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
35
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
36
  GPIO_Init(GPIOD, &GPIO_InitStructure);
37
  GPIO_SetBits(GPIOD,GPIO_Pin_14);
38
39
  // Init interrupt
40
  NVIC_InitTypeDef NVIC_InitStructure;
41
42
  /* TIM3 clock enable */
43
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
44
45
  /* Enable the TIM3 gloabal Interrupt */
46
  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
47
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
48
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
49
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
50
  NVIC_Init(&NVIC_InitStructure);
51
52
  /* Compute the prescaler value */
53
  PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 500000) - 1;
54
55
  /* Time base configuration */
56
  TIM_TimeBaseStructure.TIM_Period = 65535;
57
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
58
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
59
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
60
61
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
62
63
  /* Prescaler configuration */
64
  TIM_PrescalerConfig(TIM3, PrescalerValue, TIM_PSCReloadMode_Immediate);
65
66
  /* Output Compare Timing Mode configuration: Channel1 */
67
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
68
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
69
  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
70
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
71
72
  TIM_OC1Init(TIM3, &TIM_OCInitStructure);
73
74
  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);
75
}


und aus der ISR:
1
uint16_t capture = 0;
2
extern __IO uint16_t CCR1_Val;
3
extern __IO bool TIM3_flag;
4
5
void TIM3_IRQHandler(void)
6
{
7
  if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
8
  {
9
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
10
11
    TIM3_flag = true;
12
13
   capture = TIM_GetCapture1(TIM3);
14
    TIM_SetCompare1(TIM3, capture + CCR1_Val);
15
  }
16
}

Kann ich den TIM3 in verbindung mit sleep modes überhaupt nutzen? Wenn 
ja, wie muss ich die Sleep modes einstellen.

Danke für die Hilfe

von Dr. Sommer (Gast)


Lesenswert?

Robin H. schrieb:
> Nur mit den Sleep Modes klappt es leider
> nicht.. Oder wird die Clock im Sleep Mode für den TIM3 ausgeschaltet?

Versuch's doch erstmal mit dem einfachsten Sleep Mode, bei dem nur der 
Prozessor-Kern abgeschaltet wird:
1
__WFI ();
oder
1
__asm__ volatile ("wfi");
Dabei bleiben alle zuvor aktivierten Peripherie-Einheiten an, und der 
Prozessor wacht bei Interrupts wieder auf.

Robin H. schrieb:
> if (TIM3_flag == true){
>                 // do stuff
>         TIM3_flag = false;
>       }
Bei den ARM's kannst du die eigentliche Verarbeitung auch problemlos in 
der ISR machen, du musst nicht Flags setzen und das in der main() 
machen. Indem du anderen Interrupts eine höhere Priorität zuweist, 
können die eventuell lange laufende andere ISR's unterbrechen - somit 
ist die "Regel", keine langen Verarbeitungen in der ISR zu machen, 
hinfällig. Die main() sieht dann nur noch so aus:
1
int main () {
2
  // Initialisierungen ...
3
  __enable_irq (); // Interrupts ein
4
  while (1) {
5
    __WFI (); // Schlafen
6
  }
7
}
Und der Rest kommt in die ISR's. Das entspricht dann einer 100% 
asynchronen Programmierung.

von Stefan F. (Gast)


Lesenswert?

> Oder wird die Clock im Sleep Mode für den TIM3 ausgeschaltet?

Kommt auf den konkreten Sleep Modus an. Siehe 
http://stefanfrings.de/stm32/index.html#power

von Robin H. (robin_h319)


Lesenswert?

Dr. Sommer schrieb:
> Versuch's doch erstmal mit dem einfachsten Sleep Mode, bei dem nur der
> Prozessor-Kern abgeschaltet wird:__WFI ();oder__asm__ volatile
> ("wfi");Dabei bleiben alle zuvor aktivierten Peripherie-Einheiten an,
> und der
> Prozessor wacht bei Interrupts wieder auf.

Super, danke. Mit __WFI(); hat sofort geklappt!

Dr. Sommer schrieb:
> Indem du anderen Interrupts eine höhere Priorität zuweist,
> können die eventuell lange laufende andere ISR's unterbrechen - somit
> ist die "Regel", keine langen Verarbeitungen in der ISR zu machen,
> hinfällig.

Werde ich mir mal anschauen. Bin gerade dabei Interrupts mit 
Statemachines (Yakindu State Chart Tools) zu verbinden und möchte eine 
möglichst "hardware unabhängige" Lösung erarbeiten, quasi ne Art 
Template/Pattern. Vielleicht sollte ich bei ARM's einen anderen Ansatz 
wählen.

Viele Grüße und Danke,
Robin

von Dr. Sommer (Gast)


Lesenswert?

Robin H. schrieb:
> Vielleicht sollte ich bei ARM's einen anderen Ansatz
> wählen.

Würde ich gar nicht - State Machines kann man wunderbar in ISR's packen, 
und in einem Interrupt immer jeweilig auf die entsprechenden Ereignisse 
reagieren und den Zustand ändern. Wenn du im Interrupt gar nichts machst 
außer Flags zu setzen, kannst du die ISR auch ganz weglassen, und die 
Interrupt-Flags direkt in der main() abfragen...

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.