BS2: SEROUT/SERIN at 38400 easy-peasy
tomcrawford
Posts: 1,129
in BASIC Stamp
There have been some discussions recently about (relatively) fast serial I/O with the BS2. I decided to experiment. I chose to use only "standard" baud rates.
1. SEROUT works just fine up to and including 38,400 with formatting.
BS2OutComplete shows the complete output. The first six characters are the text string, then 4 characters of HEX4 formatting, and finally 5 characters of DEC5 formatting. There are plenty of extra STOP bits, but that is perfectly legal. Async is asynchronous.

BS2OutDetail shows a single character. The bit time is 25.92, corresponding to 38,580 baud rate, less than 1% fast.

2. SERIN works up to 38,400, but WITHOUT formatting. Here is a driver I wrote for propellor. I wrote my own because I wanted explicit control over the protocol including number of stop bits. It turns out that a single stop bit was adequate.
and here is the BS2 program that received it.
Note that SERIN uses only STR (capture a string). Formatting like HEXn and DECn do work only to 9600. So any conversion you need to do needs to be done by hand.
1. SEROUT works just fine up to and including 38,400 with formatting.
' {$STAMP BS2}
' {$PBASIC 2.5}
TxOut PIN 1
RxIn PIN 2 'receive data here
Baud CON 6 '38400 baud
ByteSize VAR Byte
WordSize VAR Word
main:
WordSize = 12345
DO
SEROUT TxOut, baud, ["String", HEX4 Wordsize, DEC5 WordSize, CR]
PAUSE 50
LOOP
BS2OutComplete shows the complete output. The first six characters are the text string, then 4 characters of HEX4 formatting, and finally 5 characters of DEC5 formatting. There are plenty of extra STOP bits, but that is perfectly legal. Async is asynchronous.

BS2OutDetail shows a single character. The bit time is 25.92, corresponding to 38,580 baud rate, less than 1% fast.

2. SERIN works up to 38,400, but WITHOUT formatting. Here is a driver I wrote for propellor. I wrote my own because I wanted explicit control over the protocol including number of stop bits. It turns out that a single stop bit was adequate.
{Serial Character Stream Generator
Transmit test streams for formstted testing}
CON
_clkmode = xtal1 + pll16x 'Standard clock mode
_xinfreq = 5_000_000 '* crystal frequency = 80 MHz
TxOut = 17
BaudRate = 38400 '
HalfStops = 0 '1 stop bit
VAR
long Command '<> 0 says => driveer busy
'14..0 : Address in hub memory
long MyParm[6] 'passing addresses, etc to display driver
byte Cog
byte TheString[10]
word DecVal '
OBJ
pst : "parallax serial terminal"
PUB main
pst.Start (115_200) 'start up ser terminal
pst.str(String("hello, world ")) 'runs in cog 1
pst.NewLine
waitcnt(clkfreq/10 + cnt)
MyParm[0] := @Command 'address of string to send
MyParm[1] := 80_000_000/BaudRate 'bit time in clock cycles
MyParm[2] := HalfStops 'optional extra half stop bits
cog := cognew(@PCog, @MyParm) 'start up the output cog
pst.str(String("Transmit Cog: ")) '
pst.hex(Cog,1)
pst.NewLine
waitcnt(clkfreq/10+cnt)
repeat DecVal from 0 to 65_000
Dec2ASC(DecVal, @TheString)
Command := @TheString 'transmit dec
repeat while (Command <> 0)
waitcnt(clkfreq/20 + cnt)
pst.char("*")
PUB Dec2ASC(InVal, Point)| Count 'convert word to 5 ascii digits
byte[Point][0] := "0"+InVal / 10_000
byte[Point][1] := "0"+(Inval//10_000) / 1_000
Byte[Point][2] := "0"+(InVal//1_000) / 100
Byte[Point][3] := "0"+(InVal//100) / 10
Byte[Point][4] := "0"+(InVal//10)
byte[Point][5] := 13 'terminator for BS2
byte[Point][6] := 0 'terminator for serial out
DAT
PCog org 0 'This PASM driver is a serial driver
mov AdPar,Par 'get the address of input parameters
rdlong AdCommand, AdPar 'address of command long
add AdPar, #4
rdlong BitTime, AdPar 'clocks per bit
mov HalfBT, BitTime
shr HalfBT, #1 'clocks per half bit time
add AdPar, #4
rdlong HalfSB, AdPar 'number of half stop bits
or outa, TxMask 'comes up high
or dira, TxMask 'transmitter is an output
'*********************wait here for something to do*************************
top rdlong AdString, AdCommand wz 'wait for a command (address of string)
if_Z jmp #top 'just hang here
Cloop rdbyte TheChar, AdString wz 'get the (first)(next) character
if_Z jmp #done 'zero terminated string
add AdString, #1 'point to following char
mov BitCount, #8 '8 bits per character
mov time, BitTime
add time, cnt 'time at end of start bit
andn outa, TxMask 'send start bit
waitcnt time, BitTime 'time start bit
BLoop shr TheChar, #1 wc 'next (first) bit into carry
muxc outa, TXMask 'then onto pin
waitcnt time, BitTime 'one bit time
djnz BitCount, #BLoop 'eight bits per character
or outa, TXMask 'stop bit
waitcnt time, HalfBT 'one stop bit
mov BitCount, HalfSB wz 'optional half stop bits
if_Z jmp #CLoop 'no optional stop bits
SLoop waitcnt time, HalfBT 'at least one half stop bit
djnz BitCount, #SLoop 'however many
jmp #CLoop 'on to next character
done wrlong zero, AdCommand 'tell boss cog done
jmp #top 'and wait for another
'
zero long 0 'constants
TxMask long 1<<TxOut 'mask corresponding to transmit pin
BitTime res 'clocks per bit time
AdPar res 'address into parameter list
AdCommand res 'address in hub of command long
MyCommand res 'my copy of the command
BitCount res 'number of bits per character
time res 'time to wait
AdString res 'current address in string
theChar res 'the character we are transmitting
HalfSB res 'number of optional half stop bits
HalfBT res 'half bit time (for optional 1/2 stops)
and here is the BS2 program that received it.
' {$STAMP BS2}
' {$PBASIC 2.5}
RxIn PIN 2 'receive data here
baud CON 6 '38400 Baud
SerString VAR Byte(10) 'buffer so as to use STR
Result VAR Word 'decimal value from convert
CharCount VAR Byte 'number of characters to convert
Point VAR Byte 'pointer into character string
main:
DO
SERIN RXIn, baud, [STR serString\10\13] 'up to 10 chars, teerminated with CR
DEBUG STR SerString, " " 'display raw string for manual inspection
CharCount = 5 'convert 5 digits
GOSUB Asc2Dec 'convert ASCII decimal string to binary
DEBUG DEC5 Result, CR 'display result in decimal
LOOP
Asc2Dec: 'convert ascii string
Result = 0 'remove previous result
FOR Point = 0 TO CharCount - 1 'work way through string
Result = (Result * 10) + (SerString(Point) - "0") 'shift and add
NEXT
RETURN
Note that SERIN uses only STR (capture a string). Formatting like HEXn and DECn do work only to 9600. So any conversion you need to do needs to be done by hand.
