Skip to content

Change us_ticker timer (32-bit) on Nucleo L152RE and F401RE #177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 19, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ typedef enum {
PB_8 = 0x18,
PB_9 = 0x19,
PB_10 = 0x1A,
PB_11 = 0x1B,
PB_12 = 0x1C,
PB_13 = 0x1D,
PB_14 = 0x1E,
Expand Down
14 changes: 0 additions & 14 deletions libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_F401RE/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,12 @@ static TIM_HandleTypeDef TimMasterHandle;

void sleep(void)
{
// Disable us_ticker update interrupt
TimMasterHandle.Instance = TIM1;
__HAL_TIM_DISABLE_IT(&TimMasterHandle, TIM_IT_UPDATE);

// Request to enter SLEEP mode
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);

// Re-enable us_ticker update interrupt
__HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_UPDATE);
}

void deepsleep(void)
{
// Disable us_ticker update interrupt
TimMasterHandle.Instance = TIM1;
__HAL_TIM_DISABLE_IT(&TimMasterHandle, TIM_IT_UPDATE);

// Request to enter STOP mode with regulator in low power mode
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);

// Re-enable us_ticker update interrupt
__HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_UPDATE);
}
115 changes: 15 additions & 100 deletions libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_F401RE/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,138 +30,53 @@
#include "PeripheralNames.h"
#include "stm32f4xx_hal.h"

// Timer selection:
#define TIM_MST TIM1
#define TIM_MST_UP_IRQ TIM1_UP_TIM10_IRQn
#define TIM_MST_OC_IRQ TIM1_CC_IRQn
#define TIM_MST_RCC __TIM1_CLK_ENABLE()
// 32-bit timer selection
#define TIM_MST TIM5
#define TIM_MST_IRQ TIM5_IRQn
#define TIM_MST_RCC __TIM5_CLK_ENABLE()

static TIM_HandleTypeDef TimMasterHandle;

static int us_ticker_inited = 0;
static volatile uint32_t SlaveCounter = 0;
static volatile uint32_t oc_int_part = 0;
static volatile uint16_t oc_rem_part = 0;

void set_compare(uint16_t count) {
// Set new output compare value
__HAL_TIM_SetCompare(&TimMasterHandle, TIM_CHANNEL_1, count);
// Enable IT
__HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC1);
}

// Used to increment the slave counter
static void tim_update_irq_handler(void) {
if (__HAL_TIM_GET_ITSTATUS(&TimMasterHandle, TIM_IT_UPDATE) == SET) {
__HAL_TIM_CLEAR_IT(&TimMasterHandle, TIM_IT_UPDATE);
__HAL_TIM_SetCounter(&TimMasterHandle, 0); // Reset counter !!!
SlaveCounter++;
}
}

// Used by interrupt system
static void tim_oc_irq_handler(void) {
uint16_t cval = TIM_MST->CNT;

// Clear interrupt flag
if (__HAL_TIM_GET_ITSTATUS(&TimMasterHandle, TIM_IT_CC1) == SET) {
__HAL_TIM_CLEAR_IT(&TimMasterHandle, TIM_IT_CC1);
}

if (oc_rem_part > 0) {
set_compare(oc_rem_part); // Finish the remaining time left
oc_rem_part = 0;
}
else {
if (oc_int_part > 0) {
set_compare(0xFFFF);
oc_rem_part = cval; // To finish the counter loop the next time
oc_int_part--;
}
else {
us_ticker_irq_handler();
}
}
}
static int us_ticker_inited = 0;

void us_ticker_init(void) {
if (us_ticker_inited) return;
us_ticker_inited = 1;

// Enable Timer clock
// Enable timer clock
TIM_MST_RCC;

// Configure time base
TimMasterHandle.Instance = TIM_MST;
TimMasterHandle.Init.Period = 0xFFFF;
TimMasterHandle.Init.Period = 0xFFFFFFFF;
TimMasterHandle.Init.Prescaler = (uint32_t)(SystemCoreClock / 1000000) - 1; // 1 �s tick
TimMasterHandle.Init.ClockDivision = 0;
TimMasterHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimMasterHandle.Init.RepetitionCounter = 0;
HAL_TIM_OC_Init(&TimMasterHandle);

// Configure interrupts
__HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_UPDATE);

// Update interrupt used for 32-bit counter
NVIC_SetVector(TIM_MST_UP_IRQ, (uint32_t)tim_update_irq_handler);
NVIC_EnableIRQ(TIM_MST_UP_IRQ);

// Output compare interrupt used for timeout feature
NVIC_SetVector(TIM_MST_OC_IRQ, (uint32_t)tim_oc_irq_handler);
NVIC_EnableIRQ(TIM_MST_OC_IRQ);
NVIC_SetVector(TIM_MST_IRQ, (uint32_t)us_ticker_irq_handler);
NVIC_EnableIRQ(TIM_MST_IRQ);

// Enable timer
HAL_TIM_OC_Start(&TimMasterHandle, TIM_CHANNEL_1);
}

uint32_t us_ticker_read() {
uint32_t counter, counter2;
if (!us_ticker_inited) us_ticker_init();
// A situation might appear when Master overflows right after Slave is read and before the
// new (overflowed) value of Master is read. Which would make the code below consider the
// previous (incorrect) value of Slave and the new value of Master, which would return a
// value in the past. Avoid this by computing consecutive values of the timer until they
// are properly ordered.
counter = (uint32_t)(SlaveCounter << 16);
counter += TIM_MST->CNT;
while (1) {
counter2 = (uint32_t)(SlaveCounter << 16);
counter2 += TIM_MST->CNT;
if (counter2 > counter) {
break;
}
counter = counter2;
}
return counter2;
return TIM_MST->CNT;
}

void us_ticker_set_interrupt(unsigned int timestamp) {
int delta = (int)(timestamp - us_ticker_read());
uint16_t cval = TIM_MST->CNT;

if (delta <= 0) { // This event was in the past
us_ticker_irq_handler();
}
else {
oc_int_part = (uint32_t)(delta >> 16);
oc_rem_part = (uint16_t)(delta & 0xFFFF);
if (oc_rem_part <= (0xFFFF - cval)) {
set_compare(cval + oc_rem_part);
oc_rem_part = 0;
} else {
set_compare(0xFFFF);
oc_rem_part = oc_rem_part - (0xFFFF - cval);
}
}
// Set new output compare value
__HAL_TIM_SetCompare(&TimMasterHandle, TIM_CHANNEL_1, timestamp);
// Enable IT
__HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC1);
}

void us_ticker_disable_interrupt(void) {
__HAL_TIM_DISABLE_IT(&TimMasterHandle, TIM_IT_CC1);
}

void us_ticker_clear_interrupt(void) {
if (__HAL_TIM_GET_ITSTATUS(&TimMasterHandle, TIM_IT_CC1) == SET) {
__HAL_TIM_CLEAR_IT(&TimMasterHandle, TIM_IT_CC1);
}
__HAL_TIM_CLEAR_IT(&TimMasterHandle, TIM_IT_CC1);
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,11 @@ static void SetSysClock_HSI(void)
// MCU SLEEP mode
void sleep(void)
{
// Disable us_ticker update interrupt
TIM_ITConfig(TIM9, TIM_IT_Update, DISABLE);

// Enable PWR clock
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

// Request to enter SLEEP mode with regulator ON
PWR_EnterSleepMode(PWR_Regulator_ON, PWR_SLEEPEntry_WFI);

// Re-enable us_ticker update interrupt
TIM_ITConfig(TIM9, TIM_IT_Update, ENABLE);
}

// MCU STOP mode (Regulator in LP mode, LSI, HSI and HSE OFF)
Expand Down
104 changes: 15 additions & 89 deletions libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,127 +29,53 @@
#include "us_ticker_api.h"
#include "PeripheralNames.h"

// Timer selection:
#define TIM_MST TIM9
#define TIM_MST_IRQ TIM9_IRQn
#define TIM_MST_RCC RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE)
// 32-bit timer selection
#define TIM_MST TIM5
#define TIM_MST_IRQ TIM5_IRQn
#define TIM_MST_RCC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE)

static int us_ticker_inited = 0;
static volatile uint32_t SlaveCounter = 0;
static volatile uint32_t oc_int_part = 0;
static volatile uint16_t oc_rem_part = 0;

void set_compare(uint16_t count) {
// Set new output compare value
TIM_SetCompare1(TIM_MST, count);
// Enable IT
TIM_ITConfig(TIM_MST, TIM_IT_CC1, ENABLE);
}

static void tim_update_oc_irq_handler(void) {
uint16_t cval = TIM_MST->CNT;

// Update interrupt: increment the slave counter
if (TIM_GetITStatus(TIM_MST, TIM_IT_Update) == SET) {
TIM_ClearITPendingBit(TIM_MST, TIM_IT_Update);
SlaveCounter++;
}

// Output compare interrupt: used by interrupt system
if (TIM_GetITStatus(TIM_MST, TIM_IT_CC1) == SET) {
TIM_ClearITPendingBit(TIM_MST, TIM_IT_CC1);
if (oc_rem_part > 0) {
set_compare(oc_rem_part); // Finish the remaining time left
oc_rem_part = 0;
}
else {
if (oc_int_part > 0) {
set_compare(0xFFFF);
oc_rem_part = cval; // To finish the counter loop the next time
oc_int_part--;
}
else {
us_ticker_irq_handler();
}
}
}
}
static int us_ticker_inited = 0;

void us_ticker_init(void) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

if (us_ticker_inited) return;
us_ticker_inited = 1;

// Enable Timer clock
// Enable timer clock
TIM_MST_RCC;

// Configure time base
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(SystemCoreClock / 1000000) - 1; // 1 �s tick
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM_MST, &TIM_TimeBaseStructure);

// Configure interrupts
TIM_ITConfig(TIM_MST, TIM_IT_Update, ENABLE);

// For 32-bit counter and output compare
NVIC_SetVector(TIM_MST_IRQ, (uint32_t)tim_update_oc_irq_handler);

NVIC_SetVector(TIM_MST_IRQ, (uint32_t)us_ticker_irq_handler);
NVIC_EnableIRQ(TIM_MST_IRQ);

// Enable timer
TIM_Cmd(TIM_MST, ENABLE);
}

uint32_t us_ticker_read() {
uint32_t counter, counter2;
if (!us_ticker_inited) us_ticker_init();
// A situation might appear when Master overflows right after Slave is read and before the
// new (overflowed) value of Master is read. Which would make the code below consider the
// previous (incorrect) value of Slave and the new value of Master, which would return a
// value in the past. Avoid this by computing consecutive values of the timer until they
// are properly ordered.
counter = (uint32_t)(SlaveCounter << 16);
counter += TIM_MST->CNT;
while (1) {
counter2 = (uint32_t)(SlaveCounter << 16);
counter2 += TIM_MST->CNT;
if (counter2 > counter) {
break;
}
counter = counter2;
}
return counter2;
return TIM_MST->CNT;
}

void us_ticker_set_interrupt(unsigned int timestamp) {
int delta = (int)(timestamp - us_ticker_read());
uint16_t cval = TIM_MST->CNT;

if (delta <= 0) { // This event was in the past
us_ticker_irq_handler();
}
else {
oc_int_part = (uint32_t)(delta >> 16);
oc_rem_part = (uint16_t)(delta & 0xFFFF);
if (oc_rem_part <= (0xFFFF - cval)) {
set_compare(cval + oc_rem_part);
oc_rem_part = 0;
} else {
set_compare(0xFFFF);
oc_rem_part = oc_rem_part - (0xFFFF - cval);
}
}
// Set new output compare value
TIM_SetCompare1(TIM_MST, timestamp);
// Enable IT
TIM_ITConfig(TIM_MST, TIM_IT_CC1, ENABLE);
}

void us_ticker_disable_interrupt(void) {
TIM_ITConfig(TIM_MST, TIM_IT_CC1, DISABLE);
}

void us_ticker_clear_interrupt(void) {
if (TIM_GetITStatus(TIM_MST, TIM_IT_CC1) == SET) {
TIM_ClearITPendingBit(TIM_MST, TIM_IT_CC1);
}
TIM_ClearITPendingBit(TIM_MST, TIM_IT_CC1);
}