Arm ps2 mouse interrupt (#6490)

* ps2_mouse on ARM: an interrupt-version of the ps2-mouse code ported to ARM/chibios

* ps2_mouse on ARM: link EXT callback-channel selection to the user defined PS2_LINE_CLOCK

* ps2_mouse on ARM: replace DELAY_X defines with hardware-agnostic wait_X

* ps2_mouse on ARM: replace chibios-specific defines for the pins/lines with defines from quantum/config_common.h

and drop the '_LINE' component from teh define name

* ps2_mouse on ARM: expose the software-intterupt port as a user editable define

* Update docs/feature_ps2_mouse.md

Co-Authored-By: Hugo van Kemenade <hugovk@users.noreply.github.com>

* Update feature_ps2_mouse.md

* use a define to deduce the PS_DATA_PORT instead

* reduce all-zero extcfg to oneliner

* ps2_mouse: use generic wait instead of avr-delay

* Update docs/feature_ps2_mouse.md

* ps2_mouse: changes for new chibios version

(17.6.0 -> 19.1.0)
replacing the legacy externa-interrupt driver with pal-callbacks

* ps2_mouse: use PLATFORM_KEY

Co-Authored-By: Joel Challis <git@zvecr.com>

* ps2_mouse: clang-format corrections

* ps2_mouse: add systemlocks

using the chibios equivalent to AVRs cli: chSys[Unl|L]ock

Co-authored-by: Johannes <you@example.com>
Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>
Co-authored-by: Joel Challis <git@zvecr.com>
This commit is contained in:
JohSchneider 2021-08-05 21:51:24 +00:00 committed by GitHub
parent 5bbc527460
commit bcb6e23387
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 172 additions and 20 deletions

View file

@ -50,7 +50,7 @@ In your keyboard config.h:
#endif #endif
``` ```
## Interrupt Version :id=interrupt-version ### Interrupt Version (AVR/ATMega32u4) :id=interrupt-version-avr
The following example uses D2 for clock and D5 for data. You can use any INT or PCINT pin for clock, and any pin for data. The following example uses D2 for clock and D5 for data. You can use any INT or PCINT pin for clock, and any pin for data.
@ -88,7 +88,31 @@ In your keyboard config.h:
#endif #endif
``` ```
## USART Version :id=usart-version ### Interrupt Version (ARM chibios) :id=interrupt-version-chibios
Pretty much any two pins can be used for the (software) interrupt variant on ARM cores. The example below uses A8 for clock, and A9 for data.
In rules.mk:
```
PS2_MOUSE_ENABLE = yes
PS2_USE_INT = yes
```
In your keyboard config.h:
```c
#define PS2_CLOCK A8
#define PS2_DATA A9
```
And in the chibios specifig halconf.h:
```c
#define PAL_USE_CALLBACKS TRUE
```
### USART Version :id=usart-version
To use USART on the ATMega32u4, you have to use PD5 for clock and PD2 for data. If one of those are unavailable, you need to use interrupt version. To use USART on the ATMega32u4, you have to use PD5 for clock and PD2 for data. If one of those are unavailable, you need to use interrupt version.

View file

@ -14,13 +14,13 @@ endif
ifeq ($(strip $(PS2_USE_INT)), yes) ifeq ($(strip $(PS2_USE_INT)), yes)
SRC += protocol/ps2_interrupt.c SRC += protocol/ps2_interrupt.c
SRC += protocol/ps2_io_avr.c SRC += protocol/ps2_io_$(PLATFORM_KEY).c
OPT_DEFS += -DPS2_USE_INT OPT_DEFS += -DPS2_USE_INT
endif endif
ifeq ($(strip $(PS2_USE_USART)), yes) ifeq ($(strip $(PS2_USE_USART)), yes)
SRC += protocol/ps2_usart.c SRC += protocol/ps2_usart.c
SRC += protocol/ps2_io_avr.c SRC += protocol/ps2_io_$(PLATFORM_KEY).c
OPT_DEFS += -DPS2_USE_USART OPT_DEFS += -DPS2_USE_USART
endif endif

View file

@ -40,11 +40,19 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <stdbool.h> #include <stdbool.h>
#include <avr/interrupt.h>
#include <util/delay.h> #if defined(__AVR__)
# include <avr/interrupt.h>
#elif defined(PROTOCOL_CHIBIOS) // TODO: or STM32 ?
// chibiOS headers
# include "ch.h"
# include "hal.h"
#endif
#include "ps2.h" #include "ps2.h"
#include "ps2_io.h" #include "ps2_io.h"
#include "print.h" #include "print.h"
#include "wait.h"
#define WAIT(stat, us, err) \ #define WAIT(stat, us, err) \
do { \ do { \
@ -61,12 +69,30 @@ static inline void pbuf_enqueue(uint8_t data);
static inline bool pbuf_has_data(void); static inline bool pbuf_has_data(void);
static inline void pbuf_clear(void); static inline void pbuf_clear(void);
#if defined(PROTOCOL_CHIBIOS)
void ps2_interrupt_service_routine(void);
void palCallback(void *arg) { ps2_interrupt_service_routine(); }
# define PS2_INT_INIT() \
{ palSetLineMode(PS2_CLOCK, PAL_MODE_INPUT); } \
while (0)
# define PS2_INT_ON() \
{ \
palEnableLineEvent(PS2_CLOCK, PAL_EVENT_MODE_FALLING_EDGE); \
palSetLineCallback(PS2_CLOCK, palCallback, NULL); \
} \
while (0)
# define PS2_INT_OFF() \
{ palDisableLineEvent(PS2_CLOCK); } \
while (0)
#endif // PROTOCOL_CHIBIOS
void ps2_host_init(void) { void ps2_host_init(void) {
idle(); idle();
PS2_INT_INIT(); PS2_INT_INIT();
PS2_INT_ON(); PS2_INT_ON();
// POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
//_delay_ms(2500); // wait_ms(2500);
} }
uint8_t ps2_host_send(uint8_t data) { uint8_t ps2_host_send(uint8_t data) {
@ -77,7 +103,7 @@ uint8_t ps2_host_send(uint8_t data) {
/* terminate a transmission if we have */ /* terminate a transmission if we have */
inhibit(); inhibit();
_delay_us(100); // 100us [4]p.13, [5]p.50 wait_us(100); // 100us [4]p.13, [5]p.50
/* 'Request to Send' and Start bit */ /* 'Request to Send' and Start bit */
data_lo(); data_lo();
@ -86,7 +112,6 @@ uint8_t ps2_host_send(uint8_t data) {
/* Data bit[2-9] */ /* Data bit[2-9] */
for (uint8_t i = 0; i < 8; i++) { for (uint8_t i = 0; i < 8; i++) {
_delay_us(15);
if (data & (1 << i)) { if (data & (1 << i)) {
parity = !parity; parity = !parity;
data_hi(); data_hi();
@ -98,7 +123,7 @@ uint8_t ps2_host_send(uint8_t data) {
} }
/* Parity bit */ /* Parity bit */
_delay_us(15); wait_us(15);
if (parity) { if (parity) {
data_hi(); data_hi();
} else { } else {
@ -108,7 +133,7 @@ uint8_t ps2_host_send(uint8_t data) {
WAIT(clock_lo, 50, 5); WAIT(clock_lo, 50, 5);
/* Stop bit */ /* Stop bit */
_delay_us(15); wait_us(15);
data_hi(); data_hi();
/* Ack */ /* Ack */
@ -132,7 +157,7 @@ uint8_t ps2_host_recv_response(void) {
// Command may take 25ms/20ms at most([5]p.46, [3]p.21) // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
uint8_t retry = 25; uint8_t retry = 25;
while (retry-- && !pbuf_has_data()) { while (retry-- && !pbuf_has_data()) {
_delay_ms(1); wait_ms(1);
} }
return pbuf_dequeue(); return pbuf_dequeue();
} }
@ -148,7 +173,7 @@ uint8_t ps2_host_recv(void) {
} }
} }
ISR(PS2_INT_VECT) { void ps2_interrupt_service_routine(void) {
static enum { static enum {
INIT, INIT,
START, START,
@ -218,6 +243,10 @@ RETURN:
return; return;
} }
#if defined(__AVR__)
ISR(PS2_INT_VECT) { ps2_interrupt_service_routine(); }
#endif
/* send LED state to keyboard */ /* send LED state to keyboard */
void ps2_host_set_led(uint8_t led) { void ps2_host_set_led(uint8_t led) {
ps2_host_send(0xED); ps2_host_send(0xED);
@ -232,8 +261,13 @@ static uint8_t pbuf[PBUF_SIZE];
static uint8_t pbuf_head = 0; static uint8_t pbuf_head = 0;
static uint8_t pbuf_tail = 0; static uint8_t pbuf_tail = 0;
static inline void pbuf_enqueue(uint8_t data) { static inline void pbuf_enqueue(uint8_t data) {
#if defined(__AVR__)
uint8_t sreg = SREG; uint8_t sreg = SREG;
cli(); cli();
#elif defined(PROTOCOL_CHIBIOS)
chSysLockFromISR();
#endif
uint8_t next = (pbuf_head + 1) % PBUF_SIZE; uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
if (next != pbuf_tail) { if (next != pbuf_tail) {
pbuf[pbuf_head] = data; pbuf[pbuf_head] = data;
@ -241,31 +275,66 @@ static inline void pbuf_enqueue(uint8_t data) {
} else { } else {
print("pbuf: full\n"); print("pbuf: full\n");
} }
#if defined(__AVR__)
SREG = sreg; SREG = sreg;
#elif defined(PROTOCOL_CHIBIOS)
chSysUnlockFromISR();
#endif
} }
static inline uint8_t pbuf_dequeue(void) { static inline uint8_t pbuf_dequeue(void) {
uint8_t val = 0; uint8_t val = 0;
#if defined(__AVR__)
uint8_t sreg = SREG; uint8_t sreg = SREG;
cli(); cli();
#elif defined(PROTOCOL_CHIBIOS)
chSysLock();
#endif
if (pbuf_head != pbuf_tail) { if (pbuf_head != pbuf_tail) {
val = pbuf[pbuf_tail]; val = pbuf[pbuf_tail];
pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE; pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
} }
#if defined(__AVR__)
SREG = sreg; SREG = sreg;
#elif defined(PROTOCOL_CHIBIOS)
chSysUnlock();
#endif
return val; return val;
} }
static inline bool pbuf_has_data(void) { static inline bool pbuf_has_data(void) {
#if defined(__AVR__)
uint8_t sreg = SREG; uint8_t sreg = SREG;
cli(); cli();
#elif defined(PROTOCOL_CHIBIOS)
chSysLock();
#endif
bool has_data = (pbuf_head != pbuf_tail); bool has_data = (pbuf_head != pbuf_tail);
SREG = sreg;
#if defined(__AVR__)
SREG = sreg;
#elif defined(PROTOCOL_CHIBIOS)
chSysUnlock();
#endif
return has_data; return has_data;
} }
static inline void pbuf_clear(void) { static inline void pbuf_clear(void) {
#if defined(__AVR__)
uint8_t sreg = SREG; uint8_t sreg = SREG;
cli(); cli();
#elif defined(PROTOCOL_CHIBIOS)
chSysLock();
#endif
pbuf_head = pbuf_tail = 0; pbuf_head = pbuf_tail = 0;
SREG = sreg;
#if defined(__AVR__)
SREG = sreg;
#elif defined(PROTOCOL_CHIBIOS)
chSysUnlock();
#endif
} }

View file

@ -0,0 +1,55 @@
#include <stdbool.h>
#include "ps2_io.h"
// chibiOS headers
#include "ch.h"
#include "hal.h"
/* Check port settings for clock and data line */
#if !(defined(PS2_CLOCK))
# error "PS/2 clock setting is required in config.h"
#endif
#if !(defined(PS2_DATA))
# error "PS/2 data setting is required in config.h"
#endif
/*
* Clock
*/
void clock_init(void) {}
void clock_lo(void) {
palSetLineMode(PS2_CLOCK, PAL_MODE_OUTPUT_OPENDRAIN);
palWriteLine(PS2_CLOCK, PAL_LOW);
}
void clock_hi(void) {
palSetLineMode(PS2_CLOCK, PAL_MODE_OUTPUT_OPENDRAIN);
palWriteLine(PS2_CLOCK, PAL_HIGH);
}
bool clock_in(void) {
palSetLineMode(PS2_CLOCK, PAL_MODE_INPUT);
return palReadLine(PS2_CLOCK);
}
/*
* Data
*/
void data_init(void) {}
void data_lo(void) {
palSetLineMode(PS2_DATA, PAL_MODE_OUTPUT_OPENDRAIN);
palWriteLine(PS2_DATA, PAL_LOW);
}
void data_hi(void) {
palSetLineMode(PS2_DATA, PAL_MODE_OUTPUT_OPENDRAIN);
palWriteLine(PS2_DATA, PAL_HIGH);
}
bool data_in(void) {
palSetLineMode(PS2_DATA, PAL_MODE_INPUT);
return palReadLine(PS2_DATA);
}

View file

@ -16,9 +16,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdbool.h> #include <stdbool.h>
#include <avr/io.h>
#include <util/delay.h> #if defined(__AVR__)
# include <avr/io.h>
#endif
#include "ps2_mouse.h" #include "ps2_mouse.h"
#include "wait.h"
#include "host.h" #include "host.h"
#include "timer.h" #include "timer.h"
#include "print.h" #include "print.h"
@ -42,7 +46,7 @@ static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report);
void ps2_mouse_init(void) { void ps2_mouse_init(void) {
ps2_host_init(); ps2_host_init();
_delay_ms(PS2_MOUSE_INIT_DELAY); // wait for powering up wait_ms(PS2_MOUSE_INIT_DELAY); // wait for powering up
PS2_MOUSE_SEND(PS2_MOUSE_RESET, "ps2_mouse_init: sending reset"); PS2_MOUSE_SEND(PS2_MOUSE_RESET, "ps2_mouse_init: sending reset");
@ -210,7 +214,7 @@ static inline void ps2_mouse_enable_scrolling(void) {
PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Set sample rate"); PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Set sample rate");
PS2_MOUSE_SEND(80, "80"); PS2_MOUSE_SEND(80, "80");
PS2_MOUSE_SEND(PS2_MOUSE_GET_DEVICE_ID, "Finished enabling scroll wheel"); PS2_MOUSE_SEND(PS2_MOUSE_GET_DEVICE_ID, "Finished enabling scroll wheel");
_delay_ms(20); wait_ms(20);
} }
#define PRESS_SCROLL_BUTTONS mouse_report->buttons |= (PS2_MOUSE_SCROLL_BTN_MASK) #define PRESS_SCROLL_BUTTONS mouse_report->buttons |= (PS2_MOUSE_SCROLL_BTN_MASK)
@ -252,7 +256,7 @@ static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report) {
if (scroll_state == SCROLL_BTN && timer_elapsed(scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) { if (scroll_state == SCROLL_BTN && timer_elapsed(scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) {
PRESS_SCROLL_BUTTONS; PRESS_SCROLL_BUTTONS;
host_mouse_send(mouse_report); host_mouse_send(mouse_report);
_delay_ms(100); wait_ms(100);
RELEASE_SCROLL_BUTTONS; RELEASE_SCROLL_BUTTONS;
} }
#endif #endif