diff options
| author | Otto Mattik <otto@mattik.org> | 2021-07-08 18:10:55 +0200 |
|---|---|---|
| committer | Otto Mattik <otto@mattik.org> | 2021-07-08 18:10:55 +0200 |
| commit | da34d97efb21719b2b332f8c60b2750d11bcde1f (patch) | |
| tree | 2de9fe89f6d79b8ebfcde64c5e86204e904aedf2 /avr/pwm.c | |
| download | armen-a861fb554ced7709555d2d1b639c534e3f45a83f.tar.gz armen-a861fb554ced7709555d2d1b639c534e3f45a83f.zip | |
Diffstat (limited to 'avr/pwm.c')
| -rw-r--r-- | avr/pwm.c | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/avr/pwm.c b/avr/pwm.c new file mode 100644 index 0000000..6860053 --- /dev/null +++ b/avr/pwm.c @@ -0,0 +1,223 @@ +/************************************************************************/ +/* */ +/* 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<<COM1A1)|(1<<COM1B1)|(1<<WGM10), (1<<WGM12), 2 } +#elif defined(__AVR_ATtiny85__) + { 0x002A, 0x0033, 0x0029, 0x0028, 0x0000, + (1<<COM0A1)(1<<COM0B1)|(1<<WGM01)|(1<<WGM00), 0, 1 } +#elif defined(__AVR_ATtiny841__) + { 0x004F, 0x004E, 0x004A, 0x0048, 0x0000, + (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10), (1<<WGM12), 2 }, + #if 0 + { 0x00CA, 0x00C9, 0x00C4, 0x00C2, 0x0000, + (1<<COM2A1)|(1<<COM2B1)|(1<<WGM20), (1<<WGM22), 2 } + #endif +#elif defined(__AVR_ATtiny1634__) + { 0x0072, 0x0071, 0x006C, 0x006A, 0x0000, + (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10), (1<<WGM12), 2 } +#elif defined(__AVR_ATmega328P__) + { 0x0080, 0x0081, 0x0088, 0x008A, 0x0000, + (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10), (1<<WGM12), 2 }, + { 0x00B0, 0x00B1, 0x00B3, 0x00B4, 0x0000, + (1<<COM2A1)|(1<<COM2B1)|(1<<WGM21)|(1<<WGM20), 0, 1 } +#elif defined(__AVR_ATmega2560__) + { 0x0080, 0x0081, 0x0088, 0x008A, 0x008C, + (1<<COM1A1)|(1<<COM1B1)|(1<<COM1C1)|(1<<WGM10), (1<<WGM12), 2 }, + { 0x00B0, 0x00B1, 0x00B3, 0x00B4, 0x0000, + (1<<COM2A1)|(1<<COM2B1)|(1<<WGM21)|(1<<WGM20), 0, 1 }, + { 0x0090, 0x0091, 0x0098, 0x009A, 0x009C, + (1<<COM3A1)|(1<<COM3B1)|(1<<COM3C1)|(1<<WGM30), (1<<WGM32), 2 }, + { 0x00A0, 0x00A1, 0x00A8, 0x00AB, 0x00AC, + (1<<COM4A1)|(1<<COM4B1)|(1<<COM4C1)|(1<<WGM40), (1<<WGM42), 2 }, + { 0x0120, 0x0121, 0x0128, 0x012A, 0x012C, + (1<<COM5A1)|(1<<COM5B1)|(1<<COM5C1)|(1<<WGM50), (1<<WGM52), 2 } +#endif +}; + +void gpio_pwm_freq( uint8_t scale ) +{ +#ifdef CHECK_PARAM + if( scale >= 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; + } + } +} |
