Serial Implementation

12 Oct 2010 . Edited: 12 Oct 2010

Hi All,

I've implemented a serial logger capturing data on UARTs 1 & 2 (both 4800:even:1stopbit) & it appears to be experiencing bit slip on UART2 (possibly UART1 but I've not really checked as most of the data comes in UART2).

After 32 or 33 (& always 32 or 33) characters received correctly, the logger records 0x80 where 0x00 should be, 0x8E where 0x1C should be, etc.; for the next 7 characters.

It then records 0x40 where 0x00 should be, 0x47 where 0x1D should be. Again for 7 characters.

This error is not seen when the mBed is generating it's own test data (on UART1 tx pin), only when it's capturing on the actual system.

Would it be possible to look at the serial class implementation ?? Also is this a hardware or a software UART ?? It looks like the UART is not framing properly - hence why 0x00 appear as 0x80, then 0x40 (it's even parity).

I'll be very happy to sign NDA's & the like.

12 Oct 2010

Hi

The mbed serial class uses the 16byte hardware FIFO buffer that is on the LPC1768, i susspect that you may be overruning these buffers and hence seeing corupt data.

Try looking at Andy Kirkham's SerialBuffered Class as this solved some serial buffering issues for myself.

Hope this helps

Matt

12 Oct 2010

Thanks for your response.

I'm reading the line status register & I'm not seeing any overflows reported. I also know the data that I should be seeing namely 1a,00,00,00,1b,00,00,00,1c,00,00,00,...,2a,00,00 looping. What I'm actually seeing is 1a,00,00,00,1b,80,80,80,8e,80,80,80,47,40,40,40 ... Overflowing the 16-byte buffers would not cause this. A PLL drifting while ignoring the framing would.

The data is always correct after a pause in UART RX (i.e. a stream of 1's on the line) & appears to lose sync after 32-33 characters - the last 27 or so are as described above (i.e. mostly a stream of 0's on the line).

How do you know it's a hardware FIFO ?? Links to datasheets would be greatly appreciated.

Cheers

12 Oct 2010

Hi All,

@Matt, thanks for the citation :)

@Patrick, without more details it's going to be hard to get a full solution. I'll explain.

Given your application is getting two streams at 4800 buad, personally I'd say this is very slow compared to the LPC1768 core speed. The 16byte hardware buffer really ought to be enough but only depending upon how you are handling the stream. By way of example, think about an average GPS module. It sends NMEA packets at, usually, 9600baud (I have one of these in my project). However, the GPS will only burst data once per ssecond. This is where buffers come in useful. They can take "lumpy data" and stream it in at a nice rate for your application. But if your application isn't servicing the buffer fast enough, no buffer will save you, you'll eventually overflow. The bigger the buffer, the longer until the overflow but it will come at some point.

So the key here is what does your incoming data stream look like? Does it come in bursts or is it a continuous none stop stream?

regards,

--Andy

12 Oct 2010

Seems we cross posted.

Datasheet at http://mbed.org/handbook/mbed-NXP-LPC1768  (look at the end of the page).

Do you get the same result with my SerialBuffered class? It should be a drop in replacement.

12 Oct 2010

Agreed, 4800 baud is well within the capabilites of the hardware. I do not believe this is a bandwidth/throughput issue.

I copy the rx'd data into a 1K circular buffer - ISR driven on the first character received. The hi-tide mark in the 16-byte FIFO is never more than 3 characters (& then I'd bet as a result of the debug code I had in there - now removed), in the 1k buffer it's never more than 59 (which is when I close & open the file descriptor to the SD flash filing system) - 1K is probably overkill :-)

I know what the data should be, this is not what is recorded. To make this clearer, if the thing I'm logging from only transmits values between 0x00 & 0x0F,  then no amount of buffer overflow would cause 0x3C (say) to be recorded. I can't see how this is overflow.

The data is poll/response which loosely goes as | what's up | < nothing much> | what's up | < nothing much > | what's up | < OMG there's loads to tell you about - you'd better put a pot of coffee on .... >. It's 32 - 33 bytes into the big one where it all goes bad & stays bad until it's finished after which it recovers & the next rx'd data is good.

The reason I believe it's a sync/framing issue is this - the data on the line appears as:

           111111111100000000001000000000010000000000100000000001

where the preamble of ones is no data on the line followed by the start bit 0 (where the UART syncs OK) 8 bits of 0's lsb first followed by the (even) parity bit & the stop bit 1. This gets read as 0x00 successfuly for 32 characters, then as 0x80 for 7 characters, then 0x40, etc. Also my none zero data between the 0's is shifted. ie. I'm expecting 0x1c (0001 1100) but I'm seeing 0x8e (1000 1110) & so on.

So - can I get visibilty of the Serial class sources ?? Please ;)

