Sunday 28 February 2010

When Lava met Mopho

I got a new toy! an Mopho analog synth from Dave Smith Instruments. First use.. a companion to my MIDI lavalamp to free it up from PC based soft synths. Since my original MIDI lavalamp project was based on a standard Arduino, I decided this time to make a quick little module for it using a PIC16F688 (my current weapon of choice)



Here is the circuit on stripboard



...the mess on the back...



...and the schematic...



... the lamp is wired up as described on this post

... and the PIC source code is included below (SourceBoost compiler)

#include <system.h>

#include <memory.h>



#define ANA_0 0b00000000

#define ANA_1 0b00000100

#define ANA_2 0b00001000

#define ANA_3 0b00001100

#define ANA_4 0b00010000

#define ANA_5 0b00010100

#define ANA_6 0b00011000

#define ANA_7 0b00011100

#define ADC_MAX 6



#define P_HEARTBEAT porta.5



#pragma DATA _CONFIG, _MCLRE_OFF&_WDT_OFF&_INTRC_OSC_NOCLKOUT

#pragma CLOCK_FREQ 8000000

#define ADC_AQUISITION_DELAY 10



typedef unsigned char byte;



enum {

ADC_CONNECT,

ADC_ACQUIRE,

ADC_CONVERT

};



void init_usart()

{

pir1.1 = 1; //TXIF transmit enable

pie1.1 = 0; //TXIE no interrupts



baudctl.4 = 0; // synchronous bit polarity

baudctl.3 = 1; // enable 16 bit brg

baudctl.1 = 0; // wake up enable off

baudctl.0 = 0; // disable auto baud detect



txsta.6 = 0; // 8 bit transmission

txsta.5 = 1; // transmit enable

txsta.4 = 0; // async mode

txsta.2 = 0; // high baudrate BRGH



rcsta.7 = 1; // serial port enable

rcsta.6 = 0; // 8 bit operation

rcsta.4 = 0; // enable receiver



spbrgh = 0; // brg high byte

spbrg = 15; // brg low byte (31250)

}



void send(unsigned char c)

{

txreg = c;

while(!txsta.1);

}



void sendController(byte channel, byte controller, byte value)

{

P_HEARTBEAT = 1;

send(0xb0 | channel);

send(controller&0x7f);

send(value&0x7f);

P_HEARTBEAT = 0;

}



byte adcInput[ADC_MAX] = {ANA_2, ANA_3, ANA_4, ANA_5, ANA_6, ANA_7};

byte adcInitComplete = 0;

int adcResult[ADC_MAX] = {-1,-1,-1,-1,-1,-1};

int adcIndex = 0;

int adcState = ADC_CONNECT;



////////////////////////////////////////////////////////////////

//

// doADC

//

// State machine for running the ADC and updating the adcResult

// array with the result from each analog input

//

void doADC()

{

switch(adcState)

{

// Connect ADC to the correct analog input

case ADC_CONNECT:

adcon0=0b10000001 | adcInput[adcIndex];

tmr0 = 0;

adcState = ADC_ACQUIRE;

// fall through



// Waiting for a delay while the ADC input settles

case ADC_ACQUIRE:

if(tmr0 > ADC_AQUISITION_DELAY)

{

// Start the conversion

adcon0.1=1;

adcState = ADC_CONVERT;

}

break;



// Waiting for the conversion to complete

case ADC_CONVERT:

if(!adcon0.1)

{

// store the result

adcResult[adcIndex] = (((int)adresh)<<8)|adresl;



// and prepare for the next ADC

if(++adcIndex>=ADC_MAX)

{

adcIndex = 0;

adcInitComplete = 1;

}

adcState = ADC_CONNECT;

}

break;

}

}





#define BUFLEN 8

typedef struct

{

char midiChannel;

char midiController;

int minADC;

int maxADC;

char currentValue;

char history[BUFLEN];

} CONTROLLER;



CONTROLLER controllers[ADC_MAX] = {0};



void initInput(int which, byte channel, byte controller)

{

controllers[which].midiChannel = channel;

controllers[which].midiController = controller;

controllers[which].minADC = -1;

controllers[which].maxADC = -1;

controllers[which].currentValue = -1;

}



void checkInput(int which)

{

// pointer to the controllers

CONTROLLER *p = &controllers[which];



// read the raw analog value 0-1023

int adc = adcResult[which];



// remember highest and lowest values

if((p->minADC == -1) || (p->minADC > adc))

p->minADC = adc;

if((p->maxADC == -1) || (p->maxADC < adc))

p->maxADC = adc;



// get the range of known readings

int range = p->maxADC - p->minADC;

if(range < 1)

range = 1;



// scale the current value into the range

// NB no floating point support...

int newValue = (127*(adc - p->minADC))/range;



// add the value into the history buffer

long smoothed = 0;

for(int j=0; j<BUFLEN-1;++j)

{

p->history[j] = p->history[j+1];

smoothed += p->history[j];

}

p->history[BUFLEN-1] = newValue;

smoothed += newValue;

smoothed /= BUFLEN;



// has the value changed?

if(smoothed != p->currentValue)

{

sendController(p->midiChannel, p->midiController, smoothed);

p->currentValue= smoothed;

}

}



void main()

{

int i;



// osc control / 8MHz / internal

osccon = 0b01110001;



// timer0... configure source and prescaler

option_reg = 0b10000011;

cmcon0 = 7;



// configure io

trisa = 0b00001010;

trisc = 0b00001111;

ansel = 0b11111100;



// turn on the ADC

adcon1=0b00100000; //fOSC/32

adcon0=0b10000001; // Right justify / Vdd / AD on



// initialise MIDI comms

init_usart();



// Initialise the controllers

initInput(0, 0, 1);

initInput(1, 0, 2);

initInput(2, 0, 4);

initInput(3, 0, 7);

initInput(4, 0, 11);

initInput(5, 0, 74);



adcInitComplete = 0;

for(;;)

{

doADC();

if(adcInitComplete)

{

for(i=0;i<ADC_MAX;++i)

checkInput(i);

adcInitComplete = 0;

delay_ms(20);

}

}

}

No comments:

Post a Comment