English Version
Spanish Version
French Version
MIDIbox Hardware Platform, IIC MIDI Module
The IIC MIDI module provides a bridge between IIC and MIDI, and mainly consists of a PIC16F88 microcontroller from Microchip, which runs with a special firmware (not MIOS!).
IIC and MIDI are both serial interfaces:
- IIC (Inter-IC, the abbreviation "I2C" is oftenly used as well) is qualified for fast data exchange between multiple devices via a single clock and data line
- MIDI (Musical Instrument Digital Interface) is the asynchrous interface you propably know very well (otherwise you wouldn't be interested in this site ;-)
Combining these two interfaces opens the possibility to access multiple MIDI In and Out ports from a single microcontroller. In addition, the IIC MIDI "slaves" are doing some high level MIDI protocol handling in order to relieve the "master" core from time and memory intensive tasks. This improves the overall performance.
The firmware has been prepared for up to 4 IIC MIDI slaves connected via the IIC bus to a single master:
Each slave needs an unique address, which has to be be selected with two jumpers (binary coded). In theory up to 127 slaves could be attached to the bus by altering the base address within the firmware, but in practice the bus load could increase to a level, where buffers overflow and data get lost. Performance considerations are a complex topic, and I don't know if I will ever find the time to explain all the aspects in detail here, but I can say, that there shouldn't be performance issues with up to 4 IIC_MIDI slaves - this is the configuration I'm using for my own MIDI Router, which will be heavily tested under reallife conditions in the next years :)
As a sidenote it should be mentioned, that not only MBHP_IIC_MIDI modules can be attached to the IIC bus, but also BankSticks (IIC EEPROMs), IIC LCDs or even other microcontrollers with IIC slave interface - the MBHP_IIC_MIDI firmware can be used as template for such "gadgets", like special sensors, analog/digital IO extensions, bridges to RS232, PS2 ports or... how about ethernet, a wireless link or a modem? ;-)
Use Cases
-
The module has been developed with following use cases in mind:
- as "workaround" for the annoying EUSART bug, which exists in PIC18F4620 A3 and A4 (64k flash device) and PIC18F4550 A3 (USB device), and which affects the reliability of the MIDI Out port.
Note that this silicon bug doesn't exist in newer chip revisions anymore
- as basis for a flexible MIDI Router
- as simple possibility to get additional, independent MIDI In and Out ports for projects like MIDIbox SEQ and MIDIbox SID
- as template for even more powerful gadgets, developed by members of the MIDIbox community! :-)
Configuration and Interconnections
-
The MBHP_IIC_MIDI schematic contains a superset of all components which are supported by the firmware.
There is also a reduced "OUT only" version available, which only contains the parts that are required for a single MIDI Out port - this version is especially interesting for people, who want to use the module as workaround for the EUSART bug. Note that this circuit could be downstripped even more by removing the Power and Tx LED, but in this case debugging could get difficult. Assumed, that this minimal circuit is built on a vector- or stripeboard, the costs for the PIC16F88, 20 MHz crystal, 4 caps, 4 resistors and 2 LEDs are just only ca. 5 EUR in total!
Back to the complete version: the MBHP_IIC_MIDI address needs to be selected with jumpers at the J3 port. By default, both jumpers should be stuffed in order to select address 0x10. By removing jumpers, address 0x12, 0x14 or 0x16 can be selected. Each slave module needs an unique address at the IIC bus, therefore never use the same configuration for more than one module!
Port J4 is a "MIDIbox Link" port, which provides MIDI IN/OUT at TTL level. It can be connected to a MBHP_LTC module in order to duplicate the MIDI OUT, and to get a MIDI THRU. J4 can also be used for a direct connection to another core module without using optocouplers.
Port J1 is currently not used, it's free for customizations in the firmware.
Last not least J2: this is the IIC port which is realized as a DIL header in order to simplify the 1:1 bus wiring between slaves and master. 4 of these pins (Vs/Vd for power, SC/SD for IIC) have to be connected to the pins with the same name at CORE::J4 and to IIC_MIDI::J2 of the other slaves. The RI# output is a special signal which identicates, that the receive buffer has been filled. It will only be used by a small number of applications and need to be connected to the core module, further details can be found at the appr. project pages. If no special hint is given, let this pin open. Never connect the RI# lines of the slaves together, because this will cause a short circuit!
A simplified interconnection diagram:
Imortant note for MBHP_CORE_V2 users: an additional 1k pull-up resistor is required between the Vd and SC line, it has to be directly soldered at CORE::J4 in order to allow "clock stretching". Thats a method to delay serial transfers when a slave cannot response immediately on a master request. The pull-up resistor for the SD line is already available at the core module (CORE::R2).
MBHP_CORE_V3 users will notice, that both pull-up resistors are already available - no additional resistor needs to be added!
PIC16F88 programming adapter
-
Propably SmashTV and Mike will provide pre-programmed PIC16F88 in future, but so long this service is not available, you need to "burn" the firmware into the PIC16F88 by yourself (alternatively you could ask somebody in the forum) by using a PIC programmer like MBHP_BURNER.
For 40 pin programmers an adapter to 18 pin is required, the schematic is located here.
Pictures of the programming adapter:
The programming voltage is 13.1V (PIC16F device!), the programming software PBrenner has to be used.
MBHP_IIC_MIDI transfer protocol
-
Details about the I2C protocol are described in the I2C bus specification of Philips. So long you are using MIOS functions to access the module, you don't need to take care about these bitstreams - just continue at the next chapter which describes the access algorithms.
Slave address: the address could be confusing, therefore it will be mentioned first, that the MBHP_IIC_MIDI address is the IIC slave address leftshifted one (multiplied by two). Example: IIC address 0x08 is MBHP_IIC_MIDI address 0x10. This is to simplify the programming when appending the R/W# bit to the address. Thats also the reason, why MBHP_IIC_MIDI addresses are always even numbers.
If 0x10 is sent after a Start condition, we are starting a write operation on the first MBHP_IIC_MIDI module, when 0x11 is sent, we are starting a read operation.
Transfers to MIDI OUT: Transfers to the OUT port are "Master Write" operations. After the master has sent the Start condition and the address, it continues with the data bytes, which are directly forwarded to the MIDI Tx buffer of the MBHP_IIC_MIDI module. After the last byte a Stop condition has to be sent in order to release the bus:
The Tx buffer has a size of 96 bytes. Once the buffer is full, the slave will respond with a NAK (not acknoweledge, A bit=1). In this case, the master needs to send a Stop condition, thereafter it can retry.
A Restart condition (start without Stop condition) is not allowed due to a silicon bug in the SSP module of most PIC16F derivatives.
The data value "0xff" (255 decimal) has a special purpose, because it is used as command mode token. The command mode has been prepared for future expansions of the firmware. Following sequences are currently supported:
- FF 00: enters and exits command mode, no further action.
- FF FF: enters command mode, sends 0xff over MIDI OUT, exits command mode.
- FF <cmd> <data1> ... <data_n>: enters command mode, branches to IIC_CMD_Handler in iic_cmd.asm on each byte being received. The maximum number of data bytes has to be determined within the handler, currently the handler just exits command mode after the first data byte.
The command mode leads to following requirement: if 0xff ("MIDI Reset") should be forwarded to the MIDI OUT port, the master has to sent it twice via IIC.
Transfers from MIDI IN: the master can either poll the receive state via IIC, or it can check the low-active RI# output of the MBHP_IIC_MIDI module (fastest solution, but requires an additional signal connection to the master). In case of polling via IIC, a Start condition and the address has to be sent. The R/W# flag must be 1 (Master Read operation). Thereafter the master can read the first byte which contains the "package type". If it is 0, the master can abort the transaction by sending NAK and a Stop condition:
If the package type is not zero, the master has to read up to three additional bytes:
The coding of a "package" is inspired from the USB MIDI specification. Using this format has the advantage, that a MIDI->IIC->USB router just only needs to forward the package to the IN pipe of the USB host (the package type is the CIN, and the cable number can be ORed to the high-nibble). It also simplifies the implementation of a MIDI merger, because for all packages beside of SysEx, the forwarding streams don't need to be locked - MBHP_IIC_MIDI transmits the complete MIDI event:
Type |
Size |
Description |
0x00 |
3 |
No package - all bytes are zero |
0x01 |
3 |
reserved |
0x02 |
2 |
two-byte system common messages like MTC, Song Select, etc. |
0x03 |
3 |
three-byte system common messages like SPP, etc. |
0x04 |
3 |
SysEx starts or continues |
0x05 |
s 1 |
Single-byte system common message or sysex sends with following single byte |
0x06 |
2 |
SysEx sends with following two bytes |
0x07 |
3 |
SysEx sends with following three bytes |
0x08 |
3 |
Note Off |
0x09 |
3 |
Note On |
0x0a |
3 |
Poly-Key Press |
0x0b |
3 |
Control Change |
0x0c |
2 |
Program Change |
0x0d |
2 |
Channel Preassure |
0x0e |
3 |
PitchBend Change |
0x0f |
1 |
Single Byte |
MBHP_IIC_MIDI access algorithms
-
With MIOS V1.9 and higher, the MBHP_IIC_MIDI device can be accessed in the following ways:
MIOS Tx Buffer Redirection: MIOS_MIDI_TxBufferPut operations can be redirected to a slave by selecting the address with MIOS_MIDI_InterfaceSet function:
// send MIDI clock over internal MIDI Out with normal baudrate
MIOS_MIDI_InterfaceSet(MIOS_MIDI_INTERFACE_COMMON);
MIOS_MIDI_TxBufferPut(0xf8);
// send MIDI clock over MBHP_IIC_MIDI with address 0x10
MIOS_MIDI_InterfaceSet(0x10);
MIOS_MIDI_TxBufferPut(0xf8);
// switch back to default interface
MIOS_MIDI_InterfaceAutoSet();
Default Tx Redirection: with MIOS Bootloader V1.2 and higher, Tx buffer operations will be automatically redirected to a MBHP_IIC_MIDI module by setting the address in byte 5 if the ID header. ID Example: 0000000000100000: sends outgoing MIDI data to MBHP_IIC_MODULE with address 0x10. The address can still be changed with the MIOS_MIDI_InterfaceSet during runtime, and it can be set back to the default value with MIOS_MIDI_InterfaceAutoSet
Receive function: following function can be used to receive a MIDI package:
// global array which stores the package
unsigned char iic_midi_package[4];
/////////////////////////////////////////////////////////////////////////////
// This function polls the given MBHP_IIC_MIDI module for a new package
// it returns != 0 on a new package, the data will be copied into the
// global array "iic_midi_package[4]" (this is to speed up parameter passing)
/////////////////////////////////////////////////////////////////////////////
unsigned char IIC_MIDI_Receive(unsigned char addr) __wparam
{
// start IIC access
MIOS_IIC_Start();
// send address, abort if NAK received
if( !MIOS_IIC_ByteSend(addr | 1) ) {
MIOS_IIC_Stop();
return 0;
}
// receive package type, abort if type is 0x00
if( (iic_midi_package[0] = MIOS_IIC_ByteReceive()) == 0x00 ) {
MIOS_IIC_NakSend(); // abort transfer
MIOS_IIC_Stop(); // stop IIC
return 0;
}
MIOS_IIC_AckSend();
// receive three bytes
iic_midi_package[1] = MIOS_IIC_ByteReceive();
MIOS_IIC_AckSend();
iic_midi_package[2] = MIOS_IIC_ByteReceive();
MIOS_IIC_AckSend();
iic_midi_package[3] = MIOS_IIC_ByteReceive();
MIOS_IIC_NakSend();
// stop IIC access
MIOS_IIC_Stop();
return 1;
}
Transmit function: following function can be used to send a MIDI package:
// this table contains the number of bytes depending on the package type
const unsigned char iic_midi_type_bytes[16] = { 0,0,2,3,3,1,2,3,3,3,3,3,2,2,3,1 };
/////////////////////////////////////////////////////////////////////////////
// This function sends a package to the given MBHP_IIC_MIDI module
// the package content is expected in the global array iic_midi_package[4]
// 0 is returned if the module is not available
/////////////////////////////////////////////////////////////////////////////
unsigned char IIC_MIDI_Send(unsigned char addr) __wparam
{
unsigned char retry_ctr;
unsigned char i;
unsigned char num_bytes;
// start IIC access
MIOS_IIC_Start();
// send address
retry_ctr = 0;
while( !MIOS_IIC_ByteSend(addr) ) {
// slave has sent a NAK - retry 255 times
MIOS_IIC_Stop();
if( ++retry_ctr == 255 )
return 0;
MIOS_IIC_Start();
}
// send package
num_bytes = iic_midi_type_bytes[iic_midi_package[0] & 0x0f];
for(i=0; i<num_bytes; ++i) {
retry_ctr = 0;
while( !MIOS_IIC_ByteSend(iic_midi_package[i+1]) ) {
// slave has sent a NAK - retry
// the address needs to be sent again!
MIOS_IIC_Stop();
MIOS_IIC_Start();
while( !MIOS_IIC_ByteSend(addr) ) {
MIOS_IIC_Stop();
if( ++retry_ctr == 255 )
return 0;
MIOS_IIC_Start();
}
}
}
// stop IIC access
MIOS_IIC_Stop();
// the complete package has been transmitted
return 1;
}
Note that the IIC_MIDI_Send() function can be "beautified" by using a separate function for sending the address - I've choosen the long version to simplify the reading. An assembly optimized version can be found in the MIDI Router project.
Please note also, that this version doesn't take care about the special condition for sending a "0xff" byte over MIDI - the assembly optimized version will just be called recursively. This method would really "explode" the above example.
MIDI Routing: the above examples might look complex, but they simplify MIDI routing a lot - here a simple snippet, which forwards incoming packages from the first MBHP_IIC_MIDI module to the second:
/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS after startup to initialize the
// application
/////////////////////////////////////////////////////////////////////////////
void Init(void) __wparam
{
// enable clock stretching
MIOS_IIC_CtrlSet(0x01);
}
/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS in the mainloop when nothing else is to do
/////////////////////////////////////////////////////////////////////////////
void Tick(void) __wparam
{
if( IIC_MIDI_Receive(0x10) ) {
if( !IIC_MIDI_Send(0x12) ) {
MIOS_LCD_Clear();
MIOS_LCD_PrintCString("Slave 0x12 not connected");
MIOS_LCD_MessageStart(255);
}
}
}
Here a variant, which only forwards Control Change (CC) packages:
/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS in the mainloop when nothing else is to do
/////////////////////////////////////////////////////////////////////////////
void Tick(void) __wparam
{
if( IIC_MIDI_Receive(0x10) && iic_midi_package[0] == 0x0b ) {
if( !IIC_MIDI_Send(0x12) ) {
MIOS_LCD_Clear();
MIOS_LCD_PrintCString("Slave 0x12 not connected");
MIOS_LCD_MessageStart(255);
}
}
}
Download
-
Firmware |
File |
Size |
Description |
mbhp_iic_midi_v1_0c.zip |
23k |
This package contains the precompiled firmware and the source code for PIC16F88 |
Testing
A software loopback application (iic_midi_sw_loopback) can be found in the MIOS Download section, which scans for available slaves, and directly forwards incoming MIDI data to the output ports of the same MBHP_IIC_MIDI slaves. This is a perfect application to test the module(s), and the included iic_midi.asm/iic_midi.h files can be used as module driver for selfwritten applications as well.
More PICs
A single full stuffed MBHP_IIC_MIDI module connected to a MBHP_CORE (SmashTV's PCB version)
Two MIDI-Out only modules (SmashTV's PCB version)
Credits
Thank-you goes to SmashTV who created the PCB layout, and to Michael Klein who supplied me with several free prototype boards (great service!)
Last update: 2024-05-08
Copyright © 1998-2023, Thorsten Klose. All rights reserved.
|