Openbench Logic Sniffer comes of age
A while back I bought a Openbench Logic Sniffer from Dangerous Prototypes. Whilst it kind-of worked it was most definitely alpha and really not much practical use - no big deal considering the low price. However everything is field-upgradable so I put it to one side and more or less forgot about it. Over the last few days I've revisited the project and upgraded everything, and it's turning into a fantastic little tool. The first thing of note is that the FPGA core has been completely rewritten by doggsbody, who almost unbelievably has managed to get most of the functionality of a HP16550A logic analyser into the FPGA, although the user interface hasn't yet been extended to allow access to all the new goodness.
The original flakiness between the FPGA and the PIC processor used to glue everything together seems to have been solved as well. The real icing on the cake is there's also a new client to drive it all - the old SUMP client was really getting a bit long in the tooth, and there's a new and much superior version that Jawi has produced. Unfortunately although the client is written in Java, it didn't work Solaris as it didn't include the Solaris version of the RXTX JNI library. Jawi very kindly helped me get it all working, and even better he's integrated Solaris support into the next release as well, so it will just work out of the box. There's still more work to be done, for example, from what I can gather the 200MHz sampling mode still doesn't work properly, but having said that the progress since I last took a serious look a the project is very impressive.
The last thing of note is there's now a buffer wing available that allows you to use all of the available 32 channels with 5V inputs - I'm very tempted to get one :-)
Don't delay()
It's very common for Arduino sketches to use the delay() library routine to control timing when performing time-related operations such as LED animations. Unfortunately delay() is toxic if you need to do more than one thing at once - for example animating more than one LED strip - as calling delay() just makes the CPU spin until the required amount of time has passed, and obviously nothing else can happen until the delay() call returns. The same is true for anything that uses any kind of spin-loop to wait for an event, for example polling a switch or a rotary encoder until it changes state (commonly used as a way of debouncing). The Arduino ecosphere is full of such example code and to be blunt all of it is completely useless - unless of course all you want do is dedicate your whole microcontroller to dealing with a single IO device.
It is possible to partially work around this issue by using timer interrupts to trigger actions, because the interrupt service routine will be called even if delay() is currently executing. However interrupts have their issues as well. The issues around interrupt service routine overhead and reentrancy are fairly widely understood. The issues around atomicity are less well understood, even in commercial products. Simply declaring a variable as volatile isn't sufficient - except for very simple cases you need to be sure that interrupts are disabled during all access to variables that are shared between ISR and non-ISR code. And if you are accessing several variables, or a structure, you need to make sure interrupts are disabled around the entire block.
- A RTOS may help manage shared software resources by providing features such as thread-safe queues and lists, but it can't really solve the problems related to shared hardware resources. For example, when several tasks need to access the SPI bus they each need to complete their work before relinquishing the bus. If a task is communicating with a peripheral on the bus, scheduling another task in the middle of the operation is not possible so RTOS preemption support is irrelevant - preemption needs to be disabled anyway until the current task has completed its bus transaction.
- Supporting preemption means that tasks can potentially be suspended and resumed at any point. This means that the complete state of a task needs to be saved somewhere, including all the processor registers and the current stack for the thread. This overhead is significant - the ATMega168 only has 1Kb of SRAM, and the ATMega328P has 2K. Reports say that as few as 3-4 FreeRTOS tasks can be run on Arduino-class microcontrollers.
- avr-libc, the core of the runtime system, isn't thread-safe, so if you use a RTOS you need either to lock around every call into avr-libc or you'll need a complete replacement for avr-libc. The situation with commonly-used Arduino libraries is just as bad - they weren't written with threads in mind, and will almost certainly break in strange and mysterious ways if used with a RTOS.
All in all, a RTOS isn't a good solution for severely constrained platforms such as the ATMega, yet we really need something to help us manage concurrency. That was the impetus behind the creation of my task library. It has the following features:
- Non-preemptive, cooperative scheduler.
- Fixed, priority scheduling governed by task list ordering.
- Task list fixed at compile time.
- Small code size - 28 bytes for the Task class and 116 bytes for the scheduler.
- Low RAM requirements - 4 bytes + 2 bytes per task.
- No thread stacks required - each task runs to completion, so the stack is fully unwound before task switching.
Whilst the task manager is undoubtedly much more limited than a RTOS, the limitations are ones that can usually be lived with. In compensation it becomes possible to schedule many tens of tasks even on a severely constrained platform such as the ATMega. As long as we can break the workload into small enough chunks, we can just schedule the tasks in a cooperative fashion. By providing priority scheduling we can ensure that even when temporarily overloaded the system will still remain responsive by scheduling the most important tasks first, and deferring the lower-priority tasks until the load drops again. In any case, preemption is no help if the system can't actually keep up with the rate of events it is being expected to handle.
So, in summary don't use delay() when there are better alternatives available! :-)
It's that helicopter time of year again
The Moors For The Future project has been working since 2003 to repair the damage caused to the moorland of the Dark Peak, which I live on the edge of. Part of this work involves spreading heather brash over the areas of eroded peat, so as to provide a micro-climate that will enable the surface of the peat to revegetate. Because of the nature of the terrain, it's impossible to access it by conventional means so everything has to be airlifted in by helicopter. There's a short period when this work can be done, between the end of the shooting season and the start of the nesting season, so it's a pretty hectic time. This year the project is doing its biggest-ever airlift which will be using three helicopters to transfer 24,000 dumpy bags of heather brash onto the moors, which will be spread across 1,600,000 square metres of eroded peat. The Peak District Rangers provide ground support for the helicopters, so I'm going to be out at least a day a week for the next month or so helping out. There's a video below that I took a couple of years ago showing what's involved - the helicopter carries six bags at a time and drops them off in pairs at the places we indicate. It's a bit scary the first couple of times, but the skill of the pilots is really amazing, and so far nobody has been buried under a bag :-) The project been front-page news in the local press - yeah, it's quiet around here - see these articles in The Glossop Chronicle and The Glossop Advertiser
Updated Makefile.master
If you have been using my Makefile for Arduino sketches I've been updating it regularly with bug fixes and improvements. The latest version includes:
- Arduino
bindirectory, avrdude config file and avrdude path made configurable. - Single-file sketches weren't building properly.
- Listing file now generated for the final binary image.
You can find the current version of the Makefile.master here.
Optiboot on Arduino Pro Mini
A bit too much opti, not enough boot
The newer Arduino boards such as the Uno include a new bootloader that takes up about 1/4 of the size of the old one. That means some extra memory can be freed up for applications. The new bootloader is known as Optiboot, and the site says "Compatible with 168 and 328 Arduinos including Lilypad, Pro, Nano". Unfortunately, in the case of the Pro Mini, that's not true, but it can be made to work.
- At the time of writing, the current v3 release tarball doesn't include some important bugfixes such as this one. My advice is to pull the latest version from the repository and build it yourself.
-
With the standard makefile flags Optiboot may not build, depending on which version of the compiler you are using. The fix is to add
-nostdlibtoLDFLAGSas detailed in this bug. -
Optiboot uses different upload baud speeds from the old bootloader, apparently to shave a few seconds off uploads. Unfortunately that has caused sketch upload issues such as this, and in the specific case of the Pro Mini, this. The common factor is that the Optiboot baud rate is too high to be reliable. I suspect that several of the other "Sketch won't upload" reports are caused by the same thing. Also, changing the baud rate means that it's not only necessary to fiddle with the boards.txt file to make the Arduino environment use the new baud rates, it's also necessary that you know exactly what bootloader is on a board. My recommendation is to edit the Makefile and change the
-DBAUD_RATE=XXXXXvalues to those in the original boards.txt file.
Update
I've tried five different Pro Minis, setting the baud rate to 57600 instead of 115200 and whilst four of them upload fine with Optiboot, one of them doesn't. I can get it to work by manually resetting the board, and it works fine with the standard Arduino bootloader. Clearly there's some sort of timing issue related to resets, I'll have to tinker some more.