Nowadays Arduino is the platform of choice for programming AVR microcontrollers and for good reasons. But there are times when you want to have full control over what is added to your code.
For example Arduino is enabling by default Timer0 for use in millis function
and other functions and includes some interrupt routines that perhaps your
project is not using and so adding to the code size or perhaps those
interrupts can interfere with your code.Two main alternatives are WinAVR and Atmel Studio. This tutorial covers WinAVR because it's simpler to use for a beginner.
What you will need:
- ATmega328P (used in this tutorial as an example)
- USBTinyISP programmer
- WinAVR software (more on this later)
What you can learn:
-
how to program an AVR microcontroller using an In-System Programmer such as
USBTinyISP and WinAVR
- some bitwise operations for handling the registers
There are two main ways to program a microcontroller:
Programming software
There are many tools for programming an AVR microcontroller such as Atmel Studio, PlatformIO, Eclipse with an AVR plugin, etc but the simplest and light weight solution that I found is using WinAVR.
Programming hardware
Apart from development software there is also the need of a hardware programmer that the software uses to communicate with the microcontroller and upload the code to it. Searching online for 'avr programmer' reveals lots of options. The most popular I believe is the USBTinyISP and is very cheap. There is also Atmel-ICE from Atmel. A bit more expensive but it has the benefit of being able to debug and see in real time what happens inside the microcontroller.
Getting started with WinAVR
WinAVR is a free suite of executable open source software development tools for the Atmel AVR series for Windows. WinAVR contains all the tools for developing on the AVR such as avr-gcc compiler, avrdude for uploading the code and avr-gdb for debugging.
To download WinAVR visit the project homepage at http://winavr.sourceforge.net and in the download section you will find the link https://sourceforge.net/projects/winavr/files and on that page click on download the latest version. Some users reported that the installation affected their system PATH. All I can say is that I have installed WinAVR on Windows 10 many times and didn't encounter any problem with it.
Updating WinAVR to the latest AVR-GCC and AVRDude
Unfortunately WinAVR hasn't been updated for a few years now and the avr-gcc compiler and avrdude is outdated but there is a way to update them. First download the AVR toolchain from Atmel visiting this link https://www.microchip.com/en-us/development-tools-tools-and-software/gcc-compilers-avr-and-arm.
Scrolling down you should find a link called 'AVR 8-bit Toolchain v3.62 – Windows' which is a zip file. Now in that zip file there should be a folder containing other folders such as 'avr, bin, doc, lib, etc...' Select all these folders and drag them where WinAVR is installed and replace the existing ones. By default WinAVR is installed on C:\WinAVR-20100110.
Now for AVRDude follow this link http://download.savannah.gnu.org/releases/avrdude and download 'avrdude-6.3-mingw32.zip' or newer version then extract the two files from the AVRDude zip file to C:\WinAVR-20100110\bin.
That's it.
Starting first WinAVR project
/*************************************************************
INCLUDES
**************************************************************/
#include <avr io.h>
#include <util delay.h>
#include <avr interrupt.h>
/*************************************************************
DEFINES
**************************************************************/
/*************************************************************
GLOBAL VARIABLES
**************************************************************/
/*************************************************************
FUNCTION PROTOTYPES
**************************************************************/
/*************************************************************
MAIN FUNCTION
**************************************************************/
int main(void){
while(1){
}
}
}
/*************************************************************
FUNCTIONS
**************************************************************/
/*************************************************************
ISR Handlers
**************************************************************/
Make file
Learning AVR programming by blinking a LED using ATmega328P
#define LED_DDR DDRC
#define LED_PORT PORTC
#define LED_PIN PC5
Configuring ATmega328 port pins - this can replace Arduino digitalWrite to increase the speed
Configuring a pin as a digital output
DDRC |= 1 << PC5
LED_DDR |= 1 << LED_PIN
DDRC |= 0b00100000
Pin 0 is 0b00000001Pin 1 is 0b00000010Pin 2 is 0b00000100Pin 3 is 0b00001000Pin 4 is 0b00010000Pin 5 is 0b00100000Pin 6 is 0b01000000Pin 7 is 0b10000000
0b00100000 | 0b00000010 = 0b00100010
0 or 1 = 11 or 1 = 10 or 0 = 0
DDRC |= 1 << PC5
Setting a digital output pin HIGH
PORTC |= 1 << PC5
PORTC = 1 << PC5
Setting a digital output pin LOW
PORTC &= ~(1 << PC5)
Configuring a pin as a digital input
DDRC &= ~(1 << PC5)
DDRC &= 0b11011111 (after not operation)
1 and 1 is 11 and 0 is 00 and 1 is 0
When a pin is set as an input and we write this
PORTC |= 1 << PC5
then the internal pull-up resistor is activated. Now we could add a push button between the pin and ground and when the button is pressed the pin will be pulled to ground and when the button is not pressed the pin will be high due to the pull-up resistor. This is how we can read if a button is pressed.
if(PINC & (1 << PIN5))
PINC represents all the pins of port C and by some bitwise operations we
check only if pin 5 in 1 or 0.
Toggling a pin
DDRC ^= 1 << PC5
DDRC |= 1 << PC5
DDRC &= ~(1 << PC5)
DDRC |= _BV(PC5)DDRC &= ~_BV(PC5)
int main(void){ // Set the pin as output LED_DDR |= 1<<LED_PIN; // Set the pin HIGH LED_PORT |= 1<<LED_PIN; while(1){ // Toggle the pin LED_PORT ^= 1 << LED_PIN; // Wait 500 milliseconds _delay_ms(500); } }
To compile the code click Tools -> Make All.
'fatal error: opening dependency file .dep/main.o.d: no such file or directory'
To fix it visit this forum https://www.avrfreaks.net/forum/windows-81-compilation-error?page=all and you can find a link to a .dll file. Copy this file in the WinAVR installation folder -> utils -> bin and replace the existing file. Now it should compile without errors.
To upload the code to the microcontroller click Tools -> Program. But first lets see how to connect the microcontroller to the programmer.
Connecting USBTinyISP to ATmega328P AVR
USBTinyISP has 2 headers and each one can be used but I prefer the small one. In my case the pin headers are mirrored so you should check with a multimeter first with the power of.
The corresponding pins on the microcontroller can be found in the datasheet.
This protocol of communication is called SPI (Serial Peripheral Interface) .
A 10k resistor is needed from VCC to the reset pin of the microcontroller to keep it high. If the reset pin is pulled to ground then the microcontroller will be kept in reset mode.
On the USBTinyISP there is a yellow jumper. If removed the programmer will not provide 5V power to the microcontroller (MCU) and you need to provide power from other source but be sure to have a common ground. This is useful when you want to power the micro with 3.3V for example.
Installing drivers for USBTinyISP
The drivers for USBTinyISP can be found on Adafruit website here https://learn.adafruit.com/usbtinyisp/drivers. The install includes drivers for some other programmers. Check the box that has USBtinyISP at the end.
Now if everything is connected properly you should be able to program the micro using Tools - > Program.
Having a LED blink using the delay function is useful for checking if the F_CPU is set correctly. If not the LED will blink either to slow or too fast. ATmega328 comes from the factory with their cpu clock divided by 8. In the datasheet you will see the term prescaler. The CPU clock can be divided with a prescaler of 1 (no prescaler), divided by 8, 16... The micro has an internal RC oscillator at 8MHz and has a fuse set to divide this by 8 so the actual speed is 1MHz. You could either change the speed in the makefile to 1000000 or change the fuse and set the CPU divider to 1 and keep the 8MHz specified in the makefile.
There is also the option of connecting a 16MHz crystal oscillator to the
microcontroller and get a more precise clock. For most applications the
internal RC oscillator is just fine but don't build a clock with that.
AVR Fuses
There are 3 bytes stored in a special area of flash memory called fuse bits. These are Low, High and Extended fuse bytes. Setting some of this bits wrong can make the micro unusable and will be needed a special high voltage programmer to make it work again. For this reason there are fuse calculators and as long as you are careful what options you select it will be fine.
Clock Output
Clock Divide
Reset Disable
Brown-out Detect (BOD)
Preserve EEPROM
Burning the fuses
avrdude -c usbtiny -p atmega328p -U lfuse:w:<0xHH>:m
avrdude -c usbtiny -p atmega328p -U hfuse:w:<0xHH>:m
avrdude -c usbtiny -p atmega328p -U efuse:w:<0xHH>:m
Replace 0xHH with the values from the fuse calculator.
No comments:
Post a Comment