Baudrate control

39 views
Skip to first unread message

Bill Beek

unread,
Oct 17, 2022, 9:39:52 AM10/17/22
to jallib
Hello everyone, Is there anyone who has a solution to my problem. I am working on a serial LCD now that I have this working, I want to select the baud rate before running the program. Unfortunately, the "const serial_hw_baudate" do not easily change. In the library "usart_common" I changed all the constants in a variable "var dword" but I keep getting error messages from this lib. Maybe I'm overlooking something, or is there a simple method to set the Baud rate under software control.
 Kind regards, Bill

Oliver Seitz

unread,
Oct 17, 2022, 10:47:20 AM10/17/22
to jal...@googlegroups.com
Hi Bill,

I've used different baud rates, but I did not modify the serial libraries for that. I just calculated the register values by hand and poked the different values to the different registers. The baud rate calculation in the libraries is not a thing which is good to be done at runtime. For certain baud rates, the lib will refuse to compile and inform you, that your desired baud rate cannot be set due to a deviation from the desired value which is to large to reliably work. That can't be done at runtime for a start.

Greets,
Kiste

Am Montag, 17. Oktober 2022, 15:39:54 MESZ hat Bill Beek <bill...@gmail.com> Folgendes geschrieben:


Hello everyone, Is there anyone who has a solution to my problem. I am working on a serial LCD now that I have this working, I want to select the baud rate before running the program. Unfortunately, the "const serial_hw_baudate" do not easily change. In the library "usart_common" I changed all the constants in a variable "var dword" but I keep getting error messages from this lib. Maybe I'm overlooking something, or is there a simple method to set the Baud rate under software control.
 Kind regards, Bill

--
You received this message because you are subscribed to the Google Groups "jallib" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jallib+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jallib/2b1be8c6-547c-4f0c-97bb-43fc851e4bf4n%40googlegroups.com.

Bill Beek

unread,
Oct 17, 2022, 1:40:01 PM10/17/22
to jallib
Thanks Kiste for your reply. My teacher said more than 50 years ago that poking in memory was not a good way of programming,
but I did think that this was also a possibility. If this turns out to be the only possibility,
 I'm not sure how to go about it I don't see anything in the documentation about writing directly in the PIC memory
except that you can use assembler instructions. Unfortunately I am not well informed about the PIC asm code.
A long time ago I programmed various micro processors.
 I would like to hear if you want to share a piece of code what i can alter for my needs.

 Thanks in advance, Bill.

Rob CJ

unread,
Oct 17, 2022, 1:52:25 PM10/17/22
to jal...@googlegroups.com
Hi Bill,

I applied the suggestion of Kiste in one of my programs. Here is a part of that program. This is for a PIC running at 48  MHz target clock.

I had to look up a specific baudrate to see if it was valid. If so I set the new baudrate. 

You see 4 parts (not all needed)
  1. Define valid bauddrates.  You could skip this
  2. Check if a given baudrate is valid. You could skip this too.
  3. The baudrate calculation based on the given baudrate + initialize the USART. You need this. Note: baudrate calculation is of type dword.
  4. The intiallization routine of the USART with the calculation. You need this.

; List of baudrates supported. See page 262 of the datasheet.
; Formula for baudrate calclation for 8 byte asynchronous mode
; with for sync = FALSE and brg16 = TRUE and brgh = FALSE:
; brg = target_clock/(baudrate * 16) - 1
const dword SUPPORTED_BAUDRATES[] = {
   110, 300, 600, 1200, 2400, 4800, 9600, 14400,
   19200, 28800, 38400, 57600, 115200, 230400
}

; Check if the given baudrate is supported and return TRUE if so.
function supported_baudrate(dword in baudrate) return bit is

   var byte index
   var bit found = FALSE

   for count(SUPPORTED_BAUDRATES) using index loop
      if (SUPPORTED_BAUDRATES[index] == baudrate) then
         found = TRUE
      end if 
   end loop

   return found

