diff --git a/ball_and_beam-2018/avr/Makefile b/ball_and_beam-2018/avr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a33ef6ba133b96cad790822960e538fb9762a3c3 --- /dev/null +++ b/ball_and_beam-2018/avr/Makefile @@ -0,0 +1,10 @@ +TARGETS=ball_and_beam-2018 + +ball_and_beam-2018.ARCH=avr +ball_and_beam-2018.CHIP=atmega32 +# 14.7456 MHz crystal, brown out +ball_and_beam-2018.FUSE_L=0x1f +ball_and_beam-2018.FUSE_H=0xd9 +ball_and_beam-2018.C=ball_and_beam-2018 + +include ../../lib/avr/Makefile.common diff --git a/ball_and_beam-2018/avr/ball_and_beam-2018.c b/ball_and_beam-2018/avr/ball_and_beam-2018.c new file mode 100644 index 0000000000000000000000000000000000000000..4e7ac39d1918d4950cbd76d6679ad93d1e456dc7 --- /dev/null +++ b/ball_and_beam-2018/avr/ball_and_beam-2018.c @@ -0,0 +1,250 @@ +#include <avr/eeprom.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <inttypes.h> +#include "serialio.h" + +/* + * Serial I/O assignments: + * + * DI 0 -- Motor Overtemp + * + * DO 0 -- Motor Brake + * DO 1 -- Accelerometer Self-Test + * + * AI 0 -- Ball Position + * AI 1 -- Motor Current + * AI 2 -- Accelerometer X + * AI 3 -- Accelerometer Y + * AI 4 -- Accelerometer Z + * EI 5 -- Motor Position + * + * AO 0 -- Motor Speed + */ + +/* + * Used I/O pins + * + * PA0 Ball Position + * PA1 Motor Current + * PA2 Accelerometer X + * PA3 Accelerometer Y + * PA4 Accelerometer Z + * + * PB0 Ball On Beam + * PB1 Motor direction + * PB2 Encoder Z + * PB3 Motor Brake + * PB4 Motor Thermal Flag + * PB5 Programming MOSI + * PB6 Programming MISO + * PB7 Programming SCK + * + * PD0 Serial In + * PD1 Serial Out + * PD2 Encoder A + * PD3 Encoder B + * PD5 Motor PWM + */ + +volatile unsigned char error; + + +volatile uint8_t serial_readbits; +volatile uint8_t serial_readchannels; +volatile uint8_t serial_readconfig; + +struct values { + /* Outputs */ + uint8_t motorBrake; + uint16_t motorSpeed; + uint8_t accelerometerSelfTest; + + /* Inputs */ + int16_t ballPosition; + int16_t motorCurrent; + int16_t accelerometerX; + int16_t accelerometerY; + int16_t accelerometerZ; + int32_t motorEncoder; + int8_t motorThermalFlag; + int8_t ballOnBeam; + uint8_t timer; +}; +volatile struct values global; + +SIGNAL(ADC_vect) +{ + unsigned char channel = ADMUX & 0x0f; + unsigned int value = ADCW; + + if (global.timer) { + global.timer--; + PORTD &= ~0x40; + } else { + PORTD |= 0x40; + } + switch (channel) { + case 0: { + channel = 1; + global.ballPosition = value; + } break; + case 1: { + channel = 2; + global.motorCurrent = value; + } break; + case 2: { + channel = 3; + global.accelerometerX = value; + } break; + case 3: { + channel = 4; + global.accelerometerY = value; + } break; + case 4: { + channel = 5; + global.accelerometerZ = value; + } break; + default: { + channel = 0; + } break; + } + ADMUX = 0x00 | channel; // Vref = external, right adjust + ADCSRA = 0xcf; // Enable ADC interrupts, Clock/128 +} + +typedef enum { cmd_clear_bit, cmd_set_bit, + cmd_read_bit, cmd_read_chan } command; + +SIGNAL(USART_RXC_vect) +{ + char ch = UDR; + + global.timer = 0xff; + switch (serialio_RXC(ch)) { + case serialio_clearbit: { + switch (serialio_channel) { + case 0: { PORTB &= ~0x08; } break; + case 1: { PORTC &= ~0x80; } break; + } + } break; + case serialio_setbit: { + switch (serialio_channel) { + case 0: { PORTB |= 0x08; } break; + case 1: { PORTC |= 0x80; } break; + } + } break; + case serialio_pollbit: { + if (serialio_channel < 1) { + serial_readbits |= (1<<serialio_channel); + } + } break; + case serialio_pollchannel: { + if (serialio_channel < 6) { + serial_readchannels |= (1<<serialio_channel); + } else if (serialio_channel == 31) { + serial_readconfig = 1; + } + } break; + case serialio_setchannel: { + switch (serialio_channel) { + case 0: { + int16_t speed; + if (serialio_value < 0x400) { + speed = 0x400 - serialio_value; + PORTB |= 0x02; + } else { + speed = serialio_value - 0x400; + PORTB &= ~0x02; + } + OCR1A = speed & 0x3ff; + } break; + } break; + } break; + case serialio_error: { + } break; + case serialio_more: { + } break; + } +} + +int main() +{ + serialio_init(); + serial_readbits = 0; + serial_readchannels = 0; + serial_readconfig = 0; + PORTA = 0x00; // PortA, pull-ups + DDRA = 0x00; // PortA, all inputs + PORTB = 0x00; // PortB, pull-ups / initial values + DDRB = 0x0a; // PortB, bits 1 & 3 outputs + PORTC = 0x00; // PortC, pull-ups / initial values + DDRC = 0x80; // PortC, bit 7 output + PORTD = 0x00; // PortD, pull-ups / initial values + DDRD = 0x20; // PortD, bit 5 output + TCCR0 = 0x05; // Timer0, Clock / 1024 + TCCR1A = 0x83; // OC1A 10 bit PWM (Phase Correct), clear A on match + TCCR1B = 0x01; // Clock / 1 + OCR1A = 0 & 0x3ff; + UCSRA = 0x00; // USART: + UCSRB = 0x98; // USART: RxIntEnable|RxEnable|TxEnable + UCSRC = 0x86; // USART: 8bit, no parity + UBRRH = 0; // USART: 115200 @ 14.7456MHz + UBRRL = 7; // USART: 115200 @ 14.7456MHz + ADMUX = 0x00; // Vref = external, right adjust + ADMUX = 0x0e; // Vref = external, right adjust, read 1.22V (Vbg) + ADCSRA = 0xcf; // Enable ADC interrupts, Clock/128 + + SREG = 0x80; // Global interrupt enable + while (1) { + unsigned char bits, channels, config; + struct values local; + + SREG = 0x00; // Global interrupt disable + bits = serial_readbits; + serial_readbits = 0; + channels = serial_readchannels; + serial_readchannels = 0; + config = serial_readconfig; + serial_readconfig = 0; + local = global; + SREG = 0x80; // Global interrupt enable + if (channels & 0x01) { serialio_putchannel(0, local.ballPosition); } + if (channels & 0x02) { serialio_putchannel(1, local.motorCurrent); } + if (channels & 0x04) { serialio_putchannel(2, local.accelerometerX); } + if (channels & 0x08) { serialio_putchannel(3, local.accelerometerY); } + if (channels & 0x10) { serialio_putchannel(4, local.accelerometerZ); } + if (channels & 0x20) { serialio_putchannel(5, local.motorEncoder); } + if (bits & 0x01) { serialio_putbit(0, PORTB & 0x10); } // thermalFlag + if (config) { + CONF_DIGITAL_IN(0, CONF_RESOLUTION(1)); // motorTemp + + CONF_DIGITAL_OUT(0, CONF_RESOLUTION(1)); // motorBrake + CONF_DIGITAL_OUT(1, CONF_RESOLUTION(1)); // accelerometerSelfTest + + CONF_ANALOG_IN(0, CONF_RESOLUTION(10)); // ballPosition + CONF_ANALOG_IN(0, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10000))); + CONF_ANALOG_IN(0, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10000))); + CONF_ANALOG_IN(1, CONF_RESOLUTION(10)); // motorCurrent + CONF_ANALOG_IN(1, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10000))); + CONF_ANALOG_IN(1, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10000))); + CONF_ANALOG_IN(2, CONF_RESOLUTION(10)); // accelerometerX + CONF_ANALOG_IN(2, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10000))); + CONF_ANALOG_IN(2, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10000))); + CONF_ANALOG_IN(3, CONF_RESOLUTION(10)); // accelerometerY + CONF_ANALOG_IN(3, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10000))); + CONF_ANALOG_IN(3, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10000))); + CONF_ANALOG_IN(4, CONF_RESOLUTION(10)); // accelerometerZ + CONF_ANALOG_IN(4, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(10000))); + CONF_ANALOG_IN(4, CONF_MAX(CONF_POSITIVE_MILLIVOLT(10000))); + CONF_ENCODER_IN(5, CONF_RESOLUTION(32)); // motorPosition + + CONF_ANALOG_OUT(0, CONF_RESOLUTION(11)); // motorSpeed + CONF_ANALOG_OUT(0, CONF_MIN(CONF_NEGATIVE_MILLIVOLT(12000))); + CONF_ANALOG_OUT(0, CONF_MAX(CONF_POSITIVE_MILLIVOLT(12000))); + + CONF_END(); + } + } +} +