CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

INT_RDA fail to receive randomly

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
ELCouz



Joined: 18 Jul 2007
Posts: 427
Location: Montreal,Quebec

View user's profile Send private message

INT_RDA fail to receive randomly
PostPosted: Sat Nov 29, 2014 1:06 pm     Reply with quote

Hi,

In the code everything compile and work fine but I have a problem with the serial interrupt.

Often it miss chars. Shouldn't be like this.

I always keep my ISR the KISS way. No delays/long routine inside them whatsoever.


Code:

#include <18F2550.h>
#fuses HSPLL,PLL5,CPUDIV1,NOMCLR,NOLVP,BROWNOUT,BORV43,PUT,NOWDT,NOVREGEN
#use delay(clock=48000000)
#use rs232(baud=9600, xmit=PIN_C6,rcv=PIN_C7,errors)

#define runled PIN_A0
#define dataled PIN_A1
#define faultled PIN_A2
#define ONE_WIRE_PIN PIN_A4
#define door_pin PIN_A5
#define waste_pin PIN_A3
#define lasereye_pin PIN_C0

#include "ds1820.h" //temp sensor stuff

int1 sendflag = 0;
signed int8 temp;
unsigned int8 dummy,count,savedcount;
unsigned int1 door,waste,lasereye;

//*****************************************************************************
char version[16] = "1.0 29/11/2014"; /// change when releasing a new version !!!!!! <<<---
//*****************************************************************************

#int_timer0
void timer0_isr()
{
output_toggle(runled);
if (sendflag == false){sendflag = true;}
count++;
output_low(dataled);
}

#int_rda
void serial_isr()
{
dummy=getc();
output_toggle(dataled);
}

void sendpacket() //Start char $ and 0x02, sensor temp,door status,waste status,laser status, 8-bit CRC
{
unsigned int8 CRC;

CRC= temp^door^waste^lasereye; //xor everything
putc('$');
putc(0x02);
putc(temp);
putc(door);
putc(waste);
putc(lasereye);
putc(crc);
}


void main()
{


setup_timer_0(T0_INTERNAL|T0_DIV_128);
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);


   while(true){


      if (sendflag == true) { // packet sending
      temp = ds1820_read();
      door = input(door_pin);
      waste = !input(waste_pin);
      lasereye = !input(lasereye_pin);
      sendpacket();
      sendflag = false;
      }
     
      switch (dummy)
         {
         case '0' : output_b(0x00);//turn all used relay pins in a  Low state
         dummy = 0;
         break;
         case 'A' :output_high(pin_b0); // High Relay K0
         dummy = 0;
         break;
         case 'a' :output_low(pin_b0);
         dummy = 0;
         break;
         case 'B' :output_high(pin_b1); // High Relay K1
         dummy = 0;
         break;
         case 'b' :output_low(pin_b1);
         dummy = 0;
         break;
         case 'C' :output_high(pin_b2); // High Relay K2
         dummy = 0;
         break;
         case 'c' :output_low(pin_b2);
         dummy = 0;
         break;
         case 'D' :output_high(pin_b3); // High Relay K3
         dummy = 0;
         break;
         case 'd' :output_low(pin_b3);
         dummy = 0;
         break;
         case 'E' :output_high(pin_b4); // High Relay K4
         dummy = 0;
         break;
         case 'e' :output_low(pin_b4);
         dummy = 0;
         break;
         case 'F' :output_high(pin_b5); // High Relay K5
         dummy = 0;
         break;
         case 'f' :output_low(pin_b5);
         dummy = 0;
         break;
         case 'G' :output_high(pin_b6); // High Relay K6
         dummy = 0;
         break;
         case 'g' :output_low(pin_b6);
         dummy = 0;
         break;
         case 'H' :output_high(pin_b7); // High Relay K7
         dummy = 0;
         break;
         case 'h' :output_low(pin_b7);
         dummy = 0;
         break;
         case '?' :printf("$!*"); //keep alive
         savedcount = count;
         dummy = 0;
         break;
         case '@' :printf("$%s*",version); // version info
         dummy = 0;
         break;
         }
     
     
//!         if ((count - savedcount) > 3 ) //if keep alive fail reset relay
//!         {
//!         output_b(0x00);
//!         output_high(faultled);
//!         count = 0;
//!         savedcount = 0;
//!         }   
   


   }
}



I don't know why the line temp = ds1820_read(); make the ISR miss somes rx chars.
When I commented this line I receive 100% of the serial chars.

I don't understand why the ds1820 routine make the serial ISR go bad.

Delays in the main loop should NOT affect the ISR in any way but clearly in this case the few delay_us required for the DS1820 driver make the ISR miss some chars.

Do I need a buffer or something for a single character check (dummy switch)?


Thank you very much!
_________________
Regards,
Laurent

-----------
Here's my first visual theme for the CCS C Compiler. Enjoy!
ELCouz



Joined: 18 Jul 2007
Posts: 427
Location: Montreal,Quebec

View user's profile Send private message

PostPosted: Sat Nov 29, 2014 1:21 pm     Reply with quote

I think the workaround would be to put the entire switch statement in the serial ISR but that would be ugly and a slow/complex ISR.
_________________
Regards,
Laurent

-----------
Here's my first visual theme for the CCS C Compiler. Enjoy!
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Sat Nov 29, 2014 2:12 pm     Reply with quote

The problem is simple.
Time.

Look at how long the DS1820 routines take. They are _slow_. Problem is that all the time you are handling this, if _two_ characters arrive, the first will be lost with your code. The character _is_ received fine, but gets overwritten by the second character...

Go fractionally more complex in your service routine, and use a small ring buffer (just a handful of characters).
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Sat Nov 29, 2014 3:47 pm     Reply with quote