end function

           baudrate_calculation = (target_clock/(current_baudrate * 16)) - 1
           usart_init(word(baudrate_calculation))

; Initialize the USART with the given baudrate value. The USART is enabled.
procedure usart_init(word in baudrate_value) Is
 
   usart_disable()
   ; Use 16 bit baudrate generator and set baudrate
   BAUDCON = 0b0000_1000
   SPBRG = baudrate_value
   ;Initialise transmitter, 8 bits, asynchronous mode, low speed.
   TXSTA = 0b0000_0000
   ; Initialise receiver and serial port, 8 bits
   RCSTA = 0b1000_0000
   usart_enable()

end procedure  


Hope this helps.

Kind regards,

Rob

Van: jal...@googlegroups.com <jal...@googlegroups.com> namens Bill Beek <bill...@gmail.com>
Verzonden: maandag 17 oktober 2022 19:40
Aan: jallib <jal...@googlegroups.com>
Onderwerp: Re: [jallib] Baudrate control
 

rob...@hotmail.com

unread,
Oct 18, 2022, 1:14:34 AM10/18/22
to jallib
Hello Bill,

I posted an example but never received it my self so this is a retry.

Kind regards,

Rob


Op maandag 17 oktober 2022 om 19:52:25 UTC+2 schreef rob...@hotmail.com:

Bill Beek

unread,
Oct 18, 2022, 5:34:39 AM10/18/22
to jallib
Hello Rob,
Thank you for your cooperation, yesterday I had already seen the code.
Now let's figure out how I can fit it into my program.
Maybe my question was not entirely clear so I send a piece of the code to show how I imagined it.

Kind regards, Bill.

MCU = 16F876A  20 MHz The problem here is that var "set" must be a constant.
Short vars for testing only.

var byte c1,c2,c3
var byte  set     -- Baud indicator
const serial[8]={1200,2400,4800,9600,19200,38400,57600,115200}
;var dword serial[8]={1200,2400,4800,9600,19200,38400,57600,115200}

pin_c1_direction = INPUT
pin_c2_direction = INPUT
pin_c3_direction = INPUT

include serial_hardware

if pin_c1 then
 c1 = 1
  else
  c1 = 0
end if

if pin_c2 then
 c2 = 2
  else
  c2 = 0
end if

if pin_c3 then
 c3 = 4
  else
  c3 = 0
end if

set = c1 + c2 + c3 + 1

const serial_hw_baudrate = serial[set]
;var dword serial_hw_baudrate = serial[set]
serial_hw_init()

Rob CJ

unread,
Oct 18, 2022, 1:23:04 PM10/18/22
to jal...@googlegroups.com
Hi Bill,

I understand what you try to do but it does not work because the hardware baudrate setting is calculated at compile time not at runtime.

In the library usart_common.jal you find the procedure that calculates the baudrate settings.

I once changed this code to be dynamic and created the following code but I do not remember if I ever tested it (it compiled as far as I know 🙂)

I did not use it because it is a lot of code for only calculating and setting the baudrate. That's why I suggested the other code. 

You could leave out the part which calculates it for synchronous mode and based on the PIC you are using you could leave out the 8-bit or 16-bit baudrate generator since your PIC has only one of them. In that case the code size is much smaller.

You could give it a try and if it works let me know.

Kind regards,

Rob


