From 3bd0be40d502f43bb9f941a60bf778b902ed4e6e Mon Sep 17 00:00:00 2001
From: Kevin O'Connor <kevin@koconnor.net>
Date: Wed, 3 May 2023 10:45:41 -0400
Subject: [PATCH] lib: Update to latest can2040 code

Disable tx state machine before resetting it
Check for rx message with same id as tx but different payload
Do not use canrx line to alter bit timing of cantx line
Improve bit time synchronization with slow transmitters
Implement tx synchronization to faster transmitters

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
---
 lib/can2040/can2040.c | 65 ++++++++++++++++++++++++++-----------------
 1 file changed, 39 insertions(+), 26 deletions(-)

diff --git a/lib/can2040/can2040.c b/lib/can2040/can2040.c
index 9eef0d43d..926893d94 100644
--- a/lib/can2040/can2040.c
+++ b/lib/can2040/can2040.c
@@ -76,21 +76,21 @@ rp2040_gpio_peripheral(uint32_t gpio, int func, int pull_up)
 #define can2040_offset_shared_rx_read 13u
 #define can2040_offset_shared_rx_end 15u
 #define can2040_offset_match_load_next 18u
+#define can2040_offset_tx_conflict 24u
 #define can2040_offset_match_end 25u
 #define can2040_offset_tx_got_recessive 25u
-#define can2040_offset_tx_start 26u
-#define can2040_offset_tx_conflict 31u
+#define can2040_offset_tx_write_pin 27u
 
 static const uint16_t can2040_program_instructions[] = {
     0x0085, //  0: jmp    y--, 5
     0x0048, //  1: jmp    x--, 8
-    0xe12a, //  2: set    x, 10                  [1]
+    0xe029, //  2: set    x, 9
     0x00cc, //  3: jmp    pin, 12
     0xc000, //  4: irq    nowait 0
     0x00c0, //  5: jmp    pin, 0
     0xc040, //  6: irq    clear 0
-    0xe229, //  7: set    x, 9                   [2]
-    0xf242, //  8: set    y, 2                   [18]
+    0xe429, //  7: set    x, 9                   [4]
+    0xf043, //  8: set    y, 3                   [16]
     0xc104, //  9: irq    nowait 4               [1]
     0x03c5, // 10: jmp    pin, 5                 [3]
     0x0307, // 11: jmp    7                      [3]
@@ -98,7 +98,7 @@ static const uint16_t can2040_program_instructions[] = {
     0x20c4, // 13: wait   1 irq, 4
     0x4001, // 14: in     pins, 1
     0xa046, // 15: mov    y, isr
-    0x00b2, // 16: jmp    x != y, 18
+    0x01b2, // 16: jmp    x != y, 18             [1]
     0xc002, // 17: irq    nowait 2
     0x40eb, // 18: in     osr, 11
     0x4054, // 19: in     y, 20
@@ -107,13 +107,13 @@ static const uint16_t can2040_program_instructions[] = {
     0xa027, // 22: mov    x, osr
     0x0098, // 23: jmp    y--, 24
     0xa0e2, // 24: mov    osr, y
-    0xa242, // 25: nop                           [2]
-    0x6021, // 26: out    x, 1
-    0xa001, // 27: mov    pins, x
-    0x20c4, // 28: wait   1 irq, 4
-    0x00d9, // 29: jmp    pin, 25
-    0x023a, // 30: jmp    !x, 26                 [2]
-    0x001f, // 31: jmp    31
+    0x6021, // 25: out    x, 1
+    0x00df, // 26: jmp    pin, 31
+    0xb801, // 27: mov    pins, x                [24]
+    0x02d9, // 28: jmp    pin, 25                [2]
+    0x0058, // 29: jmp    x--, 24
+    0x6021, // 30: out    x, 1
+    0x011b, // 31: jmp    27                     [1]
 };
 
 // Local names for PIO state machine IRQs
@@ -138,7 +138,7 @@ pio_sync_setup(struct can2040 *cd)
         | cd->gpio_rx << PIO_SM0_PINCTRL_SET_BASE_LSB);
     sm->instr = 0xe080; // set pindirs, 0
     sm->pinctrl = 0;
-    pio_hw->txf[0] = PIO_CLOCK_PER_BIT / 2 * 7 - 5 - 1;
+    pio_hw->txf[0] = 9 + 6 * PIO_CLOCK_PER_BIT / 2;
     sm->instr = 0x80a0; // pull block
     sm->instr = can2040_offset_sync_entry; // jmp sync_entry
 }
