USART only returns first 2 bytes from incoming 8 bytes

Coding and general discussion relating to user created compiler modules

Moderators: David Barker, Jerry Messina

Post Reply
TonyR
Posts: 75
Joined: Fri Jan 14, 2011 11:49 pm
Location: Sydney
Contact:

USART only returns first 2 bytes from incoming 8 bytes

Post by TonyR » Sat Oct 29, 2011 5:37 am

Hi Everyone, this has got me stuck.

I send an "ATDL" string to an Xbee from the TX1 of my 18F87J50 USART and that causes the Xbee to return 8 bytes of data + <CR> to my RX1.

I can see the 8 bytes enter RX1 on my scope but my USART.readbyte loop runs out of chars after the getting only first two chars of the 8.

Im sending the incoming chars out on USART2 TX2 to a dumb terminal so I can see whats happening.

USART.Write("ATDL",13)
DelayMS(200)


while USART.DataAvailableTimeout(10)
c = USART.ReadByte()
USART2.Write(c)
Wend

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Post by David Barker » Sat Oct 29, 2011 8:41 am

I've tried the following and it works for me:

Code: Select all

Include "usart.bas"
dim c as byte
setbaudrate(br19200)
while true
   while USART.DataAvailableTimeout(10)
      c = USART.ReadByte()
      USART.WriteByte(c)
   Wend
wend
Notice the additional WHILE...WEND to prevent the program from terminating

TonyR
Posts: 75
Joined: Fri Jan 14, 2011 11:49 pm
Location: Sydney
Contact:

Post by TonyR » Sat Oct 29, 2011 7:57 pm

Hi David,

Thanks for reply.

Actually the ATDL command block and read.byte block that works is all in a while wend loop. Like that I get the two chars returned at a one second interval reliably. I did try the extra while and wend. When I do that it hangs. I don't get the two chars returned at all.

Heres a bit more of the code. The first block sends +++ to the Xbee which causes a return string of "OK"+<CR>. I get OK back, but the <CR> goes missing.

Code: Select all

dim c as char 
setbaudrate(br9600) 

         USART.Write("+++")  
         DelayMS(1000)       
         While USART.DataAvailable
             c = USART.ReadByte()
             USART2.Write(c)
         Wend         
 
         while
            DelayMS(1000)
            USART.Write("ATDL",13)    
            DelayMS(100)
                   
            While USART.DataAvailableTimeout(10)         
            c = USART.ReadByte()
            USART2.Write(c)   
            Wend
         wend
This code returns: ok4040404040....... but if I comment out the outside while and wend so the code only gets called once it hangs

TonyR
Posts: 75
Joined: Fri Jan 14, 2011 11:49 pm
Location: Sydney
Contact:

Post by TonyR » Sat Oct 29, 2011 11:16 pm

Hi David,

Some more info.

The first code block below works, it sends +++ to the Xbee which returns "OK"+<CR>. The OK comes back from USART.readbyte but not the <CR>. It disappears.

The second code block sends ATDL to Xbee and I get the correct string of data appearing on RX1 pin according to my scope but DataAvailable remains silent.

I send ATDL again in the third block which again causes the correct string of data to appear on RX1 pin according to my scope but DataAvailable and USART.readbyte return only the first two bytes of my data string but then silence!

Code: Select all

         USART.Write("+++")  
         DelayMS(1200)       
         While USART.DataAvailable
             c = USART.ReadByte()
             USART2.Write(c)
         Wend         
         usart2.write(13)
                           
         DelayMS(1000)
         usart2.write ("First try",13)
         USART.Write("ATDL",13)    
         DelayMS(100)  
         While USART.DataAvailableTimeout(10)         
            c = USART.ReadByte()
            USART2.Write(c)   
         Wend
                       
         DelayMS(1000)
         usart2.write ("Second try",13)
         USART.Write("ATDL",13)    
         DelayMS(100)
         while true
             While USART.DataAvailableTimeout(200)         
                 c = USART.ReadByte()
                 USART2.Write(c)   
             Wend        
         wend

