A pre-built firmware binary demo.hex is provided for easy installation. This is built from the core firmware and a demo program.c LED sequence.
This section covers:
- Installation of the AVRDUDE programming utility
- Downloading the demo.hex demo firmware
- Programming an SMBee using the SMBeeHive programmer
AVRDUDE is a utility for programming AVR microcontrollers using popular programing devices including the USBASP used in the custom SMBeeHive programmer.
Install the current version 6.3 or later, this is available for OSX, Linux and Windows:
Install using Homebrew package manager:
brew upgrade
brew install avrdude
Install using apt
Advanced Package Tool, usually pre-installed on popular linux distributions:
sudo apt update
sudo apt upgrade
sudo apt install avrdude
To avoid having to superceed avrdude
commands with sudo
. You must set up some rules on the USB port regarding the USBASP device.
From your 'SMBeeFirmware' directory:
cd bin/linux-nonroot
. install_rule
There isn't a stand-alone installer for windows with a suitable version of AVRDUDE.
Currently the best option is to install WinAVR. and manually update its version of avrdude:
- Download and install WinAVR. Install in the default location.
- Download and unpack AVRDUDE 6.3 from the AVRDUDE download page.
- Copy the unpacked files (
avrdude.exe
&avrdude.conf
) intoC:\WinAVR-20100110\bin
, overwriting the existing versions. - Install libusbK as a USBASP driver:
- Download and install the Zadig usb driver install tool.
- Plug the USBASP into a USB port and run
Zadig
. - Select the
USBasp
from the combo box andlibusbK
as the driver.
Note: avrdude.exe
depends on external libraries from the WinAVR installation so it can't be installed in isolation.
To verify the installed version enter:
avrdude
This should report version 6.3 or later.
First get a copy of demo.hex, either:
- Download directly from the GitHub web page demo.hex.zip and unzip it.
- Clone the repository locally. See Downloading demo.hex from GitHub below.
Programme demo.hex using AVRDUDE
Connect the SMBee with the SMBeeHive programmer to the AVRDUDE host machine.
The first time the SMBee MCU is programmed you will need to program its RSTIDSBL
fuse, to disable the ATtiny10 reset pin functionality. Fuses are configuration bits separate from the flash memory, retained through a flash memory clear. Once the Fuse is programmed, this step can be omitted when reprogramming the main flash memory to modify the firmware.
avrdude -v -p attiny10 -c usbasp -U fuse:w:0xfe:m
In response to the command programming information and progress information will be outputted to the terminal which should finnish with avrdude: 1 bytes of fuse verified
.
Now programme the main flash memory assuming demo.hex is in the current directory:
avrdude -v -p attiny10 -c usbasp -U flash:w:demo.hex:i
This should complete with a message reporting successful verification of the flashed memory, for example:
"avrdude: 1006 bytes of flash verified".
It is possible to combine these two steps into:
avrdude -v -p attiny10 -c usbasp -U fuse:w:0xfe:m -U flash:w:demo.hex:i
Downloading demo.hex from GitHub
If you are on a platform without a web browser or unzip easiest way is to clone the complete repository into your local file-space:
If you don't have it, install the Git software configuration manager:
Target | install |
---|---|
Linux | sudo apt install git |
OSX | brew install git |
All | download git |
Change your default directory to a suitable location.
Get a local copy of the repository:
git clone https://github.com/milelo/SMBeeFirmware.git
The file location is SMBeeFirmware/bin/demo.hex
.
cd SMBeeFirmware
avrdude -v -p attiny10 -c usbasp -U fuse:w:0xfe:m -U flash:w:bin/demo.hex:i
If the machine you are downloading to has a web browser it is possible to download the file directly from GitHub however it isn't straightforward. Select the Raw display option for the file than use your browsers save-as function to specify the download location and file-name.
To modify flash sequence of the SMBee or other aspects of the firmware you will need to install the avr-gcc toolchain and the VSCode IDE to build and edit the firmware in your local repository clone.
Use the Homebrew package manager to install the avr-gcc toolchain you will need to build the firmware. Install version 8. I had problems compiling for the ATtiny10 on the current version 9.
From homebrew-avr:
xcode-select --install
brew tap osx-cross/avr
brew install avr-gcc@8
This is the current status building the firmware under linux with gcc-avr=1:5.4.0+Atmel3.6.1-2:
- Debian 10 (buster) - builds OK.
- Raspbian GNU/Linux 10 (buster) - build OK.
- Ubuntu 18.04 LTS - build Ok but generates the wrong code. Do not use, program size is reported as 1138 bytes (111.1% Full).
sudo apt update
sudo apt upgrade
sudo apt install make git wget
sudo apt install gcc-avr avr-libc
Check the installed version:
avr-gcc --version
Currently reporting:
avr-gcc (GCC) 5.4.0
.
I haven't found an avr-gcc toolchain installation for windows that supports the ATtiny10 MCU however the Windows 10 feature WSL, Windows Subsystem for Linux allows Linux distributions to be run under Windows which support development for the device. There are some limitations with the current version of WSL and USB support is one of them. The firmware can be built under WSL but the resulting binary must be uploaded to the bee from Windows as described above for the demo firmware, this is fairly straight forward once everything is set up because the Windows file system is shared with WSL. WSL-2, a new version of WSL is being developed by Microsoft to overcome the WSL-1 deficiencies, this will probably be formally release around April 2020.
To setup a WSL development system under Windows 10 using VSCode:
- Run windows update to ensure you have an up to date version of Windows 10.
- Install VSCode for windows: VSCode installers. Don't leave VSCode open.
- Clone the firmware repository in a suitable location in your windows file system.
git clone https://github.com/milelo/SMBeeFirmware.git
cd SMBeeFirmware
- Install WSL as described here. I've tested the build under the following distribtions:
- Debian 10 (buster) - builds OK.
- Ubuntu 18.04 LTS - build Ok but generates the wrong code. Do not use, program size is reported as 1138 bytes (111.1% Full).
- Start WSL:
wsl
The command prompt will change to that of the linux distribution. - Setup the linux distribution:
sudo apt update
sudo apt upgrade
sudo apt install make git wget
sudo apt install gcc-avr avr-libc
- Start VSCode from the same window, you should still be in the Linux 'SMBeeFirmware' directory:
code .
This will install a remote VSCode server and start VSCode running under Windows, the VSCode terminal and build will run in the Linux environment under wsl.
For more information see: Visual Studio Code Remote - WSL. - Open a VScode Terminal and build the firmware:
make compile
With the demo firmware the binaries should build and report:
'Program: 1016 bytes (99.2% Full)'
If the size is > 100% there is a problem with the build. Check the toolchain version and try an earlier version. There is a known problem under Ubuntu, see above. - The firmware can't be flashed to the Bee from wsl. Switch back to the command window you used to install wsl and set up the environment:
exit
You should now be back at a Windows command prompt in the SMBeeFrimware directory. - Assuming you insalled avrdude under Windows as described above. Connect the bee and dock and invoke the programmer:
avrdude -p attiny10 -c usbasp -U fuse:w:0xfe:m -U flash:w:src/main.hex:i
Windows and linux share the same file system so this will flash the file you built under Linux.
Note: on some linux platforms you may need to prefix make
with sudo
to flash the firmware.
Compile and upload the firmware:
make
Other make
arguments:
make demo
(Default): Flash the rstdisbl fuse and the demo firmware.make all
: Compile and upload the firmwaremake clean
: Remove the object (compiler generated) files.make compile
: Compile the firmware.make rstdisbl
: Flash the rstdisbl fuse. This is required the first-time the MCU is programmed.make upload
: Flash the compiled firmwaremake upload-demo
: Flash the precompiled demo firmware.
I used the MS VSCode IDE to develop and build the firmware. You can just use a text editor to modify the files but the IDE provides many useful features:
Download and install VSCode from VSCode installers.
You can install the GitHub Desktop App to clone the firmware repository into a local directory rather than using the command line.
This is the source code for program.c. It can be easily modified to change the LED sequence:
#include "main.h"
void program(void) {
show(EYES); //Eyes on, full brightness
wait(10); // 1s
show1(EYES, FLASH_VSLOW);
wait(30);
show(ANTENNA_RL); //Both antennae on, 100% intensity.
wait(5); // 0.5s
show1(ANTENNA_RL, FLASH_ANTIPHASE | FLASH_SLOW);// Flash antennae in anti-phase to each other.
wait(20);
show(EYES);
wait(10);
show1(EYES, FLASH_VSLOW);
wait(30);
show(ANTENNA_RL);
wait(5);
show1(ANTENNA_RL, FLASH_SLOW);
wait(30);
show1(EYES, FLASH_MED);
wait(10);
show(ANTENNA_RL);
wait(5);
show1(ANTENNA_RL, FLASH_SLOW);
wait(10);
show2(ANTENNA_RL, FLASH_SLOW, FLASH_MED);// Flash ANTENNA_R slow & ANTENNA_L medium.
wait(20);
show2(ANTENNA_RL, FLASH_MED, FLASH_SLOW);
wait(20);
show(ANTENNA_RL);
wait(5);
show1(EYES, FLASH_SLOW);
wait(15);
show1(EYES, FLASH_MED);
wait(15);
show1(EYES, FLASH_FAST);
wait(10);
show2(EYES_STING, FLASH_SLOW, FLASH_FAST);// Eyes slow, sting fast
wait(20);
show1(EYES, FLASH_MED);
wait(5);
show2(EYES_STING, FLASH_SLOW, FLASH_FAST);
wait(20);
show1(EYES, FLASH_SLOW);
wait(30);
}
This is the source code for main.h, it provides the declarations for use in program.c, the LED sequence:
// PORTB values for output activation
#include <avr/io.h>
//LED state (ledState) values
#define LEDS_OFF 0
#define ANTENNA_R 2
#define ANTENNA_L 1
#define ANTENNA_RL 3 //Individually controllable
#define EYES 5 //Not individually controllable
#define STING 6
#define EYES_STING 4 //Individually controllable
//Flash rate values for dynamic brightness (brightness parameters)
#define FLASH_FAST 0b10000001
#define FLASH_MED 0b10000010
#define FLASH_SLOW 0b10000011
#define FLASH_VSLOW 0b10000100
#define FLASH_VVSLOW 0b10000111
#define FLASH_ANTIPHASE 0b01000000 // OR with flash-rate
//wait for time specified in unit: ~s/10 eg 15 = 1.5s
void wait(uint8_t time);
//Show the specified ledState with 100% static brightness
void show(uint8_t ledState);
//Show (with 1 extra parameter) the specified ledState with specified
//static-brightness 0-100% or a flashRate value.
//OR in optional FLASH_ANTIPHASE flags eg "FLASH_VSLOW | FLASH_ANTIPHASE"
void show1(uint8_t ledState, uint8_t brightness);
//Show (with 2 extra parameters). Provides individal LED control for duel-LED states.
//Show the specified ledState with specified individual static-brightness 0-100% or flashRate value.
//OR in optional FLASH_ANTIPHASE flags eg "FLASH_VSLOW | FLASH_ANTIPHASE"
void show2(uint8_t ledState, uint8_t brightness1, uint8_t brightness2);
The main implementation can be found in main.c.
These are the main information sources to support the firmware:
-
The momentary action button SW1 toggles the MCU into and out of a low power sleep mode, this has negligible battery drain.
-
main.c
provides the main functionality and provides an API in in main.h to control the LED's. -
A separate file,
program.c
programs the steps that define the LED illumination sequence. -
For each programme step, the step-duration, fixed LED-brightness or Flash rate (modulated brightness) can be programmed.
-
At each step the LED's to be illuminated are selected, either a single LED or a pair of LED's according to table 1. Both eyes behave as a single LED. Only the table 1 combinations are currently supported.
-
Normally the
program.c
sequence is only executed once then sleep mode is entered again. -
If SW1 is given an extended press from sleep mode until the sting-led illuminates, the LED sequence is continuously looped until SW1 is pressed to enter sleep mode again.
-
The code size of
main.c
must be minimized for size to leave flash memory space forprogram.c
. -
The LED's are driven by two pulse-width-modulators used to vary their brightness.
-
The frequency of the pulse width modulators is fixed and chosen to be high enough so the LED's don't appear to flicker as they are modulated on and off to control their brightness.
-
The Brightness of the LED's is determined by the selected pulse-width on-off ratio of the connected PWM which in turn is controlled by the values of OCR0AL and OCR0BL.
-
To minimize the MCU power, the MCU clock frequency is chosen to be as low as possible but high enough to support the required PWM frequency. This ensures maximum LED brightness.
-
To give a pulsating effect rather simple on-off flashing, a waveform,
WAVEFORM[]
is used to modulate the the pulse-widths of the PWM's and therefor modulate the LED brightness. -
TC0 is utilized as an 8 bit continuously running timer counter (except in sleep). From its minimum count 0 to maximum count 0xFF is the PWM period after which the counter overflows to 0. The on time is from minimum count 0 to when the count matches the value in the register OCR0AL or OCR0BL for PWMA and PWMB respectively. The LED brightness is therefor controlled by setting the values of registers OCR0AL and OCR0BL.
-
The TC0 overflow interrupt TOV0 is enabled to generate an interrupt on every TC0 period, 4.096ms. The integer
ct0_ticks
is defined to serve as the application timer, in the Interrupt Service RoutineISR(TIM0_OVF_vect)
, this is incremented every time the ISR is called.ct0_ticks
is a 16bit unsigned integer so it will overflow approximately every 4.5 minutes defining the longest timer period.ct0_ticks
is always counting except in sleep mode. -
void wait(uint8_t time)
is the API call to pad the sequence step period and therefore define the LED illumination time. It takes the current value ofct0_ticks
counter-timer, adds the wait time to it and sets the value to the integerwaitTimerEnd
, it then polls for theWAIT_TIMEOUT
bit ofstatus
to be set.waitTimerEnd
is checked for equality withct0_ticks
on every interrupt incrementingct0_ticks
. When the integers match theWAIT_TIMEOUT
bit ofstatus
is set. This timing method is designed to be unaffected byct0_ticks
overflows. -
ct0_ticks
is also used to index the arrayWAVEFORM[]
of LED brightness values, at the selected flash rate.ct0_ticks
increments at a fixed rate however by selecting which 4 bits fromct0_ticks
are used to index the waveform, the rate of change of the index values can be selected. The lower bits will be fast, moving up a bit, the rate will halve. Bits in the variableledModulator
are used to define the flash rate for both PWMs. -
An anti-phase flag
FLASH_ANTIPHASE
is available in the API to specify that one LED should flash in anti-phase to another. This is achieved by adding an offset to one ofWAVEFORM[]
index values therefore shifting its phase by 180°. -
Each PWM can be configured to be active high to source current or active low to sink current depending on the LED it is required to drive.
-
SW1 has no hardware debounce circuitry so it must be debounced in software. The characteristics of the switch are that it may fast cycle on and off after it is pressed or released for its settling time before stabilizing. The debounce functionality is to delay for the maximum settling time
SW_SETTLE_MS
after a level or edge change from SW1 is detected before trying to read its final state. As well as toggling sleep state, the switch press duration is measured at startup to potentially enable the continuous programme loop state. -
In sleep state the processor clock is stopped however peripheral circuitry including output drivers can selectively remain active. To minimize power in sleep, the code deactivates everything when entering sleep except the switch pull-up and PB3 change detect monitoring circuit required to trigger a wake-up interrupt on a SW1 state change. Wake-up interrupt handler
ISR(PCINT0_vect)
isn't implemented, this invokes the required default programme restart behavior. -
The PWM's are programmed to operate in the Fast PWM Mode see data-sheet 12.9.3. This is the simplest mode of operation that fits our purpose.
ATTiny | PB2 | PB1 PWM-B |
PB0 PWM-A |
PB (hex) |
---|---|---|---|---|
antenna R | 0 | 1 | 0 | 2 |
antenna L | 0 | 0 | 1 | 1 |
antenna R&L | 0 | 1 | 1 | 3 |
eyes | 1 | 0 | 1 | 5 |
sting | 1 | 1 | 0 | 6 |
eyes & sting | 1 | 0 | 0 | 4 |
Table 1, PB: Port B
<iframe width="400" height="225" src="https://www.youtube.com/embed/2UukflvSl64" frameborder="0" allowfullscreen></iframe>