0
\$\begingroup\$

I have a PIC32MX795F512L which is connected to 8MHZ crystal. UART program is working with 9600 baudrate value but not working with higher baud values like 115200.

Following is the code:

#define FCY 72000000UL //PIC32 working on 72MHZ
#define FPB (FCY/2)    // Peripheral clock is half of FCY
#define BAUDRATE    9600 // Baud Rate Value
#pragma config POSCMOD=HS,FNOSC=PRIPLL //Using High speed mode with primary Oscillator 
#pragma config FPLLIDIV=DIV_2, FPLLMUL=MUL_18, FPLLODIV=DIV_1
#pragma config FPBDIV=DIV_2, FWDTEN=OFF
int main()
{
  OpenUART1( UART_EN | UART_NO_PAR_8BIT | UART_1STOPBIT  , UART_RX_ENABLE | UART_TX_ENABLE, (FPB/16/BAUDRATE)-1 );
  while(1)
  {
   putsUART1("hello\n");
   DelayMs(1000);
  }
}

Is this could be the crystal not working properly. What other reasons can cause the UART not work with higher baudrates?

\$\endgroup\$
  • \$\begingroup\$ does the uart clock divider have sufficient precison to get within 10% of the rate you want to use? \$\endgroup\$ – Jasen Jan 6 '16 at 5:42
  • 3
    \$\begingroup\$ Elaborate "Not working". Few errors? Lots of errors? All garbage? No data at all? \$\endgroup\$ – kabZX Jan 6 '16 at 5:49
  • \$\begingroup\$ First check signal levels and timings at TX pin with a scope if you have one. Then check the cable quality. If your connecting cable has bad joints, high impedance, no shielding, lots of ambient noise that will cause lots of errors / lost packets. \$\endgroup\$ – kabZX Jan 6 '16 at 5:50
  • \$\begingroup\$ with that setup the ideal divisor for 115200 is 19.53125 the pic uses 19 which should be good enough \$\endgroup\$ – Jasen Jan 6 '16 at 6:05
  • \$\begingroup\$ @kabZX Cable quality and the pins are working fine. I am receiving the garbage value, some random ASCII char on terminal when increasing the baud rate \$\endgroup\$ – user007 Jan 6 '16 at 6:36
4
\$\begingroup\$

I'm guessing that the micro can't hit the higher baud rates accurately enough given the rather low clock speed of 8 MHz. This illustrates one of the drawbacks of blindly using a canned library. Your library apparently has no means to tell you what baud rate it actually ended up with and at run time it's too late to do anything about it.

Most UARTs need a clock at 16x the baud rate. At 9600 baud, that means the UART needs to get 153.6 kHz out of its baud rate generator. If you're starting with 8 MHz and constrained to only divide that by integers, then the best you can do is 52, which comes out to a 16x clock of 153.8 kHz, and a baud rate of 9615. The system will work fine with that 0.16% error, and you aren't noticing it.

At 115.2 kBaud you need a UART clock of 1.843 MHz. That is 8 MHz / 4.34. The closest you can come is divide by 4, which yields a UART clock of 2 MHz, and a baud rate of 125 k. That is 8.5% error, which is too large to allow the system to work.

When you need high baud rates, and especially when you want to keep the clock of the microcontroller low, you usually want to use a baud rate crystal, like 7.3728 MHz. That is deliberately a multiple of all the common baud rates times 16.

\$\endgroup\$
  • \$\begingroup\$ Isn't the PIC code in the question suggesting that there is a PLL that is upping the PIC clock to 72 MHz? \$\endgroup\$ – Andy aka Jan 6 '16 at 13:09
  • \$\begingroup\$ @Andy: Could be. I didn't look at any of the code. I don't use the standard libraries like that. When you do, you end up with mysterious problems like this. The only frequency mentioned by the OP was 8 MHz. If he is actually running the PIC at something else, he needs to tell us. \$\endgroup\$ – Olin Lathrop Jan 6 '16 at 13:18
  • \$\begingroup\$ In the code I have mentioned that PIC32 is running at 72MHZ and I have mentioned the fuse settings on how I am driving my MCU to run at 72MHZ \$\endgroup\$ – user007 Jan 7 '16 at 6:47
