Forum: Mikrocontroller und Digitale Elektronik STM32F1 STOPMode RTC Wakeup


von Alexander H. (alex95)


Lesenswert?

Hallo zusammen,

wie schon in der Überschrift erwähnt versuche ich einen STM32F103C8T aus 
dem STOPMode mit Hilfe eines RTC-Alarms aufzuwecken. Im SleepMode klappt 
das auch schon. Nur im STOPMode wacht der STM32 nicht mehr auf. Nur ein 
Signal auf dem entsprechend konfiguriertem Pin PA0 schafft hier Abhilfe.
Hier ein Auszug aus meiner main.c:

  __HAL_RTC_ALARM_EXTI_ENABLE_RISING_EDGE();
  __HAL_RTC_ALARM_EXTI_ENABLE_IT();

  HAL_GPIO_WritePin(LED_A_GPIO_Port, LED_A_Pin, SET);
  HAL_RTC_SetAlarm_IT(&hrtc, &alarm_a, RTC_FORMAT_BIN);
  HAL_SuspendTick();

  HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
//  HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);

  HAL_ResumeTick();
  SystemClock_Config();
  HAL_GPIO_WritePin(LED_A_GPIO_Port, LED_A_Pin, RESET);

Da ja laut STM Dokumentation die EXTI_Line17 speziell im STOPMode 
konfiguriert werden muss, habe ich die zwei oberen Zeilen verwendet, was 
jedoch kein Unterschied macht. Ich habe Zwar schon einige Beiträge zu 
dem Thema gefunden. Entweder wurde hier jedoch der SleepMode verwendet 
oder nicht die HAL Librarys genutzt.
Ich hoffe jemand kennt sich besser mit dem Thema aus und kann mir 
helfen.

Gruß Alex

von Magerquark (Gast)


Lesenswert?

Ich benutze die die HAL nicht, sondern mache das "Native". Sieht bei mir 
ziemlich ähnlich aus.
Bei mir habe ich aber noch folgenden Code für den  RTC-Interrupt:
1
void RTCAlarm_IRQHandler()
2
{
3
  if((RTC->CRL&RTC_CRL_ALRF)!=0)
4
  {
5
    RTC->CRL &= ~RTC_CRL_ALRF;
6
  }
7
  EXTI->PR = EXTI_EMR_MR17;
8
}

Ob das nötig ist? Ich steck da nach einigen Jahren nicht mehr drin.

von Alexander H. (alex95)


Lesenswert?

Erstmal danke für die Antwort.
Meine Interruptcode setzt eigentlich auch das Flag zurück. Hier die 
entsprechende Stelle:
1
void RTC_IRQHandler(void)
2
{
3
  /* USER CODE BEGIN RTC_IRQn 0 */
4
5
  /* USER CODE END RTC_IRQn 0 */
6
  HAL_RTCEx_RTCIRQHandler(&hrtc);
7
  /* USER CODE BEGIN RTC_IRQn 1 */
8
  HAL_RTC_AlarmIRQHandler(&hrtc);
9
  HAL_GPIO_TogglePin(LED_B_GPIO_Port, LED_B_Pin);
10
11
  /* USER CODE END RTC_IRQn 1 */
12
}
Wie sieht denn deine "Native" Konfiguration aus falls du die noch hast?

von Magerquark (Gast)


Lesenswert?

Bitte sehr.
Den folgenden Code habe zum Testen des Stop-Modes verwendet. 
Sicherheithalber habe ich nichts bereinigt und den Code einfach roh hier 
eingestellt (abgekippt). Also bitte nicht schlagen.