-- ------------------------------------------------------------------------------
-- Title:     Calculate and set baudrate dynamically for USART 1
-- Arguments: baudrate
-- Returns:   TRUE when succesful, otherwise FALSE
-- Notes:     Uses bit-constant 'usart_hw_serial' to determine mode of operation:
--              * TRUE:  Asynchronous communications (default)
--              * FALSE: Synchronous communications          
-- ------------------------------------------------------------------------------
function _calculate_and_set_baudrate_dynamic(dword in baudrate) return bit is

   const max_deviation = 5 -- maximum % deviation of the desired baudrate
   var dword usart_calculation, real_baud, usart_div_low, usart_div_sync, clock
   var word  usart_div
   var bit   succes = TRUE
   
   clock = dword(target_clock)
   
   if (usart_hw_serial == TRUE) then           -- USART in asynchronous mode
      if (defined(BAUDCON_BRG16) == TRUE) then -- use 16 bit baudrate register
         BAUDCON_BRG16 = TRUE
         TXSTA_BRGH = TRUE
         usart_calculation = ((5 + ((10 * clock) / (4 * baudrate))) / 10) - 1    
         usart_div = word(usart_calculation)
         real_baud = clock / 4 / ((usart_div & 0xffff) + 1)
         if (real_baud > baudrate) then
            if (100 * (real_baud - baudrate) / baudrate >= max_deviation) then
               -- Asynchronous baudrate deviation is too large
               succes = FALSE
            end if
         else
            if (100 * (baudrate - real_baud) / baudrate >= max_deviation) then
               -- Asynchronous baudrate deviation is too large
               succes = FALSE
            end if
         end if
         SPBRGL = byte(usart_div)                  -- MSB
         SPBRGH = byte(usart_div >> 8)             -- LSB
      else
         -- use classic (8 bit) baudrate register
         -- <SPBRG> = ( Fosc / ( 4 * Baudrate ) ) -1
         -- first try high baudrate, will generate highest accuarcy
         -- to get the right rounding (5 + 10*f(x)) /10
         usart_calculation =((5 + ((10 * clock) / (16 * baudrate))) / 10) - 1
         usart_div = word(usart_calculation)
         -- special case if divider is 0, test if deviation is not too much
         if usart_div == 0 then
            if (100 * (baudrate - (clock / 16))) / baudrate >= max_deviation then
               -- Asynchronous baudrate is too high
               succes = FALSE
            end if
         end if
         -- if divider small enough calculate divider and set high-speed
         real_baud = clock / 16 / (usart_div + 1)
         if usart_div <= 255 then
            if (real_baud > baudrate) then
               if (100 * (real_baud - baudrate) / baudrate >= max_deviation) then
                  -- Asynchronous baudrate deviation is too large
                  succes = FALSE
               end if
            else
               if (100 * (baudrate - real_baud) / baudrate >= max_deviation) then
                  -- Asynchronous baudrate deviation is too large
                  succes = FALSE
               end if
            end if
            SPBRGL = byte(usart_div)
            TXSTA_BRGH = TRUE
            -- try the low-speed mode
         else
            usart_div_low = ((((10 * clock) / (64 * baudrate)) + 5) / 10) - 1
            -- here divider will never be 0
            -- but special case to consider,
            -- if baudrate is just a little too low
            if (usart_div_low > 255) & (100 * ((clock / (64 * 256 )) - baudrate)) /
                  baudrate < max_deviation then
               SPBRGL = 255
               TXSTA_BRGH = FALSE
               -- now calculate divider and set high-speed / low-speed bit
            elsif usart_div_low <= 255 then
               SPBRGL = byte(usart_div_low)
               TXSTA_BRGH = FALSE
            else
               -- Asynchronous baudrate is too low
               succes = FALSE
            end if
         end if
      end if
   else -- USART in synchronous mode
      usart_div_sync = ( clock / ( 4 * baudrate )) - 1
      -- special case if divider is 0 or negative
      -- test if baudrate is a little bit too high
      if usart_div_sync <= 0 then
         if (100 * (baudrate - (clock / 4))) / baudrate >= max_deviation then
            -- Synchronous baudrate is too high
            succes = FALSE
         end if
      end if
      -- special case to consider, if baudrate is just a little too high
      if (usart_div_sync > 255) & (100 * ((clock / (4 * 256)) - baudrate)) /
            baudrate < max_deviation then
         SPBRGL = 255
      elsif (usart_div_sync <= 255) then
         SPBRGL = byte(usart_div_sync)
      else
         -- Synchronous baudrate is too low
         succes = FALSE
      end if
   end if
   
   return succes

