29 #include "freertos/FreeRTOS.h" 31 #include "esp32/ulp.h" 32 #include "driver/rtc_io.h" 33 #include "soc/sens_reg.h" 34 #if __has_include("soc/rtc_io_periph.h") 35 #include "soc/rtc_io_periph.h" 41 #include "ulp_macro_ex.h" 47 #pragma GCC optimize ("O2") 48 #pragma GCC diagnostic ignored "-Wmissing-field-initializers" 59 #define OPCODE_PLACEHOLDER 12 // 12 is an unused ULP opcode we can use as placeholder 61 #define SUB_OPCODE_DAT_ENABLE_OUTPUT 0 62 #define SUB_OPCODE_DAT_ENABLE_INPUT 1 63 #define SUB_OPCODE_CLK_ENABLE_OUTPUT 2 64 #define SUB_OPCODE_CLK_ENABLE_INPUT 3 65 #define SUB_OPCODE_READ_CLK 4 66 #define SUB_OPCODE_READ_DAT 5 67 #define SUB_OPCODE_WRITE_CLK 6 68 #define SUB_OPCODE_WRITE_DAT 7 74 #define DAT_ENABLE_OUTPUT(ps2port, value) { .macro = { \ 77 .sub_opcode = SUB_OPCODE_DAT_ENABLE_OUTPUT, \ 78 .opcode = OPCODE_PLACEHOLDER } } 80 #define DAT_ENABLE_INPUT(ps2port, value) { .macro = { \ 83 .sub_opcode = SUB_OPCODE_DAT_ENABLE_INPUT, \ 84 .opcode = OPCODE_PLACEHOLDER } } 86 #define CLK_ENABLE_OUTPUT(ps2port, value) { .macro = { \ 89 .sub_opcode = SUB_OPCODE_CLK_ENABLE_OUTPUT, \ 90 .opcode = OPCODE_PLACEHOLDER } } 92 #define CLK_ENABLE_INPUT(ps2port, value) { .macro = { \ 95 .sub_opcode = SUB_OPCODE_CLK_ENABLE_INPUT, \ 96 .opcode = OPCODE_PLACEHOLDER } } 99 #define READ_CLK(ps2port) { .macro = { \ 102 .sub_opcode = SUB_OPCODE_READ_CLK, \ 103 .opcode = OPCODE_PLACEHOLDER } } 106 #define READ_DAT(ps2port) { .macro = { \ 109 .sub_opcode = SUB_OPCODE_READ_DAT, \ 110 .opcode = OPCODE_PLACEHOLDER } } 113 #define WRITE_CLK(ps2port, value) { .macro = { \ 116 .sub_opcode = SUB_OPCODE_WRITE_CLK, \ 117 .opcode = OPCODE_PLACEHOLDER } } 120 #define WRITE_DAT(ps2port, value) { .macro = { \ 123 .sub_opcode = SUB_OPCODE_WRITE_DAT, \ 124 .opcode = OPCODE_PLACEHOLDER } } 131 #define CONFIGURE_DAT_INPUT(ps2port) \ 132 DAT_ENABLE_OUTPUT(ps2port, 0), \ 133 DAT_ENABLE_INPUT(ps2port, 1) 136 #define CONFIGURE_DAT_OUTPUT(ps2port) \ 137 DAT_ENABLE_OUTPUT(ps2port, 1), \ 138 DAT_ENABLE_INPUT(ps2port, 0) 141 #define CONFIGURE_CLK_INPUT(ps2port) \ 142 CLK_ENABLE_OUTPUT(ps2port, 0), \ 143 CLK_ENABLE_INPUT(ps2port, 1) 146 #define CONFIGURE_CLK_OUTPUT(ps2port) \ 147 CLK_ENABLE_OUTPUT(ps2port, 1), \ 148 CLK_ENABLE_INPUT(ps2port, 0) 152 #define WRITE_DAT_R0(ps2port) \ 154 WRITE_DAT(ps2port, 1), \ 156 WRITE_DAT(ps2port, 0) 160 #define MEM_WRITEI(addr, value) \ 167 #define MEM_INDWRITEI(addr, value) \ 175 #define MEM_WRITER(addr, reg) \ 181 #define MEM_INDWRITER(addr, reg) \ 187 #define MEM_READR(reg, addr) \ 192 #define MEM_INDREADR(reg, addr) \ 199 #define MEM_INC(addr) \ 207 #define MEM_BL(label, addr, value) \ 214 #define MEM_BGE(label, addr, value) \ 220 #define M_LONG_BGE(label, value) \ 225 #define M_LONG_BL(label, value) \ 230 #define M_LONG_BE(label, value) \ 232 I_BGE(2, value + 1), \ 236 #define M_LONG_BNE(label, value) \ 239 I_BL(2, value + 1), \ 242 #define M_LONG_STAGEBLE(label_num, imm_value) \ 243 I_STAGEBLE(2, imm_value), \ 244 I_STAGEBGE(2, imm_value), \ 247 #define M_LONG_STAGEBL(label_num, imm_value) \ 248 I_STAGEBGE(2, imm_value), \ 251 #define M_LONG_STAGEBGE(label_num, imm_value) \ 252 I_STAGEBL(2, imm_value), \ 256 #define M_DELAY_US(us) I_DELAY(us * 8) 265 #define RTCMEM_PROG_START 0x000 // where the program begins 266 #define RTCMEM_VARS_START 0x200 // where the variables begin 269 #define RTCMEM_PORT0_TX (RTCMEM_VARS_START + 0) // 1 = send data to port 0 270 #define RTCMEM_PORT1_TX (RTCMEM_VARS_START + 1) // 1 = send data to port 1 271 #define RTCMEM_PORT0_RX_ENABLE (RTCMEM_VARS_START + 2) // 1 = Request to enable RX from port 0 272 #define RTCMEM_PORT1_RX_ENABLE (RTCMEM_VARS_START + 3) // 1 = Request to enable RX from port 1 273 #define RTCMEM_PORT0_RX_DISABLE (RTCMEM_VARS_START + 4) // 1 = Request to disable RX from port 0 274 #define RTCMEM_PORT1_RX_DISABLE (RTCMEM_VARS_START + 5) // 1 = Request to disable RX from port 1 276 #define RTCMEM_PORT0_DATAOUT (RTCMEM_VARS_START + 6) // Data to send to port 0 (when RTCMEM_PORT0_TX = 1) 277 #define RTCMEM_PORT1_DATAOUT (RTCMEM_VARS_START + 7) // Data to send to port 1 (when RTCMEM_PORT1_TX = 1) 280 #define RTCMEM_PORT0_RX (RTCMEM_VARS_START + 8) // Data received from port 0 281 #define RTCMEM_PORT1_RX (RTCMEM_VARS_START + 9) // Data received from port 1 282 #define RTCMEM_PORT0_RX_CLK_TIMEOUT (RTCMEM_VARS_START + 10) // RX port 0 CLK timeout 283 #define RTCMEM_PORT1_RX_CLK_TIMEOUT (RTCMEM_VARS_START + 11) // RX port 1 CLK timeout 285 #define RTCMEM_PORT0_DATAIN (RTCMEM_VARS_START + 12) // Data received from port 0 (when RTCMEM_PORT0_RX = 1) 286 #define RTCMEM_PORT1_DATAIN (RTCMEM_VARS_START + 13) // Data received from port 1 (when RTCMEM_PORT1_RX = 1) 289 #define RTCMEM_PORT0_RX_ENABLED (RTCMEM_VARS_START + 14) // 0 = port 0 not configured for RX, 1 = port 0 configured for RX 290 #define RTCMEM_PORT1_RX_ENABLED (RTCMEM_VARS_START + 15) // 0 = port 1 not configured for RX, 1 = port 1 configured for RX 292 #define RTCMEM_LASTVAR (RTCMEM_VARS_START + 15) 296 #define CLK_RX_TIMEOUT_VAL 100 299 #define CLK_TX_TIMEOUT_VAL 1200 // fine tuned to work with PERIBOARD 409P 302 #define WAKE_THRESHOLD 3000 306 #if RTCMEM_LASTVAR >= 0x800 307 #error "ULP program too big" 313 #define LABEL_WAIT_COMMAND 0 316 #define LABEL_RX_NEXT 2 318 #define LABEL_PORT0_ENABLE_RX 3 319 #define LABEL_PORT0_STOP_RX 4 320 #define LABEL_PORT0_TX 5 321 #define LABEL_PORT0_TX_NEXT_BIT 6 322 #define LABEL_PORT0_TX_WAIT_CLK_HIGH 7 323 #define LABEL_PORT0_TX_EXIT 8 324 #define LABEL_PORT0_RX_WAIT_LOOP 9 325 #define LABEL_PORT0_RX_CLK_IS_HIGH 10 326 #define LABEL_PORT0_RX_CLK_IS_LOW 11 327 #define LABEL_PORT0_RX_CLK_TIMEOUT 12 328 #define LABEL_PORT0_RX_CHECK_CLK 13 330 #define LABEL_PORT1_ENABLE_RX 14 331 #define LABEL_PORT1_STOP_RX 15 332 #define LABEL_PORT1_TX 16 333 #define LABEL_PORT1_TX_NEXT_BIT 17 334 #define LABEL_PORT1_TX_WAIT_CLK_HIGH 18 335 #define LABEL_PORT1_TX_EXIT 19 336 #define LABEL_PORT1_RX_WAIT_LOOP 20 337 #define LABEL_PORT1_RX_CLK_IS_HIGH 21 338 #define LABEL_PORT1_RX_CLK_IS_LOW 22 339 #define LABEL_PORT1_RX_CLK_TIMEOUT 23 340 #define LABEL_PORT1_RX_CHECK_CLK 24 348 #define TEMP_PORT0_DISABLE() \ 349 I_LD(R0, R3, RTCMEM_PORT0_RX_ENABLED), \ 351 CONFIGURE_CLK_OUTPUT(PS2_PORT0), \ 352 WRITE_CLK(PS2_PORT0, 0) 357 #define TEMP_PORT0_ENABLE() \ 358 I_LD(R0, R3, RTCMEM_PORT0_RX_ENABLED), \ 360 CONFIGURE_CLK_INPUT(PS2_PORT0) 365 #define TEMP_PORT1_DISABLE() \ 366 I_LD(R0, R3, RTCMEM_PORT1_RX_ENABLED), \ 368 CONFIGURE_CLK_OUTPUT(PS2_PORT1), \ 369 WRITE_CLK(PS2_PORT1, 0) 374 #define TEMP_PORT1_ENABLE() \ 375 I_LD(R0, R3, RTCMEM_PORT1_RX_ENABLED), \ 377 CONFIGURE_CLK_INPUT(PS2_PORT1) 381 #define PERM_PORT0_DISABLE() \ 383 I_ST(R0, R3, RTCMEM_PORT0_RX_ENABLED), \ 384 CONFIGURE_CLK_OUTPUT(PS2_PORT0), \ 385 WRITE_CLK(PS2_PORT0, 0) 389 #define PERM_PORT1_DISABLE() \ 391 I_ST(R0, R3, RTCMEM_PORT1_RX_ENABLED), \ 392 CONFIGURE_CLK_OUTPUT(PS2_PORT1), \ 393 WRITE_CLK(PS2_PORT1, 0) 421 const ulp_insn_t ULP_code[] = {
434 M_LABEL(LABEL_WAIT_COMMAND),
437 I_LD(R0, R3, RTCMEM_PORT0_TX),
438 M_BGE(LABEL_PORT0_TX, 1),
441 I_LD(R0, R3, RTCMEM_PORT0_RX_ENABLE),
442 M_BGE(LABEL_PORT0_ENABLE_RX, 1),
445 I_LD(R0, R3, RTCMEM_PORT0_RX_DISABLE),
446 M_BGE(LABEL_PORT0_STOP_RX, 1),
449 I_LD(R0, R3, RTCMEM_PORT1_TX),
450 M_BGE(LABEL_PORT1_TX, 1),
453 I_LD(R0, R3, RTCMEM_PORT1_RX_ENABLE),
454 M_BGE(LABEL_PORT1_ENABLE_RX, 1),
457 I_LD(R0, R3, RTCMEM_PORT1_RX_DISABLE),
458 M_BGE(LABEL_PORT1_STOP_RX, 1),
467 M_LABEL(LABEL_PORT0_ENABLE_RX),
471 I_ST(R0, R3, RTCMEM_PORT0_RX_ENABLED),
474 CONFIGURE_CLK_INPUT(PS2_PORT0),
475 CONFIGURE_DAT_INPUT(PS2_PORT0),
479 I_ST(R0, R3, RTCMEM_PORT0_RX_ENABLE),
487 M_LABEL(LABEL_PORT1_ENABLE_RX),
491 I_ST(R0, R3, RTCMEM_PORT1_RX_ENABLED),
494 CONFIGURE_CLK_INPUT(PS2_PORT1),
495 CONFIGURE_DAT_INPUT(PS2_PORT1),
499 I_ST(R0, R3, RTCMEM_PORT1_RX_ENABLE),
507 M_LABEL(LABEL_PORT0_STOP_RX),
509 PERM_PORT0_DISABLE(),
513 I_ST(R0, R3, RTCMEM_PORT0_RX_DISABLE),
521 M_LABEL(LABEL_PORT1_STOP_RX),
523 PERM_PORT1_DISABLE(),
527 I_ST(R0, R3, RTCMEM_PORT1_RX_DISABLE),
536 M_LABEL(LABEL_PORT0_TX),
541 I_LD(R2, R3, RTCMEM_PORT0_DATAOUT),
547 TEMP_PORT1_DISABLE(),
550 CONFIGURE_CLK_OUTPUT(PS2_PORT0),
551 WRITE_CLK(PS2_PORT0, 0),
553 CONFIGURE_DAT_OUTPUT(PS2_PORT0),
554 WRITE_DAT(PS2_PORT0, 0),
557 CONFIGURE_CLK_INPUT(PS2_PORT0),
559 M_LABEL(LABEL_PORT0_TX_NEXT_BIT),
566 M_BGE(LABEL_PORT0_TX_EXIT, CLK_TX_TIMEOUT_VAL),
572 M_BGE(LABEL_PORT0_TX_NEXT_BIT, 1),
578 M_STAGEBGE(LABEL_PORT0_TX_WAIT_CLK_HIGH, 10),
582 WRITE_DAT_R0(PS2_PORT0),
584 M_LABEL(LABEL_PORT0_TX_WAIT_CLK_HIGH),
592 M_BL(LABEL_PORT0_TX_WAIT_CLK_HIGH, 1),
601 M_STAGEBL(LABEL_PORT0_TX_NEXT_BIT, 11),
603 M_LABEL(LABEL_PORT0_TX_EXIT),
609 CONFIGURE_DAT_INPUT(PS2_PORT0),
611 I_ST(R0, R3, RTCMEM_PORT0_RX_ENABLED),
615 I_ST(R0, R3, RTCMEM_PORT0_TX),
631 M_LABEL(LABEL_PORT1_TX),
636 I_LD(R2, R3, RTCMEM_PORT1_DATAOUT),
642 TEMP_PORT0_DISABLE(),
645 CONFIGURE_CLK_OUTPUT(PS2_PORT1),
646 WRITE_CLK(PS2_PORT1, 0),
648 CONFIGURE_DAT_OUTPUT(PS2_PORT1),
649 WRITE_DAT(PS2_PORT1, 0),
652 CONFIGURE_CLK_INPUT(PS2_PORT1),
654 M_LABEL(LABEL_PORT1_TX_NEXT_BIT),
661 M_BGE(LABEL_PORT1_TX_EXIT, CLK_TX_TIMEOUT_VAL),
667 M_BGE(LABEL_PORT1_TX_NEXT_BIT, 1),
673 M_STAGEBGE(LABEL_PORT1_TX_WAIT_CLK_HIGH, 10),
677 WRITE_DAT_R0(PS2_PORT1),
679 M_LABEL(LABEL_PORT1_TX_WAIT_CLK_HIGH),
687 M_BL(LABEL_PORT1_TX_WAIT_CLK_HIGH, 1),
696 M_STAGEBL(LABEL_PORT1_TX_NEXT_BIT, 11),
698 M_LABEL(LABEL_PORT1_TX_EXIT),
704 CONFIGURE_DAT_INPUT(PS2_PORT1),
706 I_ST(R0, R3, RTCMEM_PORT1_RX_ENABLED),
710 I_ST(R0, R3, RTCMEM_PORT1_TX),
725 M_LABEL(LABEL_PORT0_RX_CLK_TIMEOUT),
731 PERM_PORT0_DISABLE(),
738 I_ST(R0, R3, RTCMEM_PORT0_RX_CLK_TIMEOUT),
751 M_LABEL(LABEL_PORT1_RX_CLK_TIMEOUT),
757 PERM_PORT1_DISABLE(),
764 I_ST(R0, R3, RTCMEM_PORT1_RX_CLK_TIMEOUT),
782 I_LD(R0, R3, RTCMEM_PORT0_RX_ENABLED),
783 M_BGE(LABEL_PORT0_RX_CHECK_CLK, 1),
788 M_BL(LABEL_RX_NEXT, WAKE_THRESHOLD),
793 M_LABEL(LABEL_PORT0_RX_CHECK_CLK),
799 M_BGE(LABEL_RX_NEXT, 1),
805 I_ST(R0, R3, RTCMEM_PORT0_DATAIN),
810 TEMP_PORT1_DISABLE(),
813 M_BX(LABEL_PORT0_RX_CLK_IS_LOW),
815 M_LABEL(LABEL_PORT0_RX_WAIT_LOOP),
820 M_BGE(LABEL_PORT0_RX_CLK_TIMEOUT, CLK_RX_TIMEOUT_VAL),
827 M_BXZ(LABEL_PORT0_RX_WAIT_LOOP),
836 M_BGE(LABEL_PORT0_RX_CLK_IS_HIGH, 1),
838 M_LABEL(LABEL_PORT0_RX_CLK_IS_LOW),
845 I_LD(R1, R3, RTCMEM_PORT0_DATAIN),
848 I_ST(R1, R3, RTCMEM_PORT0_DATAIN),
851 M_BX(LABEL_PORT0_RX_WAIT_LOOP),
853 M_LABEL(LABEL_PORT0_RX_CLK_IS_HIGH),
859 M_STAGEBL(LABEL_PORT0_RX_WAIT_LOOP, 11),
862 PERM_PORT0_DISABLE(),
866 I_ST(R0, R3, RTCMEM_PORT0_RX),
884 M_LABEL(LABEL_RX_NEXT),
887 I_LD(R0, R3, RTCMEM_PORT1_RX_ENABLED),
888 M_BGE(LABEL_PORT1_RX_CHECK_CLK, 1),
893 M_LONG_BL(LABEL_WAIT_COMMAND, WAKE_THRESHOLD),
896 M_BX(LABEL_WAIT_COMMAND),
898 M_LABEL(LABEL_PORT1_RX_CHECK_CLK),
904 M_LONG_BGE(LABEL_WAIT_COMMAND, 1),
910 I_ST(R0, R3, RTCMEM_PORT1_DATAIN),
915 TEMP_PORT0_DISABLE(),
918 M_BX(LABEL_PORT1_RX_CLK_IS_LOW),
920 M_LABEL(LABEL_PORT1_RX_WAIT_LOOP),
925 M_BGE(LABEL_PORT1_RX_CLK_TIMEOUT, CLK_RX_TIMEOUT_VAL),
932 M_BXZ(LABEL_PORT1_RX_WAIT_LOOP),
941 M_BGE(LABEL_PORT1_RX_CLK_IS_HIGH, 1),
943 M_LABEL(LABEL_PORT1_RX_CLK_IS_LOW),
950 I_LD(R1, R3, RTCMEM_PORT1_DATAIN),
953 I_ST(R1, R3, RTCMEM_PORT1_DATAIN),
956 M_BX(LABEL_PORT1_RX_WAIT_LOOP),
958 M_LABEL(LABEL_PORT1_RX_CLK_IS_HIGH),
964 M_STAGEBL(LABEL_PORT1_RX_WAIT_LOOP, 11),
967 PERM_PORT1_DISABLE(),
971 I_ST(R0, R3, RTCMEM_PORT1_RX),
984 M_BX(LABEL_WAIT_COMMAND),
995 static void replace_placeholders(uint32_t prg_start,
int size,
bool port0Enabled, gpio_num_t port0_clkGPIO, gpio_num_t port0_datGPIO,
bool port1Enabled, gpio_num_t port1_clkGPIO, gpio_num_t port1_datGPIO)
997 uint32_t CLK_rtc_gpio_num[2], CLK_rtc_gpio_reg[2], CLK_rtc_gpio_ie_s[2];
998 uint32_t DAT_rtc_gpio_num[2], DAT_rtc_gpio_reg[2], DAT_rtc_gpio_ie_s[2];
1001 #if FABGL_ESP_IDF_VERSION <= FABGL_ESP_IDF_VERSION_VAL(3, 3, 5) 1002 CLK_rtc_gpio_num[0] = (uint32_t) rtc_gpio_desc[port0_clkGPIO].rtc_num;
1003 CLK_rtc_gpio_reg[0] = rtc_gpio_desc[port0_clkGPIO].reg;
1004 CLK_rtc_gpio_ie_s[0] = (uint32_t) ffs(rtc_gpio_desc[port0_clkGPIO].ie) - 1;
1005 DAT_rtc_gpio_num[0] = (uint32_t) rtc_gpio_desc[port0_datGPIO].rtc_num;
1006 DAT_rtc_gpio_reg[0] = rtc_gpio_desc[port0_datGPIO].reg;
1007 DAT_rtc_gpio_ie_s[0] = (uint32_t) ffs(rtc_gpio_desc[port0_datGPIO].ie) - 1;
1009 int port0_clkIO = rtc_io_number_get(port0_clkGPIO);
1010 CLK_rtc_gpio_num[0] = port0_clkIO;
1011 CLK_rtc_gpio_reg[0] = rtc_io_desc[port0_clkIO].reg;
1012 CLK_rtc_gpio_ie_s[0] = (uint32_t) ffs(rtc_io_desc[port0_clkIO].ie) - 1;
1013 int port0_datIO = rtc_io_number_get(port0_datGPIO);
1014 DAT_rtc_gpio_num[0] = port0_datIO;
1015 DAT_rtc_gpio_reg[0] = rtc_io_desc[port0_datIO].reg;
1016 DAT_rtc_gpio_ie_s[0] = (uint32_t) ffs(rtc_io_desc[port0_datIO].ie) - 1;
1021 #if FABGL_ESP_IDF_VERSION <= FABGL_ESP_IDF_VERSION_VAL(3, 3, 5) 1022 CLK_rtc_gpio_num[1] = (uint32_t) rtc_gpio_desc[port1_clkGPIO].rtc_num;
1023 CLK_rtc_gpio_reg[1] = rtc_gpio_desc[port1_clkGPIO].reg;
1024 CLK_rtc_gpio_ie_s[1] = (uint32_t) ffs(rtc_gpio_desc[port1_clkGPIO].ie) - 1;
1025 DAT_rtc_gpio_num[1] = (uint32_t) rtc_gpio_desc[port1_datGPIO].rtc_num;
1026 DAT_rtc_gpio_reg[1] = rtc_gpio_desc[port1_datGPIO].reg;
1027 DAT_rtc_gpio_ie_s[1] = (uint32_t) ffs(rtc_gpio_desc[port1_datGPIO].ie) - 1;
1029 int port1_clkIO = rtc_io_number_get(port1_clkGPIO);
1030 CLK_rtc_gpio_num[1] = port1_clkIO;
1031 CLK_rtc_gpio_reg[1] = rtc_io_desc[port1_clkIO].reg;
1032 CLK_rtc_gpio_ie_s[1] = (uint32_t) ffs(rtc_io_desc[port1_clkIO].ie) - 1;
1033 int port1_datIO = rtc_io_number_get(port1_datGPIO);
1034 DAT_rtc_gpio_num[1] = port1_datIO;
1035 DAT_rtc_gpio_reg[1] = rtc_io_desc[port1_datIO].reg;
1036 DAT_rtc_gpio_ie_s[1] = (uint32_t) ffs(rtc_io_desc[port1_datIO].ie) - 1;
1040 for (uint32_t i = 0; i < size; ++i) {
1041 ulp_insn_t * ins = (ulp_insn_t *) RTC_SLOW_MEM + i;
1042 if (ins->macro.opcode == OPCODE_PLACEHOLDER) {
1043 int ps2port = ins->macro.unused;
1044 if ((port0Enabled && ps2port == 0) || (port1Enabled && ps2port == 1)) {
1045 ins->macro.unused = 0;
1046 switch (ins->macro.sub_opcode) {
1047 case SUB_OPCODE_DAT_ENABLE_OUTPUT:
1048 if (ins->macro.label)
1049 *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_ENABLE_W1TS_REG, DAT_rtc_gpio_num[ps2port] + RTC_GPIO_ENABLE_W1TS_S, 1);
1051 *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_ENABLE_W1TC_REG, DAT_rtc_gpio_num[ps2port] + RTC_GPIO_ENABLE_W1TC_S, 1);
1053 case SUB_OPCODE_DAT_ENABLE_INPUT:
1054 *ins = (ulp_insn_t) I_WR_REG_BIT(DAT_rtc_gpio_reg[ps2port], DAT_rtc_gpio_ie_s[ps2port], ins->macro.label);
1056 case SUB_OPCODE_CLK_ENABLE_OUTPUT:
1057 if (ins->macro.label)
1058 *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_ENABLE_W1TS_REG, CLK_rtc_gpio_num[ps2port] + RTC_GPIO_ENABLE_W1TS_S, 1);
1060 *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_ENABLE_W1TC_REG, CLK_rtc_gpio_num[ps2port] + RTC_GPIO_ENABLE_W1TC_S, 1);
1062 case SUB_OPCODE_CLK_ENABLE_INPUT:
1063 *ins = (ulp_insn_t) I_WR_REG_BIT(CLK_rtc_gpio_reg[ps2port], CLK_rtc_gpio_ie_s[ps2port], ins->macro.label);
1065 case SUB_OPCODE_READ_CLK:
1066 *ins = (ulp_insn_t) I_RD_REG(RTC_GPIO_IN_REG, CLK_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S, CLK_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S);
1068 case SUB_OPCODE_READ_DAT:
1069 *ins = (ulp_insn_t) I_RD_REG(RTC_GPIO_IN_REG, DAT_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S, DAT_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S);
1071 case SUB_OPCODE_WRITE_CLK:
1072 *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_OUT_REG, CLK_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S, ins->macro.label);
1074 case SUB_OPCODE_WRITE_DAT:
1075 *ins = (ulp_insn_t) I_WR_REG_BIT(RTC_GPIO_OUT_REG, DAT_rtc_gpio_num[ps2port] + RTC_GPIO_IN_NEXT_S, ins->macro.label);
1084 PS2Controller * PS2Controller::s_instance =
nullptr;
1085 Keyboard * PS2Controller::s_keyboard =
nullptr;
1086 Mouse * PS2Controller::s_mouse =
nullptr;
1087 bool PS2Controller::s_keyboardAllocated =
false;
1088 bool PS2Controller::s_mouseAllocated =
false;
1089 bool PS2Controller::s_portEnabled[2];
1090 intr_handle_t PS2Controller::s_ULPWakeISRHandle;
1091 bool PS2Controller::s_parityError[2];
1092 bool PS2Controller::s_syncError[2];
1093 bool PS2Controller::s_CLKTimeOutError[2];
1094 QueueHandle_t PS2Controller::s_dataIn[2];
1095 SemaphoreHandle_t PS2Controller::s_portLock[2];
1096 bool PS2Controller::s_initDone =
false;
1099 PS2Controller::PS2Controller()
1106 PS2Controller::~PS2Controller()
1109 if (
this == s_instance)
1110 s_instance =
nullptr;
1115 void PS2Controller::begin(gpio_num_t port0_clkGPIO, gpio_num_t port0_datGPIO, gpio_num_t port1_clkGPIO, gpio_num_t port1_datGPIO)
1120 s_portEnabled[0] = (port0_clkGPIO != GPIO_UNUSED && port0_datGPIO != GPIO_UNUSED);
1121 s_portEnabled[1] = (port1_clkGPIO != GPIO_UNUSED && port1_datGPIO != GPIO_UNUSED);
1123 if (s_portEnabled[0]) {
1124 if (!rtc_gpio_is_valid_gpio(port0_clkGPIO) || !rtc_gpio_is_valid_gpio(port0_datGPIO)) {
1125 ESP_LOGE(
"FabGL",
"Invalid PS/2 Port 0 pins");
1126 s_portEnabled[0] =
false;
1128 rtc_gpio_init(port0_clkGPIO);
1129 rtc_gpio_init(port0_datGPIO);
1133 if (s_portEnabled[1]) {
1134 if (!rtc_gpio_is_valid_gpio(port1_clkGPIO) || !rtc_gpio_is_valid_gpio(port1_datGPIO)) {
1135 ESP_LOGE(
"FabGL",
"Invalid PS/2 Port 1 pins");
1136 s_portEnabled[1] =
false;
1138 rtc_gpio_init(port1_clkGPIO);
1139 rtc_gpio_init(port1_datGPIO);
1144 for (
int i = RTCMEM_PROG_START; i < RTCMEM_LASTVAR; ++i)
1145 RTC_SLOW_MEM[i] = 0x0000;
1148 size_t size =
sizeof(ULP_code) /
sizeof(ulp_insn_t);
1149 ulp_process_macros_and_load_ex(RTCMEM_PROG_START, ULP_code, &size);
1150 replace_placeholders(RTCMEM_PROG_START, size, s_portEnabled[0], port0_clkGPIO, port0_datGPIO, s_portEnabled[1], port1_clkGPIO, port1_datGPIO);
1152 assert(size < RTCMEM_VARS_START &&
"ULP Program too long, increase RTCMEM_VARS_START");
1154 REG_SET_FIELD(SENS_SAR_START_FORCE_REG, SENS_PC_INIT, RTCMEM_PROG_START);
1155 SET_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_FORCE_START_TOP);
1157 for (
int p = 0; p < 2; ++p) {
1158 RTC_SLOW_MEM[RTCMEM_PORT0_TX + p] = 0;
1159 RTC_SLOW_MEM[RTCMEM_PORT0_RX_ENABLE + p] = 0;
1160 RTC_SLOW_MEM[RTCMEM_PORT0_RX_DISABLE + p] = 0;
1161 RTC_SLOW_MEM[RTCMEM_PORT0_RX + p] = 0;
1162 RTC_SLOW_MEM[RTCMEM_PORT0_RX_ENABLED + p] = 0;
1163 s_parityError[p] = s_syncError[p] =
false;
1164 s_dataIn[p] = (s_portEnabled[p] ? xQueueCreate(1,
sizeof(uint16_t)) :
nullptr);
1165 s_portLock[p] = (s_portEnabled[p] ? xSemaphoreCreateRecursiveMutex() :
nullptr);
1170 SET_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_START_TOP);
1175 esp_intr_alloc_pinnedToCore(ETS_RTC_CORE_INTR_SOURCE, ESP_INTR_FLAG_LEVEL2, ULPWakeISR,
nullptr, &s_ULPWakeISRHandle, 1);
1176 SET_PERI_REG_MASK(RTC_CNTL_INT_ENA_REG, RTC_CNTL_ULP_CP_INT_ENA);
1183 for (
int p = 0; p < 2; ++p) {
1184 RTC_SLOW_MEM[RTCMEM_PORT0_TX + p] = 0;
1185 RTC_SLOW_MEM[RTCMEM_PORT0_RX_ENABLE + p] = 0;
1186 RTC_SLOW_MEM[RTCMEM_PORT0_RX_DISABLE + p] = 0;
1187 RTC_SLOW_MEM[RTCMEM_PORT0_RX + p] = 0;
1188 RTC_SLOW_MEM[RTCMEM_PORT0_RX_ENABLED + p] = 0;
1189 s_parityError[p] = s_syncError[p] =
false;
1190 if (s_portEnabled[p]) {
1191 xQueueReset(s_dataIn[p]);
1192 xSemaphoreGiveRecursive(s_portLock[p]);
1209 begin(GPIO_NUM_33, GPIO_NUM_32, GPIO_NUM_26, GPIO_NUM_27);
1212 setMouse(
new Mouse);
1214 s_keyboardAllocated = s_mouseAllocated =
true;
1218 begin(GPIO_NUM_33, GPIO_NUM_32, GPIO_NUM_26, GPIO_NUM_27);
1219 setMouse(
new Mouse);
1223 s_keyboardAllocated = s_mouseAllocated =
true;
1228 (
new Keyboard)->
begin(GPIO_NUM_33, GPIO_NUM_32, generateVirtualKeys, createVKQueue);
1229 s_keyboardAllocated =
true;
1234 (
new Keyboard)->
begin(GPIO_NUM_26, GPIO_NUM_27, generateVirtualKeys, createVKQueue);
1235 s_keyboardAllocated =
true;
1240 (
new Mouse)->
begin(GPIO_NUM_33, GPIO_NUM_32);
1241 s_mouseAllocated =
true;
1246 (
new Mouse)->
begin(GPIO_NUM_26, GPIO_NUM_27);
1247 s_mouseAllocated =
true;
1253 void PS2Controller::end()
1256 if (s_keyboardAllocated)
1258 s_keyboard =
nullptr;
1260 if (s_mouseAllocated)
1264 for (
int p = 0; p < 2; ++p)
1272 if (s_portEnabled[PS2Port])
1273 RTC_SLOW_MEM[RTCMEM_PORT0_RX_DISABLE + PS2Port] = 1;
1279 if (s_portEnabled[PS2Port]) {
1282 RTC_SLOW_MEM[RTCMEM_PORT0_RX_ENABLE + PS2Port] = 1;
1289 return uxQueueMessagesWaiting(s_dataIn[PS2Port]);
1299 if (xQueueReceive(s_dataIn[PS2Port], &w, msToTicks(timeOutMS))) {
1302 s_CLKTimeOutError[PS2Port] = (w == 0xffff);
1303 if (!s_CLKTimeOutError[PS2Port]) {
1304 uint8_t startBit = w & 1;
1305 uint8_t stopBit = (w >> 10) & 1;
1306 uint8_t parity = (w >> 9) & 1;
1307 r = (w >> 1) & 0xff;
1308 s_parityError[PS2Port] = (parity != !calcParity(r));
1309 s_syncError[PS2Port] = (startBit != 0 || stopBit != 1);
1310 if (s_parityError[PS2Port] || s_syncError[PS2Port])
1315 RTC_SLOW_MEM[RTCMEM_PORT0_RX_ENABLE + PS2Port] = 1;
1325 if (s_portEnabled[PS2Port]) {
1326 RTC_SLOW_MEM[RTCMEM_PORT0_DATAOUT + PS2Port] = 0x200 | ((!calcParity(
data) & 1) << 8) |
data;
1327 RTC_SLOW_MEM[RTCMEM_PORT0_TX + PS2Port] = 1;
1334 return s_portEnabled[PS2Port] ? xSemaphoreTakeRecursive(s_portLock[PS2Port], msToTicks(timeOutMS)) :
true;
1340 if (s_portEnabled[PS2Port])
1341 xSemaphoreGiveRecursive(s_portLock[PS2Port]);
1346 void IRAM_ATTR PS2Controller::ULPWakeISR(
void * arg)
1348 uint32_t rtc_intr = READ_PERI_REG(RTC_CNTL_INT_ST_REG);
1350 if (rtc_intr & RTC_CNTL_SAR_INT_ST) {
1352 for (
int p = 0; p < 2; ++p) {
1353 if (RTC_SLOW_MEM[RTCMEM_PORT0_RX + p] & 0xffff) {
1355 uint16_t d = RTC_SLOW_MEM[RTCMEM_PORT0_DATAIN + p] & 0xffff;
1356 xQueueOverwriteFromISR(PS2Controller::s_dataIn[p], &d,
nullptr);
1357 RTC_SLOW_MEM[RTCMEM_PORT0_RX + p] = 0;
1358 }
else if (RTC_SLOW_MEM[RTCMEM_PORT0_RX_CLK_TIMEOUT + p] & 0xffff) {
1360 uint16_t d = 0xffff;
1361 xQueueOverwriteFromISR(PS2Controller::s_dataIn[p], &d,
nullptr);
1362 RTC_SLOW_MEM[RTCMEM_PORT0_RX_CLK_TIMEOUT + p] = 0;
1369 WRITE_PERI_REG(RTC_CNTL_INT_CLR_REG, rtc_intr);
This file contains fabgl::PS2Controller definition.
This file contains fabgl::Keyboard definition.
static bool lock(int PS2Port, int timeOutMS)
Gets exclusive access to the specified PS/2 port.
static Mouse * mouse()
Returns the instance of Mouse object automatically created by PS2Controller.
The PS2 Keyboard controller class.
This file contains fabgl::Mouse definition.
static bool dataAvailable(int PS2Port)
Determines if one byte has been received from the specified port.
static void sendData(uint8_t data, int PS2Port)
Sends a command to the device.
static int getData(int PS2Port, int timeOutMS)
Gets a scancode from the queue.
void begin(gpio_num_t clkGPIO, gpio_num_t dataGPIO, bool generateVirtualKeys=true, bool createVKQueue=true)
Initializes Keyboard specifying CLOCK and DATA GPIOs.
static void unlock(int PS2Port)
Releases port from exclusive access.
This file contains some utility classes and functions.
KbdMode
This enum defines how handle keyboard virtual keys.
static Keyboard * keyboard()
Returns the instance of Keyboard object automatically created by PS2Controller.
static void disableRX(int PS2Port)
Disables inputs from PS/2 port driving the CLK line Low.
void begin(gpio_num_t clkGPIO, gpio_num_t dataGPIO)
Initializes Mouse specifying CLOCK and DATA GPIOs.
static void enableRX(int PS2Port)
Enables inputs from PS/2 port releasing CLK line.
PS2Preset
This enum defines what is connected to PS/2 ports.
The PS2 Mouse controller class.
static void begin(gpio_num_t port0_clkGPIO, gpio_num_t port0_datGPIO, gpio_num_t port1_clkGPIO=GPIO_UNUSED, gpio_num_t port1_datGPIO=GPIO_UNUSED)
Initializes PS2 device controller.