AVR MICROPROCESSOR PROGRAMMING This book is about programming the avr microcontroller probably with an arduino type board. Its purpose is to investigate the avr architecture from an assembly programming perpective. Generally my interest is focussed on coding rather than hardware, or circuit design or robotics or what-not. So I am largely content to experiment over a serial connection. GOALS .... To learn how to call code using indirect addressing (ie using the x, y, z registers) so we can do something like >> call bx ; x86 architecture To develop a simple repl loop, "read, evaluate, print, loop" So a simple read-only forth style interface over a serial connection- what used to be known as a Forth "Home Brew" play chess on an atmega328 microcontroller over a serial connection. TOOLS .... == tools .. avra - an assembler to use with arduino .. avrdude - a tool to program the arduino board .. Many arduino boards use the atmega328 avr chip which has 32K of program memory * turn on the led on arduino pin 13 ---- ;hello.asm ; turns on an LED which is connected to PB5 (digital out 13) .include "/usr/share/avra/m328Pdef.inc" ;or .include "/usr/share/avra/m328def.inc" ldi r16,0b00100000 out DDRB,r16 ; DDRB == data direction register B out PortB,r16 ; send a 'high' to PB5 only Start: rjmp Start ; hang in an infinite loop ,,, * upload this hex file to the arduino with >> avrdude -p m328p -c stk500v1 -b 57600 -P /dev/ttyUSB0 -U flash:w:hello.hex This is not working. The problem is the 'stk500' which may be correct for the 'uno' arduino but not for the duemilenovo. see below for a working example. The problem seems to be the -c stk500v1 option * also try for arduino uno s etc >> -b 115200 and the port -P /dev/ttyACM0 ARCHITECTURE .... The atmel atmega chips are 8 bit risc processors. They have a stack and a register file. Data memory and program memory are separate (program memory is stored in flash). AVR ASSEMBLY * a good avr assembly site >> https://sites.google.com/site/avrasmintro/ ADC http://maxembedded.com/2011/06/the-adc-of-the-avr/ A reasonable explanation of the functioning of the adc for avr chips. Adc is yet another acronym meaning analogue to digital conversion and is included in almost all microcontrollers. Most sensors work by varying resistance or voltage depending on some environmental factor such as light, sound, temperature, pressure etc. This varying resistance gets translated into a varying voltage input into one of the avr chips input pins. The varying voltage is refered to as an 'analogue signal' or analogue input. The ADC module of the microcontroller converts this into a digital number within a certain range. So that the MC can then analyse the value of the input. PWM This stands for pulse width modulation. There is a duty cycle. This is a kind of approximated analogue output using digital highs and lows. * pwm code for an atmega8 (not sure if applicable to m328) ------------------ #define fillrate OCR2A // main() PORTB=0x00; DDRB=0x08; //We use PORTB.3 as output, for OC2A, see the atmega8 reference manual // Mode: Phase correct PWM top=0xFF // OC2A output: Non-Inverted PWM TCCR2A=0x81; // Set the speed here, it will depend on your clock rate. TCCR2B=0x02; // for example, this will alternate between 75% and 42% PWM while(1) { fillrate = 191; // ca. 75% PWM delay_ms(2000); fillrate = 107; // ca. 42% PWM delay_ms(2000); } ,,, TIMERS http://electronics.stackexchange.com/questions/2057/polyphonic-sounds-from-a-microcontroller some timer info timer (or counter) in normal mode, counts 0 to 255 then sets overflow. Prescaler, or divider, divides the system clock by value * set the prescaler ------------- ldi r16, 0b00000011 ; set timer prescaler = 64 out TCCR0B, r16 ; timer control register B ,,, Prescaler values are limited to the following. The higher the prescaler value, then the slower the timer with count up to 256 1, TCCR0B = 0b0000001 8, TCCR0B = 0b0000010 64, TCCR0B = 0b0000011 256, TCCR0B = 0b0000100 1024, TCCR0B = 0b0000101 To calculate delay for timer/counter user clock/prescaler * 256 eg 16 Mhz /1024 * 256 = ?? * blinking a led using the timer (counter) with prescaler ------------- ; blinks an LED which is connected to PB5 (digital out 13) .include "m328Pdef.inc" rjmp start sleep: in r16, TIFR0 ; get timer flags register 0 andi r16, 0b00000010 ; tov0 ~ timer overflow flag (bit 2) breq sleep ; if overflow not set, then loop ldi r16, 0b00000010 ; reset timer overflow flag by setting it out TIFR0, r16 ; to 1 ret start: ldi r19,0b00100000 ; or try etc "sbi ddrb, 0" out DDRB,r19 ; ddrb ~ data direction register B ldi r16, 0b00000101 ; set timer prescaler = 1024 out TCCR0B, r16 ; timer control register B again: ldi r19,0b00100000 ; or try sbi instruction for toggling out PortB,r19 ; rcall sleep ldi r19,0b00000000 ; turn off led out PortB,r19 ; send to pin on port b rcall sleep rjmp again ,,, If we preload the counter with eg 128 then the timer overflows twice as quickly * preload the timer counter ----------- ldi r16, 128 ; preload timer with 128 out TCNT0, r16 ; timer count register := 128 ,,, * blinking a led using the timer with prescaler and preloaded counter ------------- ; LED connected to PB5 (digital out 13) .include "m328Pdef.inc" rjmp start sleep: in r16, TIFR0 ; get timer flags register 0 andi r16, 0b00000010 ; tov0 ~ timer overflow flag (bit 2) breq sleep ; if overflow not set, then loop ldi r16, 0b00000010 ; reset timer overflow flag by setting it out TIFR0, r16 ; to 1 ret start: ldi r19,0b00100000 ; or try etc "sbi ddrb, 0" out DDRB,r19 ; ddrb ~ data direction register B ldi r16, 0b00000101 ; set timer prescaler = 1024 out TCCR0B, r16 ; timer control register B again: ldi r16, 128 ; preload timer with 128 out TCNT0, r16 ldi r19,0b00100000 ; or try sbi instruction for toggling out PortB,r19 ; rcall sleep ldi r19,0b00000000 ; turn off led out PortB,r19 ; send to pin on port b rcall sleep rjmp again ,,, By using interrupts the avr is free to do other things * use the timer using interrupts --------- .include "m328Pdef.inc" .def a = r16 ;general purpose accumulator .org 0000 rjmp on_reset ;reset vector .org 0003 rjmp tim0_ovf ; timer0 overflow handler on_reset: sbi ddrb, 0 ; set portb0 for output ldi a, 0b00000101 ; set prescaler to /1024 out tccr0b, a ; timer/counter control register "b" ldi a, 0b00000010 ; enable timer-overflow interupt ; No, timsk0 is not accessible with out ; out TIMSK0, a ; timer interrupt mask register ; sts = store direct to data space sts timsk0, a ; timer interrupt mask register sei ; enable interupts globally ; timer overflow interrupt handler tim0_ovf: sbi pinb,0 ; flip the 0 bit reti ; main loop start: nop ;do nothing rjmp start ,,, DELAYS * simple blinking code using about a 1 second delay ------------- ; turns on an LED which is connected to PB5 (digital out 13) .include "/usr/share/avra/m328Pdef.inc" ldi r19,0b00100000 ; or try etc "sbi ddrb, 0" out DDRB,r19 ; ddrb ~ data direction register B again: ldi r19,0b00100000 ; out PortB,r19 ; clr r16 ; set reg16 := 0 clr r17 ldi r18, 40 here: ; a delay loop 40*256^2 instructions dec r16 ; brne here dec r17 brne here dec r18 brne here ldi r19,0b00000000 out PortB,r19 ldi r18, 40 far: dec r16 brne far dec r17 brne far dec r18 brne far rjmp again ,,, ARDUINO * install the arduino java software >> sudo apt-get install arduino Then select the serial device and board (eg duemilenove) Then select file/preferences and check box for verbose info during upload * run arduino software with privelidges >> sudo arduino If you dont have the right priviledges the serial port will be greyed out. It doesnt seem to matter what usb socket the cable is plugged into at all. (at least not on my linux mint machine) * the following worked for me >> sudo avrdude -v -v -v -v -p atmega328p -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:hello.hex:i * the same without verbose output >> sudo avrdude -p atmega328p -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:hello.hex:i * below is a typical avrdude command from the ide >> /usr/share/arduino/hardware/tools/avrdude -C/usr/share/arduino/hardware/tools/avrdude.conf -v -v -v -v -patmega328p -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:/tmp/build5695632546898703228.tmp/sketch_mar13a.cpp.hex:i == avrdude options .. -c the programmer .. -P the serial port NOP * code to make an avr microcontroller do nothing ------------- here: rjmp here ,,, SOUND http://avrprog.pbworks.com/w/page/9345379/AvrSound a good simple program to play midi file squeakily on a piezo buzzer PIEZO BUZZERS .... This is a small device for playing sound. Apparently it can also operate as a sensor The piezo buzzer can make tunes by simply toggling the output on a pin at a certain frequency. But this job is perhaps better done with pulse width modulation using a %50 duty-cycle square wave, at different frequencies. All this can be done much better with timers and interrupts. we can also simplify by using the pinb trick to toggle and output pin circuit: pin13->100R(??)-->piezo-->Ground * buzz a piezo connected to arduino pin 13 then to ground ------------- .include "/usr/share/avra/m328Pdef.inc" ldi r19,0b00100000 out DDRB,r19 again: ldi r19,0b00100000 out PortB,r19 clr r16 clr r17 ldi r18, 4 here: dec r16 brne here dec r17 brne here dec r18 brne here ldi r19,0b00000000 out PortB,r19 ldi r18, 4 far: dec r16 brne far dec r17 brne far dec r18 brne far rjmp again ,,, The code is not working properly below * another pause routine adapted from 'retrodan' code ----------- .include "/usr/share/avra/m328Pdef.inc" .DEF A = R16 ;GENERAL PURPOSE ACCUMULATOR .DEF I = R20 ;INDEX .DEF N = R22 ;COUNTER ;.ORG 0000 ON_RESET: ldi r19,0b00100000 out DDRB,r19 ; SBI DDRB,5 ;SET PORTB0 FOR OUTPUT main: SBI PINB,5 ;TOGGLE THE BIT ;RCALL PAUSE ;WAIT/PAUSE rjmp main ;go back and do it again ; pause routines PAUSE: LDI N,0 ;DO NOTHING LOOP PLUPE: ; RCALL np ; CALLS ANOTHER DO NOTHING LOOP DEC N ; CHECK IF WE COME BACK TO ZERO BRNE PLUPE ; IF NOT LOOP AGAIN RET ;RETURN FROM CALL np: LDI I,0 ;START AT ZERO MPLUP: DEC I ;SUBTRACT ONE BRNE MPLUP ;KEEP LOOPING UNTIL WE HIT ZERO RET ;RETURN FROM CALL ,,, Below is working but there is a mysterious error with high(ramend) etc * another attempt ---------------- .include "/usr/share/avra/m328Pdef.inc" ; .INCLUDE "M169DEF.INC" .DEF A = r16 .DEF I = r21 .org $0000 reset: ;ldi a, high(ramend) ;OUT SPH,A ;LDI A,LOW(RAMEND) ;OUT SPL,A SBI DDRB,5 again: rcall bpause sbi pinb,5 ; toggle arduino output 13 pin rjmp again bpause: BLOOP: LDI I,5 BPLUPE: DEC I BRNE BPLUPE DEC A BRNE BLOOP RET ;SETUP THE STACK POINTER ;AT TOP OF MEMORY AND ;GROW DOWNWARDS ;CONFIG SPEAKER PORT ;WAIT ;CLICK THE SPEAKER ;DO IT AGAIN ;PAUSE ROUTINE ;TIME DEPENDS ON "A" ,,, POWER Batteries are rated by their mAh which means "milliamp hours" so an AA battery rated at 1000mAh could in theory produce 1 milli-amp for 1000 hours. If a project is powered by battery or solar panel, then its really a good idea to reduce power consumption. Arduino Uno draws 42mA (per hour) https://www.openhomeautomation.net/arduino-battery/ an excelent tutorial for powering an atmega328 on a breadboard with only 2 AA batteries and no voltage regulator. The atmega is powered at 3V with an external crystal. Also discusses ways to make the atmega328 use less power http://arduino.cc/en/main/standalone How to put the arduino on a bread-board powered with a ~9volt battery and using a 7805 voltage regulator to reduce voltage to 5V. Apparently this type of regulator wastes energy http://arduino.cc/en/Tutorial/ArduinoToBreadboard similar to above but without incircuit programming of the atmega chip. https://alanbmitchell.wordpress.com/2011/10/02/operate-arduino-for-year-from-batteries/ another low power article LOW POWER .... The atmega328 has 5 modes to reduce power consumption which can be activated through code. Ideas to reduce power consumption, use the on-chip oscillator and clock at 8Megahz. Use a 'switching' voltage regulator. run chip at 3V or 3.3V turn off unused stuff, like ADC etc CLOCK .... you can throttle the internal clock of the ATmega328 on the fly. see CLKPR. You can educe the internal 8MHz clock to 31.250kHz with two lines of code. SLEEP MODES .... http://www.engblaze.com/hush-little-microprocessor-avr-and-arduino-sleep-mode-basics/ a tutorial about avr sleep modes. BATTERY POWER .... CR2032 20mm coin cell battery runs at 3V and doesnt require a voltage regulator. but only has a rating of 200mAh so low power consumption is necessary. LR123 type lithium cell. high amp hours rating SOLAR POWER .... Powering an arduino or atmega with solar seems feasible put panels in series to increase voltage, and in parallel to increase amperage. http://www.instructables.com/id/Solar-powered-arduino-on-the-back-of-a-playing-car/ This is a very interesting blog on how to create a playing card sized solar panel to power an arduino AVRA avra is an assembler for use with avr chips. This is good if you dont like c or java. * to use register names you need an 'inc' file for the chip >> eg: /usr/share/avra/tn13def.inc avra doesnt seem to come with an inc file for the atmega328 but one should be findable * compile a file to a hex file >> avra hello.asm VIM AND AVR PROGRAMMING Vim can be used to compile, and upload to the arduino board code in a text file, or even code contained within another type of text document. * map the key sequence ';av' to compile the whole file with avra >> map ;as :!avra % or >> map ;as :!avra % -o %:r.hex The second example is not necessary since by default avra creates a file called name.hex where the source file is 'name.asm' In the examples below, the complete assembly program is supposed to be within 2 'markers' within a document. The markers are '---' on a line by itself and ',,,' on a line by itself. These 2 markers mark the beginning and end of the assembly program within the document. Also the cursor needs to be between these 2 markers. * compile an avr assembly program within a document to 'test.hex' >> map ;ac :?^ *---?+1,/,,,/-1w ! ( cat - ) > test.asm; avra test.asm; * compile source and upload to the arduino 'duemilanove' board >> map ;av :?^ *---?+1,/,,,/-1w ! ( cat - ) > test.asm; avra test.asm; sudo avrdude -p atmega328p -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:test.hex:i The following is useful for determining how much space is left within a boot file (which is limited to 512 bytes) * see how big a compiled file is without running it >> map ;ab :?^ *---?+1,/,,,/-1w ! ( cat - ) > test.asm; avra test.asm; ls -la DOCUMENT-NOTES: # this section contains information about the document and # will not normally be printed. # in what kind of state (good or bad) is this document document-quality: just begun document-history: @@ Mar 2015 started this book about programming avr microcontrollers such as the Atmega328 which is on some arduino boards. @@ Wed 18 march 2015 document info and some vim and avr. Playing with the piezo speaker. # who wrote this authors: mjbishop