Wireless Midi

Arduino + RFM69

Video: Wireless Midi on Vimeo

Wagner

Very nice. Did you build that organ?

Yes, I did.

https://www.youtube.com/watch?v=zNiVldLISxI

Super job and very nice setup. I'm a woodworker also.

Thank you steinie44
Woodworking is a passion of mine too.
The real woodwork on the organ is still to be made. It needs a nice cabinet.
The Organ is controlled by an Arduino mini. It decodes the midi line and activate solenoids underneath the pipes.

Wagner

Hi Wagner,

Beautiful work, the wireless midi link particularly caught my attention as such a system would solve many issues with my outdoor pyrophone. i wonder if you would be inclined to share your design and software?

Your hopefully

tanc (uk)

Hi Itanc,

Some details:

RFM69CW Anarduino from Anarduino MiniWireless Details

Assembly:

Wiring:

Tx Code (transmitter):

/*********************************************************/
/*                                                       */
/*                       WMidi Tx                        */
/*                      June  2014                       */
/*                  Anarduino + RFM69CW                  */
/*                                                       */
/*********************************************************/


#include <RHReliableDatagram.h>
#include <RH_RF69.h>
#include <SPI.h>

#define LEDG A0
#define LEDY A1
#define LEDR A2

#define RDMTX 1
#define RDMRX 2

#define LEDON   LOW
#define LEDOFF  HIGH


/*********************************************************/


RH_RF69 Radio;
RHReliableDatagram RdMngr(Radio,RDMTX);


byte MdSt;
byte MdBf[16];

unsigned long TmEr;


/*********************************************************/


void setup()
{     
 HwIni();
 MdIni();
 TmIni();
 RdIni();
 HwOky();
}


void loop()
{
 MdThr();
 TmThr();
}


/*********************************************************/


void HwIni(void)
{
 digitalWrite(LEDG,LEDOFF);  
 digitalWrite(LEDY,LEDOFF);  
 digitalWrite(LEDR,LEDOFF);  
 pinMode(LEDG,OUTPUT);     
 pinMode(LEDY,OUTPUT);
 pinMode(LEDR,OUTPUT);     
}


void HwOky(void)
{
 digitalWrite(LEDG,LEDON);  
}


void HwDat(byte t)
{
 digitalWrite(LEDY,(t)?LEDON:LEDOFF);
} 


void HwErr(byte t)
{
 digitalWrite(LEDR,(t)?LEDON:LEDOFF);  
}
 

/*********************************************************/


void MdIni(void)
{
 MdSt=0;
 Serial.begin(31250);
}

 
void MdThr(void)
{
 if(Serial.available())
  MdRxd(Serial.read());
}


void MdRxd(byte b)
{
 if(b&0x80)
  {
   MdSt=0;
   switch(b&0xf0)
    {
     case 0x80:MdSt=1;break;                 // Note Off
     case 0x90:MdSt=1;break;                 // Note On
     case 0xB0:MdSt=1;break;                 // Control
    }
   if(MdSt)
    MdBf[0]=b;
  }
 else
  if(MdSt)
   {
    if(MdSt>1)                               // 2nd Byte (Velocity)
     {
      MdSt=1;
      MdBf[2]=b;
      RdTxd(MdBf,3);
     }
    else
     {                                       // 1st Byte (Note/Control)
      MdSt=2;
      MdBf[1]=b;
     }
   }   
}


/*********************************************************/


void RdIni(void)
{
 if(RdMngr.init())
 if (Radio.init())
  {
   RdMngr.setRetries(3);
   RdMngr.setTimeout(30);
   if(Radio.setFrequency(914.8))
    if(Radio.setModemConfig(RH_RF69::GFSK_Rb250Fd250))
     return;
  }
 HwErr(1);
 delay(1000);
 setup();                                     // Try again after 1 second 
}


void RdTxd(byte *p,byte n)
{
 HwDat(1);
 if(!RdMngr.sendtoWait(p,n,RDMRX))            // 1st try
  if(!RdMngr.sendtoWait(p,n,RDMRX))           // 2nd try
   TmErr();
 HwDat(0);
}


/*********************************************************/


void TmIni(void)
{
 TmEr=0;
}


void TmErr(void)
{
 HwErr(1);
 TmEr=millis()+1000;                        // Error time = 1 sec
}


void TmThr(void)
{
 if(TmEr)
  if(millis()>TmEr)
   {
    TmEr=0;
    HwErr(0);
   }
}

Rx Code (receiver):

/*********************************************************/
/*                                                       */
/*                       WMidi Rx                        */
/*                      June  2014                       */
/*                  Anarduino + RFM69CW                  */
/*                                                       */
/*********************************************************/


#include <RHReliableDatagram.h>
#include <RH_RF69.h>
#include <SPI.h>

#define LEDG A0
#define LEDY A1
#define LEDR A2

#define RDMTX 1
#define RDMRX 2

#define LEDON   LOW
#define LEDOFF  HIGH


/*********************************************************/


RH_RF69 Radio;
RHReliableDatagram RdMngr(Radio,RDMRX);

byte MdBf[16];

unsigned long TmEr;


/*********************************************************/


void setup()
{                
 HwIni();
 MdIni();
 TmIni();
 RdIni();
 HwOky();
}


void loop()
{
 RdThr();
 TmThr();
}


/*********************************************************/


