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 %}