/************************************************************************/ /* */ /* File: avr/pwm.c */ /* Description: pulse width modulation driver. */ /* Version: 1.0 */ /* Author: Otto Mattik */ /* */ /* (C)Copyright Otto Mattik 2014-2021. */ /* */ /* This file is a part of 'armen' (a tiny operating system). */ /* 'armen' is distributed under the CeCILL-V2.1 licence. For more */ /* details about this licence, please visit the website cecill.info */ /* */ /************************************************************************/ #ifndef AVR_GPIO_C #error "do not use this code directly, it must be included via gpio.c" #endif #if defined(__AVR_ATtiny84__)\ || defined(__AVR_ATtiny85__) #if defined(UART) && (UART != 0) #error "pwm and uart, used together, are incompatible" #endif #endif #if defined(__AVR_ATtiny84__) #define GPIO_MAX_PWM 1 #elif defined(__AVR_ATtiny841__) #define GPIO_MAX_PWM 2 #elif defined(__AVR_ATtiny85__) #define GPIO_MAX_PWM 1 #elif defined(__AVR_ATtiny1634__) #define GPIO_MAX_PWM 1 #elif defined(__AVR_ATmega328P__) #define GPIO_MAX_PWM 2 #elif defined(__AVR_ATmega2560__) #define GPIO_MAX_PWM 5 #endif /* __AVR_ATtiny84__ t1, 16 bits, OC1A=PA6/6, OC1B=PA5/5 __AVR_ATtiny85__ t1, 8 bits, OC1A=PB1/1, OC1B=PB4/4 __AVR_ATtiny841__ t1, 16 bits, OC1A=TOCC1|TOCC3|TOCC5|TOCC7, OC1B=TOCC0|TOCC2|TOCC4|TOCC6 t2, 16 bits, OC2A=TOCC1|TOCC3|TOCC5|TOCC7, OC2B=TOCC0|TOCC2|TOCC4|TOCC6 __AVR_ATtiny1634__ t1, 16 bits, OC1A=PC0/16, OC1B=PB3/11 __AVR_ATmega328P__ t1, 16 bits, OC1A=PB1/1, OC1B=PB2/2 t2, 8 bits, OC2A=PB3/3, OC2B=PD3/19 __AVR_ATmega2560__ t1, 16 bits, OC1A=PB5/13, OC1B=PB6/14, 0C1C=PB7/15 t2, 8 bits, OC2A=PB4/12, OC2B=PH6/62 t3, 16 bits, OC3A=PE3/35, OC3B=PE4/36, OC3C=PE5/37 t4, 16 bits, OC4A=PH3/59, OC4B=PH4/60, OC4C=PH5/61 t5, 16 bits, OC5A=PL3/83, OC5B=PL4/84, OC5C=PL5/85 */ static uint8_t pwm_freq = 0; static struct { uint8_t* tccra; uint8_t* tccrb; uint8_t* ocra; uint8_t* ocrb; uint8_t* ocrc; uint8_t modea; uint8_t modeb; uint8_t bytes; } pwms[GPIO_MAX_PWM] = { #if defined(__AVR_ATtiny84__) { 0x004F, 0x004E, 0x004A, 0x0048, 0x0000, (1<= 1 && scale <= 5 ) #endif { uint8_t i; /* set fast pwm (8 bits) mode with OCnA and 0CnB cleared on compare match */ for( i = 0; i < GPIO_MAX_PWM; i++ ) { *pwms[i].tccra = pwms[i].modea; #if defined(__AVR_ATmega328P__)\ || defined(__AVR_ATmega2560__) if( i == 1 && scale > 2 ) { uint8_t value; if( scale == 3 ) value = 4; else if( scale == 4 ) value = 6; else value = 7; *pwms[i].tccrb = pwms[i].modeb | value; else #endif *pwms[i].tccrb = pwms[i].modeb | scale; *pwms[i].ocra = 0; *pwms[i].ocrb = 0; if( pwms[i].ocrc != 0 ) *pwms[i].ocrc = 0; } } } void gpio_pwm_set( uint8_t gpio, uint8_t percent ) { #ifdef CHECK_PARAM if( gpio < (GPIO_MAX_PORT << 3) ) #endif { uint8_t timer = 0; #if defined(__AVR_ATtiny84__) if( gpio == 6 || gpio == 5 ) { gpio = 6 - gpio; #elif defined(__AVR_ATtiny85__) if( gpio == 1 || gpio == 4 ) { gpio = (gpio == 1 ? 0 : 1); #elif defined(__AVR_ATtiny841__) if( gpio <= 7 ) { /* OC1A=TOCC1|TOCC3|TOCC5|TOCC7 OC1B=TOCC0|TOCC2|TOCC4|TOCC6 */ if( gpio <= 3 ) TOCPMSA0 |= (01 << (gpio << 2)); else TOCPMSA1 |= (01 << ((gpio - 4) << 2)); TOCPMCOE |= (1 << gpio); gpio = ((gpio & 1) == 1 ? 0 : 1); #elif defined(__AVR_ATtiny1634__) if( gpio == 16 || gpio == 11 ) { gpio = (gpio == 16 ? 0 : 1); #elif defined(__AVR_ATmega328P__) if( gpio == 1 || gpio == 2 ) gpio -= 1; else if( gpio == 3 || gpio == 19 ) { gpio = (gpio == 3 ? 0 : 1); timer = 1; } else return; { #elif defined(__AVR_ATmega2560__) if( gpio >= 13 || gpio <= 15 ) gpio -= 13; else if( gpio == 12 || gpio == 62 ) { gpio = (gpio == 12 ? 0 : 1); timer = 1; } else if( gpio >= 35 && gpio <= 37 ) { gpio -= 35; timer = 2; } else if( gpio >= 59 && gpio <= 61 ) { gpio -= 59; timer = 3; } else if( gpio >= 83 && gpio <= 85 ) { gpio -= 83; timer = 4; } else return; { #endif percent = (255 * percent) / 100; if( gpio == 0 ) *pwms[timer].ocra = percent; #if defined(__AVR_ATmega2560__) else if( gpio == 2 ) *pwms[timer].ocrc = percent; #endif else *pwms[timer].ocrb = percent; } } }