/ src / usb_rx.pio
usb_rx.pio
  1  
  2  ; Copyright (c) 2021-2024 sekigon-gonnoc
  3  
  4  .define public IRQ_RX_BS_ERR    1   ; bit stuffinc error
  5  .define public IRQ_RX_EOP       2   ; eop detect flag
  6  .define public IRQ_RX_START     3   ; packet start flag
  7  .define public DECODER_TRIGGER  4
  8  
  9  .define BIT_REPEAT_COUNT 6        ; bit repeat counter
 10  
 11  .define db0 0
 12  .define db1 1
 13  
 14  ; USB signal edge and eop detector
 15  ; 17 instruction
 16  ;            FS(12M)  LS(1.5M)
 17  ; Run at     96MHz    12MHz
 18  ; jmp_pin    d-       d+ 
 19  ; in_pin     d+       d-
 20  ; both d+/d- pin should be input invert overrideed
 21  .program usb_edge_detector
 22  eop:
 23      irq wait IRQ_RX_EOP
 24  start:
 25      jmp pin start               ; Wait fall edge
 26      irq IRQ_RX_START [1]
 27  
 28  .wrap_target
 29  pin_still_low:
 30      irq DECODER_TRIGGER [1]		; Trigger NRZI decoder
 31  
 32  ; Resync on rising edge
 33  pin_low:
 34      jmp pin pin_went_high
 35  pin_went_low:
 36      jmp pin pin_went_high
 37      jmp pin pin_went_high
 38      jmp pin pin_went_high
 39      jmp pin pin_went_high
 40      jmp pin pin_went_high
 41  .wrap
 42  
 43  pin_still_high:
 44      mov x, isr [2] 
 45      jmp x-- eop	     		    ; Jump to eop if jmp_pin and in_pin are high because both inputs are inverted
 46  ; Jump to here on rising edge
 47  pin_went_high:
 48      mov isr, null
 49      in pins, 1                  ; Capture the pin to check eop.
 50      irq DECODER_TRIGGER			; Trigger NRZI decoder
 51      jmp pin pin_still_high
 52      jmp pin_went_low            ; To adjust interval of decoder trigger, jump to pin_went_low (not pin_low)
 53  
 54  .program usb_edge_detector_debug
 55  .side_set 1
 56  eop:
 57      irq wait IRQ_RX_EOP     side db0
 58  start:
 59      jmp pin start           side db1     ; Wait fall edge
 60      irq IRQ_RX_START [1]    side db0
 61  
 62  .wrap_target
 63  pin_still_low:
 64      irq DECODER_TRIGGER [1]	side db0	 ; Trigger NRZI decoder
 65  
 66  ; Resync on rising edge
 67  pin_low:
 68      jmp pin pin_went_high   side db1
 69  pin_went_low:
 70      jmp pin pin_went_high   side db1
 71      jmp pin pin_went_high   side db1
 72      jmp pin pin_went_high   side db1
 73      jmp pin pin_went_high   side db1
 74      jmp pin pin_went_high   side db1
 75  .wrap
 76  
 77  pin_still_high:
 78      mov x, isr [2] 			side db1
 79      jmp x-- eop	     		side db1     ; Jump to eop if jmp_pin and in_pin are high because both inputs are inverted
 80  ; Jump to here on rising edge
 81  pin_went_high:
 82      mov isr, null			side db1
 83      in pins, 1				side db0     ; Capture the pin to check eop.
 84      irq DECODER_TRIGGER		side db0     ; Trigger NRZI decoder
 85      jmp pin pin_still_high  side db0
 86      jmp pin_went_low 		side db1     ; To adjust interval of decoder trigger, jump to pin_went_low (not pin_low)
 87  
 88  ; USB NRZI data decoder
 89  ; 15 instruction
 90  ;            FS(12M)  LS(1.5M)
 91  ; Run at     as fast as possible
 92  ; jmp_pin    d+       d- 
 93  ; both d+/d- pin should be input invert overrideed
 94  ; Fill OSR by 1 and set 0 to x before runnning this program
 95  .program usb_nrzi_decoder
 96  start:
 97      ; set x, 0
 98  .wrap_target
 99  set_y:
