[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.
pull/158/head
bcostm 2014-01-31 18:14:31 +01:00
parent e9fe1394a5
commit 0110c3eec4
3 changed files with 74 additions and 63 deletions

View File

@ -66,7 +66,8 @@ typedef enum {
typedef enum { typedef enum {
PWM_2 = (int)TIM2_BASE, PWM_2 = (int)TIM2_BASE,
PWM_3 = (int)TIM3_BASE PWM_3 = (int)TIM3_BASE,
PWM_4 = (int)TIM4_BASE
} PWMName; } PWMName;
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -36,8 +36,7 @@
static const PinMap PinMap_PWM[] = { 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_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_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 {PB_6, PWM_4, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_UP, GPIO_AF_TIM4)}, // TIM4_CH1
//{PC_7, PWM_3, STM_PIN_DATA(GPIO_Mode_AF, GPIO_OType_PP, GPIO_PuPd_UP, GPIO_AF_TIM3)}, // TIM3_CH2
{NC, NC, 0} {NC, NC, 0}
}; };
@ -52,6 +51,7 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
// Enable TIM clock // Enable TIM clock
if (obj->pwm == PWM_2) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 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_3) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
if (obj->pwm == PWM_4) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
// Configure GPIO // Configure GPIO
pinmap_pinout(pin, PinMap_PWM); pinmap_pinout(pin, PinMap_PWM);
@ -78,9 +78,6 @@ void pwmout_write(pwmout_t* obj, float value) {
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); obj->pulse = (uint32_t)((float)obj->period * value);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 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; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
// Configure channel 1 // Configure channel 1
if (obj->pin == PB_4) { if ((obj->pin == PB_4) || (obj->pin == PB_6)) {
TIM_OC1PreloadConfig(tim, TIM_OCPreload_Enable); TIM_OC1PreloadConfig(tim, TIM_OCPreload_Enable);
TIM_OC1Init(tim, &TIM_OCInitStructure); TIM_OC1Init(tim, &TIM_OCInitStructure);
} }

View File

@ -29,60 +29,68 @@
#include "us_ticker_api.h" #include "us_ticker_api.h"
#include "PeripheralNames.h" #include "PeripheralNames.h"
// Timers selection: // Timer selection:
// The Master timer clocks the Slave timer
#define TIM_MST TIM9 #define TIM_MST TIM9
#define TIM_MST_IRQ TIM9_IRQn #define TIM_MST_IRQ TIM9_IRQn
#define TIM_MST_RCC RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE) #define TIM_MST_RCC RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE)
#define TIM_SLV TIM4 static int us_ticker_inited = 0;
#define TIM_SLV_IRQ TIM4_IRQn static uint32_t SlaveCounter = 0;
#define TIM_SLV_RCC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE) static uint32_t us_ticker_int_counter = 0;
static uint16_t us_ticker_int_remainder = 0;
#define MST_SLV_ITR TIM_TS_ITR3 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++;
}
int us_ticker_inited = 0; // 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();
}
}
}
}
void us_ticker_init(void) { void us_ticker_init(void) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
if (us_ticker_inited) return; if (us_ticker_inited) return;
us_ticker_inited = 1; us_ticker_inited = 1;
// Enable Timers clock // Enable Timer clock
TIM_MST_RCC; TIM_MST_RCC;
TIM_SLV_RCC;
// Master and Slave timers time base configuration // Configure time base
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 0xFFFF; TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(SystemCoreClock / 1000000) - 1; // 1 µs tick TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(SystemCoreClock / 1000000) - 1; // 1 µs tick
TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM_MST, &TIM_TimeBaseStructure); TIM_TimeBaseInit(TIM_MST, &TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseInit(TIM_SLV, &TIM_TimeBaseStructure);
// Master timer configuration // Configure interrupts
TIM_OCStructInit(&TIM_OCInitStructure); TIM_ITConfig(TIM_MST, TIM_IT_Update, ENABLE);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; TIM_ITConfig(TIM_MST, TIM_IT_CC1, ENABLE);
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 // For 32-bit counter and output compare
TIM_SelectSlaveMode(TIM_SLV, TIM_SlaveMode_External1); NVIC_SetVector(TIM_MST_IRQ, (uint32_t)tim_update_oc_irq_handler);
// The connection between Master and Slave is done here NVIC_EnableIRQ(TIM_MST_IRQ);
TIM_SelectInputTrigger(TIM_SLV, MST_SLV_ITR);
// Enable timers // Enable timer
TIM_Cmd(TIM_SLV, ENABLE);
TIM_Cmd(TIM_MST, ENABLE); 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 // 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 // value in the past. Avoid this by computing consecutive values of the timer until they
// are properly ordered. // 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); counter += (uint32_t)TIM_GetCounter(TIM_MST);
while (1) { while (1) {
counter2 = (uint32_t)((uint32_t)TIM_GetCounter(TIM_SLV) << 16); counter2 = (uint32_t)(SlaveCounter << 16);
counter2 += (uint32_t)TIM_GetCounter(TIM_MST); counter2 += (uint32_t)TIM_GetCounter(TIM_MST);
if (counter2 > counter) { if (counter2 > counter) {
break; break;
@ -108,26 +116,31 @@ uint32_t us_ticker_read() {
} }
void us_ticker_set_interrupt(unsigned int timestamp) { void us_ticker_set_interrupt(unsigned int timestamp) {
if (timestamp > 0xFFFF) { int delta = (int)(timestamp - us_ticker_read());
TIM_SetCompare1(TIM_SLV, (uint16_t)((timestamp >> 16) & 0xFFFF));
TIM_ITConfig(TIM_SLV, TIM_IT_CC1, ENABLE); if (delta <= 0) { // This event was in the past
NVIC_SetVector(TIM_SLV_IRQ, (uint32_t)us_ticker_irq_handler); us_ticker_irq_handler();
NVIC_EnableIRQ(TIM_SLV_IRQ); return;
} }
else { else {
TIM_SetCompare1(TIM_MST, (uint16_t)timestamp); us_ticker_int_counter = (uint32_t)(delta >> 16);
TIM_ITConfig(TIM_MST, TIM_IT_CC1, ENABLE); us_ticker_int_remainder = (uint16_t)(delta & 0xFFFF);
NVIC_SetVector(TIM_MST_IRQ, (uint32_t)us_ticker_irq_handler); if (us_ticker_int_counter > 0) { // means delta > 0xFFFF
NVIC_EnableIRQ(TIM_MST_IRQ); 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) { void us_ticker_disable_interrupt(void) {
TIM_ITConfig(TIM_MST, TIM_IT_CC1, DISABLE); TIM_ITConfig(TIM_MST, TIM_IT_CC1, DISABLE);
TIM_ITConfig(TIM_SLV, TIM_IT_CC1, DISABLE);
} }
void us_ticker_clear_interrupt(void) { 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);
TIM_ClearITPendingBit(TIM_SLV, TIM_IT_CC1); }
} }