Serial probs proton to SF

General discussion relating to the library modules supplied with the compiler

Moderators: David Barker, Jerry Messina

Post Reply
Francis
Registered User
Registered User
Posts: 314
Joined: Sun Mar 25, 2007 9:40 am
Location: Devon

Serial probs proton to SF

Post by Francis » Mon Jun 11, 2007 9:58 am

I was wondering if someone could help with a little problem I have with moving a drop of (working) code from proton to SF.
My apologies for a great long post.

Basically, what I'm tryin to do is this:
1. Sit in a main routine waiting for USART serial input.
2. When data is detected then read it into a byte array. The data is variable length and I need a timeout as terminator.

All was fine in proton but I want to move it to SF and therefore have been jiggling things. Unfortunately I seem to have done something daft and as SF is pretty new to me I was after some guidance (pretty please).

This is the 'guts' of my code (warts 'n all):

Code: Select all

// device and clock...
Device = 18F2520
Clock =  8

//  SD file system settings, usart and soft I2C port numbers
#option SD_SPI = MSSP         // 
#option I2C_SCL = PORTA.4     // Use Software I2C
#option I2C_SDA = PORTA.5
#option WDT = true            // switch on wdt


' Include Libraries:-
Include "SI2C.bas"
Include "SDFileSystem.bas"
Include "usart.bas"
Include "Convert.bas"

// variables...
Dim Index , ErrFlag , TempLB, TempHB , TempSign , ConFB , GenByte , SerialBuffer As Byte
Dim SData(100) As Byte
Dim FName As String(15)
Dim Address , I , J , K As Word


// Aliases
Dim RXBUF          As PIR1.5                       ' Rx buffer contents flag bit
Dim RedLED         As PORTB.1
Dim GreenLED       As PORTB.0

// Initialise
Sub InitStart()
    SetBaudrate(br9600)
    SI2C.Initialize
    ADCON1=%1111
    OSCCON.7 = 0            ' Set to Sleep on Sleep command
    WDTCON.0 = 1            ' Watchdog ON as I need it later
     RCSTA = %10010000  ' Enable serial port and continuous receive
     RCSTA.4 = 0                 ' Clear and reset CREN (RCSTA.4)
     RCSTA.4 = 1
End Sub


// Read serial port
Sub ReadSerial()
    J = 0
    While  DataAvailableTimeout(50)
      SData(J) = ReadByte()                  ' Transfer byte to array
      If Overrun Or FrameError Then          ' Test for error
        USART.Write("Read Error",13,10)
      EndIf 
      Inc(J)
    Wend
    SerialBuffer = J - 1
    RCSTA.4 = 0                             ' Clear and reset CREN (RCSTA.4)
    RCSTA.4 = 1
    USART.Write("Received data (",DecToStr(SerialBuffer),") bytes.",13,10)
    For  J = 0 To 10 ' First 10 bytes of SerialBuffer
      'WriteByte(SData(J))         
      USART.Write(DecToStr(SData(J)),":")
      Repeat
      Until TXSTA.1 = 0
    Next
    
End Sub


Main:
InitStart()
USART.Write("Starting code",13,10)
While true
   USART.Write("Starting loop",13,10)
  Low(RedLED)
  DelayMS(500)
  High(RedLED)

  While Not DataAvailable               ' or RXBUF = BFalse
     ASM
       ClrWDT                           ' Sit here waiting for serial in....
     End ASM   
  Wend
  USART.Write("PIR1.5= ",DecToStr(RXBUF),13,10)     ' Let me know
  USART.Write("Data in",13,10)
  Low(RedLED)
  ReadSerial()                          ' goto readserial routine
  DelayMS(300)
Wend

  
Please note:
1. I am programming via serial onto a bootloaded 18F2520 for my testing.
2. I have scoped serial pins and have a luvvly clean signal and my serial i/f works perfectly.
3. Baud rates set correctly.

The problems:
I run the code and fire up the Serial Communicator.
It sits there waiting for data. Good.
I type in F (for example) into the Transmit window and click send.
It pops out of waiting loop and confirms PIR1.5 = 1. Also good.
BUT, this is where it starts to go wrong...
It should tell me that 1 byte has been received and send the ASCI for F back to the Serial Comm Rx window.
But it tells me that 40 bytes have been received, all ASCII value 255.
My 'scope shows 1 nice clean byte has been sent.

Then it goes back to the waiting loop, BUT ignores any further serial input.
If I put a test print inside the While Not DataAvailable loop it shows that PIR1.5 remains at 0.

Whilst there is obviously a more efficient way of coding what I'm trying to code, I can't see why it's going SO wrong.

Even mowing the lawn hasn't given me inspiration, so I was hoping a kind soul would spot my naive mistake.
Sorry, Tim, I don't want to use interrupts, but any help is gratefully accepted during my learning curve.
Thanks.

PS. Is it possible to get scroll bars for the CODE display like the proton forum?

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 » Mon Jun 11, 2007 12:06 pm

I've just taken a brief look at your code and there are a few things which stand out

(a) you have quite a few fixed delays in your code. Given the limited buffering capability of the PIC it is more than likely you will receive overrun errors for data streams
(b) SData(J) = ReadByte() should be SData(J) = USART.ReadByte()
(c) SerialBuffer = J - 1 - if J = 0, and SerialBuffer is byte then 255 would seem correct. Better to test J > 0 before processing.

I would also take a look at the 'Interrupt_OnData.bas' sample program. Rather than using DataAvailableTimeout(), you can just let the module buffer data in the background and test with ISRRX.DataAvailable(). Here is a skeleton program (which works) which should get you going

Code: Select all

include "isrrx.bas"
include "usart.bas"
include "Convert.bas"

// variables...
dim SData(100) as byte
dim SDataSize as byte

// Read serial port
sub ReadSerial()
    dim Index as byte
    SDataSize = 0
    while ISRRX.DataAvailable
      SData(SDataSize) = ISRRX.ReadByte()
      inc(SDataSize)
    wend
    
    if SDataSize > 0 then 
       USART.Write("Received data (",DecToStr(SDataSize),") bytes.",13,10)
       for  Index = 0 to (SDataSize - 1)
          USART.Write(DecToStr(SData(Index)),":")
       next 
    endif 
end sub

ISRRX.Initialize // init the ISRRX module!
SetBaudrate(br9600)
USART.Write("Starting code",13,10)
while true
  toggle(PORTD.0)
  delayms(500)
  ReadSerial()
wend 
Notice that the main loop has a 500ms delay between LED high and low. Without the ISR the USART buffer would certainly overrun. However, in the above code, no data is lost. The ISRRX module is also very easy to use, as it uses familiar ReadByte() and DataAvailable() calls - you don't have to worry about setting up the interrupt, the module will do it all for you!

Francis
Registered User
Registered User
Posts: 314
Joined: Sun Mar 25, 2007 9:40 am
Location: Devon

Post by Francis » Mon Jun 11, 2007 12:44 pm

David,

Yes, the changing the Readbyte to USART.Readbyte cured it. Thank you.
I only used Readbyte() as that was shown in the 'Samples' USART code that I looked at e.g. Echo.

SerialBuffer = J - 1 , ah my mistake. Grateful for your highlighting that.

All those 'test prints' were just for my investigation and I was only sending a byte at a time. They are all to be removed once it works - and now it does thanks to you.

The isrrx looks very interesting and useful. I shall, if I may, put that in my Grimoire for future use.

In my little project the 'sending' PIC sends data-blocks in a (potentially) discontinuous stream so, I would assume that in my project, testing ISSRX may detect presence of data but may not realise there is a timeout as a terminator. i.e. data may come in as byte-byte-little gap-byte-little gap-byte-byte - big gap. And I detect 'big gap' as the eod. I can't have a specific eod byte value. Sorry, probably doesn't make any sense.

This Swordfish is brilliant, well done!
And the support/help is much appreciated.

Regards,

Francis (on an enjoyable learning-curve).

Post Reply