analog read sent as midi

Working to output analog value read from an expression pedal as a midi control change message.

// Pedal2Serial 04: Send to the computer the values read from
// analogue input 0 (expression pedal pot)
// Transmits new reading only when input value changes
// by at least 2 steps
// 04 after converting to 7-bit value (Continuous Controller level)
// O5 sends status, control type and value (MIDI msg) for each
// change
// 06 no more CR LF on each message
// baud rate set to standard 31250

#define SENSOR 0 // select the input pin for the
// sensor resistor

int val = 0; // variable to store the value coming
// from the sensor
int oldval = 0; // previous reading for comparison
byte CCval = 0; // Continuous Controller value for midi
byte StatChan = 176; // sets continuous controller mode, channel 1
byte CtrlSel = 7; // sets controller type, #7 (vol)

void setup() {

Serial.begin(31250); // open the serial port to send data back
// to the computer at 9600 bits per second
// set to 31250 for midi port
}

void loop() {

val = analogRead(SENSOR); // read the value from
// the sensor

if ( ! ((val <= oldval + 2) && (val >= oldval - 2))) {

CCval = (val / 8); // set Continuous Controller value

Serial.print(StatChan, BYTE); // send status byte with channel #
Serial.print(CtrlSel, BYTE); // send Control type #
Serial.print(CCval, BYTE); // print the value to
// the serial port

oldval = val;
}

delay(10); // wait 10ms between
// each send
}

Since the serial function returns before the character is actually done sending, I can easily generate new values much faster than they are sent. Then when I stop, it can take a few seconds for the accumulated values to finish sending. What I think I need is to have each analog read fully "sent" before another analog read is allowed. Is there any way I can do that?

Hi,

