Skip to content

Commit dd292a7

Browse files
committed
NUCLEO_F103RB: Add pwmout api + change timers for ticker
1 parent c33dbfd commit dd292a7

File tree

6 files changed

+221
-49
lines changed

6 files changed

+221
-49
lines changed

libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_F103RB/PeripheralNames.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,10 @@ typedef enum {
4646
I2C_2 = (int)I2C2_BASE
4747
} I2CName;
4848

49-
// typedef enum {
50-
// PWM_1 = 1,
51-
// PWM_2,
52-
// PWM_3,
53-
// PWM_4,
54-
// PWM_5,
55-
// PWM_6
56-
// } PWMName;
49+
typedef enum {
50+
PWM_2 = (int)TIM2_BASE,
51+
PWM_3 = (int)TIM3_BASE
52+
} PWMName;
5753

5854
typedef enum {
5955
CAN_1 = (int)CAN1_BASE

libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_F103RB/device.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
#define DEVICE_RTC 0
3737

38-
#define DEVICE_PWMOUT 0
38+
#define DEVICE_PWMOUT 1
3939

4040
//=======================================
4141

libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_F103RB/objects.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@ struct i2c_s {
6666
I2CName i2c;
6767
};
6868

69-
//struct pwmout_s {
70-
// __IO uint32_t *MR;
71-
// PWMName pwm;
72-
//};
69+
struct pwmout_s {
70+
PWMName pwm;
71+
PinName pin;
72+
uint32_t period;
73+
uint32_t pulse;
74+
};
7375

7476
#include "gpio_object.h"
7577

libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_F103RB/pinmap.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
#include "error.h"
1818

1919
// Alternate-function mapping
20-
// TODO: add lines if needed...
2120
static const uint32_t AF_mapping[] = {
22-
0, // 0 = No AF
23-
GPIO_Remap_SPI1, // 1
24-
GPIO_Remap_I2C1, // 2
25-
GPIO_Remap_USART1, // 3
26-
GPIO_Remap_USART2 // 4
21+
0, // 0 = No AF
22+
GPIO_Remap_SPI1, // 1
23+
GPIO_Remap_I2C1, // 2
24+
GPIO_Remap_USART1, // 3
25+
GPIO_Remap_USART2, // 4
26+
GPIO_FullRemap_TIM2, // 5
27+
GPIO_FullRemap_TIM3 // 6
2728
};
2829

2930
/**
@@ -42,8 +43,9 @@ void pin_function(PinName pin, int data) {
4243
uint32_t port_index = (pin_number >> 4);
4344
GPIO_TypeDef *gpio = ((GPIO_TypeDef *)(GPIOA_BASE + (port_index << 10)));
4445

45-
// Enable GPIO clock
46+
// Enable GPIO and AFIO clocks
4647
RCC_APB2PeriphClockCmd((uint32_t)(RCC_APB2Periph_GPIOA << port_index), ENABLE);
48+
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
4749

4850
// Configure GPIO
4951
GPIO_InitTypeDef GPIO_InitStructure;
@@ -53,10 +55,18 @@ void pin_function(PinName pin, int data) {
5355
GPIO_Init(gpio, &GPIO_InitStructure);
5456

5557
// Configure Alternate Function
56-
if ((afnum > 0) && (afnum < 5)) {
57-
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
58-
GPIO_PinRemapConfig(AF_mapping[afnum], ENABLE);
58+
if (afnum > 0) {
59+
GPIO_PinRemapConfig(AF_mapping[afnum], ENABLE);
60+
}
61+
62+
// Disconnect JTAG-DP + SW-DP signals.
63+
// Warning: Need to reconnect under reset
64+
if ((pin == PA_13) || (pin == PA_14)) {
65+
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);
5966
}
67+
if ((pin == PA_15) || (pin == PB_3) || (pin == PB_4)) {
68+
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
69+
}
6070
}
6171

6272
/**
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2006-2013 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include "pwmout_api.h"
17+
18+
#include "cmsis.h"
19+
#include "pinmap.h"
20+
#include "error.h"
21+
22+
// Only TIM2 and TIM3 can be used (TIM1 and TIM4 are used by the us_ticker)
23+
static const PinMap PinMap_PWM[] = {
24+
// TIM2
25+
{PA_2, PWM_2, STM_PIN_DATA(GPIO_Mode_AF_PP, 0)}, // TIM2_CH3 OK
26+
{PA_3, PWM_2, STM_PIN_DATA(GPIO_Mode_AF_PP, 0)}, // TIM2_CH4 OK
27+
// TIM2 remap
28+
{PA_15, PWM_2, STM_PIN_DATA(GPIO_Mode_AF_PP, 5)}, // TIM2r_CH1 FAIL
29+
{PB_3, PWM_2, STM_PIN_DATA(GPIO_Mode_AF_PP, 5)}, // TIM2r_CH2 FAIL - ARDUINO D3
30+
{PB_10, PWM_2, STM_PIN_DATA(GPIO_Mode_AF_PP, 5)}, // TIM2r_CH3 OK - ARDUINO D6
31+
{PB_11, PWM_2, STM_PIN_DATA(GPIO_Mode_AF_PP, 5)}, // TIM2r_CH4 OK
32+
// TIM3
33+
{PA_6, PWM_3, STM_PIN_DATA(GPIO_Mode_AF_PP, 0)}, // TIM3_CH1 OK
34+
{PA_7, PWM_3, STM_PIN_DATA(GPIO_Mode_AF_PP, 0)}, // TIM3_CH2 OK - ARDUINO D11
35+
{PB_1, PWM_3, STM_PIN_DATA(GPIO_Mode_AF_PP, 0)}, // TIM3_CH4 OK
36+
// TIM3 remap
37+
{PB_4, PWM_3, STM_PIN_DATA(GPIO_Mode_AF_PP, 6)}, // TIM3r_CH1 FAIL - ARDUINO D5
38+
{PC_6, PWM_3, STM_PIN_DATA(GPIO_Mode_AF_PP, 6)}, // TIM3r_CH1 OK
39+
{PC_7, PWM_3, STM_PIN_DATA(GPIO_Mode_AF_PP, 6)}, // TIM3r_CH2 OK - ARDUINO D9
40+
{PB_5, PWM_3, STM_PIN_DATA(GPIO_Mode_AF_PP, 6)}, // TIM3r_CH2 FAIL - Bug confirmed in ES
41+
{PC_8, PWM_3, STM_PIN_DATA(GPIO_Mode_AF_PP, 6)}, // TIM3r_CH3 OK
42+
{PC_9, PWM_3, STM_PIN_DATA(GPIO_Mode_AF_PP, 6)}, // TIM3r_CH4 OK
43+
{NC, NC, 0}
44+
};
45+
46+
void pwmout_init(pwmout_t* obj, PinName pin) {
47+
// Get the peripheral name from the pin and assign it to the object
48+
obj->pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM);
49+
50+
if (obj->pwm == (PWMName)NC) {
51+
error("PWM pinout mapping failed");
52+
}
53+
54+
// Enable TIM clock
55+
if (obj->pwm == PWM_2) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
56+
if (obj->pwm == PWM_3) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
57+
58+
// Configure GPIO
59+
pinmap_pinout(pin, PinMap_PWM);
60+
61+
obj->pin = pin;
62+
obj->period = 0;
63+
obj->pulse = 0;
64+
65+
pwmout_period_us(obj, 20000); // 20 ms per default
66+
}
67+
68+
void pwmout_free(pwmout_t* obj) {
69+
TIM_TypeDef *tim = (TIM_TypeDef *)(obj->pwm);
70+
TIM_DeInit(tim);
71+
}
72+
73+
void pwmout_write(pwmout_t* obj, float value) {
74+
TIM_TypeDef *tim = (TIM_TypeDef *)(obj->pwm);
75+
TIM_OCInitTypeDef TIM_OCInitStructure;
76+
77+
if (value < 0.0) {
78+
value = 0.0;
79+
} else if (value > 1.0) {
80+
value = 1.0;
81+
}
82+
83+
//while(TIM_GetFlagStatus(tim, TIM_FLAG_Update) == RESET);
84+
//TIM_ClearFlag(tim, TIM_FLAG_Update);
85+
86+
obj->pulse = (uint32_t)((float)obj->period * value);
87+
88+
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
89+
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
90+
TIM_OCInitStructure.TIM_Pulse = obj->pulse;
91+
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
92+
93+
if ((obj->pin == PA_6) || (obj->pin == PA_15) || (obj->pin == PB_4) || (obj->pin == PC_6)) { // TIM Channel 1
94+
TIM_OC1PreloadConfig(tim, TIM_OCPreload_Enable);
95+
TIM_OC1Init(tim, &TIM_OCInitStructure);
96+
}
97+
98+
if ((obj->pin == PA_7) || (obj->pin == PB_3) || (obj->pin == PB_5) || (obj->pin == PC_7)) { // TIM Channel 2
99+
TIM_OC2PreloadConfig(tim, TIM_OCPreload_Enable);
100+
TIM_OC2Init(tim, &TIM_OCInitStructure);
101+
}
102+
103+
if ((obj->pin == PA_2) || (obj->pin == PB_10) || (obj->pin == PC_8)) { // TIM Channel 3
104+
TIM_OC3PreloadConfig(tim, TIM_OCPreload_Enable);
105+
TIM_OC3Init(tim, &TIM_OCInitStructure);
106+
}
107+
108+
if ((obj->pin == PA_3) || (obj->pin == PB_1) || (obj->pin == PB_11) || (obj->pin == PC_9)) { // TIM Channel 4
109+
TIM_OC4PreloadConfig(tim, TIM_OCPreload_Enable);
110+
TIM_OC4Init(tim, &TIM_OCInitStructure);
111+
}
112+
}
113+
114+
float pwmout_read(pwmout_t* obj) {
115+
float value = 0;
116+
if (obj->period > 0) {
117+
value = (float)(obj->pulse) / (float)(obj->period);
118+
}
119+
return ((value > 1.0) ? (1.0) : (value));
120+
}
121+
122+
void pwmout_period(pwmout_t* obj, float seconds) {
123+
pwmout_period_us(obj, seconds * 1000000.0f);
124+
}
125+
126+
void pwmout_period_ms(pwmout_t* obj, int ms) {
127+
pwmout_period_us(obj, ms * 1000);
128+
}
129+
130+
void pwmout_period_us(pwmout_t* obj, int us) {
131+
TIM_TypeDef *tim = (TIM_TypeDef *)(obj->pwm);
132+
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
133+
float dc = pwmout_read(obj);
134+
135+
TIM_Cmd(tim, DISABLE);
136+
137+
obj->period = us;
138+
139+
TIM_TimeBaseStructure.TIM_Period = obj->period - 1;
140+
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(SystemCoreClock / 1000000) - 1; // 1 µs tick
141+
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
142+
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
143+
TIM_TimeBaseInit(tim, &TIM_TimeBaseStructure);
144+
145+
// Set duty cycle again
146+
pwmout_write(obj, dc);
147+
148+
TIM_ARRPreloadConfig(tim, ENABLE);
149+
TIM_Cmd(tim, ENABLE);
150+
}
151+
152+
void pwmout_pulsewidth(pwmout_t* obj, float seconds) {
153+
pwmout_pulsewidth_us(obj, seconds * 1000000.0f);
154+
}
155+
156+
void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
157+
pwmout_pulsewidth_us(obj, ms * 1000);
158+
}
159+
160+
void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
161+
float value = (float)us / (float)obj->period;
162+
pwmout_write(obj, value);
163+
}

libraries/mbed/targets/hal/TARGET_STM/TARGET_NUCLEO_F103RB/us_ticker.c

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,65 +27,66 @@ void us_ticker_init(void) {
2727
if (us_ticker_inited) return;
2828
us_ticker_inited = 1;
2929

30-
// Enable Timer clock
31-
RCC_APB1PeriphClockCmd((RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3), ENABLE);
32-
30+
// Enable Timers clock
31+
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
32+
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
33+
3334
// Time base configuration
34-
// TIM2 is used as "master", "TIM3" as "slave". TIM3 is clocked by TIM2.
35+
// TIM1 is used as "master", "TIM4" as "slave". TIM4 is clocked by TIM1.
3536
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
3637
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(SystemCoreClock / 1000000) - 1; // 1 µs tick
3738
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
3839
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
39-
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
40+
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
4041
TIM_TimeBaseStructure.TIM_Prescaler = 0;
41-
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
42+
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
4243

4344
// Master timer configuration
4445
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
4546
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
4647
TIM_OCInitStructure.TIM_Pulse = 0;
4748
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
48-
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
49-
TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);
50-
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
49+
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
50+
TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);
51+
TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);
5152

5253
// Slave timer configuration
53-
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Gated);
54-
TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1);
54+
TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Gated);
55+
TIM_SelectInputTrigger(TIM4, TIM_TS_ITR0);
5556

5657
// Enable timers
57-
TIM_Cmd(TIM3, ENABLE);
58-
TIM_Cmd(TIM2, ENABLE);
58+
TIM_Cmd(TIM4, ENABLE);
59+
TIM_Cmd(TIM1, ENABLE);
5960
}
6061

6162
uint32_t us_ticker_read() {
6263
uint32_t counter;
6364
if (!us_ticker_inited) us_ticker_init();
64-
counter = (uint32_t)((uint32_t)TIM_GetCounter(TIM3) << 16) + (uint32_t)TIM_GetCounter(TIM2);
65+
counter = (uint32_t)((uint32_t)TIM_GetCounter(TIM4) << 16) + (uint32_t)TIM_GetCounter(TIM1);
6566
return counter;
6667
}
6768

6869
void us_ticker_set_interrupt(unsigned int timestamp) {
6970
if (timestamp > 0xFFFF) {
70-
TIM_SetCompare1(TIM3, (uint16_t)((timestamp >> 16) & 0xFFFF));
71-
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
72-
NVIC_SetVector(TIM3_IRQn, (uint32_t)us_ticker_irq_handler);
73-
NVIC_EnableIRQ(TIM3_IRQn);
71+
TIM_SetCompare1(TIM4, (uint16_t)((timestamp >> 16) & 0xFFFF));
72+
TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);
73+
NVIC_SetVector(TIM4_IRQn, (uint32_t)us_ticker_irq_handler);
74+
NVIC_EnableIRQ(TIM4_IRQn);
7475
}
7576
else {
76-
TIM_SetCompare1(TIM2, (uint16_t)timestamp);
77-
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
78-
NVIC_SetVector(TIM2_IRQn, (uint32_t)us_ticker_irq_handler);
79-
NVIC_EnableIRQ(TIM2_IRQn);
77+
TIM_SetCompare1(TIM1, (uint16_t)timestamp);
78+
TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
79+
NVIC_SetVector(TIM1_CC_IRQn, (uint32_t)us_ticker_irq_handler);
80+
NVIC_EnableIRQ(TIM1_CC_IRQn);
8081
}
8182
}
8283

8384
void us_ticker_disable_interrupt(void) {
84-
TIM_ITConfig(TIM2, TIM_IT_CC1, DISABLE);
85-
TIM_ITConfig(TIM3, TIM_IT_CC1, DISABLE);
85+
TIM_ITConfig(TIM1, TIM_IT_CC1, DISABLE);
86+
TIM_ITConfig(TIM4, TIM_IT_CC1, DISABLE);
8687
}
8788

8889
void us_ticker_clear_interrupt(void) {
89-
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
90-
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
90+
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
91+
TIM_ClearITPendingBit(TIM4, TIM_IT_CC1);
9192
}

0 commit comments

Comments
 (0)