The firmware is basically an extension of Fatlimeys multiplexer code.
I read each of the 32 analogue inputs (8 per multiplexer, one multiplexer on each of the 4 analogue extension pins) into an array of bytes (the ADC gives us 10bit values, so I just right shift it by two bits to drop the 2 least significant bits). The first 12 values are passed to Fatlimeys existing superfader code (the only modification I made to this was to use uint8_t instead of uint16_t for each value, and to extend it from four superfaders to twelve). The rest are treated as buttons and I wrote some code to determine the button state (and transitions, since notes are only sent when the state changes). I do this by checking the current value against a threshold. There is no need for debounce code when using the analogue value.
The buttons are split into three groups (and a single specially treated "shift" button): 11 normal buttons, 4 bank buttons and 4 "global" bank buttons.
The bank buttons are rigged up so that the existing code for external banks mode reads their state and handles banking the midifighter as if they were connected directly to the digital expansion pins.
The "global" banks change the MIDI channel used by all other buttons (including the midifighter buttons), but not the knobs and faders. This is done by adding a global_bank value to the MIDI channel in the send code in midi.c, so if global_bank is 0, then the channel used is the one configured from the midifighter menu mode (3 by default), if global_bank is 1 then the channel is one greater than the selected one (4 by default) and so on.
When the shift button is pressed down, and a global bank button is pressed, then the MIDI channel is changed for the knobs and faders and works the same way as the global banks.
So, in summary, the code looks something like this (pseudocode):
Theres obviously a little more to it, but that should give a reasonable idea as to what we changed.Code:read MIDI input from USB, unchanged from the latest firmware source if (analogue expansion is enabled) { uint8_t adc_values[32]; for (i = 0 to 31) { select multiplexer read analog pin one into adc_values read analog pin two into adc_values read analog pin three into adc_values read analog pin four into adc_values } select global_bank MIDI channel static bool button_states[20]; for (i = 12 to 31) { bool button_changed = false; bool button_pressed = false; if (adc_values[i] < up_threshold && button_states[i - 12] == false) { button_changed = true; button_pressed = false; } else if (adc_values[i] > down_threshold && button_states[i - 12] == true) { button_changed = true; button_pressed = true; } if (button_changed) { button_states[i - 12] = button_pressed; if (i < 24) { if (i != shift_button) { // Normal button send midi note for button i-12, note on/off is button_pressed } else { // Shift button handle shift button } } else if (i < 28) { // Global banks if (button_pressed) { global_bank = i - 24; } } else { // Banks set button state bits so the external banks code can use it } } } send button state information to PIC select shift+global MIDI channel existing superfader code select global_bank MIDI channel } existing midifigfhter code for banks, buttons, leds etc
The PIC code is very simple, and our PIC24 is really overpowered for what its used for (we use a PIC24 instead of a cheaper PIC16 because I happened to have an unused one already). All it does is read single bit buttons states on PORTA and set the correct bit on PORTB, which is connected to LEDs. Thats it.
The input logic is something like this:
SS (slave select) is connected to midifighter digital pin 4 (the one not connected to multiplexers), the other three are connected to both the multiplexers and the PIC. A single LED state is sent through DAT (data) for each pulse on CLK (clock). ACK (acknowledge) is used for the PIC to tell the midifighter when it's ready for the next bit (rather than trying to time the clocks). The midifighter firmware then contains code like this:Code:wait for SS to become set wait for CLK to become set read DAT set (or unset) appropriate PORTB bit set ACK wait for CLK to become unset unset ACK repeat
The midifighter sends the bits in the order that is most convenient for the PIC, so it has to shuffle them a little first (as the buttons are connected in slightly different orders than the LEDs).Code:set SS set CLK set DAT to state of next LED wait for ACK to become set unset CLK wait for ACK to clear repeat for each LED unset SS
The LED states are determined in two ways:
For the normal buttons, including shift button, if the button is down, the LED is on.
For the bank buttons, only the LED for the current bank is on, the others are off.
The normal buttons could just as easily have been connected directly to an LED, but by having the midifighter control them, we can set them depending on MIDI input (eg, so traktor can control them), though our firmware does not yet do this.
There are a few more bugs to iron out, especially in the midifighter-PIC communication code and the midifighter code I wrote needs a major cleanup, but once this is done, we will most likely be releasing the code. Unfortunately I think we fried our midifighter so it will take a while before we can finish it.
Bookmarks