Mark81
August 21, 2021, 6:49am
1
Here my sketch for STM32:
#define PWM_RC_FREQ 50
#define PIN_SERVO PE9
typedef struct
{
bool active;
int pin;
uint32_t channel;
HardwareTimer *timer;
} Servo_t;
Servo_t servo;
float float_rc(float angle, float min, float max)
{
float in_min = 0.0;
float in_max = 180.0;
float out_min = min / 20000 * 65535;
float out_max = max / 20000 * 65535;
return (angle - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void servo_on()
{
pinMode(servo.pin, OUTPUT);
servo.timer->setMode(servo.channel, TIMER_OUTPUT_COMPARE_PWM1, servo.pin);
servo.timer->setOverflow(PWM_RC_FREQ, HERTZ_FORMAT);
servo.timer->setCaptureCompare(servo.channel, float_rc(90.0, 1966, 7864), RESOLUTION_16B_COMPARE_FORMAT);
servo.timer->resume();
servo.active = true;
}
void servo_off()
{
servo.timer->setMode(servo.channel, TIMER_DISABLED, servo.pin);
servo.timer->pause(); // if I pause the timer also the other associated channels won't work
pinMode(servo.pin, INPUT);
servo.active = false;
}
void setup()
{
servo.active = false;
servo.pin = PIN_SERVO;
TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(servo.pin), PinMap_PWM);
servo.channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(servo.pin), PinMap_PWM));
servo.timer = new HardwareTimer(Instance);
servo.timer->setMode(servo.channel, TIMER_DISABLED, servo.pin);
servo_on();
}
void loop()
{
static unsigned long millis_old = 0;
if (millis() - millis_old > 2000)
{
if (servo.active) servo_off();
else servo_on();
millis_old = millis();
}
}
It works but pausing the timer with servo.timer->pause();
inside servo_off()
leads to pause also all the other channels of the timer.
Instead I want to disable the current channel only. Making the pin an input.
If I remove the pause()
call, I'm not able to get the PWM again in servo_on()
. It will stay at high level.
From '#define PWM_RC_FREQ 50' I assume you are generating a PWM signal for a servo or ESC with BLDC motor. Why not use a library? You didn't say exactly which microcontroller you were programming, but maybe this library
STM32_ISR_Servo library [GitHub release]
[arduino-library-badge]
Why do we need this STM32_ISR_Servo library
Features
This library enables you to use 1 Hardware Timer on an STM32F/L/H/G/WB/MP1-based board to control up to 16 independent servo motors.
Currently supported Boards
STM32F/L/H/G/WB/MP1 boards (with 32+K Flash)
Nucleo-144
Nucleo-64
Discovery
Generic STM32F0, STM32F1, STM32F2, STM32F3, STM32F4, STM32F7 (with 64+K Flash): x8 and up
STM32L0, STM32L1, STM32L4, STM32L5
STM32G0, Sā¦
would help you.
1 Like
Mark81
August 22, 2021, 5:39pm
3
I'm using the Nucleo-144 F429ZI dev board.
I don't want to use third-part libraries because the actual code is very complex and should handle specific features.
I just want to be able to configure a pin as input or as output for hardware PWM like in the test code above.
Okay. At least you can look at the library code to see how it works. That might help you enough.
Mark81
August 23, 2021, 2:13pm
5
Thanks. That means you don't see an error in my code?
I don't see an error in your code but it doesn't matter for 2 reasons. First, obviously the code doesn't do what you want. Second, most of the code I'm not sure what it does because it's above my level of understanding. Someone else may be able to help you.
Mark81
August 24, 2021, 4:07am
7
I gave a look at the library: 1. it was released the same day you sent the message (3 days ago). 2. it's a software generated PWM (even if under ISR).
Sorry, but I don't see how it can help me to understand how to reconfigure the timer to enable and disable the PWM for each channel. We're talking about two completely different stuff!
Try it, but not tested.
#define PWM_RC_FREQ 50
#define PIN_SERVO PE9
typedef struct
{
bool active;
int pin;
uint32_t channel;
HardwareTimer *timer;
} Servo_t;
Servo_t servo;
float float_rc(float angle, float min, float max)
{
float in_min = 0.0;
float in_max = 180.0;
float out_min = min / 20000 * 65535;
float out_max = max / 20000 * 65535;
return (angle - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void servo_on()
{
pinMode(servo.pin, OUTPUT);
servo.timer->pause();
servo.timer->setMode(servo.channel, TIMER_OUTPUT_COMPARE_PWM1, servo.pin);
servo.timer->setOverflow(PWM_RC_FREQ, HERTZ_FORMAT);
servo.timer->setCaptureCompare(servo.channel, float_rc(90.0, 1966, 7864), RESOLUTION_16B_COMPARE_FORMAT);
servo.timer->resume();
servo.active = true;
}
void servo_off()
{
servo.timer->pause();
servo.timer->setMode(servo.channel, TIMER_DISABLED, servo.pin);
servo.timer->resume();
pinMode(servo.pin, INPUT);
servo.active = false;
}
void setup()
{
servo.active = false;
servo.pin = PIN_SERVO;
TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(servo.pin), PinMap_PWM);
servo.channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(servo.pin), PinMap_PWM));
servo.timer = new HardwareTimer(Instance);
servo.timer->setMode(servo.channel, TIMER_DISABLED, servo.pin);
servo_on();
}
void loop()
{
static unsigned long millis_old = 0;
if (millis() - millis_old > 2000)
{
if (servo.active) servo_off();
else servo_on();
millis_old = millis();
}
}
Mark81
August 24, 2021, 5:27am
9
It has the same problem: when disabling one channel, also the other 3 channels related to the same timer will be disabled.
Apparently I solved in a very easy way:
void servo_off()
{
pinMode(servo.pin, INPUT);
servo.active = false;
}
system
Closed
December 22, 2021, 5:28am
10
This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.