void HwIni(void)
{
 digitalWrite(LEDG,LEDOFF);  
 digitalWrite(LEDY,LEDOFF);  
 digitalWrite(LEDR,LEDOFF);  
 pinMode(LEDG,OUTPUT);     
 pinMode(LEDY,OUTPUT);
 pinMode(LEDR,OUTPUT);     
}


void HwOky(void)
{
 digitalWrite(LEDG,LEDON);  
}


void HwDat(byte t)
{
 digitalWrite(LEDY,(t)?LEDON:LEDOFF);
} 


void HwErr(byte t)
{
 digitalWrite(LEDR,(t)?LEDON:LEDOFF);  
}
 

/*********************************************************/


void MdIni(void)
{
 Serial.begin(31250);
}

 
void MdTxd(byte *p,byte n)
{
 Serial.write(p,n);
}


/*********************************************************/


void RdIni(void)
{
 if(RdMngr.init())
  {
   RdMngr.setRetries(3);
   RdMngr.setTimeout(30);
   if(Radio.setFrequency(914.8))
    if(Radio.setModemConfig(RH_RF69::GFSK_Rb250Fd250))
     return;
  }
 HwErr(1);
 delay(1000);
 setup();                                     // Try again after 1 second 
}


void RdThr(void)
{
 if(RdMngr.available())
  RdRxd();
}


void RdRxd(void)
{
 byte l;
 
 l=16;
 HwDat(1);
 if(RdMngr.recvfromAck(MdBf,&l))
  MdTxd(MdBf,l);
 else
  TmErr();
 HwDat(0);
}


/*********************************************************/


void TmIni(void)
{
 TmEr=0;
}


void TmErr(void)
{
 HwErr(1);
 TmEr=millis()+1000;                        // Error time = 1 sec
}


void TmThr(void)
{
 if(TmEr)
  if(millis()>TmEr)
   {
    TmEr=0;
    HwErr(0);
   }
}

Wagner

thank you so much for such prompt generosity! i will inwardly digest and see how far i get!

Hi Wagner,

So I have been doing some reading . The module you have used here is an arduino and a tranciever in one, is that correct? If so how do you upload the sketch to it and can it run other code as well? I have built a bespoke MIDI decoder using an atmega328pu that listens to the midi stream and actuates solenoid valves and spark gap igniters accordingly.

My project is also a pipe organ of sorts and takes the form of a pyrophone (steel pipes with propane burners in that bottom). Due to its mechanical complexity I have elected to provide each tube with a decoder and due to its large scale a wireless data link will save a considerable wiring loom. As such if I can use one of your circuits to receive the data and decode it that would be a truly neat solution.

Is it possible to use this in a one to many format?

I have emailed the supplier you suggested to ask if they will ship to the uk but have not heard as yet. Its odd that when I search the uk for this module I can only find i tranciever by itself and not with an arduino attached.

I think your work is extremely satisfying to regard even over the web, which i am sure does not do it justice.

Thanks again

tanc

Hi Wagner,

which frequency modules did you use?

cheers

tanc

Hi Tanc

The arduino from the manufacturer, Hoperf, is exactly like an Arduino Mini Pro, plus a RF69 radio. For programing one uses an USB-Serial interface, like the Ft232.

Some pins are used to control the radio (SS, SCK, MOSI, MISO, D2, D5...), all the others are available. See Schematic at Anarduino MiniWireless Details

As I live in the US, I've used the 915 MHz version. For other countries, see the appropriate legislation ISM radio band - Wikipedia

For my home, the radios are programed to use the specific frequency 914.8 MHz. See the function RdIni() on the code. At 915.0 I had some interference with other 915 MHz devices, like my TV wireless headphone.

My application is a one-to-one communication, but the code can easily be changed to one-to-several. The library takes care of that option. Each node has its own address (RDMTX and RDMRX on my code); for sending a data packet, you specify the FROM and TO address on the send() functions. See RadioHead library at RadioHead: RHReliableDatagram Class Reference

Wagner

Hello Tanc,

Your project is interesting. The Pyrophone is new to me.

My organ has a more traditional concept, as it uses a single midi decoder for all the pipes. The decoder receives and accepts midi signals for one specific channel and each note is connected to a pipe.

See: Midi Decoder - Exhibition / Gallery - Arduino Forum

In this video, Harpsichord+Organ Midi - YouTube the midi is transmitted by the RFM69 from the laptop (TX) to the organ (RX) port Midi-In, the midi channel 5 is consumed by the organ and activate he solenoids. The midi stream is also retransmitted via the Midi-Thru port via cable to the Harpsichord where another midi decoder, this time in channel 0. actuate over the Harpsichord keys.

The radios are very good. I've experienced very little delays.

The only caveat is that they work at 3.3 V and requires a USB to serial FT232 that provides 3.3 V.

I've modified the boards to accept the standard 5 V by cutting a PCB track and adding a diode, like this (in red color):

Good luck,

Wagner

Some more info...

Hi Wagner,

Will I need one ft232 for each tranciever or just one for all?

I have ordered 3 units to attempt a 1 to 2 system.

Very Excited and grateful

cheers

tanc

Just one FT232 is enough. Like this one: FT232
Pay attention for the 3.3 V issue.

Wagner

Hi there Wagner,

tanc here (pyrophone). at last the mini wireless modules arrived today (3 months to ship and hope i dont need the rest in a hurry!). just wanted to say thanks again for sharing your work and i hope to prototype a 1tx and 2 rx in the next few days. i will let you know how it goes.

regards

tanc