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
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
|
@ -88,7 +88,31 @@ In your keyboard config.h:
|
|||
#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.
|
||||
|
||||
|
|
|
@ -14,13 +14,13 @@ endif
|
|||
|
||||
ifeq ($(strip $(PS2_USE_INT)), yes)
|
||||
SRC += protocol/ps2_interrupt.c
|
||||
SRC += protocol/ps2_io_avr.c
|
||||
SRC += protocol/ps2_io_$(PLATFORM_KEY).c
|
||||
OPT_DEFS += -DPS2_USE_INT
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(PS2_USE_USART)), yes)
|
||||
SRC += protocol/ps2_usart.c
|
||||
SRC += protocol/ps2_io_avr.c
|
||||
SRC += protocol/ps2_io_$(PLATFORM_KEY).c
|
||||
OPT_DEFS += -DPS2_USE_USART
|
||||
endif
|
||||
|
||||
|
|
|
@ -40,11 +40,19 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
#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_io.h"
|
||||
#include "print.h"
|
||||
#include "wait.h"
|
||||
|
||||
#define WAIT(stat, us, err) \
|
||||
do { \
|
||||
|
@ -61,12 +69,30 @@ static inline void pbuf_enqueue(uint8_t data);
|
|||
static inline bool pbuf_has_data(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) {
|
||||
idle();
|
||||
PS2_INT_INIT();
|
||||
PS2_INT_ON();
|
||||
// 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) {
|
||||
|
@ -77,7 +103,7 @@ uint8_t ps2_host_send(uint8_t data) {
|
|||
|
||||
/* terminate a transmission if we have */
|
||||
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 */
|
||||
data_lo();
|
||||
|
@ -86,7 +112,6 @@ uint8_t ps2_host_send(uint8_t data) {
|
|||
|
||||
/* Data bit[2-9] */
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
_delay_us(15);
|
||||
if (data & (1 << i)) {
|
||||
parity = !parity;
|
||||
data_hi();
|
||||
|
@ -98,7 +123,7 @@ uint8_t ps2_host_send(uint8_t data) {
|
|||
}
|
||||
|
||||
/* Parity bit */
|
||||
_delay_us(15);
|
||||
wait_us(15);
|
||||
if (parity) {
|
||||
data_hi();
|
||||
} else {
|
||||
|
@ -108,7 +133,7 @@ uint8_t ps2_host_send(uint8_t data) {
|
|||
WAIT(clock_lo, 50, 5);
|
||||
|
||||
/* Stop bit */
|
||||
_delay_us(15);
|
||||
wait_us(15);
|
||||
data_hi();
|
||||
|
||||
/* 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)
|
||||
uint8_t retry = 25;
|
||||
while (retry-- && !pbuf_has_data()) {
|
||||
_delay_ms(1);
|
||||
wait_ms(1);
|
||||
}
|
||||
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 {
|
||||
INIT,
|
||||
START,
|
||||
|
@ -218,6 +243,10 @@ RETURN:
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined(__AVR__)
|
||||
ISR(PS2_INT_VECT) { ps2_interrupt_service_routine(); }
|
||||
#endif
|
||||
|
||||
/* send LED state to keyboard */
|
||||
void ps2_host_set_led(uint8_t led) {
|
||||
ps2_host_send(0xED);
|
||||
|
@ -232,8 +261,13 @@ static uint8_t pbuf[PBUF_SIZE];
|
|||
static uint8_t pbuf_head = 0;
|
||||
static uint8_t pbuf_tail = 0;
|
||||
static inline void pbuf_enqueue(uint8_t data) {
|
||||
#if defined(__AVR__)
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
#elif defined(PROTOCOL_CHIBIOS)
|
||||
chSysLockFromISR();
|
||||
#endif
|
||||
|
||||
uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
|
||||
if (next != pbuf_tail) {
|
||||
pbuf[pbuf_head] = data;
|
||||
|
@ -241,31 +275,66 @@ static inline void pbuf_enqueue(uint8_t data) {
|
|||
} else {
|
||||
print("pbuf: full\n");
|
||||
}
|
||||
|
||||
#if defined(__AVR__)
|
||||
SREG = sreg;
|
||||
#elif defined(PROTOCOL_CHIBIOS)
|
||||
chSysUnlockFromISR();
|
||||
#endif
|
||||
}
|
||||
static inline uint8_t pbuf_dequeue(void) {
|
||||
uint8_t val = 0;
|
||||
|
||||
#if defined(__AVR__)
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
#elif defined(PROTOCOL_CHIBIOS)
|
||||
chSysLock();
|
||||
#endif
|
||||
|
||||
if (pbuf_head != pbuf_tail) {
|
||||
val = pbuf[pbuf_tail];
|
||||
pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
|
||||
}
|
||||
|
||||
#if defined(__AVR__)
|
||||
SREG = sreg;
|
||||
#elif defined(PROTOCOL_CHIBIOS)
|
||||
chSysUnlock();
|
||||
#endif
|
||||
|
||||
return val;
|
||||
}
|
||||
static inline bool pbuf_has_data(void) {
|
||||
#if defined(__AVR__)
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
#elif defined(PROTOCOL_CHIBIOS)
|
||||
chSysLock();
|
||||
#endif
|
||||
|
||||
bool has_data = (pbuf_head != pbuf_tail);
|
||||
|
||||
#if defined(__AVR__)
|
||||
SREG = sreg;
|
||||
#elif defined(PROTOCOL_CHIBIOS)
|
||||
chSysUnlock();
|
||||
#endif
|
||||
return has_data;
|
||||
}
|
||||
static inline void pbuf_clear(void) {
|
||||
#if defined(__AVR__)
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
#elif defined(PROTOCOL_CHIBIOS)
|
||||
chSysLock();
|
||||
#endif
|
||||
|
||||
pbuf_head = pbuf_tail = 0;
|
||||
|
||||
#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 <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#if defined(__AVR__)
|
||||
# include <avr/io.h>
|
||||
#endif
|
||||
|
||||
#include "ps2_mouse.h"
|
||||
#include "wait.h"
|
||||
#include "host.h"
|
||||
#include "timer.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) {
|
||||
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");
|
||||
|
||||
|
@ -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(80, "80");
|
||||
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)
|
||||
|
@ -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) {
|
||||
PRESS_SCROLL_BUTTONS;
|
||||
host_mouse_send(mouse_report);
|
||||
_delay_ms(100);
|
||||
wait_ms(100);
|
||||
RELEASE_SCROLL_BUTTONS;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue