;SIC PROJECT 056 LOW-COST PCB MILLING MACHINE ;INITIAL VERSION FOR MIT COURSE 2 BACHELOR'S THESIS "Rapid Prototyping of Rapid Prototyping Machines" SUPERVISED BY NEIL GERSHENFELD, DIRECTOR, MIT CBA ;--REVISION HISTORY----------------------------------------------------------------------- ; ; --------------------------------------------------------------------------------- ; | DATE | MODIFICATIONS | NAME |FILENAME | ; |--------|---------------------------|-------------------|-----------------------| ; |03/09/08| CREATED |ILAN E MOYER |i0.smc.03.asm | ; |--------|---------------------------|-------------------|-----------------------| ; |12/31/08| SPIFFIFIED |ILAN E MOYER |056-054.asm | ; |--------|---------------------------|-------------------|-----------------------| ; |3/20/09 | ADDED HALF-STEPPING |ILAN E MOYER |056-054b.asm | I changed the format of motorpositions to allow 8 half-positions ; |--------|---------------------------|-------------------|-----------------------| ; |3/20/09 | FIXED SINGLE-STEP ISSUE |ILAN E MOYER |056-054c.asm | ; |--------|---------------------------|-------------------|-----------------------| ; |11/29/09| MODIFIED FOR NETWORKING |ILAN E MOYER |056-054d.asm | ; |--------|---------------------------|-------------------|-----------------------| ; |12/08/09| ADDED VM URL RESPONSE |ILAN E MOYER |056-054e.asm | ; |--------|---------------------------|-------------------|-----------------------| ; |12/13/09| ADDED 3-AXIS MOTION |ILAN E MOYER |056-054f.asm | ; |--------|---------------------------|-------------------|-----------------------| ; |01/06/10| REFACTORED FOR FABINABOX |ILAN E MOYER |076-001a.asm | ; |--------|---------------------------|-------------------|-----------------------| ; |01/07/10| ADDED RX PULLUP, LEDS OFF |ILAN E MOYER |076-001a.asm | RX pullup is necessary to avoid tripping rcv watchdog. Also turned off ind leds after move. ; |--------|---------------------------|-------------------|-----------------------| ; |01/10/10| FIXED MOTION CODE |ILAN E MOYER |076-001b.asm | ; |--------|---------------------------|-------------------|-----------------------| ; |01/12/10| ADDED STATUS RESPONSE |ILAN E MOYER |076-001c.asm | Also fixed push/pop temp3 and temp4 in motion interrupt. ; |--------|---------------------------|-------------------|-----------------------| ; |01/15/10| CONVERTED TO H BRIDGE |ILAN E MOYER |076-004a.asm | ; |--------|---------------------------|-------------------|-----------------------| ; |04/26/10| CHANGED FABNET BAUD RATE |ILAN E MOYER |076-004b.asm | Changed to 38.4K to avoid issues with linux serial driver ; ---------------------------------------------------------------------------------- ; ; ; ;--HARDWARE CONFIGURATION (076-004 REV1)--------------------------------------------- ; ; ; ; ; ; ; ; ; ; T ; X ; ; E _ ; N R ; A E ; B T R S P P P P ; L X X E C C C C ; E D D T 5 4 3 2 ; --------------- ; LED| | PC1 ; BUTTON| | PC0 ; GND| | ADC7 ; VCC| ATMEGA88 | GND ; GND| | AREF ; VCC| | ADC6 ; XTAL1| | AVCC ; XTAL2| | SCK ; --------------- ; P M P S E P M M ; D O H L N B O I ; 5 D A E A 2 S S ; E S E B I O ; E P L ; E ; / ; O ; C ; 1 ; A ; ; ; ;--PORT B ASSIGNMENTS-------------------------------------------------------------- ; ; PB0 = H BRIDGE SLEEP ; PB1 = H BRIDGE ENABLE ; PB2 = PB2 ; PB3 = MOSI ; PB4 = MISO ; PB5 = SCK ; PB6 = XTAL1 ; PB7 = XTAL2 ; ;--PORT C ASSIGNMENTS-------------------------------------------------------------- ; ; PC0 = Z AXIS INDICATOR LED ; PC1 = Y AXIS INDICATOR LED ; PC2 = X AXIS INDICATOR LED ; PC3 = N/C ; PC4 = N/C ; PC5 = N/C ; PC6 = /RESET ;--PORT D ASSIGNMENTS-------------------------------------------------------------- ; PD0 = RXD ; PD1 = TXD ; PD2 = RS485 TX ENABLE ; PD3 = LED ; PD4 = BUTTON ; PD5 = PD5 ; PD6 = H BRIDGE MODE ; PD7 = H BRIDGE PHASE ;--INCLUDE FILES------------------------------------------------------------------- ; .DEVICE ATMega88 .include "m88def.inc" ;--DEFINITIONS--------------------------------------------------------------------- ;PORT DIRECTION MASKS ;PACKET LOCATIONS .equ rx_packet_location = 0x0100 ;SRAM start location for rx packet .equ tx_packet_location = 0x0200 ;SRAM start location for tx packet ;PAcKET OFFSETS .equ packet_startbyte = 0 .equ packet_srcaddress0 = 1 .equ packet_srcaddress1 = 2 .equ packet_srcport = 3 .equ packet_destaddress0 = 4 .equ packet_destaddress1 = 5 .equ packet_destport = 6 .equ packet_length = 7 .equ packet_payload = 8 ;PACKET STANDARD VALUES .equ packet_unicast_startbyte = 74 .equ packet_broadcast_startbyte = 138 ;NODE OFFSETS .equ node_address_location = 0x0300 ;SRAM start location for node address ;H-BRIDGE OFFSETS .equ packet_duty_cycle = 0 .equ packet_direction = 1 ;NODE VALUES .equ node_address0 = 165 .equ node_address1 = 134 ;RECEIVER WATCHDOG CONSTANTS .equ watchdog_trip = 253 ;PORTS: UI .equ button_input = PIND .equ led_output = PORTD .equ led_toggle = PIND ;PORTS: COMM .equ comm_port = PORTD .equ comm_dir = DDRD ;PORTS: H-BRIDGE .equ h_mode_ddr = DDRD .equ h_mode_port = PORTD .equ h_phase_ddr = DDRD .equ h_phase_port = PORTD .equ h_sleep_ddr = DDRB .equ h_sleep_port = PORTB .equ h_enable_ddr = DDRB .equ h_enable_port = PORTB ;PINS: UI .equ button = PD4 .equ led = PD3 ;PINS: COMM .equ rx_pin = PD0 .equ tx_pin = PD1 .equ tx_enable = PD2 ;PINS: H-BRIDGE .equ h_mode = PD6 .equ h_phase = PD7 .equ h_sleep = PB0 .equ h_enable = PB1 ;DIRECTION MASKS .equ portb_directions = (1 << h_sleep)|(0 << h_enable) .equ portc_directions = 0 .equ portd_directions = (1 << tx_pin)|(1 << tx_enable)|(1 << led)|(1 << h_mode)|(1 << h_phase) ;PULLUP MASKS .equ portb_pullups = 0 .equ portc_pullups = 0 .equ portd_pullups = (1 << button)|(1 << rx_pin) ;REGISTERS .def numzero = r0 .def current_step_0 = r1 .def packetlength = r2 .def packetchecksum = r3 .def rcv_watchdog = r4 ; working registers .def temp1 = r16 .def temp2 = r17 .def temp3 = r18 .def temp4 = r19 .def duty_cycle = r20 .def packetposition = r21 ; FLAG REGISTERS .equ comm_status = GPIOR0 ;using general purpose IO register to conserve standard registers. .equ packet_received = 0 ;first bit of comm_status. .equ packet_inbound = 1 .equ packet_outbound = 2 .equ bridge_on = 3 ;indicates that H-Bridge is active ;SRAM .equ Memory_Start = 0x0060 ;--PROGRAM INITIALIZATION---------------------------------------------------------- .cseg .org 0 ;--INTERRUPT VECTOR TABLE---------------------------------------------------------- rjmp reset ; External Pin, Power-on Reset, Brown-out Reset and Watchdog System .dw 0 ; External Interrupt Request 0 .dw 0 ; External Interrupt Request 1 .dw 0 ; Pin Change Interrupt Request 0 .dw 0 ; Pin Change Interrupt Request 1 .dw 0 ; Pin Change Interrupt Request 2 .dw 0 ; Watchdog Time-out Interrupt .dw 0 ; Timer/Counter2 Compare Match A .dw 0 ; Timer/Counter2 Compare Match B rjmp isr_packet_timeout_100 ; Timer/Counter2 Overflow .dw 0 ; Timer/Counter1 Capture Event .dw 0 ; Timer/Counter1 Compare Match A .dw 0 ; Timer/Coutner1 Compare Match B .dw 0 ; Timer/Counter1 Overflow .dw 0 ; Timer/Counter0 Compare Match A .dw 0 ; Timer/Counter0 Compare Match B .dw 0 ; Timer/Counter0 Overflow .dw 0 ; SPI Serial Transfer Complete rjmp isr_packet_receiver_100 ; USART Rx Complete rjmp isr_packet_transmitter_100 ; USART, Data Register Empty rjmp isr_packet_transmitter_100 ; USART, Tx Complete .dw 0 ; ADC Conversion Complete .dw 0 ; EEPROM Ready .dw 0 ; Analog Comparator .dw 0 ; 2-wire Serial Interface .dw 0 ; Store Program Memory Ready ;--INTERRUPT ROUTINES-------------------------------------------------------------- ;-- PACKET RECEIVER -- ; ;This interrupt routine stores data from an incoming packet into SRAM ; isr_packet_receiver_100: cli push ZL push ZH push temp1 push temp2 in temp2, SREG push temp2 sts TCNT2, numzero ;clears timer0 mov rcv_watchdog, numzero ;resets watchdog counter ldi temp1, (0 << OCIE0B)|(0 << OCIE0A)|(1 << TOIE0) ;enables timer2 as watchdog for receiver sts TIMSK2, TEMP1 isr_packet_receiver_200: ;load byte into temp1, and store in SRAM lds temp1, UDR0 ldi ZH, high(rx_packet_location) ldi ZL, low(rx_packet_location) add ZL, packetposition adc ZH, numzero st Z, temp1 sbi comm_status, packet_inbound ;sets packet inbound flag isr_packet_receiver_300: ;check for packet length cpi packetposition, packet_length ;see if this byte contains the packet length brne isr_packet_receiver_400 mov packetlength, temp1 ;if YES, store the packet length in packetlength register isr_packet_receiver_400: ;checks for end-of-packet condition cpi packetposition, packet_length brlo isr_packet_receiver_500 ;checks if the packet length byte has been read yet. If YES, checks for end-of-packet cp packetposition, packetlength breq isr_packet_receiver_600 ;if this is end_of_packet, skips the checksum isr_packet_receiver_500: ;calculates the CRC of the packet mov temp3, temp1 eor temp1, packetchecksum ; IN PYTHON: crc = input^crc ldi ZH, high(crc_table*2) ;loads CRC table location into Z pointer ldi ZL, low(crc_table*2) add ZL, temp1 ;offsets Z pointer by value of temp1 adc ZH, numzero lpm packetchecksum, Z ;stores new checksum in packetchecksum inc packetposition rjmp isr_packet_receiver_exit isr_packet_receiver_600: ;check if packet is for us mov temp3, temp1 ;stores a copy of the received byte in temp3 ldi ZH, high(rx_packet_location+packet_startbyte) ;loads packet start byte into temp1 ldi ZL, low(rx_packet_location+packet_startbyte) ld temp1, Z cpi temp1, packet_broadcast_startbyte breq isr_packet_receiver_700 ;broadcast packet, skips address check. cpi temp1, packet_unicast_startbyte brne isr_packet_receiver_900 ;packet bad! ldi ZH, high(rx_packet_location+packet_destaddress0) ;load destination address byte 0 into temp1 ldi ZL, low(rx_packet_location+packet_destaddress0) ld temp1, Z ldi ZH, high(node_address_location) ;load node address byte 0 into temp2 ldi ZL, low(node_address_location) ld temp2, Z cp temp1, temp2 brne isr_packet_receiver_900 ;packet not destined for us! ldi ZH, high(rx_packet_location+packet_destaddress1) ;load destination address byte 0 into temp1 ldi ZL, low(rx_packet_location+packet_destaddress1) ld temp1, Z ldi ZH, high(node_address_location+1) ;load node address byte 0 into temp2 ldi ZL, low(node_address_location+1) ld temp2, Z cp temp1, temp2 brne isr_packet_receiver_900 ;packet not destined for us! isr_packet_receiver_700: ;check packet checksum cp temp3, packetchecksum ;see if checksum matches last byte brne isr_packet_receiver_900 ;checksum bad. For now, ditch packet. Later, this could dispatch a resend-request. isr_packet_receiver_800: ;packet is good, and destined for US! ldi temp1, (0 << OCIE0B)|(0 << OCIE0A)|(0 << TOIE0) ;disables timer0 interrupts sts TIMSK2, TEMP1 sbi comm_status, packet_received ;sets packet waiting flag clr packetposition clr packetchecksum cbi comm_status, packet_inbound ;clears packet inbound flag cbi comm_status, packet_outbound rjmp isr_packet_receiver_exit isr_packet_receiver_900: ;packet either not for us, or checksum is bad. Packet is tossed. ; sts UDR0, numzero ;REMOVE clr packetposition clr packetchecksum cbi comm_status, packet_inbound ;sets packet inbound flag ldi temp1, (0 << OCIE0B)|(0 << OCIE0A)|(0 << TOIE0) ;disables timer2 interrupts sts TIMSK2, TEMP1 isr_packet_receiver_exit: pop temp2 out SREG, temp2 pop temp2 pop temp1 pop ZH pop ZL sei reti ;-- PACKET TRANSMITTER -- ; ; This interrupt routine transmits bytes of a packet whenever they become avaliable. ; isr_packet_transmitter_100: cli push ZL push ZH push temp1 push temp2 in temp2, SREG push temp2 ldi temp1, (1<