Browse Source

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>
JohSchneider 3 năm trước cách đây
mục cha
commit
bcb6e23387

+ 26 - 2
docs/feature_ps2_mouse.md

@@ -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.
 

+ 2 - 2
tmk_core/protocol.mk

@@ -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
 

+ 80 - 11
tmk_core/protocol/ps2_interrupt.c

@@ -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);
-    SREG          = sreg;
+
+#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;
-    SREG                  = sreg;
+
+#if defined(__AVR__)
+    SREG = sreg;
+#elif defined(PROTOCOL_CHIBIOS)
+    chSysUnlock();
+#endif
 }

+ 55 - 0
tmk_core/protocol/ps2_io_chibios.c

@@ -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);
+}

+ 9 - 5
tmk_core/protocol/ps2_mouse.c

@@ -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