100      set y, BIT_REPEAT_COUNT
101  irq_wait:
102      wait 1 irq DECODER_TRIGGER			; wait signal from edge detector
103      jmp !y flip			; ignore stuff bit, without error check
104      jmp PIN pin_high
105  pin_low:
106      jmp !x K1
107  K2:
108      ; x==1
109  J1:
110      ; x==0
111      in null, 1
112  flip:
113      mov x, ~x
114  .wrap
115      
116  pin_high:
117      jmp !x J1
118  J2:
119      ; x==1
120  K1:
121      ; x==0
122      in osr, 1
123      jmp y-- irq_wait ; y is always not 0 at here
124  
125  .program usb_nrzi_decoder_debug
126  .side_set 1 opt
127  start:
128      ; set x, 0        side db0
129  .wrap_target
130  set_y:
131      set y, BIT_REPEAT_COUNT
132  irq_wait:
133      wait 1 irq DECODER_TRIGGER    ; wait signal from edge detector
134      jmp !y flip	; ignore stuff bit, without error check
135      jmp PIN pin_high
136  pin_low:
137      jmp !x K1 side db0
138  K2:
139      ; x==1
140  J1:
141      ; x==0
142      in null, 1
143  flip:
144      mov x, ~x
145  .wrap
146      
147  pin_high:
148      jmp !x J1 side db1
149  K1:
150      ; x==0
151  J2:
152      ; x==1
153      in osr, 1
154      jmp y-- irq_wait ; y is always not 0 at here
155  
156  % c-sdk {
157  #include "hardware/clocks.h"
158  #include "sdk_compat.h"
159  
160  static inline void usb_rx_fs_program_init(PIO pio, uint sm, uint offset, uint pin_dp, uint pin_dm, int pin_debug) {
161    if (pin_dp < pin_dm) {
162      pio_sm_set_consecutive_pindirs(pio, sm, pin_dp, 2, false);
163    } else {
164      pio_sm_set_consecutive_pindirs(pio, sm, pin_dm, 2, false);
165    }
166    gpio_pull_down(pin_dp);
167    gpio_pull_down(pin_dm);
168    gpio_set_inover(pin_dp, GPIO_OVERRIDE_INVERT);
169    gpio_set_inover(pin_dm, GPIO_OVERRIDE_INVERT);
170  
171    pio_sm_config c;
172  
173    if (pin_debug < 0) {
174      c = usb_nrzi_decoder_program_get_default_config(offset);
175    } else {
176      c = usb_nrzi_decoder_debug_program_get_default_config(offset);
177  
178      pio_sm_set_pins_with_mask64(pio, sm, 0, 1ull << pin_debug);
179      pio_sm_set_pindirs_with_mask64(pio, sm, 1ull << pin_debug, 1ull << pin_debug);
180      pio_gpio_init(pio, pin_debug);
181      sm_config_set_sideset_pins(&c, pin_debug);
182    }
183  
184    sm_config_set_in_pins(&c, pin_dp);  // for WAIT, IN
185    sm_config_set_jmp_pin(&c, pin_dp);  // for JMP
186  
187    // Shift to right, autopull enabled, 8bit
188    sm_config_set_in_shift(&c, true, true, 8);
189    sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
190  
191    pio_sm_init(pio, sm, offset, &c);
192    pio_sm_exec(pio, sm, pio_encode_mov_not(pio_osr, pio_null));
193    pio_sm_set_enabled(pio, sm, false);
194  }
195  
196  static inline void eop_detect_fs_program_init(PIO pio, uint sm, uint offset,
197                                             uint pin_dp, uint pin_dm, bool is_fs, int pin_debug) {
198    pio_sm_config c;
199  
200    if (pin_debug < 0) {
201      c = usb_edge_detector_program_get_default_config(offset);
202    } else {
203      c = usb_edge_detector_debug_program_get_default_config(offset);
204      pio_sm_set_pins_with_mask64(pio, sm, 0, 1ull << pin_debug);
205      pio_sm_set_pindirs_with_mask64(pio, sm, 1ull << pin_debug, 1ull << pin_debug);
206      pio_gpio_init(pio, pin_debug);
207      sm_config_set_sideset_pins(&c, pin_debug);
208    }
209  
210    sm_config_set_in_pins(&c, pin_dp);  // for WAIT, IN
211    sm_config_set_jmp_pin(&c, pin_dm);  // for JMP
212  
213    sm_config_set_in_shift(&c, false, false, 8);
214  
215    float div;
216    if (is_fs) {
217      div = (float)clock_get_hz(clk_sys) / (96000000);
218    } else {
219      div = (float)clock_get_hz(clk_sys) / (12000000);
220    }
221  
222    sm_config_set_clkdiv(&c, div);
223  
224    pio_sm_init(pio, sm, offset, &c);
225    pio_sm_set_enabled(pio, sm, true);
226  }
227  
228  %}