;****************************************************************************** ;Author: Frank F. Hitzel, Braunschweig, Germany (2004) ;This software is distributed under the terms of the GNU General Public License ;Multiplexer, S version ;Framing Error bug correction by Adolf Schwarz ;****************************************************************************** .include "2313def.inc" .MACRO showMessage ldi Zl,low(@0 << 1) ;show error message INFO_LOOP: sbic USR,UDRE rjmp DO_SEND rjmp INFO_LOOP DO_SEND: lpm inc ZL mov temp,r0 out UDR,temp cpi temp,$0d brne INFO_LOOP .ENDMACRO .LISTMAC 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 =15 ;**************************** RAM .dseg .org $60 ;ramstart rxchar0: .BYTE 1 rxcursor0: .BYTE 1 ;**************************** Code .cseg .def rxreg0 =r1 .def txreg =r5 .def status_save =r6 ;status save register for interrupt routines .def txchar =r8 ;contains next char to be sent .def rxcnt0 =r9 .def txcnt =r13 .def infofunc =r14 .def temp =r16 .def temp2 =r17 .def rxwait0 =r18 .def active_output =r19 ;contains active output as bit of the corresponding output pin .def active_input =r20 ;contains active output as bit of the corresponding output pin .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 MultiplexerS 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 ; in tim_temp,UDR 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) ; in tim_temp,UDR 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) ; in tim_temp,UDR 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 active_output,(1 << out0) ldi active_input,(1 << in0) out SREG,status_save reti SWITCH_ONE: ldi active_output,(1 << out1) ldi active_input,(1 << in1) out SREG,status_save reti SWITCH_TWO: ldi active_output,(1 << out2) ldi active_input,(1 << in2) out SREG,status_save reti SWITCH_THREE: ldi active_output,(1 << out3) ldi active_input,(1 << in3) 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 and tim_temp,active_input sbrc rxstat,0x0 ;are we receiving? rjmp tim_rec tst tim_temp ;start bit detected (zero)? breq tim_start ;jump to start receive rjmp tim_ret TIM_STOP: tst tim_temp ;check stop bit brne tim_rec_ok cbr rxstat,1 or errstat,active_input ;indicate error rjmp tim_ret TIM_REC_OK: cbr rxstat,1 sbr status,1 TIM_OUT_WAIT: sbis USR,UDRE ;normally should be empty, only for security... rjmp TIM_OUT_WAIT out UDR,rxreg0 rjmp tim_ret TIM_START: sbr rxstat,1 ;set receive bit ldi tim_temp2,9 ;9 incl. stop bit mov rxcnt0,tim_temp2 ldi rxwait0,10 rjmp tim_ret TIM_REC: subi rxwait0,1 brne tim_ret dec rxcnt0 breq tim_stop com tim_temp subi tim_temp,$ff ;generate carry if bit was set ror rxreg0 ldi rxwait0,8 ;wait 8 cycles TIM_RET: 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 active_output,(1 << out0) ldi active_input,(1 << in0) ;**************************** 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: 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 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 rjmp STATUS_LOOP2 SEND_RET: ldi temp,$0d out UDR,temp ;send 0D rjmp MAIN