1
void RTC_IRQHandler()
2
{
3
  if((RTC->ISR&RTC_ISR_ALRAF)!=0)
4
  {
5
    RTC->ISR ^= RTC_ISR_ALRAF;
6
  }
7
  EXTI->PR = EXTI_EMR_MR17;
8
}
9
10
int Test_StopMode(bool LSI_Enabled)
11
{
12
  // Delay und LED blinken lassen
13
  if(1==2)
14
  {
15
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
16
    GPIOA->MODER = 0x28000100; // GPIO_MODER_MODER4_0*1;
17
    for(int i=0; i<20; i++)
18
    {
19
      GPIOA->ODR ^= 0x010;
20
      for(int i=0; i<500000; i++)
21
      {
22
        __asm("nop");
23
      }
24
    }
25
  }
26
27
  // fCPU = 1MHz
28
  RCC->CFGR |= RCC_CFGR_HPRE_DIV8;
29
30
  // alle GPIO auf Input mit Pulldown
31
  RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
32
  GPIOA->PUPDR = 0xa6aaa8aa; // außer PA13/PA14 (SWD-Debug) und PA4 (LED)
33
  RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
34
  GPIOB->PUPDR = 0x00000008; // Achtung: bei 0xaaaaaaaa ist PB1 möglicherweise (aber wann/warum???) floating!
35
  RCC->AHBENR |= RCC_AHBENR_GPIOFEN;
36
  GPIOF->PUPDR = 0x0000000a;
37
38
  // GPIOA4 (LED) auf Ausgang (all Pulldown, except PA4 (LED-Output) and PA13/PA14 (SWD-Debug))
39
  GPIOA->MODER = 0x28000100;
40
  // GPIOA->MODER = 0x00000100; // PA4 (LED)
41
  GPIOB->MODER = 0x00000000;
42
  GPIOF->MODER = 0x00000000;
43
44
  RCC->APB1ENR |= RCC_APB1ENR_PWREN;
45
46
  bool Interrupt = true;
47
48
  // Start LSI-Timer
49
  if(LSI_Enabled)
50
  {
51
    RCC->CSR |= RCC_CSR_LSION;
52
    while((RCC->CSR&RCC_CSR_LSIRDY)==0)
53
    {
54
      __asm("nop");
55
    }
56
57
    PWR->CR |= PWR_CR_DBP;
58
59
    RCC->BDCR |= RCC_BDCR_BDRST;
60
    RCC->BDCR = 0;
61
    RCC->BDCR |= RCC_BDCR_RTCSEL_0*2; // LSE RTC
62
    RCC->BDCR |= RCC_BDCR_RTCEN;
63
64
    // Disable write protection
65
    RTC->WPR = 0xCA;
66
    RTC->WPR = 0x53;
67
68
    // Change Prescaler
69
    RTC->ISR |= RTC_ISR_INIT;
70
    while((RTC->ISR&RTC_ISR_INITF)==0)
71
    {
72
      __asm("nop");
73
    }
74
    // RTC->PRER = 0x00090013; // T =   5ms (= (0x09+1)*(0x0013+1)/40000Hz)
75
    // RTC->PRER = 0x000f0018; // T =  10ms (= (0x0f+1)*(0x0018+1)/40000Hz)
76
    // RTC->PRER = 0x000f0031; // T =  20ms (= (0x0f+1)*(0x0031+1)/40000Hz)
77
    // RTC->PRER = 0x000f00f9; // T = 100ms (= (0x0f+1)*(0x00f9+1)/40000Hz)
78
    // RTC->PRER = 0x000f09c3; // T = 1.00s (= (0x0f+1)*(0x09c3+1)/40000Hz)
79
    // RTC->PRER = 0x000f3fff; // T = 6.55s (= (0x0f+1)*(0x3fff+1)/40000Hz)
80
    const int msT = 100;  // max. 8192ms
81
    RTC->PRER = 0x00090000+msT*4-1;
82
83
    RTC->ISR ^= RTC_ISR_INIT;
84
85
    if(Interrupt)
86
        {
87
          EXTI->RTSR |= EXTI_FTSR_TR17; // rising edge
88
          EXTI->IMR |= EXTI_IMR_MR17;
89
          EXTI->PR |= EXTI_EMR_MR17;
90
          NVIC_Init(RTC_IRQn, 3, ENABLE);
91
        }
92
      else
93
        {
94
          EXTI->RTSR |= EXTI_RTSR_TR17; // rising edge
95
          EXTI->EMR |= EXTI_EMR_MR17;
96
        }
97
98
    // Alarm bei jeder Sekunde
99
    RTC->ALRMAR = RTC_ALRMAR_MSK4 | RTC_ALRMAR_MSK3 | RTC_ALRMAR_MSK2 | RTC_ALRMAR_MSK1;
100
    RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE;
101
102
    // Enable write protection
103
    RTC->WPR = 0xFE;
104
    RTC->WPR = 0x64;
105
  }
106
107
  while(true)
108
  {
109
    // Sleep
110
    PWR->CR |= PWR_CR_LPDS;
111
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
112
    if(Interrupt)
113
        {
114
          __WFI();
115
        }
116
      else
117
        {
118
          if((RTC->ISR&RTC_ISR_ALRAF)!=0)
119
          {
120
            RTC->ISR ^= RTC_ISR_ALRAF;
121
          }
122
          // Debug: Prüfen ob Dauerschlaf, wenn RTC_ISR_ALRAF bereits beim Aufruf von "__WFE()" gesetzt ist: (ist aber alles Ok)
123
          if(1==2)
124
          {
125
            while((RTC->ISR&RTC_ISR_ALRAF)==0)
126
            {
127
              __asm("nop");
128
            }
129
          }
130
          __WFE();
131
        }
132
    SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
133
134
    // Toggle LED
135
    if(1==1)
136
    {
137
      GPIOA->ODR ^= 0x010; // Toggle LED
138
      for(int i=0; i<-1000; i++)
139
      {
140
        __asm("nop");
141
      }
142
    }
143
  }
144
145
  //
146
  // - 16.11.2016
147
  //
148
  // - VCC = 3.46V
149
  //
150
  // - Interrupt = true;
151
  //
152
  // - Programm im Flash
153
  //
154
  // - LSI_Enabled==FALSE
155
  //   xMHz /   xms ->  5.5µA
156
  //
157
  // - LSI_Enabled==TRUE
158
  //   1MHz /   5ms -> 17.9µA (20.1µA im SRAM)
159
  //   1MHz /  10ms -> 12.3µA (13.4µA im SRAM)
160
  //   1MHz /  20ms ->  9.5µA (19.1µA im SRAM)
161
  //   1MHz / 100ms ->  7.3µA ( 7.4µA im SRAM)
162
  //   1MHz /  6.5s ->  6.7µA ( 6.7µA im SRAM)
163
  //   8MHz /   5ms -> 11.8µA
164
  //   8MHz /  10ms ->  9.3µA
165
  //   8MHz / 100ms ->  7.0µA
166
  //   8MHz /  6.5s ->  6.7µA
167
  //
168
  // -> Ergebnis
169
  //    - I(xMHz, x) = 5.5µA
170
  //    - I(1MHz, t) = 6.7µA + 11.2µA*5ms/t
171
  //    - I(8MHz, t) = 6.7µA +  5.1µA*5ms/t
172
  //    - Verbrauch in SRAM und FLASH gleich (etwas langsamer vermutlich wegen fehledem Optimize-Compiler-Flag)
173
174
  // - Stromaufnahme in Pausephase - im Flash (30.03.2017)
175
  //   VCC/V |  I/µA
176
  //   ------+-------
177
  //     2.0 |  5.5
178
  //     2.5 |  6.0
179
  //     3.0 |  6.5
180
  //     3.3 |  6.9 +1mA@1MHz für 50µs; +2.2mA@8MHz für 10µs; +0.2µA mit IWDG
181
  //     3.5 |  7.2
182
  //     4.0 |  7.9
183
  //     4.5 |  8.9
184
  //     5.0 |  19..12 sinkt nach und nach
185
  return 0;
186
}

