Ceci est une ancienne révision du document !
In the first article, I introduced Great Cow BASIC and how you can flash an LED just by switching it on and off in a loop and let the microcontroller do nothing more.
This time, I want to show a more elaborate version – how to get the LED to flicker or fade. If I can manage the software pieces together by the end of all these articles, I will present a version of a light reactive night light with power-saving techniques.
But, before this. I want to get a text editor with syntax highlighting for ease of use. Geany is a lightweight text editor with syntax highlighting, and, in my opinion, is very comfortable to use with Great Cow BASIC. Install it with:
sudo apt install geany
Now, open it from your start menu. First, we get Geany to handle Great Cow BASIC code as FreeBASIC code. Most of the Great Cow BASIC syntax then gets highlighted. This works good for me. Edit the filetype_extensions.conf under “tools - configuration files”, lookup the entry for FreeBASIC, and add “;*.gcb” (line 32 in the image above).
Afterwards, open up the menu “build - set build commands”, and change the compile command to
gcbasic /O:”%e”.hex /A:GCASM /V /NP “%f”
which then compiles the input file (%f means file with file extension, e. g. blink.gcb) to the output file blink.hex (%e means filename without file extension). If the verbose output from the compiler bothers you, you can safely omit the “/V” parameter. The “/NP” parameter means that the Great Cow BASIC compiler does not wait for user input and is important for its use with geany, otherwise the compiler gets stuck. To flash the compiled programs to your microcontroller (assuming the ArduinoISP is used) from geany, you could change the build command to flash AVR:
avrdude -p t13 -c avrisp -P /dev/ttyACM0 -b 19200 -U flash:w:”%e”.hex
This way, the compiled program gets right into your microcontroller. Beware: After those steps, the build parameters for FreeBASIC are overwritten, maybe it would be a good idea to save the original parameters somewhere to recover. Just in case you are about to write FreeBASIC source code in Geany as well.
Dimming LED
As a starting point, I introduced source code for a merely flickering LED. If you plan to create a program for a morse flasher or some kind of indicator light, this would be all there is to do. But, to fade a LED there is a bit more work to do. As the microcontroller only delivers digital signals which mean on / off - a different method is necessary to dim a LED. The LED has to be driven with fast and short pulses of current which tricks the human eye so that it recognize the LED brighter or darker (see ref. No. 2 for a detailed explanation). ‘Out of the box’ Great Cow BASIC offers 3 different Pulse Width Modulation (PWM) methods for Atmel AVR:
• a software PWM , • a fixed mode PWM, and • a hardware PWM based on the Atmel AVR Timer0.
We can use either the software PWM or the hardware PWM modes. To set the hardware PWM for yourself, you would have to set the registers of the microcontroller yourself, at this time this is out of scope - maybe at a later point it could be necessary to squeeze out the last byte of the microcontroller's flash memory. If you have instant demand for tweaking please refer to the datasheet.
The software PWM switches the given channel with the required amount of current for the given number of cycles (called the duty cycle). Since the duty cycle is defined as a byte value, the duty cycle would be between 0 and 255, think of it like this: 255 means 100 % current, 127 would be around 50 % current and so on. The number of cycles defines the number of pulses of the software PWM and defines how long the LED is dimmed. Although instantly repeated while in the main loop, the higher the cycles the smoother it will look. With the software PWM you can light up an arbitrary number of LEDs – contrary to the hardware PWM which is limited to the channels it is linked to. But it’s at the cost that all is software calculated, and the microcontroller is busy while the LED is lit. With the following code you can set up a randomly flickering LED with software PWM.
The Setup of the software PWM is easy; you define one or more PINs used as a PWM channel. Then, the LED lights up at random brightness and goes off after the delay. This first result looks like an unsteady flickering candle; with refinements to the code it will look a bit smoother. We will come back to this point later.
The hardware PWM, on the other hand, works similarly but uses hardware circuitry within the microcontroller to generate the required on/off pulses. The frequency and the duty cycle of the fixed mode PWM (ref. No. 6) can be set only once in the program out-of-the-box. This mode could be useful for applications where you want to light a LED at a constant level , or for other purposes which need a constant powerage. This can be changed, but you must change it within the source code.
For dimming the LED, we want to change at least the duty cycle. Instead of calculating the timings in software, there is an oscillator in the Atmel microcontroller which gives the timing for the pulses. The attiny13a has one 8-bit Timer with 2 channels for hardware PWM. One channel ‘ OC0A’ is not available for hardware PWM because it is sacrificed for other usages, eg, the pseudo random number generator. But the channel ‘OC0B’ can be used for hardware PWM and thus for dimming a LED. The hardware PWM that comes predefined with Great Cow BASIC uses the fast PWM mode of the attiny13a (see chap. 11.7.3 in ref. No. 5 for details). In short: it means the timer counts from 0 to 255, falls back to 0, and repeats until the timer is stopped. The frequency of the oscillator is calculated from the internal frequency of the attiny13a. The microcontroller frequency is actually set to 1.2 MHz, which means the hardware PWM can be driven at frequencies of 1.2 MHz, 150 kHz, 18 kHz, 4 kHz and 1 kHz (rounded to full kHz). The speed is dependent of the microcontroller’s frequency. When using the hardware PWM, the microcontroller drives the LED independently which means that other tasks can be processed virtually in parallel. If you want a fixed PWM for the LED, then you can set up the PWM this way (top right).
The fixed mode hardware PWM is easy to set up, but somewhat limited; the only manipulation that can be made during the execution of the program code is by switching the ON-OFF states with the WAIT statement. This first version looks like a candle in heavy wind conditions. Next, we will see that the setup of the fast mode PWM needs some more lines to define the hardware PWM parameter (bottom right).
To set up the Timer, the corresponding PWM channel must be set. With the attiny13a, you have only the Timer0 with channel B (constant AVRCHAN2 in Great Cow BASIC) for the fast mode PWM, and can use only PIN PB1 for the blinking or fading LED. The hardware PWM of this version looks like a candle where the wind has subsided, and, as such, looks much smoother than the fixed mode PWM version.
Comparison
Hint: Install binutils-avr via apt to get the tool avr-size; with it you can get the size of a hexfile in a human readable manner.
Type: avr-size name-of.hex
The software PWM needs some calculations and further program code to work, but the corresponding executable for one channel is rather small: Program Memory: 217/512 words (42.38%), RAM: 11/64 bytes (17.19%). The corresponding .hex file has a size of 440 KByte. The fixed and the fast mode hardware PWMs need a specific PIN of the microcontroller to work, which limits the number of LEDs you can use. But, once started, the PWM can operate independently (the plan is to prove that this is true for the idle mode, we will see this in a later part). The size of the code differs. For the version of the code with fixed mode PWM, it uses Program Memory: 244/512 words (47.66%), RAM: 9/64 bytes (14.06%). Or around 488 KByte. The fast mode PWM uses Program Memory: 478/512 words (93.36%) RAM: 15/64 bytes (23.44%). Or around 936 KByte. Conclusion
All three types of the PWM will work out-of-the-box and are useful on their own.
The software PWM gives the possibility to drive LEDs (or motors, or other analogue driven things) without much hassle, but at the cost that other code has to be optimized to be run somehow (thus the microcontroller has so called interrupts, we will briefly introduce this topic later). Secondly, the microcontroller must be in an active state, and cannot be set to the idle sleep mode while using the PWM.
The hardware PWM of the attiny13a is limited due to the few Timers (exactly one) on board, and the resulting code with random numbers will soon get too big to add more functionality. PWM on the tiny13a can look a little odd because of the low timer resolution of the attiny13a and the gaps from the random values. So there is some space left for optimisation.
Bring it all together
For fun (above), here is one example of a smoother fade effect, if you know ‘Dr Who’, it looks familiar - like the light on top of the TARDIS.