Forum: Mikrocontroller und Digitale Elektronik STM32F303 Wakeup Timer löst keine Interrupts aus


von Stefan F. (Gast)


Lesenswert?

Ich möchte erreichen, dass der Wakeup Timer alle 2 Sekunden einen 
Interrupt auslöst damit die LED an PA5 blinkt. Sie bleibt aber leider 
dunkel. Sieht jemand, was ich falsch mache?
1
#include "stm32f3xx.h"
2
#include <stdio.h>
3
4
uint32_t SystemCoreClock=8000000;
5
6
// Delay loop for the default 8 MHz CPU clock with optimizer enabled
7
void delay(uint32_t msec)
8
{
9
    for (uint32_t j=0; j<2000UL*msec; j++)
10
    {
11
        __NOP();
12
    }
13
}
14
15
// Redirect standard output to the serial port
16
int _write(int file, char *ptr, int len)
17
{
18
    for (int i=0; i<len; i++)
19
    {
20
        while(!(USART2->ISR & USART_ISR_TXE));
21
        USART2->TDR = *ptr++;
22
    }
23
    return len;
24
}
25
26
void initSerial()
27
{
28
    // Use system clock for USART2
29
    SET_BIT(RCC->APB1ENR, RCC_APB1ENR_USART2EN);
30
    MODIFY_REG(RCC->CFGR3, RCC_CFGR3_USART2SW, RCC_CFGR3_USART2SW_0);
31
32
    // PA2 (TxD) shall use the alternate function 7 (see Reference manual)
33
    MODIFY_REG(GPIOA->AFR[0], GPIO_AFRL_AFRL2, 7U<<GPIO_AFRL_AFRL2_Pos);
34
    MODIFY_REG(GPIOA->MODER, GPIO_MODER_MODER2, GPIO_MODER_MODER2_1);
35
36
    // Set baudrate
37
    USART2->BRR = (SystemCoreClock / 2400);
38
39
    // Enable transmitter of USART2
40
    USART2->CR1 = USART_CR1_UE + USART_CR1_TE;
41
}
42
43
void init_io()
44
{
45
    // Enable Port A
46
    SET_BIT(RCC->AHBENR, RCC_AHBENR_GPIOAEN);
47
48
    // PA5 = Output for the LED (High=On, Low=Off)
49
    MODIFY_REG(GPIOA->MODER, GPIO_MODER_MODER5, GPIO_MODER_MODER5_0);
50
}
51
52
void initRtc()
53
{
54
    // Enable the power interface
55
    SET_BIT(RCC->APB1ENR, RCC_APB1ENR_PWREN);
56
57
    // Enable the power of the backup domain
58
    SET_BIT(PWR->CR, PWR_CR_DBP);
59
60
    // Enable LSE oscillator with medium driver power
61
    MODIFY_REG(RCC->BDCR, RCC_BDCR_LSEDRV, RCC_BDCR_LSEDRV_1);
62
    SET_BIT(RCC->BDCR, RCC_BDCR_LSEON);
63
64
    // Wait until LSE oscillator is ready
65
    while(!READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY)) {}
66
67
    // Select LSE as clock source for the RTC
68
    MODIFY_REG(RCC->BDCR, RCC_BDCR_RTCSEL, RCC_BDCR_RTCSEL_LSE);
69
70
    // Enable the RTC
71
    SET_BIT(RCC->BDCR, RCC_BDCR_RTCEN);
72
73
    // Enable write access to the RTC registers
74
    WRITE_REG(RTC->WPR, 0xCA);
75
    WRITE_REG(RTC->WPR, 0x53);
76
77
    // Stop the wakeup timer to allow configuration update
78
    CLEAR_BIT(RTC->CR, RTC_CR_WUTE);
79
80
    // Wait until the wakeup timer is ready for configuration update
81
    while (!READ_BIT(RTC->ISR, RTC_ISR_WUTWF)) {};
