aboutsummaryrefslogtreecommitdiff
path: root/avr/pwm.c
diff options
context:
space:
mode:
authorOtto Mattik <otto@mattik.org>2021-07-08 18:10:55 +0200
committerOtto Mattik <otto@mattik.org>2021-07-08 18:10:55 +0200
commitda34d97efb21719b2b332f8c60b2750d11bcde1f (patch)
tree2de9fe89f6d79b8ebfcde64c5e86204e904aedf2 /avr/pwm.c
downloadarmen-da34d97efb21719b2b332f8c60b2750d11bcde1f.tar.gz
armen-da34d97efb21719b2b332f8c60b2750d11bcde1f.zip
git: update to v1.0HEADv1.0master
Diffstat (limited to 'avr/pwm.c')
-rw-r--r--avr/pwm.c223
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;
+ }
+ }
+}