PWM works

This commit is contained in:
Edward Emelianov
2026-03-15 23:44:58 +03:00
parent 61262435a8
commit 03b05051aa
9 changed files with 292 additions and 161 deletions

View File

@@ -22,6 +22,7 @@
#include "adc.h"
#include "flash.h"
#include "gpio.h"
#include "pwm.h"
#include "usart.h"
static uint16_t monitor_mask[2] = {0}; // pins to monitor == 1 (ONLY GPIO and ADC)
@@ -80,56 +81,6 @@ static const pinprops_t pin_props[2][16] = {
#undef _S
#undef _I
#if 0
PWM (start - collisions):
PxN XY (XY: TIMX_CHY)
PA1 22 *
PA2 23 **
PA3 24 ***
PA6 161
PA7 141
PA9 12
PA10 13
PB0 33
PB1 34
PB3 22 *
PB4 31
PB5 32
PB10 23 **
PB11 24 ***
-> need to set up timers / channels
TIM1 / 2 3
TIM2 / 2 3 4
TIM3 / 1 2 3 4
TIM14 / 1
TIM16 / 1
#endif
#define PT(t, ch) {.tim = t, .chidx = ch}
#define PTC(t, ch, P, p) {.tim = t, .chidx = ch, .collision = 1, .collport = P, .collpin = p}
static const pwmtimer_t timer_map[2][16] = {
[0] = {
[1] = PTC(TIM2, 1, 1, 3),
[2] = PTC(TIM2, 2, 1, 10),
[3] = PTC(TIM2, 3, 1, 11),
[6] = PT(TIM16, 0),
[7] = PT(TIM14, 0),
[9] = PT(TIM1, 1),
[10] = PT(TIM1, 2)
},
[1] = {
[0] = PT(TIM3, 2),
[1] = PT(TIM3, 3),
[3] = PTC(TIM2, 1, 0, 1),
[4] = PT(TIM3, 0),
[5] = PT(TIM3, 1),
[10] = PTC(TIM2, 2, 0, 2),
[11] = PTC(TIM2, 3, 0, 3)
}
};
#undef PT
#undef PTC
typedef struct{
uint8_t isrx : 1;
uint8_t istx : 1;
@@ -244,6 +195,21 @@ int chkpinconf(){
if(cfg->monitor) UC.monitor = 1;
}
break;
case FUNC_PWM:{
pwmtimer_t pwm;
if(!canPWM(port, pin, &pwm)){
DBG("Can't PWM\n");
defconfig(cfg);
ret = FALSE;
break;
}
if(pwm.collision && pinconfig[pwm.collport][pwm.collpin].af == FUNC_PWM){
DBG("Found collision -> remove\n");
defconfig(&pinconfig[pwm.collport][pwm.collpin]); // set later collision to defaults
ret = FALSE;
break;
}
}
default: break; // later fill other functions
}
}
@@ -252,9 +218,11 @@ int chkpinconf(){
}
// now check USART configuration
if(active_usart != -1){
DBG("Got active USART\n");
UC.idx = active_usart;
if(!chkusartconf(&UC)) ret = FALSE;
}else{
DBG("No active USARTs\n");
get_defusartconf(&UC); // clear global configuration
the_conf.usartconfig = UC;
}
@@ -361,7 +329,7 @@ int gpio_reinit(){
gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << shift2)) | (cfg->speed << shift2);
gpio->PUPDR = (gpio->PUPDR & ~(3 << shift2)) | (cfg->pull << shift2);
if(pin < 8){
int shift4 = pin << 4;
int shift4 = pin << 2;
gpio->AFR[0] = (gpio->AFR[0] & ~(0xf << shift4)) | (cfg->afno << shift4);
}else{
int shift4 = (pin - 8) << 2;
@@ -380,6 +348,18 @@ int gpio_reinit(){
oldstates[port][pin] = (gpio->IDR >> pin) & 1;
}
}
// start/stop PWM on this pin
if(cfg->mode == MODE_AF && cfg->af == FUNC_PWM){
if(!startPWM(port, pin)) ret = FALSE;
}else{ // check for collisions
pwmtimer_t t;
if(canPWM(port, pin, &t)){
if(t.collision){ // stop PWM only if "earlier" channel don't set on this
if((t.collport < port || t.collpin < pin) && (pinconfig[t.collport][t.collpin].af != FUNC_PWM))
stopPWM(port, pin);
}else stopPWM(port, pin);
}
}
}
}
// if all OK, copy to the_conf
@@ -390,7 +370,7 @@ int gpio_reinit(){
if(get_curusartconf(&usc) && (usc.RXen | usc.TXen)){
if(!usart_config(NULL)) ret = FALSE;
else if(!usart_start()) ret = FALSE;
}
}else usart_stop();
return ret;
}
@@ -437,9 +417,15 @@ int16_t pin_in(uint8_t port, uint8_t pin){
break;
case MODE_ANALOG:{
int8_t chan = get_adc_channel(port, pin);
if(chan >= 0){
return (int16_t)getADCval(chan); // getADCval ×ÏÚ×ÒÁÝÁÅÔ uint16_t
if(chan >= 0)
val = (int16_t) getADCval(chan);
}
break;
case MODE_AF:{
pinconfig_t curconf;
if(!get_curpinconf(port, pin, &curconf)) return -1;
if(curconf.af == FUNC_PWM)
val = getPWM(port, pin);
}
break;
default:
@@ -487,16 +473,3 @@ uint16_t gpio_alert(uint8_t port){
return alert;
}
/**
* @brief canPWM - check if pin have PWM ability
* @param port - port (0/1 for GPIOA/GPIOB)
* @param pin - pin (0..15)
* @param t (o) - struct for pin's PWM timer
* @return TRUE if can, FALSE if no
*/
int canPWM(uint8_t port, uint8_t pin, pwmtimer_t *t){
if(port > 1 || pin > 15) return 0;
if(t) *t = timer_map[port][pin];
if(timer_map[port][pin].tim) return TRUE;
return FALSE;
}

View File

@@ -91,15 +91,6 @@ typedef struct{
uint16_t threshold; // threshold for ADC measurement
} pinconfig_t;
// Timers for PWM
typedef struct{
volatile TIM_TypeDef *tim; // timer
uint8_t chidx : 2; // channel index (0..3)
uint8_t collision : 1; // have collision with other channel (1)
uint8_t collport : 1; // collision port index (0 - GPIOA, 1 - GPIOB)
uint8_t collpin : 4; // collision pin index (0..15)
} pwmtimer_t;
/*
typedef struct{
uint32_t speed;
@@ -121,5 +112,3 @@ int gpio_reinit();
int pin_out(uint8_t port, uint8_t pin, uint8_t newval);
int16_t pin_in(uint8_t port, uint8_t pin);
uint16_t gpio_alert(uint8_t port);
int canPWM(uint8_t port, uint8_t pin, pwmtimer_t *t);

View File

@@ -27,6 +27,7 @@ extern "C"{
#include "flash.h"
#include "gpio.h"
#include "gpioproto.h"
#include "pwm.h"
#include "usart.h"
#undef USBIF
#define USBIF IGPIO
@@ -46,7 +47,8 @@ static uint8_t hex_input_mode = 0; // ==0 for text input, 1 for HEX + text in qu
#define COMMAND_TABLE \
COMMAND(canspeed, "CAN bus speed setter/getter (kBaud, 10..1000)") \
COMMAND(curcanspeed,"current CAN bus speed (interface speed, not settings)") \
COMMAND(dumpconf, "dump current configuration") \
COMMAND(curpinconf, "dump current (maybe wrong) pin configuration") \
COMMAND(dumpconf, "dump global configuration") \
COMMAND(eraseflash, "erase full flash storage") \
COMMAND(help, "show this help") \
COMMAND(hexinput, "input is text (0) or hex + text in quotes (1)") \
@@ -127,6 +129,7 @@ KW(AIN) \
KW(SPEED) \
KW(TEXT) \
KW(HEX) \
KW(PWM) \
enum{ // indexes of string keywords
#define KW(k) STR_ ## k,
@@ -155,6 +158,7 @@ static const Keyword keywords[] = {
KEY(USART, GROUP_FUNC, FUNC_USART)
KEY(SPI, GROUP_FUNC, FUNC_SPI)
KEY(I2C, GROUP_FUNC, FUNC_I2C)
KEY(PWM, GROUP_FUNC, FUNC_PWM)
KEY(MONITOR, GROUP_MISC, MISC_MONITOR)
KEY(THRESHOLD, GROUP_MISC, MISC_THRESHOLD)
KEY(SPEED, GROUP_MISC, MISC_SPEED)
@@ -177,10 +181,10 @@ static const char* errtxt[ERR_AMOUNT] = {
static const char *pinhelp =
"Pin settings: PXx = MODE PULL OTYPE FUNC MISC (in any sequence), where\n"
" MODE: AIN, IN or OUT (analog in, digital in, output)\n"
" MODE: AIN, IN or OUT (analog in, digital in, output), also AF (automatically set when AF selected)\n"
" PULL: PU, PD or FL (pullup, pulldown, no pull - floating)\n"
" OTYPE: PP or OD (push-pull or open-drain)\n"
" FUNC: USART or SPI (enable alternate function and configure peripheal)\n"
" FUNC: USART, SPI, I2C or PWM (enable alternate function and configure peripheal)\n"
" MISC: MONITOR - send data by USB as only state changed\n"
" THRESHOLD (ADC only) - monitoring threshold, ADU\n"
" SPEED - interface speed/frequency\n"
@@ -294,16 +298,27 @@ static void pin_getter(uint8_t port, uint8_t pin){
// `port` and `pin` are checked in `parse_pin_command`
// set GPIO values (if *setter is 0/1) or configure it
static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){
char _1st = *setter;
if(_1st == '0' || _1st == '1'){ // just set/clear pin state; throw out all text after "1"/"0"
DBG("set pin\n");
if(pin_out(port, pin, _1st - '0')) return ERR_OK;
return ERR_CANTRUN;
}
if(strncmp(setter, "help", 4) == 0){ // send PIN help
SENDn(pinhelp);
return ERR_AMOUNT;
}
pinconfig_t curconf;
if(!get_curpinconf(port, pin, &curconf)) return ERR_BADVAL; // copy current config
uint32_t U32;
char *end = getnum(setter, &U32);
if(end != setter && *end == 0){ // number -> set pin/PWM value
if(U32 > 0xff) return ERR_BADVAL;
uint8_t val = (uint8_t) U32;
if(curconf.mode == MODE_OUTPUT){ // set/clear pin
if(U32 > 1) U32 = 1;
DBG("set pin\n");
if(pin_out(port, pin, val)) return ERR_OK;
return ERR_CANTRUN;
}else if(curconf.mode == MODE_AF && curconf.af == FUNC_PWM){
if(setPWM(port, pin, val)) return ERR_OK;
return ERR_CANTRUN;
}
}
// complex setter: parse properties
uint8_t mode_set = 0xFF, pull_set = 0xFF, otype_set = 0xFF, func_set = 0xFF;
bool monitor = false;
@@ -311,14 +326,12 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){
uint32_t *pending_u32 = NULL; // -//- for uint32_t
usartconf_t UsartConf;
if(!get_curusartconf(&UsartConf)) return ERR_CANTRUN;
pinconfig_t curconf;
if(!get_curpinconf(port, pin, &curconf)) return ERR_BADVAL; // copy current config
#define DELIM_ " ,"
char *saveptr, *token = strtok_r(setter, DELIM_, &saveptr);
while(token){
if(pending_u16){
uint32_t val;
char *end = getnum(token, &val);
end = getnum(token, &val);
if(end == token || val > 0xFFFF) return ERR_BADVAL;
*pending_u16 = (uint16_t)val;
pending_u16 = NULL; // reset
@@ -327,7 +340,7 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){
}
if(pending_u32){
uint32_t val;
char *end = getnum(token, &val);
end = getnum(token, &val);
if(end == token) return ERR_BADVAL;
*pending_u32 = val;
pending_u32 = NULL;
@@ -468,31 +481,22 @@ static errcodes_t cmd_curcanspeed(const char *cmd, char _U_ *args){
return ERR_AMOUNT;
}
static errcodes_t cmd_dumpconf(const char _U_ *cmd, char _U_ *args){
SEND("userconf_sz="); SEND(u2str(the_conf.userconf_sz));
SEND("\ncurrentconfidx="); SENDn(i2str(currentconfidx));
for(int i = 0; i < InterfacesAmount; ++i){
SEND("interface"); PUTCHAR('0' + i);
PUTCHAR('=');
int l = the_conf.iIlengths[i] / 2;
char *ptr = (char*) the_conf.iInterface[i];
for(int j = 0; j < l; ++j){
PUTCHAR(*ptr);
ptr += 2;
}
NL();
}
SEND("canspeed="); SENDn(u2str(the_conf.CANspeed));
SEND("Pin configuration:\n");
// dump global pin config (current == 0) or current (==1)
static void dumppinconf(int current){
if(current) SEND("Current p");
else PUTCHAR('P');
SEND("in configuration:\n");
#define S(k) SEND(str_keywords[STR_ ## k])
#define SP(k) do{PUTCHAR(' '); S(k);}while(0)
for(int port = 0; port < 2; port++){
char port_letter = (port == 0) ? 'A' : 'B';
for(int pin = 0; pin < 16; pin++){
pinconfig_t *p = &the_conf.pinconfig[port][pin];
pinconfig_t cur, *p = &cur;
if(current && !get_curpinconf(port, pin, &cur)) continue; // local
if(!current) p = &the_conf.pinconfig[port][pin]; // global
if(!p->enable) continue;
PUTCHAR('P'); PUTCHAR(port_letter); SEND(i2str(pin)); SEND(EQ);
switch(p->mode){
#define S(k) SEND(str_keywords[STR_ ## k])
#define SP(k) do{PUTCHAR(' '); S(k);}while(0)
case MODE_INPUT:
S(IN);
if(p->pull == PULL_UP) SP(PU);
@@ -519,6 +523,7 @@ static errcodes_t cmd_dumpconf(const char _U_ *cmd, char _U_ *args){
case FUNC_USART: S(USART); break;
case FUNC_SPI: S(SPI); break;
case FUNC_I2C: S(I2C); break;
case FUNC_PWM: S(PWM); break;
default: SEND("UNKNOWN_AF");
}
break;
@@ -537,6 +542,33 @@ static errcodes_t cmd_dumpconf(const char _U_ *cmd, char _U_ *args){
NL();
}
}
#undef S
#undef SP
}
static errcodes_t cmd_curpinconf(const char _U_ *cmd, char _U_ *args){
dumppinconf(TRUE);
return ERR_AMOUNT;
}
static errcodes_t cmd_dumpconf(const char _U_ *cmd, char _U_ *args){
SEND("userconf_sz="); SEND(u2str(the_conf.userconf_sz));
SEND("\ncurrentconfidx="); SENDn(i2str(currentconfidx));
for(int i = 0; i < InterfacesAmount; ++i){
SEND("interface"); PUTCHAR('0' + i);
PUTCHAR('=');
int l = the_conf.iIlengths[i] / 2;
char *ptr = (char*) the_conf.iInterface[i];
for(int j = 0; j < l; ++j){
PUTCHAR(*ptr);
ptr += 2;
}
NL();
}
SEND("canspeed="); SENDn(u2str(the_conf.CANspeed));
dumppinconf(FALSE); // global pin config
#define S(k) SEND(str_keywords[STR_ ## k])
#define SP(k) do{PUTCHAR(' '); S(k);}while(0)
usartconf_t U = the_conf.usartconfig;
if(U.RXen || U.TXen){ // USART enabled -> tell config
S(USART); SEND(EQ);
@@ -547,44 +579,9 @@ static errcodes_t cmd_dumpconf(const char _U_ *cmd, char _U_ *args){
else if(!U.TXen && U.RXen) SEND(" RXONLY");
NL();
}
// here are usart/spi/i2c configurations
#if 0
bool usart_enabled = false;
for (int port = 0; port < 2 && !usart_enabled; port++) {
for (int pin = 0; pin < 16; pin++) {
pinconfig_t *p = &the_conf.pinconfig[port][pin];
if (p->enable && p->mode == MODE_AF && p->af == FUNC_USART) {
usart_enabled = true;
break;
}
}
}
if (usart_enabled) {
SEND("usart=");
// usart_config (baud, bits, parity, stopbits)
// e.g: SEND(u2str(usart_config.baudrate)); SEND(" ");
// SEND(i2str(usart_config.databits)); PUTCHAR(usart_config.parity); SEND(i2str(usart_config.stopbits));
NL();
}
bool spi_enabled = false;
for(int port = 0; port < 2 && !spi_enabled; port++){
for (int pin = 0; pin < 16; pin++) {
pinconfig_t *p = &the_conf.pinconfig[port][pin];
if (p->enable && p->mode == MODE_AF && p->af == FUNC_SPI) {
spi_enabled = true;
break;
}
}
}
if (spi_enabled) {
SEND("spi=");
// spi_config (speed, mode)
NL();
}
#endif
return ERR_AMOUNT;
#undef S
#undef SP
return ERR_AMOUNT;
}
static errcodes_t cmd_setiface(const char* cmd, char *args){
@@ -801,6 +798,7 @@ void GPIO_process(){
// starting init by flash settings
void GPIO_init(){
gpio_reinit();
pwm_setup();
usartconf_t usc;
if(get_curusartconf(&usc)) usart_text = usc.textproto;
}

View File

@@ -35,8 +35,8 @@ TRUE_INLINE void pins_setup(){ // setup some common GPIO
void hardware_setup(){
// enable all active GPIO clocking
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_DMA1EN;
RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_SYSCFGEN;
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM16EN;
RCC->APB1ENR |= RCC_APB1ENR_USART2EN | RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM14EN;
pins_setup();
adc_setup();
GPIO_init();

View File

@@ -16,17 +16,160 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stm32f0.h>
#include <string.h>
#include "pwm.h"
/*
* initial setup of all available PWM timers / channels:
* TIM1 / 2 3
* TIM2 / 2 3 4
* TIM3 / 1 2 3 4
* TIM14 / 1
* TIM16 / 1
*/
static volatile TIM_TypeDef * const timers[TIMERS_AMOUNT] = {
[TIM1_IDX] = TIM1,
[TIM2_IDX] = TIM2,
[TIM3_IDX] = TIM3,
[TIM14_IDX] = TIM14,
[TIM16_IDX] = TIM16,
};
#if 0
PWM (start - collisions):
PxN XY (XY: TIMX_CHY)
PA1 22 *
PA2 23 **
PA3 24 ***
PA6 161
PA7 141
PA9 12
PA10 13
PB0 33
PB1 34
PB3 22 *
PB4 31
PB5 32
PB10 23 **
PB11 24 ***
-> need to set up timers / channels
TIM1 / 2 3
TIM2 / 2 3 4
TIM3 / 1 2 3 4
TIM14 / 1
TIM16 / 1
#endif
#define PT(i, ch) {.timidx = i, .chidx = ch}
#define PTC(i, ch, P, p) {.timidx = i, .chidx = ch, .collision = 1, .collport = P, .collpin = p}
static const pwmtimer_t timer_map[2][16] = {
[0] = {
[1] = PTC(TIM2_IDX, 1, 1, 3),
[2] = PTC(TIM2_IDX, 2, 1, 10),
[3] = PTC(TIM2_IDX, 3, 1, 11),
[6] = PT(TIM16_IDX, 0),
[7] = PT(TIM14_IDX, 0),
[9] = PT(TIM1_IDX, 1),
[10] = PT(TIM1_IDX, 2)
},
[1] = {
[0] = PT(TIM3_IDX, 2),
[1] = PT(TIM3_IDX, 3),
[3] = PTC(TIM2_IDX, 1, 0, 1),
[4] = PT(TIM3_IDX, 0),
[5] = PT(TIM3_IDX, 1),
[10] = PTC(TIM2_IDX, 2, 0, 2),
[11] = PTC(TIM2_IDX, 3, 0, 3)
}
};
#undef PT
#undef PTC
// counter of used channels (0 - timer OFF)
static uint8_t channel_counter[TIMERS_AMOUNT] = {0};
void pwm_setup(){
;
// setup; start/stop only by user request
for(int i = 1; i < TIMERS_AMOUNT; ++i){ // start from 1 as 0 forbidden
volatile TIM_TypeDef *timer = timers[i];
timer->CR1 = 0;
timer->PSC = 7; // 6MHz for 23.4kHz PWM
timer->ARR = 254; // 255 == 100%
// PWM mode 1, preload enable
timer->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE |
TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2PE;
timer->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3PE |
TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4PE;
timer->BDTR |= TIM_BDTR_MOE; // enable main output (need for some timers)
timer->EGR |= TIM_EGR_UG; // force update generation
}
bzero(channel_counter, sizeof(channel_counter));
}
/**
* @brief canPWM - check if pin have PWM ability
* @param port - port (0/1 for GPIOA/GPIOB)
* @param pin - pin (0..15)
* @param t (o) - struct for pin's PWM timer
* @return TRUE if can, FALSE if no
*/
int canPWM(uint8_t port, uint8_t pin, pwmtimer_t *t){
if(port > 1 || pin > 15) return 0;
if(t) *t = timer_map[port][pin];
if(timer_map[port][pin].timidx == TIM_UNSUPPORTED) return FALSE;
return TRUE;
}
/**
* @brief startPWM - run PWM on given port/pin
* @param port
* @param pin
* @return FALSE if unsupported
*/
int startPWM(uint8_t port, uint8_t pin){
timidx_t idx = timer_map[port][pin].timidx;
if(idx == TIM_UNSUPPORTED) return FALSE;
volatile TIM_TypeDef *timer = timers[idx];
uint8_t chidx = timer_map[port][pin].chidx;
uint32_t chen = TIM_CCER_CC1E << (chidx<<2);
if(0 == (timer->CCER & chen)){
if(0 == channel_counter[idx]++) timer->CR1 |= TIM_CR1_CEN; // start timer if need
timer->CCER |= chen; // enable channel
}
return TRUE;
}
// stop given PWM channel and stop timer if there's no used channels
void stopPWM(uint8_t port, uint8_t pin){
timidx_t idx = timer_map[port][pin].timidx;
if(idx == TIM_UNSUPPORTED) return;
volatile TIM_TypeDef *timer = timers[idx];
uint8_t chidx = timer_map[port][pin].chidx;
uint32_t chen = TIM_CCER_CC1E << (chidx<<2);
if(timer->CCER & chen){
if(0 == --channel_counter[idx]) timer->CR1 &= ~TIM_CR1_CEN; // stop timer
timer->CCER &= ~chen;
}
}
/**
* @brief setPWM - set PWM value for given pin on given port
* @param port
* @param pin
* @param val - 0..255
* @return FALSE if pin can't PWM
*/
int setPWM(uint8_t port, uint8_t pin, uint8_t val){
timidx_t idx = timer_map[port][pin].timidx;
if(idx == TIM_UNSUPPORTED) return FALSE;
volatile uint32_t *CCR = &timers[idx]->CCR1 + timer_map[port][pin].chidx;
*CCR = val;
return TRUE;
}
/**
* @brief getPWM - get PWM value for given pin on given port
* @param port
* @param pin
* @return -1 if there's no PWM on that pin
*/
int16_t getPWM(uint8_t port, uint8_t pin){
timidx_t idx = timer_map[port][pin].timidx;
if(idx == TIM_UNSUPPORTED) return -1;
volatile uint32_t *CCR = &timers[idx]->CCR1 + timer_map[port][pin].chidx;
return (int16_t) *CCR;
}

View File

@@ -18,4 +18,32 @@
#pragma once
#include <stdint.h>
// used timers
typedef enum{
TIM_UNSUPPORTED = 0,
TIM1_IDX,
TIM2_IDX,
TIM3_IDX,
TIM14_IDX,
TIM16_IDX,
TIMERS_AMOUNT
}timidx_t;
// Timers for PWM
typedef struct{
timidx_t timidx : 3; // timer index from array of timers used
uint8_t chidx : 2; // channel index (0..3)
uint8_t collision : 1; // have collision with other channel (1)
uint8_t collport : 1; // collision port index (0 - GPIOA, 1 - GPIOB)
uint8_t collpin : 4; // collision pin index (0..15)
} pwmtimer_t;
void pwm_setup();
int canPWM(uint8_t port, uint8_t pin, pwmtimer_t *t);
int startPWM(uint8_t port, uint8_t pin);
void stopPWM(uint8_t port, uint8_t pin);
int setPWM(uint8_t port, uint8_t pin, uint8_t val);
int16_t getPWM(uint8_t port, uint8_t pin);

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 18.0.2, 2026-03-15T02:24:04. -->
<!-- Written by QtCreator 18.0.2, 2026-03-15T23:41:05. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>

View File

@@ -1,2 +1,2 @@
#define BUILD_NUMBER "192"
#define BUILD_NUMBER "207"
#define BUILD_DATE "2026-03-15"