]> vault307.fbx.one Git - micorpython_ir.git/blob - TRANSMITTER.md
micropython_ir projects
[micorpython_ir.git] / TRANSMITTER.md
1 # IR Transmitter
2
3 ##### [Main README](./README.md#1-ir-communication)
4
5 # 1. Hardware Requirements
6
7 The transmitter requires a Pyboard 1.x (not Lite), a Pyboard D or an ESP32.
8 Output is via an IR LED which needs a simple circuit to provide sufficient
9 current. Typically these need 50-100mA of drive to achieve reasonable range and
10 data integrity. A suitable 940nm LED is [this one](https://www.adafruit.com/product/387).
11
12 On the Pyboard the transmitter test script assumes pin X1 for IR output. It can
13 be changed, but it must support Timer 2 channel 1. Pins for pushbutton inputs
14 are arbitrary: X3 and X4 are used. The driver uses timers 2 and 5.
15
16 On ESP32 the demo uses pin 23 for IR output and pins 18 and 19 for pushbuttons.
17 These pins may be changed. The only device resource used is `RMT(0)`.
18
19 On Raspberry Pi Pico the demo uses pin 17 for IR output and pins 18 and 19 for
20 pushbuttons. These pins may be changed. The driver uses the PIO to emulate a
21 device similar to the ESP32 RMT. The device driver is
22 [documented here](./RP2_RMT.md); this is for experimenters and those wanting to
23 use the library in conjunction with their own PIO assembler code.
24
25 ## 1.1 Wiring
26
27 All microcontrollers require an external circuit to drive the LED. The notes
28 below on specific microcontrollers assume that such a circuit is used.
29
30 I use the following circuit which delivers just under 40mA to the diode. R2 may
31 be reduced for higher current.
32 ![Image](images/circuit.png)
33
34 This alternative delivers a constant current of about 53mA if a higher voltage
35 than 5V is available. R4 determines the current value and may be reduced to
36 increase power.
37 ![Image](images/circuit2.png)
38
39 The transistor type is not critical.
40
41 The driver assumes circuits as shown. Here the carrier "off" state is 0V,
42 which is the driver default. If using an alternative circuit where "off" is
43 required to be 3.3V, the class variable `active_high` should be set `False`.
44
45 ## 1.2 ESP32 Wiring
46
47 The ESP32 RMT device now supports the carrier option, and this driver has been
48 updated to use it. The same circuits as above may be used to connect to pin 23
49 (or other pin, if the code has been adapted). The `active_high` option is not
50 available on the ESP32 `RMT` object, so any alternative circuit must illuminate
51 the LED if the pin state is high.
52
53 ## 1.3 RP2 Wiring
54
55 There is no `active_high` option so the circuit must illuminate the LED if the
56 pin state is high, as per the above drivers. Test programs use pin 17, but this
57 can be reassigned.
58
59 # 2. Dependencies and installation
60
61 ## 2.1 Dependencies
62
63 The device driver has no dependencies.
64
65 On ESP32 a firmware version >= V1.17 is required. The Loboris port is not
66 supported owing to the need for the RMT device and other issues.
67
68 The demo program uses `uasyncio` primitives from
69 [this repo](https://github.com/peterhinch/micropython-async). Clone the repo to
70 a directory on your PC:
71 ```bash
72 $ git clone https://github.com/peterhinch/micropython-async
73 ```
74 move to its `v3` directory, and copy the `primitives` directory with its
75 contents to the filesystem.
76
77 ## 2.2 Installation
78
79 The transmitter is a Python package. This minimises RAM usage: applications
80 only import the device driver for the protocol in use. Clone the repository to
81 the current directory of your PC with:
82 ```bash
83 $ git clone https://github.com/peterhinch/micropython_ir
84 ```
85
86 Copy the following to the target filesystem:
87 1. `ir_tx` Directory and contents.
88
89 The demo is of a 2-button remote controller with auto-repeat. It may be run by
90 issuing:
91 ```python
92 from ir_tx.test import test
93 ```
94 Instructions will be displayed at the REPL.
95
96 # 3. The driver
97
98 This is specific to Pyboard D, Pyboard 1.x (not Lite), ESP32 and Raspberry Pi
99 Pico (RP2 architecture chip).
100
101 It implements a class for each supported protocol, namely `NEC`, `SONY_12`,
102 `SONY_15`, `SONY_20`, `RC5` and `RC6_M0`. Each class is subclassed from a
103 common abstract base class in `__init__.py`. The application instantiates the
104 appropriate class and calls the `transmit` method to send data.
105
106 Basic usage on a Pyboard:
107 ```python
108 from machine import Pin
109 from ir_tx.nec import NEC
110 nec = NEC(Pin('X1'))
111 nec.transmit(1, 2) # address == 1, data == 2
112 ```
113 Basic usage on ESP32:
114 ```python
115 from machine import Pin
116 from ir_tx.nec import NEC
117 nec = NEC(Pin(23, Pin.OUT, value = 0))
118 nec.transmit(1, 2) # address == 1, data == 2
119 ```
120 Basic usage on Pico:
121 ```python
122 from machine import Pin
123 from ir_tx.nec import NEC
124 nec = NEC(Pin(17, Pin.OUT, value = 0))
125 nec.transmit(1, 2) # address == 1, data == 2
126 ```
127
128 #### Common to all classes
129
130 Constructor args:
131 1. `pin` A Pin instance instantiated as an output. On a Pyboard this is a
132 `pyb.Pin` instance supporting Timer 2 channel 1: `X1` is employed by the test
133 script. On ESP32 any `machine.Pin` may be used. Must be connected to the IR
134 diode as described below.
135 2. `freq=default` The carrier frequency in Hz. The default for NEC is 38000,
136 Sony is 40000 and Philips is 36000.
137 3. `verbose=False` If `True` emits (a lot of) debug output.
138
139 Method:
140 1. `transmit(addr, data, toggle=0, validate=False)` Args `addr`, `data` and
141 `toggle` are positive integers. The maximum vaues are protocol dependent. If
142 `validate` is `True` passed values are checked and a `ValueError` raised if
143 they are out of range. If `validate` is false invalid bits are silently
144 discarded. For example if an address of 0x11 is passed to `MCE.transmit`, the
145 address sent will be 1 because that protocol supports only a four bit address
146 field. The `toggle` field is unused by some protocols when 0 should be passed.
147
148 Class method:
149 1. `active_low` No args. Pyboard only. A `ValueError` will be thrown on ESP32.
150 The IR LED drive circuit is usually designed to turn the LED on if the driver
151 pin is high. If it has opposite polarity the method must be called before
152 instantiating the class - it will be ineffective if called later.
153
154 Class varaible:
155 1. `timeit=False` If `True` the `.transmit` method times itself and prints the
156 result in μs.
157
158 The `transmit` method is synchronous with rapid return. Actual transmission
159 occurs as a background process, on the Pyboard controlled by timers 2 and 5. On
160 ESP32 the RMT class is used. Execution times were measured on a Pyboard 1.1 and
161 the ESP32 reference board without SPIRAM. Tests were done at stock frequency and
162 with `validate=True`, `verbose=False`. A small saving could be achieved by
163 skipping validation.
164
165 | Protocol | ESP32 | Pyboard |
166 |:--------:|:-----:|:-------:|
167 | NEC | 7.8ms | 3.2ms |
168 | SONY12 | 3.2ms | 1.3ms |
169 | SONY15 | 3.6ms | 1.5ms |
170 | SONY20 | 4.5ms | 1.9ms |
171 | RC5 | 4.9ms | 1.5ms |
172 | RC6_M0 | 6.0ms | 2.0ms |
173 | MCE | 6.7ms | 2.0ms |
174
175 #### NEC class (also Samsung)
176
177 Class `NEC`. Example invocation:
178 ```python
179 from ir_tx.nec import NEC
180 ```
181
182 This has an additional method `.repeat` (no args). This causes a repeat code to
183 be transmitted. Should be called every 108ms if a button is held down.
184
185 The NEC protocol accepts 8 or 16 bit addresses. In the former case, a 16 bit
186 value is transmitted comprising the 8 bit address and its one's complement,
187 enabling the receiver to perform a simple error check. The `NEC` class supports
188 these modes by checking the value of `addr` passed to `.transmit` and sending
189 the complement for values < 256.
190
191 A value passed in `toggle` is ignored.
192
193 For Samsung protocol set the `samsung` class variable `True`:
194 ```python
195 from ir_tx.nec import NEC
196 NEC.samsung=True
197 ```
198 Samsung remotes do not seem to use repeat codes: the sample I have simply
199 repeats the original code.
200
201 Thanks are due to J.E.Tannenbaum for information about the Samsung protocol.
202
203 #### Sony classes
204
205 Classes `SONY_12`, `SONY_15` and `SONY_20`. Example invocation:
206 ```python
207 from ir_tx.sony import SONY_15
208 ```
209
210 The SIRC protocol supports three sizes, supported by the following classes:
211 1. 12 bit (7 data, 5 address) `SONY_12`
212 2. 15 bit (7 data, 8 address) `SONY_15`
213 3. 20 bit (7 data, 5 addresss, 8 extended) `SONY_20`
214
215 The `.transmit` method masks `addr` and `data` values to the widths listed
216 above. `toggle` is ignored except by `SONY_20` which treats it as the extended
217 value.
218
219 #### Philips classes
220
221 Classes `RC5` and `RC6_M0`. Example invocation:
222 ```python
223 from ir_tx.philips import RC5
224 ```
225
226 The RC-5 protocol supports a 5 bit address and 6 or 7 bit (RC5X) data. The
227 driver uses the appropriate mode depending on the `data` value provided.
228
229 The RC-6 protocol accepts 8 bit address and data values.
230
231 Both send a `toggle` bit which remains constant if a button is held down, but
232 changes when the button is released. The application should implement this
233 behaviour, setting the `toggle` arg of `.transmit` to 0 or 1 as required.
234
235 #### Microsoft MCE class
236
237 Class `MCE`. Example invocation:
238 ```python
239 from ir_tx.mce import MCE
240 # MCE.init_cs = 3
241 ```
242 There is a separate demo for the `MCE` class because of the need to send a
243 message on key release. It is run by issuing:
244 ```python
245 from ir_tx.mcetest import test
246 ```
247 Instructions will be displayed at the REPL.
248
249 I have been unable to locate a definitive specification: the protocol was
250 analysed by a mixture of googling and experiment. Behaviour may change if I
251 acquire new information. The protocol is known as OrtekMCE and the remote
252 control is sold on eBay as VRC-1100.
253
254 The remote was designed for Microsoft Media Center and is used to control Kodi
255 on boxes such as the Raspberry Pi. With a suitable PC driver it can emulate a
256 PC keyboard and mouse. The mouse emulation uses a different protocol: the class
257 does not currently support it. Pressing mouse buttons and pad will cause the
258 error function (if provided) to be called.
259
260 This supports a 4 bit address, 6 bit data and 2 bit toggle. The latter should
261 have a value of 0 for the first message, 1 for repeat messages, and 2 for a
262 final message sent on button release.
263
264 The remaining four bits are a checksum which the driver creates. The algorithm
265 requires an initial 'seed' value which my testing proved to be 4. However the
266 only [documentation](http://www.hifi-remote.com/johnsfine/DecodeIR.html#OrtekMCE)
267 I could find stated that the value should be 3. I implemented this as a class
268 variable `MCE.init_cs=4`. This enables it to be changed if some receivers
269 require 3.
270
271 # 4. Principle of operation
272
273 The classes inherit from the abstract base class `IR`. This has an array `.arr`
274 to contain the duration (in μs) of each carrier on or off period. The
275 `transmit` method calls a `tx` method of the subclass which populates this
276 array. This is done by two methods of the base class, `.append` and `.add`. The
277 former takes a list of times (in ) and appends them to the array. A bound
278 variable `.carrier` keeps track of the notional on/off state of the carrier:
279 this is required for bi-phase (manchester) codings.
280
281 The `.add` method takes a single μs time value and adds it to the last value
282 in the array: this pulse lengthening is used in bi-phase encodings.
283
284 On completion of the subclass `.tx`, `.transmit` calls `.trigger` which
285 initiates transmission as a background process. Its behaviour is platform
286 dependent.
287
288 ## 4.1 Pyboard
289
290 Tramsmission is performed by two hardware timers initiated in the constructor.
291 Timer 2, channel 1 is used to configure the output pin as a PWM channel. Its
292 frequency is set in the constructor. The OOK is performed by dynamically
293 changing the duty ratio using the timer channel's `pulse_width_percent` method:
294 this varies the pulse width from 0 to the duty ratio passed to the constructor.
295
296 The duty ratio is changed by the Timer 5 callback `._cb`. This retrieves the
297 next duration from the array. If it is not `STOP` it toggles the duty cycle
298 and re-initialises T5 for the new duration. If it is `STOP` it ensures that the
299 duty ratio is set to the `_SPACE`
300
301 Here `.trigger` appends a special `STOP` value and initiates physical
302 transmission by calling the Timer5 callback.
303
304 ## 4.2 ESP32
305
306 The RMT class now supports `carrier_freq` and `carrier_duty_percent`
307 constructor args, so the base class `IR` (in `__init__.py`) uses these to
308 enable the OOK (on-off keying) waveform.
309
310 The `.trigger` method calls `RMT.write_pulses` and returns with `RMT` operating
311 in the background.
312
313 ## 4.3 Duty ratio
314
315 In every case where I could find a specified figure it was 30%. I measured
316 that from a variety of remotes, and in every case it was close to that figure.
317
318 # 5. Unsupported protocols
319
320 You can use the receiver module to capture an IR burst and replay it with the
321 transmitter. This enables limited support for unknown protocols. This is
322 strictly for experimenters and I haven't documented it in detail.
323
324 There are two limitations. The first is timing accuracy: both receiving and
325 transmitting processes introduce some timing uncertainty. This is only likely
326 to be a practical problem with fast protocols. In brief testing with a known
327 protocol the scripts below worked.
328
329 The more tricky problem is handling repeat keys: different protocols use widely
330 varying approaches. If repeat keys are to be supported some experimentation and
331 coding is likely to be required.
332
333 The following captures a single burst and saves it to a file:
334 ```python
335 from ir_rx.acquire import test
336 import ujson
337
338 lst = test() # May report unsupported or unknown protocol
339 with open('burst.py', 'w') as f:
340 ujson.dump(lst, f)
341 ```
342 This replays it:
343 ```python
344 from ir_tx import Player
345 from sys import platform
346 import ujson
347
348 if platform == 'esp32':
349 from machine import Pin
350 pin = (Pin(23, Pin.OUT, value = 0), Pin(21, Pin.OUT, value = 0))
351 else:
352 from pyb import Pin, LED
353 pin = Pin('X1')
354 with open('burst.py', 'r') as f:
355 lst = ujson.load(f)
356 ir = Player(pin)
357 ir.play(lst)
358 ```
359 The `ir_tx.Player` class is a minimal subclass supporting only the `.play`
360 method. This takes as an arg an iterable comprising time values of successive
361 mark and space periods (in μs).
362
363 The `ir_rx.acquire.test` function makes assumptions about the likely maximum
364 length and maximum duration of a burst. In some cases this may require some
365 modification e.g. to instantiate `IR_GET` with different args.