uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res) { uint32_t bus_clk = periph_apb_clk(pwm_config[pwm].bus); /* verify parameters */ assert((pwm < PWM_NUMOF) && ((freq * res) < bus_clk)); /* power on the used timer */ pwm_poweron(pwm); /* reset configuration and CC channels */ dev(pwm)->CR1 = 0; dev(pwm)->CR2 = 0; for (int i = 0; i < TIMER_CHAN; i++) { dev(pwm)->CCR[i] = 0; } /* configure the used pins */ unsigned i = 0; while ((i < TIMER_CHAN) && (pwm_config[pwm].chan[i].pin != GPIO_UNDEF)) { gpio_init(pwm_config[pwm].chan[i].pin, GPIO_OUT); gpio_init_af(pwm_config[pwm].chan[i].pin, pwm_config[pwm].af); i++; } /* configure the PWM frequency and resolution by setting the auto-reload * and prescaler registers */ dev(pwm)->PSC = (bus_clk / (res * freq)) - 1; dev(pwm)->ARR = res - 1; /* set PWM mode */ switch (mode) { case PWM_LEFT: dev(pwm)->CCMR1 = CCMR_LEFT; dev(pwm)->CCMR2 = CCMR_LEFT; break; case PWM_RIGHT: dev(pwm)->CCMR1 = CCMR_RIGHT; dev(pwm)->CCMR2 = CCMR_RIGHT; break; case PWM_CENTER: dev(pwm)->CCMR1 = 0; dev(pwm)->CCMR2 = 0; dev(pwm)->CR1 |= (TIM_CR1_CMS_0 | TIM_CR1_CMS_1); break; } /* enable PWM outputs and start PWM generation */ #ifdef TIM_BDTR_MOE dev(pwm)->BDTR = TIM_BDTR_MOE; #endif dev(pwm)->CCER = (TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC4E); dev(pwm)->CR1 |= TIM_CR1_CEN; /* return the actual used PWM frequency */ return (bus_clk / (res * (dev(pwm)->PSC + 1))); }
/** * @note The PWM is always initialized with left-aligned mode. * * TODO: add center and right aligned modes */ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) { (void) mode; /* unused */ switch (dev) { #if PWM_0_EN case PWM_0: /* select function PWM[3] for pins */ PWM_0_PORT &= ~((3 << PWM_0_CH0_PIN * 2) | (3 << PWM_0_CH1_PIN * 2) | (3 << PWM_0_CH2_PIN * 2)); PWM_0_PORT |= (PWM_0_FUNC << PWM_0_CH0_PIN * 2) | (PWM_0_FUNC << PWM_0_CH1_PIN * 2) | (PWM_0_FUNC << PWM_0_CH2_PIN * 2); /* power on PWM1 */ pwm_poweron(dev); /* select PWM1 clock */ PCLKSEL0 &= ~(BIT13); PCLKSEL0 |= (BIT12); /* reset PWM1s counter */ PWM1TCR = BIT1; /* set prescaler */ PWM1PR = (CLOCK_CORECLOCK / (freq * res)) - 1; /* set match register */ PWM1MR0 = res; PWM_0_CH0_MR = 0; PWM_0_CH1_MR = 0; PWM_0_CH2_MR = 0; /* reset timer counter on MR0 match */ PWM1MCR = BIT1; /* enable PWM1 channel 3, 4 and 5 */ PWM1PCR = (1 << (8 + PWM_0_CH0)) | (1 << (8 + PWM_0_CH1)) | (1 << (8 + PWM_0_CH2)); /* enable PWM1 timer in PWM mode */ PWM1TCR = BIT0 + BIT3; /* update match registers */ PWM1LER = BIT0 | (1 << PWM_0_CH0) | (1 << PWM_0_CH1) | (1 << PWM_0_CH2); break; #endif default: return 0; } return freq; }
uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) { TIM_TypeDef *tim = NULL; GPIO_TypeDef *port = NULL; uint32_t pins[PWM_MAX_CHANNELS]; uint32_t af; int channels; uint32_t pwm_clk; pwm_poweron(dev); switch (dev) { #if PWM_0_EN case PWM_0: tim = PWM_0_DEV; port = PWM_0_PORT; pins[0] = PWM_0_PIN_CH0; pins[1] = PWM_0_PIN_CH1; pins[2] = PWM_0_PIN_CH2; pins[3] = PWM_0_PIN_CH3; af = PWM_0_PIN_AF; channels = PWM_0_CHANNELS; pwm_clk = PWM_0_CLK; PWM_0_PORT_CLKEN(); break; #endif #if PWM_1_EN case PWM_1: tim = PWM_1_DEV; port = PWM_1_PORT; pins[0] = PWM_1_PIN_CH0; pins[1] = PWM_1_PIN_CH1; pins[2] = PWM_1_PIN_CH2; pins[3] = PWM_1_PIN_CH3; af = PWM_1_PIN_AF; channels = PWM_1_CHANNELS; pwm_clk = PWM_1_CLK; PWM_1_PORT_CLKEN(); break; #endif default: pwm_poweroff(dev); return 0; } /* setup pins: alternate function */ for (int i = 0; i < channels; i++) { port->MODER &= ~(3 << (pins[i] * 2)); port->MODER |= (2 << (pins[i] * 2)); if (pins[i] < 8) { port->AFR[0] &= ~(0xf << (pins[i] * 4)); port->AFR[0] |= (af << (pins[i] * 4)); } else { port->AFR[1] &= ~(0xf << ((pins[i] - 8) * 4)); port->AFR[1] |= (af << ((pins[i] - 8) * 4)); } } /* reset timer configuration registers */ tim->CR1 = 0; tim->CR2 = 0; tim->CCMR1 = 0; tim->CCMR2 = 0; /* set prescale and auto-reload registers to matching values for resolution and frequency */ if ((res > 0xffff) || ((res * freq) > pwm_clk)) { return 0; } tim->PSC = (pwm_clk / (res * freq)) - 1; tim->ARR = res - 1; freq = (pwm_clk / (res * (tim->PSC + 1))); /* set PWM mode */ switch (mode) { case PWM_LEFT: tim->CCMR1 |= (TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2); tim->CCMR2 |= (TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2); break; case PWM_RIGHT: tim->CCMR1 |= (TIM_CCMR1_OC1M_0 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC2M_0 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2); tim->CCMR2 |= (TIM_CCMR2_OC3M_0 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC4M_0 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2); break; case PWM_CENTER: tim->CR1 |= (TIM_CR1_CMS_0 | TIM_CR1_CMS_1); break; } /* enable output on PWM pins */ tim->CCER |= (TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC4E); /* enable PWM generation */ pwm_start(dev); return freq; }
int pwm_init(pwm_t dev, pwm_mode_t mode, unsigned int frequency, unsigned int resolution) { FTM_Type *tim = NULL; PORT_Type *port[PWM_MAX_CHANNELS]; /* cppcheck-suppress unassignedVariable */ uint8_t pins[PWM_MAX_CHANNELS]; uint8_t af[PWM_MAX_CHANNELS]; /* cppcheck-suppress unassignedVariable */ uint8_t ftmchan[PWM_MAX_CHANNELS]; int channels = 0; uint32_t pwm_clk = 0; pwm_poweron(dev); switch (dev) { #if PWM_0_EN case PWM_0: tim = PWM_0_DEV; port[0] = PWM_0_PORT_CH0; port[1] = PWM_0_PORT_CH1; port[2] = PWM_0_PORT_CH2; port[3] = PWM_0_PORT_CH3; pins[0] = PWM_0_PIN_CH0; pins[1] = PWM_0_PIN_CH1; pins[2] = PWM_0_PIN_CH2; pins[3] = PWM_0_PIN_CH3; ftmchan[0] = PWM_0_FTMCHAN_CH0; ftmchan[1] = PWM_0_FTMCHAN_CH1; ftmchan[2] = PWM_0_FTMCHAN_CH2; ftmchan[3] = PWM_0_FTMCHAN_CH3; af[0] = PWM_0_PIN_AF_CH0; af[1] = PWM_0_PIN_AF_CH1; af[2] = PWM_0_PIN_AF_CH2; af[3] = PWM_0_PIN_AF_CH3; channels = PWM_0_CHANNELS; pwm_clk = PWM_0_CLK; PWM_0_PORT_CLKEN(); break; #endif default: return -1; } if (channels > PWM_MAX_CHANNELS) { return -1; } /* cppcheck-suppress nullPointer */ tim->MODE = (1 << FTM_MODE_WPDIS_SHIFT); /* setup pins, reset timer match value */ for (int i = 0; i < channels; i++) { port[i]->PCR[pins[i]] = PORT_PCR_MUX(af[i]); /* cppcheck-suppress nullPointer */ tim->CONTROLS[i].CnV = 0; } /* reset timer configuration registers */ /* cppcheck-suppress nullPointer */ tim->COMBINE = 0; /* set prescale and mod registers to matching values for resolution and frequency */ if (resolution > 0xffff || (resolution * frequency) > pwm_clk) { return -2; } /* cppcheck-suppress nullPointer */ tim->SC = FTM_SC_PS((pwm_clk / (resolution * frequency)) - 1); /* cppcheck-suppress nullPointer */ tim->MOD = resolution; /* set PWM mode */ switch (mode) { case PWM_LEFT: for (int i = 0; i < channels; i++) { /* cppcheck-suppress nullPointer */ tim->CONTROLS[ftmchan[i]].CnSC = (1 << FTM_CnSC_MSB_SHIFT | 1 << FTM_CnSC_ELSB_SHIFT); } break; case PWM_RIGHT: for (int i = 0; i < channels; i++) { /* cppcheck-suppress nullPointer */ tim->CONTROLS[ftmchan[i]].CnSC = (1 << FTM_CnSC_MSB_SHIFT | 1 << FTM_CnSC_ELSA_SHIFT); } break; case PWM_CENTER: for (int i = 0; i < channels; i++) { /* cppcheck-suppress nullPointer */ tim->CONTROLS[ftmchan[i]].CnSC = (1 << FTM_CnSC_MSB_SHIFT); } /* cppcheck-suppress nullPointer */ tim->SC |= (1 << FTM_SC_CPWMS_SHIFT); break; } /* enable timer ergo the PWM generation */ pwm_start(dev); return 0; }