Skip to content
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

Arm ps2 mouse interrupt #6490

Merged
merged 16 commits into from
Aug 5, 2021
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions docs/feature_ps2_mouse.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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.

Expand Down
4 changes: 2 additions & 2 deletions tmk_core/protocol.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
73 changes: 62 additions & 11 deletions tmk_core/protocol/ps2_interrupt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
JohSchneider marked this conversation as resolved.
Show resolved Hide resolved
#include "wait.h"

#define WAIT(stat, us, err) \
do { \
Expand All @@ -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) {
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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 {
Expand All @@ -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 */
Expand All @@ -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();
}
Expand All @@ -148,7 +173,7 @@ uint8_t ps2_host_recv(void) {
}
}

ISR(PS2_INT_VECT) {
void ps2_interrupt_service_routine(void) {
static enum {
INIT,
START,
Expand Down Expand Up @@ -218,6 +243,10 @@ ISR(PS2_INT_VECT) {
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);
Expand All @@ -232,40 +261,62 @@ 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();
#endif

JohSchneider marked this conversation as resolved.
Show resolved Hide resolved
uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
if (next != pbuf_tail) {
pbuf[pbuf_head] = data;
pbuf_head = next;
} else {
print("pbuf: full\n");
}

#if defined(__AVR__)
SREG = sreg;
#endif
JohSchneider marked this conversation as resolved.
Show resolved Hide resolved
}
static inline uint8_t pbuf_dequeue(void) {
uint8_t val = 0;

#if defined(__AVR__)
uint8_t sreg = SREG;
cli();
#endif
JohSchneider marked this conversation as resolved.
Show resolved Hide resolved

if (pbuf_head != pbuf_tail) {
val = pbuf[pbuf_tail];
pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
}

#if defined(__AVR__)
SREG = sreg;
#endif
JohSchneider marked this conversation as resolved.
Show resolved Hide resolved

return val;
}
static inline bool pbuf_has_data(void) {
#if defined(__AVR__)
uint8_t sreg = SREG;
cli();
#endif
JohSchneider marked this conversation as resolved.
Show resolved Hide resolved

bool has_data = (pbuf_head != pbuf_tail);
SREG = sreg;
#if defined(__AVR__)
SREG = sreg;
#endif
return has_data;
}
static inline void pbuf_clear(void) {
#if defined(__AVR__)
uint8_t sreg = SREG;
cli();
#endif

pbuf_head = pbuf_tail = 0;
SREG = sreg;
#if defined(__AVR__)
SREG = sreg;
#endif
}
55 changes: 55 additions & 0 deletions tmk_core/protocol/ps2_io_chibios.c
Original file line number Diff line number Diff line change
@@ -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);
}
14 changes: 9 additions & 5 deletions tmk_core/protocol/ps2_mouse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
JohSchneider marked this conversation as resolved.
Show resolved Hide resolved
# include <avr/io.h>
#endif

#include "ps2_mouse.h"
JohSchneider marked this conversation as resolved.
Show resolved Hide resolved
#include "wait.h"
#include "host.h"
#include "timer.h"
#include "print.h"
Expand All @@ -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");

Expand Down Expand Up @@ -205,7 +209,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)
Expand Down Expand Up @@ -247,7 +251,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
Expand Down