Jump to content

Tutorial #029: Fast Scan Matrix for velocity sensitive Keyboard


TK.
 Share

Recommended Posts

Finally we've a proper solution for scanning a velocity sensitive keyboard at fast speed (300 uS) with low CPU load (so that other tasks can be processed in parallel).

-> http://svnmios.midibox.org/listing.php?repname=svn.mios32&path=%2Ftrunk%2Fapps%2Ftutorials%2F029_keyboard_velocity%2F

I tested it on a defective Korg microKONTROL - the original firmware scanned the keyboard only at 500 uS, which means that the app has a higher accuracy than the commercial solution. :)

microKONTROL_mod.jpg

Details are described in the README.txt

Best Regards, Thorsten.

Link to comment
Share on other sites

Hello Thorsten

Details are described in the README.txt

"

...

MIOS32_SRIO_ScanStart is now called immediately (again) when a scan has finished,

accordingly only the transfer rate limits the scan speed. It has been set to

MIOS32_SPI_PRESCALER_64 (0.64 uS on a 120 MHz LPC1769).

The resulting matrix scan speed is ca. 300 uS for 16 rows and 8 columns (= 512 contacts)

....

"

I don´t understand your calculation.

As far as I can follow there are 2 ser. DOUT register for the rows an 1 ser. DIN register for the columns which lead to 16 x 8 = 128 contacts or 64 early & final contacts pairs.

This means for me 64 keys with velocity sensing.

Supposing (16 bits [for DOUT] + 8 bits [for DIN])/row * 0.64 uS/bit * 16 rows = 246 uS plus some spare processing time leads to the aforementioned 300 uS scan time but for 128 contacts.

Where is my error in reasoning?

Regards

Jo

Edited by nlate
Link to comment
Share on other sites

Finally somebody who reads the README! :)

I fixed the wrong value, 128 contacts are scanned of course!

Note that only 16 bits have to be shifted per row, since DINs are read concurrently to DOUT shift-out.

The additional overhead is caused by interrupt latency and (unoptimized) value transfers + pin change detection into C arrays before the next 16bit scan is started.

Best Regards, Thorsten.

Link to comment
Share on other sites

Hi Thorsten,

I looked into the code at app.c of tutorial #29 and have some (may be silly) questions:

  1. Why don´t you use a debounce fct. ?
    Is this not necessary, because today´s keyboards (Fatar etc.) use bubble contacts.
  2. If I want to use 16bit (u16) array variables, to save valuable RAM space, does this cost more exec cycles on an ARM core?
    (I am an injured Intel x86 guy :pirate:)
  3. What about timestamp wraparound?
    (after 15 days running the tutorial)

Thanks in advance for responding.

Kindly Regards

Jo

Link to comment
Share on other sites

Hi,

here my silly answers:

  1. Why don´t you use a debounce fct. ?
    Is this not necessary, because today´s keyboards (Fatar etc.) use bubble contacts.

It wasn't necessary when I tested it with the Korg keyboard.

If you notice a bouncing issue, please let me know and I will improve the example!

It could be solved by adding a simple check: the note on event should only be sent once after the "early contact" has been activated, and note off should only be sent once after the "final contact" has been deactivated.

(no debounce counter is required)

[*]If I want to use 16bit (u16) array variables, to save valuable RAM space, does this cost more exec cycles on an ARM core?

(I am an injured Intel x86 guy :pirate:)

If I understand your question correctly, you propose to change the din_activated_timestamp array into a u16 array, right?

This shouldn't hurt.

[*]What about timestamp wraparound?

Thats no issue in the way how I've implemented the delay measurement.

As long as we are calculating with values in the same resolution range (int and u32 are both 32bit values), the wraparound will take place by construction; the delay will always be correct.

Best Regards, Thorsten.

Link to comment
Share on other sites

Hi Thorsten

I admire your passion in bringing ideas to well structured code!

Imho APP_SRIO_ServicePrepare() and APP_SRIO_ServiceFinish() can be accellerated:

Skip MIOS32_DOUT_SRSet() of final contact row 2, 4, 6, 8, 10 for the Korg KB

if din_value of the related early contact row 1, 3, 5, 7, 9 is 0xff (no early contact pressed)

I observed this behavior on a Fatar keyboard some time ago, see:

one small side note to your Readme.txt and code comments, I´m a little confused about the meaning of your word depressed.

Does it mean released/untouched?

Kindly Regards,

Jo

Edited by nlate
Link to comment
Share on other sites

Imho APP_SRIO_ServicePrepare() and APP_SRIO_ServiceFinish() can be accellerated:

Skip MIOS32_DOUT_SRSet() of final contact row 2, 4, 6, 8, 10 for the Korg KB

if din_value of the related early contact row 1, 3, 5, 7, 9 is 0xff (no early contact pressed)

Nice idea! :)

But it only makes sense if the selection pattern is used for a single matrix.

Meanwhile I started with MIDIbox KB:

