Maker Pro
Maker Pro

Sending MIDI signals via PIC's Usart module [SOLVED]

Hi.

I'm trying to send MIDI signal from a PIC microcontroller to plug any equipment to a DIN socket.
If anybody have ever done this, i'd like some informations about the way to do this.

I have a 3 pin connector to link to my external DIN socket, connected as on this shematic :
https://www.sonelec-musique.com/images3/electronique_interfaces_midi_out_001a.gif

I use a PIC18F26K22 and for transmission I use the USART module.
Recept doesn't interest me, I'm just trying to send this signal but I don't know what will be the equipment which will be downstream (otherwise it'd understand MIDI signals).

The original signal is read from a SD card by SPI connection. I have ever controlled that this reading is OK.

When I have to begin or stop a note, Midi standard works at 31250kHz and imposes this sequence (3 bytes) :
  • 0x8C to open a note, C being the channel (0-15) when we communicate with multiple instruments, or 0x9C to close a note.
  • 0xNN, to send what note to open (0-128)
  • 0xVV, the "velocity", corresponding to level at which note should be played for instrument which support it.

In the MIDI files, each message is separated by some bytes to indicate a delay to wait between the two messages.
My µC operates delays read in the Midi file and send "in time" the activations or deactivations of notes.

Here is my code :
Code:
// Ports config
// As datasheet says : "For all modes of EUSART operation, the TRIS control bits corresponding to the RXx/DTx and TXx/CKx pins should be set to ‘1’. The EUSART control will automatically reconfigure the pin from input to output, as needed."
TRICbits.TRISC6 = 1;
// I don't use receiver, it's pin (RC7) is used for another function and is set as an output.

// Usart config
TXSTA1 = 0x00; // 8bit transmission, asyncronous, low speed baud rate.
RCSTA1 = 0x80; // Enable serial port
BAUDCON1 = 0x00; // Idle state is high
SPBRG1 = 7; // working at 16MHz SPBRG = (Fosc/31250/64)-1
// Next I enable transmitter
TXSTA1birts.TXEN = 1;

// For sending a byte, I use this function, it's called 3 times in a row, to send the 3 bytes of a MIDI message :
void UART_Write(unsigned char Data) {
   // Wait for the end of an eventual current transmission
   while (!TXSTA1bits.TRMT);
   TXREG1 = Data;
}

