static void pwm_bcm2836_config(struct pwm_t * pwm, int duty, int period, int polarity) { struct pwm_bcm2836_pdata_t * pdat = (struct pwm_bcm2836_pdata_t *)pwm->priv; unsigned long scaler = (unsigned long)(1000000000ULL / clk_get_rate(pdat->clk)); u32_t ctrl; if(pwm->__duty != duty) { write32(pdat->virt + PWM_DUTY(pdat->channel), duty / scaler); } if(pwm->__period != period) { write32(pdat->virt + PWM_PERIOD(pdat->channel), period /scaler); } if(pwm->__polarity != polarity) { ctrl = read32(pdat->virt + PWM_CTRL); if(polarity) ctrl |= (0x10 << PWM_CTRL_SHIFT(pdat->channel)); else ctrl &= ~(0x10 << PWM_CTRL_SHIFT(pdat->channel)); write32(pdat->virt + PWM_CTRL, ctrl); } }
static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip); unsigned long long c; int period_cycles, duty_cycles; u32 val; c = clk_get_rate(lpc32xx->clk) / 256; c = c * period_ns; do_div(c, NSEC_PER_SEC); /* Handle high and low extremes */ if (c == 0) c = 1; if (c > 255) c = 0; /* 0 set division by 256 */ period_cycles = c; /* The duty-cycle value is as follows: * * DUTY-CYCLE HIGH LEVEL * 1 99.9% * 25 90.0% * 128 50.0% * 220 10.0% * 255 0.1% * 0 0.0% * * In other words, the register value is duty-cycle % 256 with * duty-cycle in the range 1-256. */ c = 256 * duty_ns; do_div(c, period_ns); if (c > 255) c = 255; duty_cycles = 256 - c; val = readl(lpc32xx->base + (pwm->hwpwm << 2)); val &= ~0xFFFF; val |= PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles); writel(val, lpc32xx->base + (pwm->hwpwm << 2)); return 0; }
void analogWrite(uint8_t pin, int val) { pinMode(pin, OUTPUT); // pin as output if (val == 0) { digitalWrite(pin, LOW); // set pin to LOW when duty cycle is 0 // digitalWrite will take care of invalid pins } else if (val == 255) { digitalWrite(pin, HIGH); // set pin HIGH when duty cycle is 255 // digitalWrite will take care of invalid pins } else { uint8_t bit = digitalPinToBitMask(pin); // get pin bit uint8_t port = digitalPinToPort(pin); // get pin port volatile uint16_t *sel; volatile uint16_t *sel2; if (port == NOT_A_PORT) return; // pin on timer? sel = portSelRegister(port); // get the port function select register address *sel |= bit; // set bit in pin function select register //TODO: Firgure out a better way to determine if SEL2 needs to be set if(bit == BV(4) && port == P1) { sel2 = portSel2Register(port); // get the port function select register address *sel2 |= bit; } switch(digitalPinToTimer(pin)) { // which timer and CCR? //case: T0A0 // CCR0 used as period register case T0A1: // Timer0 / CCR1 TA0CCR0 = PWM_PERIOD; // PWM Period TA0CCTL1 = OUTMOD_7; // reset/set TA0CCR1 = PWM_DUTY(val); // PWM duty cycle TA0CTL = TASSEL_2 + MC_1 + analog_div; // SMCLK, up mode break; #if defined(__MSP430_HAS_TA3__) case T0A2: // Timer0 / CCR1 TA0CCR0 = PWM_PERIOD; // PWM Period TA0CCTL2 = OUTMOD_7; // reset/set TA0CCR2 = PWM_DUTY(val); // PWM duty cycle TA0CTL = TASSEL_2 + MC_1+ analog_div; // SMCLK, up mode break; #endif #if defined(__MSP430_HAS_T1A3__) //case: T1A0 // CCR0 used as period register case T1A1: // Timer0 / CCR1 TA1CCR0 = PWM_PERIOD; // PWM Period TA1CCTL1 = OUTMOD_7; // reset/set TA1CCR1 = PWM_DUTY(val); // PWM duty cycle TA1CTL = TASSEL_2 + MC_1+ analog_div; // SMCLK, up mode break; case T1A2: // Timer0 / CCR1 TA1CCR0 = PWM_PERIOD; // PWM Period TA1CCTL2 = OUTMOD_7; // reset/set TA1CCR2 = PWM_DUTY(val); // PWM duty cycle TA1CTL = TASSEL_2 + MC_1+ analog_div; // SMCLK, up mode break; #endif #if defined(__MSP430_HAS_T2A3__) //case: T2A0 // CCR0 used as period register case T2A1: // Timer0 / CCR1 TA2CCR0 = PWM_PERIOD; // PWM Period TA2CCTL1 = OUTMOD_7; // reset/set TA2CCR1 = PWM_DUTY(val); // PWM duty cycle TA2CTL = TASSEL_2 + MC_1+ analog_div; // SMCLK, up mode break; case T2A2: // Timer0 / CCR1 TA2CCR0 = PWM_PERIOD; // PWM Period TA2CCTL2 = OUTMOD_7; // reset/set TA2CCR2 = PWM_DUTY(val); // PWM duty cycle TA2CTL = TASSEL_2 + MC_1+ analog_div; // SMCLK, up mode break; #endif case NOT_ON_TIMER: // not on a timer output pin default: // or TxA0 pin if (val < 128) { digitalWrite(pin, LOW); // } else { digitalWrite(pin, HIGH); } } } }
/** * analogWrite * * set PWM output level * * @param pin pin number * @param val duty cycle */ void analogWrite(uint8_t pin, uint16_t val) { if (val == 0) { pinMode(pin, OUTPUT); digitalWrite(pin, LOW); } else { uint8_t bit = digitalPinToBitMask(pin); uint8_t port = digitalPinToPort(pin); volatile uint8_t *dir = portDirRegister(port); volatile uint8_t *sel = portSelRegister(port); volatile uint8_t *map = digitalPinToPortMap(pin); *dir |= bit; // Config pin as an output *sel |= bit; // Select alternate function // Set PWM period TA0CCR0 = analogPeriod; TA1CCR0 = analogPeriod; uint8_t timer = digitalPinToTimer(pin); PMAPPWD = 0x02D52; // Get write-access to port mapping regs PMAPCTL |= PMAPRECFG; // Leave Pin mapping open switch(timer) { case T0A1: *map = PM_TA0CCR1A; TA0CCTL1 = OUTMOD_7; // CCR1 reset/set TA0CCR1 = PWM_DUTY(val); // CCR1 PWM duty cycle break; case T0A2: *map = PM_TA0CCR2A; TA0CCTL2 = OUTMOD_7; // CCR1 reset/set TA0CCR2 = PWM_DUTY(val); // CCR1 PWM duty cycle break; case T0A3: *map = PM_TA0CCR3A; TA0CCTL3 = OUTMOD_7; // CCR1 reset/set TA0CCR3 = PWM_DUTY(val); // CCR1 PWM duty cycle break; case T0A4: *map = PM_TA0CCR4A; TA0CCTL4 = OUTMOD_7; // CCR1 reset/set TA0CCR4 = PWM_DUTY(val); // CCR1 PWM duty cycle break; case T1A1: *map = PM_TA1CCR1A; TA1CCTL1 = OUTMOD_7; // CCR1 reset/set TA1CCR1 = PWM_DUTY(val); // CCR1 PWM duty cycle break; case T1A2: *map = PM_TA1CCR2A; TA1CCTL2 = OUTMOD_7; // CCR1 reset/set TA1CCR2 = PWM_DUTY(val); // CCR1 PWM duty cycle break; default: break; } PMAPPWD = 0; // Lock port mapping registers if (timer < T1A1) { if (val == TA0CCR0) // duty cycle = period? { pinMode(pin, OUTPUT); digitalWrite(pin, HIGH); } else TA0CTL = TASSEL_2 + MC_1 + TACLR; // SMCLK, up mode, clear TAR } else { if (val == TA1CCR0) // duty cycle = period? { pinMode(pin, OUTPUT); digitalWrite(pin, HIGH); } else TA1CTL = TASSEL_2 + MC_1 + TACLR; // SMCLK, up mode, clear TAR } } }