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>master
parent
5bbc527460
commit
bcb6e23387
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue