From 0110c3eec4a825c99860280d059f6e765f595745 Mon Sep 17 00:00:00 2001 From: bcostm Date: Fri, 31 Jan 2014 18:14:31 +0100 Subject: [PATCH] [NUCLEO_L152RE] Add PWM output, ticker with one timer The us_ticker uses now only one timer instead of two. Another PWM output on TIM4 has been added. --- .../TARGET_NUCLEO_L152RE/PeripheralNames.h | 5 +- .../TARGET_NUCLEO_L152RE/pwmout_api.c | 19 ++- .../TARGET_NUCLEO_L152RE/us_ticker.c | 113 ++++++++++-------- 3 files changed, 74 insertions(+), 63 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/PeripheralNames.h b/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/PeripheralNames.h index fcf4480659..fd9ab88f2a 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/PeripheralNames.h +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/PeripheralNames.h @@ -65,8 +65,9 @@ typedef enum { } I2CName; typedef enum { - PWM_2 = (int)TIM2_BASE, - PWM_3 = (int)TIM3_BASE + PWM_2 = (int)TIM2_BASE, + PWM_3 = (int)TIM3_BASE, + PWM_4 = (int)TIM4_BASE } PWMName; #ifdef __cplusplus diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/pwmout_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/pwmout_api.c index ec02d4a7e7..aa76b9c5ce 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/pwmout_api.c +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/pwmout_api.c @@ -34,11 +34,10 @@ #include "error.h" static const PinMap PinMap_PWM[] = { - {PB_3, PWM_2, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_UP, GPIO_AF_TIM2)}, // TIM2_CH2 - {PB_4, PWM_3, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_UP, GPIO_AF_TIM3)}, // TIM3_CH1 - //{PB_10, PWM_2, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_UP, GPIO_AF_TIM2)}, // TIM2_CH3 - //{PC_7, PWM_3, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_UP, GPIO_AF_TIM3)}, // TIM3_CH2 - {NC, NC, 0} + {PB_3, PWM_2, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_UP, GPIO_AF_TIM2)}, // TIM2_CH2 + {PB_4, PWM_3, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_UP, GPIO_AF_TIM3)}, // TIM3_CH1 + {PB_6, PWM_4, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_UP, GPIO_AF_TIM4)}, // TIM4_CH1 + {NC, NC, 0} }; void pwmout_init(pwmout_t* obj, PinName pin) { @@ -52,7 +51,8 @@ void pwmout_init(pwmout_t* obj, PinName pin) { // Enable TIM clock if (obj->pwm == PWM_2) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); if (obj->pwm == PWM_3) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); - + if (obj->pwm == PWM_4) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); + // Configure GPIO pinmap_pinout(pin, PinMap_PWM); @@ -77,10 +77,7 @@ void pwmout_write(pwmout_t* obj, float value) { } else if (value > 1.0) { value = 1.0; } - - //while(TIM_GetFlagStatus(tim, TIM_FLAG_Update) == RESET); - //TIM_ClearFlag(tim, TIM_FLAG_Update); - + obj->pulse = (uint32_t)((float)obj->period * value); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; @@ -89,7 +86,7 @@ void pwmout_write(pwmout_t* obj, float value) { TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // Configure channel 1 - if (obj->pin == PB_4) { + if ((obj->pin == PB_4) || (obj->pin == PB_6)) { TIM_OC1PreloadConfig(tim, TIM_OCPreload_Enable); TIM_OC1Init(tim, &TIM_OCInitStructure); } diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/us_ticker.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/us_ticker.c index 0c07cbf537..99d043b369 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/us_ticker.c +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_L152RE/us_ticker.c @@ -29,60 +29,68 @@ #include "us_ticker_api.h" #include "PeripheralNames.h" -// Timers selection: -// The Master timer clocks the Slave timer +// Timer selection: +#define TIM_MST TIM9 +#define TIM_MST_IRQ TIM9_IRQn +#define TIM_MST_RCC RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE) -#define TIM_MST TIM9 -#define TIM_MST_IRQ TIM9_IRQn -#define TIM_MST_RCC RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE) +static int us_ticker_inited = 0; +static uint32_t SlaveCounter = 0; +static uint32_t us_ticker_int_counter = 0; +static uint16_t us_ticker_int_remainder = 0; -#define TIM_SLV TIM4 -#define TIM_SLV_IRQ TIM4_IRQn -#define TIM_SLV_RCC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE) +static void tim_update_oc_irq_handler(void) { + // Update interrupt: increment the slave counter + if (TIM_GetITStatus(TIM_MST, TIM_IT_Update) == SET) { + TIM_ClearITPendingBit(TIM_MST, TIM_IT_Update); + SlaveCounter++; + } -#define MST_SLV_ITR TIM_TS_ITR3 + // Output compare interrupt: used by interrupt system + if (TIM_GetITStatus(TIM_MST, TIM_IT_CC1) == SET) { + TIM_ClearITPendingBit(TIM_MST, TIM_IT_CC1); + if (us_ticker_int_counter > 0) { + TIM_SetCompare1(TIM_MST, 0xFFFF); + us_ticker_int_counter--; + } else { + if (us_ticker_int_remainder > 0) { + TIM_SetCompare1(TIM_MST, us_ticker_int_remainder); + us_ticker_int_remainder = 0; + } else { + // This function is going to disable the interrupts if there are + // no other events in the queue + us_ticker_irq_handler(); + } + } + } +} -int us_ticker_inited = 0; - -void us_ticker_init(void) { - +void us_ticker_init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; - TIM_OCInitTypeDef TIM_OCInitStructure; - + if (us_ticker_inited) return; us_ticker_inited = 1; - // Enable Timers clock + // Enable Timer clock TIM_MST_RCC; - TIM_SLV_RCC; - // Master and Slave timers time base configuration + // Configure time base TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = 0xFFFF; 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); - TIM_TimeBaseStructure.TIM_Prescaler = 0; - TIM_TimeBaseInit(TIM_SLV, &TIM_TimeBaseStructure); - - // Master timer configuration - TIM_OCStructInit(&TIM_OCInitStructure); - TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; - TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; - TIM_OCInitStructure.TIM_Pulse = 0; - TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; - TIM_OC1Init(TIM_MST, &TIM_OCInitStructure); - TIM_SelectMasterSlaveMode(TIM_MST, TIM_MasterSlaveMode_Enable); - TIM_SelectOutputTrigger(TIM_MST, TIM_TRGOSource_Update); - // Slave timer configuration - TIM_SelectSlaveMode(TIM_SLV, TIM_SlaveMode_External1); - // The connection between Master and Slave is done here - TIM_SelectInputTrigger(TIM_SLV, MST_SLV_ITR); + // Configure interrupts + TIM_ITConfig(TIM_MST, TIM_IT_Update, ENABLE); + TIM_ITConfig(TIM_MST, TIM_IT_CC1, ENABLE); + + // For 32-bit counter and output compare + NVIC_SetVector(TIM_MST_IRQ, (uint32_t)tim_update_oc_irq_handler); + NVIC_EnableIRQ(TIM_MST_IRQ); - // Enable timers - TIM_Cmd(TIM_SLV, ENABLE); + // Enable timer TIM_Cmd(TIM_MST, ENABLE); } @@ -94,10 +102,10 @@ uint32_t us_ticker_read() { // 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)((uint32_t)TIM_GetCounter(TIM_SLV) << 16); + counter = (uint32_t)(SlaveCounter << 16); counter += (uint32_t)TIM_GetCounter(TIM_MST); while (1) { - counter2 = (uint32_t)((uint32_t)TIM_GetCounter(TIM_SLV) << 16); + counter2 = (uint32_t)(SlaveCounter << 16); counter2 += (uint32_t)TIM_GetCounter(TIM_MST); if (counter2 > counter) { break; @@ -108,26 +116,31 @@ uint32_t us_ticker_read() { } void us_ticker_set_interrupt(unsigned int timestamp) { - if (timestamp > 0xFFFF) { - TIM_SetCompare1(TIM_SLV, (uint16_t)((timestamp >> 16) & 0xFFFF)); - TIM_ITConfig(TIM_SLV, TIM_IT_CC1, ENABLE); - NVIC_SetVector(TIM_SLV_IRQ, (uint32_t)us_ticker_irq_handler); - NVIC_EnableIRQ(TIM_SLV_IRQ); + int delta = (int)(timestamp - us_ticker_read()); + + if (delta <= 0) { // This event was in the past + us_ticker_irq_handler(); + return; } else { - TIM_SetCompare1(TIM_MST, (uint16_t)timestamp); - TIM_ITConfig(TIM_MST, TIM_IT_CC1, ENABLE); - NVIC_SetVector(TIM_MST_IRQ, (uint32_t)us_ticker_irq_handler); - NVIC_EnableIRQ(TIM_MST_IRQ); + us_ticker_int_counter = (uint32_t)(delta >> 16); + us_ticker_int_remainder = (uint16_t)(delta & 0xFFFF); + if (us_ticker_int_counter > 0) { // means delta > 0xFFFF + TIM_SetCompare1(TIM_MST, 0xFFFF); + us_ticker_int_counter--; + } else { + TIM_SetCompare1(TIM_MST, us_ticker_int_remainder); + us_ticker_int_remainder = 0; + } } } void us_ticker_disable_interrupt(void) { TIM_ITConfig(TIM_MST, TIM_IT_CC1, DISABLE); - TIM_ITConfig(TIM_SLV, TIM_IT_CC1, DISABLE); } void us_ticker_clear_interrupt(void) { - TIM_ClearITPendingBit(TIM_MST, TIM_IT_CC1); - TIM_ClearITPendingBit(TIM_SLV, TIM_IT_CC1); + if (TIM_GetITStatus(TIM_MST, TIM_IT_CC1) == SET) { + TIM_ClearITPendingBit(TIM_MST, TIM_IT_CC1); + } }