Analog midi input and wire.h

Status
Not open for further replies.

danixdj

Well-known member
Hi, i have a problem, if i use a OLED display by i2c the reading data from the MIDI analog input is very slow, i don't understand why...

There is a procedure for increase MIDI priority or something similar?

P.S. If i use usbMIDI or not use OLED all works fast and fine.

Code:
----------------
#include <MIDI.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Wire.h>
#define OLED_RESET -1
Adafruit_SSD1306 display(OLED_RESET);

byte noteon, numberon;

void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
MIDI.begin(1);
MIDI.turnThruOff();
MIDI.setHandleNoteOn(MyHandleNoteOn);
MIDI.setHandleControlChange(MyCCFunction);
usbMIDI.setHandleNoteOn(MyHandleNoteOn);
usbMIDI.setHandleControlChange(MyCCFunction);}

void loop() {
display.clearDisplay();
while(MIDI.read());
while(usbMIDI.read());
display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,23); display.setTextColor(WHITE); display.println(noteon);display.print(numberon);
display.display();
}

void MyHandleNoteOn(byte channel, byte note, byte velocity) {noteon=note;}

void MyCCFunction(byte channel, byte number, byte value) {numberon = number;}

--------

Thank you.
 
On many LCD's clearing the display can be a slow operation. It is often faster to just erase the text that you wrote, rather than clearing the whole display.
 
Note: I have not done anything with Midi, so I don't know much about some of the stuff.

However my quick look at at the SSC1306 code, looks like your display uses a memory buffer to hold everything and when you call display.display() it outputs a everything to the screen. Don't know which display you have so don't know how many bytes get output and you are doing it all of the time.
If I look at your loop code I see:
Code:
void loop() {
    display.clearDisplay();
    while(MIDI.read());
    while(usbMIDI.read());
    display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,23); display.setTextColor(WHITE); display.println(noteon);display.print(numberon);
    display.display();
}
So every time you go through the loop, you clear the display and redraw.

Maybe change some of the code to use a changed flag. Maybe something like:
Code:
bool value_changed = false;
void loop() {
    while(MIDI.read());
    while(usbMIDI.read());
    if (value_changed) {
        display.clearDisplay();
        display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,23); display.setTextColor(WHITE); display.println(noteon);display.print(numberon);
        display.display();
        value_changed = false;
}

void MyHandleNoteOn(byte channel, byte note, byte velocity) {
    noteon=note;
    value_changed = true;
}

void MyCCFunction(byte channel, byte number, byte value) {
    numberon = number;
    value_changed = true;
}
Note: If I were doing it for myself I would probably change the callback functions to only set value_changed if the new value did not equal the old value.
 
Thank you KurtE!
Your it's a good solution but only for the example code... i'm making a efx system with 8 different efx, synthesizer with drums and the other functions... it's impossible use this... :(

I have 10 different menu, peak sensor (and display real time), i must to find a solution that make a priority to analog midi read..
 
MIDI read uses Tx/Rx pins.

Other than than I can't see how something works in usbMIDI but not MIDI
 
MIDI read uses Tx/Rx pins.

Other than than I can't see how something works in usbMIDI but not MIDI

Yes but there is a feature for reading fast USB always i think, because there aren't problem with usb midi and it's a serial communication also, i don't know what i must to do :(
 
Again I may be missing something, but my gut tells me, that the issue is not the priority of how fast that the system checks the hardware Serial port, but if I am guessing correct, it is your code:
Code:
while(MIDI.read());
That is then actually reading the input from the Serial ports buffered data and then calling your callback? If so the issue is more an issue of being able to get your callback called quicker.

If so the issue is with how the Adafruit_SSD1306 driver works. It caches everything into memory and when you call display it blasts the whole display in one shot:
which if your display is 128x64 bits, you are outputting: 128x64/8 bytes or 1024 bytes to the display and the code won't return until that is done. (Half that if you have the 128x32).

So this is an expensive operation. I believe this is I2C, so actually a few more bytes are transferred.. Where this code outputs 16 bytes per begin/endTransmission.

How to make this work? Not sure best way with this display.

Again I would try to minimize and only update display if something changes.

Also maybe try hacking the display code, to maybe try to add a call to yield in this loop and then try to process the midi code in the serial 1 event function (serial1Event ? )

Or see if how possible it would be to make a DMA version of this. But I am not an expert in DMA, so ...
 
Code:
byte noteon, numberon;
byte noteonL1;   // lag
...

if noteon != noteonL1 {
  display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,23); display.setTextColor(WHITE); 
  display.println(noteon);display.print(numberon);
}
noteonL1 = noteon; // set lag
....
Something like this??
 
Maybe, it also may depend on your other code. That is if you are checking 8 inputs and maybe updating the display, then maybe during your refresh cycle you see if anything has updated. If so update all of the changed things and then only call display.display once to update all of them. But again this still be slow...
 
Code:
byte noteon, numberon;
byte noteonL1;   // lag
...

if noteon != noteonL1 {
  display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,23); display.setTextColor(WHITE); 
  display.println(noteon);display.print(numberon);
}
noteonL1 = noteon; // set lag
....
Something like this??


Your idea for the lag is GREAT!!!! it works fine...

I use Wire.setClock(4800000); and 6 cycles before refresh display... now the display is very quickly and MIDI read is perfectly in time!
SOLVED !!!!!!!!

Thank you!!!

Code:
----------------
#include <MIDI.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Wire.h>
#define OLED_RESET -1
Adafruit_SSD1306 display(OLED_RESET);

byte noteon, numberon, lag;

void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
MIDI.begin(1);
MIDI.turnThruOff();
MIDI.setHandleNoteOn(MyHandleNoteOn);
MIDI.setHandleControlChange(MyCCFunction);
usbMIDI.setHandleNoteOn(MyHandleNoteOn);
usbMIDI.setHandleControlChange(MyCCFunction);
Wire.setClock(4800000);
}

void loop() {
lag++;
if (lag==6) {display.clearDisplay();}
while(MIDI.read());
while(usbMIDI.read());
display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,23); display.setTextColor(WHITE); display.println(noteon);display.print(numberon);
if (lag==6) {display.display(); }
if (lag==7) {lag=0;}
}

void MyHandleNoteOn(byte channel, byte note, byte velocity) {noteon=note;}

void MyCCFunction(byte channel, byte number, byte value) {numberon = number;}

--------
 
Status
Not open for further replies.
Back
Top