5
\$\begingroup\$

I am trying to send my name (Ziga) through my micro-controller UART periphery to my PC. GND, Tx, Rx lines from micro-controller are directly connected to the UART-USB converter CP2102 which is pluged into my PC.

My PC is running Linux OS and I am using application minicom to check for transferred information. During Transmission my minicom terminal prints some weird symbols (click to zoom in):

enter image description here

and if I enable "HEX display" option I get these values (click to zoom in):

enter image description here

The values are 0x5C = 92 which is \ in ASCII then 0xFC = 252 which hasn't got any sign in old ASCII so it becomes ?, then there is 0x40 = 64 equal to @ in ASCII and finally 0x81 = 129 which again isn't defined in old ASCII so it becomes ?.

while I am getting correct image on my osciloscope (click to zoom in):

enter image description here

Why don't I get ZigaZigaZigaZiga... in minicom console? Values for single letters are correct acording to ASCII table.


ADD 1:

I took an oscilloscope image of letter a from Ziga. I hope this can help to determine if micro-controller baudrate is correct.

enter image description here


ADD 2:

I tried using 2 stop bits on minicom as well as on micro-controller and I get a different result which is even worse - it only transfers 3 characters instead of four (Ziga has four). Take a look:

enter image description here


ADD 3:

I found this info about external oscilators. Does this mean PCLK clock mentioned in micro-controller user manual is 12Mhz?

enter image description here


ADD 4:

So we figured out that it must be a baudrate problem, so I started reading user manual and found out on page 21 that my PCLK = 3MHz by default. Then I chose an algorithm on page 509 to calculate values:

DLL = 0
DLM = 13

DIVADDVAL = 1
MULVAL = 2

These values should give me 9600 baudrate according to the equation (4) on page 508. Well it gives 9615.384615 which should be 0.16% accurate. So then I started programming and I set the values above like this:

DLL &= ~(0xFF);                //setting first byte to 0  (divisor latch least signifficant byte)
DLL |= 13;                     //setting first byte to 13 (divisor latch least signifficant byte)
DLM &= ~(0xFF);                //setting first byte to 0 (divisor latch most signifficant byte) -- not really needed
DLM |= 0;                      //setting first byte to 0 (divisor latch least signifficant byte) -- not really needed
FDR |= (1<<5); FDR &= ~(1<<4); //setting value MULVAL
FDR |= 0x1;                    //setting value DIVADDVAL

But still I don't get right baudrate...

\$\endgroup\$
24
  • 1
    \$\begingroup\$ Wrong baud rate? \$\endgroup\$
    – Armandas
    Jan 4, 2016 at 17:45
  • 1
    \$\begingroup\$ What is the time/div setting on your 'scope? If its 250uSec/div then your baud rate looks right. \$\endgroup\$
    – brhans
    Jan 4, 2016 at 18:17
  • 1
    \$\begingroup\$ What microcontroller are you using? \$\endgroup\$ Jan 4, 2016 at 18:17
  • 2
    \$\begingroup\$ Try working with 2 stop bits. Perhaps it's missynchronized. \$\endgroup\$
    – Eugene Sh.
    Jan 4, 2016 at 18:43
  • 1
    \$\begingroup\$ Anyway, if your bit length is 300/8usec = 40uSec, then your baud rate is 1/40uSec=26.67k, not 9600 \$\endgroup\$
    – Eugene Sh.
    Jan 4, 2016 at 18:49

4 Answers 4

1
\$\begingroup\$

I just ran into this same problem myself. The OP's 9600 baud rate setup worked for me where the values calculated from the manual did not.

The issue for me was that the default startup code used in my project (Keil using the LPC4000_DFP-1.1.0 pack) calls a function "SystemInit" which sets up the clock registers to non-reset values.

The problem function resides in "system_LPC407x_8x_177x_8x.c". The function is called from start-up code in "startup_LPC407x_8x_177x_8x.s".

