Using CMSIS NVIC functions to set custom timer interrupt handler.

Dependencies:   mbed

Committer:
Ladon
Date:
Wed Jul 24 15:08:28 2019 +0000
Revision:
0:12efa8652054
Child:
1:8d34cf217c0a
Talking to Timer registers.; Enabling interrupt using NVIC functions.; Lighting LED for specified intervals.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Ladon 0:12efa8652054 1 #include <mbed.h>
Ladon 0:12efa8652054 2
Ladon 0:12efa8652054 3 #include <iostream>
Ladon 0:12efa8652054 4 // ^cout...
Ladon 0:12efa8652054 5 // -
Ladon 0:12efa8652054 6 #include <iomanip>
Ladon 0:12efa8652054 7 // ^setw...
Ladon 0:12efa8652054 8 // -
Ladon 0:12efa8652054 9
Ladon 0:12efa8652054 10 using namespace std;
Ladon 0:12efa8652054 11
Ladon 0:12efa8652054 12 // Board: NUCLEO-F303RE
Ladon 0:12efa8652054 13 // -
Ladon 0:12efa8652054 14 // Datasheet:
Ladon 0:12efa8652054 15 // https://www.st.com/resource/en/datasheet/stm32f303re.pdf
Ladon 0:12efa8652054 16 // Reference Manual:
Ladon 0:12efa8652054 17 // https://www.st.com/resource/en/reference_manual/dm00043574.pdf
Ladon 0:12efa8652054 18 // Programming Manual:
Ladon 0:12efa8652054 19 // https://www.st.com/resource/en/programming_manual/dm00046982.pdf
Ladon 0:12efa8652054 20 // (Some address #definitions):
Ladon 0:12efa8652054 21 // https://raw.githubusercontent.com/ARMmbed/mbed-os/master/targets/TARGET_STM/TARGET_STM32F3/TARGET_STM32F303xE/device/stm32f303xe.h
Ladon 0:12efa8652054 22 // -
Ladon 0:12efa8652054 23
Ladon 0:12efa8652054 24 // Direct port access is shown in this example:
Ladon 0:12efa8652054 25 // https://os.mbed.com/users/Ladon/code/Write_to_port_directly__LED/
Ladon 0:12efa8652054 26 // CPU hang discussion:
Ladon 0:12efa8652054 27 // https://community.arm.com/developer/tools-software/tools/f/keil-forum/33581/cpu-crash-when-enable-nvic-for-timer/82797#82797
Ladon 0:12efa8652054 28 // Possible clock definition:
Ladon 0:12efa8652054 29 // https://os.mbed.com/users/mbed_official/code/mbed-dev/file/f392fc9709a3/targets/TARGET_STM/TARGET_STM32F3/TARGET_STM32F303xE/TARGET_NUCLEO_F303RE/system_clock.c/
Ladon 0:12efa8652054 30 // We 're probably interested in APB1.
Ladon 0:12efa8652054 31 // -
Ladon 0:12efa8652054 32
Ladon 0:12efa8652054 33 //
Ladon 0:12efa8652054 34 // * Let 's use a timer to blink the LED.
Ladon 0:12efa8652054 35 // * Let 's use TIM6 or TIM7 from the datasheet.
Ladon 0:12efa8652054 36 // * For TIM6 there is IRQ 54 (TIM6_DAC1), as seen in the Reference Manual.
Ladon 0:12efa8652054 37 // * We find the appropriate alias (TIM6_DAC1_IRQn) in the "#definitions" ^^file above.
Ladon 0:12efa8652054 38 // * We 'll use ^this and the TIM6_DAC1_IRQHandler one, with NVIC CMSIS instructions
Ladon 0:12efa8652054 39 // like NVIC_EnableIRQ and NVIC_GetPendingIRQ, as seen in the ^^programming manual.
Ladon 0:12efa8652054 40 //
Ladon 0:12efa8652054 41 // * About the interrupt period:
Ladon 0:12efa8652054 42 // * Assuming that the APB1 peripheral clock, which is responsible for TIM6,
Ladon 0:12efa8652054 43 // runs at 36Mhz, we can limit the TIM6 to 36000 using the ARR (Auto Reload Register),
Ladon 0:12efa8652054 44 // and downscale it by 1000. This leaves us with 1 full timer counter per second:)
Ladon 0:12efa8652054 45 // * Truth is, input clock seems to be 72Mhz..
Ladon 0:12efa8652054 46 // * About setting arbitrary period:
Ladon 0:12efa8652054 47 // * Knowing that the counter clock (probably 72Mhz) gets divided by (1+TIM6_PSC) we can:
Ladon 0:12efa8652054 48 // * Divide by 1000 (1 + 999) and
Ladon 0:12efa8652054 49 // * Limit Counter to 72000 which is not possible in 16 bits, but 72000 = 36000 * 2 so
Ladon 0:12efa8652054 50 // let 's divide by 2 * 1000 instead. and limit to 36000.
Ladon 0:12efa8652054 51 // That leaves us with the filling period of 1sec. In order to chose any other period,
Ladon 0:12efa8652054 52 // we imagine the following equality:
Ladon 0:12efa8652054 53 // 72Mhz 36000 steps
Ladon 0:12efa8652054 54 // ---------------- = ------------- ==> 2000 + X = 2000 * T ==> X = 2000 * (T - 1)
Ladon 0:12efa8652054 55 // (1 + 1999 + X) T secs
Ladon 0:12efa8652054 56 // Thus, PSC (prescaler) is : 1999 + X = 1999 + 2000 * (T - 1), where T is in seconds.
Ladon 0:12efa8652054 57 // -
Ladon 0:12efa8652054 58 // From the Reference Manual:
Ladon 0:12efa8652054 59 //
Ladon 0:12efa8652054 60 // TIM6 base address:
Ladon 0:12efa8652054 61 // 0x4000 1000
Ladon 0:12efa8652054 62 // -
Ladon 0:12efa8652054 63 // TIM6_CR1: Control Register 1:
Ladon 0:12efa8652054 64 // Address offset: 0x00.
Ladon 0:12efa8652054 65 // 16bits.
Ladon 0:12efa8652054 66 // Bit0: CEN: Counter Enable.
Ladon 0:12efa8652054 67 // Enabled when 1.
Ladon 0:12efa8652054 68 // Bit2: URS: Update Request Source.
Ladon 0:12efa8652054 69 // 1: Only counter overflow/underflow generates an update interrupt.
Ladon 0:12efa8652054 70 //
Ladon 0:12efa8652054 71 // TIM6_DIER: DMA/ Interrupt Enable Register:
Ladon 0:12efa8652054 72 // Address offset: 0x0C.
Ladon 0:12efa8652054 73 // 16bits.
Ladon 0:12efa8652054 74 // Bit0: UIE: Update Interrupt Enable.
Ladon 0:12efa8652054 75 // 1: Enabled.
Ladon 0:12efa8652054 76 // I 'm not sure what this does..
Ladon 0:12efa8652054 77 // Bit8: UDE: Update DMA Request Enable.
Ladon 0:12efa8652054 78 // 1: Enabled.
Ladon 0:12efa8652054 79 //
Ladon 0:12efa8652054 80 // TIM6_SR: Status Register:
Ladon 0:12efa8652054 81 // Address offset: 0x10.
Ladon 0:12efa8652054 82 // 16bits.
Ladon 0:12efa8652054 83 // Bit0: UIF: Update Interrupt Flag:
Ladon 0:12efa8652054 84 // ??
Ladon 0:12efa8652054 85 //
Ladon 0:12efa8652054 86 // TIM6_EGR: Event Generation Register:
Ladon 0:12efa8652054 87 // Address offset: 0x14.
Ladon 0:12efa8652054 88 // 16bits (1bit) w/o
Ladon 0:12efa8652054 89 // Bit0: UG: Update Generation:
Ladon 0:12efa8652054 90 // When set to 1, re-initializes the timer counter and generates an
Ladon 0:12efa8652054 91 // update of the registers; it is automatically cleared by hardware.
Ladon 0:12efa8652054 92 // Sounds like a reset button.
Ladon 0:12efa8652054 93 //
Ladon 0:12efa8652054 94 // TIM6_CNT: Counter:
Ladon 0:12efa8652054 95 // Address offset: 0x24.
Ladon 0:12efa8652054 96 // 32bits wide.
Ladon 0:12efa8652054 97 // Bits 15..0: CNT: Counter value.
Ladon 0:12efa8652054 98 // Bit31: UIFCPY: A read-only copy of UIF (update interrupt flag) bit from TIM6_SR (status register).
Ladon 0:12efa8652054 99 // Note: In order to read the current count, mask the lower 16 bits.
Ladon 0:12efa8652054 100 //
Ladon 0:12efa8652054 101 // TIM6_PSC: Prescaler:
Ladon 0:12efa8652054 102 // Address offset: 0x28.
Ladon 0:12efa8652054 103 // 16bits.
Ladon 0:12efa8652054 104 // The counter clock frequency CK_CNT is equal to f_{CK_PSC} / (PSC + 1).
Ladon 0:12efa8652054 105 //
Ladon 0:12efa8652054 106 // TIM6_ARR: Auto Reload Register:
Ladon 0:12efa8652054 107 // Address Offset: 0x2C.
Ladon 0:12efa8652054 108 // 16bits (r/w).
Ladon 0:12efa8652054 109 // Info: The upper limit for the counter.
Ladon 0:12efa8652054 110 //
Ladon 0:12efa8652054 111 // RCC_APB1ENR: APB1 Peripheral Clock Enable Register:
Ladon 0:12efa8652054 112 // Base register: (?)RCC at 0x40021000.
Ladon 0:12efa8652054 113 // Address Offset: 0x1C.
Ladon 0:12efa8652054 114 // 32bits.
Ladon 0:12efa8652054 115 // Bit4: TIM6EN: Timer 6 clock Enable.
Ladon 0:12efa8652054 116 // 0: Disable.
Ladon 0:12efa8652054 117 // 1: Enable.
Ladon 0:12efa8652054 118 // -
Ladon 0:12efa8652054 119
Ladon 0:12efa8652054 120 // For TIM6 register:
Ladon 0:12efa8652054 121 // -
Ladon 0:12efa8652054 122 volatile unsigned short* cr1 = reinterpret_cast<volatile unsigned short*>(0x40001000U);
Ladon 0:12efa8652054 123 volatile unsigned short* dier = reinterpret_cast<volatile unsigned short*>(0x4000100CU);
Ladon 0:12efa8652054 124 volatile unsigned short* sr = reinterpret_cast<volatile unsigned short*>(0x40001010U);
Ladon 0:12efa8652054 125 volatile unsigned short* egr = reinterpret_cast<volatile unsigned short*>(0x40001014U);
Ladon 0:12efa8652054 126 volatile unsigned int* cnt = reinterpret_cast<volatile unsigned int*>( 0x40001024U);
Ladon 0:12efa8652054 127 volatile unsigned short* psc = reinterpret_cast<volatile unsigned short*>(0x40001028U);
Ladon 0:12efa8652054 128 volatile unsigned short* arr = reinterpret_cast<volatile unsigned short*>(0x4000102CU);
Ladon 0:12efa8652054 129
Ladon 0:12efa8652054 130 // For RCC register:
Ladon 0:12efa8652054 131 // -
Ladon 0:12efa8652054 132 volatile unsigned int* apb1enr = reinterpret_cast<unsigned int*>(0x40021000U + 0x1CU);
Ladon 0:12efa8652054 133 volatile unsigned int* apb1rstr = reinterpret_cast<unsigned int*>(0x40021000U + 0x10U);
Ladon 0:12efa8652054 134
Ladon 0:12efa8652054 135 // For GPIOA register:
Ladon 0:12efa8652054 136 // -
Ladon 0:12efa8652054 137 volatile unsigned int* moder = reinterpret_cast<volatile unsigned int*>( 0x48000000U);
Ladon 0:12efa8652054 138 volatile unsigned short* odr = reinterpret_cast<volatile unsigned short*>(0x48000014U);
Ladon 0:12efa8652054 139
Ladon 0:12efa8652054 140 // Timer functions:
Ladon 0:12efa8652054 141 // -
Ladon 0:12efa8652054 142
Ladon 0:12efa8652054 143 void inline enable_timer6 ()
Ladon 0:12efa8652054 144 {
Ladon 0:12efa8652054 145 // *cr1 = 0x8D;
Ladon 0:12efa8652054 146 *cr1 = 5;
Ladon 0:12efa8652054 147 }
Ladon 0:12efa8652054 148
Ladon 0:12efa8652054 149 /*
Ladon 0:12efa8652054 150 void inline disable_timer6 ()
Ladon 0:12efa8652054 151 {
Ladon 0:12efa8652054 152 *cr1 |= 2;
Ladon 0:12efa8652054 153 }
Ladon 0:12efa8652054 154 */
Ladon 0:12efa8652054 155
Ladon 0:12efa8652054 156 void inline enable_timer6_interrupt ()
Ladon 0:12efa8652054 157 {
Ladon 0:12efa8652054 158 *dier = 1;
Ladon 0:12efa8652054 159 }
Ladon 0:12efa8652054 160
Ladon 0:12efa8652054 161 void inline clear_timer6_status ()
Ladon 0:12efa8652054 162 {
Ladon 0:12efa8652054 163 *sr = 0;
Ladon 0:12efa8652054 164 }
Ladon 0:12efa8652054 165
Ladon 0:12efa8652054 166 void inline reset_timer6 ()
Ladon 0:12efa8652054 167 {
Ladon 0:12efa8652054 168 *egr = 1;
Ladon 0:12efa8652054 169 clear_timer6_status();
Ladon 0:12efa8652054 170 }
Ladon 0:12efa8652054 171
Ladon 0:12efa8652054 172 void inline downscale_timer6_by (const unsigned short& v)
Ladon 0:12efa8652054 173 {
Ladon 0:12efa8652054 174 *psc = v;
Ladon 0:12efa8652054 175 }
Ladon 0:12efa8652054 176
Ladon 0:12efa8652054 177 void inline downscale_timer6_max ()
Ladon 0:12efa8652054 178 {
Ladon 0:12efa8652054 179 downscale_timer6_by(0xFFFF);
Ladon 0:12efa8652054 180 }
Ladon 0:12efa8652054 181
Ladon 0:12efa8652054 182 void inline limit_timer6_counter_to (const unsigned short& v)
Ladon 0:12efa8652054 183 {
Ladon 0:12efa8652054 184 *arr = v;
Ladon 0:12efa8652054 185 }
Ladon 0:12efa8652054 186
Ladon 0:12efa8652054 187 void inline set_interrupt_period_to (const double& T)
Ladon 0:12efa8652054 188 {
Ladon 0:12efa8652054 189 limit_timer6_counter_to(36000);
Ladon 0:12efa8652054 190 downscale_timer6_by(1999 + (T - 1) * 2e3);
Ladon 0:12efa8652054 191 }
Ladon 0:12efa8652054 192
Ladon 0:12efa8652054 193 void inline set_interrupt_period_to_1sec ()
Ladon 0:12efa8652054 194 {
Ladon 0:12efa8652054 195 set_interrupt_period_to(1);
Ladon 0:12efa8652054 196 }
Ladon 0:12efa8652054 197
Ladon 0:12efa8652054 198 // GPIOA functions:
Ladon 0:12efa8652054 199 // -
Ladon 0:12efa8652054 200
Ladon 0:12efa8652054 201 void init_LED ()
Ladon 0:12efa8652054 202 {
Ladon 0:12efa8652054 203 unsigned int tmp = *moder;
Ladon 0:12efa8652054 204 tmp |= 0x00000400U;
Ladon 0:12efa8652054 205 tmp &= 0xFFFFF7FFU;
Ladon 0:12efa8652054 206 // ^ Write 0,1 to bits 11,10.
Ladon 0:12efa8652054 207 // -
Ladon 0:12efa8652054 208 *moder = tmp;
Ladon 0:12efa8652054 209 }
Ladon 0:12efa8652054 210
Ladon 0:12efa8652054 211 void toggle_LED ()
Ladon 0:12efa8652054 212 {
Ladon 0:12efa8652054 213 *odr ^= 0x20;
Ladon 0:12efa8652054 214 }
Ladon 0:12efa8652054 215
Ladon 0:12efa8652054 216 // Other functions:
Ladon 0:12efa8652054 217 // -
Ladon 0:12efa8652054 218
Ladon 0:12efa8652054 219 void inline enable_clock_for_timer6 ()
Ladon 0:12efa8652054 220 {
Ladon 0:12efa8652054 221 *apb1enr |= 0x00000010U;
Ladon 0:12efa8652054 222 }
Ladon 0:12efa8652054 223
Ladon 0:12efa8652054 224 // NVIC functions:
Ladon 0:12efa8652054 225 // -
Ladon 0:12efa8652054 226
Ladon 0:12efa8652054 227 extern "C" void TIM6_DAC1_IRQHandler (void)
Ladon 0:12efa8652054 228 {
Ladon 0:12efa8652054 229 clear_timer6_status();
Ladon 0:12efa8652054 230 toggle_LED();
Ladon 0:12efa8652054 231 }
Ladon 0:12efa8652054 232
Ladon 0:12efa8652054 233 inline void enable_interrupt ()
Ladon 0:12efa8652054 234 {
Ladon 0:12efa8652054 235 NVIC_EnableIRQ(TIM6_DAC1_IRQn);
Ladon 0:12efa8652054 236 }
Ladon 0:12efa8652054 237
Ladon 0:12efa8652054 238 //
Ladon 0:12efa8652054 239 // -
Ladon 0:12efa8652054 240 //
Ladon 0:12efa8652054 241
Ladon 0:12efa8652054 242 int main ()
Ladon 0:12efa8652054 243 {
Ladon 0:12efa8652054 244 cout << "Entered main()." << endl;
Ladon 0:12efa8652054 245 init_LED();
Ladon 0:12efa8652054 246 enable_interrupt();
Ladon 0:12efa8652054 247 enable_clock_for_timer6();
Ladon 0:12efa8652054 248 // ^ I think we need clock (?APB1?) running in order to setup the timer.
Ladon 0:12efa8652054 249 // -
Ladon 0:12efa8652054 250 set_interrupt_period_to(0.5);
Ladon 0:12efa8652054 251 // ^ LED stays open for 0.5 and closed for 0.5 with a total of 1 sec.
Ladon 0:12efa8652054 252 // -
Ladon 0:12efa8652054 253 enable_timer6_interrupt();
Ladon 0:12efa8652054 254 enable_timer6();
Ladon 0:12efa8652054 255 cout << "Exiting main().." << endl;
Ladon 0:12efa8652054 256 cout << endl;
Ladon 0:12efa8652054 257 }