|
|
View previous topic :: View next topic |
Author |
Message |
tbb
Joined: 03 Oct 2011 Posts: 5 Location: Serbia
|
RDA problem using pointers to buffer structure |
Posted: Sun Oct 09, 2011 4:55 am |
|
|
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: 9225 Location: Greensville,Ontario
|
|
Posted: Sun Oct 09, 2011 5:31 am |
|
|
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
|
|
Posted: Sun Oct 09, 2011 7:05 am |
|
|
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: 19504
|
|
Posted: Sun Oct 09, 2011 2:36 pm |
|
|
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
|
|
Posted: Mon Oct 10, 2011 1:58 am |
|
|
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 |
|
|
|
|
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
|