; *************************************************************************** ; defines .equ COM_MAXWAIT = 200 ; maximum loop count when waiting for rising/falling clock (TODO: Make frequency-dependant) .equ COM_BUFFER_FLAGS_DONE = 0x80 .equ COM_BUFFER_FLAGS_RECEIVED = 0x40 .equ COM_BUFFER_FLAGS_TOSEND = 0x20 .equ COM_BUFFER_FLAGS_RELEASED = 0x10 .equ COM_BUFFER_FLAGS_PRIO1 = 0x08 .equ COM_BUFFER_FLAGS_PRIO0 = 0x04 .equ COM_BUFFER_FLAGS_IFACE1 = 0x02 .equ COM_BUFFER_FLAGS_IFACE0 = 0x01 .equ COM_BUFFER_PRIO_INFO = 0 .equ COM_BUFFER_PRIO_NORMAL = COM_BUFFER_FLAGS_PRIO0 .equ COM_BUFFER_PRIO_IMPORTANT = COM_BUFFER_FLAGS_PRIO1 .equ COM_BUFFER_PRIO_VITAL = (COM_BUFFER_FLAGS_PRIO0 | COM_BUFFER_FLAGS_PRIO1) .equ COM_REPEAT_INFO = 3 .equ COM_REPEAT_NORMAL = 32 .equ COM_REPEAT_IMPORTANT = 64 .equ COM_REPEAT_VITAL = 255 .equ COM_BUFFER_NUM = 4 .equ COM_BUFFER_SIZE = 16 ; CAVE: Need to change routine COM_BufferPosToY when changing this value!! .equ COM_BUFFER_OFFS_FLAGS = 0 ; first byte in buffer is flags byte .equ COM_BUFFER_OFFS_DATA = 1 .equ COM_MSG_OFFS_DESTADDR = 0 .equ COM_MSG_OFFS_MSGLEN = 1 .equ COM_MSG_OFFS_MSGDATA = 2 .equ COM_CMD_PING = 1 .equ COM_CMD_COMSENDSTATS = 2 .equ COM_CMD_COMRECVSTATS = 3 .equ COM_CMD_I2CBUSMEMBER = 4 .equ COM_CMD_DEBUG = 5 .equ COM_CMD_VALUE = 6 .equ COM_ERR_NOTFORME = 1 .equ COM_ERR_CHECKSUM = 2 .equ COM_ERR_IO = 3 ; *************************************************************************** ; data .dseg comDataBegin: comFlags: .byte 1 comAddress: .byte 1 comRepeatCount: .byte 1 comReserved1: .byte 1 comStatsPacketsIn: .byte 2 comStatsPacketsOut: .byte 2 comStatsRecvErrs: .byte 2 comStatsCollisions: .byte 2 comStatsMissed: .byte 2 comStatsAborted: .byte 2 comStatsIgnored: .byte 2 comStatsHandled: .byte 2 comRecvBuffersReadPos: .byte 1 comRecvBuffersWritePos: .byte 1 comRecvBuffersUsed: .byte 1 comRecvBuffers: .byte (COM_BUFFER_SIZE*COM_BUFFER_NUM) comDataEnd: ; *************************************************************************** ; code .cseg comIsrPcint0: push r15 in r15, SREG sbic COM_PIN_ATTN, COM_PINNUM_ATTN rjmp comIsrPcint0_end ; low, read packet push r1 push r16 push r17 push r18 push r19 push r20 push r21 push r22 push xh push xl push yh push yl rcall comReceivePacketHandleBuffer ; (R1, R16, R17, R18, R19, R20, R21, R22, X, Y pop yl pop yh pop xl pop xh pop r22 pop r21 pop r20 pop r19 pop r18 pop r17 pop r16 pop r1 comIsrPcint0_end: pop r15 reti ; --------------------------------------------------------------------------- ; Com_Init ; ; IN: ; OUT: ; - CFLAG: set if okay, clear on error ; USED: R16, R17, X, Y Com_Init: ; preset SRAM data area ldi xh, HIGH(comDataBegin) ldi xl, LOW(comDataBegin) clr r16 ldi r17, (comDataEnd-comDataBegin) rcall Utils_FillSram ldi r16, 1 ; debug: set fixed address "1" sts comAddress, r16 ; setup pins and interrupts cbi COM_PORT_DATA, COM_PINNUM_DATA ; disable internal pullup for DATA cbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; disable internal pullup for ATTN cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN port as input sbi COM_IRQ_ADDR_ATTN, COM_IRQ_BIT_ATTN ; enable pin change irq for ATTN line in r16, GIMSK ; enable pin change irq PCIE0 or PCIE1 ori r16, (1< CARRY brcs comSendByte_setHigh ; HI: +2, LO: +1 comSendByte_setLow: sbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as output nop rjmp comSendByte_waitBit ; +2 comSendByte_setHigh: cbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as input, pullup R makes it ONE nop ; +1 (to make pin change available) sbis COM_PIN_DATA, COM_PINNUM_DATA ; +1 if okay, +2 otherwise rjmp comSendByte_error ; +2 if error comSendByte_waitBit: ; 7 cycles in this loop until now Utils_WaitNanoSecs COM_BIT_LENGTH, 10, r22 dec r21 ; +1 brne comSendByte_loop ; +2, sum per loop: 10 cycles ; send stopbit cbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as input, pullup R makes it ONE Utils_WaitNanoSecs COM_BIT_LENGTH, 4, r22 sec ret comSendByte_error: clc ret ; --------------------------------------------------------------------------- ; comReceiveByte ; ; Receive a byte. ; ; IN: ; - nothing ; OUT: ; - CFLAG: set if okay, clear otherwise ; - R16: byte read (if CFLAG set) ; MODIFIED REGS: R16, R20, R21, R22 (R17) comReceiveByte: cbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input cbi COM_PORT_DATA, COM_PINNUM_DATA ; disable internal pullup for DATA ldi r21, 8 ; bits left clr r20 ; byte currently receiving ; wait for startbit rcall comWaitForDataLow ; (R17) brcc comReceiveByte_error Utils_WaitNanoSecs COM_BIT_LENGTH/2, 5, r22 ; goto middle of startbit to maximize sync stability comReceiveByte_loop: Utils_WaitNanoSecs COM_BIT_LENGTH, 8, r22 ; 8 cycles used in the complete loop between waits sec ; +1 sbic COM_PIN_DATA, COM_PINNUM_DATA ; LOW: +2, HIGH: +1 rjmp comReceiveByte_shiftIn ; HIGH: +2, rjmp, use set CFLAG clc ; LOW: +1 comReceiveByte_shiftIn: ror r20 ; +1 dec r21 ; +1 brne comReceiveByte_loop ; +2, sum per loop: 8 cycles rcall comWaitForDataHigh ; wait for start of stopbit brcc comReceiveByte_error mov r16, r20 sec ret comReceiveByte_error: clc ret ; --------------------------------------------------------------------------- ; comWaitForDataLow ; ; Waits up to COM_MAXWAIT loops for low data line ; IN: ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGISTERS: r17, r22 comWaitForDataLow: ldi r17, COM_MAXWAIT comWaitForDataLow_loop: sbis COM_PIN_DATA, COM_PINNUM_DATA rjmp comWaitForDataLow_done Utils_WaitNanoSecs 100, 0, r22 ; wait for 100 nanosecs dec r17 brne comWaitForDataLow_loop clc ; timeout ret comWaitForDataLow_done: sec ; ok ret ; --------------------------------------------------------------------------- ; comWaitForDataHigh ; ; Waits up to COM_MAXWAIT loops for high data line ; IN: ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGISTERS: r17, r22, X comWaitForDataHigh: ldi r17, COM_MAXWAIT comWaitForDataHigh_loop: sbic COM_PIN_DATA, COM_PINNUM_DATA rjmp comWaitForDataHigh_done Utils_WaitNanoSecs 100, 0, r22 ; wait for 100 nanosecs dec r17 brne comWaitForDataHigh_loop clc ; timeout ret comWaitForDataHigh_done: sec ; ok ret ; --------------------------------------------------------------------------- ; comWaitForAttnHigh ; ; Waits up to COM_MAXWAIT loops for high ATTN line ; IN: ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGISTERS: r17, r22, X comWaitForAttnHigh: ldi r17, COM_MAXWAIT comWaitForAttnHigh_loop: sbic COM_PIN_ATTN, COM_PINNUM_ATTN rjmp comWaitForAttnHigh_done Utils_WaitNanoSecs 100, 0, r22 ; wait for 100 nanosecs dec r17 brne comWaitForAttnHigh_loop clc ; timeout ret comWaitForAttnHigh_done: sec ; ok ret ; *************************************************************************** ; buffer functions ; --------------------------------------------------------------------------- ; COM_BufferAlloc ; ; Allocate a transfer buffer. ; IN: ; - nothing ; OUT: ; - CFLAG: set if okay, clear otherwise ; - Y: pointer to allocated buffer in SRAM ; MODIFIED REGISTERS: r16, r17, r21 COM_BufferAlloc: in r21, SREG ; save global interrupt enable bit from SREG cli lds r17, comRecvBuffersUsed cpi r17, COM_BUFFER_NUM brcc COM_AllocBuffer_error ; no buffer available inc r17 ; increment number of buffers used sts comRecvBuffersUsed, r17 ; store new value lds r16, comRecvBuffersWritePos ; get current write pos mov r17, r16 ; increment for next call inc r17 cpi r17, COM_BUFFER_NUM ; CF set if COM_BUFFER_NUM > R17 brcs COM_AllocBuffer_l1 clr r17 ; wraparound COM_AllocBuffer_l1: sts comRecvBuffersWritePos, r17 ; store new writepos for next caller rcall COM_BufferPosToY ; (R16, R17) clr r17 std y+COM_BUFFER_OFFS_FLAGS, r17 ; preset flags out SREG, r21 ; restore global interrupt enable bit in SREG sec ret COM_AllocBuffer_error: out SREG, r21 clc ret ; --------------------------------------------------------------------------- ; COM_BufferDeallocBack ; ; Release a transfer buffer at the end of the list by decreasing the write pos. ; This releases the last allocated buffer! ; ; IN: ; - nothing ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGISTERS: r16, r17, r21 COM_BufferDeallocBack: in r21, SREG ; save global interrupt enable bit from SREG cli lds r17, comRecvBuffersUsed tst r17 breq COM_BufferDeallocBack_error ; no buffer allocated, nothing to release dec r17 sts comRecvBuffersUsed, r17 ; store new value lds r17, comRecvBuffersWritePos tst r17 ; 0? brne COM_BufferDeallocBack_l1 ; nope go directly decrement r17 ldi r17, COM_BUFFER_NUM ; wrap-around COM_BufferDeallocBack_l1: dec r17 sts comRecvBuffersWritePos, r17 out SREG, r21 sec ret COM_BufferDeallocBack_error: out SREG, r21 clc ret ; --------------------------------------------------------------------------- ; COM_BufferDeallocFront ; ; Release a transfer buffer by increasing the read pos. ; ; IN: ; - nothing ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGISTERS: r16, r17, r21 COM_BufferDeallocFront: in r21, SREG ; save global interrupt enable bit from SREG cli lds r17, comRecvBuffersUsed tst r17 breq COM_BufferDeallocFront_error ; no buffer allocated, nothing to release dec r17 sts comRecvBuffersUsed, r17 ; store new value lds r17, comRecvBuffersReadPos inc r17 cpi r17, COM_BUFFER_NUM brcs COM_BufferDeallocFront_l1 clr r17 ; wrap-around COM_BufferDeallocFront_l1: sts comRecvBuffersReadPos, r17 out SREG, r21 sec ret COM_BufferDeallocFront_error: out SREG, r21 clc ret ; --------------------------------------------------------------------------- ; COM_BufferPosToY ; ; Get a pointer to the SRAM position of the given buffer. ; CAVE: Code must correspond to COM_BUFFER_SIZE!! ; IN: ; - R16: buffer number (starting with 0) ; OUT: ; - Y: pointer to buffer in SRAM ; MODIFIED REGISTERS: R16, R17 COM_BufferPosToY: ; calculate offset clr r17 mov yl, r16 clr yh lsl yl rol yh ; *2 lsl yl rol yh ; *4 lsl yl rol yh ; *8 lsl yl rol yh ; *16 ; add base position of buffers ldi r16, LOW(comRecvBuffers) ldi r17, HIGH(comRecvBuffers) add yl, r16 adc yh, r17 ret