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 support@ccsinfo.com

RDA problem using pointers to buffer structure

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



Joined: 03 Oct 2011
Posts: 5
Location: Serbia

View user's profile Send private message

RDA problem using pointers to buffer structure
PostPosted: Sun Oct 09, 2011 4:55 am     Reply with quote

I'm trying to implement a double buffering input from rs232 (because I need synchronized IO timing to run some cnc router). So I have to use pointer to buffer structure, right? For testing reason, PIC is returning every char it receives on rs232. First 8 chars is OK, after that next n chars are garbage like, then 4 OK, then n of garbage again, etc. IO was OK before I've changed RDA routine to use pointer(to buffer). What is the catch (22)? I've tried to put some delay before and/or after sending back chars to rs232, same result.

Code:

#include <18F2410.h>
#device adc=10
#fuses EC_IO,WDT512,NOPUT,NOPROTECT,NOBROWNOUT,NOLVP,NODEBUG,NOPROTECT,MCLR
#use delay(clock=24MHz,restart_wdt)
#use rs232(UART1,baud=460800,stream=PC,ERRORS)

// CONST
#DEFINE LED PIN_A4
#define BUFFER_SIZE   256

// VARS
struct buffer {
char   buff[BUFFER_SIZE];
int8   next_in;
int8   next_out;
};

struct buffer RS232IN;
struct buffer RS232OUT;
struct buffer *PB;
char   C;
int16   sec;

#define DATA_IN(B)   (B##.next_in != B##.next_out)

boolean DATAIN(struct buffer *pb)
{
   if (pb->next_in == pb->next_out)
      return 0;
   else
      return 1;
}

char GET_FROM_RS232IN_BUFFER()
{
   byte retval;
   retval = PB->buff[PB->next_out];
   PB->next_out=(PB->next_out + 1) & (BUFFER_SIZE-1);
   return retval;
}

#int_RDA
void RDA_isr()
{
   int t;
   PB->buff[PB->next_in] = fgetc(PC);
   t=PB->next_in;
   PB->next_in = (PB->next_in + 1) & (BUFFER_SIZE-1);
   if (PB->next_in == PB->next_out) PB->next_in = t;
}

void main()
{
   PB = &RS232IN;
   PB->next_in = 0;
   PB->next_out = 0;

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF|ADC_TAD_MUL_0);
   setup_spi(FALSE);
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_BIT);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED|T2_DIV_BY_1,255,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_vref(FALSE);
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);
   setup_low_volt_detect(FALSE);
   setup_oscillator(False);

   // TODO: USER CODE!!
   RS232IN.next_in  = 0; RS232IN.next_out = 0;
   RS232OUT.next_in  = 0; RS232OUT.next_out = 0;
   sec = 0;
   output_low(LED);

   while(TRUE)
   {
      if (DATAIN(PB)) {
         C = GET_FROM_RS232IN_BUFFER(); //(RS232IN);
         output_toggle(LED);
         fputc(C,PC);
      }
      else output_low(LED);
   }
}


PS Using FT232R as usb2serial
temtronic



Joined: 01 Jul 2010
Posts: 9164
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Oct 09, 2011 5:31 am     Reply with quote

hmm..
the last line probably tells it all ..

"PS Using FT232R as usb2serial"

USB is not interrupt driven, non -deterministic, etc. as well, what other applications are running on the PC ?

Cut the link to the PIC, cut code on the PC to test that side of the connection.Odds are good some 'application' is affecting the PIC<->PC serial data transfer.A simple 'loopback' test for a few minutes may confirm the problem.If you want realtime control, add a real RS232 comport if possible. If not , get rid of ALL nonessential program on the PC.Hidden 'autoupdates' can cause 'odd' problems.You need to dedicate the PC to ONLY interfacing to the PIC,not have Internet access,etc.

If possible ,cut PC code using Delphi or some other truly standalone,very tight program that doesn't use Windows drivers,DLLs, etc.

Also be sure to use good solid conections and sheilding cables for the PIC<->PC interface.'Silly' things like a noisey router,neigbours arc welder,etc. might send a 'glitch' to your setup.

Divide and conqueur ! process of elimination....Prove WHERE the problem really is, then fix it. Don't always assume it's the PIC program.
tbb



Joined: 03 Oct 2011
Posts: 5
Location: Serbia

View user's profile Send private message

PostPosted: Sun Oct 09, 2011 7:05 am     Reply with quote

Guess you're right, but I'm still confused...

Code:
#int_RDA
void RDA_isr()
{
   int t;
   //PB->buff[PB->next_in] = fgetc(PC);
   RS232IN.buff[RS232IN.next_in] = fgetc(PC);
   //t=PB->next_in;
   t = RS232IN.next_in;
   //PB->next_in = (PB->next_in + 1) & (BUFFER_SIZE-1);
   RS232IN.next_in = (RS232IN.next_in + 1) & (BUFFER_SIZE - 1);
   //if (PB->next_in == PB->next_out) PB->next_in = t;
   if (RS232IN.next_in == RS232IN.next_out) RS232IN.next_in = t;
}


As you can see, I've put comment on code lines using PB pointer, and loading data into buffer named RS232IN goes well, but when I try to load data into pointer PB, things go wrong...

Code:
struct buffer {
char   buff[BUFFER_SIZE];
int8   next_in;
int8   next_out;
};

struct buffer RS232IN;
struct buffer *PB;


Code:


void main()
{
   PB = &RS232IN;
...
Ttelmah



Joined: 11 Mar 2010
Posts: 19346

View user's profile Send private message

PostPosted: Sun Oct 09, 2011 2:36 pm     Reply with quote

Seriously, sloth.....

It takes just one to three instructions instruction to read a byte from memory.
However to access an array, requires you to take the address of the array, add the offset to the byte required, load this into the table pointer registers, and then perform the operation. Typically a dozen instructions.
Accessing something via a pointer involves the same. Now you have pointers accessing things inside the ISR, multiple times (8!), and then one of these accessing an array referenced by this. I'd guess, perhaps 100 instructions....
It then takes typically 60 instructions to get into and out of an interrupt handler.
Your serial is at 460800bps, so up to 46000characters/sec. Your processor is doing just 6MIPS, so just 130 instruction times between bytes.....
With the hardware buffering, it takes a few cycles to run out of time, but then data loss follows.

The interrupt handler can be done more efficiently, even with a pointer, but not by much. Consider use of pointers inside an ISR, to be 'ill advised' on grounds of speed. If you want to have some form of 're-use' of buffer code, then instead use a #define macro.

Best Wishes
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Mon Oct 10, 2011 1:58 am     Reply with quote

All the above are important. Plus at at all speeds interrupt locking and atomicity are a real problem. Consider your code:

Code:

      if (DATAIN(PB)) {
         C = GET_FROM_RS232IN_BUFFER();


What happens if an interrupt occurs between calling DATAIN() and GET_FROM_RS232IN_BUFFER(), especially when the buffer wraps? What happens if interrupts happen while *inside* these functions? While it can happen at all speeds, it more more likely to happen at the very high baudrates you want to run at. The entire operation above - checking the buffer and reading from it - has to be atomic to prevent apparent data loss, misplaced bytes and garbage data. These can and often are due more to buffer mismanagement than to actual data loss on the comms line/hardware.

By the way, these are circular buffers, not double buffers. Double buffers are where there are two distinct buffer areas: one is filled while the other is emptied/used/processed. Circular buffering uses one buffer that's filled at one point while being emptied from another and is addressed/indexed/pointed to so that it appears to be a continous buffer space.

RF Developer
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