예제 #1
0
파일: pwm.c 프로젝트: AdamRLukaitis/RIOT
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;
}
예제 #2
0
파일: pwm.c 프로젝트: JiapengLi/RIOT
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;
}