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/gpio.c | 394 +-------------------------------------------------------- 1 file changed, 4 insertions(+), 390 deletions(-) (limited to 'src/avr/gpio.c') diff --git a/src/avr/gpio.c b/src/avr/gpio.c index 15da3d79..c7ca1220 100644 --- a/src/avr/gpio.c +++ b/src/avr/gpio.c @@ -1,27 +1,18 @@ // GPIO functions on AVR. // -// Copyright (C) 2016,2017 Kevin O'Connor +// Copyright (C) 2016-2018 Kevin O'Connor // // This file may be distributed under the terms of the GNU GPLv3 license. -#include // NULL #include "autoconf.h" // CONFIG_MACH_atmega644p #include "command.h" // shutdown #include "gpio.h" // gpio_out_write +#include "internal.h" // GPIO2REGS #include "irq.h" // irq_save #include "pgm.h" // PROGMEM -#include "sched.h" // DECL_INIT +#include "sched.h" // sched_shutdown - -/**************************************************************** - * General Purpose Input Output (GPIO) pins - ****************************************************************/ - -#define GPIO(PORT, NUM) (((PORT)-'A') * 8 + (NUM)) -#define GPIO2PORT(PIN) ((PIN) / 8) -#define GPIO2BIT(PIN) (1<<((PIN) % 8)) - -static volatile uint8_t * const digital_regs[] PROGMEM = { +volatile uint8_t * const digital_regs[] PROGMEM = { #ifdef PINA &PINA, #else @@ -36,14 +27,6 @@ static volatile uint8_t * const digital_regs[] PROGMEM = { #endif }; -struct gpio_digital_regs { - // gcc (pre v6) does better optimization when uint8_t are bitfields - volatile uint8_t in : 8, mode : 8, out : 8; -}; - -#define GPIO2REGS(pin) \ - ((struct gpio_digital_regs*)READP(digital_regs[GPIO2PORT(pin)])) - struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val) { @@ -117,372 +100,3 @@ gpio_in_read(struct gpio_in g) { return !!(g.regs->in & g.bit); } - - -/**************************************************************** - * Hardware Pulse Width Modulation (PWM) pins - ****************************************************************/ - -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); - } -} - - -/**************************************************************** - * Analog to Digital Converter (ADC) pins - ****************************************************************/ - -static const uint8_t adc_pins[] PROGMEM = { -#if CONFIG_MACH_atmega168 || CONFIG_MACH_atmega328 || CONFIG_MACH_atmega328p - GPIO('C', 0), GPIO('C', 1), GPIO('C', 2), GPIO('C', 3), - GPIO('C', 4), GPIO('C', 5), GPIO('E', 0), GPIO('E', 1), -#elif CONFIG_MACH_atmega644p || CONFIG_MACH_atmega1284p - GPIO('A', 0), GPIO('A', 1), GPIO('A', 2), GPIO('A', 3), - GPIO('A', 4), GPIO('A', 5), GPIO('A', 6), GPIO('A', 7), -#elif CONFIG_MACH_at90usb1286 || CONFIG_MACH_at90usb646 - GPIO('F', 0), GPIO('F', 1), GPIO('F', 2), GPIO('F', 3), - GPIO('F', 4), GPIO('F', 5), GPIO('F', 6), GPIO('F', 7), -#elif CONFIG_MACH_atmega32u4 - GPIO('F', 0), GPIO('F', 1), GPIO('F', 2), GPIO('F', 3), - GPIO('F', 4), GPIO('F', 5), GPIO('F', 6), GPIO('F', 7), - GPIO('D', 4), GPIO('D', 6), GPIO('D', 7), GPIO('B', 4), -#elif CONFIG_MACH_atmega1280 || CONFIG_MACH_atmega2560 - GPIO('F', 0), GPIO('F', 1), GPIO('F', 2), GPIO('F', 3), - GPIO('F', 4), GPIO('F', 5), GPIO('F', 6), GPIO('F', 7), - GPIO('K', 0), GPIO('K', 1), GPIO('K', 2), GPIO('K', 3), - GPIO('K', 4), GPIO('K', 5), GPIO('K', 6), GPIO('K', 7), -#endif -}; - -enum { ADMUX_DEFAULT = 0x40 }; -enum { ADC_ENABLE = (1<= ARRAY_SIZE(adc_pins)) - shutdown("Not a valid ADC pin"); - if (READP(adc_pins[chan]) == pin) - break; - } - - // Enable ADC - ADCSRA = ADC_ENABLE; - - // Disable digital input for this pin -#ifdef DIDR2 - if (chan >= 8) - DIDR2 |= 1 << (chan & 0x07); - else -#endif - DIDR0 |= 1 << chan; - - return (struct gpio_adc){ chan }; -} - -enum { ADC_DUMMY=0xff }; -static uint8_t last_analog_read = ADC_DUMMY; - -// Try to sample a value. Returns zero if sample ready, otherwise -// returns the number of clock ticks the caller should wait before -// retrying this function. -uint32_t -gpio_adc_sample(struct gpio_adc g) -{ - if (ADCSRA & (1<> 3) & 0x01) << MUX5; -#endif - ADMUX = ADMUX_DEFAULT | (g.chan & 0x07); - - // Start the sample - ADCSRA = ADC_ENABLE | (1<mode & GPIO2BIT(SS))) - // The SS pin must be an output pin (but is otherwise unused) - gpio_out_setup(SS, 0); - gpio_out_setup(SCK, 0); - gpio_out_setup(MOSI, 0); - gpio_in_setup(MISO, 0); - - SPCR = (1< 3) - shutdown("Invalid spi_setup parameters"); - - // Make sure the SPI interface is enabled - spi_init(); - - // Setup rate - struct spi_config config = {0, 0}; - if (rate >= (CONFIG_CLOCK_FREQ / 2)) { - config.spsr = (1<= (CONFIG_CLOCK_FREQ / 4)) { - config.spcr = 0; - } else if (rate >= (CONFIG_CLOCK_FREQ / 8)) { - config.spcr = 1; - config.spsr = (1<= (CONFIG_CLOCK_FREQ / 16)) { - config.spcr = 1; - } else if (rate >= (CONFIG_CLOCK_FREQ / 32)) { - config.spcr = 2; - config.spsr = (1<= (CONFIG_CLOCK_FREQ / 64)) { - config.spcr = 2; - } else { - config.spcr = 3; - } - - // Setup mode - config.spcr |= (1<