@@ -33,7 +33,7 @@ class UART:
33
33
Parity = busio .UART .Parity
34
34
35
35
def __init__ (
36
- self , tx = None , rx = None , baudrate = 9600 , bits = 8 , parity = None , stop = 1 , timeout = 1
36
+ self , tx = None , rx = None , baudrate = 9600 , bits = 8 , parity = None , stop = 1 , timeout = 1 , cts = None , rts = None
37
37
): # pylint: disable=invalid-name, too-many-arguments
38
38
self .bitcount = bits + (1 if parity else 0 )
39
39
self .bits = bits
@@ -43,72 +43,159 @@ def __init__(
43
43
self ._timeout = timeout
44
44
self .rx_pio = None
45
45
if rx :
46
- # Minimum viable 8n1 UART receiver. Wait for the start bit, then sample 8 bits
47
- # with the correct timing.
48
- # IN pin 0 is mapped to the GPIO used as UART RX.
49
- # Autopush must be enabled, with a threshold of 8.
50
-
51
- # Line by line explanation:
52
- # * Wait for start bit
53
- # * Preload bit counter, delay until eye of first data bit
54
- # * Loop 8 times
55
- # * Sample data
56
- # * Each iteration is 8 cycles
57
- rx_code = adafruit_pioasm .assemble (
58
- ".program uart_rx_mini\n "
59
- + "start:\n "
60
- + " wait 0 pin 0\n "
61
- + f" set x, { self .bitcount - 1 } [10]\n "
62
- + "bitloop:\n "
63
- + " in pins, 1\n "
64
- + " jmp x-- bitloop [6]\n "
65
- + " jmp pin good_stop\n "
66
- + " wait 1 pin 0\n " # Skip IRQ
67
- + " jmp start\n "
68
- + "good_stop:\n "
69
- + " push\n "
70
- )
71
- self .rx_pio = rp2pio .StateMachine (
72
- rx_code ,
73
- first_in_pin = rx ,
74
- jmp_pin = rx ,
75
- frequency = 8 * baudrate ,
76
- auto_push = False ,
77
- push_threshold = self .bitcount ,
78
- )
46
+ if rts :
47
+ # Fleshed-out 8n1 UART receiver with hardware flow control handling
48
+ # framing errors and break conditions more gracefully.
49
+ # Wait for the start bit whilst updating rts with the FIFO level
50
+ # then sample 8 bits with the correct timing.
51
+ # IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
52
+ # OUT pin 0 is mapped to the GPIO used as UART RTS# (Request To Send).
53
+
54
+ # Line by line explanation:
55
+ # * Update rts pin with status of fifo level (high when full).
56
+ # * Loop back to start whilst waiting for the start bit (low).
57
+ # * Preload bit counter, then delay until eye of first data bit.
58
+ # * Shift data bit into ISR
59
+ # * Loop bitcount times, each loop iteration is 8 cycles.
60
+ # * Jump to good_stop if there's a stop bit (high)
61
+ # * otherwise wait for line to return to idle state.
62
+ # * Don't push data if we didn't see good framing and start again.
63
+ # * Push valid data and return to the start.
64
+ rx_code = adafruit_pioasm .assemble (
65
+ ".program uart_rx_mini\n "
66
+ + "start:\n "
67
+ + " mov pins !status\n "
68
+ + " jmp pin start\n "
69
+ + f" set x, { self .bitcount - 1 } [10]\n "
70
+ + "bitloop:\n "
71
+ + " in pins, 1\n "
72
+ + " jmp x-- bitloop [6]\n "
73
+ + " jmp pin good_stop\n "
74
+ + " wait 1 pin 0\n " # Skip IRQ
75
+ + " jmp start\n "
76
+ + "good_stop:\n "
77
+ + " push\n "
78
+ )
79
+
80
+ # mov_status_n is set to 7 allowing 2 further
81
+ # entries (8 in the joined FIFO and one in ISR).
82
+ self .rx_pio = rp2pio .StateMachine (
83
+ rx_code ,
84
+ first_in_pin = rx ,
85
+ jmp_pin = rx ,
86
+ frequency = 8 * baudrate ,
87
+ auto_push = False ,
88
+ push_threshold = self .bitcount ,
89
+ first_out_pin = rts ,
90
+ mov_status_type = 'rxfifo' ,
91
+ mov_status_n = 7 ,
92
+ )
93
+ else :
94
+ # Fleshed-out 8n1 UART receiver which handles
95
+ # framing errors and break conditions more gracefully.
96
+ # IN pin 0 is mapped to the GPIO used as UART RX.
97
+
98
+ # Line by line explanation:
99
+ # * Wait for start bit
100
+ # * Preload bit counter, then delay until eye of first data bit.
101
+ # * Shift data bit into ISR
102
+ # * Loop bitcount times, each loop iteration is 8 cycles.
103
+ # * Jump to good_stop if there's a stop bit (high)
104
+ # * otherwise wait for line to return to idle state.
105
+ # * Don't push data if we didn't see good framing and start again.
106
+ # * Push valid data and return to the start.
107
+ rx_code = adafruit_pioasm .assemble (
108
+ ".program uart_rx_mini\n "
109
+ + "start:\n "
110
+ + " wait 0 pin 0\n "
111
+ + f" set x, { self .bitcount - 1 } [10]\n "
112
+ + "bitloop:\n "
113
+ + " in pins, 1\n "
114
+ + " jmp x-- bitloop [6]\n "
115
+ + " jmp pin good_stop\n "
116
+ + " wait 1 pin 0\n " # Skip IRQ
117
+ + " jmp start\n "
118
+ + "good_stop:\n "
119
+ + " push\n "
120
+ )
121
+ self .rx_pio = rp2pio .StateMachine (
122
+ rx_code ,
123
+ first_in_pin = rx ,
124
+ jmp_pin = rx ,
125
+ frequency = 8 * baudrate ,
126
+ auto_push = False ,
127
+ push_threshold = self .bitcount ,
128
+ )
79
129
80
130
self .tx_pio = None
81
131
if tx :
82
132
stop_delay = stop * 8 - 1
83
- # An 8n1 UART transmit program.
84
- # OUT pin 0 and side-set pin 0 are both mapped to UART TX pin.
85
-
86
- # Line by line explanation:
87
- # * Assert stop bit, or stall with line in idle state
88
- # * Preload bit counter, assert start bit for 8 clocks
89
- # * This loop will run 8 times (8n1 UART)
90
- # * Shift 1 bit from OSR to the first OUT pin
91
- # * Each loop iteration is 8 cycles.
92
- tx_code = adafruit_pioasm .Program (
93
- ".program uart_tx\n "
94
- + ".side_set 1 opt\n "
95
- + f" pull side 1 [{ stop_delay } ]\n "
96
- + f" set x, { self .bitcount - 1 } side 0 [7]\n "
97
- + "bitloop:\n "
98
- + " out pins, 1\n "
99
- + " jmp x-- bitloop [6]\n "
100
- )
101
- self .tx_pio = rp2pio .StateMachine (
102
- tx_code .assembled ,
103
- first_out_pin = tx ,
104
- first_sideset_pin = tx ,
105
- frequency = 8 * baudrate ,
106
- initial_sideset_pin_state = 1 ,
107
- initial_sideset_pin_direction = 1 ,
108
- initial_out_pin_state = 1 ,
109
- initial_out_pin_direction = 1 ,
110
- ** tx_code .pio_kwargs ,
111
- )
133
+ if cts :
134
+ # An 8n1 UART transmit program with hardware flow control
135
+ # OUT pin 0 and side-set pin 0 are both mapped to UART TX pin.
136
+ # IN pin 0 is mapped to GPIO pin used as CTS# (Clear To Send),
137
+
138
+ # Line by line explanation:
139
+ # * Assert stop bit, or stall with line in idle state
140
+ # * Wait for CTS# before transmitting
141
+ # * Preload bit counter, assert start bit for 8 clocks
142
+ # * This loop will run 8 times (8n1 UART)
143
+ # * Shift 1 bit from OSR to the first OUT pin
144
+ # * Each loop iteration is 8 cycles.
145
+ tx_code = adafruit_pioasm .Program (
146
+ ".program uart_tx\n "
147
+ + ".side_set 1 opt\n "
148
+ + f" pull side 1 [{ stop_delay } ]\n "
149
+ + "wait 0 pin 0\n "
150
+ + f" set x, { self .bitcount - 1 } side 0 [7]\n "
151
+ + "bitloop:\n "
152
+ + " out pins, 1\n "
153
+ + " jmp x-- bitloop [6]\n "
154
+ )
155
+ self .tx_pio = rp2pio .StateMachine (
156
+ tx_code .assembled ,
157
+ first_out_pin = tx ,
158
+ first_sideset_pin = tx ,
159
+ frequency = 8 * baudrate ,
160
+ initial_sideset_pin_state = 1 ,
161
+ initial_sideset_pin_direction = 1 ,
162
+ initial_out_pin_state = 1 ,
163
+ initial_out_pin_direction = 1 ,
164
+ first_in_pin = cts ,
165
+ pull_in_pin_up = True ,
166
+ wait_for_txstall = False ,
167
+ ** tx_code .pio_kwargs ,
168
+ )
169
+ else :
170
+ # An 8n1 UART transmit program.
171
+ # OUT pin 0 and side-set pin 0 are both mapped to UART TX pin.
172
+
173
+ # Line by line explanation:
174
+ # * Assert stop bit, or stall with line in idle state
175
+ # * Preload bit counter, assert start bit for 8 clocks
176
+ # * This loop will run 8 times (8n1 UART)
177
+ # * Shift 1 bit from OSR to the first OUT pin
178
+ # * Each loop iteration is 8 cycles.
179
+ tx_code = adafruit_pioasm .Program (
180
+ ".program uart_tx\n "
181
+ + ".side_set 1 opt\n "
182
+ + f" pull side 1 [{ stop_delay } ]\n "
183
+ + f" set x, { self .bitcount - 1 } side 0 [7]\n "
184
+ + "bitloop:\n "
185
+ + " out pins, 1\n "
186
+ + " jmp x-- bitloop [6]\n "
187
+ )
188
+ self .tx_pio = rp2pio .StateMachine (
189
+ tx_code .assembled ,
190
+ first_out_pin = tx ,
191
+ first_sideset_pin = tx ,
192
+ frequency = 8 * baudrate ,
193
+ initial_sideset_pin_state = 1 ,
194
+ initial_sideset_pin_direction = 1 ,
195
+ initial_out_pin_state = 1 ,
196
+ initial_out_pin_direction = 1 ,
197
+ ** tx_code .pio_kwargs ,
198
+ )
112
199
113
200
def deinit (self ):
114
201
"""De-initialize the UART object."""
0 commit comments