Open FFBoard
Open source force feedback firmware
MotorPWM.cpp
Go to the documentation of this file.
1/*
2 * MotorPWM.cpp
3 *
4 * Created on: Mar 29, 2020
5 * Author: Yannick
6 */
7
8#include <MotorPWM.h>
9#ifdef PWMDRIVER
10
11#include "cpp_target_config.h"
12
13/*
14 * Mapping of names for ModePWM_DRV
15 */
16const std::vector<std::string> RC_SpeedNames = {"20ms","15ms","10ms","5ms"};
17const std::vector<std::string> PWM_SpeedNames = {"3khz","9khz","17khz","24khz"};
18// Names of SpeedPWM_DRV
19const std::vector<std::string> PwmModeNames = {"RC PPM","0%-50%-100% Centered","0-100% PWM/DIR","0-100% dual PWM"};
20bool MotorPWM::pwmDriverInUse = false;
21
23 .name = "PWM" ,
24 .id=CLSID_MOT_PWM,
25 };
27 return info;
28}
29
31 return !MotorPWM::pwmDriverInUse; // Creatable if not already in use for example by another axis
32}
33
34
35MotorPWM::MotorPWM() : CommandHandler("pwmdrv",CLSID_MOT_PWM) {
36
39 //HAL_TIM_Base_Start_IT(timer);
41
43 registerCommand("freq", MotorPWM_commands::freq, "PWM period selection",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
44 registerCommand("mode", MotorPWM_commands::mode, "PWM mode",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
45 registerCommand("dir", MotorPWM_commands::dir, "Invert direction",CMDFLAG_GET | CMDFLAG_SET);
46}
47
50 HAL_TIM_PWM_Stop(timerConfig.timer, timerConfig.channel_1);
51 HAL_TIM_PWM_Stop(timerConfig.timer, timerConfig.channel_2);
52 HAL_TIM_PWM_Stop(timerConfig.timer, timerConfig.channel_3);
53 HAL_TIM_PWM_Stop(timerConfig.timer, timerConfig.channel_4);
54 HAL_TIM_Base_Stop_IT(timerConfig.timer);
55}
56
57
58
59void MotorPWM::turn(int16_t power){
60 if(!active)
61 return;
62
63 if(invertDir){
64 power = -power;
65 }
66 /*
67 * Generates a classic RC 20ms 1000-2000µs signal
68 * Centered at 1500µs for bidirectional RC ESCs and similiar stuff
69 */
71 int32_t pval = power;
72
73 float val = ((pval * 1000)/0x7fff)*tFreq;
74 val = clip((1500*tFreq)-val,1000*tFreq, 2000*tFreq);
76
77 /*
78 * Generates a 0-100% PWM signal
79 * and outputs complementary direction signals.
80 * Can be used with cheap halfbridge modules and DC motors
81 */
82 }else if(mode == ModePWM_DRV::PWM_DIR){
83 if(power < 0){
86 }else{
89 }
90 int32_t val = (uint32_t)((abs(power) * period)/0x7fff);
92
94 int32_t pval = 0x7fff+power;
95 int32_t val = (pval * period)/0xffff;
97
98 }else if(mode == ModePWM_DRV::PWM_DUAL){
99 int32_t val = (uint32_t)((abs(power) * period)/0x7fff);
100 if(power < 0){
103 }else{
106 }
107 }
108}
109
113std::pair<uint16_t,uint16_t> MotorPWM::freqToPeriodPsc(uint32_t freq){
114 uint32_t arr_raw = (timerConfig.timerFreq/freq);
115 uint32_t prescaler = arr_raw / 0xffff;
116 uint32_t arr = arr_raw / (prescaler + 1);
117 return {arr,prescaler};
118}
119
124 bool ok = true;
125 switch(spd){
126
129 period = 40000; //20ms (40000/Sysclock)
131 }else{
132 std::tie(period,prescaler) = freqToPeriodPsc(3000);
133 }
134
135 break;
138 period = 30000;//15ms(30000/47)
140 }else{
141 std::tie(period,prescaler) = freqToPeriodPsc(9000);
142 }
143
144 break;
147 period = 20000; //10ms (20000/47)
149 }else{
150 std::tie(period,prescaler) = freqToPeriodPsc(17000);
151 }
152 break;
155 period = 10000; //5ms (20000/23)
157 }else{
158 std::tie(period,prescaler) = freqToPeriodPsc(24000);
159 }
160 break;
161 default:
162 ok = false;
163 }
164
165 if(ok){
166 this->pwmspeed = spd;
167 tFreq = (float)(timerConfig.timerFreq/1000000)/(float)(prescaler+1);
168
173 HAL_TIM_MspPostInit(timerConfig.timer);
174// setPWM_HAL(0, timer, channel_1, period);
175// pwmInitTimer(timer, channel_2,period,prescaler);
176// setPWM_HAL(0, timer, channel_2, period);
177 turn(0);
178 }
179}
180
184void MotorPWM::setPWM(uint32_t value,uint8_t ccr){
185 if(ccr == 1){
186 timerConfig.timer->Instance->CCR1 = value; // Set next CCR for channel 1
187 }else if(ccr == 2){
188 timerConfig.timer->Instance->CCR2 = value; // Set next CCR for channel 2
189 }else if(ccr == 3){
190 timerConfig.timer->Instance->CCR3 = value; // Set next CCR for channel 3
191 }else if(ccr == 4){
192 timerConfig.timer->Instance->CCR4 = value; // Set next CCR for channel 4
193 }
194
195}
196
198 return this->pwmspeed;
199}
200
201
202
203
205 // 0-3: mode
206 // 4-6: speed
207 uint16_t var = (uint8_t)this->mode & 0x7; // 1 bit free
208 var |= ((uint8_t)this->pwmspeed & 0x7) << 4;
209 var |= (this->invertDir & 0x1) << 15; // Last bit inversion
210 Flash_Write(ADR_PWM_MODE, var);
211}
213 uint16_t var = 0;
214 if(Flash_Read(ADR_PWM_MODE, &var)){
215 uint8_t m = var & 0xf;
216 this->setMode(ModePWM_DRV(m));
217
218 uint8_t s = (var >> 4) & 0x7;
219 this->setPwmSpeed(SpeedPWM_DRV(s));
220
221 this->invertDir = (var >> 15) & 0x1;
222 }
223}
224
225
227 active = true;
228 turn(0);
229}
230
232 turn(0);
233 active = false;
234}
235
236
238 this->mode = mode;
239 setPwmSpeed(pwmspeed); // Reinit timer
240}
241
243 return this->mode;
244}
245
246
247
248CommandStatus MotorPWM::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
249
250 switch(static_cast<MotorPWM_commands>(cmd.cmdId)){
251
253 {
254 if(cmd.type == CMDtype::set){
255 this->setPwmSpeed((SpeedPWM_DRV)cmd.val);
256 }else if(cmd.type == CMDtype::get){
257 replies.emplace_back((uint8_t)this->getPwmSpeed());
258 }else if(cmd.type == CMDtype::info){
259 std::vector<std::string> names = PWM_SpeedNames;
260 if(this->mode == ModePWM_DRV::RC_PWM){
261 names = RC_SpeedNames;
262 }else{
263 names = PWM_SpeedNames;
264 }
265 for(uint8_t i = 0; i<names.size();i++){
266 replies.emplace_back(names[i] + ":" + std::to_string(i)+"\n");
267 }
268 }
269 break;
270 }
272 {
273 if(cmd.type == CMDtype::set){
274 this->setMode((ModePWM_DRV)cmd.val);
275 }else if(cmd.type == CMDtype::get){
276 replies.emplace_back((uint8_t)this->getMode());
277 }else if(cmd.type == CMDtype::info){
278 for(uint8_t i = 0; i<PwmModeNames.size();i++){
279 replies.emplace_back(PwmModeNames[i] + ":" + std::to_string(i)+"\n");
280 }
281 }
282 break;
283 }
285 return handleGetSet(cmd, replies, this->invertDir);
286 default:
288 }
289
290 return CommandStatus::OK;
291
292}
293
294
295
297void pwmInitTimer(TIM_HandleTypeDef* timer,uint32_t channel,uint32_t period,uint32_t prescaler){
298 timer->Instance->ARR = period;
299 timer->Instance->PSC = prescaler;
300 TIM_OC_InitTypeDef sConfigOC = {0};
301 sConfigOC.OCMode = TIM_OCMODE_PWM1;
302 sConfigOC.Pulse = 0;
303 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
304 sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
305 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
306 sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
307 sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
309 HAL_TIM_PWM_Stop(timer, channel);
310 HAL_TIM_PWM_ConfigChannel(timer, &sConfigOC, channel);
311 //setPWM_HAL(0,timer,channel,period);
312 HAL_TIM_PWM_Start(timer, channel);
314
315}
316
317
321void setPWM_HAL(uint32_t value,TIM_HandleTypeDef* timer,uint32_t channel,uint32_t period){
322 TIM_OC_InitTypeDef sConfigOC;
323
324 sConfigOC.OCMode = TIM_OCMODE_PWM1;
325 sConfigOC.Pulse = value;
326 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
327 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
328 sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
329 HAL_TIM_PWM_ConfigChannel(timer, &sConfigOC, channel);
330 HAL_TIM_PWM_Start(timer, channel);
331}
332#endif
CommandStatus
const std::vector< std::string > PWM_SpeedNames
Definition: MotorPWM.cpp:17
cpp_freertos::MutexStandard pwmTimMutex
Definition: MotorPWM.cpp:296
const std::vector< std::string > RC_SpeedNames
Definition: MotorPWM.cpp:16
const std::vector< std::string > PwmModeNames
Definition: MotorPWM.cpp:19
void setPWM_HAL(uint32_t value, TIM_HandleTypeDef *timer, uint32_t channel, uint32_t period)
Definition: MotorPWM.cpp:321
void pwmInitTimer(TIM_HandleTypeDef *timer, uint32_t channel, uint32_t period, uint32_t prescaler)
Definition: MotorPWM.cpp:297
SpeedPWM_DRV
Definition: MotorPWM.h:25
ModePWM_DRV
Definition: MotorPWM.h:24
void registerCommand(const char *cmd, const ID cmdid, const char *help=nullptr, uint32_t flags=0)
static CommandStatus handleGetSet(const ParsedCommand &cmd, std::vector< CommandReply > &replies, TVal &value)
void saveFlash()
Definition: MotorPWM.cpp:204
SpeedPWM_DRV getPwmSpeed()
Definition: MotorPWM.cpp:197
MotorPWM_commands
Definition: MotorPWM.h:55
virtual ~MotorPWM()
Definition: MotorPWM.cpp:48
int32_t prescaler
Definition: MotorPWM.h:90
static bool pwmDriverInUse
Definition: MotorPWM.h:84
static const PWMConfig timerConfig
Definition: MotorPWM.h:102
void setPwmSpeed(SpeedPWM_DRV spd)
Definition: MotorPWM.cpp:123
ModePWM_DRV mode
Definition: MotorPWM.h:96
void turn(int16_t power)
Definition: MotorPWM.cpp:59
static std::pair< uint16_t, uint16_t > freqToPeriodPsc(uint32_t freq)
Definition: MotorPWM.cpp:113
static ClassIdentifier info
Definition: MotorPWM.h:62
MotorPWM()
Definition: MotorPWM.cpp:35
bool invertDir
Definition: MotorPWM.h:92
float tFreq
Definition: MotorPWM.h:88
ModePWM_DRV getMode()
Definition: MotorPWM.cpp:242
void startMotor()
Definition: MotorPWM.cpp:226
void stopMotor()
Definition: MotorPWM.cpp:231
const ClassIdentifier getInfo()
Command handlers always have class infos. Works well with ChoosableClass.
Definition: MotorPWM.cpp:26
void setPWM(uint32_t value, uint8_t ccr)
Definition: MotorPWM.cpp:184
void restoreFlash()
Definition: MotorPWM.cpp:212
void setMode(ModePWM_DRV mode)
Definition: MotorPWM.cpp:237
SpeedPWM_DRV pwmspeed
Definition: MotorPWM.h:95
bool active
Definition: MotorPWM.h:97
static bool isCreatable()
Definition: MotorPWM.cpp:30
int32_t period
Definition: MotorPWM.h:89
CommandStatus command(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
Definition: MotorPWM.cpp:248
virtual bool Lock(TickType_t Timeout=portMAX_DELAY)
Definition: cmutex.cpp:71
virtual bool Unlock()
Definition: cmutex.cpp:78
T clip(T v, C l, C h)
Definition: cppmain.h:58
bool Flash_Write(uint16_t adr, uint16_t dat)
bool Flash_Read(uint16_t adr, uint16_t *buf, bool checkempty=true)
const char * name
TIM_HandleTypeDef * timer
Definition: MotorPWM.h:44
uint8_t rcpwm_chan
Definition: MotorPWM.h:39
uint32_t timerFreq
Definition: MotorPWM.h:45
uint32_t channel_4
Definition: MotorPWM.h:31
uint8_t dualpwm2
Definition: MotorPWM.h:42
uint8_t centerpwm_chan
Definition: MotorPWM.h:37
uint8_t dualpwm1
Definition: MotorPWM.h:41
uint32_t channel_1
Definition: MotorPWM.h:28
uint8_t dir_chan_n
Definition: MotorPWM.h:35
uint32_t channel_2
Definition: MotorPWM.h:29
uint32_t channel_3
Definition: MotorPWM.h:30
uint8_t dir_chan
Definition: MotorPWM.h:34
uint8_t pwm_chan
Definition: MotorPWM.h:33
uint32_t cmdId