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.
main.cpp
- Committer:
- Ladon
- Date:
- 2019-07-24
- Revision:
- 0:12efa8652054
- Child:
- 1:8d34cf217c0a
File content as of revision 0:12efa8652054:
#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;
}