82
83
    // The wakeup period is 2 clock pulses
84
    WRITE_REG(RTC->WUTR,1);
85
86
    // Clock source of the wakeup timer is 1 Hz
87
    MODIFY_REG(RTC->CR, RTC_CR_WUCKSEL, RTC_CR_WUCKSEL_2);
88
89
    // Enable the wakeup timer with interrupts
90
    SET_BIT(RTC->CR, RTC_CR_WUTE + RTC_CR_WUTIE);
91
92
    // Enable interrupt in NVIC
93
    NVIC_EnableIRQ(RTC_WKUP_IRQn);
94
}
95
96
void RTC_WKUP_IRQHandler(void)
97
{
98
    // Clear interrupt flag
99
    CLEAR_BIT(RTC->ISR, RTC_ISR_WUTF);
100
101
    // Toggle LED 
102
    GPIOA->ODR ^= GPIO_ODR_5;
103
}
104
105
int main(void)
106
{
107
    init_io();
108
    initRtc();
109
    initSerial();
110
    while(1)
111
    {
112
        printf("Time %ld\n",RTC->TR);
113
        delay(500);
114
    }
115
}

An der seriellen Ausgabe via printf() erkenne ich, dass die Uhr läuft. 
Der ausgegebene Zahlenwert ändert sich jede Sekunde. Nur der Interrupt 
wird nie aufgerufen. Hier hänge ich fest.

Als Hardware dient ein Nucleo-64 Board mit STM32F303RE ohne externe 
Beschaltung. Stromversorgung über USB Kabel.

von Stefan F. (Gast)


Lesenswert?

Ich habe es selbst heraus gefunden: Knackpunkt war, dass ich mich noch 
um die EXTI Register kümmern musste.

Ich habe dazu noch eine Frage (weiter unten).
1
#include "stm32f3xx.h"
2
#include <stdio.h>
3
4
void init_io()
5
{
6
    // Enable Port A
7
    SET_BIT(RCC->AHBENR, RCC_AHBENR_GPIOAEN);
8
9
    // PA5 = Output for the LED
10
    MODIFY_REG(GPIOA->MODER, GPIO_MODER_MODER5, GPIO_MODER_MODER5_0);
11
}
12
13
void initRtc()
14
{
15
    // Enable the power interface
16
    SET_BIT(RCC->APB1ENR, RCC_APB1ENR_PWREN);
17
18
    // Enable access to the backup domain
19
    SET_BIT(PWR->CR, PWR_CR_DBP);
20
21
    // Enable LSE oscillator with medium driver power
22
    MODIFY_REG(RCC->BDCR, RCC_BDCR_LSEDRV, RCC_BDCR_LSEDRV_1);
23
    SET_BIT(RCC->BDCR, RCC_BDCR_LSEON);
24
25
    // Wait until LSE oscillator is ready
26
    while(!READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY)) {}
27
28
    // Select LSE as clock source for the RTC
29
    MODIFY_REG(RCC->BDCR, RCC_BDCR_RTCSEL, RCC_BDCR_RTCSEL_LSE);
30
31
    // Enable the RTC
32
    SET_BIT(RCC->BDCR, RCC_BDCR_RTCEN);
33
34
    // Enable write access to the RTC registers
35
    WRITE_REG(RTC->WPR, 0xCA);
36
    WRITE_REG(RTC->WPR, 0x53);
37
38
    // Enter initialzation mode for changes to RTC->TR, RTC->DR and RTC->PRER
39
    // SET_BIT(RTC->ISR, RTC_ISR_INIT);
40
41
    // Wait until the initialization mode is active
42
    // while (!READ_BIT(RTC->ISR, RTC_ISR_INITF)) {};
43
44
    // The RTC prescaler is already set to (127+1)*(255+1) = 32768 by default
45
    // WRITE_REG(RTC->PRER,(127<<RTC_PRER_PREDIV_A_Pos)+255);
