Scanning matrix keyboard timing

W5ZZO

Well-known member
I have a (partially) half-baked idea to make some sort of YASS (Yet Another Silly Synthesizer). I salvaged some matrix musical keypads and reverse engineered their layout.
They are the expected diode matrix, with two contacts per note for velocity calculation. At this time there is no multiplexing, each column and row has their own Teensy data pin.

In the partial code below, without the delay(1) inserted I get all 0 readings from the digitalRead() calls. It appears that the time needed for the voltage to propagate through the diode is more than the time needed to perform the function call. This will make each scan unacceptably long, as it adds 48ms total.

Does anyone have an idea for a better speedbump or approach to reading these keys?

Code:
// perform keys scan
  for(int i=0; i<NUMCOLS; i++) {
    for(int j=0; j<NUMROWS; j++) {
      pinMode(kCols[i], INPUT_PULLUP);
      delay(1);
      noteMap[i][j]=digitalRead(kRows[j]);
      pinMode(kCols[i], INPUT_PULLDOWN);
      }

- Wes
 
I have a (partially) half-baked idea to make some sort of YASS (Yet Another Silly Synthesizer). I salvaged some matrix musical keypads and reverse engineered their layout.
They are the expected diode matrix, with two contacts per note for velocity calculation. At this time there is no multiplexing, each column and row has their own Teensy data pin.

In the partial code below, without the delay(1) inserted I get all 0 readings from the digitalRead() calls. It appears that the time needed for the voltage to propagate through the diode is more than the time needed to perform the function call. This will make each scan unacceptably long, as it adds 48ms total.

Does anyone have an idea for a better speedbump or approach to reading these keys?

Code:
// perform keys scan
  for(int i=0; i<NUMCOLS; i++) {
    for(int j=0; j<NUMROWS; j++) {
      pinMode(kCols[i], INPUT_PULLUP);
      delay(1);
      noteMap[i][j]=digitalRead(kRows[j]);
      pinMode(kCols[i], INPUT_PULLDOWN);
      }

- Wes

Try with delaymicros() and a lower delaytime test with something like delaymicros(50);

Keep in mind that delaymicros() doesn't call yield() at the moment.
 
Thanks for the response.
After I made that post, I "discovered" delayMicroseconds(). I tested my code and it works with a delay of 2us, but not at 1us.
For the time being that helps some, as it is 500% faster. I don't like the busy-wait aspect, but since the code is in a loop, the individual time is pretty minimal.
I don't need a continual scan, although I am not sure of how often I need to do one and still capture some effective measure of the velocity.

- Wes
 
Thanks for the response.
After I made that post, I "discovered" delayMicroseconds(). I tested my code and it works with a delay of 2us, but not at 1us.
For the time being that helps some, as it is 500% faster. I don't like the busy-wait aspect, but since the code is in a loop, the individual time is pretty minimal.
I don't need a continual scan, although I am not sure of how often I need to do one and still capture some effective measure of the velocity.

- Wes

It's 500 times faster, which is a bit more than 500% ;-)
 
In case anyone searches this out someday, here are my findings:
1) Using INPUT_PULLUP is too weak to power two diodes at once (multiple rows in the same column at the same time fail). I switched to output mode and used digitalWrite() to get the juice I needed.
2) This is probably hardware dependent (mine is prototyped, not a circuit board with short runs) but some keys "stick" at 2us and work at 3us.

This produces more reliable polyphonic scans than what I wrote before. Perhaps I will need to spawn the scanning and velocity calculation task off to a separate, slower processor (and effectively make it a midi keyboard). But for now I am going to use a timer to schedule the scanning and then process the results into sounds. I will see how well that works in time.
I have included the revised code for reference:
Code:
// perform keys scan
  for(int i=0; i<NUMCOLS_24NOTE; i++) {
    for(int j=0; j<NUMROWS_24NOTE; j++) {
      pinMode(kCols[i], OUTPUT);
      digitalWrite(kCols[i], HIGH);
      delayMicroseconds(3);
      note24Map[i][j]=digitalRead(kRows[j]);
      digitalWrite(kCols[i], LOW);
      pinMode(kCols[i], INPUT_DISABLE);
      }
    }

- Wes
 
Back
Top