Skip to content

Commit 4bb8de2

Browse files
committed
feat(srv/generic-power): Add support for PWM'ing of power outputs
@todo Remove STM32-specific code and dependencies
1 parent 5803461 commit 4bb8de2

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed

services/generic-power/generic-power.c

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313

1414
#include <main.h>
1515
#include <interfaces/power.h>
16+
#include <libopencm3/stm32/rcc.h>
1617
#include <libopencm3/stm32/gpio.h>
18+
#include <libopencm3/stm32/timer.h>
1719
#include <interfaces/dac.h>
1820

1921
#include "generic-power.h"
@@ -30,9 +32,17 @@ static power_ret_t generic_power_enable(Power *self, bool enable) {
3032

3133
power->enabled = enable;
3234
if (enable != power->enable_invert) {
33-
gpio_set(power->locm3_enable_port, power->locm3_enable_pin);
35+
if (power->timer) {
36+
timer_set_oc_value(power->timer, power->timer_oc, (uint32_t)((power->voltage_v / power->vref_v) * 255.0f));
37+
} else {
38+
gpio_set(power->locm3_enable_port, power->locm3_enable_pin);
39+
}
3440
} else {
35-
gpio_clear(power->locm3_enable_port, power->locm3_enable_pin);
41+
if (power->timer) {
42+
timer_set_oc_value(power->timer, power->timer_oc, 255 - (uint32_t)((power->voltage_v / power->vref_v) * 255.0f));
43+
} else {
44+
gpio_clear(power->locm3_enable_port, power->locm3_enable_pin);
45+
}
3646
}
3747

3848
return POWER_RET_OK;
@@ -42,6 +52,7 @@ static power_ret_t generic_power_enable(Power *self, bool enable) {
4252
static power_ret_t generic_power_set_voltage(Power *self, float voltage_v) {
4353
GenericPower *power = (GenericPower *)self->parent;
4454

55+
power->voltage_v = voltage_v;
4556
if (power->dac_p == NULL || power->vref_v == 0.0f) {
4657
/* No DAC is set, cannot set output voltage. The same applies if we don't know the reference voltage. */
4758
return POWER_RET_FAILED;
@@ -104,6 +115,35 @@ generic_power_ret_t generic_power_set_enable_gpio(GenericPower *self, uint32_t p
104115
return GENERIC_POWER_RET_OK;
105116
}
106117

118+
119+
generic_power_ret_t generic_power_set_pwm(GenericPower *self, uint32_t timer, enum tim_oc_id timer_oc) {
120+
if (!(TIM_CR1(timer) & TIM_CR1_CEN)) {
121+
/* Timer counter is not enbaled. */
122+
timer_set_mode(timer, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
123+
timer_continuous_mode(timer);
124+
timer_direction_up(timer);
125+
timer_enable_preload(timer);
126+
timer_enable_break_main_output(timer);
127+
timer_disable_preload(timer);
128+
/* Always configure for 4 MHz output */
129+
/** @todo check the computation, it should probably be more elaborate than this. */
130+
timer_set_prescaler(timer, (rcc_apb1_frequency / 4e6) - 1);
131+
timer_set_period(timer, 255);
132+
timer_enable_counter(timer);
133+
}
134+
135+
timer_enable_oc_preload(timer, timer_oc);
136+
timer_set_oc_mode(timer, timer_oc, TIM_OCM_PWM1);
137+
timer_set_oc_value(timer, timer_oc, 0);
138+
timer_enable_oc_output(timer, timer_oc);
139+
140+
self->timer = timer;
141+
self->timer_oc = timer_oc;
142+
143+
return GENERIC_POWER_RET_OK;
144+
}
145+
146+
107147
generic_power_ret_t generic_power_set_voltage_dac(GenericPower *self, Dac *dac_p, Dac *dac_m) {
108148
if (dac_p && dac_m) {
109149
u_log(system_log, LOG_TYPE_INFO, U_LOG_MODULE_PREFIX("voltage output is differential"));

services/generic-power/generic-power.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#pragma once
1010

1111
#include <main.h>
12+
#include <libopencm3/stm32/timer.h>
1213
#include <interfaces/power.h>
1314
#include <interfaces/dac.h>
1415

@@ -24,6 +25,11 @@ typedef struct generic_power {
2425
uint32_t locm3_enable_pin;
2526
bool enable_invert;
2627

28+
/* If timer is enabled (nonzero), use a timer to generate PWM
29+
* on the configured GPIO output. */
30+
uint32_t timer;
31+
enum tim_oc_id timer_oc;
32+
2733
/* Setting of the output voltage is only supported if at least one DAC device is available. In this case
2834
* a single ended output voltage is set referenced to the ground. If a second DAC device is available,
2935
* the output is considered fully differential and swings around Vref/2. It may be negative. */
@@ -43,5 +49,6 @@ generic_power_ret_t generic_power_init(GenericPower *self);
4349
generic_power_ret_t generic_power_free(GenericPower *self);
4450

4551
generic_power_ret_t generic_power_set_enable_gpio(GenericPower *self, uint32_t port, uint32_t pin, bool invert);
52+
generic_power_ret_t generic_power_set_pwm(GenericPower *self, uint32_t timer, enum tim_oc_id timer_oc);
4653
generic_power_ret_t generic_power_set_voltage_dac(GenericPower *self, Dac *dac_p, Dac *dac_m);
4754
generic_power_ret_t generic_power_set_vref(GenericPower *self, float vref_v);

0 commit comments

Comments
 (0)