Tuesday, 28 August 2012

Thoughts on 'GPIO MIDI'

Lots of folks on the Pi forums have been talking about 'GPIO MIDI' vs. USB MIDI, my assumption was that they meant 'UART on the 0.1" pitch connector', as that seems to have become known as the 'GPIO' connector even though it pulls a lot more than GPIOs off the board. But of course it's perfectly feasible to implement a MIDI interface without the PIC to gearshift, just using a GPIO for bit-banging (or whatever the input side of bit-banging is - bint-banging??). But would it make any sense? And would it just kill the CPU stone dead?

So I whipped up a proof of concept MIDI input thread based on sampling a GPIO pin, fed direct from the output of the opto. And it's so not going to work, at least not without destroying the CPU. Bit-banged output is easy, just just usleep for a whole bit period. And once you've set up the stop bit you consume no cycles. Input on the other hand demands either an interrupt hooked onto the GPIO (which means an entire device driver, which means the kernel, and Hey Daddio I Don't Wanna Go ... )  or it requires oversampling of the line to align the sample point with reasonable accuracy at the centre of the incoming bit. Say 1/8 of a bit. Then once you are certain you've seen a start bit you can merrily usleep for a whole bit period until the byte is assembled. Which is OK if you are reading bytes all the time, or if your keyboard is guaranteed to be sending out Active Sensing bytes, but most modern keyboards don't, and that means the line is idle most of the time. Which means that your input handler is spending 99% of the time in the most CPU-heavy bit of code, the oversampled 'Has there definitely been a start bit yet?' state.

That means usleep(4) at the highest priority level.

Forever.

That'll bring you to your knees.

So there remain 3 MIDI possibilities -

a) MIDI will always need a gear-shifter to convert 31250 from the keyboard into 38400 for the UART - fine, I'll enter the Raspberry Pi MIDI interface business
b) USB will work well enough to not kill the CPU - fine, I just need to rework my code back into USB mode
c) The good guys in Pi land will publish a workaround to allow the UART to run natively at 3125 - fine, I don't need to change any code and I just pull the PIC out of the minterface and short its input to its output.

I really don't want a) to be the outcome, but at this moment it's all I have.

Fingers crossed for USB or a native 31250 UART mode.

UPDATE - so, I decided to do more that just lash up a proof of concept and read the code and shake my head - I complied it and ran it. Interesting result - the stock synth with UART MIDI consumed 43.2% of the CPU when idling (no notes being played). Same app but with a 'fake GPIO handler' running (i.e.

while (1) {
    usleep(4);
    call_some_functions(pretend_to_assemble_MIDI_bytes);
}

and usage went up to 61.5%. So the usleep(4) forever and ever at a higher priority than anything else is burning about 20% of the CPU. Which means that at £30 a Raspberry Pi is actually a not unreasonable choice for a bit-banging gearchanger for a PICless MIDI interface. 2 Pis, back to back, one just handing 31250 bytes to the other at 38400. A nice software solution for those who don't like to turn on a soldering iron.

 That's funny.

6 comments:

  1. hey have you tried to use wiringPi? https://projects.drogon.net/raspberry-pi/wiringpi/ It let's you use the pi like an arduino, you just need to import the lib in a c file. Might work nicely without killing the CPU. let me know

    ReplyDelete
  2. Maybe you missed my point, which is that unless you can trigger an interrupt off an edge, big banging (or whatever the input equivalent of bit-banging is actually called) will kill the CPU. Simple maths.

    ReplyDelete
  3. You can use poll() or select() on the GPIO /sys/ entry(ies), and have the kernel wake your process when the value changes. I would be surprised if the latency was low enough but it would be worth a shot, perhaps if your process was scheduled with realtime priority.

    ReplyDelete
    Replies
    1. Thanks for the tip - one for this weekend maybe!

      Delete
  4. Hey, I'm pretty sure the Raspberry's UART can run at almost any speed, but you need to configure a UART-clock in /boot/config.txt
    Here's a guide on how I did it for 1Mbaud, which should also work on the baudrate you need (you'd just need to calculate another uart_clock)
    http://fw.hardijzer.nl/?p=138

    ReplyDelete
  5. Frans-Willem - thanks, I will definitely take a look at this - if I just brutally downclock the thing by the right percentage then tell it to run at 38400 it should just work this way.

    ReplyDelete