@@ -183,7 +183,10 @@ pio_tx_setup(struct can2040 *cd)
 {
     pio_hw_t *pio_hw = cd->pio_hw;
     struct pio_sm_hw *sm = &pio_hw->sm[3];
-    sm->execctrl = cd->gpio_rx << PIO_SM0_EXECCTRL_JMP_PIN_LSB;
+    sm->execctrl = (
+        cd->gpio_rx << PIO_SM0_EXECCTRL_JMP_PIN_LSB
+        | can2040_offset_tx_conflict << PIO_SM0_EXECCTRL_WRAP_TOP_LSB
+        | can2040_offset_tx_conflict << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB);
     sm->shiftctrl = (PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS
                      | PIO_SM0_SHIFTCTRL_AUTOPULL_BITS);
     sm->pinctrl = (1 << PIO_SM0_PINCTRL_SET_COUNT_LSB
@@ -247,6 +250,7 @@ static void
 pio_tx_reset(struct can2040 *cd)
 {
     pio_hw_t *pio_hw = cd->pio_hw;
+    pio_hw->ctrl = 0x07 << PIO_CTRL_SM_ENABLE_LSB;
     pio_hw->ctrl = ((0x07 << PIO_CTRL_SM_ENABLE_LSB)
                     | (0x08 << PIO_CTRL_SM_RESTART_LSB));
     pio_hw->irq = (SI_MATCHED | SI_ACKDONE) >> 8; // clear PIO irq flags
@@ -255,9 +259,6 @@ pio_tx_reset(struct can2040 *cd)
     sm->shiftctrl = 0;
     sm->shiftctrl = (PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS
                      | PIO_SM0_SHIFTCTRL_AUTOPULL_BITS);
-    // Must reset again after clearing fifo
-    pio_hw->ctrl = ((0x07 << PIO_CTRL_SM_ENABLE_LSB)
-                    | (0x08 << PIO_CTRL_SM_RESTART_LSB));
 }
 
 // Queue a message for transmission on PIO "tx" state machine
@@ -266,13 +267,14 @@ pio_tx_send(struct can2040 *cd, uint32_t *data, uint32_t count)
 {
     pio_hw_t *pio_hw = cd->pio_hw;
     pio_tx_reset(cd);
-    pio_hw->instr_mem[can2040_offset_tx_got_recessive] = 0xa242; // nop [2]
+    pio_hw->instr_mem[can2040_offset_tx_got_recessive] = 0x6021; // out x, 1
     uint32_t i;
     for (i=0; i<count; i++)
         pio_hw->txf[3] = data[i];
     struct pio_sm_hw *sm = &pio_hw->sm[3];
     sm->instr = 0xe001; // set pins, 1
-    sm->instr = can2040_offset_tx_start; // jmp tx_start
+    sm->instr = 0x6021; // out x, 1
+    sm->instr = can2040_offset_tx_write_pin; // jmp tx_write_pin
     sm->instr = 0x20c0; // wait 1 irq, 0
     pio_hw->ctrl = 0x0f << PIO_CTRL_SM_ENABLE_LSB;
 }
@@ -287,7 +289,8 @@ pio_tx_inject_ack(struct can2040 *cd, uint32_t match_key)
     pio_hw->txf[3] = 0x7fffffff;
     struct pio_sm_hw *sm = &pio_hw->sm[3];
     sm->instr = 0xe001; // set pins, 1
-    sm->instr = can2040_offset_tx_start; // jmp tx_start
+    sm->instr = 0x6021; // out x, 1
+    sm->instr = can2040_offset_tx_write_pin; // jmp tx_write_pin
     sm->instr = 0x20c2; // wait 1 irq, 2
     pio_hw->ctrl = 0x0f << PIO_CTRL_SM_ENABLE_LSB;
 
@@ -680,8 +683,11 @@ tx_check_local_message(struct can2040 *cd)
         return 0;
     struct can2040_transmit *qt = &cd->tx_queue[tx_qpos(cd, cd->tx_pull_pos)];
     struct can2040_msg *pm = &cd->parse_msg, *tm = &qt->msg;
-    if (qt->crc == cd->parse_crc && tm->id == pm->id && tm->dlc == pm->dlc
-        && tm->data32[0] == pm->data32[0] && tm->data32[1] == pm->data32[1]) {
+    if (tm->id == pm->id) {
+        if (qt->crc != cd->parse_crc || tm->dlc != pm->dlc
+            || tm->data32[0] != pm->data32[0] || tm->data32[1] != pm->data32[1])
+            // Message with same id that differs in content - an error
+            return -1;
         // This is a self transmit
         cd->tx_state = TS_CONFIRM_TX;
         return 1;
@@ -757,22 +763,25 @@ report_note_message_start(struct can2040 *cd)
 }
 
 // Setup for ack injection (if receiving) or ack confirmation (if transmit)
-static void
+static int
 report_note_crc_start(struct can2040 *cd)
 {
     int ret = tx_check_local_message(cd);
     if (ret) {
+        if (ret < 0)
+            return -1;
         // This is a self transmit - setup tx eof "matched" signal
         cd->report_state = RS_NEED_TX_ACK;
         uint32_t bits = (cd->parse_crc_bits << 9) | 0x0ff;
         pio_match_check(cd, pio_match_calc_key(bits, cd->parse_crc_pos + 9));
-        return;
+        return 0;
     }
 
     // Setup for ack inject (after rx fifos fully drained)
     cd->report_state = RS_NEED_RX_ACK;
     pio_signal_set_txpending(cd);
     pio_irq_set(cd, SI_MAYTX | SI_TXPENDING);
+    return 0;
 }
 
 // Parser successfully found matching crc
@@ -961,7 +970,11 @@ data_state_go_crc(struct can2040 *cd)
     cd->parse_crc_bits = (crc_bits << 1) | 0x01; // Add crc delimiter
     cd->parse_crc_pos = crcstart_bitpos + crc_bitcount + 1;
 
-    report_note_crc_start(cd);
+    int ret = report_note_crc_start(cd);
+    if (ret) {
+        data_state_go_discard(cd);
+        return;
+    }
     data_state_go_next(cd, MS_CRC, 16);
 }