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:
- 2:7c45a714b991
- Parent:
- 1:8d34cf217c0a
- Child:
- 3:db424769ecca
--- a/main.cpp Fri Jul 26 12:32:55 2019 +0000
+++ b/main.cpp Thu Aug 01 07:53:05 2019 +0000
@@ -1,193 +1,59 @@
#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 ()
+void inline enable_timer ()
{
-// *cr1 = 0x8D;
- *cr1 = 5;
+ TIM2->CR1 = TIM_CR1_URS | TIM_CR1_CEN;
}
-/*
-void inline disable_timer6 ()
+void inline enable_timer_interrupt ()
{
- *cr1 |= 2;
+ cout << "Setting DIER..." << endl;
+ cout << "DIER was : 0x" << hex << TIM2->DIER << endl;
+ cout << "Status is : 0x" << hex << TIM2->SR << endl;
+ TIM2->DIER = TIM_DIER_UIE;
+ cout << "Set DIER." << endl;
}
-*/
-void inline enable_timer6_interrupt ()
+void inline clear_timer_status ()
{
- *dier = 1;
+ TIM2->SR = 0;
}
-void inline clear_timer6_status ()
+void inline reset_timer ()
{
- *sr = 0;
-}
-
-void inline reset_timer6 ()
-{
- *egr = 1;
- clear_timer6_status();
+ TIM2->EGR = TIM_EGR_UG;
+ clear_timer_status();
}
-void inline downscale_timer6_by (const unsigned short& v)
+void inline downscale_timer_by (const unsigned short& v)
{
- *psc = v;
+ cout << "Downscaling counter by : 0x" << hex << 1 + v << endl;
+ TIM2->PSC = v;
}
-void inline downscale_timer6_max ()
+void inline downscale_timer_max ()
{
- downscale_timer6_by(0xFFFF);
+ downscale_timer_by(0xFFFF);
}
-void inline limit_timer6_counter_to (const unsigned short& v)
+void inline limit_timer_counter_to (const unsigned int& v)
{
- *arr = v;
+ cout << "Limiting counter to : 0x" << hex << v << endl;
+ TIM2->ARR = v;
}
void inline set_interrupt_period_to (const double& T)
{
- limit_timer6_counter_to(36000);
- downscale_timer6_by(1999 + (T - 1) * 2e3);
+ limit_timer_counter_to(36000);
+ downscale_timer_by(1999 + (T - 1) * 2e3);
// ^This allows : 500us <= T <= 32.768
// The ^former was found by solving : 0 <= 1999 + (T - 1) * 2e3 <= 0xFFFF, for the prescaler register.
// -
@@ -203,39 +69,41 @@
void init_LED ()
{
- unsigned int tmp = *moder;
- tmp |= 0x00000400U;
- tmp &= 0xFFFFF7FFU;
- // ^ Write 0,1 to bits 11,10.
+ GPIOA->MODER &= ~GPIO_MODER_MODER5;
+ // Set as output.
// -
- *moder = tmp;
+ GPIOA->MODER |= 1 << GPIO_MODER_MODER5_Pos;
}
void toggle_LED ()
{
- *odr ^= 0x20;
+ GPIOA->ODR ^= GPIO_ODR_5;
}
// Other functions:
// -
-void inline enable_clock_for_timer6 ()
+void inline enable_clock_for_timer ()
{
- *apb1enr |= 0x00000010U;
+ RCC->APB1RSTR |= RCC_APB1RSTR_TIM2RST;
+ RCC->APB1RSTR &= ~RCC_APB1RSTR_TIM2RST;
+ RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
}
// NVIC functions:
// -
-extern "C" void TIM6_DAC1_IRQHandler (void)
+extern "C" void TIM2_IRQHandler (void)
{
- clear_timer6_status();
+ cout << "Interrupt hit!" << endl;
+ clear_timer_status();
toggle_LED();
}
inline void enable_interrupt ()
{
- NVIC_EnableIRQ(TIM6_DAC1_IRQn);
+ NVIC_SetPriority(TIM2_IRQn, 255);
+ NVIC_EnableIRQ(TIM2_IRQn);
}
//
@@ -246,15 +114,25 @@
{
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);
+ enable_clock_for_timer();
+ TIM2->ARR = 0xffffffff;
+ TIM2->CR1 = TIM2->CR2 = TIM2->SMCR = TIM2->DIER = TIM2->SR = TIM2->CCMR1 = TIM2->CCMR2
+ = TIM2->CCER = TIM2->CNT = TIM2->PSC = TIM2->CCR1 = TIM2->CCR2 = TIM2->CCR3
+ = TIM2->CCR4 = TIM2->DCR = TIM2->DMAR = 0;
+ downscale_timer_max();
+ limit_timer_counter_to(0x1000);
// ^ LED stays open for 0.5 and closed for 0.5 with a total of 1 sec.
// -
- enable_timer6_interrupt();
- enable_timer6();
+ clear_timer_status();
+// enable_timer_interrupt();
+ enable_timer();
+ enable_interrupt();
cout << "Exiting main().." << endl;
cout << endl;
+ while (true)
+ {
+ cout << hex
+ << "Status : 0x" << TIM2->SR << endl
+ << "Count : 0x" << TIM2->CNT << endl;
+ }
}
\ No newline at end of file