Assignment
- Modify an existing PCB board design to include a button
- Read the AT44 data sheet
- Modify an assembly language program to have the button do something
- Modify a C program to have the button do something
How to do this on a Mac running OSX 10.5.8 (Leopard) and using USB->serial cables (dasa) to program the AVR:
If you are using an intel mac running leopard (NOT snow leopard), you might find it handy to have the assembler to compile assembly language so you don't have to use windows/bootcamp. We found this hard to find, so we have made our own assembler by downloading pascal and compiling the source code of the assembler found here:
Here is the compiled assembler that you should just be able to use:
To modify the board, it seemed easiest to do this directly in cad.py by editing the drawing code in the "define board" section like this:
#
# define board
#
width = 1.1
height = 1.02
x = 1
y = 1
z = -.005
w = .016
mask = .004
pcb = PCB(x,y,width,height,mask)
IC1 = ATtiny44_SOICN('IC1\nt44')
pcb = IC1.add(pcb,x+.54,y+.6,z)
J1 = header_ICP('J1')
pcb = J1.add(pcb,IC1.x+.05,IC1.pad[7].y-.24,z,angle=0)
button= button_6mm('B1')
pcb=button.add(pcb,IC1.pad[14].x+.22,IC1.pad[14].y-.09,z,angle=0)
pcb= wire(pcb,w,
IC1.pad[14],
button.pad[1])
pcb= wire(pcb,w,
IC1.pad[12],
button.pad[2])
I chose to fab my board on the vinyl cutter, and the resulting board looked like this:
To modify the assembly language code to talk to/from the button, you must define some terms (using .equ), then initialize the button (using the sbi and cbi commands), then insert a couple lines of code that skip the next command under certain circumstances (the sbis command).
Here is the modified assembler code that simply checks whether the button is pushed and outputs the state of the bit (nothing fancy):
;
; hello.echo.44.asm
;
; 115200 baud serial echo and LED hello-world program
;
; Neil Gershenfeld
; CBA MIT 10/12/09
;
; (c) Massachusetts Institute of Technology 2009
; Permission granted for experimental and personal use;
; license for commercial sale available from MIT.
;
.include "tn44def.inc"
.equ led_pin = PB2; LED pin
.equ led_port = PORTB; LED port
.equ led_dir = DDRB; LED dir
.equ txpin = PA6; transmit pin
.equ rxpin = PA7; receive pin
.equ comm_port = PORTA; comm port
.equ comm_dir = DDRA; comm direction
.equ comm_pins = PINA; comm pins
.equ button_pin=PA1; button receive pin
.equ button_port = PORTA; buttons port
.equ button_dir= DDRA; button direction
.equ button_pins = PINA; button pins
.def bitcnt = R16; bit counter
.def temp = R17; temporary storage
.def temp1 = R18; temporary storage
.def txbyte = R19; transmit byte
.def rxbyte = R20; receive byte
;
; print
;
.macro print
ldi zl,low(@0*2)
ldi zh,high(@0*2)
rcall print_db
.endmacro
.cseg
.org 0
rjmp reset
;
; half_bit_delay
; serial half bit delay
;
half_bit_delay:
ldi temp, 25; 115200 baud (20 MHz clock /1)
half_bit_delay_loop:
dec temp
brne half_bit_delay_loop
ret
;
; putchar
; assumes no line driver (doesn't invert bits)
;
putchar:
ldi bitcnt, 10; 1 start + 8 data + 1 stop bit
com txbyte; invert everything
sec; set start bit
putchar0:
brcc putchar1; if carry set
sbi comm_port, txpin; send a '0'
rjmp putchar2; else
putchar1:
cbi comm_port, txpin ; send a '1'
nop; even out timing
putchar2:
rcall half_bit_delay; bit delay
rcall half_bit_delay; "
lsr txbyte; get next bit
dec bitcnt; if not all bits sent
brne putchar0; send next bit
ret;
;
; getchar
; assumes no line driver (doesn't invert bits)
;
getchar:
ldi bitcnt, 9; 8 data + 1 stop bit
getchar1:
sbis comm_pins, rxpin; wait for start bit
rjmp getchar1
rcall half_bit_delay; delay to middle of bit
getchar2:
rcall half_bit_delay; bit delay
rcall half_bit_delay; "
clc; clear carry
sbis comm_pins, rxpin; if RX pin high skip
sec; otherwise set carry
dec bitcnt
breq getchar3; return if all bits read
ror rxbyte; otherwise shift bit into receive byte
rjmp getchar2; go get next bit
getchar3:
ret
;
; blink_delay
; LED blink delay
;
blink_delay:
ldi temp, 255
blink_delay_loop:
ldi temp1, 255
blink_delay_loop1:
dec temp1
brne blink_delay_loop1
dec temp
brne blink_delay_loop
ret
;
; blink
; blink the LED
;
blink:
sbi led_port, led_pin
rcall blink_delay
cbi led_port, led_pin
ret
;
; print_db
; prints a null-terminated .db string
;
print_db:
print_loop:
lpm
mov txbyte,R0
cpi txbyte,0
breq return
rcall putchar
adiw zl, 1
rjmp print_loop
return:
ret
;
; main program
;
reset:
;
; set fuse low byte to 0x7E for 20 MHz resonator
;
; set clock divider to /1
;
ldi temp, (1 << CLKPCE)
ldi temp1, (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0)
out CLKPR, temp
out CLKPR, temp1
;
; set stack pointer to top of RAM
;
ldi temp, high(RAMEND)
out SPH, temp
ldi temp, low(RAMEND)
out SPL, temp
;
; init comm pin
;
sbi comm_port, txpin
sbi comm_dir, txpin
;
; init LED pins
;
cbi led_port, led_pin
sbi led_dir, led_pin
;
; init button pins
;
sbi button_port, button_pin
cbi button_dir, button_pin
;
; start main loop
;
loop:
rcall getchar
print message
message: .db "received character: ",0
mov txbyte, rxbyte
rcall putchar
ldi txbyte,49
sbis button_pins, button_pin
ldi txbyte,48
rcall putchar
ldi txbyte,10
rcall putchar
rcall blink
rjmp loop
Once this code is modified, you must then reassemble it using whatever assembler you can. If you're running an intel mac, you can either use bootcamp or parallels and do this in windows using one of the compilers listed on the class webpage, or you can use the process I describe above to assemble it on the mac. I did the latter, and issued the following command:
gavrasm hello.echo.44.asm
This assembles the program and creates a hex file that can be sent to the AT44.
Programming the AT44
Now, you can hook up your cables in the same configuration as the hello world board. TAKE GREAT CARE TO PUT YOUR HEADERS ON CORRECTLY OR YOU COULD FRY PART OR ALL OF YOUR BOARD! The 6-pin programming header should be exactly like the last assignment, and the 4-pin communications header is rotated 90 degrees - with no modifications to the one given to us in class, this meant that my two cables came out parallel to each other on one side of the board:
Hook up the one of the USB->serial cables to the computer. Open a terminal and find out what port it's on. Modify Neil's avrdude command from the first week - make sure you include the right port and AT44 instead of AT45 and the real name of your hex file.