Programming the controller with sound from your phone – halfway notes

From a desktop computer or laptop, we usually flash microcontrollers via USB, and often with some kind of programmer. What if we want to flash or configure a craft from our phone? Some phones have USB-OTG. Some controllers support BlueTooth. There are systems that support WiFi. Unfortunately, all this is not widespread – you need a suitable phone, a suitable controller, etc.

It became interesting – is it possible to “bleep” data through the phone’s speaker and pick it up with a microphone connected to the microcontroller? In this article I will briefly talk about my pathetic attempts in this direction. So far, “halfway” – because, presumably, a demonstration of the principle itself for Arduino may be more useful for most colleagues than the final, narrowly focused result – a bootloader for a specific processor.

There was a “preceding stage” – transmission through the phone’s audio jack, over a wire – I’ll also briefly tell you about this and show you (you can try it).

Warning!!!

Do not click the buttons on the attached web pages without taking off the headphones!

The idea is not new

Who remembers the ZX-Spectrum and some other computers of that era – they loaded using a tape recorder, albeit through a linear output (and used a filter and comparator at their input).

Telephones with touch-tone dialing – on them you could dial a number by “beeping” it into the handset – for example, a watch with memory for a number of numbers.

And even earlier there was RAM for early computers, which drove a sound wave (usually in a dense medium, not in air) from one end to the other and then fed it back to the beginning with feedback. Dynamic, it turns out, memory. On sound 🙂

Previous attempt

For now, I’ll skip the background why all this was needed – in short, for use in the educational process. But since there has not yet been an ideal solution, the use is also mostly in test mode on volunteers who did not have the opportunity to get away. Ho-ho-ho.

The previous version allows you to program AVR chips in assembler (we used AtMega8) approximately as follows:

  • a custom bootloader is flashed into the controller (here code and firmware)

  • in addition to the chip, you only need a connector (on ADC3 and GND) and an LED to observe the result (and also a button to enter the programming mode at startup)

  • connect an audio cable with a 3.5 jack between the controller and the phone, press the button at startup to switch the controller to boot mode

  • open a web page with a form for entering the program (here she is)

  • write the code (by default there is a certain stub of a couple of commands)

  • Click Compile and Burn (the assembler compiler is built into JS)

If you want to try to flash this bootloader, in my opinion you need to set the frequency of the internal oscillator to 1 MHz using fuses. And launching the bootloader itself (in 1kb of memory, I think). It is limited to the ability to record either 1 or 4 pages.

In general, it worked more or less – but a couple of problems emerged, even three:

  • the invented exchange protocol was not reliable enough – a program with more than 50 commands was loaded with an error every other time

  • and he was pretty slow

  • and most importantly, not every phone has an audio jack these days!

So – one could rack one's brains over the first two points – but on the third, the understanding came that we needed to take the next step – transmit the sound directly through the speaker and pick it up with a microphone.

In words it sounds clear and even banal. In reality, everything turns out to be a little more complicated.

Connection diagram

Initially, I wanted the electronic part to be as simple as possible – connect the microphone directly to the ADC and that’s it. That old version still works (as can be seen from the code) – unfortunately, when transmitting “through the air” and not over a wire, the signal is very weak. In addition, the nonlinearity of such transmission adds problems – you have to try digital filtering, smoothing, etc. The old version used small “bundles” – something like 10 periods of a rather high-pitched frequency – and the distances between them were coded as zeros and ones. The transfer speed was simply divine (you can check it yourself on the above page – add a dozen or two NOPs to the program. Something on the order of 10 commands per second.

I decided to give up and slightly complicate the hardware part for the sake of more reliable and faster transmission.

The microphone connection is standard – through a small resistor to the positive (do not confuse the polarity of the microphone!) – and from the middle of this “stand” the oscillations go through the capacitor to the base of the transistor. The transistor is without a pull-up, so it is usually closed and the voltage at the collector is close to VCC – when some kind of “click” comes to the microphone – the pulse passes through the capacitor and opens it briefly – a short “zero” appears at the PIN output. We connect this output to the selected leg of the microcontroller.

In this form, the circuit is quite sensitive to the ratings of the components (capacitor and resistor in the collector circuit in the first place) – which in turn depend on the transmission coefficient of the transistor. We have to experiment a little how much it can be “coarsened”, taking into account that, for example, multiple triggers can be filtered out in the code (already).

Software part

At the moment, what we have is a “demo” – a web page on which you can enter some text into the input field and press “Beep”. Using simple JS code, all this is converted into a sequence of data for output to sound.

This is the page https://rodiongork.github.io/avr-mic-loader/extra/sound2.html

The coding principle is as follows for now (I won’t go into too much detail because it may change a little):

  • in the data chain 0-0-0-0-…-0-0 1s appear in places – we will call them “peaks”, these are values ​​​​for output to sound, not logical values, but not so important

  • bit 0 is encoded by the gap between two peaks of 13 zeros, and bit 1 is shorter, by 7 zeros

  • sound is reproduced at 16kHz sampling

  • bytes are encoded by analogy with UART – while there is no data, units are transmitted, and the first “failure” to 0 is the “start bit” followed by eight data bits

As for the firmware, this is code for Arduino, so you can easily try to run such an installation yourself (well, several of the components mentioned above will be needed).

The code is simple – it checks the signal on the input pin in a loop, and when it detects a dip in LOW (that is, a “peak” in the audio channel), it records the time until the next peaks. After each next peak, we determine whether the bit 0 or 1 arrived in this way – and if we detect 0, then we begin counting a new byte. When the byte is ready, we simply print it.

This is the firmware https://github.com/RodionGork/avr-mic-loader/blob/master/idea-proof/receiver-air/receiver-air/receiver-air.ino (there’s an extra level of nesting here, but oh well)

The text entered on the web page is “spiked” through the speaker, picked up by the microphone and output to the serial port by the microcontroller, that is, it can be seen in Serial Monitor:

Last lines - test for errors

Last lines – test for errors

You shouldn’t look closely at the code or take it too seriously – this is purely a draft to test the idea, evaluate the delays and try out how to make a bootloader. Still, it includes the DEBUG macro – if you activate it, bits are drawn instead of symbols (as shown in the middle of the picture – from dollars and hyphens).

Result evaluation

In this embodiment, the transmission is successful when the distance between the microphone and the phone speaker is about a centimeter. Although it probably depends on the quality of both. We still have to experiment with different devices. In addition, the primitive electronic amplifier circuit could perhaps be improved a little – I’ll test it some more.

The transmission speed is much higher – it’s easy to estimate that on average 1 bit occupies about 10 “points” of a sound wave, and an 11-bit byte means 110 points. At a frequency of 16 kHz this is more than 140 bytes per second (that is, 70 AVR commands).

The “receiver” code has become much simpler because there is no need to process “clumsy” data from the ADC. This is important for creating a bootloader – the less assembler, the easier life! In addition, it is now suitable for chips without an ADC at all.

The system has (at first glance) become more error-resistant. In principle, the occurrence of errors now simply depends on the distance between the microphone and the speaker.

It is clear that this method is not very suitable for transferring large amounts of data (although we will check how much it can be accelerated). For firmware of a few kilobytes it will do. Or to download the configuration.

One of the advantages is that it can be used with any controller, as long as it can write to its flash memory (younger AVRs and some other chips cannot).

But it’s too early to talk about controllers – I’ll dig a little deeper to make the protocol more reliable and then I’ll create a new version of the bootloader.

If anyone is willing to test it and has ideas for improvement or some important observations, please share! If you want to somehow reuse it in your crafts, you’re welcome – I’ll try to answer your questions!

See you soon 🙂

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *