Path: Home => AVR-overview => Assembler intro => Ports

Introduction to AVR assembler programming for beginners

What is a Port?

Ports in the AVR are gates from the central processing unit to internal and external hard- and software components. The CPU communicates with these components, reads from them or writes to them, e.g. to the timers or the parallel ports. The most used port is the flag register, where results of previous operations are written to and branch conditions are read from.

There are 64 different ports, which are not physically available in all different AVR types. Depending on the storage space and other internal hardware the different ports are either available and accessable or not. Which of these ports can be used is listed in the data sheets for the processor type.

Ports have a fixed address, over which the CPU communicates. The address is independent from the type of AVR. So e.g. the port adress of port B is always 0x18 (0x stands for hexadecimal notation). You don't have to remember these port adresses, they have convenient aliases. These names are defined in the include files (header files) for the different AVR types, that are provided from the producer. The include files have a line defining port B's address as follows:

.EQU PORTB, 0x18

So we just have to remember the name of port B, not its location in the I/O space of the chip. The include file 8515def.inc is involved by the assembler directive

.INCLUDE "C:\Somewhere\8515def.inc"

and the registers of the 8515 are all defined then and easily accessable.

Ports usually are organised as 8-bit numbers, but can also hold up to 8 single bits that don't have much to do with each other. If these single bits have a meaning they have their own name associated in the include file, e.g. to enable manipulation of a single bit. Due to that name convention you don't have to remember these bit positions. These names are defined in the data sheets and are given in the include file, too. They are provided here in the port tables.

As an example the MCU General Control Register, called MCUCR, consists of a number of single control bits that control the general property of the chip (see the description in MCUCR in detail). It is a port, fully packed with 8 control bits with their own names (ISC00, ISC01, ...). Those who want to send their AVR to a deep sleep need to know from the data sheet how to set the respective bits. Like this:

.DEF MyPreferredRegister = R16
    LDI MyPreferredRegister, 0b00100000
    OUT MCUCR, MyPreferredRegister
    SLEEP


The Out command brings the content of my preferred register, a Sleep-Enable-Bit called SE, to the port MCUCR and sets the AVR immediately to sleep, if there is a SLEEP instruction executed. As all the other bits of MCUCR are also set by the above instructions and the Sleep Mode bit SM was set to zero, a mode called half-sleep will result: no further command execution will be performed but the chip still reacts to timer and other hardware interrupts. These external events interrupt the big sleep of the CPU if they feel they should notify the CPU.

Reading a port's content is in most cases possible using the IN command. The following sequence

.DEF MyPreferredRegister = R16
    IN MyPreferredRegister, MCUCR

reads the bits in port MCUCR to the register. As many ports have undefined and unused bits in certain ports, these bits always read back as zeros.

More often than reading all 8 bits of a port one must react to a certain status of a port. In that case we don't need to read the whole port and isolate the relevant bit. Certain commands provide an opportunity to execute commands depending on the level of a certain bit (see the JUMP section). Setting or clearing certain bits of a port is also possible without reading and writing the other bits in the port. The two commands are SBI (Set Bit I/o) and CBI (Clear Bit I/o). Execution is like this:

.EQU ActiveBit=0 ; The bit that is to be changed
    SBI PortB, ActiveBit ; The bit will be set to one
    CBI PortB, Activebit ; The bit will be cleared to zero

These two instructions have a limitation: only ports with an adress smaller than 0x20 can be handled, ports above cannot be accessed that way.

For the more exotic programmer: the ports can be accessed using SRAM access commands, e.g. ST and LD. Just add 0x20 to the port's adress (the first 32 addresses are the registers!) and access the port that way. Like demonstrated here:

.DEF MyPreferredRegister = R16
    LDI ZH,HIGH(PORTB+32)
    LDI ZL,LOW(PORTB+32)
    LD MyPreferredRegister,Z


That only makes sense in certain cases, but it is possible. It is the reason why the first address location of the SRAM is always 0x60.

