-
-
Notifications
You must be signed in to change notification settings - Fork 39.9k
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
Cirque trackpad features: circular scroll, inertial cursor #17482
Changes from 8 commits
26bbb93
20f677f
421c2f9
0f2d232
fbee3bb
6e4a63a
0c35461
f873816
7428dc1
43b2f99
4d46e59
f85df63
8344eaa
97d1644
de833e8
969e612
dbe15af
516677a
7158ed6
f08d5e7
3ff32b0
60da778
7bf6c68
064d9e4
e48a3d1
18aa3a1
8bd6c92
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
#define SYSCONFIG_1 0x03 | ||
#define FEEDCONFIG_1 0x04 | ||
#define FEEDCONFIG_2 0x05 | ||
#define FEEDCONFIG_3 0x06 | ||
#define CALIBRATION_CONFIG_1 0x07 | ||
#define PS2_AU_CONTROL 0x08 | ||
#define SAMPLE_RATE 0x09 | ||
|
@@ -49,7 +50,7 @@ | |
// clang-format on | ||
|
||
bool touchpad_init; | ||
uint16_t scale_data = 1024; | ||
uint16_t scale_data = CIRQUE_PINNACLE_DEFAULT_SCALE; | ||
|
||
void cirque_pinnacle_clear_flags(void); | ||
void cirque_pinnacle_enable_feed(bool feedEnable); | ||
|
@@ -127,7 +128,8 @@ void cirque_pinnacle_enable_feed(bool feedEnable) { | |
// Reads <count> bytes from an extended register at <address> (16-bit address), | ||
// stores values in <*data> | ||
void ERA_ReadBytes(uint16_t address, uint8_t* data, uint16_t count) { | ||
uint8_t ERAControlValue = 0xFF; | ||
uint8_t ERAControlValue = 0xFF; | ||
uint16_t timeout_timer; | ||
|
||
cirque_pinnacle_enable_feed(false); // Disable feed | ||
|
||
|
@@ -138,9 +140,10 @@ void ERA_ReadBytes(uint16_t address, uint8_t* data, uint16_t count) { | |
RAP_Write(ERA_CONTROL, 0x05); // Signal ERA-read (auto-increment) to Pinnacle | ||
|
||
// Wait for status register 0x1E to clear | ||
timeout_timer = timer_read(); | ||
do { | ||
RAP_ReadBytes(ERA_CONTROL, &ERAControlValue, 1); | ||
} while (ERAControlValue != 0x00); | ||
} while ((ERAControlValue != 0x00) && (timer_elapsed(timeout_timer) <= CIRQUE_PINNACLE_TIMEOUT)); | ||
|
||
RAP_ReadBytes(ERA_VALUE, data + i, 1); | ||
|
||
|
@@ -150,7 +153,8 @@ void ERA_ReadBytes(uint16_t address, uint8_t* data, uint16_t count) { | |
|
||
// Writes a byte, <data>, to an extended register at <address> (16-bit address) | ||
void ERA_WriteByte(uint16_t address, uint8_t data) { | ||
uint8_t ERAControlValue = 0xFF; | ||
uint8_t ERAControlValue = 0xFF; | ||
uint16_t timeout_timer; | ||
|
||
cirque_pinnacle_enable_feed(false); // Disable feed | ||
|
||
|
@@ -162,9 +166,10 @@ void ERA_WriteByte(uint16_t address, uint8_t data) { | |
RAP_Write(ERA_CONTROL, 0x02); // Signal an ERA-write to Pinnacle | ||
|
||
// Wait for status register 0x1E to clear | ||
timeout_timer = timer_read(); | ||
do { | ||
RAP_ReadBytes(ERA_CONTROL, &ERAControlValue, 1); | ||
} while (ERAControlValue != 0x00); | ||
} while ((ERAControlValue != 0x00) && (timer_elapsed(timeout_timer) <= CIRQUE_PINNACLE_TIMEOUT)); | ||
|
||
cirque_pinnacle_clear_flags(); | ||
} | ||
|
@@ -192,6 +197,53 @@ void cirque_pinnacle_tune_edge_sensitivity(void) { | |
ERA_ReadBytes(0x0168, &temp, 1); | ||
} | ||
|
||
// Perform calibration | ||
void cirque_pinnacle_calibrate(void) { | ||
uint8_t calconfig; | ||
uint16_t timeout_timer; | ||
|
||
// CalConfig1 (Compensation) | ||
// Bit 0: Calibrate, 1=calibrate, 0=complete | ||
// Bit 1: Background Comp Enable, 1=enable, 0=disable | ||
// Bit 2: NERD Comp Enable (No, I don't know what NERD means), 1=enable, 0=disable | ||
// Bit 3: Track Error Comp Enable, 1=enable, 0=disable | ||
// Bit 4: Tap Comp Enable, 1=enable, 0=disable | ||
// Bit 6: Calibration Matrix Disable, 1=disabled, 0=enabled | ||
RAP_ReadBytes(CALIBRATION_CONFIG_1, &calconfig, 1); | ||
calconfig |= 0x01; | ||
RAP_Write(CALIBRATION_CONFIG_1, calconfig); | ||
KarlK90 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Calibration takes ~100ms according to GT-AN-090624, doubling the timeout just to be safe | ||
timeout_timer = timer_read(); | ||
do { | ||
RAP_ReadBytes(CALIBRATION_CONFIG_1, &calconfig, 1); | ||
} while ((calconfig & 0x01) && (timer_elapsed(timeout_timer) <= 200)); | ||
|
||
cirque_pinnacle_clear_flags(); | ||
} | ||
|
||
// Enable/disable cursor smoothing, smoothing is enabled by default | ||
void cirque_pinnacle_cursor_smoothing(bool enable) { | ||
uint8_t feedconfig3; | ||
|
||
// FeedConfig3 (Advanced feature flags) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this register available in all trackpad versions (TM040040/TM035035/TM023023) and Pinnacle firmwares? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FeedConfig3 register is listed in GT-AN-090625, which is stated as a companion document to GT-AN-090620. Same thing is stated for the ERA document (GT-AN-090623) and compensation document (GT-AN-090624). |
||
// Bit 0: DualPoint Buttons, 1=enable, 0=disable | ||
// Bit 1: Smoothing Disable, 1=disable, 0=enable | ||
// Bit 2: Palm/NERD measurements Disable, 1=disable, 0=enable | ||
// Bit 3: Noise Avoidance Disable, 1=disable, 0=enable | ||
// Bit 4: WRAP lockout Disable | ||
// Bit 5: Dynamic EMI adjust Disable | ||
// Bit 6: HW EMI detection Disable | ||
// Bit 7: SW EMI detection Disable | ||
RAP_ReadBytes(FEEDCONFIG_3, &feedconfig3, 1); | ||
KarlK90 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (enable) { | ||
feedconfig3 &= ~0x02; | ||
} else { | ||
feedconfig3 |= 0x02; | ||
} | ||
RAP_Write(FEEDCONFIG_3, feedconfig3); | ||
} | ||
|
||
/* Pinnacle-based TM040040/TM035035/TM023023 Functions */ | ||
void cirque_pinnacle_init(void) { | ||
#if defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi) | ||
|
@@ -241,6 +293,8 @@ void cirque_pinnacle_init(void) { | |
RAP_Write(Z_IDLE_COUNT, 5); | ||
|
||
cirque_pinnacle_set_adc_attenuation(CIRQUE_PINNACLE_ATTENUATION); | ||
// Perform manual calibration after setting ADC attenuation | ||
dkao marked this conversation as resolved.
Show resolved
Hide resolved
|
||
cirque_pinnacle_calibrate(); | ||
|
||
cirque_pinnacle_tune_edge_sensitivity(); | ||
cirque_pinnacle_enable_feed(true); | ||
|
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.
At least on I2C we could use
&& touchpad_init==true
directly, as this will be set to false if there is any I2C error (or timeout). Not sure if SPI considersCIRQUE_PINNACLE_TIMEOUT
at all?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.
SPI doesn't have ack or check for any timeout. It will return whatever state MISO happens to be floating in, if the device is not connected. That could be either 0xFF or 0x00 (or something inbetween if there's noise on the line?).
Looking at AVR's spi_master.c for example:
spi_start()
always returns true, except if chip select pin is invalid but that's an error before ever interacting with the device. Sotouch_init
check can't really apply for SPI.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.
This actually fixed a dead lock for me that happened with the code before. I started a small refactoring of the
RAP_Read/Write
functions. If you find it useful feel free to include it in this pr cirque_timeout.patch.txtThere 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.
As a side note, if a single I2C transfer fails the whole driver will turn into an invalid state - which requires a reboot of the keyboard. I can think of mechanism on the pointing device driver level that will try to re-init a driver in such a case after a certain timeout. But this is not in the scope of this PR.
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 think handling
touch_init
and I2C transaction failures adds too much to this PR, let's handle that in a separate one.