When I send a signal, I can control with digital oscilloscope that this signal exists. Unfortunately, I tried to connect my MIDI cable to various equipments and it seems they never receive anything (or they don't understand the messages).

Could you help me to understand what happen, what isn't correctly configured or what is the error when sending my MIDI message ?
Should I send a "0 delay message" before each message to prevent the external equipment to understand my message as a delay ?

Thanks so much for your help.
 

(*steve*)

¡sǝpodᴉʇuɐ ǝɥʇ ɹɐǝɥd
Moderator
Perhaps I wasn't clear.

There seems to be quite a bit of information on the web concerning using the UART of a PIC to handle MIDI.

What have you tried (unsuccessfully) to fix your problem?

Off the top of my head, I would be ensuring that the speed, the parity, word length, and number/duration of start and stop pulses are configured correctly in the UART. I would also check that I don't have the transmit and receive backwards, that the correct voltage range is used, and that my ground is correct.

All that is OK?
 
I have just controlled than my signal seems like the signal sent by another equipment. But my oscilloscope is very limited (and/or i'm not aware about all it's functionalities).

What is the same :
  • Positions of 5V/Data/GND on the DIN connector, and seems correct.
  • Speed seems to be the same
  • Polarity is the same (idle is high)

What I'm not sure :
  • If I have to send à "0 delay" information before my messages. Even if MIDI documentation say no, I think it depends of how the external equipment is implemented.
  • If I have to send a start bit, a stop bit or parity bit. I can read in MIDI specifications that :
    With a data transmission rate of 31.25 Kbit/s and 10 bits transmitted per byte of MIDI data, a3-byte Note On or Note Off message takes about 1 ms to be sent.
    I understand I have to send a start and a stop bit but I'm not sure. For the moment I send my messages alone (without any start, stop or parity bits).
    Although, if I have to send a start and/or a stop bit, I imagine it have to be 0 (to be different than idle state) but I'm not sure...
Finally, my english beeing very poor, it explain why I don't find the correct informations...
Also, it's the first time I try to use the Usart module of PIC. Probably there is anything important I didn't understand correctly…
 
Last edited:
Thanks for these informations.

Reading again the PIC18f26k22's datasheet, I understand that start and stop bits are always sent when using Usart transmitter. Configuration only concerns usage of a 9th bit (polarity bit ?) and what is this 9th bit. According to MIDI documentation, I understand that this one isn't used.

So I think that my issue is elsewhere.
Here are the configuration bits I don't understand well in PIC's datasheet :

  • TXSTA1bits.TX9, cleared : I don't use the 9-bit transmission
  • TXSTA1bits.SENDB, cleared : To send a "break character", I don't know what is this one but I think I have not to use it... Or is it the "stop bit" ?

About last Steve's message :
  • What are the number/duration of startand stop bits. I don't find informations about this in PIC's datasheet. I understand that it's automatic and always one single bit.
  • MIDI protocol using one cable for transmission and one cable for reception (MIDI OUT/MIDI IN), I think it's impossible for data to be sent back on my transmission cable...
 
OK.
I try to test it with a minimum software. So I initialize my modules and just after write :
Code:
while (1) {
    CLRWDT();
    UART_Write(0b10101010);
}

My UART_Write function is the same as in my first message.
I've mesured by my oscillo the signal generated. Unfortunately, I can't export it to my computer and I've no camera to take a snapshot. So I've to draw the signal generated manually… :confused:

Here is :


As signal is idle high, I think that a 0V is a bit '1' and a 5V a bit '0'.
So, I can read :
  • a '1' start bit
  • my message (0b10101010)
  • a '0' stop bit
  • a final '0' bit which maybe correspond to the moment of the CLRWDT() instruction.
    [EDIT]No, after deactivating the WatchDog Timer and removing the CLRWDT() instruction, result is the same[/EDIT]
The 0/5V and the 0.12ms time are mesured by the oscilloscope. 0.12ms seems to bee a bit long.

After trying to do the same, with external 16MHz quartz (OSCCON = 0x70) instead of internal HFINTOSC set to 16MHz too (OSCCON=0x72), signal is the same but time mesured between 2 edges is 32µs...

Why ? I don't understand...
 
Last edited:

(*steve*)

¡sǝpodᴉʇuɐ ǝɥʇ ɹɐǝɥd
Moderator
32 us for a bit is exactly what you should expect for 31250 baud.

120us (0.12ms) is almost exactly 4 times longer.

Does it work with the crystal instead of the internal oscillator?
 
OK !!!:D

I found my f...ing mistake !
The finality of my µC is merge different MIDI signals.
For this, it read from a SD card and can receive signal by other ways.
Each port save its data in a separated large buffer.
My main loop run through each buffer, one by one and when a complete MIDI message is found, send it via Usart connexion.

My fault code, when sending the message :
Code:
for (i = 0; i < iRxByteCount; i++) UART_Write(arrRxNote[iRxByteCount]);
... :oops:
It sent 3 times the last read byte...

Obviously, the right code was :
Code:
for (i = 0; i < iRxByteCount; i++) UART_Write(arrRxNote[i]);
 
You asked at same time as me.

Yes I still have this problem. For saving power, I switch on internal oscillator whenever possible.
Normally, it's always working on the crystal when sending data. But in case of failure of the crysrtal, fail-safe PIC's internal module switch to internal oscillator.
So I'm going to try now to send my signal with internal oscillator. I don't know why it appears to be 4 times slower than crystal.

EDIT : it seems to work fine now, even working on internal oscillator... I don't what happened just before...
It seems that the problem appears when switching from one oscillator to the other one. I don't understand why, cause they work at the same speed.

Anyway, thank you so much for having tried to help me.
 
Last edited:
I think the good way will be not to stop the external oscillator... :D

In fact, according to datasheet, shutting off the crystal saves only 0.5mA. It could be interesting but at this rate, my battery should discharge in 316 hours in place of 300 hours...
It's without considering my various other module which consume some current, and without taking account of Idle and Sleep modes that I use too and which save much more current.

Just for information, my configuration is this one :
Code:
#pragma config CONFIG1H = 0xC3    // Oscillator Selection bits (2Speed-StartUp, Fail-Safe, HS External 16MHz)
    OSCCON = 0x72;      // Internal Oscillator selected, working at 16MHz

    // When I have to switch from a source to another one, I use this :
    OSCCONbits.SCS = 0b00;    // to enable the crystal
    OSCCONbits.SCS = 0b01;    // to disable crystal and work on internal oscillator...

PS : is there a way on this forum to mark this subject as "SOLVED" ?
 
Top