From 69f01a24a3ad59e5395a1e0006d1487e8a38711f Mon Sep 17 00:00:00 2001 From: mars Date: Fri, 24 Feb 2012 06:55:39 +0000 Subject: [PATCH] preliminary implementation --- DiscreteController.h | 27 ++++++++ EuclideanSequencer.cpp | 153 ++++++++++++++++++++++++++++++++++++++--- Makefile | 2 +- adc_freerunner.cpp | 40 +++++++++++ adc_freerunner.h | 14 ++++ device.h | 26 +++++++ main.cpp | 2 +- 7 files changed, 253 insertions(+), 11 deletions(-) create mode 100644 DiscreteController.h create mode 100644 adc_freerunner.cpp create mode 100644 adc_freerunner.h create mode 100644 device.h diff --git a/DiscreteController.h b/DiscreteController.h new file mode 100644 index 0000000..17f7edf --- /dev/null +++ b/DiscreteController.h @@ -0,0 +1,27 @@ +#ifndef _DISCRETE_CONTROLLER_H_ +#define _DISCRETE_CONTROLLER_H_ + +#define ADC_VALUE_RANGE 4096 + +class DiscreteController { +public: + int8_t range; + int8_t value; + virtual void hasChanged(int8_t v){} + void update(uint16_t x){ + uint16_t m = ADC_VALUE_RANGE / range; + if(x > m) + x -= m/4; + else + x = 0; + int8_t v = (int8_t)(x/m); + if(value == v-1 && (x % m) < range/2) + v = value; // suppress change: reading too close to previous value + if(value != v){ + value = v; + hasChanged(value); + } + } +}; + +#endif /* _DISCRETE_CONTROLLER_H_ */ diff --git a/EuclideanSequencer.cpp b/EuclideanSequencer.cpp index 0a27e9f..3930233 100644 --- a/EuclideanSequencer.cpp +++ b/EuclideanSequencer.cpp @@ -1,27 +1,162 @@ #include +#include +#include +#include "device.h" #include "bjorklund.h" +#include "adc_freerunner.h" +#include "DiscreteController.h" class Sequence { public: - uint32_t bits; - uint8_t length; - uint8_t pos; - - void calculate(int fills, int steps){ + Sequence() : pos(0), offset(0) {} + void calculate(int fills){ Bjorklund algo; - bits = algo.compute(steps, fills); - length = steps; + bits = algo.compute(length, fills); } - /* Rotate Left */ void rol(uint8_t steps){ -// steps = std::min(steps, length); bits = (bits << steps) | (bits >> (length-steps)); + offset += steps; + } + /* Rotate Right */ + void ror(uint8_t steps){ + bits = (bits >> steps) | (bits << (length-steps)); + offset -= steps; + } + bool next(){ + if(pos >= length) + pos = 0; + return bits & pos++; + } +// private: + uint32_t bits; + uint8_t length; + int8_t offset; + volatile uint8_t pos; +}; + +class GateSequencer : public Sequence { +public: + GateSequencer(int8_t p1, int8_t p2, int8_t p3): + output(p1), trigger(p2), alternate(p3){ + SEQUENCER_TRIGGER_SWITCH_DDR &= ~trigger; + SEQUENCER_TRIGGER_SWITCH_PORT |= trigger; + SEQUENCER_ALTERNATE_SWITCH_DDR &= ~alternate; + SEQUENCER_ALTERNATE_SWITCH_PORT |= alternate; + SEQUENCER_OUTPUT_DDR |= output; + off(); + } + void rise(){ + if(Sequence::next()){ + if(isTriggering()) + on(); + else if(isAlternating()) + toggle(); + } + } + void fall(){ + if(isTriggering()) + off(); + } + inline void on(){ + SEQUENCER_OUTPUT_PORT |= output; + } + inline void off(){ + SEQUENCER_OUTPUT_PORT &= ~output; + } + inline void toggle(){ + SEQUENCER_OUTPUT_PORT ^= output; + } + inline bool isTriggering(){ + return SEQUENCER_TRIGGER_SWITCH_PORT & trigger; + } + inline bool isAlternating(){ + return SEQUENCER_ALTERNATE_SWITCH_PORT & alternate; } +private: + int8_t output; + int8_t trigger; + int8_t alternate; }; +GateSequencer seqA(SEQUENCER_OUTPUT_PIN_A, + SEQUENCER_TRIGGER_SWITCH_PIN_A, + SEQUENCER_ALTERNATE_SWITCH_PIN_A); + +GateSequencer seqB(SEQUENCER_OUTPUT_PIN_B, + SEQUENCER_TRIGGER_SWITCH_PIN_B, + SEQUENCER_ALTERNATE_SWITCH_PIN_B); + +SIGNAL(INT0_vect){ + if(SEQUENCER_CLOCK_PORT & SEQUENCER_CLOCK_PIN){ + seqA.fall(); + seqB.fall(); + }else{ + seqA.rise(); + seqB.rise(); + } +} + void setup(){ + // define interrupt 0 + EICRA = 1 << ISC00; // trigger int0 on any logical change. + // pulses that last longer than one clock period will generate an interrupt. + EIMSK |= (1 << INT0); +// EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); +// EIMSK |= (1 << INT0); +// define interrupt 1 +// EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10); +// EIMSK |= (1 << INT1); + SEQUENCER_CLOCK_DDR &= ~SEQUENCER_CLOCK_PIN; + SEQUENCER_CLOCK_PORT |= SEQUENCER_CLOCK_PIN; // enable pull-up resistor } +class StepController : public DiscreteController { +public: + Sequence& seq; + DiscreteController& fills; + StepController(Sequence& s, DiscreteController& f) : seq(s), fills(f) {} + virtual void hasChanged(int8_t steps){ + steps += 8; // range is 8-24 + seq.length = steps; + fills.range = steps-1; + fills.value = -1; // force change + } +}; + +class FillController : public DiscreteController { +public: + Sequence& seq; + FillController(Sequence& s) : seq(s) {} + virtual void hasChanged(int8_t val){ + seq.calculate(val+1); + } +}; + +class RotateController : public DiscreteController { +public: + Sequence& seq; + RotateController(Sequence& s) : seq(s) {} + virtual void hasChanged(int8_t val){ + if(val > seq.offset) + seq.rol(val-seq.offset); + else if(val < seq.offset) + seq.ror(seq.offset-val); + } +}; + +FillController fillA(seqA); +FillController fillB(seqB); +StepController stepA(seqA, fillA); +StepController stepB(seqB, fillB); +RotateController rotateA(seqA); +RotateController rotateB(seqB); + void loop(){ + stepA.update(getAnalogValue(SEQUENCER_STEP_A_CONTROL)); + stepB.update(getAnalogValue(SEQUENCER_STEP_B_CONTROL)); + fillA.update(getAnalogValue(SEQUENCER_FILL_A_CONTROL)); + fillB.update(getAnalogValue(SEQUENCER_FILL_B_CONTROL)); + rotateA.update(getAnalogValue(SEQUENCER_ROTATE_A_CONTROL)); + rotateB.update(getAnalogValue(SEQUENCER_ROTATE_B_CONTROL)); } diff --git a/Makefile b/Makefile index b647b7f..e5c72cd 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ AVRDUDE_PROGRAMMER = stk500v1 MCU = atmega168 F_CPU = 16000000 -CXXSRC = EuclideanSequencer.cpp bjorklund.cpp main.cpp +CXXSRC = EuclideanSequencer.cpp bjorklund.cpp adc_freerunner.cpp main.cpp SRC = serial.c ############################################################################ diff --git a/adc_freerunner.cpp b/adc_freerunner.cpp new file mode 100644 index 0000000..04db779 --- /dev/null +++ b/adc_freerunner.cpp @@ -0,0 +1,40 @@ +#include "adc_freerunner.h" + +#include + +uint16_t adc_values[ADC_CHANNELS]; + +void setup_adc(){ + ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz + + ADMUX |= (1 << REFS0); // Set ADC reference to AVCC +// ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading + +// ADCSRA |= (1 << ADFR); // Set ADC to Free-Running Mode + ADCSRA |= (1 << ADATE); + + ADCSRA |= (1 << ADEN); // Enable ADC + ADCSRA |= (1 << ADSC); // Start A2D Conversions + + // enable ADC interrupt + ADCSRA |= (1 << ADIE); + + // start interrupts +// sei(); +} + +ISR(ADC_vect) +{ + static uint8_t oldchan; + uint8_t curchan = ADMUX & 7; + + adc_values[oldchan] = ADCL; + adc_values[oldchan] |= ADCH << 8; + + oldchan = curchan; + + if(++curchan == ADC_CHANNELS) + curchan = 0; + + ADMUX = (ADMUX & ~7) | curchan; +} diff --git a/adc_freerunner.h b/adc_freerunner.h new file mode 100644 index 0000000..cb9639e --- /dev/null +++ b/adc_freerunner.h @@ -0,0 +1,14 @@ +#ifndef _ANALOGREADER_H_ +#define _ANALOGREADER_H_ + +#include + +#define ADC_CHANNELS 6 + +extern uint16_t adc_values[ADC_CHANNELS]; + +void setup_adc(); + +#define getAnalogValue(i) adc_values[i] + +#endif /* _ANALOGREADER_H_ */ diff --git a/device.h b/device.h new file mode 100644 index 0000000..8c23af3 --- /dev/null +++ b/device.h @@ -0,0 +1,26 @@ + +#define SEQUENCER_STEP_A_CONTROL 0 +#define SEQUENCER_STEP_B_CONTROL 1 +#define SEQUENCER_FILL_A_CONTROL 2 +#define SEQUENCER_FILL_B_CONTROL 3 +#define SEQUENCER_ROTATE_A_CONTROL 4 +#define SEQUENCER_ROTATE_B_CONTROL 5 + +#define SEQUENCER_CLOCK_PORT PORTD +#define SEQUENCER_CLOCK_DDR DDRD +#define SEQUENCER_CLOCK_PIN _BV(PORTD2) + +#define SEQUENCER_OUTPUT_PORT PORTD +#define SEQUENCER_OUTPUT_DDR DDRD +#define SEQUENCER_OUTPUT_PIN_A _BV(PORTD6) +#define SEQUENCER_OUTPUT_PIN_B _BV(PORTD7) + +#define SEQUENCER_TRIGGER_SWITCH_PORT PORTD +#define SEQUENCER_TRIGGER_SWITCH_DDR DDRD +#define SEQUENCER_TRIGGER_SWITCH_PIN_A _BV(PORTD4) +#define SEQUENCER_TRIGGER_SWITCH_PIN_B _BV(PORTD5) + +#define SEQUENCER_ALTERNATE_SWITCH_PORT PORTB +#define SEQUENCER_ALTERNATE_SWITCH_DDR DDRB +#define SEQUENCER_ALTERNATE_SWITCH_PIN_A _BV(PORTB0) +#define SEQUENCER_ALTERNATE_SWITCH_PIN_B _BV(PORTB1) diff --git a/main.cpp b/main.cpp index e84a0d6..4bc760e 100644 --- a/main.cpp +++ b/main.cpp @@ -4,7 +4,7 @@ void setup(); void loop(); int main(void){ - init(); +// init(); setup(); for (;;) loop();