12 Oct 2010

Well, you are asking the wrong person for the code to teh Serial class. The people at Mbed have decided they are not going to publish their code.

But my code is public and basically overloads most of teh Serial class functions replicating them but with my own code. So is the problem stil there with my code? That we can see (it's public here). You haven't mentioned that yet.

Also, you state you are using Mbed Serial class library but then you are reading LPC_UART1->LSR and also have you're own ISR. So far I have found that sometime mixing you're own register level code with Mbed libraries can have unexpect results (see http://mbed.org/forum/bugs-suggestions/topic/1130/ ) so without seeing your code it's rather hard to tell.

12 Oct 2010

Boo to not sharing the code - I'd be happy to fix it for them, gratis.

The RX handler is attached via the serial class - taht's what I meant by ISR driven; sorry if it caused some confusion.

I'm reading the LSR as it's good practice - some hardware implementations require it.

The mBed serial class sits on top of the driver - as does your buffered class & my code. The problem is not here & cannot be fixed (easily or properly anyhow) here. The data that the serial driver is presenting to the software upstream is wrong. If you pump crap into a pipe, then you can do whatever changes you like to the pipe, you'll still get crap coming out the other end.

I haven't tried your code - I don't think it will fix anything (mine is essentially a cut down version targetted at this specific task): the problem happens somewhere between Serial::getch() & the tin.

Thanks for your reply - I didn't know about mixing register accesses with mbed libs caused problems.

12 Oct 2010

Hi Patrick,

It sounds to me like it could be down to a baudrate mismatch, where one end (mbed or the source device) not quite transmitting within tolerance.

If you can give us an email at support@mbed.org with the summary and, if possible, the device you are talking to, we'll raise a ticket and investigate it with you. It'd be good to get to the bottom of it.

Thanks!

Simon

12 Oct 2010

Hi Simon,

Thanks for your input - I'll send something in the morning. What are the tolerances in the baudrate - & how is this accomodated for in the framing ?? I'm asking as I'm considering writing my own serial driver & don't want to waste my time if I can't improve on what's already there.

The devices (2) I'm listening to are not generally available, no help there. But IIRC I have scope traces for the line levels (RS232) as I was wondering about the possibility of noise causing this badness. I'll have a looksee but I recall they were pretty bob on.

12 Oct 2010

I don't think accessing the registers is going to be a problem with the Mbed libraries unless you're doing something "exotic". If your just reading LSR then I can't see a problem with that. Have to say, like Simon says, does sound like a baudrate problem.

Just to give you some confidence, my project is using all 3 UARTs and I haven't yet seen a problem with baudrates. But there again, I haven't used 4800, only 9600 and higher. That might be a clue?

12 Oct 2010

No - no black magic or exotic register accesses (yet ;-) ) Just reading the LSR. Checking the overflow bit

I agree - it's a sync issue. That's why I asked about HW/SW UART implementation. I'm familiar with 16550 et al & I can't see that implemetation losing the start bit. A software implementation with a PLL, however, could drift.

I'd have thought that slower rates would be more tolerant (that why they're there - to handle 1950's switching technology) but I don't yet know what compromises there are in the system clock frequencies & dividers to achieve 4800. Config is the first place to look which is why I'd like a peek at the sources. Thanks Andy for the clue

Can anyone using external 4800b contribute ??

13 Oct 2010

If you look at the baud rate calculator I did here:-

http://mbed.org/users/AjK/libraries/SerialBuffered/lfp8fd/docs/sb__aux_8cpp_source.html#l00038

and then run all the possible permutations for 4800 you get whole numbers across the board (baud, bad pun!) so I don't see any room/margin for error within the Mbed for a baud rate mismatch.

13 Oct 2010

user Patrick Blanchon wrote:

I haven't tried your code - I don't think it will fix anything (mine is essentially a cut down version targetted at this specific task): the problem happens somewhere between Serial::getch() & the tin.

Someone is trying to help you with a possible solution. You could've at least tried it before brushing off the offer.

I think you should also publish your code (unless it's propietary).

13 Oct 2010

user Andy Kirkham wrote:

If you look at the baud rate calculator I did here:-

http://mbed.org/users/AjK/libraries/SerialBuffered/lfp8fd/docs/sb__aux_8cpp_source.html#l00038

and then run all the possible permutations for 4800 you get whole numbers across the board (baud, bad pun!) so I don't see any room/margin for error within the Mbed for a baud rate mismatch.

Apologies. When you suggested using your buffered class I was under the wrong impression that it was overloading the serial class (IIRC it used to do that) - hence my reluctance to try it as the issue is in the UART FIFO syncing. I had no idea until I read the link above that you'd implemented it anew from the tin thru' to the getch().

I'm giving it a go now.

@Ivor: I wasn't brushing off any offers - I was just under the totally wrong impression that it was a waste of my time to try it. Apologies also.

Thanks again to everyone.

13 Oct 2010

@ Andy: The documentation was an unexpected bonus - thanks again. There's a typo in it: the documentation erroreously states taht the valid stop bits for the format function are SerialBuffered::None, One ... This should be SerialBuffered::StopBit1, etc...

If you're using 6 or 8 bit characters with 1 stop bit then using SerialBuffered::One won't be an issue as the stop bit parameter - deviate from this tho' & you'll see behaviour.

Cheers again - don't know yet if it's working.

13 Oct 2010

Hi Patrick,

Here is a quick program to dump out all the uart divider settings:

#include "mbed.h"

DigitalOut myled(LED1);

Serial s(p9, p10);

int main() {

    // setup the baudrate of UART3 to 4800
    s.baud(4800);

    // extract the resulting divider values that were setup   
   
    LPC_UART3->LCR |= (1 << 7);     // set LCR[DLAB] to get access to dividers
    int dlm = LPC_UART3->DLM;
    int dll = LPC_UART3->DLL;
    int div = LPC_UART3->FDR & 0xF;
    int mul = LPC_UART3->FDR >> 4;
    LPC_UART3->LCR &= ~(1 << 7);    // clear LCR[DLAB]

    int pclk = 96000000;

    // from LPC1768 User Manual, 14.4.12 :
    float baudrate = pclk / (16.0 * (float)(256 * dlm + dll) * (1.0 + ((float)div / (float)mul)));
    
    printf("dlm = %d, dll = %d, div = %d, mul = %d\n", dlm, dll, div, mul);
    printf("baudrate = %f\n", baudrate);
}

If I run this, it seems to confirm that the baudrate dividers are setup correctly:

Section 14 of the LPC1768 User Manual discusses all the UART related settings and features, so it might be worth working through that and see if there is anything there that stands out. You are using parity which I guess is less common. Perhaps you could report back once you've experimented with Andy's code too.

Hope this helps, or at least eliminates some things.

Simon

13 Oct 2010 . Edited: 13 Oct 2010

Well Andy's code behaves in exactly the same way - still worth a try tho'.

The issue as I believe it to be is the tx baud rate is not quite what it should be - I just seen some traces that suggest that it's 4791.1b. I don't yet know if this is a systematic error that I can accomodate by changing the rx baud rate or if it's drifting around 4k8 & it needs tracking. This difference means that on a fixed sampling period of 4.8kHz I'd be 1 bit early after ~49 characters so it's feasable that after 32/33 characters I'm sampling in the previous bit.

So what are the tolerances in the UART - does anyone know ?? Also why is the UART not syncing on the start bit & not detecting & correcting framing errors (if this is indeed the issue - which it might not be) ??

 

Thanks again.

13 Oct 2010

Hi Patrick,

Assuming you mean the tx that is slightly off is your other non-mbed source, perhaps you could try and compensate by setting the mbed baudrate to match what you are seeing e.g. call baud() with 4791? As you say, if it is jitter on your device, that may not help so much, but it could be your device is just not quite on the money e.g. low accuracy oscillator.

Simon

14 Oct 2010
user Simon Ford wrote:

Hi Patrick,

Assuming you mean the tx that is slightly off is your other non-mbed source, perhaps you could try and compensate by setting the mbed baudrate to match what you are seeing e.g. call baud() with 4791? As you say, if it is jitter on your device, that may not help so much, but it could be your device is just not quite on the money e.g. low accuracy oscillator.

Simon

I could do. It's specualtion ATM but everyhing does point to bit slip. What I'd really like to know is why the FIFO isn't synced to the falling edge of the start bit - if this is the case. If anyone can come up with a test to verify this I'd be grateful.

14 Oct 2010 . Edited: 14 Oct 2010

On a test Mbed I connected p9 to p14 and then ran the following code:-

#include "mbed.h"

DigitalOut myled(LED1);

Ticker onesec;

Serial pc(USBTX, USBRX);
Serial tx(p9, NC);
Serial rx(NC, p14);

int test[16] = { 0x1a, 0, 0, 0, 0x2a, 0, 0, 0, 0x3a, 0, 0, 0x4a, 0, 0, 0 };

void sendchars(void) {
    // Fill the 16byte TX FIFO with 16chars.
    for (int i = 0; i < 16; i++) {
        tx.putc(test[i]);
    }
}

int main() {

    pc.baud(115200);
    tx.baud(4791);
    rx.baud(4800);

    onesec.attach(&sendchars, 1);
    
    while(1) {
        if (rx.readable()) {
            pc.printf("%02x", rx.getc());
        }
    }
}

Notice the TX baud is deliberately set to 4791.

All my tests runs so far have failed to reproduce what you report seeing. My example shows what Serial rx gets is what tx sends even though there is a deliberate baud rate mis-match.

Think it's time for you to get a scope and actually look at whats arriving at the MBed serial input and "really see for sure" what is going in. It may help if you used an output from teh Mbed to create a 16x clock that you can feed into a dual trace scope to actually see what's really going on.

 

Update: I added Simon's code for reading the baud rate divisors to calculate the actual baud rates in use after setup and here's what I got:-

dlm = 2, dll = 136, div = 14, mul = 15
UART3 (p9) baudrate = 4789.271973
dlm = 4, dll = 226, div = 0, mul = 1
UART1 (p14) baudrate = 4800.000000

So Uart3 isn't exactly 4791, but it's still "deliberately incorrect" and off from 4800. So, I think as I said, you are left either a) looking at the incoming signal with a scope or an LA or b) getting a max232 and some caps and shoving the signal straight into your PC terminal to see what it makes of it or both a and b

