drv_timer.c
Go to the documentation of this file.
1 /*
2  drv_timer.c : timer support for STM32F103CB
3 
4  Adapted from https://github.com/multiwii/baseflight/blob/master/src/drv_timer.c
5 
6  This file is part of BreezySTM32.
7 
8  BreezySTM32 is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  BreezySTM32 is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with BreezySTM32. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <stdbool.h>
23 
24 #include "stm32f10x_conf.h"
25 #include "core_cm3.h"
26 #include "drv_timer.h"
27 #include "drv_gpio.h"
28 
29 /* FreeFlight/Naze32 timer layout
30  TIM2_CH1 RC1 PWM1
31  TIM2_CH2 RC2 PWM2
32  TIM2_CH3 RC3/UA2_TX PWM3
33  TIM2_CH4 RC4/UA2_RX PWM4
34  TIM3_CH1 RC5 PWM5
35  TIM3_CH2 RC6 PWM6
36  TIM3_CH3 RC7 PWM7
37  TIM3_CH4 RC8 PWM8
38  TIM1_CH1 PWM1 PWM9
39  TIM1_CH4 PWM2 PWM10
40  TIM4_CH1 PWM3 PWM11
41  TIM4_CH2 PWM4 PWM12
42  TIM4_CH3 PWM5 PWM13
43  TIM4_CH4 PWM6 PWM14
44 
45  RX1 TIM2_CH1 PA0 [also PPM] [also used for throttle calibration]
46  RX2 TIM2_CH2 PA1
47  RX3 TIM2_CH3 PA2 [also UART2_TX]
48  RX4 TIM2_CH4 PA3 [also UART2_RX]
49  RX5 TIM3_CH1 PA6 [also ADC_IN6]
50  RX6 TIM3_CH2 PA7 [also ADC_IN7]
51  RX7 TIM3_CH3 PB0 [also ADC_IN8]
52  RX8 TIM3_CH4 PB1 [also ADC_IN9]
53 
54  Outputs
55  PWM1 TIM1_CH1 PA8
56  PWM2 TIM1_CH4 PA11
57  PWM3 TIM4_CH1 PB6? [also I2C1_SCL]
58  PWM4 TIM4_CH2 PB7 [also I2C1_SDA]
59  PWM5 TIM4_CH3 PB8
60  PWM6 TIM4_CH4 PB9
61  { TIM2, GPIOA, Pin_1, TIM_Channel_2, TIM2_IRQn, 0, }, // PWM2
62  { TIM2, GPIOA, Pin_2, TIM_Channel_3, TIM2_IRQn, 0, }, // PWM3
63  { TIM2, GPIOA, Pin_3, TIM_Channel_4, TIM2_IRQn, 0, }, // PWM4
64  { TIM3, GPIOA, Pin_6, TIM_Channel_1, TIM3_IRQn, 0, }, // PWM5
65  { TIM3, GPIOA, Pin_7, TIM_Channel_2, TIM3_IRQn, 0, }, // PWM6
66  { TIM3, GPIOB, Pin_0, TIM_Channel_3, TIM3_IRQn, 0, }, // PWM7
67  Groups that allow running different period (ex 50Hz servos + 400Hz throttle + etc):
68  TIM2 4 channels
69  TIM3 4 channels
70  TIM1 2 channels
71  TIM4 4 channels
72 */
73 
75  { TIM2, GPIOA, Pin_0, TIM_Channel_1, TIM2_IRQn, 0, }, // PWM1
76  { TIM2, GPIOA, Pin_1, TIM_Channel_2, TIM2_IRQn, 0, }, // PWM2
77  { TIM2, GPIOA, Pin_2, TIM_Channel_3, TIM2_IRQn, 0, }, // PWM3
78  { TIM2, GPIOA, Pin_3, TIM_Channel_4, TIM2_IRQn, 0, }, // PWM4
79  { TIM3, GPIOA, Pin_6, TIM_Channel_1, TIM3_IRQn, 0, }, // PWM5
80  { TIM3, GPIOA, Pin_7, TIM_Channel_2, TIM3_IRQn, 0, }, // PWM6
81  { TIM3, GPIOB, Pin_0, TIM_Channel_3, TIM3_IRQn, 0, }, // PWM7
82  { TIM3, GPIOB, Pin_1, TIM_Channel_4, TIM3_IRQn, 0, }, // PWM8
83  { TIM1, GPIOA, Pin_8, TIM_Channel_1, TIM1_CC_IRQn, 1, }, // PWM9
84  { TIM1, GPIOA, Pin_11, TIM_Channel_4, TIM1_CC_IRQn, 1, }, // PWM10
85  { TIM4, GPIOB, Pin_6, TIM_Channel_1, TIM4_IRQn, 0, }, // PWM11
86  { TIM4, GPIOB, Pin_7, TIM_Channel_2, TIM4_IRQn, 0, }, // PWM12
87  { TIM4, GPIOB, Pin_8, TIM_Channel_3, TIM4_IRQn, 0, }, // PWM13
88  { TIM4, GPIOB, Pin_9, TIM_Channel_4, TIM4_IRQn, 0, }, // PWM14
89 };
90 
91 enum {
92  TIM1_IDX = 0,
97 };
98 
99 #define CC_CHANNELS_PER_TIMER 4 // TIM_Channel_1..4
100 
101 static const TIM_TypeDef *const timers[MAX_TIMERS] = {
102  [TIM1_IDX] = TIM1, [TIM2_IDX] = TIM2, [TIM3_IDX] = TIM3, [TIM4_IDX] = TIM4
103 };
104 
105 typedef struct channelConfig_s {
106  uint16_t channel;
107  uint16_t interruptBit;
108  uint16_t (*TIM_GetCaptureFn)(TIM_TypeDef *TIMx);
110 
116 };
117 
118 typedef struct timerConfig_s {
120  uint8_t channel;
122  uint8_t reference;
123 } timerConfig_t;
124 
126 
127 static int lookupTimerIndex(const TIM_TypeDef *tim)
128 {
129  int timerIndex;
130  for (timerIndex = 0; timerIndex < MAX_TIMERS; timerIndex++ ) {
131  if (timers[timerIndex] == tim)
132  break;
133  }
134  return timerIndex;
135 }
136 
137 static int lookupChannelIndex(const int channel)
138 {
139  int channelIndex;
140  for (channelIndex = 0; channelIndex < CC_CHANNELS_PER_TIMER; channelIndex++ ) {
141  if (channels[channelIndex].channel == channel)
142  break;
143  }
144  return channelIndex;
145 }
146 
147 void configureTimerChannelCallback(TIM_TypeDef *tim, uint8_t channel, uint8_t reference, timerCCCallbackPtr *callback)
148 {
149  assert_param(IS_TIM_CHANNEL(channel));
150 
151  int timerIndex = lookupTimerIndex(tim);
152  int channelIndex = lookupChannelIndex(channel);
153 
154  if (timerIndex >= MAX_TIMERS || channelIndex >= CC_CHANNELS_PER_TIMER) {
155  return;
156  }
157 
158  timerConfigs[timerIndex][channelIndex].callback = callback;
159  timerConfigs[timerIndex][channelIndex].channel = channel;
160  timerConfigs[timerIndex][channelIndex].reference = reference;
161 }
162 
164 {
165  switch (channel) {
166  case TIM_Channel_1:
168  break;
169  case TIM_Channel_2:
171  break;
172  case TIM_Channel_3:
174  break;
175  case TIM_Channel_4:
177  break;
178  }
179 }
180 
181 void configureTimerCaptureCompareInterrupt(const timerHardware_t *timerHardwarePtr, uint8_t reference, timerCCCallbackPtr *callback)
182 {
183  configureTimerChannelCallback(timerHardwarePtr->tim, timerHardwarePtr->channel, reference, callback);
184  configureTimerInputCaptureCompareChannel(timerHardwarePtr->tim, timerHardwarePtr->channel);
185 }
186 
187 void timerNVICConfigure(uint8_t irq)
188 {
189  NVIC_InitTypeDef NVIC_InitStructure;
190 
191  NVIC_InitStructure.NVIC_IRQChannel = irq;
192  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
193  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
194  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
195  NVIC_Init(&NVIC_InitStructure);
196 }
197 
198 void configTimeBase(TIM_TypeDef *tim, uint16_t period, uint8_t mhz)
199 {
200  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
201 
202  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
203  TIM_TimeBaseStructure.TIM_Period = period - 1; // AKA TIMx_ARR
204 
205  // "The counter clock frequency (CK_CNT) is equal to f CK_PSC / (PSC[15:0] + 1)." - STM32F10x Reference Manual 14.4.11
206  // Thus for 1Mhz: 72000000 / 1000000 = 72, 72 - 1 = 71 = TIM_Prescaler
207  TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / ((uint32_t)mhz * 1000000)) - 1;
208 
209 
210  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
211  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
212  TIM_TimeBaseInit(tim, &TIM_TimeBaseStructure);
213 }
214 
215 void timerConfigure(const timerHardware_t *timerHardwarePtr, uint16_t period, uint8_t mhz)
216 {
217  configTimeBase(timerHardwarePtr->tim, period, mhz);
218  TIM_Cmd(timerHardwarePtr->tim, ENABLE);
219  timerNVICConfigure(timerHardwarePtr->irq);
220 }
221 
222 
223 static timerConfig_t *findTimerConfig(unsigned int timerIndex, unsigned int channelIndex)
224 {
225  assert_param(timerIndex < MAX_TIMERS);
226  assert_param(channelIndex < CC_CHANNELS_PER_TIMER);
227 
228  return &(timerConfigs[timerIndex][channelIndex]);
229 }
230 
231 static void timCCxHandler(TIM_TypeDef *const tim, unsigned int timerIndex)
232 {
233  unsigned int channelIndex;
234 
235  for (channelIndex = 0; channelIndex < CC_CHANNELS_PER_TIMER; channelIndex++) {
236  channelConfig_t const *const channel = &channels[channelIndex];
237 
238  if (TIM_GetITStatus(tim, channel->interruptBit) == SET) {
239  TIM_ClearITPendingBit(tim, channel->interruptBit);
240 
241  uint16_t capture;
242  capture = channel->TIM_GetCaptureFn(tim);
243 
244  timerConfig_t *timerConfig;
245  timerConfig = findTimerConfig(timerIndex, channelIndex);
246  if (timerConfig->callback) {
247  timerConfig->callback(timerConfig->reference, capture);
248  }
249  }
250  }
251 }
252 
254 {
256 }
257 
258 void TIM2_IRQHandler(void)
259 {
261 }
262 
263 void TIM3_IRQHandler(void)
264 {
266 }
267 
268 void TIM4_IRQHandler(void)
269 {
271 }
Definition: drv_gpio.h:44
Definition: drv_gpio.h:50
#define TIM_IT_CC3
uint8_t channel
Definition: drv_timer.c:120
#define TIM4
Definition: stm32f4xx.h:2039
uint32_t TIM_GetCapture3(TIM_TypeDef *TIMx)
Gets the TIMx Input Capture 3 value.
#define TIM_IT_CC4
void NVIC_Init(NVIC_InitTypeDef *NVIC_InitStruct)
Initializes the NVIC peripheral according to the specified parameters in the NVIC_InitStruct.
#define TIM1
Definition: stm32f4xx.h:2078
uint16_t channel
Definition: drv_timer.c:106
uint32_t TIM_GetCapture1(TIM_TypeDef *TIMx)
Gets the TIMx Input Capture 1 value.
#define CC_CHANNELS_PER_TIMER
Definition: drv_timer.c:99
void TIM_TimeBaseInit(TIM_TypeDef *TIMx, TIM_TimeBaseInitTypeDef *TIM_TimeBaseInitStruct)
Initializes the TIMx Time Base Unit peripheral according to the specified parameters in the TIM_TimeB...
timerConfig_t timerConfigs[MAX_TIMERS][CC_CHANNELS_PER_TIMER]
Definition: drv_timer.c:125
#define TIM_Channel_3
#define GPIOA
Definition: stm32f4xx.h:2110
#define TIM3
Definition: stm32f4xx.h:2038
#define TIM2
Definition: stm32f4xx.h:2037
#define GPIOB
Definition: stm32f4xx.h:2111
void TIM2_IRQHandler(void)
Definition: drv_timer.c:258
TIM_TypeDef * tim
Definition: drv_timer.c:119
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef *TIM_TimeBaseInitStruct)
Fills each TIM_TimeBaseInitStruct member with its default value.
void configureTimerChannelCallback(TIM_TypeDef *tim, uint8_t channel, uint8_t reference, timerCCCallbackPtr *callback)
Definition: drv_timer.c:147
ITStatus TIM_GetITStatus(TIM_TypeDef *TIMx, uint16_t TIM_IT)
Checks whether the TIM interrupt has occurred or not.
#define TIM_Channel_2
uint32_t SystemCoreClock
void assert_param(int val)
void timerCCCallbackPtr(uint8_t port, uint16_t capture)
Definition: drv_timer.h:24
#define TIM_Channel_4
uint32_t TIM_GetCapture2(TIM_TypeDef *TIMx)
Gets the TIMx Input Capture 2 value.
Definition: drv_gpio.h:48
static timerConfig_t * findTimerConfig(unsigned int timerIndex, unsigned int channelIndex)
Definition: drv_timer.c:223
Definition: stm32f4xx.h:706
void TIM4_IRQHandler(void)
Definition: drv_timer.c:268
const timerHardware_t timerHardware[]
Definition: drv_timer.c:74
void TIM_Cmd(TIM_TypeDef *TIMx, FunctionalState NewState)
Enables or disables the specified TIM peripheral.
TIM_TypeDef * tim
Definition: drv_timer.h:27
uint8_t channel
Definition: drv_timer.h:30
void configureTimerCaptureCompareInterrupt(const timerHardware_t *timerHardwarePtr, uint8_t reference, timerCCCallbackPtr *callback)
Definition: drv_timer.c:181
timerCCCallbackPtr * callback
Definition: drv_timer.c:121
void TIM3_IRQHandler(void)
Definition: drv_timer.c:263
Definition: drv_gpio.h:45
#define TIM_IT_CC1
#define IS_TIM_CHANNEL(CHANNEL)
uint32_t TIM_GetCapture4(TIM_TypeDef *TIMx)
Gets the TIMx Input Capture 4 value.
static const channelConfig_t channels[CC_CHANNELS_PER_TIMER]
Definition: drv_timer.c:111
#define TIM_Channel_1
Definition: drv_gpio.h:51
void timerConfigure(const timerHardware_t *timerHardwarePtr, uint16_t period, uint8_t mhz)
Definition: drv_timer.c:215
Definition: drv_gpio.h:43
TIM Time Base Init structure definition.
Definition: stm32f4xx_tim.h:55
void TIM_ITConfig(TIM_TypeDef *TIMx, uint16_t TIM_IT, FunctionalState NewState)
Enables or disables the specified TIM interrupts.
struct channelConfig_s channelConfig_t
#define TIM_IT_CC2
uint8_t reference
Definition: drv_timer.c:122
void timerNVICConfigure(uint8_t irq)
Definition: drv_timer.c:187
uint16_t(* TIM_GetCaptureFn)(TIM_TypeDef *TIMx)
Definition: drv_timer.c:108
static int lookupChannelIndex(const int channel)
Definition: drv_timer.c:137
uint16_t interruptBit
Definition: drv_timer.c:107
static void timCCxHandler(TIM_TypeDef *const tim, unsigned int timerIndex)
Definition: drv_timer.c:231
void TIM1_CC_IRQHandler(void)
Definition: drv_timer.c:253
static const TIM_TypeDef *const timers[MAX_TIMERS]
Definition: drv_timer.c:101
static int lookupTimerIndex(const TIM_TypeDef *tim)
Definition: drv_timer.c:127
Definition: drv_gpio.h:42
void configureTimerInputCaptureCompareChannel(TIM_TypeDef *tim, const uint8_t channel)
Definition: drv_timer.c:163
void configTimeBase(TIM_TypeDef *tim, uint16_t period, uint8_t mhz)
Definition: drv_timer.c:198
uint8_t irq
Definition: drv_timer.h:31
#define TIM_CounterMode_Up
struct timerConfig_s timerConfig_t
Definition: drv_gpio.h:49
void TIM_ClearITPendingBit(TIM_TypeDef *TIMx, uint16_t TIM_IT)
Clears the TIMx&#39;s interrupt pending bits.


rosflight_firmware
Author(s): Daniel Koch , James Jackson
autogenerated on Wed Jul 3 2019 19:59:24