von Alexander H. (alex95)


Lesenswert?

Vielen Dank schonmal,
Ich habe beide Programme jetzt miteinander verglichen und wie du schon 
geschrieben hast machen beide ungefähr das Gleiche.
Das Problem lag in meinem Fall bei den Interrupt Handlern.
Ich habe bei mir nur den RTC_IRQHandler benutzt, welcher auch 
automatisch von CubeMX generiert wird.
Gefehlt hat der spezielle RTC_Alarm_IRQHandler. Dieser musste bei mir 
selbst geschrieben werden. Mich wundert jetzt nur, dass dieser auch bei 
dir fehlt oder ich übersehe auch nur wieder etwas.
Mich würde nur noch interessieren, ob ich die Einstellung für den Alarm 
Interrupt in CubeMX nur nicht gefunden habe oder ob man diese immer 
manuell vornehmen muss. Falls jemand auch CubeMX benutzt kann er ja mal 
seine Ideen hier schreiben. Ich nutze die Version 5.0.1.

von Magerquark (Gast)


Lesenswert?

Ich Trottel hab den Code aus meinem STM32F0-Ordner genommen. Der Code 
für den STM32F1 sieht anders aus. Dort verwende ich auch den 
RTCAlarm_IRQHandler. (Bzw. wenn unbenötigt nötig würde es aber auch ohne 
Interrupt per "Event" gehen.)

von Stefan F. (Gast)


Lesenswert?

Ist mir auch schon mal passiert. Leider spuckt der Compiler keine 
Fehlermeldung aus, wenn die C-Funktion des Interrupt Handlers den 
falschen Namen hat.

Ich glaube, man müsste die ganzen Weak referenzen aus der 
startup_stm32.s entfernen. Kennt jemand eine elegantere Lösung, diesen 
Fehler zu vermeiden?

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.