Hi, Habr, long time no see!
First, a few important news about the
Black Swift microcomputer project, and then we move on to the main topic: how to make a microcomputer with OpenWRT a fully-fledged embedded device.
A full-fledged embedded computer, in my opinion, is impossible without two things:
- Support for interrupts on various occasions, including signals on GPIO inputs
- Support for hardware resolutions with good resolution
')
Without this, a significant part of the real automation tasks either does not solve at all, or is solved in such a way that it would not be better solved at all. The only exceptions are the most banal ones - to pull the relay, to flash with a LED, to track a couple of buttons. Anything that requires precise timings and / or a more or less quick response to external events is simply not feasible without carrying out the corresponding functionality to an external controller that can do the above things, which unnecessarily complicates the design of the device.
All the more surprising that with a sufficient number of microcomputers on the SoC Atheros AR9331 and cheaper Ralink RT5350, positioned specifically as embedded solutions, with the support of these two functions in OpenWRT, everything is very sad. Here, of course, the question arises of who needs these microcomputers at this level of support, but we will leave it hanging in the air.

However, if you
look at it over TCP / IP , you can get it for a healthy person.
But first - the news:
- The first batch of Black Swift is in Russia and is already being sent for ruble pre-orders (that is, not made on Kickstarter). If you specified a pre-order delivery - wait, if self-pickup - call the office and drive up.
- If you did not pre-order, but you want to buy Black Swift - call the office and drive up, we have quite a lot of boards above the volume of pre-orders. You can arrange delivery, but then for obvious reasons you will end up in the tail of the pre-order queue.
- FCC certification will end soon, apparently - successfully.
- Satisfaction of backers with Kickstarter, as promised, is expected in June. We cannot send out the Russian-speaking or any other individual backers of the board separately for technical features of Kickstarter.
- The documentation is slowly being updated, due to lack of time, first of all, English-language .
- In particular, the images of virtual machines with the OpenWRT SDK and Eclipse - here (in a couple of days I will update them with the latest version of the SDK with our patches). Useful for anyone who wants to write something under OpenWRT, but does not really understand how.
And now - to the topic.
Theory
In Atheros AR9331 there are two things that are very important for an embedded computer - these are hardware timers (four pieces ticking at the system bus frequency, generating an interrupt upon reaching zero) and interrupts on the GPIO legs (they can trigger on both signal edges).
Unfortunately, at the program level in OpenWRT there is no support for either one or the other - that is, if you want to read some intervals or emulate some protocols, then udelay () is in your hands and hope that in multitasking environment, no one will fit into the middle of your protocol emulation - on the neck. To support GPIO IRQ, there is a widely known
patch in a narrow environment that solves only a part of the problem: you just need to get an interrupt, you have to process it and bring it to the user space where your own program lives. And, of course, in order to impose a patch, you will need to assemble the entire firmware yourself - the exercise is slow and not hemorrhoid.
There is nothing to support timers.
More precisely, until recently, it was not.
A kernel module that catches GPIO interrupts and sends them to the user space - here:
github.com/blackswift/gpio-irq-handlerIt works simply: you need to write the line “+ GPIO PID” to the / sys / kernel / debug / gpio-irq pseudo file, where GPIO is the number of the required foot, PID is your process to which you need to send a signal. Then pick up the signal handler number 42 and wait for it. Remove interrupt - “- GPIO PID” in the same file.
Kernel module that supports hardware timers - here:
github.com/blackswift/timer-irq-handlerIt doesn’t work any harder: first in / sys / kernel / debug / timer-irq we write “+ TIMER TICK”, where TIMER is the timer number (from 0 to 3, no system is busy, so it remains to follow between your applications to did not try to catch together in one timer), TICK - its resolution in microseconds (each tick will generate an interrupt, so do not set less than 20 µs). Then there is “+ TIMER TIMEOUT PID”, where TIMEOUT is the period through which you want to receive the signal, and PID is your process. The signal number is 43. If you want the timer to work only once, add the word “once” at the end. If you do not want - it will work until you say “- TIMER” in the above file.
The core modules will obviously only work on the AR9331, since other chips have a different register addressing. Moreover, for the GPIO IRQ to work, you need a firmware with the above patch, and at the moment “out of the box” you get such firmware only on Black Swift.
Practice
The knowledge gained must be used, that is, to collect something useful with timers and interrupts. I will have a weather station (see KDPV). Why? Firstly, a thing that everyone understands, and secondly, a common DHT22 sensor is also a pain in the ass. It has a similar to 1-Wire protocol, only if there is synchronization in 1-Wire, then the host once pulls the data leg to the “ground”, and then the sensor itself ottabanan output 41 at the output in response. “0” and “1” differ in pulse durations - 28 µs versus 70 µs.
A rather unpleasant thing to decode: you have to calculate the length of the incoming short pulses. Without interruptions is solved, but the stability of the work, frankly, you do not like it. If you want, I will give you a software implementation of the protocol, I have it. Will try.
With interruptions, the matter is simplified radically: without much difficulty, you can write a kernel module that catches an interrupt on the right leg, counts 35 μs from it with the commonplace udelay () and measures the level on the same leg. If there is “1”, then the signal is longer than 35 µs, that is, in fact, “1”. Actually, everything. If you write your kernel module a little harder than us, then here’s the source:
github.com/blackswift/gpio-dht-handlerHaving captured the data from the sensor, the module outputs it either to the kernel output (see the logread command), or by signal 44 to the application at the specified PID. In case of a CRC error, “Error” will arrive in the console, and in the application - 0.

