** Arduino and Avr programming using mainly Assembler This booklet contains info about my experiments with the arduino boards, such as duemilenove, pro mini, eleven etc. There is also a booklet 'avr' which deals with assembly programming of the arduino boards. 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. SETUP * install arduino ide >> apt-get install arduino Arduino has to be run as sudo on my computer!! to be able to edit sketches. eg sudo arduino * install avrdude and avra to compile , upload from command line. (not ide) >> apt-get install avrdude avra * install fritzing to make pretty pictures of arduino circuits >> apt-get install fritzing Connect usb to uart connector.. rx:tx tx:rx gnd:gnd 3v3:vcc dtr:dtr dont connect 5v (for a 3v3 pro mini for example) In the ide choose tools->board->pro mini 328 3v3 (for example) choose serial port (usb for example) Load an example sketch from ide, eg "blink" and upload. what led on pin 13 blink. * install arduino-mk for command line stuff with arduino * environment vars for mk ------- ARDUINO_DIR = /usr/share/arduino ARDMK_DIR = /usr AVR_TOOLS_DIR = /usr ,,, * make file for arduino-mk ------- BOARD_TAG = pro328 # for the pro mini 3v3 atmega328 # ARDUINO_PORT = /dev/cu.usb* ARDUINO_PORT = /dev/ttyUSB0 # include libraries here ARDUINO_LIBS = Ethernet Ethernet/utility SPI include /usr/share/arduino/Arduino.mk ,,, * show valid values for the boardtag variable. >> make show_boards http://www.mjoldfield.com/atelier/2009/02/arduino-cli.html info on how to do it. make sketch file, eg "first.ino" and copy to new dir, cd there >> make * upload sketch >> make upload It worked!!! SKETCHES Programs written in the arduino ide are called sketches. * basic sketch with serial ------------ void setup() { Serial.begin(9600); Serial.println("Hello !!!"); } void loop() { } ,,, BLINK .... Blink is the quintessential starting sketch on the arduino. It requires no hardware because all or most arduinos have a LED on the board. * blink the onboard led ------------ // on some arduino boards the on-board led may be // on a different pin. int led = 13; void setup() { pinMode(led, OUTPUT); } void loop() { digitalWrite(led, HIGH); // turn LED on delay(1000); // wait 1 second digitalWrite(led, LOW); // turn LED off delay(1000); // wait 1 second } ,,, BOARDS pro mini - based on atmega328. connect with ftdi cable to usb 32K flash (program) - 2K bootload 2K sram (data). 1K eeprom 3.3v and 8 megaherz 5v and 16 megaherz External interrupts. pin 2,3 uno - atmega328, 5v 16megaherz? BOOKS The mazidi book looks a good and simple resource for programming the arduino in assembler. But the examples must be modified for the atmega328 http://www.microdigitaled.com/AVR/Code/AVR_codes.htm all the mazidi books examples as plain text source code are available here which is an amazing resource. Since all the examples are very carefully and well written. * wget -c --user-agent=Mozilla --no-directories --accept='Example*.*' -r -l 1 http://www.microdigitaled.com/AVR/Code/AVR_codes.htm This wget got most of the chapters but not all. -c continue, -r -l1 recursive but only one level, --accept file name pattern. The examples need to be adapted because they are for the m32def device eg txen -> txen0, ucsrb -> ucsr0b. Also, many "out" instructions need to be replaced by "sts" since we are dealing with extended i/o space. I think The examples are all uppercase and use tabs between mnemonics and register names. * make names better >> rename 's/\.TXT$/.txt/' *.TXT * insert an example using vim >> :r mazidi/Example11_5.asm ARDUINO C BOOKS .... "Arduino, circuits and projects guide" by Gunter Spanner has lots of good stuff in it. Eg sin wave fast pwm for nice "ding" tones etc. 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. Develop a byte code system. Ie, a simple interpreter of byte code for the atmega328 TOOLS == tools .. avra - an assembler to use with arduino .. avrdude - a tool to program the arduino board .. DISPLAYS SEVEN SEGMENT DISPLAY .... This is the old calculator number display. NOKIA SCREEN .... nokia 5510, based on phillips pd.... is commonly used with arduino. LCD .... Hitachi HD44780 is the most common control chip of liquid crystal displays, and is supported by an arduino library. The arduino-mk program has a good example of using an lcd with and arduino and the lcd library. >> /usr/share/doc/arduino-mk/examples/HelloWorld/HelloWorld.ino The circuit: * LCD RS pin to digital pin 12 * LCD Enable pin to digital pin 11 * LCD D4 pin to digital pin 5 * LCD D5 pin to digital pin 4 * LCD D6 pin to digital pin 3 * LCD D7 pin to digital pin 2 * LCD R/W pin to ground * 10K resistor: * ends to +5V and ground * wiper to LCD VO pin (pin 3) OLED SCREEN .... The Oled screen is a more recent technology compared to lcd screens with high contrast and 2 wire interface. ULTRASONIC Simple ultrasonic boards can find range based on the speed of sound. Ultrasonic Sensor HC-SR04. This needs 5v. Emit at 40KHz and receive an echo. Speed is dependant on temperature of air. connections: trigger -> pin 9, echo -> 10, gnd:gnd, vcc:5v I used the 5 volt wire from the ftdi board to power the ultrasonic sensor with a pro mini 3v3 and it worked, but is this bad for the echo pin to receive 5v ?? * simple sketch, assuming speed of sound 340 m/s, no resistors ---------------- // pin numbers or use "define" const int trigPin = 9; const int echoPin = 10; const int ledPin = 13; long duration; int distance; void setup() { pinMode(trigPin, OUTPUT); // trigger fires sound pulse pinMode(echoPin, INPUT); // echo receives sound pulse Serial.begin(9600); // Starts the serial communication } void loop() { digitalWrite(trigPin, LOW); delayMicroseconds(2); // trigger HIGH for 10 micro secs sends sound pulse digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); // returns the sound wave travel time in microseconds duration = pulseIn(echoPin, HIGH); // distance in centimeters, assumes speed of sound 340 m/s distance = duration*0.034/2; Serial.print("Echo duration: "); Serial.print(duration); Serial.println(" microseconds "); Serial.print("Distance: "); Serial.print(distance); Serial.println(" cm "); if (distance < 40) { digitalWrite(ledPin, HIGH); Serial.println("< 40 cm !!"); } else { digitalWrite(ledPin, LOW); } delay(800); } ,,, SERVO MOTORS positions 45: extreme left 90: centre 135: extreme right circuit: 3v3: red wire, gnd: black wire, other to pin 9, no resistor * control a servo motor ------------ #include Servo servo; //int pos = 0; void setup() { Serial.begin(9600); servo.attach(9); } void loop() { Serial.println("sweep..."); for (int pos = 0; pos <= 180; pos += 1) { servo.write(pos); delay(15); } Serial.println("and back..."); for (int pos = 180; pos >= 0; pos -= 1) { servo.write(pos); delay(15); } } ,,, We can communicate to the program below with ... >> sudo picocom -b 9600 --echo /dev/ttyUSB0 There is a gotcha here. Many serial terminals send line feeds cr lf etc which makes Serial.available return true even when there is nothing to read. So I am using a hack in the code below to get rid of the lf if any. * control a servo with keyboard and serial ----------------- #include Servo servo; void setup() { pinMode(9,OUTPUT); servo.attach(9); //analog pin 0 //servo.setMaximumPulse(2000); //servo.setMinimumPulse(700); Serial.begin(9600); Serial.println("Enter position 0 to 180 ?"); } void loop() { //static int v = 0; if (Serial.available()) { int v = Serial.parseInt(); servo.write(v); Serial.print("To position:"); Serial.println(v); v = 0; // get rid of line feed if terminal is sending one if (Serial.available()) { Serial.read(); } } } ,,, BLUETOOTH WITH HC05 The HC-05 is a very inexpensive and widely used bluetooth chip which is compatible and easy to use from an Arduino board The default baud rate is 38400 (not 9600), 8 data bits, 1 stop bit, no parity bit. Once the hc05 is connected to the rx and tx pins of an arduino board, the serial communication coding is exactly the same as any other serial connection, which is very handy. https://www.itead.cc/wiki/Serial_Port_Bluetooth_Module_%28Master/Slave%29_:_HC-05 Lots of good info about the HC=05 http://www.instructables.com/id/Modify-The-HC-05-Bluetooth-Module-Defaults-Using-A/ Modify hc05 with at commands The hc-05 has an onboard led which is good for knowing what is going on with it. So ... == hc-05 onboard led information led not lit: no power! put 3v3 on vcc and gnd to gnd led fast flash: power put no signal led slow single flash: connected to serial but not paired led slow double flash: connected and paired!! Using the hc05 bluetooth board we can connect to an arduino microcontroller using a linux computer with no wires!! http://pi19404.github.io/pyVision/2015/04/03/22/ this page was very usefull for getting it all working and giving command line incantations. It is possible blueman does this for you, below * in /etc/bluetooth/rfcomm.conf put, changing the mac address ------------ rfcomm0 { bind no; device 98:D3:31:XX:XX:XX; # change this to your HC05 mac address channel 1; comment "Serial Port"; } ,,, * install cutecom a nice gui serial terminal >> sudo apt-get install cutecom Now pair the device using 'blueman', your device should appear with an option to connect via serial * Start the cutecom serial terminal >> sudo cutecom Note!! On my system cutecom has to be started as root or you wont be able to connect to open /dev/rfcomm0 and in the device box type /dev/rfcomm0 (etc). Set the baud rate to 57600, and click open device. Now type your commands and see the robot move (if its a robot you are controlling). Of course this assumes you have code on the arduino that receives serial data and executes commands. Baud Rate: in my experiments the robot moved even when the baud rate was not correct (??). * or use picocom with hc-05 connected to usb port >> sudo picocom -b 38400 --echo /dev/ttyUSB0 Unusually the default baud rate for HC-05 bluetooth is 38400 when connected via usb, but 9600 when connected via bluetooth... Type control-a control-x to exit picocom * minicom is another alternative >> sudo minicom -b 38400 -D /dev/ttyUSB0 Then turn off hardware flow control (control-a o) and turn echo on Minicom allows scripts which could be useful. Turning hardware flow control off only seems necessary when connected via usb AT COMMANDS TO CONFIGURE THE HC05 .... We can use the venerable old "AT" modem commands to configure an HC-05 chip. I thought those days were over ... I use the graphical "cutecom" serial monitor with baud=38400, line-ending=cr,lf device=/dev/ttyUSB0 (when the HC-05 is plugged into a usb port via a usb-to-uart converter). It appears that it is not possible to configure an HC-05 via bluetooth which makes sense because it would invalidate the security of the device. Connect HC-05 to the usb to uart converter board as follows >> rx to tx, tx:rx, 3v3 to vcc, gnd to gnd, easy... The CR+LF line ending is important, it wont work otherwise When connecting the HC-05, hold down the little reset button (which it hopefully has, otherwise proceedure is different). The led will blink very slowly Type "AT" to receive "OK" for confirmation of communication * see if communication is happening with HC-05 bluetooth chip >> AT * display the module working state >> AT+STATE? (eg: "INITIALIZED" "READY" "PAIRABLE" "PAIRED" "INQUIRING" "CONNECTING" "CONNECTED" "DISCONNECTED" "NUKNOW" ) * show the bluetooth password or pin code >> AT+PSWD or AT+PSWD? * change the bluetooth connection pin code >> AT+PSWD= * check the current baud rate, stop bit and parity >> AT+UART? * set the baud rate to 38400, no stop bit, no parity >> AT+UART=38400,0,0 * set the baud rate to 115200, stop bit, with parity >> AT+UART=115200,1,2 * get the hc-05 bluetooth address (not mac address) >> AT+ADDR? eg: +ADDR:1234:56:abcdef (NAP: UAP : LAP) These addresses are used when binding master (server) and slave (client). See the next sub-section for more information. Its important to change the name to something memorable, so that pairing will be easy. This name is what appears in the blue tooth connection screen (eg for android/linux/windows) * set module name (default hc-05) >> AT+NAME= * get bluetooth device name (address eg: 00:02:72:OD:22:24) >> AT+RNAME? 0002,72,od2224\r\n * check connect mode (0=fixed address, 1=any address, 2=slave loop) >> AT+ CMODE? * set fixed address 98:D3:31:20:93:CB >> AT+BIND=98d3,31,2093cb MASTER SLAVE .... In the master slave mode, the HC-05 can automatically connect to another HC-05 bluetooth chip. This obviates the need to have to manually connect via bluetooth in order to control a robot, for example. The second HC-05 board can be connected to computer with a usb-to-uart board (ftdi) When I typed at+init the 2 modules bound together. But... there is disagreement about cmode=0/1 which is fixed address mode??? I had to configure the master HC-05 (which is plugged into the usb port of my laptop via a usb-to-uart board) at 38400 baud even though the slave (on the arduino robot) is apparently running at 57600. This works! I get coherent responses from the robot serial connection. If I set the master at 57600 I get gibberish responses from the robot (which indicates a baud mismatch). It seems that when the HC-05 is plugged into the usb port via the usb-to-uart converter it always runs at 38400 no matter what its configured baud rate is!!!??? On my HC-05 at+cmode=0 is fixed address and must be used with at+bind On my HC-05 at+cmode=1 binds to any address. The key to all this is the at+init command which actually binds the "slave" hc-05 to the "master" hc-05 (which is connected to the computer or some other controlling device. When cmode=1 (connect to any device) after at+init the hc-05 blinks slowly while it search for another device in range and then binds to it. But when cmode=0 and bind=addr the hc-05 connects quickly after at+init (2 short flashes) * set an HC-05 to master mode, and bind it to the slave (on the robot) ------ AT+ORGL // factory reset AT+RMAAD // clear all paired devices AT+UART=38400,0,0 // baud rate, stop, parity AT+ROLE=1 // master mode AT+CMODE=0 // fixed address connection mode, yes (or AT+CMODE=1 connect to any device in transmission range) AT+BIND=98D3,31,3069B0 // address of slave AT+INIT ,,, The slave usually doesnt have to be configured at all, it appears. * set an HC-05 to slave mode >> AT+ROLE=0 GOTCHAS .... If you connect tx->tx and rx->rx Wrong! (hc05 to arduino) the hc-05 will pair and connect but not do anything. Sometimes picocom will say >> FATAL: cannot open /dev/rfcomm5: Device or resource busy but why??? maybe the device is being used by some other process (cutecom ...) Make sure you are using >> sudo !!! >> sudo minicom or sudo picocom or sudo cutecom Or make sure that you are using the last /device Eg if you try /dev/rfcomm3 when blueman has assigned /dev/rfcomm4 then rfcomm3 will be "busy" STACK The avr chips usually have a hardware stack which is used for procedure calls (call, rcall) and can be used by the programmer explicitly with "push" and "pop". However the stack is 8 bit, obviously, so it is a bit clumsy to use it to pass pointers to code or data space. The stack pointer registers should be initialized before using the stack (ie calling a procedure). * initialize the stack, must be done before any "call/rcall" ----------- .include "m328Pdef.inc" ldi r21, high(ramend) out sph, r2 ldi r20, low(ramend) out spl, r21 ,,, SERIAL TERMINALS .... minicom, picocom, microcom, cutecom (easiest, graphical) If gibberish is returned from arduino, check that baud rates match. WINDOWS install driver cp2102 to use the usb to uart device. Then putty at baud rate 38400 maybe com70 INTERPRETER The following is the bare bones code for running an interpreter over a serial connection. Here the mcu receives data via serial and executes the appropriate command. A more sofisticated system could read the serial stream for a whole line and modify commands with parameters etc, after that, if/loop/ etc. A tiny command interpreter is what is needed, maybe an adaption of python, forth, lua or tcl This is 'arduino' c... * a simple interpreting loop getting commands from serial ------------------- void setup() { Serial.begin(57600); // ... } void loop() { if (Serial.available() > 0) { data = Serial.read(); Serial.print("rx:"); Serial.print(data); } if (data == 'a') { // execute command for 'a' } else if (data == 'b') { } else {} } SYNTAX FOR ARDUINO C * print as ascii >> Serial.write(a); 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 avr assembly is not case sensitive * a so so avr assembly site >> https://sites.google.com/site/avrasmintro/ MACROS .... Setting up the stack needs to be a macro and not a function because function calls with rcall etc, are not available until the stack pointer has been set! * macro example to set up the stack pointer ------------------ .include "m328Pdef.inc" .macro initstack ldi r21,high(ramend) out sph,r21 ldi r21,low(ramend) out spl,r21 .endmacro initstack ,,, DEF .... we can give registers more descriptive names with the .def assembler directive * eg --------- .def r0 = acc .def r18 = counter ,,, LABELS .... labels require a colon, eg buffer: not buffer labels cant start with dot (ie local labels in nasm) cant have dots in them... CONSTANTS .... * define constants ------------- .equ score = 100 .set score = 100 ; the same ,,, DATA SEGMENT .... In the atmel avr architecture, code and data space are separate. * specify the data segment >> .dseg * an example of creating a buffer in the data segment --------- .dseg counter .byte 2 .cseg ,,,, CODE SEGMENT .... With .db we can define string constants such as "test" but without any escaped characters (eg \n) * define some constant data in the code segment ---------------- .include "m328Pdef.inc" .cseg greet: .db "hello", 0 ;greet: .db "hello", '\n', 0 message: .db 'h','e','l','l','o',0 ; a harder way to do it ,,, MNEMONICS .... avr assembly, as with all microcontroller assemblies has a plethora of mnemonics or aliases for referring to ports and registers. Eg: tccr0b means "timer/counter 0 control register b". These are in addition to all the standard assembly mnemonics such as "ldi" etc. ARITHMETIC INSTRUCTIONS ..... These instructions perform some simple arithmetic on an 8 bit register. add, sub, inc, dec JUMPS .... jumps go to a particular instruction if the given condition is met. There are conditions which are specific to signed and unsigned numbers among others. brne - branch if not equal SKIPS .... skips are similar to jumps except that they only skip one (the next) instruction, if the condition is met. PROCEDURES .... rcall - LOGICAL INSTRUCTIONS .... ANDI .... andi - logical and with immediate (literal) value EOR .... exclusive or. This can be used for toggling bits, but the operand cant be immediate. eg "eor r20, 1" is an error and won't be compiled BITS .... * toggle the least significant bit in r17 ----------- eor r17, 1 eor r17, 0x01 ; the same ,,, * toggle the most significant bit in r17 ----------- eor r17, 1<<8 eor r17, 0b10000000 ; this is the same, but more verbose ,,, MOVING DATA TABLE READ INSTRUCTIONS LPM .... Reading data from the code segment (flash memory) is often referred to as table reading. The code segment data is often assumed to be "constant" since it is not usually altered during the execution of a program (although it can be with the spm instructions) There is usually much more code memory (eg 32K in atmega328) than sram data memory (2K in atmega328) so it is a good idea to store long strings here. lpm Rn, Z - load program memory lpm Rn, Z+ - load program memory and increment pointer * read a string stored in the program memory ------ .include "m328Pdef.inc" .dseg .cseg buffer: .db 5, "hello" ldi r16, 5 ; load string count into r16 ldi zh, high(buffer<<1) ldi zl, low(buffer<<1) inc zl nextchar: lpm r20, z ; get contents of byte at z into r16 inc zl dec r16 brne nextchar here: rjmp here ; loop for ever ,,, IN .... in gets data from an i/o port LDI .... ldi - load immediate value * an example using ldi ----------------------- ldi r16, 0b00000101 ,,, INDIRECT ADDRESSING WITH LD AND ST .... * load contents of sram location 0x130 into r18 ------ .include "m328Pdef.inc" .eseg ; define eeprom data buffers here ; 1024 bytes of eeprom in atmega328 ebuffer: .db 5, "hello" .dseg ; define sram data buffers here. ; 2k bytes of sram in atmega328 dbuffer: .byte 30 .cseg ldi xl, 0x30 ldi xh, 0x01 ld r18, x here: rjmp here ; loop for ever ,,, * store 0 in 16 addresses starting at 0x0060 ------ .include "m328Pdef.inc" .dseg buffer: .byte 16 .cseg ldi r16, 16 ldi xl, 0x60 ldi xh, 0x00 ldi r20, 0x0 again: st x+, r20 dec r16 brne again here: rjmp here ; loop for ever ,,, STS .... store direct to data space ARITHMETIC IN ASSEMBLER DIVISION .... There is no division instruction for the avr atmega mcs. This can be done with repeated subtraction or another technique. ADDING TWO BYTE NUMBERS .... use addc. STRINGS It appears that avra doesnt support special chars such as \n * define some "constant" strings in the code segment ---------------- .include "m328Pdef.inc" .cseg greet: .db "hello", 0 message: .db 'h','e','l','l','o',0 ; a harder way to do it ,,, * create a 20 byte string buffer in the data segment (sram) ---------------- .include "m328Pdef.inc" .dseg input: .byte 20 .cseg greet: .db "hello", 0 ,,, PROGRAM DATA SPACE SERIAL INTERFACE The avr atmega chips have a serial uart interface. This needs to be configured to a certain baud rate, parity and stop bit. The serial interface is very useful for communicating with the atmega from a computer, since the standard arduino usb connection can be treated as a serial connection. Also, in a forth-style system the serial connection is used to issue commands and "program" the chip. By combining these techniques with and hc05 bluetooth chip we have a simple way to wirelessly control and program an arduino. * formula for value of ubrr register >> #define ubrr (FOSC/(16*BAUD))-1 SERIAL COMMUNICATION IN C The serial interface is a great way to get information from an arduino about what it is doing or feeling. You can get this over the usb interface to the computer or via an hc05 bluetooth component for "remote" boards. Make sure the "baud" rate is the same on the serial monitor and in the sketch. >> Serial.begin(9600); baud rate is 9600. Serial monitor has to be the same or else gibberish is shown. Also make sure line endings are NL & CR serial.write() etc * basic sketch with serial ------------ void setup() { Serial.begin(9600); Serial.println("Hello !!!"); } void loop() { } ,,, * read one char from serial port and do something with it ------------------- void loop() { static int v = 0; if (Serial.available()) { char ch = Serial.read(); switch(ch) { case '0'...'9': v = ch - '0'; Serial.print("To position:"); Serial.println(v); break; case 's': break; case 'w': break; } } //Servo::refresh(); } ,,, TRANSMITTING .... By removing umsel0 code something positive happened. the little yellow tx light on the arduino uno lit up. good. wow its finally working, printing out yes yes yes the whole time. nice To test, open a serial terminal with device /dev/ttyACM0 or something similar and select baud 9600. * transmit using the usart serial interface ------------------ .include "m328Pdef.inc" ldi r21,high(ramend) out sph,r21 ldi r21,low(ramend) out spl,r21 ldi r16,(1< 0 here: rjmp here ; loop for ever ,,, RECEIVING RX .... * receive 40 chars from usart into a buffer ------------------ .include "m328Pdef.inc" .dseg buffer: .byte 60 .cseg ; set up stack ldi r21,high(ramend) out sph,r21 ldi r21,low(ramend) out spl,r21 rcall serialx ldi r17,'o' call trnsmt ldi r17,'k' call trnsmt ldi r17,' ' call trnsmt here: rcall acceptx rcall printx rjmp here serial: .dw 0 .db "serial", 0 serialx: ldi r16,(1< 0 ldi r17, 13 ; newline sts UDR0, r17 ; send it to serial ret trnsmt: lds r16, UCSR0A ; usart control, status register, cant use sbis sbrs r16, UDRE0 ; is usart data register UDR empty? rjmp trnsmt ; if not, then just wait sts UDR0,r17 ; if empty tx next character ret ,,, * receiving using the usart serial interface ------------------ .include "m328Pdef.inc" .dseg .cseg message: .db "hello",0 ldi r21,high(ramend) out sph,r21 ldi r21,low(ramend) out spl,r21 ldi r16,(1<> 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. COMPILING WITH AVRA obtain a file called "m328Pdef.inc". This contains all the aliases or mnemonics for the atmega328. If you are using a different avr chip obtain the appropriate file. remove the semi colon from the line ;.device ATmega328P This allows the compiler to check things like memory ranges and allows use of high(ramend) etc, eg for initializing the stack. UPLOADING NOT IN SYNC THE DREADED ERROR .... The "not in sync" error prevents any new sketch or code being uploaded from the arduino ide or from avrdude etc. It can be caused by a multitude of things... eg To solve, first check the arduino board type. Then check usb cable connections. Then check rx/tx pins not connected. Then swap out usb cable for different one. Then swap out board for different. Etc. solution by elimination... * here is the dreaded not in sync error ----- avrdude: stk500_recv(): programmer is not responding avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x00 ,,,, !! causes of out of sync error: * serial port chosen badly. eg ttyS0 instead of ttyACM0 * bad usb cable: For example: for a "freetronics" uno compatible, a good usb cable will light on board led, turn power led blue, flash onboard led, then flash rx led once, then flash D13 onboard led. A bad cable may just turn on the power led blue, and turn on D13 led weakly. * bad ftdi cable connection * wrong "baud" rate (if manually set with avrdude) * wrong board type selected (eg uno when using pro mini) * something plugged into the rx/tx serial pins of the board, for example trying to upload a sketch by usb cable with an ftdi usb-to-uart connect plugged in * a "fried" board or atmega chip, the worst scenario. * ... COMMAND LINE UPLOAD .... The trick is to select verbose output in the arduino ide to see the appropriate switches for avrdude for a given arduino board etc. The following details how to upload code, eg a hex file to an arduino board from the unix command line. It doesnt seem to matter what usb socket the cable is plugged into at all. (at least not on my linux mint machine) * upload to duemilenove arduino >> sudo avrdude -v -v -v -v -p atmega328p -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:hello.hex:i Notice here the device and baud rate are different. * upload to "uno" compatible freetronics arduino board >> sudo avrdude -p atmega328p -carduino -P/dev/ttyACM0 -b115200 -D -Uflash:w:hello.hex:i If we use the wrong baud rate, avrdude gives messages, >> avrdude: stk500_recv(): programmer is not responding >> avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00 * the same without verbose output >> sudo avrdude -p atmega328p -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:hello.hex:i * avrdude upload command for "uno" board connected via usb >> usr/share/arduino/hardware/tools/avrdude -C/usr/share/arduino/hardware/tools/avrdude.conf -v -v -v -v -patmega328p -carduino -P/dev/ttyACM0 -b115200 -D -Uflash:w:/tmp/build4770305616360723053.tmp/Blink.cpp.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 ideas: sin wave calculation. ding sound using decaying amplitude hilo tech sound file. exponential decay of amplitude for nice ding. fast pwm. see arduino book "gunter" 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 ,,, These may be modified Gunter Spanner examples pin10 -> piezo -> gnd (no resistor, polarity unimportant) * just stop the piezo !! its so tinny ---------- const int speaker = 10; void setup() { pinMode(speaker, OUTPUT); } void loop() { } ,,, * a simple alarm ---------- const int speaker = 10; void setup() { pinMode(speaker, OUTPUT); } void loop() { tone(speaker, 550, 450); delay(1000); } ,,, * science fiction sound ---------- const int speaker = 10; void setup() { pinMode(speaker, OUTPUT); } void loop() { for (int i = 200; i < 500; i += 10) { tone(speaker, i, 50); delay(20); } delay(1000); } ,,, * sin wav ---------- const int speaker = 9; const byte value[] = { 127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173, 176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240, 242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223, 221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78, 76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31, 33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124 }; void setup() { pinMode(speaker, OUTPUT); //tone(speaker, 550, 200); TCCR1A = 0b10000001; TCCR1B = 0b00001001; } void analogOut(byte val) { OCR1A = (val); } void loop() { for (unsigned int j = 0; j < 256; j++) { analogOut(value[j]); delayMicroseconds(10); } } ,,, 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. The arduino pro mini is good because it is lower power consumption than other arduinos. Arduino Uno draws 42mA. So would exhaust 1 AA battery in about 30 hours 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 CAR ROBOT BY BOB ELLIOTT The car robot is small, inexpensive and easy to modify. It uses an arduino pro mini, with a voltage regulator, hbridge and hc05 for bluetooth serial communication. On android, we are using blueterm 2 to drive the robot. First pair the robot in bluetooth settings (single slow flashing led on the hc05) and then connect in the blueterm screen (double slow flashing when successful) DEVICES OR BITS AND BOBS This section contains a list of handy stuff that can be used in arduino projects, with a short description of what the item does hc-05 connect to an arduino via bluetooth serial ws2811 12mm DC5V leds. Big individually addressable strips of leds, use fastled.io library cr2032 coin cell battery small battery with about 200mAH capacity PROJECT IDEAS This is just a list of things that may be possible with an arduino analog meters using old voltage meters hsmag.cc/JBGDAz plant waterer hsmag.cc/HhpgXb Synthesizer using lookup tables for sin waves and connecting to speaker jack via aligator clips boldport pcb solder club 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. Also, how to compile arduino c...? from the command line * 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 or c 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 ,a :?^ *---?+1,/,,,/-1w ! ( cat - ) > test.asm; avra test.asm; * compile source and upload to the arduino 'duemilanove' board >> map ,u :?^ *---?+1,/,,,/-1w ! ( cat - ) > test.asm; avra test.asm; sudo avrdude -p atmega328p -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:test.hex:i * compile source and upload to the arduino 'uno' board >> map ,v :?^ *---?+1,/,,,/-1w ! ( cat - ) > test.asm; avra test.asm; sudo avrdude -p atmega328p -carduino -P/dev/ttyACM0 -b115200 -D -Uflash:w:test.hex:i * open a serial terminal to communicate with an arduino >> map ,s :! sudo picocom -b 9600 --echo /dev/ttyACM0 Type control-a control-x to exit picocom 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 VIM WITH ARDUINO C .... we use arduino-mk with a Makefile in a subdirectory to automatically compile and upload a sketch which is written in arduino c with the "vim" text editor. The only tricky bit is automatically getting the arduino libraries into the Makefile. We may need to hand edit that file in some cases. the arduino-mk needs to be configured, see above in "setup" * extract an arduino c prog in a vim doc to a subdirectory "sketch" >> map ;ac :?^ *---?+1,/,,,/-1w ! ( cat - ) > sketch/test/test.ino; ls -la sketch/test * compile an arduino c prog in a vim doc to a subdirectory "sketch/test" >> map ;ac :?^ *---?+1,/,,,/-1w ! ( cat - ) > sketch/test/test.ino; cd sketch/test; make if there are other ".ino" files in sketch/test this will fail * compile an arduino c prog and upload to the board >> map ;au :?^ *---?+1,/,,,/-1w ! ( cat - ) > sketch/test/test.ino; cd sketch/test; make; make upload This last mapping is not quite working, programmer out of sync etc only small problem I think. The Makefile in the sketch/test subfolder has a tag that determines the type of arduino board (pro mini 328 3v3 etc) and the serial port. Adjust that makefile for different boards * look in doc folder for good examples of using arduino-mk >> /usr/share/doc/arduino-mk/examples/ * an example Makefile for arduino-mk bash uploading -------- #BOARD_TAG=pro328 BOARD_TAG=uno #ARDUINO_PORT = /dev/cu.usb* #ARDUINO_PORT = /dev/ttyUSB* # try a very general tty port, ttyUSB0, ttyS0 ARDUINO_PORT = /dev/tty* #ARDUINO_LIBS = Ethernet Ethernet/utility SPI #ARDUINO_LIBS = Servo include /usr/share/arduino/Arduino.mk ,,, DOCUMENT-NOTES: # this section contains "meta" information about the document # 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. * 8 November 2016 I combined the arduino book with the avr book, since my main focus now with the arduino will be programming in assembler. First I need to learn the avr architecture. # who wrote this authors: mjbishop