DaveX, blinkin' marvellous work. *applause*
Some improvements you might like to make. Truncating an ADC value to remove LSB noise doesn't unfortunately work for all values in the number line, only most of them. Take for instance the 10-bit value:
010011111?
where "?" is the noisy bit. The ADC value is wobbling between two digital values:
0100111111 and 0101000000
Truncating to 7 bits will still send a noisy value to the result because the chain of 1-bits causes the noise to "rise up" through the value and appear in the truncated end result.
The trick to "debouncing" ADC reads is to keep a copy of the previous ADC value at full resolution and only pass on the new ADC value to the truncation code if the full-res value has changed by, say, plus or minus two bits. This adds a bit of hysteresis into the system that will remove noise but still allow actual movement to be recorded quickly. Here's some code:
Code:
// Make sure any change in the value is due to
// user action and not sampling noise. We do this by making sure the
// value has changed by a minimum amount before we say it has
// changed - essentially adding a small amount of Hysteresis into
// the system. This part happens at full resolution.
for (uint8_t i=0; i<4; ++i) {
// Read the ADC value once and record it for use everywhere else.
int16_t value = adc_read(i);
// NOTE: Need a signed 16-bit value for the difference
int16_t difference = value - g_analog_prev[i];
// If the difference is less than three bits either way we
// assume the difference was noise and the ADC was not changed.
if (abs(difference) < 8) {
// do not send the noisy new value, use the old reliable one.
adc_value[i] = g_analog_prev[i];
} else {
adc_value[i] = value;
}
}
// Next, loop over these fresh ADC values to see if, after
// truncation, they have changed and a MIDI event needs
// to be generated.
for (uint8_t i=0; i<4; ++i) {
// Lose the bottom three bits of each 10-bit ADC value,
// converting it to a 7-bit CC value.
uint8_t value = (uint8_t)(adc_value[i] >> 3);
uint8_t prev_value = (uint8_t)(g_analog_prev[i] >> 3);
// Compare the CC value to the previous one sent. If there has
// been a change, generate a new MIDI Control Change event
// sending the new value.
if (value != prev_value) {
// Generate the default CC event.
midi_stream_cc(16 + i, value);
....
// Record the new ADC value, at full resolution, for the next
// time through.
g_analog_prev[i] = adc_value[i];
}
....
}
Do this and your faders return rock solid results. This code comes from a Midifighter update I'm working on.
Looks like you'll have to find a few unused words of RAM to use for the previous values. Also, if you have any clue why the lights flicker when the unit recieves MIDI input I'd love to try and fix that. My guess is there's no latch on the LED values and the flickering is the LED bits rippling through the serial input. No good way to fix that unfortunately.
Keep up the good work! Should you feel the desire to share your discoveries as an open source Creative Commons project, I'd love to help you out. Check your PM!
Bookmarks