Shop OBEX P1 Docs P2 Docs Learn Events
Trouble with serial receive code — Parallax Forums

Trouble with serial receive code

David BetzDavid Betz Posts: 14,516
edited 2015-02-18 18:56 in Propeller 1
Can someone spot the bug in this simple serial receive function? What I'm wondering about is if I have to wait half a bit time after sampling the stop bit.
' receive a byte
' output:
'    rxdata is the byte received
rxbyte                  waitpne rxmask, rxmask      ' wait for a start bit
                        mov     rxcnt, bitticks     ' wait until half way through the bit time
                        shr     rxcnt, #1
                        add     rxcnt, bitticks
                        add     rxcnt, cnt
                        mov     rxbits, #9          ' receive 8 data bits and the stop bit
:next                   waitcnt rxcnt, bitticks     ' wait until the center of the next bit
                        test    rxmask, ina wc      ' sample the rx pin
                        rcr     rxdata, #1          ' add to the byte being received
                        djnz    rxbits, #:next
                        shr     rxdata, #32-9       ' shift the received data to the low bits
                        and     rxdata, #$ff        ' mask off the stop bit
rxbyte_ret              ret

Comments

  • Cluso99Cluso99 Posts: 18,069
    edited 2015-02-15 20:23
    David,
    What your code is actually doing is waiting 1.5 clock times after cnt+16. The +16 is the time the instructions execute after the waitpne.
    It would be better if you sampled the cnt immediately after the waitpne. Alternately adjust the rxcnt accordingly.
    BTW This only applies for high speeds. At lower speeds it is irrelevant.

    Also, you can sample and compile the last bit (8th bit) and then check that the stop bit is present at the next bit sample time.

    As for the bug, well you are adding rxcnt which is 1.5 bit times each time, rather than 1 bit time (at the :next label), so you sample is sliding into the next bit.
  • David BetzDavid Betz Posts: 14,516
    edited 2015-02-15 20:31
    I don't think I understand. Doesn't the instruction at :next wait until CNT reaches rxcnt and then add bitticks to rxcnt in preparation for the next WAITCNT instruction? And bitticks contains the number of clock ticks in a bit time. Initially, I wait a half a bit time to get to the center of the start bit and then after that a whole bit time to get to the center of each of the data bits and the stop bit. Actually, this code is mostly stolen from FDS.
  • Cluso99Cluso99 Posts: 18,069
    edited 2015-02-15 20:39
    David Betz wrote: »
    I don't think I understand. Doesn't the instruction at :next wait until CNT reaches rxcnt and then add bitticks to rxcnt in preparation for the next WAITCNT instruction? And bitticks contains the number of clock ticks in a bit time. Initially, I wait a half a bit time to get to the center of the start bit and then after that a whole bit time to get to the center of each of the data bits and the stop bit. Actually, this code is mostly stolen from FDS.
    You are of course correct. My mistake.

    Here is code I wrote for one of the P2 versions. Its unravelled code because it is being run under an LMM interpreter, but the basics the same.
    ''-------[ Rx: Receive a char ]------------------------------------------------ <--- receive char --->
    ''_HubRx
    '' On Entry:
    ''      lmm_f = -not used-                              ' mode:
    ''      lmm_x = -anything-                              ' value:
    '' Call Format:
    ''             'FCALL   SP++, @_HubRx                   ' \                     < call: receive char>
    ''               wrlong  lmm_pc, lmm_sp                 ' | PUSH PC
    ''               add     lmm_sp, #4                     ' | SP++
    ''               rdlong  lmm_pc, lmm_pc                 ' | CALL...
    ''               long    @_HubRx                        ' / ...PC = ADDR
    '' On Return:
    ''      lmm_f = -same-                                  ' mode:   (unchanged)
    ''      lmm_x = char                                    ' char:   input char
    ''--------------------------------------------------------------------------------------------------
    _HubRx                                                  '                       <--- receive char --->
    '               ----------------------------------------        
    :wait1          getp    #_rxpin                 wc      ' ensure stop/idle
            if_nc   sub     lmm_pc, #(($+1)-:wait1)*4       '> br back:  (not stop/idle)
    :wait0          getp    #_rxpin                 wc      ' wait for start                \ start =0 edge 
            if_c    sub     lmm_pc, #(($+1)-:wait0)*4       '> br back:  (stop/idle)        /
                    getcnt  lmm_w                           ' get initial time              \ setup 0.5 bit time
                    mov     lmm_x, lmm_bittime              ' bit period                    |
                    shr     lmm_x, #1                       ' 0.5 bit period                |
                    add     lmm_w, lmm_x                    ' add 0.5 bit period to time    |
                    waitcnt lmm_w, lmm_bittime              ' center of start bit           /
                    getp    #_rxpin                 wc      ' check start bit =0            \ verify start =0
            if_c    sub     lmm_pc, #(($+1)-:wait1)*4       '> br back:  (invalid)          /
                    mov     lmm_x, #0                       ' clear char
                    waitcnt lmm_w,lmm_bittime               ' wait until bit period elapsed /
                    getp    #_rxpin                 wc      ' rx pin into c                 \ b0
                    rcr     lmm_x, #1                       ' accumulate bit                |
                    waitcnt lmm_w,lmm_bittime               ' wait until bit period elapsed /
                    getp    #_rxpin                 wc      ' rx pin into c                 \ b1
                    rcr     lmm_x, #1                       ' accumulate bit                |
                    waitcnt lmm_w,lmm_bittime               ' wait until bit period elapsed /
                    getp    #_rxpin                 wc      ' rx pin into c                 \ b2
                    rcr     lmm_x, #1                       ' accumulate bit                |
                    waitcnt lmm_w,lmm_bittime               ' wait until bit period elapsed /
                    getp    #_rxpin                 wc      ' rx pin into c                 \ b3
                    rcr     lmm_x, #1                       ' accumulate bit                |
                    waitcnt lmm_w,lmm_bittime               ' wait until bit period elapsed /
                    getp    #_rxpin                 wc      ' rx pin into c                 \ b4
                    rcr     lmm_x, #1                       ' accumulate bit                |
                    waitcnt lmm_w,lmm_bittime               ' wait until bit period elapsed /
                    getp    #_rxpin                 wc      ' rx pin into c                 \ b5
                    rcr     lmm_x, #1                       ' accumulate bit                |
                    waitcnt lmm_w,lmm_bittime               ' wait until bit period elapsed /
                    getp    #_rxpin                 wc      ' rx pin into c                 \ b6
                    rcr     lmm_x, #1                       ' accumulate bit                |
                    waitcnt lmm_w,lmm_bittime               ' wait until bit period elapsed /
                    getp    #_rxpin                 wc      ' rx pin into c                 \ b7
                    rcr     lmm_x, #1                       ' accumulate bit                |
                    waitcnt lmm_w,lmm_bittime               ' wait until bit period elapsed /
                    getp    #_rxpin                 wc      ' rx pin into c                 \ verify stop bit =1
            if_nc   sub     lmm_pc, #(($+1)-:wait1)*4       '> br back:  (invalid)          /
                    shr     lmm_x, #24                      ' shift char into b7..0
    '               ----------------------------------------        
    '              'JUMP    @_HubReturn                     ' \                     <jump>
                     rdlong  lmm_pc, lmm_pc                 ' | JUMP...
                     long    @_HubReturn                    ' / ...PC = ADDR        <returns to calling routine>
    '---------------------------------------------------------------------------------------------------
    
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-15 20:49
    David Betz wrote: »
    Can someone spot the bug in this simple serial receive function? What I'm wondering about is if I have to wait half a bit time after sampling the stop bit.
    ' receive a byte
    ' output:
    '    rxdata is the byte received
    rxbyte                  waitpne rxmask, rxmask      ' wait for a start bit
                            mov     rxcnt, bitticks     ' wait until half way through the bit time
                            shr     rxcnt, #1
                            add     rxcnt, bitticks
                            add     rxcnt, cnt
                            mov     rxbits, #9          ' receive 8 data bits and the stop bit
    :next                   waitcnt rxcnt, bitticks     ' wait until the center of the next bit
                            test    rxmask, ina wc      ' sample the rx pin
                            rcr     rxdata, #1          ' add to the byte being received
                            djnz    rxbits, #:next
                            shr     rxdata, #32-9       ' shift the received data to the low bits
                            and     rxdata, #$ff        ' mask off the stop bit
    rxbyte_ret              ret
    

    You really need to precalculate the half-bit timing so that you are ready to apply it after detecting the start bit otherwise you will have timing errors at higher speeds.
    Here is the high-speed code I use in Tachyon.
    [font=courier]
    DAT
    { *** SERIAL RECEIVE *** }
    
    '**************************************** SERIAL RECEIVE ******************************************
    
    { This is a dedicated serial receive routine that runs in it's own cog }
    
    DAT
                            long 0[2]	' read and write	' this hub space is used for rxwr & rxrd at runtime
    rxbuffers					' hub ram gets reused as the receive buffer
                            	org
    
    HSSerialRx			mov	rxwr,#0	' init write index
     			wrword	rxwr,hubrxwr 	' clear rxrd in hub
     			wrword	rxwr,hubrxrd 	' make rxwr = rxrd
    			mov	stticks,rxticks	' calculate start bit timing
     			shr	stticks,#1	' half a bit time less
     			sub	stticks,#4	' compensate timing - important at high speeds
     			mov	breakcnt,#200	' reset break count
    
    
    receive			mov	rxcnt,stticks	' Adjusted bit timing for start bit
     			waitpne	rxpin,rxpin	' wait for a low = start bit
    '
    ' START BIT DETECTED
    '                                                        	' time sample for middle of start bit
     			add	rxcnt,cnt           	' uses special start bit timing
     			waitcnt	rxcnt,rxticks
     			test	rxpin,ina       wz      	' sample middle of start bit
    rxcond2		if_nz	jmp	#receive                	' restart if false start otherwise bit time from center
    
    '
    ' START bit validated
    ' Read in data bits lsb first
    ' No point in looping as we have plenty of code to play with
    ' and inlining (don't call) and unrolling (don't loop) can lead to higher receive speeds
    '
     			waitcnt	rxcnt,rxticks	' wait until middle of first data bit
     			test	rxpin,ina wc	' sample bit 0
     			muxc	rxdata,#01	' and assemble rxdata
     			waitcnt	rxcnt,rxticks
     			test	rxpin,ina wc	' sample bit 1
     			muxc	rxdata,#02
     			waitcnt	rxcnt,rxticks
     			test	rxpin,ina wc	' sample bit 2
     			muxc	rxdata,#04
     			waitcnt	rxcnt,rxticks
     			test	rxpin,ina wc	' sample bit 3
     			muxc	rxdata,#08
     			waitcnt	rxcnt,rxticks
     			test	rxpin,ina wc	' sample bit 4
     			muxc	rxdata,#$10
     ' data bit 5
    			waitcnt	rxcnt,rxticks
     			test	rxpin,ina wc	' sample bit 5
     			muxc	rxdata,#$20
     			mov	X1,rxbuf	' squeeze in some overheads, calc write pointer
     			add	X1,rxwr	        ' X points to buffer location to store
    ' data bit 6
     			waitcnt	rxcnt,rxticks
     			test	rxpin,ina wc	' sample bit 6
     			muxc	rxdata,#$40
     			add	rxwr,#1	        ' update write index
     			and	rxwr,wrapmask
    ' last data bit 7
     			waitcnt	rxcnt,rxticks
     			test	rxpin,ina wc	' sample bit 7
     			muxc	rxdata,#$80
     			wrbyte	rxdata,X1	' save data in buffer - could take 287.5ns worst case
    ' stop bit
    stopins			waitcnt	rxcnt,rxticks	' check stop bit early (need to detect errors and breaks)
     			test	rxpin,ina wc	' sample stop bit
    		if_nc	jmp	#frmerror	' framing error - check for break - disregard timing now
    		if_c	wrword	rxwr,hubrxwr	' update hub index for code reading the buffer if all good
    			wrbyte	rxdata,lkptr
     			jmp	#receive
    
    ' Framing error - check if it's a null character as it may be part of a break condition
    '
    frmerror
    			sub	rxwr,#1
     			cmp	rxdata,#0 wz	'if it's a null it could be part of a break
     		if_nz	mov	breakcnt,#200	'reset the break count (compromise here to keep main loop tight)
    		if_nz	jmp	#receive	'ignore normal framing error
    			or	outa,rxpin
     			or	dira,rxpin	'unintentional? make sure the input is not floating
     			mov	rxcnt,#16
    			djnz	rxcnt,$
     			andn	dira,rxpin	'restore input and delay
     			mov	rxcnt,#16
     			djnz	rxcnt,$
     			test	rxpin,ina wz	'if it's still low then it is being intentionally driven
     		if_nz	jmp	#receive	'ignore floating input
     			djnz	breakcnt,#receive
    aboot
     			mov	rxcnt,#$80
     			clkset	rxcnt	' reboot[/font]
    
  • David BetzDavid Betz Posts: 14,516
    edited 2015-02-15 20:58
    Thanks for the high speed code but do you think my code is likely to give me trouble at low speeds like 115200 baud?
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-15 21:10
    David Betz wrote: »
    Thanks for the high speed code but do you think my code is likely to give me trouble at low speeds like 115200 baud?

    There shouldn't be a problem as far as I can see but it's what you do after you receive the data that I'm not sure about. Will it be ready for the next character?
  • pjvpjv Posts: 1,903
    edited 2015-02-15 21:34
    David Betz wrote: »
    Can someone spot the bug in this simple serial receive function? What I'm wondering about is if I have to wait half a bit time after sampling the stop bit.

    David,

    The code looks perfect to me, although I have not tested it. That last sample, number nine, falls in the middle of the stop bit, and that gives you up to half a bit period to deal with the received byte before you need to start searching for the start bit of the following character.

    Should work fine up to a Megabit, possibly two. Do some cycle counting to get the exact maximum.

    Cheers,

    Peter (pjv)
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-15 22:09
    pjv wrote: »
    David,

    The code looks perfect to me, although I have not tested it. That last sample, number nine, falls in the middle of the stop bit, and that gives you up to half a bit period to deal with the received byte before you need to start searching for the start bit of the following character.

    Should work fine up to a Megabit, possibly two. Do some cycle counting to get the exact maximum.

    Cheers,

    Peter (pjv)

    It's easy enough to get these simple loops working for a single character at these much higher baud rates. The trick is to get them to buffer it and be ready for the next. This is where this simple loop might have a problem even at 115.2k but we don't know what it has to do when it does a return.
  • jmgjmg Posts: 15,173
    edited 2015-02-15 22:14
    David Betz wrote: »
    What I'm wondering about is if I have to wait half a bit time after sampling the stop bit.
    Wait until what ?
    Usually the Stop bit is sampled Mid bit (tho that can be nudged left, if time to deal with the byte is tight)
    Ideally, you start looking for the START bit at the MID Stop bit, as that gives the highest theoretical baud tolerance

    However, if you begin testing for Start edge at 0.75 of Stop bit, you still have 0.25 bit time of tolerance, in 10 bits or 2.5% (budget total for both ends)
    If you delay till 90% of stop bit, you have 0.1 bit time or 1.0%, so you can see the effect
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-02-15 22:26
    David,

    Here's another simple serial loop that works like the others and may help you -- I tend to write code in the simplest, most obvious fashion that I can. To be honest, unrolling it was inspired by Peter's code.
    receive                 mov     rxwork, #0                      ' clear work var
                            mov     rxtimer, rxbit1x5               ' set timer to 1.5 bits
                            
    waitstart               waitpne rxmask, rxmask                  ' wait for falling edge
                            add     rxtimer, cnt                    ' sync with system counter
    
                            { unrolled for best speed }
                            
    rxbyte                  waitcnt rxtimer, rxbit1x0               ' wait for middle of bit
                            test    rxmask, ina             wc      ' rx --> c  
                            muxc    rxwork, #%0000_0001             ' c --> bit0  
                            
                            waitcnt rxtimer, rxbit1x0
                            test    rxmask, ina             wc      ' rx --> c  
                            muxc    rxwork, #%0000_0010             ' c --> bit1 
    
                            waitcnt rxtimer, rxbit1x0
                            test    rxmask, ina             wc      ' rx --> c  
                            muxc    rxwork, #%0000_0100             ' c --> bit2 
                            
                            waitcnt rxtimer, rxbit1x0
                            test    rxmask, ina             wc      ' rx --> c  
                            muxc    rxwork, #%0000_1000             ' c --> bit3 
    
                            waitcnt rxtimer, rxbit1x0
                            test    rxmask, ina             wc      ' rx --> c  
                            muxc    rxwork, #%0001_0000             ' c --> bit4 
                            
                            waitcnt rxtimer, rxbit1x0
                            test    rxmask, ina             wc      ' rx --> c  
                            muxc    rxwork, #%0010_0000             ' c --> bit5 
    
                            waitcnt rxtimer, rxbit1x0
                            test    rxmask, ina             wc      ' rx --> c  
                            muxc    rxwork, #%0100_0000             ' c --> bit6 
                            
                            waitcnt rxtimer, rxbit1x0
                            test    rxmask, ina             wc      ' rx --> c  
                            muxc    rxwork, #%1000_0000             ' c --> bit7 
    
                            waitpeq rxmask, rxmask                  ' wait for stop bit
    
    putrxbuf                rdlong  t1, rxheadpntr                  ' t1 := rxhead
                            add     t1, rxbufpntr                   ' t1 := rxbuf[rxhead]
                            wrbyte  rxwork, t1                      ' rxbuf[rxhead] := rxwork
                            sub     t1, rxbufpntr                   ' t1 := rxhead 
                            add     t1, #1                          ' inc t1
                            and     t1, #BUF_MASK                   ' rollover if needed
                            wrlong  t1, rxheadpntr                  ' rxhead := t1
    
                            jmp     #receive
    
  • Cluso99Cluso99 Posts: 18,069
    edited 2015-02-15 23:11
    The biggest point to note, as others have said, is to ensure you can get the rx routine back to waitpne before the next start bit edge. Any delay will put the sampling beyond the mid bit, and will possibly cause a problem as successive characters are received if the timing is not spot-on. But it depends on the actual timing error between the transmitter and receiver.
  • pjvpjv Posts: 1,903
    edited 2015-02-15 23:15
    It's easy enough to get these simple loops working for a single character at these much higher baud rates. The trick is to get them to buffer it and be ready for the next. This is where this simple loop might have a problem even at 115.2k but we don't know what it has to do when it does a return.

    Peter,

    See my code snippets in the "extra stop bit" thread. It dumps to hub at 5 Mega bits per second.... all day long.

    I'll try to find a bit of time to link it with a Spin control program in the next while for a demonstration.

    Cheers,

    Peter (pjv)
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-15 23:28
    pjv wrote: »
    Peter,

    See my code snippets in the "extra stop bit" thread. It dumps to hub at 5 Mega bits per second.... all day long.

    I'll try to find a bit of time to link it with a Spin control program in the next while for a demonstration.

    Cheers,

    Peter (pjv)

    This was more of a comment on your comment about how David's code should work fine at megabit speeds. So the point was it all depends on whether it's ready for the next character.

    I have 10Mbit code too that transmits and receives continually but like the 5M code it is locked to that rate (and CLKFREQ) so it's not really a general-purpose receive routine.
  • ksltdksltd Posts: 163
    edited 2015-02-18 08:05
    The OBEX assembly language drivers all have a few foibles.

    Start of Receive
    It's important to not start the Rx process if the Rx wire isn't continuously high for 10 bit times. Failing to do this can cause the receiver to lock onto the middle of a character and be out of sync with the incoming bit stream for a very long time. This need only be done when the driver is started ...

    End of Receive
    There's no reason to wait until the middle of the stop bit unless you want to detect and report framing errors. Since none of the OBEX code detects framing errors, the best implementation is to sample the eighth bit and then simply wait for the Rx wire to go high. If the eighth bit was a one, you can leave in the middle of that bit time. If it was a zero, you need to wait only until the leading edge of the stop bit arrives.

    Doing this, you buy back either 1/2 bit time or 1 1/2 bit times for the rest of your implementation to handle the received byte and get back to looking for a start bit. Turns out that's enough time to do things like maintain a CRC16 without any added latency, etc.

    Transmit
    On the transmit side, the implementation sends two stop bits, which decreases throughput by 10%. There's no real rationale for this - the receiver can either keep up or it can't.
  • David BetzDavid Betz Posts: 14,516
    edited 2015-02-18 16:45
    Thanks for your advice. I did finally get my code working and I got rid of the second stop bit on transmit. I haven't done what you suggest for optimizing receive though. I've attached the code I ended up with. I'm sure it isn't optimal by any means but it works for me!

    pkt.zip
  • jmgjmg Posts: 15,173
    edited 2015-02-18 16:58
    ksltd wrote: »
    The OBEX assembly language drivers all have a few foibles.
    ....
    Transmit
    On the transmit side, the implementation sends two stop bits, which decreases throughput by 10%. There's no real rationale for this - the receiver can either keep up or it can't.

    On a system where TxMIT is master, 2 stop bits can buy some more system margin in streaming data cases.
    However, 2 Stops bits on a slave transmit seems a very bad idea where incoming master Rx is 1 stop bit.
    There is not enough time to reply to every byte, and designs that expect duplex replies would fail.

    If the remote unit needs (mostly) 2 stop bits, then send with 2 stop bits, and TX replies will usually pace off the Rx with 1 added stop bit. If the baud rates are not exactly matched, there will be rare 2+1/-1 stop bits to keep the average data rates matched.
  • ksltdksltd Posts: 163
    edited 2015-02-18 17:37
    The terms master and slave aren't applicable to asynchronous serial protocol. These things are simply streaming transmit and receive implementations with 8 data bits and no parity.

    You might have some protocol built on top of what's provided, but if your protocol has real-time limitations, you can't implemented it safely on these drivers as you can't really determine what's going on with the wire in a meaningful, reliable way. Your only choice is to modify the driver. If modifying it by adding a 2nd stop bit works for you, then have at it.

    But the simple fact remains that the OBEX transmit implementations waste 10% of the available bandwidth at any baud rate because there's an 11 where there ought to be a 10.
  • jmgjmg Posts: 15,173
    edited 2015-02-18 17:46
    ksltd wrote: »
    The terms master and slave aren't applicable to asynchronous serial protocol. These things are simply streaming transmit and receive implementations with 8 data bits and no parity.
    Call them what you like, but master means the one determining the data flow, that the slave has to keep up with.
    The problems arise when the baud rates are not exactly the same, and sustained high throughputs stress the details of the implementation.

    As Micros, and PCs get faster, the chances of hitting sustained high throughput goes up.
    ksltd wrote: »
    . Your only choice is to modify the driver. If modifying it by adding a 2nd stop bit works for you, then have at it.
    I think #16 talks about removing stop bits to fix his issues, not adding :
    " I got rid of the second stop bit on transmit."
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-18 17:49
    ksltd wrote: »
    The OBEX assembly language drivers all have a few foibles.

    Start of Receive
    It's important to not start the Rx process if the Rx wire isn't continuously high for 10 bit times. Failing to do this can cause the receiver to lock onto the middle of a character and be out of sync with the incoming bit stream for a very long time. This need only be done when the driver is started ...

    End of Receive
    There's no reason to wait until the middle of the stop bit unless you want to detect and report framing errors. Since none of the OBEX code detects framing errors, the best implementation is to sample the eighth bit and then simply wait for the Rx wire to go high. If the eighth bit was a one, you can leave in the middle of that bit time. If it was a zero, you need to wait only until the leading edge of the stop bit arrives.

    Doing this, you buy back either 1/2 bit time or 1 1/2 bit times for the rest of your implementation to handle the received byte and get back to looking for a start bit. Turns out that's enough time to do things like maintain a CRC16 without any added latency, etc.

    Transmit
    On the transmit side, the implementation sends two stop bits, which decreases throughput by 10%. There's no real rationale for this - the receiver can either keep up or it can't.

    If you are getting picky with the obex then join the queue but then again the fact that we have an obex should be appreciated as a lot of people have contributed their time and resources. Far better to contribute a better object and make it a better obex.

    However some serial objects don't seem to include false start bit rejection just as UARTs do, nor do they detect framing errors which requires that half-time sample into the stop bit. I also use framing errors to detect break sequences as every time I have a framing error and data of zero I count down until I accept it as a break sequence and in the case of a lot of my systems this will reset the Prop which is ideal for forcing a reboot remotely. There's also the timing errors at higher speeds and the inability of many objects to cope with full throughput (back-to-back, no extra stop bits) at those higher speeds.

    But for the most part what's in the obex is what most people mostly need. Some other features that are useful are things like gap detection (for MODBUS etc), parity, 9-bit multidrop mode, runtime selectable buffers and sizes, RS485 support etc. The fact is that I have written drivers with a lot of these features and have not contributed to the obex which is something I have been intending to correct. It just seems that everybody picks FDS each and everytime, if I type in "full duplex serial" into the obex search there it is at the top, and there are no reviews or star ratings to give the unwary any feedback. Besides, a lot of these drivers are loaded up with conversion utilities which IMO should be common to all stream I/O. In Tachyon I just simply select the stream input/output device whether it be an LCD or VGA or printer or LED matrix etc and all the formatting operations and control sequences (rather than explicit methods) are common so it still works the same if I change the output device.
    LCD CLS PRINT" CLOCK FREQUENCY IS " CLKFREQ PRINT CR
    LEDS CLS PRINT" CLOCK FREQUENCY IS " CLKFREQ PRINT CR
    CON CLS PRINT" CLOCK FREQUENCY IS " CLKFREQ PRINT CR

    I think the use of explicit methods such as dec hex str newline etc etc in each and every Spin driver is ugly.
  • David BetzDavid Betz Posts: 14,516
    edited 2015-02-18 17:49
    jmg wrote: »
    I think #16 talks about removing stop bits to fix his issues, not adding :
    " I got rid of the second stop bit on transmit."
    Well, to be fair, removing the second stop bit didn't get rid of any issues. I just found that it didn't seem to be necessary for my application. The problems I was having were elsewhere. :-)
  • jmgjmg Posts: 15,173
    edited 2015-02-18 18:28
    David Betz wrote: »
    ... The problems I was having were elsewhere. :-)

    You might want to elaborate, so others reading this thread in the future get information that may help their case.
  • jmgjmg Posts: 15,173
    edited 2015-02-18 18:56
    .... There's also the timing errors at higher speeds and the inability of many objects to cope with full throughput (back-to-back, no extra stop bits) at those higher speeds.

    But for the most part what's in the obex is what most people mostly need. Some other features that are useful are things like gap detection (for MODBUS etc), parity, 9-bit multidrop mode, runtime selectable buffers and sizes, RS485 support etc. The fact is that I have written drivers with a lot of these features and have not contributed to the obex which is something I have been intending to correct. ....
    The code you have pasted looks very widely useful.

    I've been running some numbers on higher Baud rates, where the Prop talks to something other than another Prop.
    One common MCU Internal Osc clock is 24.5MHz, and another is 48MHz. 3~6MBd look practical.

    A better fit for 24.5MHz is 3.076923MBd, which gives 0.460% error. ( 26 Prop SysClks per bit )

    For those cases where a fractional Cycle is ideal, it may be possible to have a compile-time baud ?
    (no runtime param), and use waitcnt,#immedA ..waitcnt,#immedB where immedA, immedB vary by 1 but average to the better fit - sample points should .all be within 1 sysclk of ideal.
Sign In or Register to comment.