Problemi con libreria midi

Buonasera a tutti, uso un arduino mega flashato con successo per la comunicazione usb-midi nativa (testato e funziona da dio) l'unica pecca e' che non posso usare alcune librerie create appositamente per leonardo etc etc. Sto lavorando ad un progetto, mi serve di avere un centinaio di pulsanti,10potenziometri e 4 encoder...
ho attaccato i pulsanti a dei multiplexer (CD74HC4067) , i potenziometri direttamente al MEGA, idem per gli encoder. Funziona tutto a mestiere finche lo testo singolarmente... ma quando provo pulsanti ed encoder insieme, che per funzionare usano la stessa libreria "midi", gli encoder scrivono male e lentamente i dati... non riesco a trovare una soluzione. Chiedo Aiuto!

Author of the MIDI_Controller library here, excuse my English.

Rotary encoders have to be polled frequently, otherwise you miss edges. If your code is busy polling multiplexers and 100 buttons, the time between encoder readings increases.

One possible solution is to change your code so it doesn't scan all buttons at once, but leaves some time in between to read the encoders.
Another approach is to use interrupts (either a timer interrupt or pin change interrupts) to ensure that no encoder pulses are missed, even while the main loop is busy with a function that takes multiple milliseconds.
You can have a look at this thread on how to do that:

See also Control Surface: Pin-Change-Interrupt-Encoders.ino and Control Surface: Timer-Interrupt-Encoders.ino.

Also keep in mind that sending MIDI is slow. Do you really need to send each message five times?

I'm really honored to talk with you, you save me a lot in my last project with ur library!!
I actually have seen your new "control surface" library but the encoders cant do what i want... i need that they send a 0 and 127 CCvalue 5 Times every step.
Unluckily i cant do this with ur library :confused:
Now i'm going to study this interrupt... but from what i can see, it will be pretty hard ahahahah

If u have some sort of tips to do that with your library i would be very grateful!!

yes, i have to do that to bypass a sort of "security" made by the productors of what i want control :slight_smile:

@gemini99xd , @PieterP : you are in the ITALIAN section of the forum, so ... I am already tolerating the use of the English language but ... at least, be so kind to other users, to use Google Translate or DeepL to put, in addition to the English text, also the Italian translation. Thanks.

Guglielmo

1 Like

Sono davvero onorato di parlare con te, mi hai risparmiato molto nel mio ultimo progetto con la tua libreria!!
In realtà ho visto la tua nuova libreria "superficie di controllo" ma i codificatori non possono fare quello che voglio ... ho bisogno che inviino un valore CC 0 e 127 5 volte ogni passaggio.
Sfortunatamente non posso farlo con la tua libreria :confused:
Ora studierò questa interruzione... ma da quello che posso vedere, sarà piuttosto difficile ahahahah

Se hai qualche consiglio per farlo con la tua libreria te ne sarei molto grato!!

Tieni inoltre presente che l'invio del MIDI è lento. Hai davvero bisogno di inviare ogni messaggio cinque volte?

Sì, devo farlo per aggirare una sorta di "sicurezza" fatta dai produttori di ciò che voglio controllare :slight_smile:

1 Like

Grazie, per il futuro metti tutto direttamente in un unico post :wink:

Guglielmo

Ho provato a testare gli encoders con solo 2 mux in serie e funzionano abbastanza bene, quindi si, il problema e' sicuramente un sovraccarico di lettura e scrittura... come posso modificare il mio codice affinchè gli encoders si prendano il loro tempo per lavorare e allo stesso tempo posso continuare ad usare i vari pulsanti? anche perche avvolte potrei doverli usare contemporaneamente...

I tried to test the encoders with only 2 muxes in series and they work quite well, so yes, the problem is definitely a reading and writing overload ... how can I modify my code so that the encoders take their time to work and at the same time can I continue to use the various buttons? also because sometimes I might have to use them at the same time ...

The Mega has plenty of ports, you need 5 of them to read 20 encoders, in the code below, I've used ports A, C, F, K and L, because their pins are nicely accessible.

e che porte sono A,C,F,K e L?
what ports are A,C,F,K and L ? i didn't find anything about it

this is want i need actually :

