4
\$\begingroup\$

One thing I do not understand in reading about doing Assembly with the Atmel AVR (or perhaps with Arduino platform) is the actual outputting to devices (like LEDS/motors) and such. Most Assembly "tutorials" simply explain counting/numeric stuff with registers.

Can anyone explain how exactly you send an out signal to a motor or LED under AVR assembly?

I guess I dont exactly get what each "pin" does for the microcontroller, and which ones can send output signals. (to turn a motor or led)

asked Feb 28, 2011 at 19:52
\$\endgroup\$

3 Answers 3

6
\$\begingroup\$

The AVR, like most microcontrollers, uses memory-mapped IO. In a nutshell, this means that a part of the memory space of the microcontroller is reserved for the peripherals. When you change a bit in this area of memory, you're not sending a signal to change a bit of memory, you're sending a signal to change the value of a peripheral.

To understand the details of how this works on your AVR, the Special Function Registers section of AVR-libc (and, more importantly, sfr_defs.h and iom328p.h) are recommended reading.

[Warning: Technical writing ahead, pay close attention] For example, PORTB is defined as _SFR_IO8(0x05) in iom328p.h. In sfr_defs.h, _SFR_IO8(io_addr) is defined as _MMIO_BYTE((io_addr) + __SFR_OFFSET). __SFR_OFFSET is 0x20, the location just after the registers. The space after this address and before RAMSTART (0x100) is used for the peripherals. Going back to our example, _MMIO_BYTE(mem_addr) is defined as (*(volatile uint8_t *)(mem_addr)). Therefore, when you write PORTB, you're really writing *(volatile uint8_t *)(0x25), which defines a byte-wide pointer to the location in memory 0x25. [/Warning]

So, when (in C) you write PORTB |= 0x01, you're really writing the value 1 to the peripheral at byte 0x25, or port B pin 0. If this pin is configured as output (using DDRB, which is at 0x24), PORTB |= 0x01 will cause port B pin 0 to go high. Phew!

So, if you use the assembly instructions (SBI - Set Bit in I/O Register):

sbi 0x24,1 ;Data direction set to output
sbi 0x25,1 ;Set port B pin 0 high

You'll set the pin high.

Of course, use inline assembler with GCC and #include <avr/io.h> to get the conventional names and simplify your task.

Note that all of the peripherals use this scheme, not just the IO pins. Read iom328p.h if you're interested in the locations of other peripherals.

answered Feb 28, 2011 at 21:08
\$\endgroup\$
0
1
\$\begingroup\$

Something like this:

 #define LED PB3
 sbi DDRB,LED ;PB3 output (LED)
loop:
 sbi PORTB,LED ;LED on
 rcall dly
 cbi PORTB,LED ;LED off
 rcall dly
 rjmp loop

I've left out a lot of other stuff that is needed for a working program.

answered Feb 28, 2011 at 20:13
\$\endgroup\$
0
\$\begingroup\$
.device ATmega168
.equ DDRB = 0x04
.equ PORTB = 0x05
.org 0x0000
 rjmp RESET
RESET:
 ldi R16,0x20
 out DDRB,R16
 ldi R18,0x00
 ldi R17,0x00
 ldi R20,0x20
Loop:
 ldi R19,0xE8
aloop:
 inc R17
 cpi R17,0x00
 brne aloop
 inc R18
 cpi R18,0x00
 brne aloop
 inc R19
 cpi R19,0x00
 brne aloop
 eor R16,R20
 out PORTB, R16
 rjmp Loop
answered Apr 9, 2011 at 1:51
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.