46
47
    // End the initialization mode
48
    // CLEAR_BIT(RTC->ISR, RTC_ISR_INIT);
49
50
    // Stop the wakeup timer to allow configuration update
51
    CLEAR_BIT(RTC->CR, RTC_CR_WUTE);
52
53
    // Wait until the wakeup timer is ready for configuration update
54
    while (!READ_BIT(RTC->ISR, RTC_ISR_WUTWF)) {};
55
56
    // Clock source of the wakeup timer is 1 Hz
57
    MODIFY_REG(RTC->CR, RTC_CR_WUCKSEL, RTC_CR_WUCKSEL_2);
58
59
    // The wakeup period is 0+1 clock pulses
60
    WRITE_REG(RTC->WUTR,0);
61
62
    // Enable the wakeup timer with interrupts
63
    SET_BIT(RTC->CR, RTC_CR_WUTE + RTC_CR_WUTIE);
64
65
    // Optional: disable write access to the RTC registers
66
    // WRITE_REG(RTC->WPR, 0xFF);
67
68
    // Enable EXTI20 interrupt on rising edge
69
    SET_BIT(EXTI->IMR, EXTI_IMR_MR20);
70
    SET_BIT(EXTI->RTSR, EXTI_RTSR_TR20);
71
    NVIC_EnableIRQ(RTC_WKUP_IRQn);
72
73
    // Clear (old) pending interrupt flags
74
    CLEAR_BIT(RTC->ISR, RTC_ISR_WUTF);
75
    SET_BIT(EXTI->PR, EXTI_PR_PR20);
76
}
77
78
void RTC_WKUP_IRQHandler(void)
79
{
80
    // Clear interrupt flag
81
    CLEAR_BIT(RTC->ISR, RTC_ISR_WUTF);
82
    SET_BIT(EXTI->PR, EXTI_PR_PR20);
83
84
    // Toggle LED
85
    GPIOA->ODR ^= GPIO_ODR_5;
86
}
87
88
int main(void)
89
{
90
    init_io();
91
    initRtc();
92
    while(1){};
93
}

Ist es korrekt, dass ich in der ISR das Interrupt-Flag doppelt 
zurücksetzen muss (in der RTC und im NVIC)? Es scheint nötig zu sein, 
aber vielleicht geht es eleganter.

von pegel (Gast)


Lesenswert?

Das mit dem EXTI 20 habe ich durch anlegen mit CubeMX auch gerade heraus 
gefunden.

Der IRQHandler sieht so aus:
1
/**
2
  * @brief  Handle Wake Up Timer interrupt request.
3
  * @param  hrtc RTC handle
4
  * @retval None
5
  */
6
void HAL_RTCEx_WakeUpTimerIRQHandler(RTC_HandleTypeDef *hrtc)
7
{
8
  /* Get the pending status of the WAKEUPTIMER Interrupt */
9
  if(__HAL_RTC_WAKEUPTIMER_GET_FLAG(hrtc, RTC_FLAG_WUTF) != RESET)
10
  {
11
    /* WAKEUPTIMER callback */
12
    HAL_RTCEx_WakeUpTimerEventCallback(hrtc);
13
    
14
    /* Clear the WAKEUPTIMER interrupt pending bit */
15
    __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(hrtc, RTC_FLAG_WUTF);
16
  }
17
18
  /* Clear the EXTI's line Flag for RTC WakeUpTimer */
19
  __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();
20
  
21
  /* Change RTC state */
22
  hrtc->State = HAL_RTC_STATE_READY;
23
}

Bei der Auswahl des Interrupt in CubeMX heisst der:

"RTC wakeup-interrupt through EXTI line 20"

von Stefan F. (Gast)


Lesenswert?

Danke, ich hatte das im CubeMx nicht gefunden. Danke, dein Auszug 
bestätigt, dass es wohl so gemacht werden muss.

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.