I'm working on an electronic sign project that uses bluetooth (and possibly ethernet/wlan later on) to communicate either with a .NET or Android application (used for transmitting messages to the sign, as well as controlling speed and color of the display). Everything is nearly complete, proof of concept works, all that's left is to build the final control boards for the sign. As I intend to try and productize and sell the kit, one of the features I wanted was the ability for users to be able to update the firmware in the field, if new features, bug fixes were made to the code (so I wouldn't have to re-program every board my self).
While I'm using an Arduino Uno for developing the code, my control board is a custom solution using an ATMega 328p chip. I'm fairly inexperienced with micros still, as well as boot-loaders, but it is my understanding that to be able to update code on the chips (such as in the arduino boards), you must have a bootloader installed on the chip to be able to self-program, without using an ISP.
Can anyone point out some beginner-friendly sites/docs/how-to's on how boot-loaders work, and how I would go about using one to achieve what I'm trying to do? I will still need to figure out how to get the .NET or android apps to be able to push firmware to the board, but first step is to figure out how to get the board to accept updates and program itself. Auto-reset is of course needed.
One last thing. I intent to use Arduino 0023 to update the code and generate the .hex files to distribute for any update, but it will fall on the apps to be able to push out the updates (I won't ask users to install the arduino IDE).
The current Arduino bootloader fits into around 500KB of code-area. It appears that Bluetooth is the only connectivity of your custom-board to external world. If so, and given your question it appears that you are looking at modifying the bootloader to use the Bluetooth Serial-Port-Profile to stream new (updated) hex file, to perform the 'field upgrade'. I am far from being an expert on this, but having read some articles/posts earlier (should be easy to google), here is what happens in a bootloader.
It is always the program that runs "first" after a power-cycle / reset
It has logic that "watches" for something that indicates "new code" needing to be loaded to program the uC/uP.
e.g. It could 'watch' a block-storage device (SD card), or serial link or ethernet etc., for some special indication (a distinct pattern) which tells it that the subsequent data is 'new code' to run on this uC/uP.
In your case, it'd have to be the serial emulated channel over Bluetooth, but for that, Bluetooth stack should have been initialized and communication ready to be served. If you are adopting the "shield" approach, or using a Bluetooth module, there is still some non-trivial amount of code (& initialization data) to prep the module, and initiate the communication, and probably very unlikely to be anywhere close to 500KB. While I am not sure, but I think there is a limit on the size of bootloader.
If indeed there was some "new code", then bootloader replaces the new code in flash, and invokes the entry-point into this new code, else it goes ahead and invoked the entry-point of the existing code in flash storage.
IMHO, the logic at high-level is very simple, though the devil is in the details.
Anyhow that is the part about the code on your device. Then there is the part which is the application on your Android device. I suspect that you need a port of something similar to avrdude on that device, to use serial-over-bluetooth. Of course, you can take a complete DIY approach, taking care of the serial communication with your digital-signage device. The bootloading process (AFAIK) uses avrdude to stream the new hex file to the 'being programmed' device.
The Arduino bootloader is here on my PC --
c:\arduino-0022\hardware\arduino\bootloaders\atmega\ATmegaBOOT_168.c
Have no idea if something like that already does exist. And all that I wrote above is a beginner / newbie's initial impression of a short while exposure to Arduino and uC programming.
Like I said, I am no expert. So after posting my previous reply, I did some reading around and I realized that I might have oversimplified. Here are some good resources -
I suppose there's the option of having a second uC on-board whose sole task is to poll an SD card. If it finds new code, connect to the main uC via ISP/ICSP and flash the code. Should work ... I think.
lemming:
Providing an ISP could be pricey and user unfriendly.
Pricy? Yes, it adds $20 or so of cost.
User unfriendly? How so?
Hook up ISP to sign.
Hook up ISP to computer.
Run sign programmer application on computer.
No less user friendly than anything else AFAICT. Yes, you probably need to install some drivers, but that's going to happen for anything you do, as computers don't come with serial ports anymore.
a second uC on-board whose sole task is to poll an SD card.
That's actually a pretty good way to do it I think, total cost maybe $5 and easy for people to understand, just put an SD in and power up.
Would that need a complete cold start, or couldn't it be done simply by sticking the SD card in and hitting reset on the uC attached to the reader. Once it comes up and sees code, it can do what it needs to do.
This does bring up another question though: is there a way to reset whatever status of a running uC prior to reflashing? For example, if I have a string of LEDs running and I decide to upload new code, for the time it takes the code to upload, the LEDs will be left in whatever state (on or off) they were when the uC went into reset and while it's accepting the new code. This doesn't only apply to LEDs of course, just any code that's running on the uC when it got reset and put into receiving mode. Is there a way to reset it, pull everything low for example before new code gets uploaded?
I'm sure there are reasons not to (such as not pulling SPI low since that's being used for SPI upload, or TX/RX is using FTDI ...)
For example, if I have a string of LEDs running and I decide to upload new code, for the time it takes the code to upload, the LEDs will be left in whatever state (on or off) they were when the uC
RESET turns all the pins into INPUTs with the pull-ups disabled. Same state they are in after a power-up.
Right you are. Which just answered my own question on what I am seeing with my strips: they're driven through SPI, and when the uC gets RESET, while it changes the uC's pins, it doesn't control the LED IC itself, so that is left in whatever last state it was in. So that would mean, having to somehow send a signal down whatever bus is being used for the attached devices to also shut down, turn off, reset, do whatever needs to be done.
I suppose one way is to have a control logic or mechanical switch on the VCC that's supplying the device(s), that's also tied to the Arduino. As long as the Arduino's pin is HIGH, everything works as expected. When the Arduino's pin goes LOW, it cuts VCC to the attached devices. In the case of LEDs, this would effectively turn everything off while the uC gets new data reflashed to it. Once that's done and the uC comes back online, it re-enabled VCC to the devices and start running the new code.
Would that need a complete cold start, or couldn't it be done simply by sticking the SD card in and hitting reset on the uC attached to the reader.
Yep, that would work to. The end result would be pretty much the same and it would save cycling the power. You could also poll the SD so that no action is needed by the user.
for the time it takes the code to upload, the LEDs will be left in whatever state (on or off) they were when the uC went into reset
I would use a GPIO line to interrupt the LED processor to tell it the lights are about to go out. It then sets the LEDs to whatever state you want and acknowledges the programming processor.
Controlling the VCC would work as well but it will need extra hardware like a relay.
for the time it takes the code to upload, the LEDs will be left in whatever state (on or off) they were when the uC went into reset
I would use a GPIO line to interrupt the LED processor to tell it the lights are about to go out. It then sets the LEDs to whatever state you want and acknowledges the programming processor.
Controlling the VCC would work as well but it will need extra hardware like a relay.
That would assume they actually have some way of receiving an interrupt. The WS280x family that I use are simply VCC, GND, and the 2-wire (SDA/SCK) control lines. If VCC is cycled, at least the drivers will come back up in a known OFF state till they start receiving data over the signal lines.
Unfortunately, this doesn't always work. I have some sample LEDs that I'm working with and those things always come up HIGH when you first turn them on. As soon as I apply VCC, the thing comes up blindingly bright (within its tolerances) and a microsecond later shuts off as data starts flowing. Rather annoying. The vendor hasn't been very helpful in helping either ... datasheet says zip.
Now that I think about it, I like the way the BlinkM modules work. When you set a new sequence in their Sequencer and hit upload, the BlinkM will fade out, new sequence uploaded and then the code is run. I wonder how they accomplish that ...
That would assume they actually have some way of receiving an interrupt.
Not the WS280x, you interrupt the LED controlling processor, presumably this is an ATmega328 which has external interrupts.
Ah, if there's something involved that has a GPIO available to then interrupt the uC, which would then terminate whatever it's doing, including (but not limited to) sending a signal down an RGB strip telling it to shut off. Got it. For the purpose of this thread, and my suggestion of a second uC reading an SD card and reflashing the main uC, that would work.
However, this wouldn't work if you're uploading directly from USB, or FTDI ... at least, I can't see a way that it would. Neither of those methods have a free GPIO do use to interrupt the main uC ...
I suppose there's the option of having a second uC on-board whose sole task is to poll an SD card.
If that is used for the user upload no other programming method is needed.
Right, I figured that's what you were referring to. For the sake of the exercise, if one was uploading through direct USB, or FTDI ... can something like that be accomplished? I have a feeling that's what the BlinkM Sequencer is doing, before upload, it instructs the thing (or multiple of them if they're strung together) to fade out, then start uploading code.
The only way I can see that working is by rerouting the DTR reset pulse to an INT then using the ISR to fade out/turn off and then jump to the bootloader.
What I don't know is how long avrdude will wait before giving up and spitting a out of sync error.
If you wanted to write code or a batch script for the PC you could open and close the serial line, wait for a second then start avrdude. This would not need any hardware mods if the Arduino code is written to automatically fade out on reset.