Spyros Papanastasiou / Mbed 2 deprecated General_purpose_timer_TIM2__custom_interrupt_handler

Dependencies:   mbed

Files at this revision

API Documentation at this revision

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

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Jul 24 15:08:28 2019 +0000
@@ -0,0 +1,257 @@
+#include <mbed.h>
+
+#include <iostream>
+// ^cout...
+// -
+#include <iomanip>
+// ^setw...
+// -
+
+using namespace std;
+
+// Board: NUCLEO-F303RE
+// -
+// Datasheet:
+//      https://www.st.com/resource/en/datasheet/stm32f303re.pdf
+// Reference Manual:
+//      https://www.st.com/resource/en/reference_manual/dm00043574.pdf
+// Programming Manual:
+//      https://www.st.com/resource/en/programming_manual/dm00046982.pdf
+// (Some address #definitions): 
+//      https://raw.githubusercontent.com/ARMmbed/mbed-os/master/targets/TARGET_STM/TARGET_STM32F3/TARGET_STM32F303xE/device/stm32f303xe.h
+// -
+
+// Direct port access is shown in this example:
+//      https://os.mbed.com/users/Ladon/code/Write_to_port_directly__LED/
+// CPU hang discussion:
+//      https://community.arm.com/developer/tools-software/tools/f/keil-forum/33581/cpu-crash-when-enable-nvic-for-timer/82797#82797
+// Possible clock definition:
+//      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/
+//      We 're probably interested in APB1.
+// -
+
+//
+// * Let 's use a timer to blink the LED.
+// * Let 's use TIM6 or TIM7 from the datasheet.
+// * For TIM6 there is IRQ 54 (TIM6_DAC1), as seen in the Reference Manual.
+// * We find the appropriate alias (TIM6_DAC1_IRQn) in the "#definitions" ^^file above.
+// * We 'll use ^this and the TIM6_DAC1_IRQHandler one, with NVIC CMSIS instructions
+//   like NVIC_EnableIRQ and NVIC_GetPendingIRQ, as seen in the ^^programming manual.
+//
+// * About the interrupt period:
+//      * Assuming that the APB1 peripheral clock, which is responsible for TIM6,
+//        runs at 36Mhz, we can limit the TIM6 to 36000 using the ARR (Auto Reload Register),
+//        and downscale it by 1000. This leaves us with 1 full timer counter per second:)
+//      * Truth is, input clock seems to be 72Mhz..
+//      * About setting arbitrary period:
+//          * Knowing that the counter clock (probably 72Mhz) gets divided by (1+TIM6_PSC) we can:
+//              * Divide by 1000 (1 + 999) and
+//              * Limit Counter to 72000 which is not possible in 16 bits, but 72000 = 36000 * 2 so
+//                let 's divide by 2 * 1000 instead. and limit to 36000.
+//            That leaves us with the filling period of 1sec. In order to chose any other period,
+//            we imagine the following equality:
+//                  72Mhz          36000 steps                 
+//            ----------------  = ------------- ==> 2000 + X = 2000 * T ==> X = 2000 * (T - 1)
+//             (1 + 1999 + X)        T secs                   
+//            Thus, PSC (prescaler) is : 1999 + X = 1999 + 2000 * (T - 1), where T is in seconds.
+// -
+// From the Reference Manual:
+//
+// TIM6 base address:
+//      0x4000 1000
+// -
+// TIM6_CR1: Control Register 1:
+//      Address offset: 0x00.
+//      16bits.
+//      Bit0: CEN: Counter Enable.
+//          Enabled when 1.
+//      Bit2: URS: Update Request Source.
+//          1: Only counter overflow/underflow generates an update interrupt.
+//
+// TIM6_DIER: DMA/ Interrupt Enable Register:
+//      Address offset: 0x0C.
+//      16bits.
+//      Bit0: UIE: Update Interrupt Enable.
+//          1: Enabled.
+//          I 'm not sure what this does..
+//      Bit8: UDE: Update DMA Request Enable.
+//          1: Enabled.
+//
+// TIM6_SR: Status Register:
+//      Address offset: 0x10.
+//      16bits.
+//      Bit0: UIF: Update Interrupt Flag:
+//          ??
+//
+// TIM6_EGR: Event Generation Register:
+//      Address offset: 0x14.
+//      16bits (1bit) w/o
+//      Bit0: UG: Update Generation:
+//          When set to 1, re-initializes the timer counter and generates an 
+//          update of the registers; it is automatically cleared by hardware.
+//          Sounds like a reset button.
+//
+// TIM6_CNT: Counter:
+//      Address offset: 0x24.
+//      32bits wide.
+//      Bits 15..0: CNT: Counter value.
+//      Bit31: UIFCPY: A read-only copy of UIF (update interrupt flag) bit from TIM6_SR (status register).
+//      Note: In order to read the current count, mask the lower 16 bits.
+//
+// TIM6_PSC: Prescaler:
+//      Address offset: 0x28.
+//      16bits.
+//      The counter clock frequency CK_CNT is equal to f_{CK_PSC} / (PSC + 1).
+//
+// TIM6_ARR: Auto Reload Register:
+//      Address Offset: 0x2C.
+//      16bits (r/w).
+//      Info: The upper limit for the counter.
+//
+// RCC_APB1ENR: APB1 Peripheral Clock Enable Register:
+//      Base register: (?)RCC at 0x40021000.
+//      Address Offset: 0x1C.
+//      32bits.
+//      Bit4: TIM6EN: Timer 6 clock Enable.
+//          0: Disable.
+//          1: Enable.
+// -
+
+// For TIM6 register:
+// -
+volatile unsigned short* cr1   = reinterpret_cast<volatile unsigned short*>(0x40001000U);
+volatile unsigned short* dier  = reinterpret_cast<volatile unsigned short*>(0x4000100CU);
+volatile unsigned short* sr    = reinterpret_cast<volatile unsigned short*>(0x40001010U);
+volatile unsigned short* egr   = reinterpret_cast<volatile unsigned short*>(0x40001014U);
+volatile unsigned int*   cnt   = reinterpret_cast<volatile unsigned int*>(  0x40001024U);
+volatile unsigned short* psc   = reinterpret_cast<volatile unsigned short*>(0x40001028U);
+volatile unsigned short* arr   = reinterpret_cast<volatile unsigned short*>(0x4000102CU);
+
+// For RCC register:
+// -
+volatile unsigned int* apb1enr  = reinterpret_cast<unsigned int*>(0x40021000U + 0x1CU);
+volatile unsigned int* apb1rstr = reinterpret_cast<unsigned int*>(0x40021000U + 0x10U);
+
+// For GPIOA register:
+// -
+volatile unsigned int*   moder = reinterpret_cast<volatile unsigned int*>(  0x48000000U);
+volatile unsigned short* odr   = reinterpret_cast<volatile unsigned short*>(0x48000014U);
+
+// Timer functions:
+// -
+
+void inline enable_timer6 ()
+{
+//    *cr1     = 0x8D;
+    *cr1 = 5;
+}
+
+/*
+void inline disable_timer6 ()
+{
+    *cr1 |= 2;
+}
+*/
+
+void inline enable_timer6_interrupt ()
+{
+    *dier    = 1;
+}
+
+void inline clear_timer6_status ()
+{
+    *sr = 0;
+}
+
+void inline reset_timer6 ()
+{
+    *egr = 1;
+    clear_timer6_status();
+}
+
+void inline downscale_timer6_by (const unsigned short& v)
+{
+    *psc = v;
+}
+
+void inline downscale_timer6_max ()
+{
+    downscale_timer6_by(0xFFFF);
+}
+
+void inline limit_timer6_counter_to (const unsigned short& v)
+{
+    *arr = v;
+}
+
+void inline set_interrupt_period_to (const double& T)
+{
+    limit_timer6_counter_to(36000);
+    downscale_timer6_by(1999 + (T - 1) * 2e3);
+}
+
+void inline set_interrupt_period_to_1sec ()
+{
+    set_interrupt_period_to(1);
+}
+
+// GPIOA functions:
+// -
+
+void init_LED ()
+{
+    unsigned int tmp = *moder;
+    tmp |= 0x00000400U;
+    tmp &= 0xFFFFF7FFU;
+    // ^ Write 0,1 to bits 11,10.
+    // -
+    *moder = tmp;
+}
+
+void toggle_LED ()
+{
+    *odr ^= 0x20;
+}
+
+// Other functions:
+// -
+
+void inline enable_clock_for_timer6 ()
+{
+    *apb1enr |= 0x00000010U;
+}
+
+// NVIC functions:
+// -
+
+extern "C" void TIM6_DAC1_IRQHandler (void)
+{
+    clear_timer6_status();
+    toggle_LED();
+}
+
+inline void enable_interrupt ()
+{
+    NVIC_EnableIRQ(TIM6_DAC1_IRQn);
+}
+
+//
+// -
+//
+
+int main ()
+{
+    cout << "Entered main()." << endl;
+    init_LED();
+    enable_interrupt();
+    enable_clock_for_timer6();
+    // ^ I think we need clock (?APB1?) running in order to setup the timer.
+    // -
+    set_interrupt_period_to(0.5);
+    // ^ LED stays open for 0.5 and closed for 0.5 with a total of 1 sec.
+    // -
+    enable_timer6_interrupt();
+    enable_timer6();
+    cout << "Exiting main().." << endl;
+    cout << endl;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Jul 24 15:08:28 2019 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/mbed_official/code/mbed/builds/65be27845400
\ No newline at end of file