Assembly Programming on Atmega328p

Lecture 1

The Atmega328p microcontroller is a small computer on a single integrated circuit which contains a processor core, memory and programmable input and output peripherals.

imagens/img0.png

Why assembly?

  • Code is optimized for speed & space;

  • Assembly coding enables you to learn H/W organization of microcontroller;

  • Assembly code can take full advantages of controller H/W features;

Hardware Organization

imagens/img1.jpg

Instruction Set

Table 1. Instruction set table

Arithmetic and Logic

ADD

SUB

AND

OR

MUL

Branch

JMP

RCALL

RET

CPI

BREQ

Data transfer

MOV

In

OUT

LDI

STS

Bit-by-bit test

ROL

CBI

CLC

SWAP

ROR

Memory Map

imagens/img3.png

The purpose of this section is to provide the fundamentals for building an example to turn an LED on and off. This objective will be achieved through the analysis of the programs led.ino and led.S built using functions from the AVR Instruction Set Manual.

Table 2. Material list

Item

Quantidade

Plataforma Arduino

1

Cabo USB

1

Protoboard

1

Led

1

Resistor de 200 ohms

1

imagens/img7.png

Code

We need to create two files. The first file in c++ (extension .ino) and the second file in assembly (extension .S). Both with the same name and in the same directory.

//-------------------------
// C Code for Blinking LED
//-------------------------
extern "C"{
  void start();
  void led(byte);
}

void setup(){
  start();
}

void loop(){
  led(1); delay(200);
  led(0); delay(200);
}
;---------------
; Assembly Code
;---------------
#define __SFR_OFFSET 0x00
#include "avr/io.h"
;------------------------
.global start
.global led
;------------------------
start:
    SBI   DDRB, 5             ;set PB5 (D19) as i/o
    RET                       ;return to setup() function
;---------------------------------------------------------------------------
led:
    CPI   R24, 0x00           ;value in R24 passed by caller compared with 0
    BREQ  ledOFF              ;jump (branch) if equal to subroutine ledOFF
    SBI   PORTB, 5            ;set D19 to high
    RET                       ;return to loop() function
;---------------------------------------------------------------------------
ledOFF:
    CBI   PORTB, 5            ;set D19 to low
    RET                       ;return to loop() function
;---------------------------------------------------------------------------

Registers

ATMega328P has 32 general purpose registers [Registers R0 to R31]

  • 8 bit registers

  • Mapped to SRAM memory [Addresses between 0x00 and 0x1F]

imagens/img8.jpg

SRAM

ATMega328P has 2 Kbytes of main memory implemented with SRAM

  • Some segments are reserved

    • 0x00 to 0x1F are the 32 registers

    • 0x20 to 0x5F are I/O registers (Memory mapped I/O)

imagens/img9.png

Instruction format

  • Most instructions occupy 16 bits

  • There are several formats of instruction

  • Variable length opcodes

imagens/img10.png

Ex. Register Direct

  • Op: Opcode

  • Rr: Source register 1

  • Rd: Source 2 and destination register

Assembly instructions

  • Assembly instructions follow the same order used in MIPS

  • OPCODE destination, source

    • ldi r16,0xF (Load immediate 0xF into register r16)

  • The number of operands varies according to the operation

Code (advanced level)

The codes below can be downloaded from the links: led.s and Makefile.

.global main                    ;defining a global function
        .type main, @function   ;defining the type

main:
        ldi r16,0b00100000      ;ldi loads an immediate into registers 16 through 31.
        ldi r17,0b00000000
        ; The “register” DDRB (Section 14.4 of the manual), which is at address 0x4,
        ; configures the pins of port B are for input (0) or output (1).

        ; out loads to the I/O address the value that is stored in the register

        ; Loading 0b00000001 to address 0x4, making pin 5 of Port B used as output,
        ; and the others as input
        out 0x04,r16

LOOP:
        ; Register PORTB (address 0x5) defines whether a high or low signal is sent
        ; to the output pins of port B. Let's send logic 1 (5 volts) into PB5.
        out 0x05,r17
        jmp LOOP                ; Jump to loop label (infinite loop)
#
# Makefile
#
FILENAME   = led
PORT       = /dev/cu.usbserial-A600BOBB
DEVICE     = atmega328p
PROGRAMMER = arduino
# BAUD can be 115200, 74888, 57600
BAUD       = 57600
COMPILE    = avr-gcc -Wall -Os -mmcu=$(DEVICE)

default: compile upload clean

compile:
        $(COMPILE) -o $(FILENAME) $(FILENAME).s

upload:
        avrdude -v -p $(DEVICE) -c $(PROGRAMMER) -P $(PORT) -b $(BAUD) -U flash:w:$(FILENAME)

clean:
        rm $(FILENAME)

Lecture 2

ATmega328p MCU registers

imagens/img14.jpg
imagens/img15.png
  • Registers divided into two groups based on how they are used and their functionalities

  • R16 to R31 are more versatile and useful than R0 to R15

  • Example:

    • The registers that work with immediate data (R16 to R31) store a byte of information or words (pairs of registers x, y and z).

//-------------------------
// C Code
//-------------------------
extern "C"{
  void start();
}

void setup(){
  start();
}

void loop(){
}
;---------------
; Assembly Code
;---------------
#define __SFR_OFFSET 0x00
#include "avr/io.h"
;------------------------
.global start
;------------------------
start:
    LDI   R16, 0xFF           ;load immediate byte 0xFF into register
;    LDI   R15, 0xFF           ;trying to use a different register
    RET                       ;return to setup() function
