von
Stefan F. (Gast)
24.03.2019 21:22
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)
24.03.2019 22:44
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)
24.03.2019 22:55
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)
25.03.2019 07:12
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.