One solution is to copy both files into your project rather than using the standard ones and modify the C file to setup the clocks the way you want them. Alternately, you can modify the assembler file to prevent the call to "SystemInit" altogether; be aware however that in this case you will need to set up the co-processor yourself (as in "fpu_init", which is called from "SystemInit"), as this appears to be necessary for normal functioning (I'm not yet clear why).

\$\endgroup\$
3
  • \$\begingroup\$ And this is why I hate STARTUP CODE which isn't supplied as a source code but rather just an object file... Do you maybe have a source code for the startup file? I need the one for GNU compiler... \$\endgroup\$
    – 71GA
    Jan 30, 2017 at 19:28
  • \$\begingroup\$ Sorry, no. The startup code I used was for MDK-ARM (armcc). I don't have this installed at the moment, but it's free to download and you could probably adapt it to gcc easily enough. \$\endgroup\$
    – Carl
    Jan 31, 2017 at 22:53
  • \$\begingroup\$ Looks like I'll have to write it myself... Why are they hiding this? Does anyone know? =/ \$\endgroup\$
    – 71GA
    Feb 2, 2017 at 8:51
3
\$\begingroup\$

I think you have a baud rate mismatch.

At 9600 baud, each bit should be ~104us wide. Here is an actual ASCII 5 on the scope with a single bit timed at 105us...

enter image description here

(note that ASCII 5 is a handy char for testing because it is alternating ones and zeros in binary)

At 9600 baud, a single byte should be ~833us wide (8 data bits, not counting start and stop)....

enter image description here

Your trace shows the same 8 bits taking ~300us, so your serial clock is about 2.7x too fast.

Try setting your baud rate in Minicom to 26656 baud and see what you get. If you see Ziga, then you can start looking for why the serial clock is too fast.

\$\endgroup\$
1
  • \$\begingroup\$ for seeing bits ascii U is even better than 5 it's up-down all the way from start bit to stop bit. \$\endgroup\$
    – Jasen
    Jan 4, 2016 at 22:56
2
\$\begingroup\$

What you show looks like typical baud barf.

One of your diagrams shows you are sending 8 bits in 300 µs, which means 26.7 kBaud. That's a odd value. Try a standard baud rate, like 9600, and make sure your PC is set to that. 9600 baud means 104.2 µs per bit time, so 8 bits should take 833 µs and a full 10-bit (1 start bit, 8 data bits, 1 stop bit) character 1.04 ms.

\$\endgroup\$
4
  • \$\begingroup\$ Please take a look at ADD 4 in my question. I added some explanation regarding the baudrate calculation as described in the documentation. I also added some C-programming lines where I set those values. \$\endgroup\$
    – 71GA
    Jan 4, 2016 at 22:36
  • 1
    \$\begingroup\$ @71GA: I'm not familiar with your processor. Most UARTs want a clock that is 16x the baud rate. If you want 9600 baud, then you need to feed it 153.6 kHz. Starting with 3 MHz, that would require dividing by 19.5, which isn't going to work. 4800 baud would require dividing by 39.06, so 39 should work. That may require loading 38 into a register depending on how your hardware works. \$\endgroup\$ Jan 4, 2016 at 22:46
  • \$\begingroup\$ The lowest I can observe on my PC is 9600. \$\endgroup\$
    – 71GA
    Jan 5, 2016 at 0:38
  • \$\begingroup\$ @71GA: So set it to 4800. It's not going to magically happen by itself so that you can observe it. \$\endgroup\$ Jan 5, 2016 at 11:31
1
\$\begingroup\$

This thread still isn't solved but we discovered that I had a UART baudrate mismatch and I can confirm this. But where is the problem? If I read LPC4088 user manual I can read that it uses 12MHz internal oscillator (p.7). Thanks to you I also found clock generation chapter (p.21) with this schematic:

enter image description here

Now to completely understand this we need to search documentation for default values of multiplexers CLKSRCSEL[0]=0 (p.34), CCLKSEL[8]=0 (p.33) and divider PCLKSEL[4:0]=0x4 (p.34). So I should be getting PCLK = 12Mhz/4 = 3MHz but I think this is not true or there must be a mistake with the algorithm to calculate baudrate or equation (p.508, p.509):

enter image description here enter image description here

In my case I tried to calculate with PCLK=3MHz and I wanted baudrate 9600. So first I calculated DL_EST = PCLK/(16*9600) = 19.53 (EST stands for estimate) and this isn't an integer so FR_EST = 1.5 and DL_EST = PCLK/(16*9600*1.5) = 13.02 = 13. Next we calculate FR_EST = PCLK/(16*9600*13) = 1.5024. It holds that my 1.5 < FR_EST < 1.9 so I can read values for a divisor latch DL from the table (p.510):

enter image description here

From the tables and calculation above it follows that in my case:

DIVADDVAL = 1
MULVAL = 2
DL = 13

Because DL = 13 = 00000000 00001101 consists of divisor latch least significant byte DLL and divisor latch most significant byte DLM, those two are equal to:

DLL = 13
DLM = 0

I used those values to program LPC4088 UART baudrate, but I didn't get 9600 like I should. I even double checked the supplied equation which returns 9615.384615 and this is 0.16% accurate which looks fine.

Well I gave up on the NXP's algorithm/equation and tried to work by trial and error and I found out that:

DIVADDVAL = 1
MULVAL = 2
DL = 255         //this means DLL = 255 and DLM = 0

Returned 9600 baudrate and I could communicate with my PC just fine. But I still don't know what the error is. Am I doing anything wrong in the code or is it NXP who provided wrong algorithms?

Here is my fully working C program. Do you notice any errors?

#include "LPC4088-ioconfig.h"
#include "LPC4088-system.h"
#include "LPC4088-gpio.h"
#include "LPC4088-uart.h"


int main(){

    //PIN settings    
    IOCON_P0_0 &= ~(0x67F);
    IOCON_P0_0 |= (1<<1);
    IOCON_P0_1 &= ~(0x67F);
    IOCON_P0_1 |= (1<<1);

    //turn on UART3
    PCONP |= (1<<25);

    //we set 8-bit characters, no parity, one stop-bit in LCR register
    //LCR.DLAB = 1
    LCR |= (0x3);
    LCR &= ~(0x7C);
    LCR |= (1<<7);

    //set DLL[0-7] = 255, DLM[0-7] = 0, FDR[0-3] = 1, FDR[4-7] = 2
    //values obtained by trial & error - NXP's algorithms don't work
    DLL &= ~(0xFF);
    DLL |= 255;
    DLM &= ~(0xFF);
    DLM |= 0;

    FDR &= ~(0xFF); 
    FDR |= 1;           //DIVADDVAL 
    FDR |= (2<<4);      //MULVAL

    //LCR.DLAB = 0 
    LCR &= ~(1<<7);

    //enable Rx and Tx FIFO
    FCR |= 0x1;

    unsigned char posiljka[] = "Ziga";

    while(1){

        for ( int i = 0 ; i < ( sizeof(posiljka)/sizeof(posiljka[0]) -1 ) ; ++i ){

            //we read LSR and wait for THR to empty
            while ( (LSR & (1<<5)) != (1<<5) );

            //send one character at a time
            THR = posiljka[i];
        }
    }
}
\$\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.