Author |
Message |
xiphocoleon
Joined: Oct 04, 2013 Posts: 40 Location: Brooklyn
|
Posted: Sun Apr 05, 2015 9:03 pm Post subject:
MIDI to CV 555 VCO design ideas Subject description: I'm trying to make a MIDI controlled 555 VCO |
|
|
Hi all --
I am trying to make a 555 VCO that is controlled by a MIDI source. Also, this oscillator will be for bass frequencies, so it only needs limited octave range.
So far, I plan to capture a MIDI signal via an optocoupler circuit, but after this, I am not sure the best way to proceed:
Should the signal go:
MIDI source --> optocoupler --> microcontroller to convert optocoupler pulse to a control voltage that would allow for linear control of a 555 VCO
For now I am going to use an Arduino for the microcontroller, but eventually once I get the prototype working I'll use my own set of discrete parts.
However, please advise:
1) Is the block diagram above appropriate to achieve a MIDI-CV controlled 555 VCO?
2) Will the 555 stay in tune well enough, for say three octaves in standard bass frequency range?
3) Please direct me to any other relevant links for this project. I've searched through this forum and didn't quite find what I was looking for.
Thanks! |
|
Back to top
|
|
|
Boerge
Joined: Sep 02, 2009 Posts: 80 Location: Germany
|
Posted: Mon Apr 06, 2015 3:30 am Post subject:
Re: MIDI to CV 555 VCO design ideas Subject description: I'm trying to make a MIDI controlled 555 VCO |
|
|
Hi,
xiphocoleon wrote: |
For now I am going to use an Arduino for the microcontroller |
Seems a bit oversized - any little PIC or ATTiny should do the trick
xiphocoleon wrote: |
1) Is the block diagram above appropriate to achieve a MIDI-CV controlled 555 VCO? |
Hm, no diagram there
xiphocoleon wrote: |
2) Will the 555 stay in tune well enough, for say three octaves in standard bass frequency range? |
Should work. Look at the PAiA FatMan, has MIDI and uses 555 for VCO.
xiphocoleon wrote: |
3) Please direct me to any other relevant links for this project. I've searched through this forum and didn't quite find what I was looking for. |
Use your favorite search engine too look vor "PIC MIDI2CV" or "Atmel MIDI2CV", have a look at the FatMan-schemo. Should be enough for the start
greetings
Boerge _________________ ...ich will doch nur löten... |
|
Back to top
|
|
|
xiphocoleon
Joined: Oct 04, 2013 Posts: 40 Location: Brooklyn
|
Posted: Mon Apr 06, 2015 8:52 am Post subject:
|
|
|
Thank you so much. Yes, I plan to use a non-Arduino microcontroller for the final project. Thanks for the recommendations, because I've never used non-Arduino microcontrollers.
Ah yes, the "block diagram" I was referring to was just my text-based diagram:
MIDI source --> optocoupler --> microcontroller to convert optocoupler pulse to a control voltage that would allow for linear control of a 555 VCO
If anyone thinks this is not the appropriate way to process the signals, please let me know.
And I will check out the FATMAN and other search terms you've recommended.
I'll post some updates here as I progress and will post the final version so that it may help others. |
|
Back to top
|
|
|
gdavis
Joined: Feb 27, 2013 Posts: 359 Location: San Diego
Audio files: 1
|
Posted: Tue Apr 07, 2015 12:28 pm Post subject:
|
|
|
I'm not familiar with the PIC family but I've done midi to CV with arduino. Hooking up a midi receiver circuit to the arduino is simple, just connect the output of the optocoupler circuit to the serial RX pin. There is a midi library that makes handling midi messages easy. Check the Arduino website for information.
The trickier part is generating the CV output. Some people have reported success using the PWM output of the micro-controller but personally I think using a SPI DAC is easier, especially for pitch CV. There has been a fair amount of discussion about this, probably in the microcontrollers section.
BTW, Arduino isn't a microcontroller, it's a platform that utilizes a few of the Atmel AVR microcontrollers. There's even an Arduino addon for Atmel Studio. I use Atmel Studio with AVR Dragon to download my Arduino code through ICSP to my custom microcontroller board. _________________ My synth build blog: http://gndsynth.blogspot.com/ Last edited by gdavis on Tue Apr 07, 2015 12:52 pm; edited 1 time in total |
|
Back to top
|
|
|
xiphocoleon
Joined: Oct 04, 2013 Posts: 40 Location: Brooklyn
|
Posted: Tue Apr 07, 2015 12:34 pm Post subject:
|
|
|
Thanks for your input. I have studied the PAIA Fatman circuit and I am now going to consider the best way for me to set up the 555 to receive MIDI pitch data.
Initially, I wanted to set up the 555 in a quasi-astable mode, where reset would be low except when MIDI data is sent to the 555, thereby turning the 555 on and controlling its pitch at the same time. However, I have a sense that using the Reset on the 555 in this way is not the best idea. |
|
Back to top
|
|
|
gdavis
Joined: Feb 27, 2013 Posts: 359 Location: San Diego
Audio files: 1
|
Posted: Tue Apr 07, 2015 1:24 pm Post subject:
|
|
|
Oh, when I saw 555 VCO I was thinking the Thomas Henry 555 VCO circuit. Doing a good stable VCO right out of the 555 might be trickier than you think. I haven't seen the PAIA circuit though. Edit: found the PAIA circuit, that should get you started on the right track for a 555 VCO. _________________ My synth build blog: http://gndsynth.blogspot.com/ |
|
Back to top
|
|
|
xiphocoleon
Joined: Oct 04, 2013 Posts: 40 Location: Brooklyn
|
Posted: Tue Apr 07, 2015 4:18 pm Post subject:
|
|
|
I have now modified an Arduino sketch so that I can generate different pulse widths in response to different MIDI data.
If I were able to construct a VCO that could be voltage controlled by varied pulse widths, I'd be in a good spot. I am going to try and do this with a 555.
I am going to examine more closely if this is possible with the PAIA FATMAN 555 VCO. |
|
Back to top
|
|
|
xiphocoleon
Joined: Oct 04, 2013 Posts: 40 Location: Brooklyn
|
Posted: Tue Apr 07, 2015 4:26 pm Post subject:
|
|
|
I'm thinking I want to convert the pulses output by the microcontroller to a steady DC voltage, which the 555 would respond to. The important question would be: could this be tuned accurately?
A sample pulse-width to voltage circuit: http://m.eet.com/media/1144833/178105f1.pdf |
|
Back to top
|
|
|
elmegil
Joined: Mar 20, 2012 Posts: 2177 Location: Chicago
Audio files: 16
|
Posted: Tue Apr 07, 2015 7:57 pm Post subject:
|
|
|
That was alluded to earlier in the thread; some folks do do PWM -> CV circuits, and you should be able to find a few examples. Whether that's precise enough for voltage control is a different matter. I think you need to look into how you can voltage control your 555 before you get too much farther. |
|
Back to top
|
|
|
gdavis
Joined: Feb 27, 2013 Posts: 359 Location: San Diego
Audio files: 1
|
Posted: Tue Apr 07, 2015 9:50 pm Post subject:
|
|
|
xiphocoleon wrote: | I'm thinking I want to convert the pulses output by the microcontroller to a steady DC voltage, which the 555 would respond to. The important question would be: could this be tuned accurately?
A sample pulse-width to voltage circuit: http://m.eet.com/media/1144833/178105f1.pdf |
That circuit looks like it's meant for a servo pulse train which has long periods of inactivity between each pulse, hence the sample and hold.
The microcontroller output is going to be a continuous PWM signal, all you really need is a low pass filter. The trade off is going to be accuracy vs. response time. You'll have to find a cuttoff frequency that gives you the balance you need.
I've seen discussions that mentioned things like using higher order filters and combining 2 outputs to increase the accuracy and response. This muffwiggler thread I think is where I saw both mentioned, discusses a couple different low pass filters, claims he got a decent response out of it. _________________ My synth build blog: http://gndsynth.blogspot.com/ |
|
Back to top
|
|
|
comrade_zero
Joined: Mar 05, 2009 Posts: 66 Location: arizona
Audio files: 4
|
Posted: Thu Apr 09, 2015 1:54 am Post subject:
|
|
|
I don't know about using a 555 osc, but I did something very similar using an optocoupler, Arduino, and the super-simple sawtooth oscillator from Nicolas (see sticky.) Added a manual Sallen-Key filter and a simple voltage-controlled attenuator (using an LED/LDR pair driven by an Arduino pin for "envelope"). Used an extra op-amp as a comparator to tap a square wave off the original osc. Made a nice poor-man's bass monosynth. Samples on my original post here: http://electro-music.com/forum/topic-48046.html
For cv I used two PWM outs into two passive low-pass filters (something like 10k resistors into 10uF caps) and summed them at the cv in. I think I got a total of three octaves out of it. The "fun" part of this approach is that you get to manually tune each note. I set up a test circuit with the Arduino and the oscillator and manually determined each appropriate pwm output value for each note, then stuck those in an array that could be looked up for each corresponding MIDI value. I wound up using two PWM outputs because a single output (0-127) did not have good enough resolution, so I added the second as a "fine" control. Note: using this (admittedly inelegant) approach results in "settling" time for the oscillator, so it may not respond as quickly/accurately as you need. |
|
Back to top
|
|
|
JovianPyx
Joined: Nov 20, 2007 Posts: 1988 Location: West Red Spot, Jupiter
Audio files: 224
|
Posted: Thu Apr 09, 2015 8:06 am Post subject:
|
|
|
A word about the 555 timer and VCOs - You should be aware that the 555 timer is a bipolar part with a TTL type totem pole output structure. As such, when the device switches from high to low or low to high, both of the totem pole transistors are on for an instant while the switching occurs. This causes a current spike that propagates easily to other parts of the circuit.
This is a well documented problem with the Fatman VCO, but it is easily remedied. (I have built two Fatman synths). The problem manifests by causing "soft synch" which is where the 2 VCOs will lock together when the pitch controls bring the VCOs close together in pitch. Normally, we want that difference to remain (without locking) because it produces a pleasant phasing sound that we all enjoy. The first such remedy was called the "Lee Diode Modification" which is to replace the 100 ohm resistor (see the PAiA Fatman schematic) that feeds -12V to the 555 timer IC with an LED. The LED will not illuminate, but it does remove most of the problem of the current spike. The second remedy is to simply replace the 555 timer with a 7555 timer which is pin and function compatible, but the 7555 being constructed out of CMOS will not "crowbar" the PSU like the 555 part will.
My advice is to start off with the 7555 timer instead of the bipolar 555 part to avoid the soft synch problem.
Note that the original 555 (biploar) part was designed as an "industrial timer" which was made to withstand a very noisy electrical environment. _________________ FPGA, dsPIC and Fatman Synth Stuff
Time flies like a banana. Fruit flies when you're having fun. BTW, Do these genes make my ass look fat? corruptio optimi pessima
|
|
Back to top
|
|
|
xiphocoleon
Joined: Oct 04, 2013 Posts: 40 Location: Brooklyn
|
Posted: Fri May 01, 2015 6:26 am Post subject:
|
|
|
comrade_zero wrote: | I don't know about using a 555 osc, but I did something very similar using an optocoupler, Arduino, and the super-simple sawtooth oscillator from Nicolas (see sticky.) Added a manual Sallen-Key filter and a simple voltage-controlled attenuator (using an LED/LDR pair driven by an Arduino pin for "envelope"). Used an extra op-amp as a comparator to tap a square wave off the original osc. Made a nice poor-man's bass monosynth. Samples on my original post here: http://electro-music.com/forum/topic-48046.html
For cv I used two PWM outs into two passive low-pass filters (something like 10k resistors into 10uF caps) and summed them at the cv in. I think I got a total of three octaves out of it. The "fun" part of this approach is that you get to manually tune each note. I set up a test circuit with the Arduino and the oscillator and manually determined each appropriate pwm output value for each note, then stuck those in an array that could be looked up for each corresponding MIDI value. I wound up using two PWM outputs because a single output (0-127) did not have good enough resolution, so I added the second as a "fine" control. Note: using this (admittedly inelegant) approach results in "settling" time for the oscillator, so it may not respond as quickly/accurately as you need. |
Hi Comrade -- I really like your approach and I am going to check out your ideas. I have been working on another project recently and had to pause this one, but in the next weeks I am back to the MIDI to CV synth. I have been studying in the Fatman schematic a bit and it looks like it is also in the same vein of what I'm doing. I'm uncomfortable with the 8031 microcontroller because I think it's prorammed in Assembly (I think?) and I only know C++ and would be more comfortable writing my own code and modifying examples for a microcontroller that could accept that -- maybe the ATTINY 85? |
|
Back to top
|
|
|
elmegil
Joined: Mar 20, 2012 Posts: 2177 Location: Chicago
Audio files: 16
|
Posted: Fri May 01, 2015 7:03 am Post subject:
|
|
|
There are lots of MIDI to CV projects out there using Arduino of various sorts, and also a few using PIC microcontrollers which are programmed in various languages including C or C++. Arduino's dev environment is a little easier to make "just work", but that assumes you have the whole Arduino "thang". Programming an AVR (ATtiny etc) directly seems to be more or less a wash versus a PIC.
One note on an existing project out there: http://www.acxsynth.com/midi2cvlite/midi2cvlitefr.htm
I like this one, it's simple but it has one flaw -- it uses floating point math in scaling, and this means that for some types of synths (I believe those doing "running status" MIDI messages) it drops bytes and will get stuck at fast key speeds (e.g. a fast sequence). The solution is pretty simple, just convert the two multiplies here:
Code: | switch(MIDI_Byte1){
case 0x90: // Note On
if(MIDI_Byte3==0) FinNote();
else {
Note_VAL = MIDI_Byte2-24; //Le do grave a la valeur 24 et pas 0
Note_VAL = Note_VAL * 83.3333; //83.3333 = 1 V/oct /12
PlayNote(); //on joue la note
Gate();
}
break;
case 0x80: // Note Off
FinNote();
break;
case 0xE0: // pitch wheel
Pitch_Wheel_VAL = MIDI_Byte3 * 2.644;
PlayNote(); |
To use equivalent integer operations -- an integer multiply then divide is much faster than a FP multiply. |
|
Back to top
|
|
|
jackdamery
Joined: Apr 26, 2010 Posts: 75 Location: UK
|
Posted: Thu May 07, 2015 5:56 am Post subject:
|
|
|
I investigated the very thing you are doing. I found 555s are unstable (turn 555 on, measure frequency. Leave running for half an hour, measure frequency again.).
You might have more luck with the TLC555 (lincmos version of the 555). |
|
Back to top
|
|
|
xiphocoleon
Joined: Oct 04, 2013 Posts: 40 Location: Brooklyn
|
Posted: Mon May 18, 2015 4:44 pm Post subject:
|
|
|
Hi comrade_zero -- which is the Nicolas design you're referring to? http://electro-music.com/wiki/pmwiki.php?n=Schematics.NicolasSuperSimpleVPerHzVCO -- this design says it produces a triangle wave, and I know you mentioned a sawtooth wave. Could you post a link to the Nicolas design you mentioned? Thanks.
comrade_zero wrote: | I don't know about using a 555 osc, but I did something very similar using an optocoupler, Arduino, and the super-simple sawtooth oscillator from Nicolas (see sticky.) |
|
|
Back to top
|
|
|
comrade_zero
Joined: Mar 05, 2009 Posts: 66 Location: arizona
Audio files: 4
|
Posted: Mon May 18, 2015 10:23 pm Post subject:
|
|
|
http://electro-music.com/forum/post-292718.html
you can use another op-amp as a comparator to generate a pulse/square off of the output, but the circuit as-is puts out a nice sawtooth. I used tl082's in my build, but I've breadboarded it with 358's. Needs bipolar supply as drawn (i've run it off of +/- 12v), but you could run it off a single supply using a "virtual ground."
The response to cv is not perfectly linear, so you will have to manually tune each desires note (using a DAC or PWM output or whatever) and build an array of desired outputs that yield the desired notes.
Like I said, I think I got three or four in-tune octaves out of it driving it from an arduino pwm.
Good luck, hope this helps.
c_z |
|
Back to top
|
|
|
isak
Joined: Dec 13, 2009 Posts: 847 Location: Israel
Audio files: 18
|
Posted: Tue May 19, 2015 3:19 pm Post subject:
|
|
|
elmegil wrote: | There are lots of MIDI to CV projects out there using Arduino of various sorts, and also a few using PIC microcontrollers which are programmed in various languages including C or C++. Arduino's dev environment is a little easier to make "just work", but that assumes you have the whole Arduino "thang". Programming an AVR (ATtiny etc) directly seems to be more or less a wash versus a PIC.
One note on an existing project out there: http://www.acxsynth.com/midi2cvlite/midi2cvlitefr.htm
I like this one, it's simple but it has one flaw -- it uses floating point math in scaling, and this means that for some types of synths (I believe those doing "running status" MIDI messages) it drops bytes and will get stuck at fast key speeds (e.g. a fast sequence). The solution is pretty simple, just convert the two multiplies here:
Code: | switch(MIDI_Byte1){
case 0x90: // Note On
if(MIDI_Byte3==0) FinNote();
else {
Note_VAL = MIDI_Byte2-24; //Le do grave a la valeur 24 et pas 0
Note_VAL = Note_VAL * 83.3333; //83.3333 = 1 V/oct /12
PlayNote(); //on joue la note
Gate();
}
break;
case 0x80: // Note Off
FinNote();
break;
case 0xE0: // pitch wheel
Pitch_Wheel_VAL = MIDI_Byte3 * 2.644;
PlayNote(); |
To use equivalent integer operations -- an integer multiply then divide is much faster than a FP multiply. |
Hi elmegil
i got the same problem you mention above, with my x0xb0x seq and also with my DAW, i work with cubase and every time when i'm trying to move the midi note with the mouse the sound got stuck, only after pressing reset to the lite midi2cv it comes back to work normal.
can you please show how/where i need to replace it on the code?
should i insert the fix instead the whole lines below...? (its from the original code)
Code: | switch(Rx_DATA){
case 0x90: // Note On
MIDI_Byte1=Rx_DATA;
nb_Byte++;
break;
case 0x80: // Note Off
MIDI_Byte1=Rx_DATA;
nb_Byte++;
break;
case 0xE0: // pitch bend
MIDI_Byte1=Rx_DATA;
nb_Byte++;
break;
case 0xB0:; //Modulation
MIDI_Byte1=Rx_DATA;
nb_Byte++;
break;
case 0xFE: //Active Sensing
break;
default:
MIDI_Byte1 = 0;
}
|
thanks in advance,
Isak E. _________________ http://www.myspace.com/mgmtrance |
|
Back to top
|
|
|
elmegil
Joined: Mar 20, 2012 Posts: 2177 Location: Chicago
Audio files: 16
|
Posted: Tue May 19, 2015 3:38 pm Post subject:
|
|
|
It doesn't appear to be the same problem to me, nothing in the code fragment you've included does a multiply.
It may be the same symptom, but I don't see anything in the fragment of code you've included that leads me to any conclusion about the cause.
Sorry |
|
Back to top
|
|
|
isak
Joined: Dec 13, 2009 Posts: 847 Location: Israel
Audio files: 18
|
Posted: Tue May 19, 2015 3:46 pm Post subject:
|
|
|
elmegil wrote: | It doesn't appear to be the same problem to me, nothing in the code fragment you've included does a multiply.
It may be the same symptom, but I don't see anything in the fragment of code you've included that leads me to any conclusion about the cause.
Sorry |
thank you for replying
sorry, i dont understand...
didnt you said its a fix for the ACX lite midi2cv?
if yes, where should i put it on the code?
this is the whole code :
Code: |
/*
Logiciel de gestion du module MIDI CV/Gate ACS Lite version
Alain COUPEL 11 novembre 2008
PORT A : 0= output, 1= input
RA0 TRIGGER 0
RA1 Select DAC2 0
RA2 SDI 0
RA3 Select DAC1 0
RA4 SCK 0
RA5 MCLR 1 input pour reset
RA6 LED 0
RA7 GATE 0
TRISA = 0b00100000
PORT B :
RB0 NC 0
RB1 NC 0
RB2 Rx 1 INPUT Rx MIDI
RB3 NC 0
RB4 NC 0
RB5 NC 0
RB6 NC 1
RB7 NC 1
TRISB = 0b11000100
*/
#include<htc> //Compilateur Hi-Tech PICC std
__CONFIG(INTIO &WDTDIS & PWRTEN &MCLREN & UNPROTECT & BORDIS & FCMDIS );
#define TRIG RA0 //Trigger output
#define SDI RA2 //SPI Data
#define CI1 RA3 // DAC select
#define SCK RA4 //SPI Clock
#define LED RA6 //LED output
#define GATE RA7 //Gate output
#define DACa 0b0001000000000000 // = 0x1000 DACa select
#define DACb 0b1001000000000000 // = 0x9000 DACb select
int
Note_VAL, //
Tx_DATA, // Data to transfer
Pitch_Wheel_VAL;
unsigned char
k, n,
nb_Byte, //Bytes number of the MIDI message
nb_Notes, // Number of notes played simultaneously
Rx_DATA,
MIDI_Chnl, // Numéro de canal MIDI
MIDI_Byte1,
MIDI_Byte2,
MIDI_Byte3; // groupe de 3 octets MIDI
void delai(void){
char i, j;
for(i=0;i<255;i++)
for(j=0;j<120;j++);
}
void clignote(void){
for(k=0;k<3;k++){
RA6 = 1;
delai();
RA6=0;
delai();
}
}
void Init_PIC(void){
OSCCON = 0b01111100; //osc 8 MHz
TRISA = 0b00100000; //port A output
PORTA = 0b00001010; // unselect DAC
TRISB = 0b11000100;
ANSEL = 0; //désactivation des convertisseurs A/N
OPTION = 0b00000011; //RBPU/INTEDG/T0CS/T0SE/PSA/PS2/PS1/PS0
}
void Init_Interrupt(void){
GIE = 1; //enables global interrupts
PEIE = 1; //enables all periph interrupts
RBIE = 0; // 0 = disables port change interrupt
RCIE = 0; //disable rx interrupts
TXIE=0; //disable tx interrupts
}
void Init_Serial(void){
SPBRG=15; //Value for 31250 bauds:((CLK/(16 * BAUD) -1))
BRGH=1; //High Speed
SYNC=0; //asynchronous
SPEN=1; //enable serial port pin
CREN=1; //enable reception
SREN=0; //no effect
RX9=0; //8-bit reception
}
void Send_SPI(void){
for(n=0;n<16;n++){
SCK = 0;
Tx_DATA = Tx_DATA <<1> 4095) Tx_DATA = 4095;
Tx_DATA = Tx_DATA + DACa;
RA3 = 0;
Send_SPI();
RA3 = 1;
}
void PlayCTRL(void){
Tx_DATA = MIDI_Byte3 << 5; //only the first 6 bits are used (0-5V)
Tx_DATA = Tx_DATA + DACb;
RA3 = 0;
Send_SPI();
RA3 = 1;
}
void Gate(void){
nb_Notes++;
LED = 1;
TRIG = 1;
GATE = 1;
TMR0IF = 0; //disable interrupt flag
TMR0 = 0;
TMR0IE = 1; //enable Timer0 interrupt
}
void FinNote(void){
nb_Notes--;
if(nb_Notes==0){
LED = 0;
TRIG = 0;
GATE = 0;
}
}
void interrupt Timer(void){
TMR0IE = 0; //disable Timer0 interrupt
TMR0IF = 0; //disable interrupt flag
TRIG = 0;
}
void TestsMIDI(void){
switch(MIDI_Byte1){
case 0x90: // Note On
if(MIDI_Byte3==0) FinNote();
else {
Note_VAL = MIDI_Byte2-24; //Le do grave a la valeur 24 et pas 0
Note_VAL = Note_VAL * 83.3333; //83.3333 = 1 V/oct /12
PlayNote(); //on joue la note
Gate();
}
break;
case 0x80: // Note Off
FinNote();
break;
case 0xE0: // pitch wheel
Pitch_Wheel_VAL = MIDI_Byte3 * 2.644;
PlayNote();
break;
case 0xB0: //Modulation
if(MIDI_Byte2==1) // Est ce bien la molette de modulation ?
PlayCTRL();
}
}
void clear_usart_errors(void){
if (OERR){
CREN=0;
CREN=1;
}
if (FERR){
Rx_DATA=RCREG;
TXEN=0;
TXEN=1;
}
}
main(){
Init_PIC();
Init_Serial();
Init_Interrupt();
nb_Byte=0;
nb_Notes = 0;
Pitch_Wheel_VAL = 167;
clignote();
while(MIDI_Byte1!=0x90){ //Autolearn MIDI Channel
PlayNote();
if(RCIF){
clear_usart_errors();
Rx_DATA=RCREG;
MIDI_Byte1 = Rx_DATA&0xF0;
MIDI_Chnl = Rx_DATA&0x0F;
}
}
for (;;){ // boucle infinie : on peut jouer tant qu'on veut !!
if(RCIF){
clear_usart_errors();
Rx_DATA=RCREG;
switch(nb_Byte){
case 0:
if(!(Rx_DATA&0x80)&& MIDI_Byte1){ //Test de Running Status
nb_Byte = 2;
MIDI_Byte2 = Rx_DATA;
}
else{
Rx_DATA = Rx_DATA - MIDI_Chnl;
switch(Rx_DATA){
case 0x90: // Note On
MIDI_Byte1=Rx_DATA;
nb_Byte++;
break;
case 0x80: // Note Off
MIDI_Byte1=Rx_DATA;
nb_Byte++;
break;
case 0xE0: // pitch bend
MIDI_Byte1=Rx_DATA;
nb_Byte++;
break;
case 0xB0:; //Modulation
MIDI_Byte1=Rx_DATA;
nb_Byte++;
break;
case 0xFE: //Active Sensing
break;
default:
MIDI_Byte1 = 0;
}
}//if running status
break;
case 1:
MIDI_Byte2=Rx_DATA;
nb_Byte++;
break;
case 2:
MIDI_Byte3=Rx_DATA;
nb_Byte = 0;
TestsMIDI();
}//switch(nb_Byte)
}//if(RCIF)
}//for
}//main
|
i hope we understand each other
sorry if were not _________________ http://www.myspace.com/mgmtrance |
|
Back to top
|
|
|
elmegil
Joined: Mar 20, 2012 Posts: 2177 Location: Chicago
Audio files: 16
|
Posted: Tue May 19, 2015 7:17 pm Post subject:
|
|
|
I see the confusion
The fragment I posted is from the TestMIDI routine, and I did not post the actual correction, I just noted it needed to be made an integer operation.
Note that I did make some other minor changes because I am compiling with the free XC8 compiler rather than Hi-Tech C.
Here is the corrected code, in its entirety:
Code: |
/*
Logiciel de gestion du module MIDI CV/Gate ACS Lite version
Alain COUPEL 11 novembre 2008
PORT A : 0= output, 1= input
RA0 TRIGGER 0
RA1 Select DAC2 0
RA2 SDI 0
RA3 Select DAC1 0
RA4 SCK 0
RA5 MCLR 1 input pour reset
RA6 LED 0
RA7 GATE 0
TRISA = 0b00100000
PORT B :
RB0 NC 0
RB1 NC 0
RB2 Rx 1 INPUT Rx MIDI
RB3 NC 0
RB4 NC 0
RB5 NC 0
RB6 NC 1
RB7 NC 1
TRISB = 0b11000100
*/
//#include<htc> //Compilateur Hi-Tech PICC std
#include <stdio>
#include <stdlib>
#include <xc>
#include <pic16f88>
// options are different between Hi-Tech C & XC8, in particular complaining about not having FOSC_INTOSCIO
//__CONFIG(INTIO &WDTDIS & PWRTEN &MCLREN & UNPROTECT & BORDIS & FCMDIS);
__CONFIG(MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & WDTE_OFF & PWRTE_ON & LVP_OFF & DEBUG_OFF & FOSC_INTOSCIO);
#define TRIG RA0 //Trigger output
#define SDI RA2 //SPI Data
#define CI1 RA3 // DAC select
#define SCK RA4 //SPI Clock
#define LED RA6 //LED output
#define GATE RA7 //Gate output
#define DACa 0b0001000000000000 // = 0x1000 DACa select
#define DACb 0b1001000000000000 // = 0x9000 DACb select
int
Note_VAL, //
Tx_DATA, // Data to transfer
Pitch_Wheel_VAL;
unsigned char
k, n,
nb_Byte, //Bytes number of the MIDI message
nb_Notes, // Number of notes played simultaneously
Rx_DATA,
MIDI_Chnl, // Num?ro de canal MIDI
MIDI_Byte1,
MIDI_Byte2,
MIDI_Byte3; // groupe de 3 octets MIDI
void delai(void) {
char i, j;
for (i = 0; i < 255; i++)
for (j = 0; j < 120; j++);
}
void clignote(void) {
for (k = 0; k < 3; k++) {
RA6 = 1;
delai();
RA6 = 0;
delai();
}
}
void Init_PIC(void) {
OSCCON = 0b01111100; //osc 8 MHz
TRISA = 0b00100000; //port A output
PORTA = 0b00001010; // unselect DAC
TRISB = 0b11000100;
PORTB = 0b00000000;
ANSEL = 0; //d?sactivation des convertisseurs A/N
OPTION_REG = 0b00000011; //RBPU/INTEDG/T0CS/T0SE/PSA/PS2/PS1/PS0
}
void Init_Interrupt(void) {
GIE = 1; //enables global interrupts
PEIE = 1; //enables all periph interrupts
RBIE = 0; // 0 = disables port change interrupt
RCIE = 0; //disable rx interrupts
TXIE = 0; //disable tx interrupts
}
void Init_Serial(void) {
SPBRG = 15; //Value for 31250 bauds:((CLK/(16 * BAUD) -1))
BRGH = 1; //High Speed
SYNC = 0; //asynchronous
SPEN = 1; //enable serial port pin
CREN = 1; //enable reception
SREN = 0; //no effect
RX9 = 0; //8-bit reception
}
void Send_SPI(void) {
for (n = 0; n < 16; n++) {
SCK = 0;
Tx_DATA = Tx_DATA <<1> 4095) Tx_DATA = 4095;
Tx_DATA = Tx_DATA + DACa;
RA3 = 0;
Send_SPI();
RA3 = 1;
}
void PlayCTRL(void) {
Tx_DATA = MIDI_Byte3 << 5; //only the first 6 bits are used (0-5V)
Tx_DATA = Tx_DATA + DACb;
RA3 = 0;
Send_SPI();
RA3 = 1;
}
void Gate(void) {
nb_Notes++;
LED = 1;
TRIG = 1;
GATE = 1;
TMR0IF = 0; //disable interrupt flag
TMR0 = 0;
TMR0IE = 1; //enable Timer0 interrupt
}
void FinNote(void) {
nb_Notes--;
if (nb_Notes == 0) {
LED = 0;
TRIG = 0;
GATE = 0;
}
}
void interrupt Timer(void) {
TMR0IE = 0; //disable Timer0 interrupt
TMR0IF = 0; //disable interrupt flag
TRIG = 0;
}
void TestsMIDI(void) {
switch (MIDI_Byte1) {
case 0x90: // Note On
if (MIDI_Byte3 == 0) FinNote();
else {
|
Code: |
Note_VAL = MIDI_Byte2 - 24; //Le do grave a la valeur 24 et pas 0
//Note_VAL = Note_VAL * 83.3333; //83.3333 = 1 V/oct /12
// use integer math instead; the slowdown causes dropped notes and hanging gates
// with some MIDI sources
Note_VAL = Note_VAL * 250;
Note_VAL = (int) (Note_VAL / 3);
|
Code: |
PlayNote(); //on joue la note
Gate();
}
break;
case 0x80: // Note Off
FinNote();
break;
case 0xE0: // pitch wheel
Pitch_Wheel_VAL = MIDI_Byte3 * 2.644;
PlayNote();
break;
case 0xB0: //Modulation
if (MIDI_Byte2 == 1) // Est ce bien la molette de modulation ?
PlayCTRL();
}
}
void clear_usart_errors(void) {
if (OERR) {
CREN = 0;
CREN = 1;
}
if (FERR) {
Rx_DATA = RCREG;
TXEN = 0;
TXEN = 1;
}
}
main() {
Init_PIC();
Init_Serial();
Init_Interrupt();
nb_Byte = 0;
nb_Notes = 0;
Pitch_Wheel_VAL = 167;
clignote();
while (MIDI_Byte1 != 0x90) { //Autolearn MIDI Channel
PlayNote();
if (RCIF) {
clear_usart_errors();
Rx_DATA = RCREG;
MIDI_Byte1 = Rx_DATA & 0xF0;
MIDI_Chnl = Rx_DATA & 0x0F;
}
}
for (;;) { // boucle infinie : on peut jouer tant qu'on veut !!
if (RCIF) {
clear_usart_errors();
Rx_DATA = RCREG;
switch (nb_Byte) {
case 0:
if (!(Rx_DATA & 0x80) && MIDI_Byte1) { //Test de Running Status
nb_Byte = 2;
MIDI_Byte2 = Rx_DATA;
} else {
Rx_DATA = Rx_DATA - MIDI_Chnl;
switch (Rx_DATA) {
case 0x90: // Note On
MIDI_Byte1 = Rx_DATA;
nb_Byte++;
break;
case 0x80: // Note Off
MIDI_Byte1 = Rx_DATA;
nb_Byte++;
break;
case 0xE0: // pitch bend
MIDI_Byte1 = Rx_DATA;
nb_Byte++;
break;
case 0xB0:; //Modulation
MIDI_Byte1 = Rx_DATA;
nb_Byte++;
break;
case 0xFE: //Active Sensing
break;
default:
MIDI_Byte1 = 0;
}
}//if running status
break;
case 1:
MIDI_Byte2 = Rx_DATA;
nb_Byte++;
break;
case 2:
MIDI_Byte3 = Rx_DATA;
nb_Byte = 0;
TestsMIDI();
}//switch(nb_Byte)
}//if(RCIF)
}//for
}//main
|
|
|
Back to top
|
|
|
isak
Joined: Dec 13, 2009 Posts: 847 Location: Israel
Audio files: 18
|
Posted: Tue May 19, 2015 8:15 pm Post subject:
|
|
|
Ok, got it
So your minor changes of the code is fixing what exactly? _________________ http://www.myspace.com/mgmtrance |
|
Back to top
|
|
|
elmegil
Joined: Mar 20, 2012 Posts: 2177 Location: Chicago
Audio files: 16
|
Posted: Tue May 19, 2015 10:52 pm Post subject:
|
|
|
A floating point math operation (83.333 * whatever it was) is very expensive on a PIC because there is no floating point coprocessor. So it has to link in a library that has (probably) dozens of instructions to accomplish the multiplication, plus time to do a subroutine call and return. This takes some significant time to run (in processor time), and while I haven't looked at the code I wouldn't be surprised if it also takes measures to ensure it isn't interrupted, for example, by the serial port service routine.
So the reason you're getting stuck notes is that the processor is busy doing floating point math when it needs to be accepting incoming serial messages, and so those incoming messages occasionally get dropped.
If you instead do the math strictly as integers (and in the end, you have to end up with an integer anyway, the DAC doesn't understand floating point math), it can be done in-line, and with relatively few instructions. For example multiply times 250 can be done as multiply times 125 then left shift one bit. Similarly integer division can be done in line, efficiently, and often with shifts. And if we guess that there are things blocking interrupts int he FP library, there definitely would not be in any in-line integer math.
It goes faster and is less prone to possible bad interactions with the interrupts driving the UART, and in my testing I was entirely unable to get any notes to get stuck the same way I could with the floating point math.
Trust me, this insight was hard-won, I spent quite a while trying to figure out where it was dropping the incoming stream, and initially it was just a lucky guess as to what would be tying up the CPU enough to drop bytes. Once I found it, the explanation seemed obvious, but until I made the leap it was far from it. |
|
Back to top
|
|
|
isak
Joined: Dec 13, 2009 Posts: 847 Location: Israel
Audio files: 18
|
Posted: Tue May 19, 2015 11:57 pm Post subject:
|
|
|
WOW
You really got to the bottom of this stuck notes, haa?
Ok, I got it.
Last 2 questions please.
1.Why you divide the code to 3 parts? the middle small code, is it the correction?
2. Can you please upload the whole code in one piece so I won't make mistakes trying to understand what goes where?
Thanks man _________________ http://www.myspace.com/mgmtrance |
|
Back to top
|
|
|
elmegil
Joined: Mar 20, 2012 Posts: 2177 Location: Chicago
Audio files: 16
|
|
Back to top
|
|
|
|