2
\$\begingroup\$

From my calculations, i'd say the issue is excess baud rate error. The value placed in register UxBRG ultimately determines your baud rate. Since the register's value must be an integer, the value obtained from prescribed baud rate formulas (in the datasheet) are rounded to the nearest integer and placed in the register; there is always some error, the question are 'how much?' and 'Is it tolerable?'. Since you are using FCY/2 (= 72/2 = 36 MHz) as peripheral clock and you're using Standard Speed mode (i.e. BRGH = 0, also evident since you are dividing by 16), then, for 1152000 baud, according to the formula:

    UxBRG = (FPB / 16 / BaudRate) - 1 
    UxBRG = (36000000 / 16 / 115200) - 1 = 18.53 = 18

To calculate how much error we have from truncating 18.53 down to 18,

    Baud Rate = FPB / 16 * (UxBRG + 1)
    Baud Rate = 36000000 / 16 * (18 + 1) = 118421 // approximate
    % Error = ((118421 - 115200) / 115200) * 100 = 2.79 %

Acceptable baud rate error differs depending on the device and if its two devices of the same class speaking to each other (e.g. PIC to PIC) but its generally agreed that 2 % is a good maximum for most cases and 2.79 % exceeds that value. So, to solve this problem, there are 2 ways I can see:

  • Use 72 MHz as the peripheral clock instead, if possible.

    UxBRG = (72000000 / 16 / 115200) - 1 = 38.06 = 38
    Baud Rate = 72000000 / 16 * (38 + 1) = 115384
    % Error = ((115384 - 115200) / 115200) * 100 = 0.16 %
    

    This error is acceptable.

  • Change from Standard Speed mode to High Speed mode. This involves setting BRGH or, using your library, calling OpenUART1 this way:

    OpenUART1( UART_EN | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_BRGH_FOUR, UART_RX_ENABLE | UART_TX_ENABLE, (FPB/4/BAUDRATE)-1 );
    

With this change, the new values are:

    UxBRG = (36000000 / 4 / 115200) - 1 = 77.125 = 77
    Baud Rate = 36000000 / 4 * (77 + 1) = 115384
    % Error = ((115384 - 115200) / 115200) * 100 = 0.16 %

Same error as before, still acceptable.

\$\endgroup\$
  • \$\begingroup\$ Your calculations are correct, I tried your ways but was receiving random chars. I am confused because everything seems to be fine but still its not working. \$\endgroup\$ – user007 Jan 7 '16 at 7:17
  • \$\begingroup\$ You tried BOTH methods? Looking at the 32bitPeripheralLibraryGuide, and perhaps you should also OR this value: UART_TX_PIN_NORMAL in OpenUART1 second argument. Also add a delay of 1 sec after the OpenUART1call. I assume you also changed the value of the #define BAUDRATE at the top of your program to 115200. \$\endgroup\$ – TisteAndii Jan 7 '16 at 16:21
2
\$\begingroup\$

I had trouble in the past using the UART at 2Mbps but my problem was that the buffer at the receiving end was being filled before I could pop the received bytes.

I would get the first few bytes correctly and after that everything was garbage.

There are two things I would do:

  1. Check the lines with an oscilloscope (you mentioned a debugger but I don't know how you can check the logic level of the PCB traces with that) or a logic analyser to make sure that what pic is spitting out is correct. You can send bytes which in binary would be 01010101 so you can easily examine them on the scope's screen.
  2. I would not neglect the other side of the line. First of all check if the MAX32 chip can accept the baudrate you chose. AFAIK the FTDI chips have baud registers too so you can't feed it any baudrate. Secondly I would use the hardware handshaking pins and see if it makes a difference.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.