It works! Pretty darn well in fact!
Although I did have a couple of minor problems when I had assembled the board.
First, I could not connect to the BLE112 module with the CC Debugger in order to load firmware onto the Bluetooth module. Not so good... I spent quite some time tracing the connections of the programming header and the BLE112 module and comparing with the prototype but everything seemed to match so I feared I had a malfunctioning BLE112 module. Which would bad since those are by far the most expensive part and not easy to unsolder – in fact, it would probably require ordering more parts and building a completely new board. However – a bit more connection tracing, this time at the pins of the 2.54 to 1.27 mm adapter board attached to the CC Debugger, revealed that there was a faulty ground connection. It looks like it's the pin on the programming header itself that has a poor connection. Fortunately I can fix this by making a temporary green-wire fix (by temporary I mean hand-held) while programming the module. Whew!
Then came the next problem. I had actually discovered this when I was assembling the board: I had forgotten the 4k7 Ω pull-up resistors for the I2C interface of the EEPROM! Doh! And it turned out that the ATmega couldn't communicate with the EEPROM. This was easily fixed, however, by simply activating the ATmega's pull-ups for PC4 and PC5.
With the problems fixed, everything worked like a charm. With all IR LEDs in place the range is excellent (tough I have yet to see if I can control the neighbors' TV sets :). And it looks just awesome in its laser-cut acrylic case with countersunk screws and threaded insets (so no screw heads or nuts protrude from the case).
There is still a bit of iOS app programming remaining, like converting the app to a universal app so it'll run on iPad as well as iPhone.
Enjoy the pictures – click for full-size version:
While the PCB is getting made, I've done some work on the enclosure.
It is being made from five layers of 5 mm transparent acrylic from Ponoko.The layers are held together by M3 countersunk machine screws. While the front and middle layers have 3 mm holes for the screws, the rearmost layer has 4 mm holes for fixing the screws by using threaded insets. The rearmost layer also has three holes for mounting the PCB. The PCB will also be mounted with M3 screws into threaded instets and lifted a bit off the back using nylon spacers (which I need since there are a couple of through-hole parts).
The opening in the bottom of the middle layers are for the DC power plug.
(Click for large versions.)
And here's a short animation – click to play video:
I've done some more work on the app. It is now possible to configure the user interface by way of an XML file. At the moment modifying the XML file requires building the app again but this will be changed so the XML file can be downloaded and uploaded from within iTunes.
The XML file specifies a number of "pages" (in the screenshots I have two pages: "TV" and "Channels"). The user swipes sideways to navigate between the pages.
Each page has a layout that specifies how large the buttons are and where they are positioned. Right now the app only supports "medium buttons" (3 x 4 buttons) and "large buttons" (3 x 3 buttons) but more will be added.
Each button position on a page can be left empty or hold a button. A button is configured with an ID (the command ID used – thus the same command can be sent from more than one button), a color (which sets the button's background image), a text and a mode. Mode is either "normal" (command is sent on touch up), "touchdown" (command is sent on touch down) or "repeat" (command is continously being sent as long as the button is pressed).
View a sample configuration file here.
Screenshots – click to see full screenshot:
The PCB for the BLE multi-remote is done and it looks like everything fits. Except for the 10 µF capacitor (left side, middle) where I've used a C instead of B sized footprint. This is why you should always print out a 1-to-1 sized version of the PCB and place the actual components on it (never mind the values, of course, as long as the correct packages are used):
Oh, and if you can't find the TSOP34838 IR receiver anywhere then that's because I forgot to include it in the schematic and board… I just realized that. Doh!
Anyway, it's been added where C7 (bottom-middle) is now and C7 has been moved a bit to the left and up and rotated 90°.
I've run into a few problems with the AVR firmware. (The GitHub repository for which is located here.) Recording of IR signals works fine and the values I record correspond nicely to the theoretical reality ("theoretical reality"?). If you can't remember the protocols and timings, you can find a great explanation of the various protocols here.
But – when I send the signals they are too long (as recorded by my oscilloscope connected to the output pin of the MCU which controls the IR LEDs).
My first approach was:
_delay_us( high_duration );
_delay_us( low_duration );
First I tried simply subtracting a "trim" value from each recorded duration. Which almost worked. But the necessary trim value became so high that, for short durations, the total delay became less than zero microseconds (which, of course, was interpreted as a really high number instead). And even if I clamped the delay values so they couldn't be less than zero, the pulses were still too long.
So instead I now use the 16 bit TIMER1 (TIMER0 is used to generate the 38 kHz output to modulate the IR signal). I configure the timer for CTC mode with the same duration as when sampling IR signals. When learning signals I increase a counter (16 bit resolution) to record the pulse as a number of "sample intervals".
Now when sending, I simply use the raw recorded counter value and decrease a counter on every compare match of the timer. When reaching zero, I toggle the IR signal and reset the counter to the next value in the recorded sequence. When I reach a counter value of zero I stop the timer and the signal is complete.
And a whole 'nother thing is that I've been running the MCU on 3.3 V at 16 MHz. Which according to the datasheet (section 28.3 Speed Grades) is out of spec. Sure, it may well run fine but in this case where timing is crucial I had better throttle it down to 12 MHz which is inside the Safe Operating Area.
And lo and behold – everything works!
The first revision of the PCB layout for the multi-remote project is done. Mind you, I always go through a couple of revisions before getting it manufactured (because I always mess something up in the first few attempts).
I've made a couple of upgrades to the iPhone app: it now has four command buttons as well as "Toggle debug window", "Record IR" and "Scan for devices" buttons. The command buttons and the Record button are only enabled when a device is connected. And the Scan button is only visible (replaces the Record button) when no device is connecte
The app now starts searching automatically when becoming active. If it discovers the last device it was connected to, it connects immediately. Otherwise, it shows a list of devices and lets the user pick a device to connect to. Only devices that advertise the correct service UUID are listed.
The UI also got a little upgrade – it's still just a prototype, mind you...
Also, I've added a MOSFET (IRL1404 – for the PCB version I'll use a IRLML2502) to drive the IR LED with more power. Before, the LED was just driven directly from a MCU pin (which, as everyone knows, is bad form). Now, the MCU pin is connected to the gate of the MOSFET (logic-level) which turns on the LED and current limiting resistor for 100 mA in a common-source configuration.
As expected, the range improved tremendously. And I'm still only using one wide-angle LED.
I have gotten a prototype assembled and working. So far, I've got the following working:
- Connect and disconnect to devices advertising a specific service UUID
- Automatically connect if a known device UUID is found
- Read RESPONSE attribute (although it is not used for anything at the moment)
- Receive notifications when the RESPONSE attribute is updated
- Send commands by updating the COMMAND attribute
- Send commands to the MCU over serial USART when the COMMAND attribute is updated. (Only the command type is sent now – the sequence ID is not yet included.)
- Commands are also sent to the MCU when a client device connects or disconnects (which is ignored at the moment).
- Record an IR signal and store it in the EEPROM.
- Playback the IR signal stored in EEPROM (or a hardcoded test sequence).
- Write the stored IR signal to serial for debugging.
- Respond to commands received on the serial line and trigger recording, playback or one of the debugging commands.
And it works! I can switch my television on and off from my iPhone :)
Next step is to use both high-intensity and wide-angle IR LEDS and to drive them at much higher power (right now the one wide-angle LED is being driven directly by the MCU – which you should never do).
Here is a picture of the prototype in all its glory:
And here is another picture with the individual parts labelled:
Here's some notes on how to store IR codes for the IR controller project:
If I were using pre-programmed codes in a few known formats (like RC-5 or NEC1) I could store the commands using just the two or three bytes that actually make up the sequence. For example, a NEC sequence consists of one address byte and one command byte (although it is sent as a lead-in followed by four bytes).
But mostly I will need to record IR signals and store those. The proper way of doing it would probably be to parse the recorded signal, identify the protocol and store the required few bytes. But that sounds like way too much work. So instead I'll just be storing the time intervals for on-off pairs. I would like to use one byte for each time code and if I use 100 µs resolution I will get from 0.1 ms to 25.5 ms in .1 ms intervals. I think that might be good enough – but time will tell :)
Firstly, an ATmega328P has only 1 KB of EEPROM storage. And most likely, that will not be enough. So I'll be using an external EEPROM chip. The "24C" series seems to be very widely used and uses a simple I2C protocol. So something like Microchip's 25LC512 seems suitable (512 Kbits, 3.3 V and is available in both DIP and SOIC packages) and will give me an extra 64 KB of non-volatile memory. I'm thinking that will be enough.
The IR codes will have differing lengths. And the correct way of storing those in the EEPROM would involve some kind of allocation table and stuff in order not to waste memory space. But instead of messing around with all that I've decided to go for a super-simple solution there every IR code uses a fixed size (like 128 bytes – something that is a whole multiple of the EEPROM chip's page size). That way I can easily access the code for a specific index.
The data will be in raw time-on, time-off format and terminated by a 0 value (since a 0 ms pulse will never occur).
Thus, for my LG television which uses the NEC1 protocol, an "off" command (address 0x04, command 0xC5) can be stored like this:
06, 06, 06, 06, 06, 17, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06,
06, 17, 06, 17, 06, 06, 06, 17, 06, 17, 06, 17, 06, 17, 06, 17,
06, 17, 06, 06, 06, 17, 06, 06, 06, 06, 06, 06, 06, 17, 06, 17,
06, 06, 06, 17, 06, 06, 06, 17, 06, 17, 06, 17, 06, 06, 06, 06, 00
For a total of 67 bytes for a code that basically consists of two bytes! Way inefficient, I know, but it's easy to use.
Using a size of 128 bytes for one IR code will accomodate codes of up to 64 IR pulses and I will be able to fit 512 codes into the EEPROM – and that should be more buttons that I'll ever need. (Maybe I will need to up the size to 256 bytes – we'll see.)
I've made some progress on the BLE112 module. So far, I have:
- Got it wired up in the most basic configurations (VDD, GND, debugging and RESET and TX/RX for UART1, alternative 1 and UART0, alternative 2).
- Got the CC Debugger working.
- Created a project consisting of a hardware setup specification, a simple GATT specification and a BGScript.
- Created an iPhone app that scans for Bluetooth LE devices with the required service UUID, connects to a peripheral and finds the two required attributes (one for sending commands to the BLE112 and one for reading responses).
So far, so good. But I've run into a small problem: I can send serial data from the BLE112 (in response to a startup event or when an attribute changes its value – like when the iOS app writes a value to the command attribute) but I can't seem to receive serial data on the BLE112. Everything should be configured correctly (I think) but the event handler simply doesn't get called in the BGScript.
Maybe the port needs to configured differently. Or maybe I will give up and try using SPI instead and see if that helps.
However, since the BLE112 is used only to receive commands from the iPhone and pass them on to the MCU (like "send IR code such-and-such"), I may not even need to send data from the MCU to the BLE112...
I'll do some more troubleshooting and see if I find a solution.
(It seems I'm not the only one with this problem.)
For the remote control project, I'm still undecided on whether to use Wi-Fi or Bluetooth LE for connectivity.
Bluetooth LE is still a quite new technology and there aren't many manufacturers of Bluetooth LE chips and modules. Read this article for a good guide to the availabe chips and modules (most of which seem to be based on TI's CC2540 chip).
There's no way I'm going to mess around with the chip itself – impedance matching of the antenna trace and shielding and whatnot are better left in more capable hands. So I'll be using a complete module. And Bluegiga's BLE112 seems nice: it's based on the CC2540 and there's plenty of documentation on Bluegiga's Tech Forum (you need to register to access the documentation which if both free and easy – no NDA's or anything).
However… There are not a lot of distributors of the BLE112. Mouser has it. But it "may require a licence to export from the United States". But I went ahead and ordered a couple of BLE112 modules and a CC DEBUGGER (which is necessary for configuring the BLE112 module).
It turns out that Mouser was not able to export the CC Debugger to Denmark and for the BLE112 I had to fill out an "Customer End-User Certificate" so they can decide whether I'm eligible for getting my hands on that kind of technology or not. (Strangely enough, Bluegiga is based in Finland which is practically Denmark's next-door neighbors.)
I did, however, manage to get a CC Debugger from the Danish branch RS Components instead (since they ship from Europe there is no export hassle) and I'm still waiting to hear from Mouser…
For my day job, I develop iPhone apps. Fairly often people are interested in developing an app that interacts with some sort of hardware device. Usually the setup they envision is not feasible, sometimes it's nowhere near possible. But I digress...
To demonstrate one possible iOS-to-hardware setup, I made a small prototype consisting of a GainSpan GS1011MIE Wi-Fi module, an ATmega328 and a LED (if you understand Danish or know how to use Google Translate, you can read about it here.)
Wanting to build something slightly more useful than remote controlled LED, I came up with the idea of a remote controlled IR remote control (yeah I know, "remote controlled remote control"). Specifically, a remote control that can control everything from TV, DVD, Apple TV and set-top box which is controlled from an iOS app.
Initial ideas in no particular order include:
- Powered by external 12 V (or 9 or 5 V) adapter
- Use both wide and narrow angle, high intensity IR LEDs (just like the TV-B-Gone) so exact placement is not terribly important
- RTC so it can be programmed to perform actions (macros) at specific times
- Use an IR receiver to learn remote codes
- GS1011M Wi-Fi module (which will also allow the device to be controlled from a browser or whatever) or
- BLE112 Bluetooth LE module (in which case the device will not be connected to the Internet but it will allow much smoother integration to the iPhone app)
- Enclosure: either 3D printed (Shapeways) or layered laser-cut acryllic (Ponoko)
Further bulletins as events warrant…