To the top of that page

Details of relevant ports in the AVR

The following table holds the most used ports. Not all ports are listed here, some of the MEGA and AT90S4434/8535 types are skipped. If in doubt see the original reference. Ports:
ComponentLinkRegisterLink
AccumulatorSREG Status RegisterSREG
StackSPL/SPH StackpointerSPL/SPH
Ext.SRAM/
Ext.Interrupt
MCUCR MCU General Control RegisterMCUCR
Ext.Int.INT Interrupt Mask RegisterGIMSK
Flag RegisterGIFR
Timer InterruptsTimer Int. Timer Int Mask RegisterTIMSK
Timer Interrupt Flag RegisterTIFR
Timer 0Timer 0 Timer/Counter 0 Control RegisterTCCR0
Timer/Counter 0TCNT0
Timer 1Timer 1 Timer/Counter Control Register 1 ATCCR1A
Timer/Counter Control Register 1 BTCCR1B
Timer/Counter 1TCNT1
Output Compare Register 1 AOCR1A
Output Compare Register 1 BOCR1B
Input Capture RegisterICR1L/H
Watchdog TimerWDT Watchdog Timer Control RegisterWDTCR
EEPROMEEPROM EEPROM Adress RegisterEEAR
EEPROM Data RegisterEEDR
EEPROM Control RegisterEECR
SPISPI Serial Peripheral Control RegisterSPCR
Serial Peripheral Status RegisterSPSR
Serial Peripheral Data RegisterSPDR
UARTUART UART Data RegisterUDR
UART Status RegisterUSR
UART Control RegisterUCR
UART Baud Rate RegisterUBRR
Analog ComparatorANALOG Analog Comparator Control and Status RegisterACSR
I/O-PortsIO-Ports   


To the top of that page

The status register as the most used port

By far the mostly used port is the status register with its 8 bits. Usually access to this port is only by automatic setting and clearing bits by the CPU or accumulator, some access is by reading or branching on certain bits in that port, in a few cases it is possible to manipulate these bits directly (using the assembler command SEx or CLx, where x is the bit abbreviation). Most of these bits are set or cleared by the accumulator through bit-test, compare- or calculation-operations. The following list has all assembler commands that set or clear status bits depending on the result of the execution.
BitCalculationLogicCompareBitsShift Others
ZADD, ADC, ADIW, DEC, INC, SUB, SUBI, SBC, SBCI, SBIW AND, ANDI, OR, ORI, EOR, COM, NEG, SBR, CBR CP, CPC, CPI BCLR Z, BSET Z, CLZ, SEZ, TST ASR, LSL, LSR, ROL, ROR CLR
CADD, ADC, ADIW, SUB, SUBI, SBC, SBCI, SBIW COM, NEG CP, CPC, CPI BCLR C, BSET C, CLC, SEC ASR, LSL, LSR, ROL, ROR -
NADD, ADC, ADIW, DEC, INC, SUB, SUBI, SBC, SBCI, SBIW AND, ANDI, OR, ORI, EOR, COM, NEG, SBR, CBR CP, CPC, CPI BCLR N, BSET N, CLN, SEN, TST ASR, LSL, LSR, ROL, ROR CLR
VADD, ADC, ADIW, DEC, INC, SUB, SUBI, SBC, SBCI, SBIW AND, ANDI, OR, ORI, EOR, COM, NEG, SBR, CBR CP, CPC, CPI BCLR V, BSET V, CLV, SEV, TST ASR, LSL, LSR, ROL, ROR CLR
SSBIW - - BCLR S, BSET S, CLS, SES - -
HADD, ADC, SUB, SUBI, SBC, SBCI NEG CP, CPC, CPI BCLR H, BSET H, CLH, SEH - -
T- - - BCLR T, BSET T, BST, CLT, SET - -
I- - - BCLR I, BSET I, CLI, SEI - RETI


To the top of that page

©2002 by http://www.avr-asm-tutorial.net