i think you are wrong. At a baud rate of 31250 it takes about 300us to send a character. You send 3 characters for a MIDI command, this needs 1 ms. In your loop you have a delay of 10ms after each sending, so the sending is completely done before the next one starts.
(this is true as long as you do not use flow control - MIDI does'nt use it).

Mike

about the comment,

i think you are wrong. At a baud rate of 31250 it takes about 300us to send a character. You send 3 characters for a MIDI command, this needs 1 ms. In your loop you have a delay of 10ms after each sending, so the sending is completely done before the next one starts.

I carefully read the reference entry about serial output, and it indicates that program execution resumes before transmission is complete. Were it not so, it would be impossible for me to fill the output buffer with analog reads faster than they are sent.

(this is true as long as you do not use flow control - MIDI does'nt use it).

What is flow control? Is it possible it might be useful for this app?

I carefully read the reference entry about serial output, and it indicates that program execution resumes before transmission is complete

From the Serial reference:

It will wait for one character to send, before going on to the next character. However the function returns before sending the last character

That mean the function writes the last character to the UART Tx register and then returns. The last character will finish transmission about 320us later.

From the Serial reference:
Quote:
It will wait for one character to send, before going on to the next character. However the function returns before sending the last character

That mean the function writes the last character to the UART Tx register and then returns. The last character will finish transmission about 320us later.

If you look at my listing, you will see that I use one command to send each byte. This means that EVERY character sent is the "last" for that command statement, meaning that program execution resumes before the sending of EACH character. I have not figured out how I can send all 3 bytes with one command without having cr and lf appended. If I did, 2 of the 3 bytes would be sent before program execution resumed. This might help some, but probably would not entirely solve the problem.

This means that EVERY character sent is the "last" for that command statement, meaning that program execution resumes before the sending of EACH character

So, it still has to wait up to 320us for every character before sending the NEXT "last" character.

Please use the "Code" (#) button when posting code.

So, it still has to wait up to 320us for every character before sending the NEXT "last" character.

I'm not sure about that. It seems as though there is some kind of serial output buffer provided "under the hood" when the code is compiled. We don't write it, but it is provided for us because they just know that everybody needs it anyway.

Even if you are right, I wonder how much code gets run during those 320 uS??

Anyhow, none of the explanations so far given get me any closer to how to fix the problem (except maybe the mention of "flow control"??). If someone thinks that my diagnosis of the problem is wrong, and has a suggested other "fix" to try, I am only too happy to run the needed tests. I am less concerned about whether I'm "right" than I am about how to actually solve the problem.

I'm not sure about that

It executes this:

void HardwareSerial::write(uint8_t c)
{
      while (!((*_ucsra) & (1 << _udre)))
            ;

      *_udr = c;
}

In other words, for each character written, the serial write method waits (spins, does nothing for up to one whole character period) for the transmit register to become empty, i.e. for the last character written to it to be shifted out.
It then writes the given character to the transmit register and returns.
Some UARTs have a short FIFO to the actual transmit register, but even this is going to fill sooner or later.

There is no free lunch.

Re: analog read sent as midi
Reply #7 - Today at 16:07:02
Quote:
I'm not sure about that

It executes this:
Code:

void HardwareSerial::write(uint8_t c)
{
while (!((*_ucsra) & (1 << _udre)))
;

*_udr = c;
}

In other words, for each character written, the serial write method waits (spins, does nothing for up to one whole character period) for the transmit register to become empty, i.e. for the last character written to it to be shifted out.
It then writes the given character to the transmit register and returns.

Now, for the simple print command that only sends a single character, after the character is sent to the UART, there is a return to program UNLESS the transmit register is not empty?? Do I understand correctly that then, if the last character had not yet been shifted out of the register, the command would wait before returning? If that is the case, then I would expect
The first print command returns immediately after pushing the character into the transmit register.
The second print command must then wait until the transmit register is empty before it can return from pushing its character into the register.
The third print command likewise cannot "push and return" until the second character has left the transmit register, but still returns before its own character has left the register... and we are back to your stated 320 uS of "transmission time" during which the program is running merrily on its way.

Some UARTs have a short FIFO to the actual transmit register, but even this is going to fill sooner or later.

There is no free lunch.

Never said there was. Still, SOMETHING is buffering all the "backlogged" analog read data until the serial print routines can catch up. In my tests, I am talking about DOZENS of readings that have been buffered SOMEWHERE. The readings continue to be taken, or they would not continue to "spill out" after I had stopped moving the pedal.

I am still left no closer to an answer for the original problem. How to I get the next analog read to wait until AFTER the results of the previous read have been fully transmitted?

I have not figured out how I can send all 3 bytes with one command without having cr and lf appended

and we are back to your stated 320 uS of "transmission time" during which the program is running merrily on its way

I really don't understand what you mean by this.
"Merrily on its way" means it delays another 10ms (the equivalent of over 30 transmitted characters, so we can assume the lastCCval you sent has got to its destination) before reading another analogue value and (potentially) sending another three bytes.

Quote:
and we are back to your stated 320 uS of "transmission time" during which the program is running merrily on its way

I really don't understand what you mean by this.
"Merrily on its way" means it delays another 10ms (the equivalent of over 30 transmitted characters, so we can assume the lastCCval you sent has got to its destination) before reading another analogue value and (potentially) sending another three bytes.

I would have thought that, too, except for my test results. Now, if I lengthen that last delay to 50 mS, I cannot build up excess readings that may transmit for several seconds after I stop moving the pedal. So, yeah, if there is ENOUGH delay ADDED then no new readings will be taken until after the data transmission is finished.

All this leads me to suspect that the actual time it takes to complete the transmission of 3 characters is much more than 1 mS. I am not disputing how long it takes to send ONE character. My thought is that the program overhead for something going on BETWEEN character sends is "stretching" things out.

I will take a closer look at the serial.write command, but I am not sure that it does not have some of the same problems.

Ok, I just tried replacing the "serial.print" statements with the equivalent "serial.write" statements. I think the new statements work a little better/faster, but the change still does not stop "collected" analog reads from building up faster than they are transmitted. I can still easily build up a "backlog" that takes several seconds to finish transmitting after I have stopped creating new entries.

How do I make the program wait for data to be fully sent before continuing???

What is the receiver of the MIDI data? Perhaps there is an input buffer that fills up when you have 10ms delays.

The Serial output port on Arduino does not do any more buffering than the single byte that is in the transmit buffer and as AWOL said this corresponds to 350uS. So the two first bytes of the MIDI CC message will have been transmitted when the program returns from the write of the third byte. The third byte will be completely transmitted 350uS later.

What is the receiver of the MIDI data? Perhaps there is an input buffer that fills up when you have 10ms delays.

Boy do I feel silly. I have been using S2Midi.exe to read the midi data. I also have tested using Midi-Ox on a different computer (going into a hardware midi port on that machine), but I did not think before to check for the same problem with that program. Midi-Ox does not show any trouble. Now we go from "dumb" to "dumber". On the box I built, I put an LED to show data transmission, and only now did I think to look at that LED to show if transmission continued after I stopped moving the pedal. No problem there either.

As a tech, I am accustomed to trusting my test instruments, although I have occasionally discovered that one of them had "lied" to me. Well, now I know that S2Midi.exe's display routines cannot keep up with continuing fast streams of incoming data.

So, all this time chasing a problem that wasn't even there. Thanks to all for your patience in trying to explain the setup to me!!

And, thank you for letting us know that you solved the problem, and how.