+ static PwmHardware pwm_channels[] =
+ {
+ {//PWM Channel 0
+ .pwm_pin = BV(PWM0),
+ .base = (volatile PwmChannelRegs *)&PWM_CMR0,
+ },
+ {//PWM Channel 1
+ .pwm_pin = BV(PWM1),
+ .base = (volatile PwmChannelRegs *)&PWM_CMR1,
+ },
+ {//PWM Channel 2
+ .pwm_pin = BV(PWM2),
+ .base = (volatile PwmChannelRegs *)&PWM_CMR2,
+ },
+ {//PWM Channel 3
+ .pwm_pin = BV(PWM3),
+ .base = (volatile PwmChannelRegs *)&PWM_CMR3,
+ },
+ };
+
+ /*
+ * Init pwm.
+ */
+ void pwm_hw_init(Pwm *ctx, unsigned ch)
+ {
+
+ ctx->hw = &pwm_channels[ch];
+
+ /*
+ * Init pwm:
+ * - clear PIO outputs
+ * - enable PIO outputs
+ * - Enable PWM functions
+ * - Power on PWM
+ */
+ PWM_PIO_CODR = ctx->hw->pwm_pin;
+ PWM_PIO_OER = ctx->hw->pwm_pin;
+ PWM_PIO_PER = ctx->hw->pwm_pin;
+ PWM_PIO_ABSR = ctx->hw->pwm_pin;
+
+ PMC_PCER |= BV(PWMC_ID);
+
+ /* Disable prescalers A and B */
+ PWM_MR = 0;
+
+ /*
+ * Set pwm mode:
+ * WARNING: is forbidden to write 0 or 1 to duty cycle value,
+ * and so for start we set duty to 2.
+ * Also:
+ * - set period aligned to left
+ * - set output waveform to start at high level
+ * - allow duty cycle modify at next period event
+ */
+ ctx->hw->base->CDTY = 2;
+ ctx->hw->base->CMR = BV(PWM_CPOL);
+ PWM_ENA = BV(ch);
+ }