14 Oct 2010

Hi Patrick,

Here is an example testing for framing errors:

// See when the rx UART looses framing based on baudrate shmoo, sford
// connect p13 to p10

#include "mbed.h"

Serial device(p13, NC);
Serial m(NC, p10);

int main() {
    m.baud(4800);
    m.format(8, Serial::Even, 1);
    device.format(8, Serial::Even, 1);

    for(int baud_rate=4800; baud_rate>=4000; baud_rate -= 25) {
        device.baud(baud_rate);
        device.printf("Hello world! How are you today! Hello world! How are you today!\n");

        wait(0.05);

        int frame_error = (LPC_UART3->LSR >> 3) & 1;
        m.getc();  

        printf("baud_rate: %d, frame_error: %d\n", baud_rate, frame_error);
    }
}

And the results I get:

So this shows the program is working and the framing errors do get detected. Hope you can use this to help further your investigations.

Simon

14 Oct 2010

user Simon Ford wrote:

Hi Patrick,

Here is an example testing for framing errors:

 

// See when the rx UART looses framing based on baudrate shmoo, sford
// connect p13 to p10

#include "mbed.h"

Serial device(p13, NC);
Serial m(NC, p10);

int main() {
    m.baud(4800);
    m.format(8, Serial::Even, 1);
    device.format(8, Serial::Even, 1);

    for(int baud_rate=4800; baud_rate>=4000; baud_rate -= 25) {
        device.baud(baud_rate);
        device.printf("Hello world! How are you today! Hello world! How are you today!\n");

        wait(0.05);

        int frame_error = (LPC_UART3->LSR >> 3) & 1;
        m.getc();  

        printf("baud_rate: %d, frame_error: %d\n", baud_rate, frame_error);
    }
}

