-
-
Notifications
You must be signed in to change notification settings - Fork 40.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix matrix_io_delay() timing in quantum/matrix.c #9603
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 96 in d4dc2a5
// Select row and wait for row selecton to stabilize |
Given the above comment, i cant see why the matrix delay was moved from directly after select_row
?
Also, was there a reason this was not applied to quantum/split_common/matrix.c
?
That comment is wrong. I think a lot of people have the same misconceptions as the comment.
Of course, I was going to change |
FYI:after
|
QMK runs on more than a 32u4, we would have to certain on the observed behaviour is consistent on all supported chips. Given where the delay is right now, that seems "safer" while not optimal. Not a massive fan of the risk vs reward here. |
Look at the picture above. There is an unstable time for the signal just after unselect_row(). In the current code, matrix_io_delay() doesn't cover that time. This PR is intended to remedy that. |
In its current form, the delay before read will also handle the last And as i also mention above, that image only shows one of the many chips we support. Making assumptions based off that single observed behaviour could lead to issues. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs validation (and not just "it works on my board" sort of testing, oscilloscope level verification) on...
Various STM32:
- f103
- f303
- f4x1
- f072
More AVR:
- atmega32a
- atmega328p
The waveform after unselect_row() above is the result of the routine manipulation to the GPIO. That's the basic behavior of digital circuits. All AVRs and ARMs behave no differently. If you don't believe my explanation, ask someone who knows about hardware. |
Its not my burden to provide defence and justification of the change, its the submitter. I'm asking for proof of the statement If we go with your previous observation of 1 clock cycle is required after |
That’s right. Okay, I will try again. |
Specifically to this point, I know that at least three Unsure if it's anything to do with instruction pipelining or the like, but single instruction GPIO is definitely not the case for everything. (Results in the following implementation, for example: https://github.com/tzarc/qmk_build/blob/master/tzarc-cyclone/cyclone.c#L71) |
I downloaded one of the STM32 series datasheets and am browsing through it. The GPIO seems to be connected to the APB2 bus, which is slower than the CPU. The APB2 bus is running on a clock that is divided by the cpu clock. Perhaps that's what's involved. |
Just a note, been running this implementation for several weeks without any issues. |
Should probably retarget to |
Due to tzarc's comment above, I'm investigating the need for a very short delay after 'select_row()'. |
Co-authored-by: Ryan <[email protected]>
Co-authored-by: Ryan <[email protected]>
Co-authored-by: Ryan <[email protected]>
Co-authored-by: Ryan <[email protected]>
…nd tmk_core/common/wait.h
eb5af42
to
9ce7c0a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see that my review was re-requested -- been using this on the Djinn for several months (including newer iterations), and the code looks and works perfectly fine as far as I can see.
Why is there no delay after the last unselect? When the next matrix_scan runs it could select the first row/column again before 30µs has passed. |
Ok, but there should still be a delay after the last unselect? Otherwise there's an assumption being made that it will take at least that amount of time for other processing before selecting again. I have a PR here to actually get short unselect times on ChibiOS instead of 100µs: #12211 If the scan rate can be improved by decreasing the unselect delay further then the per-key debounce algorithms really need to start tracking the order of key changes. |
In the above picture (AVR), it looks like it takes about 40us from the end of matrix_scan() until the next matrix_scan() is called. In the case of ARM, assuming a 4x clock, it would be around 10us. If the scan interval is shorter and insufficient, you can increase GPIO_INPUT_PIN_DELAY to extend the matrix_output_select_delay() time. You can increase the GPIO_INPUT_PIN_DELAY in units of cpu clocks, so you can adjust it precisely. |
Yes but that's in one specific case. If someone runs QMK on something much faster or decides to call matrix_scan() in a loop until the matrix changes it could fail to meet the minimum time. In reality I can remove the unselect delay entirely and the keyboard still works ok because it's just not fast enough to be a problem. |
The following functions in __attribute__((weak)) void matrix_output_select_delay(void) { waitInputPinDelay(); }
__attribute__((weak)) void matrix_output_unselect_delay(void) { matrix_io_delay(); }
__attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); }
__attribute__((weak)) void matrix_scan_user(void) {} |
Yes I know I can override those functions, I'm stating that the default implementation shouldn't skip the last unselect delay. |
copy `waitInputPinDelay` macro from qmk#9603
copy `wait_cpuclock` macro from qmk#9603
* fix matrix_io_delay() timing in quantum/matrix.c * Updated comments explaining the need for matrix_io_delay() in quantum/matrix.c * fix matrix_io_delay() timing in quantum/split_common/matrix.c * Update quantum/matrix.c Co-authored-by: Ryan <[email protected]> * Update quantum/split_common/matrix.c Co-authored-by: Ryan <[email protected]> * Update quantum/matrix.c Co-authored-by: Ryan <[email protected]> * Update quantum/split_common/matrix.c Co-authored-by: Ryan <[email protected]> * add waitOutputPinValid() and wait_cpuclock() into quantum/quantum.h and tmk_core/common/wait.h * add matrix_output_select_delay() and matrix_output_unselect_delay() * fix quantum/matrix_common.c, tmk_core/common/matrix.h * fix tmk_core/common/wait.h * fix quantum/quantum.h, tmk_core/common/wait.h * waitOutputPinValid() rename to waitInputPinDelay() in quantum/quantum.h. * waitOutputPinValid() rename to waitInputPinDelay() in quantum/matrix_common.c * update tmk_core/common/wait.h * update comment in quantum/matrix.c, quantum/split_common/matrix.c * update quantum/quantum.h: Make more margin in the GPIO_INPUT_PIN_DELAY default value. Co-authored-by: Ryan <[email protected]>
Description
The timing of the call to matrix_io_delay() has been changed to the appropriate time. With this change, we can reduce the number of times we call matrix_io_delay() by one.Separated
matrix_io_delay()
into the following two functions so that you can set the appropriate delay value for each.matrix_output_select_delay()
- afterselect_row()/select_col()
The delay is a small number of clocks specific to the MCU.
The default implementation is as follows:
See below for more information on
waitInputPinDelay()
.matrix_output_unselect_delay()
- afterunselect_row()/unselect_col()
The delay is in the range of a few microseconds, depending on the capacitance and resistance of the entire keyboard circuitry.
The default implementation is as follows:
Added
waitInputPinDelay()
intoquantum/quantum.h
.On AVR's GPIO and ARM's GPIO, the input signal changes need some clock time to be read into the input pins.
The
waitInputPinDelay()
will wait the necessary time. The wait time is set toGPIO_INPUT_PIN_DELAY
in units of the clock.If
GPIO_INPUT_PIN_DELAY
is not set, the following values are used.AVR
The datasheets for ATmega32u4/16u4, ATmega32u2/16u2, ATmega328p, AT90usb646/1286, etc. say that a delay of one clock is required after a change in the input signal. Therefore, the default value of GPIO_INPUT_PIN_DELAY can be set to 1, but we'll set it to 2 to allow for some leeway.
ARM-based MCUs
For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus to which the GPIO is connected.
The connected buses differ depending on the various series of MCUs.
Also, since the CPU instruction execution clock and GPIO bus clock can vary depending on the MCU GPIO bus configuration and MCU internal register settings, the optimal delay value cannot be determined. Therefore, GPIO_INPUT_PIN_DELAY defaults to a rather large value of 0.25 microseconds.
Current matrix.c timing (click)
current matrix.c timing
over view
detail view
New matrix.c timing (click)
new matrix.c timing
over view
detail view
Types of Changes
Checklist