end function





Verzonden: dinsdag 18 oktober 2022 11:34
You received this message because you are subscribed to a topic in the Google Groups "jallib" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jallib/vc1s65yXPkQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jallib+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jallib/8852c568-89d0-4224-95fa-ecd30b6cdc3an%40googlegroups.com.

Bill Beek

unread,
Oct 20, 2022, 1:15:45 PM10/20/22
to jallib
Hi Rob,
I am going to try out the function you have sent, I see that it is suitable for various PIC's and also test whetherthe chosen X-tal frequency
is good enough for the desired baudates. I myself use an 18.432 MHz x-tal that I still found in my junkbox. in that casemy code can
be more simple because of the very small spread, but obviously not for general use.
 I'll let you know if it worked out. B.T.W. this is very instructive for me. and I'm going to appreciate JAL more and more.
Thank you for your effort,
Kind regards Bill.

Rob CJ

unread,
Oct 21, 2022, 1:23:33 PM10/21/22
to jal...@googlegroups.com
Hi Bill,

Thanks and good to hear that you might becomd a fan of JAL.

I saw that your PIC had an 8-bit baudrate generator so you would only need this part of the code:
Good luck testing.

Kind regards,

Rob


Verzonden: donderdag 20 oktober 2022 19:15

Bill Beek

unread,
Oct 22, 2022, 10:14:15 AM10/22/22
to jallib
Hi Rob,
I applied the function unchanged to 3 types: 16F876A, 18F2520 and 18F25K22.
On the first 2 the function worked fine. So very useful for me.
The function is used as a library "usart_dynamic" with the following 2 lines added:
 if (defined(usart_hw_serial) == FALSE) then
const bit usart_hw_serial = TRUE   ; default is async mode (not sync)
end if
In the library "serial_hardware" I have changed the call to the correct library and the new function.
I have change the name of this lib of coarse. It worked right away.
The 18F25K22 does not want to generate the correct Baud rate, the relevant registers do have the correct values.
I will look with the oscilloscope to see what kind of Baud rate is really generated.

Thanks again for your help,
Kind regards Bill.

vsurducan

unread,
Oct 22, 2022, 11:27:11 AM10/22/22
to jal...@googlegroups.com
Bill, one good workaround for zero error baudrate is to use zero error usart crystals You will always have zero error baud rate. 7.3728MHz, 14.7456MHz etc. 

Bill Beek

unread,
Oct 22, 2022, 1:24:07 PM10/22/22
to jallib
Hi Vasile,
I will use a 18.432 Mhz crystal, found in my junkbox..

rob...@hotmail.com

unread,
Feb 8, 2025, 5:58:55 AMFeb 8
to jallib
Hello all,

This is an old post but my reason for responding is the following. There are modules that can be controlled via the serial interface by sending AT commands. In these modules you can change the baudrate but the serial library does not support that so you cannot make use of a higher baudrate (the default of these modules is often 9600 baud).

So I changed - not yet tested and not yet uploaded - the serial library as follows:
-) If you define SERIAL_HW_BAUDRATE the library works as usual and you call serial_hw_init() as you are used to.
-) If you do not define SERIAL_HW_BAUDRATE you must pass the baudrate as argument to serial_hw_init()

So when using the SERIAL_HW_BAUDRATE constant there is no change but the behavior is different if you want to use the fixed baudrate but you forgot to define it. If you do not define it and you just call serial_hw_init() the compiler will now report that a parameter is missing for serial_hw_init() instead the message that SERIAL_HW_BAUDRATE is not defined.

I assume that you are OK with this.

BTW. When using the feature to change the baudrate dynamically, you will need more Code space and Data space.

Kind regards,

Rob


Op maandag 17 oktober 2022 om 13:39:52 UTC schreef bill...@gmail.com:
Reply all
Reply to author
Forward
0 new messages