Autobaud on the propeller not using special characters but total packet length.
Clock Loop
Posts: 2,069
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)
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
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?
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?)
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.
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.
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. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }}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 DATThese 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.
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:  ---> 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 := -1And 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