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