Skip to content

Commit

Permalink
preliminary implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mars committed Feb 24, 2012
1 parent da68045 commit 69f01a2
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 11 deletions.
27 changes: 27 additions & 0 deletions 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_ */
153 changes: 144 additions & 9 deletions EuclideanSequencer.cpp
@@ -1,27 +1,162 @@
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#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));
}
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -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

############################################################################
Expand Down
40 changes: 40 additions & 0 deletions adc_freerunner.cpp
@@ -0,0 +1,40 @@
#include "adc_freerunner.h"

#include <avr/interrupt.h>

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;
}
14 changes: 14 additions & 0 deletions adc_freerunner.h
@@ -0,0 +1,14 @@
#ifndef _ANALOGREADER_H_
#define _ANALOGREADER_H_

#include <inttypes.h>

#define ADC_CHANNELS 6

extern uint16_t adc_values[ADC_CHANNELS];

void setup_adc();

#define getAnalogValue(i) adc_values[i]

#endif /* _ANALOGREADER_H_ */
26 changes: 26 additions & 0 deletions 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)
2 changes: 1 addition & 1 deletion main.cpp
Expand Up @@ -4,7 +4,7 @@ void setup();
void loop();

int main(void){
init();
// init();
setup();
for (;;)
loop();
Expand Down

0 comments on commit 69f01a2

Please sign in to comment.