Ttelmah is right. The DS1820 is very slow to read/interact with, particularly if you wrote the interface code in a blocking manner.

I use that sensor on all the boards I've designed and I've come up with a method to read that chip that doesn't block. I can't share the code but I can tell you how to do it.

When you want to read temperature, initialize a timer and simultaneously set the DIO line low. Set the timer to correspond to the 1820's initial reset pulse length. When the timer's interrupt fires, set the line high and reload the timer for the next time quanta in the grand scheme. Proceed in this manner for the entire interaction sequence, substituting a DIO read instead of a set when you're reading the sensor. At the end of the entire sequence, disable the timer.

Voila. A non-blocking DS1820 interaction scheme.
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Sun Nov 30, 2014 2:27 am     Reply with quote

Agreed.
In his case though the DS code is not actually 'blocking', but his receive interrupt has no buffering. So if a second character is received before he handles the first, 'data loss'.... :(
This is where small buffers are so useful. Smile
ELCouz



Joined: 18 Jul 2007
Posts: 427
Location: Montreal,Quebec

View user's profile Send private message

PostPosted: Sun Nov 30, 2014 7:35 am     Reply with quote

Thanks guy for the explanation!

Do you have a very simple example of a ring buffer?

No need a full code just a snippet.

thanks again!

EDIT: found this but I think it's too complicated for just 2-3 chars of buffering...

http://www.ccsinfo.com/forum/viewtopic.php?t=20211
_________________
Regards,
Laurent

-----------
Here's my first visual theme for the CCS C Compiler. Enjoy!
ELCouz



Joined: 18 Jul 2007
Posts: 427
Location: Montreal,Quebec

View user's profile Send private message

PostPosted: Sun Nov 30, 2014 7:46 am     Reply with quote

Well after digging for awhile with google. I stumbled upon a post made by you Ttelmah few years ago (10 years!!!)!

Very useful for explaining the ex_sisr.c example.

http://www.ccsinfo.com/forum/viewtopic.php?t=19083

This example cannot be more simple I think.
_________________
Regards,
Laurent

-----------
Here's my first visual theme for the CCS C Compiler. Enjoy!
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Sun Nov 30, 2014 8:52 am     Reply with quote

One coda to that.

Everything is fine if you use _binary_ sizes for the buffer (2,4,8,16 etc..). However there is a problem if you want a 'non binary' size (3,5,6,7 etc.). With the binary size, the compiler codes x % y, using the & operator, so it only takes a single instruction. However if you use a non binary size, it has to use a division. This results in divisions having interrupts disabled in the main code, and is relatively large/slow.

So for 'non binary' buffer sizes, change this:
Code:

in = (++in % size);

to:
Code:

if (++in==size)
   in=0;


and the same when incrementing the 'out'.

This is small (only one instruction more than the '&' solution), and works for all buffer sizes. Smile

It's a thing that CCS ought to warn about in the example.
ELCouz



Joined: 18 Jul 2007
Posts: 427
Location: Montreal,Quebec

View user's profile Send private message

PostPosted: Sun Nov 30, 2014 9:24 am     Reply with quote

Thanks Ttelmah!

I'll stick to binary size buffer (easier for computing).

I don't see any empty slot in this example.

A true circular buffer must have an empty slot to determine end / start location right?
Otherwise it's hard to know when the buffer is full or empty...

Quote:
The CCS code handles this, by setting 'in' back to the last value if this happens, throwing away the newest character.


I find that odd that it overwrite by default the newest values. Isn't the point of a ring buffer to make a circle and erase older values first?
_________________
Regards,
Laurent

-----------
Here's my first visual theme for the CCS C Compiler. Enjoy!
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Sun Nov 30, 2014 10:17 am     Reply with quote

You don't have to have an empty slot.

If the increment will make the 'in' == 'out', then the buffer is full.

If 'in' == 'out' then the buffer is empty.

You can code to throw away the oldest. If the buffer is full, you increment 'next_out', to lose the oldest character. Realistically the point is that if the buffer is sensibly sized you shouldn't overflow.

If you want, you don't even have to code the buffer. You can let the compiler do it 'for you':
Code:

#use rs232(BAUD=9600,UART1 ,ERRORS, RECEIVE_BUFFER=8)

//Then don't code an INT_RDA, or enable it (the compiler will do this)

//Then replace the switch, with:
    if (kbhit())
    {
       switch (getc())
       //and test as required

    }
    else
    {
       //here do your 'no character' stuff

    }


The compiler will automatically generate a receive ISR, enable it, and automatically change 'kbhit' to test the status of this, instead of the physical port.
ELCouz



Joined: 18 Jul 2007
Posts: 427
Location: Montreal,Quebec

View user's profile Send private message

PostPosted: Sun Nov 30, 2014 11:23 am     Reply with quote

Thanks for the clarification Ttelmah! Smile

Have a nice day!
_________________
Regards,
Laurent

-----------
Here's my first visual theme for the CCS C Compiler. Enjoy!
jeremiah



Joined: 20 Jul 2010
Posts: 1358

View user's profile Send private message

PostPosted: Mon Dec 01, 2014 9:26 am     Reply with quote

As a note:
Unless it has changed in the last half year or so, the built in buffer that Ttelmah mentioned does have a noteable downfall in that if you ever fill the buffer it completely starts over, losing the current contents of the buffer. Instead of doing the pre increment check for next_in == next_out, it increments it regardless, resetting the buffer size back to 0 (and then to 1 for the next byte that comes in).
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Mon Dec 01, 2014 10:09 am     Reply with quote

It still does.

I pointed this out here, and to CCS right when they first launched it.

It is a downside, and rather silly....
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group