Jerry Messina
Swordfish Developer
Posts: 1470
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Post by Jerry Messina » Sun Oct 30, 2011 1:47 pm

It's surprisingly difficult to get bidirectional serial communications working reliably when you just use delays and the like. You never know when the external device is going to be sending something, or how long you might need to wait. The USART module only provides a single character worth of buffering, and that's the extra char in the hardware usart itself.

Take a look at the ISRRX.bas module for an example of interrupt-driven serial port handling that uses a receive buffer. While it's a bit more involved, it's infinitely better for this kind of thing.

TonyR
Posts: 75
Joined: Fri Jan 14, 2011 11:49 pm
Location: Sydney
Contact:

Post by TonyR » Sun Oct 30, 2011 6:58 pm

Hi Jerry,

Thanks for your suggestion about ISSRX.bas. I might give up soon and try that.

This maybe related - USART1 is set br9600 and is 9600. I set my "monitor channel" USART2 to br9600 but what comes out is 2400. I didn't have time to chase this bug so my dumb terminal on USART2 is set to 2400. (I think thats something to do with BRG16).

Because I worried about that in another attempt I made a 10 byte receive "buffer" for USART1 with an SF array and tried to simply "clock" the 10 bytes in on "Data.Available" and got the same result. First two bytes OK, then none. ie. No I/O to USART2 and still only two bytes.

The PIC has ample processing speed to get those 9 bytes but it only gets the first two!

Jerry Messina
Swordfish Developer
Posts: 1470
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Post by Jerry Messina » Sun Oct 30, 2011 9:30 pm

There's plenty of speed. I run interrupt-driven serial links > 230K baud with no problems at all.

Code: Select all

         USART.Write("+++") 
         DelayMS(1200)       
         While USART.DataAvailable
             c = USART.ReadByte()
             USART2.Write(c)
         Wend   
The timing of this loop has to be very exact for it to work. After sending the "+++", if the device responds with more than two chars while "delayms(1200)" is executing, you'll lose characters. If you manage to make it into the while loop ok, the second time through the loop the "While USART.DataAvailable" will fail if the device has not sent another character before you do this test, so you could be off by 1us and have this fail. If uart2 baud rate is slower than uart1, you'll probably fail this loop as well.

Check the Overrun() routine after this loop, and you'll probably find it set. That would make sense... you get the "O" + "K" and then the CR is causing an overrun, or you'll find that it hasn't been transmitted yet before the loop gets to the next iteration.

It could well be that your buffering code suffers from the same sort of issues and that's why it doesn't seem to work either.

You need to restructure the loop to wait until you get a response, perhaps something like

Code: Select all

dim gotCR as boolean

USART.Write("+++") 
gotCR = false
while (gotCR = false)
    if (USART.DataAvailable) then
        c = USART.ReadByte()
        USART2.Write(c)
        if (c = 13) then
            gotCR = true
        end if
    end if
wend
You'll probably want to add some additional error handling to that since there's no provision for buffering, dropped/missing chars, uart errors, or an overall response timeout, but you should be able to see all the response chars as long as usart2 is at least as fast as usart1.

You're right about the 9600 baud running at 2400... either BRG16 or BRGH isn't being set to what you want.

Oh, and using ISRRX isn't giving up at all. On the contrary, it's implementing more of what you really need to get a serial link working properly. When you sit down and think about all the varying transmit, receive, and inter-byte delay times involved, as I said it's a lot more complicated than it seems at first.

TonyR
Posts: 75
Joined: Fri Jan 14, 2011 11:49 pm
Location: Sydney
Contact:

Post by TonyR » Sun Oct 30, 2011 10:08 pm

A light has just gone on in my head.

There's no buffering and it didn't occur to me there's no flow control eitherl!

Now I understand, thanks Jerry.

Post Reply