http://svnmios.midibox.org/listing.php?repname=svn.mios32&path=%2Ftrunk%2Fapps%2Fcontrollers%2Fmidibox_kb_v1%2F

which can service multiple keyboards of multiple types - here such an optimization would lead to unnecessary complexity, especially once the remaining DOUTs should be used for driving a LED matrix as well.

one small side note to your Readme.txt and code comments, I´m a little confused about the meaning of your word depressed.

Does it mean released/untouched?

Yes.

Google gives me 30 million hits for "depress button", I hope that they don't need antidepressant drugs... ;-)

Anyhow: http://www.thefreedictionary.com/depress

Best Regards, Thorsten.

Link to comment
Share on other sites

Hi Thorsten,

Aggreed to all your points :)

Just had a rough look at the new project you mentioned above.

Looks very promissing. Looking forward for your coded ideas.:)

Kindly Regards, Jo

PS: If you are in the Bodensee region, let me know via pm. Appart from cristal-clear water, we also have several sorts of good beer!. :wink:

Edited by nlate
Link to comment
Share on other sites

Hi Thorsten

Meanwhile I started with MIDIbox KB:

http://svnmios.midib...idibox_kb_v1%2F

which can service multiple keyboards of multiple types - here such an optimization would lead to unnecessary complexity, especially once the remaining DOUTs should be used for driving a LED matrix as well.

I think I found a small bug in http://svnmios.midib...rc%2Fkeyboard.c

in fct. void KEYBOARD_Periodic_1mS(void)

{

:::::::::::::::

:::::::::::::::

// check all 8 pins of the SR // should be: 16 ?

int sr_pin;

u8 mask = 0x01; // should be: u16 mask = 0x0001;

for(sr_pin=0; sr_pin<16; ++sr_pin, mask <<= 1)

if( changed & mask )

KEYBOARD_NotifyToggle(kb, row, sr_pin, (din_value[kb][row] & mask) ? 1 : 0);

}

}

}

Regards, Jo

Link to comment
Share on other sites

You are wrong: these are two bugs! ;-)

(fixed)

Btw.: meanwhile I think that I should provide the scan optimization that you found for Fatar solution as an option - it will work as long as the selection pattern isn't used for other purposes, and if it isn't enabled by default, somebody can troubleshoot the matrix connections first before enabling this feature.

Best Regards, Thorsten.

Link to comment
Share on other sites

  • 2 years later...

Dear Thorsten, dear MIDIBOXers

First of all Happy New Year 2015!

During regression tests of the midibox_kb_v1 project I found a nasty bug in
SVN.MIOS32\trunk\modules\keyboard\keyboard.c at the KEYBOARD_NotifyToggle() fct.:
 

// released key ?
if( depressed ) {
.....
[L578]: s16 delay = *ts_break_ptr - *ts_make_ptr;
.....

and

 

} else {
// pressed key ?
.....
[L631]: s16 delay = *ts_make_ptr - *ts_break_ptr;
.....
}

the (signed short) variable s16 delay leads to the following behaviour during delay calculations in case of overrun

(s. 2nd & 3rd line during a debug session):

[18721.553] Released: s16 delay= 17982 = u16 ts_break=58069 - u16 ts_make =40087
[18796.922] Pressed : s16 delay= 24956 = u16 ts_make =14748 - u16 ts_break=55328
[18817.231] Released: s16 delay=-20449 = u16 ts_break=40161 - u16 ts_make =60610 /!\

:sad:

 

the 2nd line is still correct because the subtraction doesn´t exceed the positive range of the (signed short) s16 delay range.
the 3rd line is mathematically correct, but not from the applicational view point.

The local fct.:

[L802]: static int KEYBOARD_GetVelocity(s16 delay, u16 delay_slowest, u16 delay_fastest)

doesn´t handle negative delay values correctly because it handles all values below delay_fastest as max. velocity!

So I changed the delay values in line 578, 631 & 802 from  s16  to u16 with the result that the overrun case is now handled correctly:

Released: u16 delay= 17982 = u16 ts_break=58069 - u16 ts_make =40087
Pressed : u16 delay= 24956 = u16 ts_make =14748 - u16 ts_break=55328
Released: u16 delay= 45087 = u16 ts_break=40161 - u16 ts_make =60610

:rolleyes:

Thorsten, would you be so kind to check if my findings are correct, and make the proposed changes in

modules/keyboard/keyboard.c  and in apps/tutorials/029_keyboard_velocity/app.c if you confirm.


Thanks and best regards,
Jo
 

Edited by nlate
Link to comment
Share on other sites

Hi Jo.

 

I wish you a happy new year as well! :)

 

Thanks for reporting the finding!

I agree and remember that I had similar experiences in the past, therefore fixed it immediately without additional testing at my side.

 

Well, wouldn't it be nice if we would have some automated tests for such complex routines? ;-)

 

Best Regards, Thorsten.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...