Unfortunately, you cannot use interrupts to detect changes of the buttons connected through the multiplexers. This is simply a consequence of how a multiplexer works internally.

Moving the multiplexers to an interrupt doesn't solve the underlying problem, which is that reading all multiplexers takes quite a long time compared to the encoders. Just moving it to an interrupt handler doesn't change that, it might even make it worse, because now you're dealing with very long interrupt handlers which is bad for other reasons as well.

If you draw a time line, this is the original scenario:

[mmmmmmmm][e][mmmmmmmm][e][mmmmmmmm][e] ...  (main loop)

where m is reading the multiplexers and buttons, and e is reading the encoders. The m part takes too long, so too much time passes between two updates of the encoders.

The solution I proposed is moving the encoders in a timer interrupt, which gives the following time line.

[mm   mm   mm   mm] [mm   mm   mm   mm]   ...  (main loop)
   [e]  [e]  [e]  [e]  [e]  [e]  [e]  [e] ...  (interrupt)

As you can see, this allows you to read the encoders more frequently, even though the reading of the buttons still takes a long time.

If you move the multiplexers into an interrupt handler, you get this:

          [e]          [e]          [e] ...  (main loop)
[mmmmmmmm]   [mmmmmmmm]   [mmmmmmmm]    ...  (interrupt)

This gives you the same timing as the first version without interrupts, so that won't work.

Traduzione automatica: I pin di I/O digitale sono disposti in un numero di porte a 8 bit. Vedere le etichette in https://content.arduino.cc/assets/Pinout-Mega2560rev3_latest.pdf (ad es. il pin 49 è PL0, o il primo bit della porta L). Vedi anche https://docs.arduino.cc/hacking/software/PortManipulation.


The digital IO pins are arranged in a number of 8-bit ports. See the pin labels in https://content.arduino.cc/assets/Pinout-Mega2560rev3_latest.pdf (e.g. pin 49 is PL0, or the first bit of port L). See also https://docs.arduino.cc/hacking/software/PortManipulation.

Traduzione automatica: Potresti provare a impostare l'argomento speedMultiply delle classi encoder su 5.
In alternativa, puoi utilizzare uno dei due esempi che ho collegato in precedenza ({Pin-Change,Timer}-Interrupt-Encoders.ino) per ottenere le posizioni degli encoder, quindi semplicemente tenere traccia dei delta e inviare manualmente i messaggi MIDI (nel tuo loop principale).


You could try setting the speedMultiply argument of the encoder classes to 5 (Control Surface: CCRotaryEncoder Class Reference).
Alternatively, you could use one of the two examples I linked to earlier ({Pin-Change,Timer}-Interrupt-Encoders.ino) to get the positions of the encoders, and then simply keep track of the deltas and send the MIDI messages manually (in your main loop).

Traduzione automatica: Dovrai intercalare la lettura dei mux con la lettura degli encoder, come spiegato nel thread “Control surface + library encoder”, o interrompendo manualmente i tuoi loop for o usando gli interrupt per interrompere il codice principale (o ad una certa frequenza fissa, o quando i pin degli encoder cambiano stato). Anche se l'accesso a tutti questi input è relativamente lento per un computer, sembrerà comunque istantaneo alla nostra percezione umana.


You'll have to interleave the reading of the muxes with the reading of the encoders, as explained in the “Control surface + library encoder” thread, either by manually breaking up your for loops or by using interrupts to interrupt the main code (either at a certain fixed rate, or when the pins of the encoders change state). Even though accessing all these inputs is relatively slow for a computer, it will still appear instantaneous to our human perception.

Sono a dir poco affascinato dalle tue spiegazioni, ma non essendo un vero e proprio programmatore sono in difficolta...

Non ho mai usato queste porte e da quello che mi hai linkato non ci ho capito praticamente nulla ahahahah scusami!

The digital IO pins are arranged in a number of 8-bit ports. See the pin labels in https://content.arduino.cc/assets/Pinout-Mega2560rev3_latest.pdf (e.g. pin 49 is PL0 , or the first bit of port L). See also https://docs.arduino.cc/hacking/software/PortManipulation .

Non so come fare questa cosa della lettura...

