Beispiel #1
0
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)));
}
Beispiel #2
0
/**
 * @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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}