3 ##### [Main README](./README.md#1-ir-communication)
5 # 1. Hardware Requirements
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).
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.
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)`.
21 I use the following circuit which delivers just under 40mA to the diode. R2 may
22 be reduced for higher current.
23 
25 This alternative delivers a constant current of about 53mA if a higher voltage
26 than 5V is available. R4 determines the current value and may be reduced to
28 
30 The transistor type is not critical.
32 The driver assumes circuits as shown. Here the carrier "off" state is 0V,
33 which is the driver default. If using an alternative circuit where "off" is
34 required to be 3.3V, the class variable `active_high` should be set `False`.
38 The ESP32 RMT device now supports the carrier option, and this driver has been
39 updated to use it. The same circuits as above may be used to connect to pin 23
40 (or other pin, if the code has been adapted). The `active_high` option is not
41 available on the ESP32 `RMT` object, so any alternative circuit must illuminate
42 the LED if the pin state is high.
44 # 2. Dependencies and installation
48 The device driver has no dependencies.
50 On ESP32 a firmware version >= V1.14 is required. The Loboris port is not
51 supported owing to the need for the RMT device and other issues.
53 The demo program uses `uasyncio` primitives from
54 [this repo](https://github.com/peterhinch/micropython-async). Clone the repo to
55 a directory on your PC:
57 $ git clone https://github.com/peterhinch/micropython-async
59 move to its `v3` directory, and copy the `primitives` directory with its
60 contents to the filesystem.
64 The transmitter is a Python package. This minimises RAM usage: applications
65 only import the device driver for the protocol in use. Clone the repository to
66 the current directory of your PC with:
68 $ git clone https://github.com/peterhinch/micropython_ir
71 Copy the following to the target filesystem:
72 1. `ir_tx` Directory and contents.
74 The demo is of a 2-button remote controller with auto-repeat. It may be run by
77 from ir_tx.test import test
79 Instructions will be displayed at the REPL.
83 This is specific to Pyboard D, Pyboard 1.x (not Lite) and ESP32.
85 It implements a class for each supported protocol, namely `NEC`, `SONY_12`,
86 `SONY_15`, `SONY_20`, `RC5` and `RC6_M0`. Each class is subclassed from a
87 common abstract base class in `__init__.py`. The application instantiates the
88 appropriate class and calls the `transmit` method to send data.
90 Basic usage on a Pyboard:
92 from machine import Pin
93 from ir_tx.nec import NEC
95 nec.transmit(1, 2) # address == 1, data == 2
99 from machine import Pin
100 from ir_tx.nec import NEC
101 nec = NEC(Pin(23, Pin.OUT, value = 0))
102 nec.transmit(1, 2) # address == 1, data == 2
105 #### Common to all classes
108 1. `pin` A Pin instance instantiated as an output. On a Pyboard this is a
109 `pyb.Pin` instance supporting Timer 2 channel 1: `X1` is employed by the test
110 script. On ESP32 any `machine.Pin` may be used. Must be connected to the IR
111 diode as described below.
112 2. `freq=default` The carrier frequency in Hz. The default for NEC is 38000,
113 Sony is 40000 and Philips is 36000.
114 3. `verbose=False` If `True` emits (a lot of) debug output.
117 1. `transmit(addr, data, toggle=0, validate=False)` Args `addr`, `data` and
118 `toggle` are positive integers. The maximum vaues are protocol dependent. If
119 `validate` is `True` passed values are checked and a `ValueError` raised if
120 they are out of range. If `validate` is false invalid bits are silently
121 discarded. For example if an address of 0x11 is passed to `MCE.transmit`, the
122 address sent will be 1 because that protocol supports only a four bit address
123 field. The `toggle` field is unused by some protocols when 0 should be passed.
126 1. `active_low` No args. Pyboard only. A `ValueError` will be thrown on ESP32.
127 The IR LED drive circuit is usually designed to turn the LED on if the driver
128 pin is high. If it has opposite polarity the method must be called before
129 instantiating the class - it will be ineffective if called later.
132 1. `timeit=False` If `True` the `.transmit` method times itself and prints the
135 The `transmit` method is synchronous with rapid return. Actual transmission
136 occurs as a background process, on the Pyboard controlled by timers 2 and 5. On
137 ESP32 the RMT class is used. Execution times were measured on a Pyboard 1.1 and
138 the ESP32 reference board without SPIRAM. Tests were done at stock frequency and
139 with `validate=True`, `verbose=False`. A small saving could be achieved by
142 | Protocol | ESP32 | Pyboard |
143 |:--------:|:-----:|:-------:|
144 | NEC | 7.8ms | 3.2ms |
145 | SONY12 | 3.2ms | 1.3ms |
146 | SONY15 | 3.6ms | 1.5ms |
147 | SONY20 | 4.5ms | 1.9ms |
148 | RC5 | 4.9ms | 1.5ms |
149 | RC6_M0 | 6.0ms | 2.0ms |
150 | MCE | 6.7ms | 2.0ms |
154 Class `NEC`. Example invocation:
156 from ir_tx.nec import NEC
159 This has an additional method `.repeat` (no args). This causes a repeat code to
160 be transmitted. Should be called every 108ms if a button is held down.
162 The NEC protocol accepts 8 or 16 bit addresses. In the former case, a 16 bit
163 value is transmitted comprising the 8 bit address and its one's complement,
164 enabling the receiver to perform a simple error check. The `NEC` class supports
165 these modes by checking the value of `addr` passed to `.transmit` and sending
166 the complement for values < 256.
168 A value passed in `toggle` is ignored.
172 Classes `SONY_12`, `SONY_15` and `SONY_20`. Example invocation:
174 from ir_tx.sony import SONY_15
177 The SIRC protocol supports three sizes, supported by the following classes:
178 1. 12 bit (7 data, 5 address) `SONY_12`
179 2. 15 bit (7 data, 8 address) `SONY_15`
180 3. 20 bit (7 data, 5 addresss, 8 extended) `SONY_20`
182 The `.transmit` method masks `addr` and `data` values to the widths listed
183 above. `toggle` is ignored except by `SONY_20` which treats it as the extended
188 Classes `RC5` and `RC6_M0`. Example invocation:
190 from ir_tx.philips import RC5
193 The RC-5 protocol supports a 5 bit address and 6 or 7 bit (RC5X) data. The
194 driver uses the appropriate mode depending on the `data` value provided.
196 The RC-6 protocol accepts 8 bit address and data values.
198 Both send a `toggle` bit which remains constant if a button is held down, but
199 changes when the button is released. The application should implement this
200 behaviour, setting the `toggle` arg of `.transmit` to 0 or 1 as required.
202 #### Microsoft MCE class
204 Class `MCE`. Example invocation:
206 from ir_tx.mce import MCE
209 There is a separate demo for the `MCE` class because of the need to send a
210 message on key release. It is run by issuing:
212 from ir_tx.mcetest import test
214 Instructions will be displayed at the REPL.
216 I have been unable to locate a definitive specification: the protocol was
217 analysed by a mixture of googling and experiment. Behaviour may change if I
218 acquire new information. The protocol is known as OrtekMCE and the remote
219 control is sold on eBay as VRC-1100.
221 The remote was designed for Microsoft Media Center and is used to control Kodi
222 on boxes such as the Raspberry Pi. With a suitable PC driver it can emulate a
223 PC keyboard and mouse. The mouse emulation uses a different protocol: the class
224 does not currently support it. Pressing mouse buttons and pad will cause the
225 error function (if provided) to be called.
227 This supports a 4 bit address, 6 bit data and 2 bit toggle. The latter should
228 have a value of 0 for the first message, 1 for repeat messages, and 2 for a
229 final message sent on button release.
231 The remaining four bits are a checksum which the driver creates. The algorithm
232 requires an initial 'seed' value which my testing proved to be 4. However the
233 only [documentation](http://www.hifi-remote.com/johnsfine/DecodeIR.html#OrtekMCE)
234 I could find stated that the value should be 3. I implemented this as a class
235 variable `MCE.init_cs=4`. This enables it to be changed if some receivers
238 # 4. Principle of operation
240 The classes inherit from the abstract base class `IR`. This has an array `.arr`
241 to contain the duration (in μs) of each carrier on or off period. The
242 `transmit` method calls a `tx` method of the subclass which populates this
243 array. This is done by two methods of the base class, `.append` and `.add`. The
244 former takes a list of times (in ) and appends them to the array. A bound
245 variable `.carrier` keeps track of the notional on/off state of the carrier:
246 this is required for bi-phase (manchester) codings.
248 The `.add` method takes a single μs time value and adds it to the last value
249 in the array: this pulse lengthening is used in bi-phase encodings.
251 On completion of the subclass `.tx`, `.transmit` calls `.trigger` which
252 initiates transmission as a background process. Its behaviour is platform
257 Tramsmission is performed by two hardware timers initiated in the constructor.
258 Timer 2, channel 1 is used to configure the output pin as a PWM channel. Its
259 frequency is set in the constructor. The OOK is performed by dynamically
260 changing the duty ratio using the timer channel's `pulse_width_percent` method:
261 this varies the pulse width from 0 to the duty ratio passed to the constructor.
263 The duty ratio is changed by the Timer 5 callback `._cb`. This retrieves the
264 next duration from the array. If it is not `STOP` it toggles the duty cycle
265 and re-initialises T5 for the new duration. If it is `STOP` it ensures that the
266 duty ratio is set to the `_SPACE`
268 Here `.trigger` appends a special `STOP` value and initiates physical
269 transmission by calling the Timer5 callback.
273 The RMT class now supports `carrier_freq` and `carrier_duty_percent`
274 constructor args, so the base class `IR` (in `__init__.py`) uses these to
275 enable the OOK (on-off keying) waveform.
277 The `.trigger` method calls `RMT.write_pulses` and returns with `RMT` operating
282 In every case where I could find a specified figure it was 30%. I measured
283 that from a variety of remotes, and in every case it was close to that figure.
285 # 5. Unsupported protocols
287 You can use the receiver module to capture an IR burst and replay it with the
288 transmitter. This enables limited support for unknown protocols. This is
289 strictly for experimenters and I haven't documented it in detail.
291 There are two limitations. The first is timing accuracy: both receiving and
292 transmitting processes introduce some timing uncertainty. This is only likely
293 to be a practical problem with fast protocols. In brief testing with a known
294 protocol the scripts below worked.
296 The more tricky problem is handling repeat keys: different protocols use widely
297 varying approaches. If repeat keys are to be supported some experimentation and
298 coding is likely to be required.
300 The following captures a single burst and saves it to a file:
302 from ir_rx.acquire import test
305 lst = test() # May report unsupported or unknown protocol
306 with open('burst.py', 'w') as f:
311 from ir_tx import Player
312 from sys import platform
315 if platform == 'esp32':
316 from machine import Pin
317 pin = (Pin(23, Pin.OUT, value = 0), Pin(21, Pin.OUT, value = 0))
319 from pyb import Pin, LED
321 with open('burst.py', 'r') as f:
326 The `ir_tx.Player` class is a minimal subclass supporting only the `.play`
327 method. This takes as an arg an iterable comprising time values of successive
328 mark and space periods (in μs).
330 The `ir_rx.acquire.test` function makes assumptions about the likely maximum
331 length and maximum duration of a burst. In some cases this may require some
332 modification e.g. to instantiate `IR_GET` with different args.