You'll have to interleave the reading of the muxes with the reading of the encoders
Comunque credo sia meglio usare le interrupt...

La tua libreria non va bene per me perche non da un 0ccvalue ma da 1 a 127!! senno' era perfetto!

You could try setting the speedMultiply argument of the encoder classes to 5 (Control Surface: CCRotaryEncoder Class Reference).

Mi hai dato molte opzioni, secondo te quel'è la migliore? cosi la studio e ci lavoro su!
Grazie mille delle spiegazioni e del tempo che mi stai dedicando!

TRANSLATE VERSION:
I am very fascinated by your explanations, but not being a real programmer I am in trouble ...

I have never used these ports and from what you linked me I did not understand practically anything ahahahah sorry!

The digital IO pins are arranged in a number of 8-bit ports. See the pin labels in [https://content.arduino.cc/assets/Pinout-Mega2560rev3_latest.pdf] (https://content.arduino.cc/assets/Pinout-Mega2560rev3_latest.pdf) (e.g. pin 49 is PL0 , or the first bit of port L). See also [https://docs.arduino.cc/hacking/software/PortManipulation] (https://docs.arduino.cc/hacking/software/PortManipulation).

I don't know how to do this reading thing ...

You'll have to interleave the reading of the muxes with the reading of the encoders
However I think it is better to use interrupts ...

Your library is not good for me because it does not give a 0ccvalue but from 1 to 127 !! otherwise it was perfect!

You could try setting the speedMultiply argument of the encoder classes to 5 ([Control Surface: CCRotaryEncoder Class Reference] (https://tttapa.github.io/Control-Surface-doc/Doxygen/d3/d62/ classCCRotaryEncoder.html # ac4ae9db8215502ab1eb932d68418f4e0)).

You have given me many options, in your opinion which is the best? so I'll study it and work on it!
Thank you so much for the explanations and the time you are dedicating to me!

Arduino mega have only 6 interrupt pin, but i have 4 encoder how can i do?

Mega, Mega2560, MegaADK 2, 3, 18, 19, 20, 21 (pins 20 & 21 are not available to use for interrupts while they are used for I2C communication)

i have probbably done with the itterrupt and work really fine
when i come back at home i will test better all code!!!

//INTERRUPT
attachInterrupt(digitalPinToInterrupt(18),Encoder1,CHANGE);
attachInterrupt(digitalPinToInterrupt(19),Encoder2,CHANGE);
attachInterrupt(digitalPinToInterrupt(20),Encoder3,CHANGE);
attachInterrupt(digitalPinToInterrupt(21),Encoder4,CHANGE);

Each digital pin corresponds to a bit in one of the microcontroller's registers. By reading the register, you access the state of these pins in your code.

This is what digitalRead() uses internally, but it's not used here because it's much faster to read all 8 pins of a port at the same time.


Traduzione automatica: Ogni pin digitale corrisponde a un bit in uno dei registri del microcontrollore. Leggendo il registro, accedi allo stato di questi pin nel tuo codice.

Questo è ciò che digitalRead() usa internamente, ma non è usato qui perché è molto più veloce leggere tutti gli 8 pin di una porta allo stesso tempo.

Non so come fare questa cosa della lettura...

This is explained in the links I posted earlier.


Traduzione automatica: questo è spiegato nei link che ho postato in precedenza.

Mi hai dato molte opzioni, secondo te quel'è la migliore? cosi la studio e ci lavoro su!
Grazie mille delle spiegazioni e del tempo che mi stai dedicando!

I'd recommend starting with one of the examples I posted earlier: Control Surface: Pin-Change-Interrupt-Encoders.ino and Control Surface: Timer-Interrupt-Encoders.ino
Get those basic examples working first, and understand what's going on. Once you can print the positions to the Serial monitor, sending the data over MIDI is trivial.


Traduzione automatica: Consiglierei di iniziare con uno degli esempi che ho postato in precedenza: Control Surface: Pin-Change-Interrupt-Encoders.ino e Control Surface: Timer-Interrupt-Encoders.ino
Fai funzionare prima quegli esempi di base e capisci cosa sta succedendo. Una volta che puoi stampare le posizioni sul monitor seriale, l'invio dei dati tramite MIDI è banale.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.