Oznog said:I've seen a number of routines that do bit banging on a serial port. But I don't get how they handle framing problems. There's an assumption that the code can start looking for the start bit at the start of the loop. If the code starts the loop in the middle of a byte though this won't work. First 0 in the bus it'll assume is a START bit. There's a good chance a 1 won't happen in the window it will look for the STOP bit in so it may realize there's a framing error.
How does the bit banger figure out what the start of the byte's framing is?
Nigel Goodwin said:The whole point of asyncronous comms is that you MUST detect a clear start bit - if not the whole thing fails, this isn't a 'bit banging' problem, it occurs with hardware UART's as well. There are a number of simple steps you can take to help reject incorrect bytes, for a start test the STOP bit, if this is wrong, then the byte hasn't been read correctly. Secondly, use the parity bit, this will help detect some further errors.
If you're trying to do wireless comms?, then RS232 is completely the wrong choice, wireless schemes (such as Manchester coding) add special start sequences to allow syncronisation of the receiver.
Oznog said:Or do we just kick the bit-time state counter over one every time it detects a bad STOP bit, until it starts consistently finding a 1 in the STOP bit time? That does seem like the way to do it.
Nigel Goodwin said:The answer is simple (as far your questions here are concerned), you simply make sure you don't miss the start bit!. Presumably though this is related to your request for multiple simultaneous serial inputs?, that makes it 'difficult'.
Oznog said:How does the hardware USART figure it out? I haven't seen an explanation.
Nigel Goodwin said:You need to think more generally, and not just on the receive side - it's the transmit side which makes it easily possible.
1) Don't send continuous data, a gap of more than one word should allow syncronisation to occur.
2) Use handshaking.
motion said:A sentence is framed by a '$' character in the beginning and a <CR><LF> sequence at the end. Use this to check if you have a valid sentence in case the async port loses bit synchronism. Eventually, the receiver will recover synchronism and you should be able to get a properly framed sentence.
If you feel you can do a simpler job than checking for a '$' and a <CR>,<LF> sequence, I don't understand what's all the fuss about the start bit.Detecting a framing error would probably not need to go to that level. First the STOP bit will be wrong more or less half the time, if you somehow don't see this then you can detect some nonsense ASCII codes (not alphanumeric, punctuation, space, <CR>, or <LF>), if you somehow
don't see that then the sentence format will be wrong too.
Pommie said:Note that the stop bit doesn't exist, it is just a gap to allow things to synchronize. Also note if all bits were 1 then the data would be a flat line.
motion said:I don't understand what's all the fuss about the start bit.
Pommie said:I just checked my interupt driven bit banger and the worst case path is only 17 cycles long. ~~~~ I could modify my code to handle multiple channels if you like and post it.
Mike.
Mike said:Is that 17 instruction cycles for 3X bit rate interrupt driven RX only code? If so, that's incredible... I'd very much like to see your code Sir...
RecSkips equ 20h
InByte equ 21h
Cache equ 22h
TransferFlags equ 23h
#define RS232In PORTB,2
decfsz RecSkips,F
goto DoneRS232
btfss TransferFlags,b_receiving
goto get_start_bit
bsf STATUS,C
btfss b_RS232In
bcf STATUS,C
rrf InByte,F
movlw 3
movwf RecSkips
btfss STATUS,C
goto DoneRS232
movf InByte,W
movwf Cache
bsf TransferFlags,b_byte_available
bcf TransferFlags,b_receiving
goto DoneRS232
get_start_bit incf RecSkips,F; set to 1
btfsc b_RS232In
goto DoneRS232
movlw 4
movwf RecSkips
bsf TransferFlags,b_receiving
movlw 80h
movwf InByte
DoneRS232
ReceiveChannel Macro chan
rrf PortTemp,F
decfsz RecSkips+chan,F
goto DoneRS232#v(chan)
btfss b_receiving,chan
goto g_strt#v(chan)
rrf InByte+chan,F
movlw 3
movwf RecSkips+chan
btfss STATUS,C
goto DoneRS232#v(chan)
movf InByte+chan,W
movwf cache+chan
bsf b_byte_avail,chan
bcf b_receiving,chan
goto DoneRS232#v(chan)
g_strt#v(chan) incf RecSkips+chan,F; set to 1
btfsc STATUS,C
goto DoneRS232#v(chan)
movlw 4
movwf RecSkips+chan
bsf b_receiving,chan
movlw 80h
movwf InByte+chan
DoneRS232#v(chan)
endm
bcf PIR1,CCP1IF; reset special event trigger interupt
movfw PORTB; read all channels at once
movwf PortTemp
ReceiveChannel 0
rrf PortTemp,F; skip bit 1
rrf PortTemp,F; skip bit 2
ReceiveChannel 1
ReceiveChannel 2
ReceiveChannel 3
ReceiveChannel 4
ReceiveChannel 5
Mike said:I've been using 3X bit rate interrupts for full duplex 9600 baud bit banged serial I/O awhile now so I appreciate your small fast algorithm... My 12F683 and 16F819 full duplex 9600 baud serial I/O demos with 16-byte circular RX and TX buffers use 34/35 instruction cycles average of the 69 instruction cycles between interrupts (using the 8-MHz INTOSC clock) but now I think I'll take a stab at trying to reduce that 50% processing 'overhead'...
Take care... Happy Holidays... Regards, Mike
Pommie said:Mike said:I've been using 3X bit rate interrupts for full duplex 9600 baud bit banged serial I/O awhile now so I appreciate your small fast algorithm... My 12F683 and 16F819 full duplex 9600 baud serial I/O demos with 16-byte circular RX and TX buffers use 34/35 instruction cycles average of the 69 instruction cycles between interrupts (using the 8-MHz INTOSC clock) but now I think I'll take a stab at trying to reduce that 50% processing 'overhead'...
Take care... Happy Holidays... Regards, Mike
That's wierd, the code I posted was from a project that was on a 16F819, used the internal 8MHz clock and had two 16 byte circular fifo buffers. I only had it running at 4800 baud as my background code was processor intensive. If your interested, I posted the fifo code In this thread .
Happy Holidays
Mike.
;******************************************************************
;* *
;* Companion Put232 and Get232 subroutines *
;* *
;******************************************************************
;
; Put232 - enter with character to be sent in W
; - performs TXBUFF 'load buffer' operation
;
Put232 movwf TXCHAR ; save character |B0
Pwait incf TX_WPTR,W ; W = WPTR + 1 |B0
andlw h'0F' ; keep it in range 00..0F |B0
addlw TXBUFF ; make it in range B0..BF |B0
movwf PTRTMP ; save here temporarily |B0
xorwf TX_RPTR,W ; buffer full (WPTR+1=RPTR)? |B0
bz Pwait ; yes, branch, wait |B0
movf FSR,W ; get FSR |B0
movwf FSRTMP ; save it |B0
movf TX_WPTR,W ; get TX buffer Wr ptr (B0..BF) |B0
movwf FSR ; setup indirect address |B0
movf TXCHAR,W ; get character |B0
movwf INDF ; place it in TX buffer |B0
movf FSRTMP,W ; |B0
movwf FSR ; restore FSR |B0
movf PTRTMP,W ; get saved TX_WPTR+1 value |B0
movwf TX_WPTR ; update TX_WPTR |B0
movf TXCHAR,W ; restore W entry data |B0
return ; |B0
;
;******************************************************************
;
; Put232 - enter with character to be sent in W
; - performs TXBUFF 'load buffer' operation
;
; vars - TXCHAR, TX_WPTR, TX_RPTR, TXBUFF, FSRTMP
; SFRs - FSR
;
Put232 movwf TXCHAR ; save character |B0
movf FSR,W ; |B0
movwf FSRTMP ; save FSR context |B0
movf TX_WPTR,W ; |B0
movwf FSR ; setup indirect address |B0
movf TXCHAR,W ; get character |B0
movwf INDF ; place it in TXBUFF |B0
movf FSRTMP,W ; |B0
movwf FSR ; restore FSR context |B0
Pwait incf TX_WPTR,W ; W = WPTR+1 |B0
andlw h'0F' ; make it 00..0F |B0
addlw TXBUFF ; make it B0..BF |B0
xorwf TX_RPTR,W ; buffer full (WPTR+1=RPTR)? |B0
bz Pwait ; yes, branch, wait |B0
xorwf TX_RPTR,W ; restore WPTR+1 value in W |B0
movwf TX_WPTR ; update TXBUFF WR pointer |B0
movf TXCHAR,W ; restore W entry data |B0
return ; |B0
;
Mike said:Code:;****************************************************************** ; ; Put232 - enter with character to be sent in W ; - performs TXBUFF 'load buffer' operation ; ; vars - TXCHAR, TX_WPTR, TX_RPTR, TXBUFF, FSRTMP ; SFRs - FSR ; Put232 movwf TXCHAR ; save character |B0 movf FSR,W ; |B0 movwf FSRTMP ; save FSR context |B0 movf TX_WPTR,W ; |B0 movwf FSR ; setup indirect address |B0 movf TXCHAR,W ; get character |B0 movwf INDF ; place it in TXBUFF |B0 movf FSRTMP,W ; |B0 movwf FSR ; restore FSR context |B0 Pwait incf TX_WPTR,W ; W = WPTR+1 |B0 andlw h'0F' ; make it 00..0F |B0 addlw TXBUFF ; make it B0..BF |B0 xorwf TX_RPTR,W ; buffer full (WPTR+1=RPTR)? |B0 bz Pwait ; yes, branch, wait |B0 [color=red]If an interrupt happens here[/color] xorwf TX_RPTR,W ; restore WPTR+1 value in W |B0 movwf TX_WPTR ; update TXBUFF WR pointer |B0 movf TXCHAR,W ; restore W entry data |B0 return ; |B0 ;
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?