static boolean initPWM(const IOPin* pin, uint32_t deciHertz){ const TimerCompare* channel = compareFromIOPin(pin); if(channel==null){ setError(PWM_PIN_NOT_AVAILABLE); return FALSE; } if(compareIsInUse(channel)){ setError(PWM_PIN_IN_USE); return FALSE; } TIMER_MODE mode; uint16_t icr; uint16_t prescaler; const Timer* timer = compareGetTimer(channel); // Find the best PWM setting for 10kHz, with 128 steps boolean valid = timerCalcPwm(timer, deciHertz, 128, &mode, &icr, &prescaler); if(!valid){ // There is no PWM setting that is valid setError( (timerIsInUse(timer)) ? PWM_TIMER_IN_USE : TIMER_HAS_NO_PWM ); }else{ // Lets set up the PWM if(!timerIsInUse(timer)){ timerSetMode(timer,mode); if(modeIsICR(mode)){ // Set the ICR PORT icrPort = pgm_read_word(&timer->pgm_icr); _SFR_MEM16(icrPort)=icr; } } // Make it an output pin and set high for brake pin_make_output(pin,TRUE); // Use inverting PWM compareSetOutputMode(channel,CHANNEL_MODE_INVERTING); // Mark the channels as in use compareAttach(channel,&nullTimerCompareCallback,0,null); // Do this last as it then turns on the timer timerSetPrescaler(timer,prescaler); } return valid; }
// Set up PWM on the given pin boolean pwmInitDeciHertz(const IOPin* pin, uint32_t deciHertz, DUTY_CYCLE duty, uint32_t* actualDeciHertz){ boolean rtn = FALSE; const TimerCompare* channel = compareFromIOPin(pin); if(channel==null){ setError(PWM_PIN_NOT_AVAILABLE); }else{ // The pin is valid if(compareIsInUse(channel)){ setError(PWM_PIN_IN_USE); }else{ // The pin is valid and available TIMER_MODE mode; uint16_t icr; uint16_t prescaler; const Timer* timer = compareGetTimer(channel); // Find the best PWM setting boolean valid = timerCalcPwm(timer, deciHertz, 100, &mode, &icr, &prescaler); if(!valid){ // There is no PWM setting that is valid setError( (timerIsInUse(timer)) ? PWM_TIMER_IN_USE : TIMER_HAS_NO_PWM ); }else{ // Lets set up the PWM if(!timerIsInUse(timer)){ timerSetMode(timer,mode); if(modeIsICR(mode)){ // Set the ICR PORT icrPort = pgm_read_word(&timer->pgm_icr); _SFR_MEM16(icrPort)=icr; } }else{ // Can't change the prescaler so just use the existing prescaler = timerGetPrescaler(timer); } // Mark the channel as in use compareAttach(channel,&nullTimerCompareCallback,0,null); // Turn the pin into an output, low pin_make_output(pin, FALSE); // Turn on the PWM pin output compareSetOutputMode(channel, CHANNEL_MODE_NON_INVERTING); // Turn on the timer timerSetPrescaler(timer,prescaler); // Set the initial duty cycle pwmSetDutyCycle(pin,duty); // Set the return value if(actualDeciHertz){ *actualDeciHertz = TimerGetPwmDeciHertz(timer); } rtn = TRUE; } } } return rtn; }