Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: main.cpp
- Revision:
- 0:12efa8652054
- Child:
- 1:8d34cf217c0a
--- /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