Now it remains to write the application itself around this - we will not go to the kernel log to see whether to put on the cap.
Here everything turns out to be just as trivial: we start a hardware timer that will tick once a minute (the maximum possible tick period is UINT_MAX microseconds, that is, a little more than 71 minutes). A signal comes from it, the handler of which sends a request to the DHT22 protocol module — it simply writes to a pseudo file. After another ten milliseconds, the response signal from the DHT22 arrives, the handler of which, in fact, processes it - in our case it writes to the file.
void irq_handler(int n, siginfo_t *info, void *unused) {

We have just received a meteorological station with a minimum labor cost, in the literal sense of the word, for half an hour on the knee, which keeps a log of temperature and humidity in a text file. With the same ease, the text file can be changed, for example, to the sqlite3 database.
A text file is better than the logread command, but for the time being it’s not quite what you want at home for a more or less healthy person. It would be necessary to display the data beautifully, with graphs. Drawing graphs in C with output to a PNG file is quite a non-trivial task, probably, you not only do not want to solve it with your bare hands, but also look for libraries that can do it. Fortunately, since we run quite a full-fledged Linux on the microcomputer, we don’t need to do anything of this: install the gnuplot package and then simply feed our data to it, accompanying them with a simple script indicating which axis and which scaler to install.
set terminal png medium size 600,300 set format x "" set key below set xrange [60:0] set yrange [0:100] set grid ytics lc rgb "#bbbbbb" lw 1 lt 0 set grid xtics lc rgb "#bbbbbb" lw 1 lt 0 set output "/www/light/img/last_60m.png" plot "-" using 0:1 title "Temperature" with lines, "-" using 0:1 title "Humidity" with lines

Again, how are we going to find out this temperature? Yes, elementary: set up a web server (for example, opkg install lighttpd - put a web server, respectively, lighttpd, notable for the fact that it can also PHP, if necessary) and make an HTML page that sucks our pictures, and at the same time the current data in numbers. If you don’t have to withstand the habroeffect, you can do everything with PHP, if you need to - the current data can be changed in a static HTML file known to any Linux user (and able to terrify the others) by sed, pulling it out of our software as it comes new data.
SR_TIME="class=\"time\">.*</span" RP_TIME="class=\"time\"> $3 </span" SR_TEMP="class=\"temp\">.*</span" RP_TEMP="class=\"temp\"> $1\°C $2% </span" cat /www/light/index.html | sed -es,"$SR_TIME","$RP_TIME", | sed -es,"$SR_TEMP","$RP_TEMP",

What is left? Well, perhaps it is sometimes useful to see with your eyes what is going on there at all. We take a webcam, stick it through the USB-OTG adapter into Black Swift and use the fswebcam utility to display a picture from it once a minute. We go through the browser on the link and look.
Link? Here is the link:
http://files.black-swift.com:9000/The port is forwarded directly to Black Swift, so everything that you see on the link revolves solely on it.
Also, they say, lately it is fashionable to display information about how many degrees you have on your balcony,
to the narodmon.ru service . Honestly, I never used it, but it turned out that it is not very difficult - copy the PHP example from the documentation, write it to the file / root/narodmon.php on Black Swift and then every 15 minutes we pull it from our software / usr / bin / php-cgi /root/narodmon.php, good PHP we also have and ready to use. Well, the parameters do not forget to pass, of course.
Here the reader may wonder - why do you need such a variety of languages ​​and utilities? Isn't it better to write everything
assembler month week on pure C, and then admire the beauty? No, not better. The beauty of full-fledged Linux on an embedded computer - in particular, is that you can get results in a matter of hours, using already known utilities and languages, and not arrange a full-fledged R & D project for a week without sleep and rest.
Basic knowledge of C, familiarity with popular Unix utilities - and that's it. Do you want PHP - here you are. Want to the database - get it, sign it. Do you want on an assembler - also possible, but very expensive.
Why nothing
Theory is when you know everything but nothing works. Practice is everything works but no one. In our laboratory, theory and practice are combined.However, in order not to praise themselves, I will note - so far everything is not working as we would like.
If you walk through our githaba, you can easily find there
an alternative module for working with DHT22 , which is beautifully made inside - it literally measures the duration of incoming pulses. In microseconds. And quite accurately - I did not check it on a calibrated generator, but the one coming with the DHT22 differs from the one specified in it by no more than 3-4 microseconds.
With one exception.
In the depths of OpenWRT, there is a rather evil USB interrupt handler that masks all other interrupts for the duration of its work - and it works for a long time, it can easily go into microseconds for 30-40 seconds. As a result, in our case we can simply skip some GPIO interrupts, at best - with a long delay. Alas, we haven’t completely figured out the wilderness of the assembler and copyrights of 1999, so the module working with two interrupts per pulse has to be put aside - catch the first interrupt and then measure 35 µs from it in such conditions much more reliably.
Here he ate two interruptions and pushed the third:

In addition, when USB is active (for example, it is streamed from a webcam), such delays occur so often that a module that suffices a single interruption is threatened. However, in a little less critical things, where delays of a couple of tens of microseconds are insignificant, you will not notice this - but still unpleasant.
If you have something to say about this, we will listen with interest.
In the following series
Did you know that in OpenWRT there is no working way to completely disable console output in UART?
Yes, this is another fun trap: no matter what parameters and what files you would write, when loading the board into the UART a lot of garbage falls; The parameters available to the user determine only the size of this mountain - and it is always non-zero.
On Black Swift, to completely disable all consoles from the UART, just give the command “fw_setenv silent 1” and reboot. But this is another story.
PS Tomorrow not only DA will come to Skolkovo Startup Village. Medvedev, but also me - in particular,
at this event . If you want to talk about crowdfunding and / or (outside the event) Black Swift - come up.