Shop OBEX P1 Docs P2 Docs Learn Events
Autobaud on the propeller not using special characters but total packet length. — Parallax Forums

Autobaud on the propeller not using special characters but total packet length.

Clock LoopClock Loop Posts: 2,069
edited 2013-08-07 10:32 in Propeller 1
I am trying to code an autobaud routine using total packet length, but have run into basic problems with using CNT and the fact that it rolls over.

And perhaps there is something that won't work with using total packet length.
What my code is trying to do is use waitpeq to find the first start bit.
My serial transmission is no faster than 1 transmission per second, so I am using this information to determine the total packet start and stop times.

I measure the high to low times, and if the initial one is more than 1 second, i know its my start bit time.
I then mesure the high to low times again, and if its more than 1 second, I know that the last rise to high time was my stop bit. I then do some math to calculate the bit rate knowing I have 9 total bits which include the start and stop bit.
I know i may have some obvious errors in my code, but my fundamental error is using CNT to store the rise and fall times. I know there is a better way to still maintain very accurate timings, and properly deal with the CNT roll.
(which i am not doing and thus why my code is Smile)
Pub Autobaud

Repeat
  
  Repeat
    waitpeq(|< SerInput, |< SerInput, 0) 'wait for high
    riseatime := cnt

    waitpeq(0, |< SerInput, 0) 'wait for low (startbit)
    fallatime := cnt

    If fallatime - riseatime > 80000000   
      startbit := fallatime
      Quit
    Else
      riseatime := 0   
      fallatime := 0
      
  Repeat
    waitpeq(|< SerInput, |< SerInput, 0) 'wait for high
    risebtime := cnt

    waitpeq(0, |< SerInput, 0) 'wait for low
    fallbtime := cnt

    If risebtime - fallbtime > 80000000
      stopbit := risebtime
      Quit
    Else
      risebtime := 0
      fallbtime := 0
      
  frametime := stopbit - startbit
  bitrate := frametime / 9
  abaudrate := bitrate * 80000000

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2011-12-17 22:27
      Repeat
        waitpeq(|< SerInput, |< SerInput, 0) 'wait for high
        risebtime := cnt
    
        waitpeq(0, |< SerInput, 0) 'wait for low
        fallbtime := cnt
    
        If [COLOR="red"]fallbtime - risebtime[/COLOR] > 80000000
          stopbit := risebtime
          Quit
        Else
          risebtime := 0
          fallbtime := 0
          
      frametime := stopbit - startbit
      bitrate := frametime / 9
      abaudrate := [COLOR="red"]80000000 / bitrate[/COLOR]
    
    
    This works for me, just detected 9600, not sure how high you can go with SPIN though.

    That said, wouldn't a NEG counter based approach be easier?
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-17 22:28
    Normally autoboarding uses some special characters. For example, the AT command set used "AT" and "at" to determine the baudrate plus id a parity bit was present and if so was it odd or even. The reason AT works nicely is there is the A has a 1 bit as b0 and means the start bit is "0" immediately followed by a "1" bit, so the timing can be accurately determined. Upper case or lower case was permitted and works the same.
  • Clock LoopClock Loop Posts: 2,069
    edited 2011-12-17 22:50
    kuroneko wrote: »
    
      Repeat
        waitpeq(|< SerInput, |< SerInput, 0) 'wait for high
        risebtime := cnt
    
        waitpeq(0, |< SerInput, 0) 'wait for low
        fallbtime := cnt
    
        If [COLOR=red]fallbtime - risebtime[/COLOR] > 80000000
          stopbit := risebtime
          Quit
        Else
          risebtime := 0
          fallbtime := 0
          
      frametime := stopbit - startbit
      bitrate := frametime / 9
      abaudrate := [COLOR=red]80000000 / bitrate[/COLOR]
    
    
    This works for me, just detected 9600, not sure how high you can go with SPIN though.

    Dude, you rawk, so i was just being a dummy with the details. I ALWAYS do this. I think its my trademark. lolz
    I fixed it like you suggested and it works great.
    THANKS!

    (fair warning to others, the above corrected code is missing the first half(omitted due to no error?)
    kuroneko wrote: »
    That said, wouldn't a NEG counter based approach be easier?
    Not sure, I code by the seat of my pants most of the time. I learn as i go, so you may know better methods of autobaud, improving on it, etc, even doing it in assembly to allow much higher autobauding.
    I am open to all suggestions.
  • Clock LoopClock Loop Posts: 2,069
    edited 2011-12-17 22:54
    Cluso99 wrote: »
    Normally autoboarding uses some special characters.
    My application doesn't allow me to modify the transmission packet at all.
  • Clock LoopClock Loop Posts: 2,069
    edited 2011-12-17 23:33
    Baud rates above 38400 seem to have larger and larger errors in the calculated baud rate out of actual rate.
    38400 calculates to be 38406 sometimes and others 38443, and 38369.
    The error range grows as baud rate grows.
    If you need more accurate autobauding, do this in propasm. ;)
  • Clock LoopClock Loop Posts: 2,069
    edited 2011-12-17 23:56
    Complete corrected working code:
    Pub Autobaud
    
    Repeat
      
      Repeat
        waitpeq(|< SerInput, |< SerInput, 0) 'wait for high
        riseatime := cnt
    
        waitpeq(0, |< SerInput, 0) 'wait for low
        fallatime := cnt
    
        If fallatime - riseatime > 80000000
          startbit := fallatime
          Quit
        Else
          riseatime := 0   
          fallatime := 0
          
      Repeat
        waitpeq(|< SerInput, |< SerInput, 0) 'wait for high
        risebtime := cnt
    
        waitpeq(0, |< SerInput, 0) 'wait for low
        fallbtime := cnt
    
        If fallbtime - risebtime > 80000000
          stopbit := risebtime
          Quit
        Else
          risebtime := 0
          fallbtime := 0
          
      frametime := stopbit - startbit
      bitrate := frametime / 9
      abaudrate := 80000000 / bitrate
    
    
    {{
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //                                                  TERMS OF USE: MIT License
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
    // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
    // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    // Software is furnished to do so, subject to the following conditions:
    //
    // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
    // Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }}
    
  • kuronekokuroneko Posts: 3,623
    edited 2011-12-18 16:29
    Clock Loop wrote: »
    I am open to all suggestions.
    Quick and dirty. Note that the initial tests with FDS as a sender show rather huge variations in calculated bit rate. Replacing it with a PASM pulse generator gives stable results. Which simply means you have to consider the quality of your incoming signal when doing the calculations. The code below happily detects 115k2 in SPIN (didn't test for higher speeds). HTH
    CON
      _clkmode = XTAL1|PLL16X
      _xinfreq = 5_000_000
    
    OBJ
      serial: "FullDuplexSerial"
    
    VAR
      long  storage
      
    PUB null | period
    
      serial.start(31, 30, %0000, 115200)
      storage := clkfreq / 115200
      cognew(@sender, @storage)
      waitcnt(clkfreq*3 + cnt)
    
      serial.tx(0)
    
      [COLOR="blue"]ctra := constant(%0_01100_000 << 23 | pin)            ' NEG detector
      frqa := 1[/COLOR]
    
      repeat
        [COLOR="orange"]waitpne(|< pin, |< pin, 0)                          ' find low pulse
        waitpeq(|< pin, |< pin, 0)                          ' wait until finished
        serial.hex(period := phsa~, 8)[/COLOR]
        serial.tx(32)
        serial.dec(clkfreq * 9 / period)
        serial.tx(13)
        
    DAT             org     0
    
    sender          rdlong  pause, #0
                    rdlong  pulse, par
    
                    mov     temp, pulse
                    shl     temp, #3                ' *8
                    add     pulse, temp             ' *9 (start bit + 8 data bits)
                    
                    mov     outa, mask
                    mov     dira, mask
    
                    mov     cnt, cnt
                    add     cnt, #9
    
    :loop           waitcnt cnt, pulse
                    andn    outa, mask
                    waitcnt cnt, pause
                    or      outa, mask
                    jmp     #:loop
                    
    mask            long    |< pin
    
    pause           res     1
    pulse           res     1
    temp            res     1
    
                    fit
                    
    CON
      pin = 16
      
    DAT
    
  • localrogerlocalroger Posts: 3,451
    edited 2011-12-18 18:14
    Clock Loop wrote: »
    Baud rates above 38400 seem to have larger and larger errors in the calculated baud rate out of actual rate.
    38400 calculates to be 38406 sometimes and others 38443, and 38369.
    The error range grows as baud rate grows.

    These estimates are still very close, and you're safe to assume that the nearest standard baud rate to your estimate is what you've actually detected. It's not like there are that many of them.
  • TappermanTapperman Posts: 319
    edited 2013-08-07 10:32
    Clock Loop wrote: »
    I know i may have some obvious errors in my code, but my fundamental error is using CNT to store the rise and fall times. I know there is a better way to still maintain very accurate timings, and properly deal with the CNT roll.
    (which i am not doing and thus why my code is Smile)

    I know this is a old horse ... however, I just had to 'fiddle' with it. I used timers to arrive at this solution. But it looks for a 'space-bar'. and I hard coded for a clock freq of 80MHz:
    PRI AutoBuad                           '' runs in its own cog
      {   This routine looks for a space-bar character before training
          on the serial stream. After figuring out the baud rate the
          top level cog will remove it from the cpu.
          
         'space-bar' character (ASCII '32') looks like this:
    
         Rcv Pin: &#61574;&#61574;&#61574;&#61574;&#61574;&#61573;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61570;&#61574;&#61573;&#61569;&#61569;&#61570;&#61574;&#61574;&#61574;&#61574;&#61574;  ---> time
                        000000 1 00
                        
         We see that there are 6 zeros (w/start bit) before the
         first high bit, then two trailing zeros after. before the
         stop bit.
    
         If we count up by one for the leading zeros then count down
         by 3 for the trailing zeros, the count in phase-b will be very
         close to zero.  Although it may not be zero, the absolute value
         of phase-b < phase-a. But only for a space-bar.
      }
    
      waitcnt(clkfreq + cnt)
      
    ' start counters
      frqa~
      ctra := %11010 << 26 + Rcv_Pin                        'time bit = 1
      frqb~
      ctrb := %10101 << 26 + Rcv_Pin                        'time bit = 0
      Phsb~
      repeat until Phsb
        Phsa~
        Frqb++
        waitpne(|< Rcv_Pin,|< Rcv_Pin,0)          ' wait for start bit (zero)
        Frqa++                                    ' begin adding 1 
        waitpeq(|< Rcv_Pin,|< Rcv_Pin,0)          ' wait for first high bit
        Frqb := -3                                ' on next low bit count by (-3)
        waitpne(|< Rcv_Pin,|< Rcv_Pin,0)          ' wait for low bit
        frqa~                                     ' stop counting high bit time
        waitpeq(|< Rcv_Pin,|< Rcv_Pin,0)          ' wait for stop bit
        frqb~                                     ' stop counting low bit time
        if ||Phsb > Phsa                          
          Phsb~                                   ' not space-bar, clear & go again
     
        repeat until ina[Rcv_Pin]
          waitcnt(clkfreq/10 + cnt)               ' settle time needed.
          
      ' upon exit of the repeat loop, only a space-bar is sensed
      ' and we can now trust phase-a to hold one bit time only!
      
      case phsa           ' calc @ 80MHz & +or- 2% xtal error
        01361..01417: Baud := 57_600
        01418..01457: Baud := 56_000
        02042..02125: Baud := 38_400
        02126..02136: Baud := 38_200
        02509..02611: Baud := 31_250
        02722..02833: Baud := 28_800
        04083..04250: Baud := 19_200
        05444..05666: Baud := 14_400
        08167..08500: Baud :=  9_600
        16333..17000: Baud :=  4_800
        32667..34000: Baud :=  2_400
        65333..68000: Baud :=  1_200
        other:        Baud := -1  
    

    And this goes in its own cog with this:
    Cog := cognew(AutoBuad, @Stack) + 1
        if cog > 0
          repeat until baud
          CogStop(Cog~ - 1)
    

    I've tested it at all the Bauds shown and it works. Just had to throw that one in for fun.

    ... Tim
Sign In or Register to comment.