[ion] Use TIM6 to keep track of time during Ion::msleep

This commit is contained in:
Jean-Baptiste Boric
2018-01-31 18:36:18 +01:00
parent 8e2ed09875
commit b774ddf7e7
3 changed files with 46 additions and 9 deletions

View File

@@ -19,15 +19,20 @@ extern "C" {
// Public Ion methods
/* TODO: The delay methods 'msleep' and 'usleep' are currently dependent on the
* optimizations chosen by the compiler. To prevent that and to gain in
* precision, we could use the controller cycle counter (Systick). */
void Ion::msleep(long ms) {
for (volatile long i=0; i<8852*ms; i++) {
__asm volatile("nop");
}
// We need a frequency high enough to not overflow the prescaler,
// which is 16 bits wide.
constexpr int TIM6_FREQ = 4*1000;
Ion::Device::waitTIM6(Ion::Device::SYSBUS_FREQ / TIM6_FREQ, ms * TIM6_FREQ / 1000);
}
/* TODO: The delay method 'usleep' is currently dependent on the optimizations
* chosen by the compiler. To prevent that and to gain in precision, we could
* use the controller cycle counter (Systick). We can't use a regular timer
* (like TIM6) for this since setting it up takes a significant amount of time
* in these timescales.
*/
void Ion::usleep(long us) {
for (volatile long i=0; i<9*us; i++) {
__asm volatile("nop");
@@ -211,8 +216,10 @@ void initClocks() {
RCC.AHB1ENR()->set(ahb1enr);
// APB1 bus
// We're using TIM3
// We're using TIM3 for the LEDs
RCC.APB1ENR()->setTIM3EN(true);
// We're using TIM6 for sleeping
RCC.APB1ENR()->setTIM6EN(true);
RCC.APB1ENR()->setPWREN(true);
// APB2 bus
@@ -240,5 +247,31 @@ void shutdownClocks() {
RCC.AHB3ENR()->setFSMCEN(false);
}
void waitTIM6(unsigned short prescaler, long cycles) {
while (cycles > 0) {
// TIM6 counts up to 2^16-1, make sure we won't overflow the counter.
uint16_t iterCycles = (cycles > 0xFFFF ? 0xFFFF : cycles);
// Initialize TIM6
TIM6.PSC()->set(prescaler);
TIM6.CNT()->set(0);
TIM6.ARR()->set(iterCycles);
TIM6.EGR()->setUG(true);
TIM6.SR()->setUIF(false);
TIM6.CR1()->setCEN(true);
// Wait until the timer elapses
do {
// TODO: Use interrupts instead of busy-waiting
__asm volatile("nop");
} while (TIM6.SR()->getUIF() == false);
// Stop TIM6
TIM6.CR1()->setCEN(false);
cycles -= iterCycles;
}
}
}
}

View File

@@ -4,6 +4,8 @@
namespace Ion {
namespace Device {
constexpr int SYSBUS_FREQ = 96*1000*1000;
void init();
void shutdown();
@@ -13,6 +15,8 @@ void shutdownPeripherals();
void initClocks();
void shutdownClocks();
void waitTIM6(unsigned short prescaler, long cycles);
/* Pin | Role | Mode | Function
* -----+-------------------+-----------------------+----------
* PA0 | Battery sensing | |

View File

@@ -47,7 +47,7 @@ void Ion::Power::suspend(bool checkIfPowerKeyReleased) {
* to clear it, and then a second WFE to wait for a _new_ event. */
asm("sev");
asm("wfe");
msleep(1);
asm("nop");
asm("wfe");
Device::initClocks();