;---------------------------------------------------------------------------
  • On the other hand, registers R0 to R15 work with indirect addressing, which means that we can store a byte located in a memory location. This code will also work with R16 and R17, but its contents cannot be changed by functions.

//-------------------------
// C Code
//-------------------------
extern "C"{
  void start();
}

void setup(){
  start();
}

void loop(){
}
;---------------
; Assembly Code
;---------------
#define __SFR_OFFSET 0x00
#include "avr/io.h"
;------------------------
.global start
;------------------------
start:
    LDS   R12, 0x200          ;load direct from data space byte at memory
                              ;location 0x200 into register
    RET                       ;return to setup() function
;---------------------------------------------------------------------------
  • The 3 word registers x, y and z can handle indirect addressing and immediate storage. The y-register can be for storing the frame point

  • R0 and R1 store the 16-bit result of a multiplication performed by opcode MUL. Mul will multiply 2 bytes and its 16-bit result is stored in R1 (MSB) and R0 (LSB)

Button controlling an Led

The purpose of this section is to provide the fundamentals to control an LED using a button. This objective will be achieved through the analysis of the programs button.ino and button.S built using functions from the AVR Instruction Set Manual.

Table 3. Material list

Item

Quantidade

Plataforma Arduino

1

Cabo USB

1

Protoboard

1

Led

1

Resistor de 200 ohms

1

Resistor de 10K ohms

1

Botão

1

imagens/img16.png
imagens/img17.png
//------------------------------------
// C Code to control led using button
//------------------------------------
extern "C"{
  void start();
  void btnLED(byte);
}

void setup(){
  start();
}

void loop(){
  btnLED(2); delay(200);
}
;---------------
; Assembly Code
;---------------
#define __SFR_OFFSET 0x00
#include "avr/io.h"
;------------------------
.global start
.global btnLED
;------------------------
start:
    SBI   DDRB, 5             ;set PB5 (13) as output
    CBI   DDRD, 2             ;set PD2 (2) as input
    RET                       ;return to setup() function
;---------------------------------------------------------------------------
btnLED:
ledON:
    ;SBIC = Skip if Bit in Register is Cleared
    ;SBIS = Skip if Bit in Register is Set
    SBIC  PIND, 2             ;skip next statement if button not pressed
    RJMP  ledOFF              ;jump to ledOFF
    SBI   PORTB, 5            ;set D19 to high
    RJMP  ledON               ;return to label ledON
ledOFF:
    CBI   PORTB, 5            ;turn OFF LED if button is not pressed
    RET

Lecture 3

imagens/img19.png

Serial Communication

Program serial port to transmit/receive data using synchronous or assynchronous modes (USART).

USART Registers

imagens/img20.png
  • UBRR

imagens/img21.png
  • UDR

imagens/img22.png
  • UCSRA

imagens/img23.png
  • UCSRB

imagens/img24.png
  • UCSRC

imagens/img25.png

Review about registers

imagens/img26.png

Write on Serial Port

The purpose of this section is to provide the fundamentals to send mensage from Atmega328p to PC. This objective will be achieved through the analysis of the programs serial.ino and serial.S built using functions from the AVR Instruction Set Manual.

Table 4. Material list

Item

Quantidade

Plataforma Arduino

1

Cabo USB

1

//------------------------------------------------
// Programming Serial Port - Printing Text Message
//------------------------------------------------
extern "C"
{
  void init_serial();
  void print_msg();
}
//----------------------------------------------------
void setup()
{
  init_serial();
}
//----------------------------------------------------
void loop()
{
  print_msg();
}
;------------------------
; Assembly Code
;------------------------
#define __SFR_OFFSET 0x00
#include "avr/io.h"
;------------------------
.global init_serial
.global print_msg
;------------------------
init_serial:
    CLR   R24
    STS   UCSR0A, R24               ;clear UCSR0A register
    STS   UBRR0H, R24               ;clear UBRR0H register
    LDI   R24, 103                  ;& store in UBRR0L 103 value
    STS   UBRR0L, R24               ;to set baud rate 9600
    LDI   R24, 1<<RXEN0 | 1<<TXEN0  ;enable RXB & TXB
    STS   UCSR0B, R24
    LDI   R24, 1<<UCSZ00 | 1<<UCSZ01;asynch, no parity, 1 stop, 8 bits
    STS   UCSR0C, R24
    RET
;-------------------------------------------------------------------------
print_msg:
    LDI   R30, lo8(message)
    LDI   R31, hi8(message)         ;Z points to string message
agn:LPM   R18, Z+                   ;load char of string onto R18
    CPI   R18, 0                    ;check if R18=0 (end of string)
    BREQ  ext                       ;if yes, exit
    ;--------------------------------------------------------------------
l1: LDS   R17, UCSR0A
    SBRS  R17, UDRE0                ;test data buffer if data can be sent
    RJMP  l1
    STS   UDR0, R18                 ;send char in R18 to serial monitor
    ;--------------------------------------------------------------------
    RJMP  agn                       ;loop back & get next character
    ;--------------------------------------------------------------------
ext:RCALL delay_sec
    RET
;------------------------------------------------------------------------
message:
    .ascii "Programming Serial Interface!" ;even number of characters!!!
    .byte 10,13,0   ;newline character, enter and null character
;------------------------------------------------------------------------
delay_sec:                          ;3s delay
    LDI   R20, 255
l4: LDI   R21, 255
l5: LDI   R22, 255
l6: DEC   R22
    BRNE  l6
    DEC   R21
    BRNE  l5
    DEC   R20
    BRNE  l4
    RET