@@ -119,20 +119,22 @@ and rebuilding.
119
119
120
120
4.5 [ Exceptions] ( ./TUTORIAL.md#45-exceptions )
121
121
122
- 5 . [ Device driver examples ] ( ./TUTORIAL.md#5-device-driver-examples )
122
+ 5 . [ Interfacing hardware ] ( ./TUTORIAL.md#5-interfacing-hardware )
123
123
124
- 5.1 [ Using the IORead mechnanism ] ( ./TUTORIAL.md#51-using-the-ioread-mechanism )
124
+ 5.1 [ Timing issues ] ( ./TUTORIAL.md#51-timing-issues )
125
125
126
- 5.1.1 [ A UART driver example ] ( ./TUTORIAL.md#511-a-uart-driver-example )
126
+ 5.2 [ Polling hardware with a coroutine ] ( ./TUTORIAL.md#52-polling-hardware-with-a-coroutine )
127
127
128
- 5.2 [ Writing IORead device drivers ] ( ./TUTORIAL.md#52-writing- ioread-device-drivers )
128
+ 5.3 [ Using the IORead mechnanism ] ( ./TUTORIAL.md#53-using-the- ioread-mechanism )
129
129
130
- 5.3 [ Polling hardware without IORead ] ( ./TUTORIAL.md#53-polling-hardware-without-ioread )
130
+ 5.3.1 [ A UART driver example ] ( ./TUTORIAL.md#531-a-uart-driver-example )
131
131
132
- 5.4 [ A complete example: aremote.py] ( ./TUTORIAL.md#54-a-complete-example-aremotepy )
132
+ 5.4 [ Writing IORead device drivers] ( ./TUTORIAL.md#54-writing-ioread-device-drivers )
133
+
134
+ 5.5 [ A complete example: aremote.py] ( ./TUTORIAL.md#55-a-complete-example-aremotepy )
133
135
A driver for an IR remote control receiver.
134
136
135
- 5.5 [ Driver for HTU21D] ( ./TUTORIAL.md#55 -htu21d-environment-sensor ) A
137
+ 5.6 [ Driver for HTU21D] ( ./TUTORIAL.md#56 -htu21d-environment-sensor ) A
136
138
temperature and humidity sensor.
137
139
138
140
6 . [ Hints and tips] ( ./TUTORIAL.md#6-hints-and-tips )
@@ -380,7 +382,7 @@ This is generally highly desirable, but it does introduce uncertainty in the
380
382
timing as the calling routine will only be rescheduled when the one running at
381
383
the appropriate time has yielded. The amount of latency depends on the design
382
384
of the application, but is likely to be on the order of tens or hundreds of ms;
383
- this is discussed further in [ Section 5] ( ./TUTORIAL.md#5-device-driver-examples ) .
385
+ this is discussed further in [ Section 5] ( ./TUTORIAL.md#5-interfacing-hardware ) .
384
386
385
387
Very precise delays may be issued by using the ` utime ` functions ` sleep_ms `
386
388
and ` sleep_us ` . These are best suited for short delays as the scheduler will
@@ -1006,46 +1008,161 @@ a keyboard interrupt should trap the exception at the event loop level.
1006
1008
1007
1009
###### [ Contents] ( ./TUTORIAL.md#contents )
1008
1010
1009
- # 5 Device driver examples
1010
-
1011
- Many devices such as sensors are read-only in nature and need to be polled to
1012
- acquire data. In the case of a driver written in Python this must be done by
1013
- having a coro which does this periodically. This may present problems if there
1014
- is a requirement for rapid polling owing to the round-robin nature of uasyncio
1015
- scheduling: the coro will compete for execution with others. There are two
1016
- solutions to this. The official solution is to delegate polling to the
1017
- scheduler using the IORead mechanism. This is currently subject to limitations.
1018
-
1019
- An alternative is to use the experimental version of uasyncio presented
1020
- [ here] ( ./FASTPOLL.md ) .
1021
-
1022
- Note that where a very repeatable polling interval is required, it should be
1023
- done using a hardware timer with a hard interrupt callback. For "very"
1024
- repeatable read microsecond level (depending on platform).
1025
-
1026
- In many cases less precise timing is acceptable. The definition of "less" is
1027
- application dependent but the latency associated with scheduling the coro which
1028
- is performing the polling may be variable on the order of tens or hundreds of
1029
- milliseconds. Latency is determined as follows. When ` await asyncio.sleep(0) `
1030
- is issued all other pending coros will be scheduled in "fair round-robin"
1031
- fashion before it is re-scheduled. Thus its worst-case latency may be
1011
+ # 5 Interfacing hardware
1012
+
1013
+ At heart all interfaces between ` uasyncio ` and external asynchronous events
1014
+ rely on polling. Hardware requiring a fast response may use an interrupt. But
1015
+ the interface between the interrupt service routine (ISR) and a user coro will
1016
+ be polled. For example the ISR might trigger an ` Event ` or set a global flag,
1017
+ while a coroutine awaiting the outcome polls the object each time it is
1018
+ scheduled.
1019
+
1020
+ Polling may be effected in two ways, explicitly or implicitly. The latter is
1021
+ performed by using the ` IORead ` mechanism which is a system designed for stream
1022
+ devices such as UARTs and sockets. At its simplest explicit polling may consist
1023
+ of code like this:
1024
+
1025
+ ``` python
1026
+ async def poll_my_device ():
1027
+ global my_flag # Set by device ISR
1028
+ while True :
1029
+ if my_flag:
1030
+ my_flag = False
1031
+ # service the device
1032
+ await asyncio.sleep(0 )
1033
+ ```
1034
+
1035
+ In place of a global, an instance variable, an ` Event ` object or an instance of
1036
+ an awaitable class might be used. Explicit polling is discussed
1037
+ further [ below] ( ./TUTORIAL.md#52-polling-hardware-with-a-coroutine ) .
1038
+
1039
+ Implicit polling consists of designing the driver to behave like a stream I/O
1040
+ device such as a socket or UART, using ` IORead ` . This polls devices using
1041
+ Python's ` select.poll ` system: because the polling is done in C it is faster
1042
+ and more efficient than explicit polling. The use of ` IORead ` is discussed
1043
+ [ here] ( ./TUTORIAL.md#53-using-the-ioread-mechanism ) .
1044
+
1045
+ ###### [ Contents] ( ./TUTORIAL.md#contents )
1046
+
1047
+ ## 5.1 Timing issues
1048
+
1049
+ Both explicit and implicit polling are currently based on round-robin
1050
+ scheduling. Assume I/O is operating concurrently with N user coros each of
1051
+ which yields with a zero delay. When I/O has been serviced it will next be
1052
+ polled once all user coros have been scheduled. The implied latency needs to be
1053
+ considered in the design. I/O channels may require buffering, with an ISR
1054
+ servicing the hardware in real time from buffers and coroutines filling or
1055
+ emptying the buffers in slower time.
1056
+
1057
+ The possibility of overrun also needs to be considered: this is the case where
1058
+ something being polled by a coroutine occurs more than once before the coro is
1059
+ actually scheduled.
1060
+
1061
+ Another timing issue is the accuracy of delays. If a coro issues
1062
+
1063
+ ``` python
1064
+ await asyncio.sleep_ms(t)
1065
+ # next line
1066
+ ```
1067
+
1068
+ the scheduler guarantees that execution will pause for at least ` t ` ms. The
1069
+ actual delay may be greater depending on the system state when ` t ` expires.
1070
+ If, at that time, all other coros are waiting on nonzero delays, the next line
1071
+ will immediately be scheduled. But if other coros are pending execution (either
1072
+ because they issued a zero delay or because their time has also elapsed) they
1073
+ may be scheduled first. This introduces a timing uncertainty into the ` sleep() `
1074
+ and ` sleep_ms() ` functions. The worst-case value for this overrun may be
1032
1075
calculated by summing, for every other coro, the worst-case execution time
1033
1076
between yielding to the scheduler.
1034
1077
1035
- If ` await asyncio.sleep_ms(t) ` is issued where t > 0 the coro is guaranteed not
1036
- to be rescheduled until t has elapsed. If, at that time, all other coros are
1037
- waiting on nonzero delays, it will immediately be scheduled. But if other coros
1038
- are pending execution (either because they issued a zero delay or because their
1039
- time has elapsed) they may be scheduled first. This introduces a timing
1040
- uncertainty into the ` sleep() ` and ` sleep_ms() ` functions. The worst-case value
1041
- for this may be calculated as above.
1078
+ There is an experimental version of uasyncio presented [ here] ( ./FASTPOLL.md ) .
1079
+ This provides for callbacks which run on every iteration of the scheduler
1080
+ enabling a coro to wait on an event with much reduced latency. It is hoped
1081
+ that improvements to ` uasyncio ` will remove the need for this in future.
1082
+
1083
+ ###### [ Contents] ( ./TUTORIAL.md#contents )
1042
1084
1043
- [ This document] ( ./FASTPOLL.md ) describes an experimental version of uasyncio
1044
- which offers a means of reducing this latency for critical tasks.
1085
+ ## 5.2 Polling hardware with a coroutine
1086
+
1087
+ This is a simple approach, but is most appropriate to hardware which may be
1088
+ polled at a relatively low rate. This is primarily because polling with a short
1089
+ (or zero) polling interval may cause the coro to consume more processor time
1090
+ than is desirable.
1091
+
1092
+ The example ` apoll.py ` demonstrates this approach by polling the Pyboard
1093
+ accelerometer at 100ms intervals. It performs some simple filtering to ignore
1094
+ noisy samples and prints a message every two seconds if the board is not moved.
1095
+
1096
+ Further examples may be found in ` aswitch.py ` which provides drivers for
1097
+ switch and pushbutton devices.
1098
+
1099
+ An example of a driver for a device capable of reading and writing is shown
1100
+ below. For ease of testing Pyboard UART 4 emulates the notional device. The
1101
+ driver implements a ` RecordOrientedUart ` class, where data is supplied in
1102
+ variable length records consisting of bytes instances. The object appends a
1103
+ delimiter before sending and buffers incoming data until the delimiter is
1104
+ received. This is a demo and is an inefficient way to use a UART compared to
1105
+ IORead.
1106
+
1107
+ For the purpose of demonstrating asynchronous transmission we assume the
1108
+ device being emulated has a means of checking that transmission is complete
1109
+ and that the application requires that we wait on this. Neither assumption is
1110
+ true in this example but the code fakes it with ` await asyncio.sleep(0.1) ` .
1111
+
1112
+ Link pins X1 and X2 to run.
1113
+
1114
+ ``` python
1115
+ import uasyncio as asyncio
1116
+ from pyb import UART
1117
+
1118
+ class RecordOrientedUart ():
1119
+ DELIMITER = b ' \0 '
1120
+ def __init__ (self ):
1121
+ self .uart = UART(4 , 9600 )
1122
+ self .data = b ' '
1123
+
1124
+ def __await__ (self ):
1125
+ data = b ' '
1126
+ while not data.endswith(self .DELIMITER ):
1127
+ yield from asyncio.sleep(0 ) # Neccessary because:
1128
+ while not self .uart.any():
1129
+ yield from asyncio.sleep(0 ) # timing may mean this is never called
1130
+ data = b ' ' .join((data, self .uart.read(self .uart.any())))
1131
+ self .data = data
1132
+
1133
+ __iter__ = __await__ # workround for issue #2678
1134
+
1135
+ async def send_record (self , data ):
1136
+ data = b ' ' .join((data, self .DELIMITER ))
1137
+ self .uart.write(data)
1138
+ await self ._send_complete()
1139
+
1140
+ # In a real device driver we would poll the hardware
1141
+ # for completion in a loop with await asyncio.sleep(0)
1142
+ async def _send_complete (self ):
1143
+ await asyncio.sleep(0.1 )
1144
+
1145
+ def read_record (self ): # Synchronous: await the object before calling
1146
+ return self .data[0 :- 1 ] # Discard delimiter
1147
+
1148
+ async def run ():
1149
+ foo = RecordOrientedUart()
1150
+ rx_data = b ' '
1151
+ await foo.send_record(b ' A line of text.' )
1152
+ for _ in range (20 ):
1153
+ await foo # Other coros are scheduled while we wait
1154
+ rx_data = foo.read_record()
1155
+ print (' Got: {} ' .format(rx_data))
1156
+ await foo.send_record(rx_data)
1157
+ rx_data = b ' '
1158
+
1159
+ loop = asyncio.get_event_loop()
1160
+ loop.run_until_complete(run())
1161
+ ```
1045
1162
1046
1163
###### [ Contents] ( ./TUTORIAL.md#contents )
1047
1164
1048
- ## 5.1 Using the IORead Mechanism
1165
+ ## 5.3 Using the IORead Mechanism
1049
1166
1050
1167
This can be illustrated using a Pyboard UART. The following code sample
1051
1168
demonstrates concurrent I/O on one UART. To run, link Pyboard pins X1 and X2
@@ -1077,8 +1194,8 @@ loop.run_forever()
1077
1194
The supporting code may be found in ` __init__.py ` in the ` uasyncio ` library.
1078
1195
The mechanism works because the device driver (written in C) implements the
1079
1196
following methods: ` ioctl ` , ` read ` , ` readline ` and ` write ` . See
1080
- [ section 5.2 ] ( ./TUTORIAL.md#52 -writing-ioread-device-drivers ) for details on
1081
- how such drivers may be written in Python.
1197
+ [ Writing IORead device drivers ] ( ./TUTORIAL.md#54 -writing-ioread-device-drivers )
1198
+ for details on how such drivers may be written in Python.
1082
1199
1083
1200
A UART can receive data at any time. The IORead mechanism checks for pending
1084
1201
incoming characters whenever the scheduler has control. When a coro is running
@@ -1089,7 +1206,7 @@ avoid buffer overflows and data loss. This can be ameliorated by using a larger
1089
1206
UART read buffer or a lower baudrate. Alternatively hardware flow control will
1090
1207
provide a solution if the data source supports it.
1091
1208
1092
- ### 5.1 .1 A UART driver example
1209
+ ### 5.3 .1 A UART driver example
1093
1210
1094
1211
The program ` auart_hd.py ` illustrates a method of communicating with a half
1095
1212
duplex device such as one responding to the modem 'AT' command set. Half duplex
@@ -1113,7 +1230,7 @@ returned. See the code comments for more details.
1113
1230
1114
1231
###### [ Contents] ( ./TUTORIAL.md#contents )
1115
1232
1116
- ## 5.2 Writing IORead device drivers
1233
+ ## 5.4 Writing IORead device drivers
1117
1234
1118
1235
The ` IORead ` mechanism is provided to support I/O to stream devices. Its
1119
1236
typical use is to support streaming I/O devices such as UARTs and sockets. The
@@ -1123,8 +1240,8 @@ handlers for any devices which are ready. This is more efficient than running
1123
1240
multiple coros each polling a device.
1124
1241
1125
1242
It should be noted that currently the task polling I/O devices effectively runs
1126
- in round-robin fashion along with other coroutines. This is arguably sub
1127
- optimal : [ see this GitHub RFC] ( https://github.com/micropython/micropython/issues/2664 ) .
1243
+ in round-robin fashion along with other coroutines. Arguably this could be
1244
+ improved : [ see this GitHub RFC] ( https://github.com/micropython/micropython/issues/2664 ) .
1128
1245
1129
1246
A device driver capable of employing the IORead mechanism may support
1130
1247
` StreamReader ` , ` StreamWriter ` instances or both. A readable device must
@@ -1178,89 +1295,7 @@ write-only.
1178
1295
1179
1296
###### [ Contents] ( ./TUTORIAL.md#contents )
1180
1297
1181
- ## 5.3 Polling hardware without IORead
1182
-
1183
- This is a simple approach, but is only appropriate to hardware which is to be
1184
- polled at a relatively low rate. This is for two reasons. Firstly the variable
1185
- latency caused by the execution of other coros will result in variable polling
1186
- intervals - this may or may not matter depending on the device and application.
1187
- Secondly, attempting to poll with a short polling interval may cause the coro
1188
- to consume more processor time than is desirable.
1189
-
1190
- The example ` apoll.py ` demonstrates this approach by polling the Pyboard
1191
- accelerometer at 100ms intervals. It performs some simple filtering to ignore
1192
- noisy samples and prints a message every two seconds if the board is not moved.
1193
-
1194
- Further examples may be found in ` aswitch.py ` which provides drivers for
1195
- switch and pushbutton devices.
1196
-
1197
- An example of a driver for a device capable of reading and writing is shown
1198
- below. For ease of testing Pyboard UART 4 emulates the notional device. The
1199
- driver implements a ` RecordOrientedUart ` class, where data is supplied in
1200
- variable length records consisting of bytes instances. The object appends a
1201
- delimiter before sending and buffers incoming data until the delimiter is
1202
- received. This is a demo and is an inefficient way to use a UART compared to
1203
- IORead.
1204
-
1205
- For the purpose of demonstrating asynchronous transmission we assume the
1206
- device being emulated has a means of checking that transmission is complete
1207
- and that the application requires that we wait on this. Neither assumption is
1208
- true in this example but the code fakes it with ` await asyncio.sleep(0.1) ` .
1209
-
1210
- Link pins X1 and X2 to run.
1211
-
1212
- ``` python
1213
- import uasyncio as asyncio
1214
- from pyb import UART
1215
-
1216
- class RecordOrientedUart ():
1217
- DELIMITER = b ' \0 '
1218
- def __init__ (self ):
1219
- self .uart = UART(4 , 9600 )
1220
- self .data = b ' '
1221
-
1222
- def __await__ (self ):
1223
- data = b ' '
1224
- while not data.endswith(self .DELIMITER ):
1225
- yield from asyncio.sleep(0 ) # Neccessary because:
1226
- while not self .uart.any():
1227
- yield from asyncio.sleep(0 ) # timing may mean this is never called
1228
- data = b ' ' .join((data, self .uart.read(self .uart.any())))
1229
- self .data = data
1230
-
1231
- __iter__ = __await__ # workround for issue #2678
1232
-
1233
- async def send_record (self , data ):
1234
- data = b ' ' .join((data, self .DELIMITER ))
1235
- self .uart.write(data)
1236
- await self ._send_complete()
1237
-
1238
- # In a real device driver we would poll the hardware
1239
- # for completion in a loop with await asyncio.sleep(0)
1240
- async def _send_complete (self ):
1241
- await asyncio.sleep(0.1 )
1242
-
1243
- def read_record (self ): # Synchronous: await the object before calling
1244
- return self .data[0 :- 1 ] # Discard delimiter
1245
-
1246
- async def run ():
1247
- foo = RecordOrientedUart()
1248
- rx_data = b ' '
1249
- await foo.send_record(b ' A line of text.' )
1250
- for _ in range (20 ):
1251
- await foo # Other coros are scheduled while we wait
1252
- rx_data = foo.read_record()
1253
- print (' Got: {} ' .format(rx_data))
1254
- await foo.send_record(rx_data)
1255
- rx_data = b ' '
1256
-
1257
- loop = asyncio.get_event_loop()
1258
- loop.run_until_complete(run())
1259
- ```
1260
-
1261
- ###### [ Contents] ( ./TUTORIAL.md#contents )
1262
-
1263
- ## 5.4 A complete example: aremote.py
1298
+ ## 5.5 A complete example: aremote.py
1264
1299
1265
1300
This may be found in the ` nec_ir ` directory. Its use is documented
1266
1301
[ here] ( ./nec_ir/README.md ) . The demo provides a complete device driver example:
@@ -1277,7 +1312,7 @@ any asyncio latency when setting its delay period.
1277
1312
1278
1313
###### [ Contents] ( ./TUTORIAL.md#contents )
1279
1314
1280
- ## 5.5 HTU21D environment sensor
1315
+ ## 5.6 HTU21D environment sensor
1281
1316
1282
1317
This chip provides accurate measurements of temperature and humidity. The
1283
1318
driver is documented [ here] ( ./htu21d/README.md ) . It has a continuously running
0 commit comments