;****************************************************************************** ;Author: Frank F. Hitzel, Braunschweig, Germany (2004) ;This software is distributed under the terms of the GNU General Public Licence ;Multiplexer, A version ;Framing Error bug correction by Adolf Schwarz ;****************************************************************************** .include "2313def.inc" ;************************************************** Macro definitions .MACRO doReceive sbrc rxstat,@0 ;are we receiving? rjmp tim_rec sbrs tim_temp,@1 ;start bit detected (zero)? rjmp tim_start ;jump to start receive rjmp tim_ret TIM_STOP: mov tim_temp2,tim_temp ;check stop bit andi tim_temp2,(1 << @1) brne tim_rec_ok cbr rxstat,(1<<@0) sbr errstat,(1<<@0) ;indicate error rjmp tim_ret TIM_REC_OK: cbr rxstat,(1<<@0) sbr status,(1<<@0) sts @2,@3 ;store char, ready rjmp tim_ret TIM_START: sbr rxstat,(1 << @0) ldi tim_temp2,9 ;9 incl. stop bit mov @4,tim_temp2 ldi @5,10 rjmp tim_ret TIM_REC: subi @5,1 brne tim_ret dec @4 breq tim_stop mov tim_temp2,tim_temp andi tim_temp2,(1 << @1) com tim_temp2 subi tim_temp2,$ff ;generate carry if bit was set ror @3 ldi @5,8 ;wait 8 cycles TIM_RET: .ENDMACRO .MACRO checkInputMac sbrs status,@0 ;receive buffer already full? rjmp NO_CHAR sbrs rxstat,@0-4 rjmp NOT_FULL sbr errstat,(1<<@0) rjmp NO_CHAR ;ignore char NOT_FULL: lds temp,@1 lds YL,@2 st Y+,temp cpi YL,@3 brlo RXB_NO_OVFL ldi YL,@4 RXB_NO_OVFL: sts @2,YL cbr status,(1<<@0) ;clear char avail bit cpi temp,$0d ;end of line? brne NO_CHAR sbr rxstat,(1<<(@0-4)) ;buffer is filled NO_CHAR: .ENDMACRO .MACRO checkSendBuffer rcall CHECK_INPUTS sbrs rxstat,@0 ;buffer 0 filled? rjmp BUF_NOTFIL MW_FIRST: sbic USR,UDRE ;can we send a byte? rjmp DO_FIRST rcall CHECK_INPUTS rjmp MW_FIRST DO_FIRST: ldi temp,('0'+@0) out UDR,temp ;send channel identification ldi ZL,@1 ;load cursor MAIN_WAIT: sbic USR,UDRE ;can we send a byte? rjmp DO_SEND rcall CHECK_INPUTS rjmp MAIN_WAIT DO_SEND: ld temp,Z+ out UDR,temp cpi temp,$0d brne MAIN_WAIT cbr rxstat,(1<<@0) ;buffer not filled anymore, go to next buffer ldi temp,@1 sts @2,temp BUF_NOTFIL: .ENDMACRO .MACRO showMessage ldi Zl,low(@0 << 1) ;show error message INFO_LOOP: sbic USR,UDRE rjmp DO_SEND rcall CHECK_INPUTS rjmp INFO_LOOP DO_SEND: lpm inc ZL mov temp,r0 out UDR,temp cpi temp,$0d brne INFO_LOOP .ENDMACRO .LISTMAC ;************************************************** Code start rjmp RESET ; Reset Handler .org $004 rjmp TIM_COMP .org $007 rjmp UART_RXC .equ frequency =10000000 ;.equ frequency =3690000 .equ baud =9600 .equ freq_divi = (frequency / (baud*8))-1 .equ out0 =1 .equ out1 =2 .equ out2 =5 .equ out3 =7 .equ in0 =0 .equ in1 =3 .equ in2 =4 .equ in3 =6 .equ rxbuffers =25 ;**************************** RAM .dseg .org $60 ;ramstart rxbuf0: .BYTE rxbuffers rxbuf1: .BYTE rxbuffers rxbuf2: .BYTE rxbuffers rxbuf3: .BYTE rxbuffers rxbufend: rxchar0: .BYTE 1 rxchar1: .BYTE 1 rxchar2: .BYTE 1 rxchar3: .BYTE 1 rxcursor0: .BYTE 1 rxcursor1: .BYTE 1 rxcursor2: .BYTE 1 rxcursor3: .BYTE 1 ;**************************** Code .cseg .def rxreg0 =r1 .def rxreg1 =r2 .def rxreg2 =r3 .def rxreg3 =r4 .def txreg =r5 .def status_save =r6 ;status save register for interrupt routines .def active_output =r7 ;contains active output as bit of the corresponding output pin .def txchar =r8 ;contains next char to be sent .def rxcnt0 =r9 .def rxcnt1 =r10 .def rxcnt2 =r11 .def rxcnt3 =r12 .def txcnt =r13 .def infofunc =r14 .def temp =r16 .def temp2 =r17 .def rxwait0 =r18 .def rxwait1 =r19 .def rxwait2 =r20 .def rxwait3 =r21 .def txwait =r22 .def rxstat =r23 ;low 4 bits full status of buffers, high 4 bits are receive_active_flags .def status =r24 ;bit0 = sending; bit1=0: last was 0d; bit2=0: last was control; bit3=1: start send; ;high 4 bits are data there bits .def errstat = r25 ;higher bits are framing errors, lower bits are overflow .def tim_temp =r26 .def tim_temp2 =r27 OUTPUT_TAB: .db out0,out1,out2,out3 ;must be within lowest 256 bytes MSG_INFO: .db "DoubleFox MultiplexerA Rev. 1.0a",13,0,0 MSG_ERROR: .db "error",13,0,0 ;*************************************************************************************************** ; UART RX ;*************************************************************************************************** UART_RXC: in status_save,SREG in tim_temp,UDR sbic USR,FE ;skip next if no framing error rjmp IGNORE_RX sbrc status,2 rjmp check_control sbrs status,1 rjmp check_first cpi tim_temp,$0d brne NO_LINEEND cbr status,(1<<1) ;clear bit -> 0d detected NO_LINEEND: mov txchar,tim_temp sbr status,(1<<3) ;start send IGNORE_RX: out SREG,status_save reti CHECK_FIRST: sbr status,(1<<1) cpi tim_temp,'$' breq IS_CONTROL mov txchar,tim_temp sbr status,(1<<3) ;start send out SREG,status_save reti IS_CONTROL: sbr status,(1<<2) ;last was control out SREG,status_save reti CHECK_CONTROL: cbr status,(1<<2) cpi tim_temp,'$' brne SWITCH_DESTPORT mov txchar,tim_temp sbr status,(1<<3) ;start send out SREG,status_save reti SWITCH_DESTPORT: cbr status,(1<<1) ;last was 0d cpi tim_temp,'0' breq SWITCH_ZERO cpi tim_temp,'1' breq SWITCH_ONE cpi tim_temp,'2' breq SWITCH_TWO cpi tim_temp,'3' breq SWITCH_THREE cpi tim_temp,'?' breq SET_INFO cpi tim_temp,'s' breq SET_INFO out SREG,status_save reti SET_INFO: mov infofunc,tim_temp out SREG,status_save reti SWITCH_ZERO: ldi tim_temp,(1 << out0) mov active_output,tim_temp out SREG,status_save reti SWITCH_ONE: ldi tim_temp,(1 << out1) mov active_output,tim_temp out SREG,status_save reti SWITCH_TWO: ldi tim_temp,(1 << out2) mov active_output,tim_temp out SREG,status_save reti SWITCH_THREE: ldi tim_temp,(1 << out3) mov active_output,tim_temp out SREG,status_save reti ;*************************************************************************************************** ; TIMER ;*************************************************************************************************** TIM_COMP: in status_save,SREG sbrc status,0 rjmp TIM_SENDING sbrc status,3 rjmp TIM_START_SEND rjmp TIM_RECEIVE TIM_SENDING: dec txwait brne TIM_RECEIVE tst txcnt brne TIM_SEND_BIT cbr status,1 ;stop bit sent, clear 'sending' bit rjmp TIM_RECEIVE TIM_SEND_BIT: dec txcnt lsr txreg ;move actual bit into carry flag in tim_temp,PORTB brcs TIM_SEND_ZERO or tim_temp,active_output out PORTB,tim_temp ;send one ldi txwait,8 rjmp TIM_RECEIVE TIM_SEND_ZERO: com active_output and tim_temp,active_output com active_output out PORTB,tim_temp ldi txwait,8 rjmp TIM_RECEIVE TIM_START_SEND: ;************************************************starting send cbr status,(1<<3) ;clear start send flag sbr status,(1<<0) ;sending flag mov txreg,txchar com txreg ldi txwait,9 mov txcnt,txwait ldi txwait,8 in tim_temp,PORTB com active_output and tim_temp,active_output com active_output out PORTB,tim_temp ;send start bit (logical 0) ;************************************************receive TIM_RECEIVE: in tim_temp,PINB doReceive 4,in0,rxchar0,rxreg0,rxcnt0,rxwait0 doReceive 5,in1,rxchar1,rxreg1,rxcnt1,rxwait1 doReceive 6,in2,rxchar2,rxreg2,rxcnt2,rxwait2 doReceive 7,in3,rxchar3,rxreg3,rxcnt3,rxwait3 out SREG,status_save reti ;*************************************************************************************************** ; RESET / Initialization ;*************************************************************************************************** RESET: ldi temp,low(RAMEND) out SPL,temp ;init Stack Pointer ;**************************** Init PORTB ldi temp,0b10100110 ;(1 = output) out DDRB,temp ser temp ;start bit is zero, so go to one out PORTB,temp ;**************************** Init UART ldi temp,(1 << TXEN)|(1 << RXEN)|(1 << RXCIE) out UCR,temp ldi temp,(frequency / (16*baud)) - 1 out UBRR,temp ;**************************** Init Timer clr temp out TCCR1A,temp ;disconnect OC1 and no PWM ldi temp,0b01001 ;select CK/1 and clear counter on match out TCCR1B,temp clr temp out OCR1AH,temp ldi temp,freq_divi ;RS232 sample frequency out OCR1AL,temp ldi temp,(1 << OCIE1A) out TIMSK,temp ;enable compare match interrupt ;**************************** Select output ldi temp,(1 << out0) mov active_output,temp ;**************************** Init receive cursors ldi temp,rxbuf0 sts rxcursor0,temp ldi temp,rxbuf1 sts rxcursor1,temp ldi temp,rxbuf2 sts rxcursor2,temp ldi temp,rxbuf3 sts rxcursor3,temp ;**************************** Clear stati (for debugging, otherwise should be zero) clr infofunc clr status clr rxstat clr status_save clr errstat clr txcnt ;'not sending' indicator dec txcnt ;txcnt = 0xFF ;*************************************************************************************************** ; RESET / Main ;*************************************************************************************************** clr ZH ;always leave ZH zero clr YH ;always leave YH zero sei MAIN: checkSendBuffer 0,rxbuf0,rxcursor0 checkSendBuffer 1,rxbuf1,rxcursor1 checkSendBuffer 2,rxbuf2,rxcursor2 checkSendBuffer 3,rxbuf3,rxcursor3 tst infofunc brne SHOW_INFO rjmp MAIN SHOW_INFO: mov temp,infofunc cpi temp,'?' breq show_version cpi temp,'s' breq show_status showMessage MSG_ERROR clr infofunc rjmp MAIN SHOW_VERSION: showMessage MSG_INFO clr infofunc rjmp MAIN SHOW_STATUS: ldi yh,8 mov yl,errstat STATUS_LOOP: sbic USR,UDRE rjmp SEND_STAT rcall CHECK_INPUTS rjmp STATUS_LOOP SEND_STAT: lsl yl brcc STAT_0 ldi temp,'1' rjmp STAT_SHOW STAT_0: ldi temp,'0' STAT_SHOW: out UDR,temp dec yh brne STATUS_LOOP clr infofunc clr errstat STATUS_LOOP2: sbic USR,UDRE rjmp SEND_RET rcall CHECK_INPUTS rjmp STATUS_LOOP2 SEND_RET: ldi temp,$0d out UDR,temp ;send 0D rjmp MAIN ;*************************************************************************************************** ; Check char avail and put into receive buffers ;*************************************************************************************************** CHECK_INPUTS: checkInputMac 4,rxchar0,rxcursor0,rxbuf1,rxbuf0 checkInputMac 5,rxchar1,rxcursor1,rxbuf2,rxbuf1 checkInputMac 6,rxchar2,rxcursor2,rxbuf3,rxbuf2 checkInputMac 7,rxchar3,rxcursor3,rxbufend,rxbuf3 ret