diff --git a/avr/com.asm b/avr/com.asm index 8bd602b..3e73342 100644 --- a/avr/com.asm +++ b/avr/com.asm @@ -10,6 +10,7 @@ .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 @@ -25,6 +26,17 @@ .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 @@ -35,19 +47,25 @@ 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 - comRingBuffer: .byte RINGBUFFER_OFFS_DATA+COM_RINGBUFFER_SIZE + 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: @@ -58,6 +76,39 @@ comDataEnd: .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 r20 + push r21 + push r22 + push xh + push xl + push yh + push yl + rcall comReceivePacketHandleBuffer ; (R1, R16, R17, R20, R21, R22, X, Y) + pop yl + pop yh + pop xl + pop xh + pop r22 + pop r21 + pop r20 + pop r17 + pop r16 + pop r1 + +comIsrPcint0_end: + pop r15 + reti + + ; --------------------------------------------------------------------------- ; Com_Init @@ -75,18 +126,15 @@ Com_Init: ldi r17, (comDataEnd-comDataBegin) rcall Utils_FillSram - ; init ringbuffer - ldi r16, COM_RINGBUFFER_SIZE - ldi yl, LOW(comRingBuffer) - ldi yh, HIGH(comRingBuffer) - rcall RingBuffer_Init + 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 - sbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input + cbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; disable internal pullup for ATTN - sbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN port as input + 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 @@ -111,7 +159,7 @@ Com_Init: ; REGS: (R1, R3, R16, R17, R18, R19, R22, X) Com_Run: - rcall comHandleNextPacketInRingbuffer ; nothing more than handling packages in ringbuffer + rcall comHandleNextPacketInQueue ; nothing more than handling packages in ringbuffer ; clc ret @@ -121,75 +169,87 @@ Com_Run: ; Mark a packet as enqueued. ; ; IN: -; - R18: pos pointer inside ring buffer to read from next +; - Y: pointer to buffer containing the enqueued packet ; - R20: priority ; OUT: ; - CFLAG: set if okay, clear otherwise -; MODIFIED REGS: R10, R11, R12, R15, R16, R20 (R3, R21, R22) +; MODIFIED REGS: R15, R16 COM_EnqueuePacket: - ldi yl, LOW(comRingBuffer) - ldi yh, HIGH(comRingBuffer) in r15, SREG cli - ldd r19, y+RINGBUFFER_OFFS_MAXSIZE - ; read length - rcall RingBuffer_Read ; (R3, R22) - cpi r16, 3 ; at least 3 bytes? - brcs COM_EnqueuePacket_error ; too few bytes - ; read flags - push r18 ; r18 points to flags - rcall RingBuffer_Read ; advances r18 behind flags - pop r18 ; r18 back to flags - ; write flags + ldd r16, y+COM_BUFFER_OFFS_FLAGS andi r16, (~(COM_BUFFER_FLAGS_PRIO1 | COM_BUFFER_FLAGS_PRIO0 | COM_BUFFER_FLAGS_RECEIVED | COM_BUFFER_FLAGS_DONE)) & 0xff or r16, r20 ; add priority ori r16, COM_BUFFER_FLAGS_TOSEND - rcall RingBuffer_Write + std y+COM_BUFFER_OFFS_FLAGS, r16 out SREG, r15 ; restore IRQ flag sec ret -COM_EnqueuePacket_error: - out SREG, r15 ; restore IRQ flag + + + +; --------------------------------------------------------------------------- +; COM_AllocBufferAndGetXY +; +; IN: +; - nothing +; OUT: +; - CFLAG: set if okay, clear otherwise +; - Y: pointer to buffer +; - X: pointer to data portion of the buffer +; MODIFIED REGS: R16, R17 (R21) + +COM_AllocBufferAndGetXY: + rcall COM_BufferAlloc ; (r16, r17, r21) + brcc COM_AllocBufferAndGetXY_error + mov xl, yl + mov xh, yh + ldi r16, COM_BUFFER_OFFS_DATA + clr r17 + add xl, r16 + adc xh, r17 + sec + ret +COM_AllocBufferAndGetXY_error: clc ret + ; --------------------------------------------------------------------------- ; Enqueue a PING packet. ; ; IN: -; - R17: destination address +; - R16: destination address ; OUT: ; - CFLAG: set if okay, clear otherwise -; MODIFIED REGS: +; MODIFIED REGS: R16, R17, R20, X (R15, Y) COM_EnqueuePing: - ldi yl, LOW(comRingBuffer) - ldi yh, HIGH(comRingBuffer) - ldi r16, 3+2 ; 3 bytes for buffer length, flags and destination address, cmd, source addr - push r17 - rcall RingBuffer_Alloc ; r16: pos of allocated buffer (r16, r17, r18, r19, r20, r21) - pop r17 + push r16 + rcall COM_AllocBufferAndGetXY ; (r16, r17, r21) + pop r16 brcc COM_EnqueuePing_error - ; write header stuff - mov r18, r16 ; r18: start of packet in ring buffer - mov r20, r16 ; r20: start of packet in ring buffer - ldd r19, y+RINGBUFFER_OFFS_MAXSIZE - ldi r16, 3+2 - rcall RingBuffer_Write ; write length (r3, r22) - clr r16 - rcall RingBuffer_Write ; write flags - mov r16, r17 - rcall RingBuffer_Write ; write dest addr + clr r17 ; r17: XOR byte + ; write header (dest address, msg length) + st X+, r16 ; destination address + eor r17, r16 + ldi r16, 2 ; 2 bytes payload + st X+, r16 + eor r17, r16 ; write payload ldi r16, COM_CMD_PING - rcall RingBuffer_Write ; write cmd + st X+, r16 + eor r17, r16 lds r16, comAddress - rcall RingBuffer_Write ; write source address - mov r18, r20 - ldi r20, COM_REPEAT_INFO - rcall COM_EnqueuePacket + st X+, r16 + eor r17, r16 + ; store XOR byte + st X+, r17 + ; mark buffer as enqueued with PRIO "info" (limited amount of retries) + ldi r20, COM_BUFFER_PRIO_INFO + rcall COM_EnqueuePacket ; (R15, R16) brcc COM_EnqueuePing_error sec ret @@ -200,52 +260,51 @@ COM_EnqueuePing_error: ; --------------------------------------------------------------------------- -; comHandleNextPacketInRingbuffer -; -; Expects global IRQ disabled. +; comHandleNextPacketInQueue ; ; IN: ; - nothing ; OUT: ; - CFLAG: set if something done, can be called again immediately (otherwise: wait for timer interrupt and retry) -; MODIFIED REGS: R1, R16, R17, R18, R19, Y (R1, R3, R16, R17, R18, R19, R22, X) +; MODIFIED REGS: R16, R17, Y (R15, R18, R21, R22, X) -comHandleNextPacketInRingbuffer: - ; read current packet in ringbuffer (read pointer) - ldi yl, LOW(comRingBuffer) - ldi yh, HIGH(comRingBuffer) - ldd r16, y+RINGBUFFER_OFFS_USED +comHandleNextPacketInQueue: + lds r16, comRecvBuffersUsed tst r16 - breq comHandleNextPacketInRingbuffer_retNc - ldd r19, y+RINGBUFFER_OFFS_MAXSIZE - ldd r18, y+RINGBUFFER_OFFS_READPOS - rcall RingBuffer_Read ; packet length (R3, R22) - cpi r16, 3 ; at least 3 bytes? - brcs comHandleNextPacketInRingbuffer_retNc - mov r1, r16 - rcall RingBuffer_Read ; read flags from packet - ldd r18, y+RINGBUFFER_OFFS_READPOS ; r18 back to read pointer - mov r17, r16 ; flags - andi r17, COM_BUFFER_FLAGS_TOSEND ; check for message to send - brne comHandleNextPacketInRingbuffer_sendPacket - mov r17, r16 ; check for received message + breq comHandleNextPacketInQueue_retNc ; no buffers in use + + lds r16, comRecvBuffersReadPos + rcall COM_BufferPosToY ; get current read buffer to Y (R16, R17) + ldd r16, y+COM_BUFFER_OFFS_FLAGS ; get flags + ; check for released buffer (dealloc) + mov r17, r16 + andi r17, COM_BUFFER_FLAGS_RELEASED ; check for buffer released + brne comHandleNextPacketInQueue_releaseBuffer + ; check for received packet + mov r17, r16 andi r17, COM_BUFFER_FLAGS_RECEIVED - brne comHandleNextPacketInRingbuffer_receivedPacket - rjmp comHandleNextPacketInRingbuffer_retNc - -comHandleNextPacketInRingbuffer_sendPacket: - rcall comSendPacketHandleRepeat ; (R1, R3, R16, R17, R18, R19, R22, X) - ret ; use CFLAG from subroutine - -comHandleNextPacketInRingbuffer_receivedPacket: + brne comHandleNextPacketInQueue_receivedPacket + ; check for buffer to send + mov r17, r16 + andi r17, COM_BUFFER_FLAGS_TOSEND ; check for message to send + brne comHandleNextPacketInQueue_sendPacket + ; nothing to do (e.g. buffer not ready to be sent) + rjmp comHandleNextPacketInQueue_retNc +comHandleNextPacketInQueue_sendPacket: + rcall comSendPacketHandleRepeat ; (R15, R16, R17, R18, R21, R22, X) + ret ; use CFLAG from subroutine +comHandleNextPacketInQueue_receivedPacket: clr r17 - sts comRepeatCount, r17 ; set comRepeatCount to zero - rcall comHandleReceivedPacket - sec ; always return with set CFLAG + sts comRepeatCount, r17 ; set comRepeatCount to zero + rcall comHandleReceivedPacket ; (r16, r17, r21, X) + sec ; always return with set CFLAG ret - -comHandleNextPacketInRingbuffer_retNc: +comHandleNextPacketInQueue_releaseBuffer: + rcall COM_BufferDeallocFront + sec ; always return with set CFLAG + ret +comHandleNextPacketInQueue_retNc: clc ret @@ -255,17 +314,13 @@ comHandleNextPacketInRingbuffer_retNc: ; comHandleReceivedPacket ; ; IN: -; - nothing +; - Y: pointer to current buffer (pointed to by comRecvBuffersReadPos) ; OUT: ; - nothing -; MODIFIED REGS: X, (R3, R22) +; MODIFIED REGS: X (r16, r17, r21) comHandleReceivedPacket: - ldi yl, LOW(comRingBuffer) - ldi yh, HIGH(comRingBuffer) - ldd r19, y+RINGBUFFER_OFFS_MAXSIZE - ldd r18, y+RINGBUFFER_OFFS_READPOS rcall onPacketReceived brcs comHandleReceivedPacket_l1 ldi xl, LOW(comStatsIgnored) @@ -275,11 +330,7 @@ comHandleReceivedPacket_l1: ldi xl, LOW(comStatsHandled) ldi xh, HIGH(comStatsHandled) comHandleReceivedPacket_l2: - ldi yl, LOW(comRingBuffer) - ldi yh, HIGH(comRingBuffer) - ldd r19, y+RINGBUFFER_OFFS_MAXSIZE - ldd r18, y+RINGBUFFER_OFFS_READPOS - rcall comDeallocReadBufAndIncrCounter ; (r16, r17, r18, r19, r20, r21) + rcall comDeallocReadBufAndIncrCounter ; (r16, r17, r21) ret @@ -288,49 +339,46 @@ comHandleReceivedPacket_l2: ; comSendPacketHandleRepeat ; ; IN: -; - R18: pos pointer inside ring buffer to read from next -; - R19: maximum size of the ringbuffer (for wrap-around) -; - Y : ringbuffer +; - Y: pointer to current buffer (pointed to by comRecvBuffersReadPos) ; OUT: ; - CFLAG: set if something done, can be called again immediately (otherwise: wait for timer interrupt and retry) -; MODIFIED REGS: R1, R15, R16, R17, R18, R19, X, (R3, R22) +; MODIFIED REGS: R15, R17, R22, X (R16, R17, R18, R21, R22) comSendPacketHandleRepeat: in r15, SREG cli - push r18 - rcall RingBuffer_Read ; packet length (R3, R22) - mov r1, r16 ; r1: ringbuffer packet length - rcall RingBuffer_Read ; flags - pop r18 + ldd r16, y+COM_BUFFER_OFFS_FLAGS rcall comSetupRepeat ; setup comRepeatCount if not already done (R16, R17) -; sbis COM_PIN_ATTN, COM_PINNUM_ATTN ; check ATTN: low? -; rjmp comSendPacketHandleRepeat_adjustRepeat ; yes, line is busy, retry later - push r18 - cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; set ATTN low - sbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN as output - Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit duration - rcall comSendPacketRaw ; (R3, R10, R11, R12, R16, R20 R21, R22) - cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; release ATTN line - pop r18 + cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; set ATTN low + sbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN as output + Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit duration + rcall comSendPacketHandleBuffer ; (R16, R17, R21, R22) + cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; release ATTN line brcc comSendPacketHandleRepeat_adjustRepeat - ; packet sent, adjust stats - mov r16, r1 + ; packet sent, adjust stats, release buffer ldi xl, LOW(comStatsPacketsOut) ldi xh, HIGH(comStatsPacketsOut) rcall comDeallocReadBufAndIncrCounter ; (r16, r17, r18) rjmp comSendPacketHandleRepeat_retC - comSendPacketHandleRepeat_adjustRepeat: + ; increment collisions counter + ldi xl, LOW(comStatsCollisions) + ldi xh, HIGH(comStatsCollisions) + clr r22 + ld r16, x+ + ld r17, x + inc r16 + adc r17, r22 + st -x, r17 + st x, r16 + ; decrement repeat counter (except for vital messages) lds r17, comRepeatCount cpi r17, COM_REPEAT_VITAL - breq comSendPacketHandleRepeat_retNC ; vital message, repeat forever + breq comSendPacketHandleRepeat_retNC ; vital message, repeat forever dec r17 sts comRepeatCount, r17 brne comSendPacketHandleRepeat_retNC - - ; dealloc buffer, inc dismiss counter - mov r16, r1 + ; dealloc buffer, inc abort counter ldi xl, LOW(comStatsAborted) ldi xh, HIGH(comStatsAborted) rcall comDeallocReadBufAndIncrCounter @@ -352,8 +400,7 @@ comSendPacketHandleRepeat_retC: ; comSetupRepeat ; ; IN: -; - R16: pos pointer inside ring buffer to read from next -; - R20: priority +; - R16: priority ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGS: R16, R17 @@ -391,162 +438,194 @@ comSetupRepeat_l99: ; comDeallocReadBufAndIncrCounter ; ; IN: -; - r16: num of bytes to dealloc ; - X : pointer to counter -; - Y : ring buffer ; OUT: ; - nothing -; REGS: r16, r17, r18 (r19, r20, r21) +; REGS: r16, r17, r21 comDeallocReadBufAndIncrCounter: - rcall RingBuffer_DeallocRead ; (r17, r18, r19, r20, r21) - clr r18 + rcall COM_BufferDeallocFront ; (r16, r17, r21) + clr r21 ld r16, x+ ld r17, x inc r16 - adc r17, r18 + adc r17, r21 st -x, r17 st x, r16 - sts comRepeatCount, r18 ; set comRepeatCount to zero + sts comRepeatCount, r21 ; set comRepeatCount to zero ret ; --------------------------------------------------------------------------- -; comSendPacketRaw +; comSendPacketHandleBuffer ; -; Send a packet. (TODO: input buffer in x, length in r16) +; Send a packet from the current read buffer (pointed to by comRecvBuffersReadPos). +; On success the flag COM_BUFFER_FLAGS_DONE is set in the buffer. +; The buffer is not released. +; +; CAVE: Expects interrupts to be disabled! ; ; IN: -; - R18: pos pointer inside ring buffer to read from next +; - Y : pointer to current read buffer ; OUT: ; - CFLAG: set if okay, clear otherwise -; MODIFIED REGS: R10, R11, R16 (R3, R21, R22) +; MODIFIED REGS: R16, R17 (R21, R22) -comSendPacketRaw: - ldi yl, LOW(comRingBuffer) - ldi yh, HIGH(comRingBuffer) - ldd r19, y+RINGBUFFER_OFFS_MAXSIZE - rcall RingBuffer_Read ; read entry length from buffer (advances r18) (R3, R22) - cpi r16, 3 ; at least 3 bytes? - brcs comSendPacketRaw_error ; too few bytes - mov r10, r16 ; r10: number of bytes at current ringbuffer pos - dec r10 - dec r10 - dec r10 ; r10: number of bytes in message - clr r11 ; r11: XOR checksum - rcall RingBuffer_Read ; read flags from buffer (ignore) - rcall RingBuffer_Read ; read dest address from buffer - eor r11, r16 ; calculate checksum - rcall comSendByte ; send destination address (R16, R21, R22) - brcc comSendPacketRaw_error - mov r16, r10 ; send msg length - eor r11, r16 ; calculate checksum - rcall comSendByte ; send msg length - brcc comSendPacketRaw_error - tst r10 ; payload? - breq comSendPacketRaw_sendCrc ; no payload, go send checksum -comSendPacketRaw_loop: - rcall RingBuffer_Read ; read byte from buffer - eor r11, r16 ; calculate checksum - rcall comSendByte ; send byte - brcc comSendPacketRaw_error - dec r10 - brne comSendPacketRaw_loop -comSendPacketRaw_sendCrc: - mov r16, r11 ; send checksum - rcall comSendByte ; send byte - brcc comSendPacketRaw_error +comSendPacketHandleBuffer: + mov xl, yl + mov xh, yh + ldi r16, COM_BUFFER_OFFS_DATA + clr r17 + add xl, r16 + adc xh, r17 + ldd r16, y+(COM_BUFFER_OFFS_DATA+COM_MSG_OFFS_MSGLEN) ; get msg payload length + ldi r17, 3 + add r16, r17 ; add dest addr, msg len and XOR byte + rcall comSendPacketFromSram ; send all that + brcc comSendPacketHandleBuffer_error + ldd r16, y+COM_BUFFER_OFFS_FLAGS + ori r16, COM_BUFFER_FLAGS_DONE + std y+COM_BUFFER_OFFS_FLAGS, r16 + sec + ret +comSendPacketHandleBuffer_error: + clc + ret + + +; --------------------------------------------------------------------------- +; comSendPacketFromSram +; +; Send a packet from SRAM +; +; IN: +; - R16: number of bytes to send +; - X: pointer to buffer to read from +; OUT: +; - CFLAG: set if okay, clear otherwise +; MODIFIED REGS: R16, R17 (R21, R22) + +comSendPacketFromSram: + mov r17, r16 +comSendPacketFromSram_loop: + ld r16, X+ + rcall comSendByte ; send byte (R16, R21, R22) + brcc comSendPacketFromSram_error + dec r17 + brne comSendPacketFromSram_loop sec ret -comSendPacketRaw_error: +comSendPacketFromSram_error: clc ret ; --------------------------------------------------------------------------- -; comReceivePacket -; -; Receive a packet. If we are the recipient of the packet then space will be allocated inside the -; given ringbuffer and the received packet will be stored there. -; -; Packages are stored in the buffer like this: -; - 1 byte : buffer size -; - 1 byte: flags (e.g. COM_BUFFER_FLAGS_RECEIVED) -; - 1 byte : destination address -; - n bytes: packet (i.e. buffer size -3 bytes) +; comReceivePacketHandleBuffer ; +; Allocate a buffer and receive a packet into it. +; On success the buffer flags will have COM_BUFFER_FLAGS_RECEIVED set. +; On error the buffer will be deallocated. ; IN: ; - nothing ; OUT: -; - CFLAG: set if okay, clear otherwise -; MODIFIED REGS: R1, R2, R3, R16, R17, R18, R19 (R20, R21, R22, XL, XH) +; - CFLAG: set if okay, cleared otherwise +; MODIFIED REGISTERS: R16, R17, X, Y (R1, R20, R21, R22) -comReceivePacket: - ldi yl, LOW(comRingBuffer) - ldi yh, HIGH(comRingBuffer) - clr r1 ; r1: checksum - ; read destination address - rcall comReceiveByte ; read byte - brcc comReceivePacket_error - ; compare destination address (accept "0" and own address) - tst r16 - breq comReceivePacket_acceptAddr - lds r17, comAddress - cp r16, r17 - breq comReceivePacket_acceptAddr - clc ; not for me - ret -comReceivePacket_acceptAddr: - mov r3, r16 ; r3: destination address (maybe we need to forward the packet) - eor r1, r16 - rcall comReceiveByte ; read packet length (R16, R17, R20, R21, R22) - brcc comReceivePacket_error - ; alloc ring buffer - mov r17, r16 ; r17: packet length - inc r16 ; packet length bytes + length byte - inc r16 ; + flags - inc r16 ; + dest addr - mov r2, r16 ; r2: number of bytes allocated in ringbuffer - push r17 - rcall RingBuffer_Alloc ; (r16, r17, r18, r19, r20, r21) - pop r17 - brcc comReceivePacket_error - mov r18, r16 ; r18: pos in ring buffer - ldd r19, y+RINGBUFFER_OFFS_MAXSIZE ; max size - mov r16, r2 ; write number of bytes allocated to ringbuffer - ori r16, COM_BUFFER_FLAGS_RECEIVED - rcall RingBuffer_Write ; (r3, r22) - ldi r16, COM_BUFFER_FLAGS_RECEIVED ; write flags to ringbuffer - rcall RingBuffer_Write ; (r3, r22) - mov r16, r3 ; write destination address for packet we saved earlier - rcall RingBuffer_Write ; (r3, r22) - ; read packet (except XOR byte, that will be read later) -comReceivePacket_loop1: - rcall comReceiveByte ; (R16, R17, R20, R21, R22) - brcc comReceivePacket_error_release_buffer - eor r1, r16 - rcall RingBuffer_Write ; (r3, r22) - dec r17 - brne comReceivePacket_loop1 - ; read XOR byte, don't store - rcall comReceiveByte ; (R16, R17, R20, R21, R22) - brcc comReceivePacket_error - eor r1, r16 - brne comReceivePacket_error_release_buffer ; XOR should be 0 here, otherwise error +comReceivePacketHandleBuffer: + rcall COM_BufferAlloc + brcc comReceivePacketHandleBuffer_error + ; get pos of data portion for the allocated buffer + mov xl, yl + mov xh, yh + ldi r16, COM_BUFFER_OFFS_DATA + clr r17 + add xl, r16 + adc xh, r17 + rcall comReceivePacketToSram ; (r1, r16, r17, R20, R21, R22, X) + brcc comReceivePacketHandleBuffer_dealloc + ; handle buffer flags + ldi r16, COM_BUFFER_FLAGS_RECEIVED + std y+COM_BUFFER_OFFS_FLAGS, r16 sec ret -comReceivePacket_error_release_buffer: - mov r16, r2 ; number of bytes allocated in ringbuffer - rcall RingBuffer_DeallocWrite ; (r17, r18, r19, r20, r21) -comReceivePacket_error: + +comReceivePacketHandleBuffer_dealloc: + rcall COM_BufferDeallocBack ; (r16, r17, r21) +comReceivePacketHandleBuffer_error: clc ret +; --------------------------------------------------------------------------- +; comReceivePacketToSram +; +; Receive a packet to the given SRAM position. +; IN: +; - X: pointer to start of buffer to receive bytes +; OUT: +; - CFLAG: set if okay, clear otherwise +; MODIFIED REGISTERS: r1, r16, r17, X (R20, R21, R22) + +comReceivePacketToSram: + clr r1 ; r1: checksum + ; read destination address + rcall comReceiveByte ; read byte (R16, R17, R20, R21, R22) + brcc comReceivePacketToSram_error + eor r1, r16 + ; compare destination address (accept "0" and own address) + tst r16 + breq comReceivePacketToSram_acceptAddr + lds r17, comAddress + cp r16, r17 + breq comReceivePacketToSram_acceptAddr + clc ; not for me + ret +comReceivePacketToSram_acceptAddr: + st X+, r16 + + ; read msg length + rcall comReceiveByte ; read packet length (R16, R17, R20, R21, R22) + brcc comReceivePacketToSram_error + eor r1, r16 + st X+, r16 + tst r16 + breq comReceivePacketToSram_readXOR + mov r17, r16 +comReceivePacketToSram_loop: + push r17 + rcall comReceiveByte ; read byte (R16, R17, R20, R21, R22) + pop r17 + brcc comReceivePacketToSram_error + st X+, r16 + eor r1, r16 + dec r17 + brne comReceivePacketToSram_loop + +comReceivePacketToSram_readXOR: + rcall comReceiveByte ; XOR byte (R16, R17, R20, R21, R22) + brcc comReceivePacketToSram_error + st X+, r16 + eor r1, r16 + brne comReceivePacketToSram_error + sec + ret + +comReceivePacketToSram_error: + clc + ret + + + +; *************************************************************************** +; lowlevel pin functions + + + ; --------------------------------------------------------------------------- ; comSendByte @@ -611,12 +690,13 @@ comSendByte_error: ; MODIFIED REGS: R16, R20, R21, R22 (R17) comReceiveByte: - sbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input + 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 + rcall comWaitForDataLow ; (R17) brcc comReceiveByte_error Utils_WaitNanoSecs COM_BIT_LENGTH/2, 5, r22 ; goto middle of startbit to maximize sync stability comReceiveByte_loop: @@ -630,7 +710,7 @@ comReceiveByte_shiftIn: dec r21 ; +1 brne comReceiveByte_loop ; +2, sum per loop: 8 cycles rcall comWaitForDataHigh ; wait for start of stopbit -; brcc comReceiveByte_error + brcc comReceiveByte_error mov r16, r20 sec ret @@ -647,7 +727,7 @@ comReceiveByte_error: ; IN: ; OUT: ; - CFLAG: set if okay, clear otherwise -; MODIFIED REGISTERS: r17, r22, X +; MODIFIED REGISTERS: r17, r22 comWaitForDataLow: ldi r17, COM_MAXWAIT @@ -655,6 +735,7 @@ comWaitForDataLow: 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 @@ -681,6 +762,7 @@ comWaitForDataHigh: 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 @@ -692,8 +774,182 @@ comWaitForDataHigh_done: +; --------------------------------------------------------------------------- +; 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 + 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 + brne COM_BufferDeallocBack_l1 + 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 + add yl, r16 + adc yh, r17 + + 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 diff --git a/avr/main.asm b/avr/main.asm index 516d782..209a9da 100644 --- a/avr/main.asm +++ b/avr/main.asm @@ -19,8 +19,6 @@ .equ COM_BIT_LENGTH = 52000 ; 104000=9600, 52000=19200, 26000=38400 -.equ COM_RINGBUFFER_SIZE = 32 ; 32 bytes for now - .equ COM_DDR_DATA = DDRA .equ COM_PORT_DATA = PORTA .equ COM_PIN_DATA = PINA @@ -52,7 +50,7 @@ rjmp main ; Reset vector reti ; EXT_INT0 - reti ; PCI0 + rjmp comIsrPcint0 ; PCI0 reti ; PCI1 reti ; WATCHDOG reti ; ICP1 @@ -74,7 +72,6 @@ ; includes .include "utils.asm" -.include "ringbuffer.asm" .include "timer.asm" .include "led.asm" .include "com.asm" @@ -262,14 +259,13 @@ onEverySecond: ; USED: depending on called routines onEvery10s: - in r15, SREG ; debug - cli - push r15 - ldi r17, 219 - rcall COM_EnqueuePing -; rcall comHandleNextPacketInRingbuffer - pop r15 - out SREG, r15 +; in r15, SREG ; debug +; cli +; push r15 +; ldi r16, 219 +; rcall COM_EnqueuePing +; pop r15 +; out SREG, r15 ret @@ -286,8 +282,6 @@ onEvery10s: ; USED: depending on called routines onEveryMinute: - sbi DDRA, PORTA2 ; debug - sbi PINA, PORTA2 ; debug (toggle) ret @@ -299,13 +293,14 @@ onEveryMinute: ; ; The packet will be removed from buffer in any case after return from this call. ; IN: -; - R18: pos of packet in ringbuffer -; - Y : pointer to ringbuffer +; - Y : pointer to received buffer ; OUT: ; - CFLAG: set if handled, cleared otherwise ; USED: depending on called routines onPacketReceived: + sbi DDRA, PORTA2 ; debug + sbi PINA, PORTA2 ; debug (toggle) clc ; not handled ret @@ -316,33 +311,42 @@ onPacketReceived: debugSendByte: - in r15, SREG ; debug - cli + push r15 + in r15, SREG ; debug + cli + push r17 + push r22 + ldi r17, 8 + sbi DDRA, PORTA2 ; debug + + cbi PORTA, PORTA2 ; debug (on) + Utils_WaitNanoSecs 100000, 0, r22 ; start with 2t low - ldi r17, 8 - sbi DDRA, PORTA2 ; debug - - cbi PORTA, PORTA2 ; debug (on) - Utils_WaitNanoSecs 200000, 0, r22 ; start with 2t low - -debugSendByte_loop: - lsr r16 - brcs debugSendByte_sendLow - cbi PORTA, PORTA2 ; debug (on) - rjmp debugSendByte_wait -debugSendByte_sendLow: - sbi PORTA, PORTA2 ; debug (off) - -debugSendByte_wait: - Utils_WaitNanoSecs 100000, 0, r22 - dec r17 - brne debugSendByte_loop - - cbi PORTA, PORTA2 ; debug (on) - Utils_WaitNanoSecs 200000, 0, r22 ; end with 2t low - sbi PORTA, PORTA2 ; debug (off) - - - out SREG, r15 + sbi PORTA, PORTA2 ; debug (off) + nop + nop + cbi PORTA, PORTA2 ; debug (on) + Utils_WaitNanoSecs 100000, 0, r22 ; start with 2t low + + debugSendByte_loop: + lsr r16 + brcs debugSendByte_sendLow + cbi PORTA, PORTA2 ; debug (on) + rjmp debugSendByte_wait + debugSendByte_sendLow: + sbi PORTA, PORTA2 ; debug (off) + + debugSendByte_wait: + Utils_WaitNanoSecs 100000, 0, r22 + dec r17 + brne debugSendByte_loop + + cbi PORTA, PORTA2 ; debug (on) + Utils_WaitNanoSecs 200000, 0, r22 ; end with 2t low + sbi PORTA, PORTA2 ; debug (off) + pop r22 + pop r17 + out SREG, r15 + pop r15 ret