From bf92ffb5bff9eedb36df697397b9a6ae27bc168e Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Tue, 20 Nov 2018 11:39:42 -0500 Subject: avr: Split gpio.c into gpio.c, adc.c, hard_pwm.c, and spi.c Split up gpio.c into multiple files in an effort to make the code a little more understandable. Signed-off-by: Kevin O'Connor --- src/avr/hard_pwm.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 src/avr/hard_pwm.c (limited to 'src/avr/hard_pwm.c') diff --git a/src/avr/hard_pwm.c b/src/avr/hard_pwm.c new file mode 100644 index 00000000..3348a664 --- /dev/null +++ b/src/avr/hard_pwm.c @@ -0,0 +1,154 @@ +// Hardware PWM pin support +// +// Copyright (C) 2016-2018 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "autoconf.h" // CONFIG_MACH_atmega644p +#include "command.h" // shutdown +#include "gpio.h" // gpio_pwm_write +#include "internal.h" // GPIO2REGS +#include "irq.h" // irq_save +#include "pgm.h" // PROGMEM +#include "sched.h" // sched_shutdown + +struct gpio_pwm_info { + volatile void *ocr; + volatile uint8_t *rega, *regb; + uint8_t en_bit, flags; +}; + +enum { GP_8BIT=1, GP_AFMT=2 }; + +static const struct gpio_pwm_info pwm_regs[] PROGMEM = { + { &OCR0A, &TCCR0A, &TCCR0B, 1<= ARRAY_SIZE(pwm_pins)) + shutdown("Not a valid PWM pin"); + if (READP(pwm_pins[chan]) == pin) + break; + } + + // Map cycle_time to pwm clock divisor + const struct gpio_pwm_info *p = &pwm_regs[chan]; + uint8_t flags = READP(p->flags), cs; + if (flags & GP_AFMT) { + switch (cycle_time) { + case 0 ... (1+8) * 510L / 2 - 1: cs = 1; break; + case (1+8) * 510L / 2 ... (8+32) * 510L / 2 - 1: cs = 2; break; + case (8+32) * 510L / 2 ... (32+64) * 510L / 2 - 1: cs = 3; break; + case (32+64) * 510L / 2 ... (64+128) * 510L / 2 - 1: cs = 4; break; + case (64+128) * 510L / 2 ... (128+256) * 510L / 2 - 1: cs = 5; break; + case (128+256) * 510L / 2 ... (256+1024) * 510L / 2 - 1: cs = 6; break; + default: cs = 7; break; + } + } else { + switch (cycle_time) { + case 0 ... (1+8) * 510L / 2 - 1: cs = 1; break; + case (1+8) * 510L / 2 ... (8+64) * 510L / 2 - 1: cs = 2; break; + case (8+64) * 510L / 2 ... (64+256) * 510L / 2 - 1: cs = 3; break; + case (64+256) * 510L / 2 ... (256+1024) * 510L / 2 - 1: cs = 4; break; + default: cs = 5; break; + } + } + volatile uint8_t *rega = READP(p->rega), *regb = READP(p->regb); + uint8_t en_bit = READP(p->en_bit); + struct gpio_digital_regs *gpio_regs = GPIO2REGS(pin); + uint8_t gpio_bit = GPIO2BIT(pin); + struct gpio_pwm g = (struct gpio_pwm) { + (void*)READP(p->ocr), flags & GP_8BIT }; + if (rega == &TCCR1A) + shutdown("Can not use timer1 for PWM; timer1 is used for timers"); + + // Setup PWM timer + irqstatus_t flag = irq_save(); + uint8_t old_cs = *regb & 0x07; + if (old_cs && old_cs != cs) + shutdown("PWM already programmed at different speed"); + *regb = cs; + + // Set default value and enable output + gpio_pwm_write(g, val); + *rega |= (1<mode |= gpio_bit; + irq_restore(flag); + + return g; +} + +void +gpio_pwm_write(struct gpio_pwm g, uint8_t val) +{ + if (g.size8) { + *(volatile uint8_t*)g.reg = val; + } else { + irqstatus_t flag = irq_save(); + *(volatile uint16_t*)g.reg = val; + irq_restore(flag); + } +} -- cgit v1.2.3-70-g09d2