And the results I get:

So this shows the program is working and the framing errors do get detected. Hope you can use this to help further your investigations.

Simon

Thanks for this. I can't run up the code as I don't have my mbeds to hand & I'm waiting on a delivery of my next one.

It would be interesting to see what happens to the other status values in the LSR - & would be really interesting what happens when a stream of 33+ zeros is received & if we actually get 0's received, or if it's 0x00 for a while followed by 0x80, then 0x40, .... If you have a mo I'd be grateful if you could try.

15 Oct 2010 . Edited: 15 Oct 2010

Sorry Andy - I totally missed your post.

Thanks for trying to reroduce this with sample data simialr to my own. I'm not surprised you didn't see anything wrong.

I've enabled the Line Status Interrupt in your buffered class & I'm logging errors - well I think I am but I'm not seeing any reports of framing/parity/overflow/break errors. Absence of evidence is not evidence of absence but it's consistent with it working OK.

Looking at the data captured some more & it's clear that bit slip would only account for the first few characters - after a while it's all brown stuff The capture below show this: the 1st column increments from 0x0 to 0xF, the rest are zeros. If you write these down as bit stream as they appear on the line then bit slip can' explain this:

00,00,00,00
01,00,00,00
02,00,00,00
03,00,00,00
04,00,00,00
05,00,00,00
06,00,80,80
10,10,10,10
08,08,08,28
08,08,08,48
08,28,08,68
08,08,04,04
04,04,04,14
04,04,04,24
04,04,04,34
04,04,04,84

I'm scraping the bottom of the barrel & have two q's:

1) is the UART implemented in software or hardware ?? If it's software I'm wondering if I'm being starved by doing other stuff (SD i/o)

2) There's every chance that this board has been plugged straight into the serial lines & would have seen +/-7V on UART 1 & 2 pins. Could this cook it ??

Cheers again

 

Update: THe logger is teed (if that's a word) in between 2 devices - both of which are logging to hyperterm what they're saying/hearing. Neither has an issue - both tx & rx expected data. There's no flow control.