View previous topic :: View next topic |
Author |
Message |
njepsen
Joined: 13 Aug 2007 Posts: 469
|
Posted: Wed Jun 08, 2022 3:58 am Post subject: BAUD RATE |
|
|
I have a serial device connected to a HW uart on the ATMEGA1284p. I routinely use 38400 baud, but when i buy the meters they are set to 115200, and sometimes ( v v rarely like x1 in 5yrs) a lightning storm or some-such can change the BR to another standard but unknown value. I want to try talking to the meter at all the standard baud rates and automatically set the rate to 38400. ( with the command BR2). The code below does that but I'm trying to get away from the clumsy case statement. Why can I not replace the whole case statement with Code: | baud = testbaudrate |
The test code snippet below does achieve what I am trying to do. Code: |
$regfile = "m1284pdef.dat"
$crystal = 9830400
$framesize = 500
$swstack = 500
$PROG &HFF , &HC7 , &HD0 , &HFD
config watchdog = 8192
stop watchdog
' Pullup On
' '-------------------------------------------------------------------------------
'Open a software UART TRANSMIT channel for debug dB9
'-------------------------------------------------------------------------------
'Open a software UART TRANSMIT channel for debug dB9
Open "comc.3:38400,8,n,1" For Output As #1 '
Open "comc.2:38400,8,n,1" For Input As #5
'---------------------------------------------------------
'Nor 140
'---------------------------------------------------------
' Open Hardware uart on pins 14 & 15 for NOR140
$baud = 38400 '
Open "com1:" For Binary As #3
Config Serialin = Buffered , Size = 200 , Cts = Pind.4 , Rts = Pind.7 , Threshold_full = 30 , Threshold_empty = 30
Config Serialout = Buffered , Size = 250
enable interrupts
Declare Function Getmeterresponse(byval metercommandstr As String*10) As String
declare sub change_meter_baudrate()
declare function confirm_meter_id() as byte
Dim Tempstr1 As String * 100
dim tempstr2 as string * 100
dim msg_id as byte
dim retries as byte
dim m as byte
dim testbaudrate as long
dim tempstr9 as string * 255
dim bArray(200) as byte at tempstr9 overlay
dim n As word
dim rxbyte as byte
'*************
'MAIN LOOP
'*************
do
wait 1
Do
Print #1 , ">> send IT " 'IT to the instrument ellicits a response "Nor140"
Tempstr1 = Getmeterresponse( "it;")
wait 1
If Instr(tempstr1 , "Nor140") <> 0 Then
print #1,">. we got correct response "
else
print #1,">> we got incorrect or no response"
call change_meter_baudrate
End If
Loop Until Retries >= 200 or msg_id = 0
loop
'***********************
'SUBROUTINES START HERE
'***********************
function confirm_meter_id() as byte
baud = 38400
tempstr1 = getmeterresponse("it;")
if instr(tempstr1,"Nor140")<>0 then
msg_id = 0
else
msg_id = 99
end if
confirm_meter_id = msg_id
end function
'*********************************************************************************
Sub Change_meter_baudrate()
' This sub checks the meter at all baud rate from 9600 to 115200 and exits when the correct response is seen
n = 0
do
incr n
for m = 0 to 4
testbaudrate = lookup(m,BR_data)
select case testbaudrate 'i want to replace this complete case statement with baud = testbaudrate
case 9600
baud = 9600
case 19200
baud = 19200
case 38400
baud = 38400
case 57600
baud = 57600
case 115200
baud = 115200
case else
print #1,">> rubbish"
end select
' baud = testbaudrate
'Now we try to set the meter baud rate to 38400 using the 'test' baudrate
print #1,">> try "; str(testbaudrate)
print #3,"BR2" 'command BR2 sets the meter baud rate to 38400
waitms 1250
msg_id = confirm_meter_id()
if msg_id = 0 then exit sub:
next m
loop until n >= 25
print #1,">> no success"
wait 2
exit sub
BR_data:
data 9600&,19200&,38400&,57600&,115200&
End Sub
'*************************************************************************************
Function Getmeterresponse(byval metercommandstr As String*10) As String
'meter response looks like E<space>57.9<cr><lf>
Local Timedelay As Long
local Index as byte
local loopcount as byte
Index = 1 'arrays are 1 based
Clear Serialin 'clear ser buffer
Print #3 , "" 'clear meter buffer
Print #3 , metercommandstr 'CRLF is added automatically
rxbyte = 0 'essential
tempstr9 = ""
tempstr1 = ""
Do
incr loopcount
While Ischarwaiting(#3) <> 0
rxbyte = waitkey(#3)
select case rxbyte
case 10 'LF
exit while
case 13 'CR
exit while
case 32 'space do nothing
case Else
if index<250 then
bArray(Index) = rxbyte 'overlay byte onto string
incr index
else
exit while
end if
end select
Wend
waitms 1
Loop Until loopcount >= 100
bArray(index) = &H0 'string terminator
print #1,">> meter said ";tempstr9
loopcount = 0
Getmeterresponse = tempstr9
End Function
'*********************************************************************************
|
(BASCOM-AVR version : 2.0.8.5 ) _________________ Neil |
|
Back to top |
|
|
EDC
Joined: 26 Mar 2014 Posts: 971
|
|
Back to top |
|
|
njepsen
Joined: 13 Aug 2007 Posts: 469
|
Posted: Wed Jun 08, 2022 8:03 am Post subject: |
|
|
Nice EDC. Elegant.
I chose the "weird" xtal freq 10 yrs ago because it gave me 0% at 38400, which is what I use, and they were ex stock at my supplier.
The issue I had was baud = var according to the help. A long is a var so why won't Baud = var (from the lookup) compile. Anyway - i will try your soln tomorrow. Thanks for taking the time to reply. _________________ Neil |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Wed Jun 08, 2022 8:06 am Post subject: Re: BAUD RATE |
|
|
njepsen wrote: | Why can I not replace the whole case statement with Code: | baud = testbaudrate |
|
Did you try Code: | baud #3, testbaudrate | ?
Edit:
Compiled and disassembled, while the compiler throws no error, it completely ignores the command, no opcodes are generated:
Code: | baud #3, testbaudrate |
I'd expect an error and not an ignore.
The answer why baud = baudratevar does not work, is stated in the help, while it is contradictory in this case:
Quote: | BAUD = var
BAUD1 = var
BAUD2 = var
BAUD3 = var
Syntax Xmega
BAUD = var
BAUD1 = var
BAUD2 = var
BAUD3 = var |
This suggests that variable arguments work for default (Mega) and XMega.
But also from the help:
Quote: | mega
...
You need to use a constant for the baud rate. Variables are not supported. |
contradicts the first.
The same is given for XMegas.
Using constants is not required technically, as the baud rate registers can be rewritten anytime.
Last edited by MWS on Wed Jun 08, 2022 8:58 am; edited 1 time in total |
|
Back to top |
|
|
albertsm
Joined: 09 Apr 2004 Posts: 5913 Location: Holland
|
Posted: Wed Jun 08, 2022 8:19 am Post subject: |
|
|
using BAUD= indeed only works with a constant. The reason is simple.
When using $baud the compiler calculates using the oscillator speed. It checks all possible values and checks what results in the lowest error. It also checks the double rate flag. So for some values it will be set, for others it wont
When a variable must be supported it will take more code. Something not needed IMO.
The software uart does allow to be changed with a variable but that is because it already has calculation routines since serin/serout can work dynamic with variables.
I just looked in the help and it seems to be very wrong (reversed). will change that.
using baud #3, someval will not work.
never got many q's about using a variable to change the baud but that is probably since it is relatively simple to change it. do take care however that there are various procedures, depending on the processor. some times a baud register is shared. so always check the datasheet. _________________ Mark |
|
Back to top |
|
|
njepsen
Joined: 13 Aug 2007 Posts: 469
|
Posted: Wed Jun 08, 2022 8:25 am Post subject: |
|
|
Hi MWS,
Yes I did and I tried it again just now. it compiles, but doesnt give me a correct solution. At least it compiles - I have had time to figure out why it doesnt give me a solution.
The next print statement Code: |
print #1,">> try "; str(testbaudrate) |
does give me the correct answers each iteration of the for/next loop so the lookup is working. _________________ Neil |
|
Back to top |
|
|
albertsm
Joined: 09 Apr 2004 Posts: 5913 Location: Holland
|
Posted: Wed Jun 08, 2022 8:27 am Post subject: |
|
|
Quote: | The software uart does allow to be changed with a variable but that is because it already has calculation routines since serin/serout can work dynamic with variables. |
that is not correct. it allows a constant only. only serin/serout use dynamic baud. _________________ Mark |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Wed Jun 08, 2022 9:06 am Post subject: |
|
|
albertsm wrote: | that is not correct. it allows a constant only. only serin/serout use dynamic baud. |
As I've edited above and you did notice yourself, the help section in question is contradictory.
Last edited by MWS on Wed Jun 08, 2022 9:10 am; edited 1 time in total |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Wed Jun 08, 2022 9:09 am Post subject: |
|
|
njepsen wrote: | but doesnt give me a correct solution. At least it compiles - I have had time to figure out why it doesnt give me a solution. |
I had the time, see my edit. |
|
Back to top |
|
|
albertsm
Joined: 09 Apr 2004 Posts: 5913 Location: Holland
|
Posted: Wed Jun 08, 2022 12:06 pm Post subject: |
|
|
both the baud and the help for it had some errors. will fix it _________________ Mark |
|
Back to top |
|
|
njepsen
Joined: 13 Aug 2007 Posts: 469
|
Posted: Thu Jun 09, 2022 3:55 am Post subject: |
|
|
Thanks guys for the comments. I found that U2X needed to be set because of the high err at 115200 and my Xtal freq. I decided to run thru the loop again so that we ended up with U2X=0 for the higher USART sample rate. Not sure if this has any advantage but it seems like a good idea. Code: |
Sub Change_meter_baudrate()
' This sub checks the meter at all baud rate from 9600 to 115200 and exits when the correct response is seen
'Becuase of high err rate at 115200, U2X = 1 is needed which has lower err rate
n = 0
do
incr n
'Single speed
for m = 0 to 4
my_UBRR = lookup(m,BR_data)
print #1,">. test number=";my_UBRR
UBRR = my_UBRR
UCSR0A.U2X=0
'Now we try to set the meter baud rate to 38400 using the 'test' baudrate
print #1,">> try "; UBRR
print #3,"BR2" 'command BR2 sets the meter baud rate to 38400
waitms 1000 'only 100 needed
msg_id = confirm_meter_id()
if msg_id = 0 then
print #1,">> Success.Single speed Both meter & USART are now at 38400"
exit sub
end if
next m
'try double speed because single speed didnt work
for m = 5 to 9
my_UBRR = lookup(m,BR_data)
print #1,">. test number=";my_UBRR
UBRR = my_UBRR
UCSR0A.U2X=1
'Now we try to set the meter baud rate to 38400 using the 'test' baudrate
print #1,">> try "; UBRR
print #3,"BR2" 'command BR2 sets the meter baud rate to 38400
waitms 1000 'only 100 needed
msg_id = confirm_meter_id()
if msg_id = 0 then exit for 'Both meter and UART now at 38400 but U2x=1, so go back to single speed & try again
next m
loop until n >= 100 'for test purposes
print #1,">> no success"
wait 2
exit sub
BR_data:
data 63,31,15,10,4,127,63,31,20,10
End Sub
|
_________________ Neil |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Thu Jun 09, 2022 12:15 pm Post subject: |
|
|
njepsen wrote: | I found that U2X needed to be set because of the high err at 115200 and my Xtal freq. |
As general rule U2X = 1 gives the same or better error, compare to the baud rate example tables from the data sheet, USART section.
By comparing U2X = 0 vs. U2X = 1 over the shown clock frequencies you'll notice that if an error of 0% appears at U2X = 0, there is always 0% at U2X = 1.
Where the error is > 0% at U2X = 0, then the U2X = 1 error is always same or better.
This is simply explained by 'finer' sample steps.
Keeping U2X always on seems to be a sound idea.
The limit is not the higher baud rates, in contrary, only with U2X = 1 the highest baud rates can be achieved.
The limits are super slow baud rates at high clock frequencies, because of the 12bit-wide UBRR.
At 20 MHz clock, U2X = 1 and UBRR = 4095 the baud rate calculates to 610 baud, the half at U2X = 0.
Quote: | I decided to run thru the loop again so that we ended up with U2X=0 for the higher USART sample rate.
Not sure if this has any advantage but it seems like a good idea. | It is senseless, as you have the same error of 0% at the lower baud rates, regardless of U2X = 0/1, while the error at the two higher baud rates is much more acceptable with U2X = 1 (1.6/-3,0%), than double as high error with U2X = 0.
The only reason running tests with off-center baud rate is in case the connected hardware is off-center too. |
|
Back to top |
|
|
njepsen
Joined: 13 Aug 2007 Posts: 469
|
Posted: Sat Jun 11, 2022 1:28 am Post subject: |
|
|
That all makes sense, and the error at my chosen 38400 baud rate is the same for both cases. I was thinking more of receiver performance & the lower sampling rate with U2X =1, where the sampling rate is 8x instead of 16x. Because the receiver decision ss to whether a bit is an 0 or a 1 is based on a majority decision of the samples - its seems logical that 16 samples should give a better result ? _________________ Neil |
|
Back to top |
|
|
njepsen
Joined: 13 Aug 2007 Posts: 469
|
Posted: Sat Jun 11, 2022 2:07 am Post subject: |
|
|
I am also getting some confusing results from setting UBRR and its siblings.
will compile and all 16 bits can be manipulated, but is not accepted by the compiler. I note that there is no entry in the m1284p.def for UBRR1.
Also - for example is accepted, but only the LS byte is loaded it seems, so if i run this in the 1284p, and then read UBRR0 and UBRR0L the result is consistent and only the LSB is set which I would expect. I cant check this with UBRR1 because it won't compile.
I can also write to and read UBRR Code: |
UBRR = 257
print #1,UBRR0
print #1,bin(UBRR0) ' -> 0000000000000001
print #1,bin(UBRR) ' -> 0000000000000001
print #1, bin(UBRR0L) ' -> 00000001
stop | and the result is the same as writing to UBRR0 Code: |
UBRR0 = 257
print #1,UBRR0
print #1,bin(UBRR0) ' -> 0000000000000001
print #1,bin(UBRR) ' -> 0000000000000001
print #1, bin(UBRR0L) ' -> 00000001 |
confusing _________________ Neil |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Sat Jun 11, 2022 10:07 am Post subject: |
|
|
njepsen wrote: | I was thinking more of receiver performance & the lower sampling rate with U2X =1 | You misunderstand. Read U2X as U(art) 2(double) X(speed), from the data sheet "Double Speed Operation (U2Xn)", if set to 1 the option is on, otherwise off.
Quote: | where the sampling rate is 8x instead of 16x. | Definitely not, the prescaler for the sampling rate is 8 instead of 16, which means the sample rate is higher.
Easy to see from the data sheet's baud rate equations, at U2X = 1 one divisor becomes 8, if the dividend (fOsc) stays the same, then the quotient (baud) gets higher.
Quote: | its seems logical that 16 samples should give a better result ? | As written, you confuse sample rate with sample rate prescaler. |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You cannot download files in this forum
|
|