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

Trying to capture data from another device

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








Trying to capture data from another device
PostPosted: Sat Aug 09, 2008 1:44 pm     Reply with quote

Im trying to capture the data from a handheld laser range finder. Specifically, I'm reading the three logic signals going to the lcd. There is a data signal, a clock signal, and an enable signal. I'm guessing that this is an i2c bus, but I'm not sure.

Code:


#int_ext
void ext_isr() //enable
{
  if(int_edge_flag == 1)  // edge = H_TO_L, data is coming
  {
    ext_int_edge(0, L_TO_H);  //toggle edge for next isr iteration
    int_edge_flag = 0;      //flag to denote trigger edge
    enable_interrupts(INT_EXT1); 
  }
  else  //edge = L_TO_H, time to print packet
  {
    ext_int_edge(0, H_TO_L);
    int_edge_flag = 1;
    disable_interrupts(INT_EXT1);
    disable_interrupts(INT_EXT);
    x=0;
    print_buffer_flag = 1;
  }
}

#int_ext1
void ext1_isr() //clock
{
 
  if(input(DATA_PIN))
  {
    byte_in |= bit_mask;
  }
  bit_mask = bit_mask << 1;
  if(bit_mask == 0x0200) //9 bits per word
  {
    bit_mask = 0x0001;
    buffer[x] = byte_in;
    x++;
    byte_in = 0;
  }
}


In main, the buffer is printed over rs232 to a PC. The data I've gotten back doesn't seem to be right. I've put the data signal and the enable signal on an oscilloscope. I can see that the first byte is 0x006A, or 106. But that number has never appeared in my data output from the PIC. Alot of the numbers are powers of 2.

Im using a PIC25j10 with a 9.216MHz crystal, using the PLL mode to run at 36.864MHz. The lcd clock signal has a frequency of 100kHz. Is this too fast for my code? How can I calculate how long 1 iteration of my ext1 isr takes?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Aug 09, 2008 2:34 pm     Reply with quote

Post your variable declarations for that code.
Guest








PostPosted: Sat Aug 09, 2008 4:07 pm     Reply with quote

This is the entire code

Code:

#include<18f25j10.h>
#fuses H4_SW, NOPROTECT, NOWDT
#define   SYSTEM_CLOCK  36864000
#use delay( clock = SYSTEM_CLOCK )
#use rs232( xmit=PIN_C6,  baud=9600, bits=8, parity=N )

#define N 64
#define DATA_PIN PIN_A0

int1 int_edge_flag,print_buffer_flag;
int16 bit_mask=0x0001;
int16 byte_in;
int16 buffer[N];
int16 x,y,z;

#int_ext
void ext_isr() //enable triggers ext0
{
  if(int_edge_flag == 1)  // edge = H_TO_L, data is coming
  {
    ext_int_edge(0, L_TO_H);  //toggle edge for next isr iteration
    int_edge_flag = 0;
    enable_interrupts(INT_EXT1); 
  }
  else  //edge = L_TO_H, time to print packet
  {
    ext_int_edge(0, H_TO_L);
    int_edge_flag = 1;
    disable_interrupts(INT_EXT1);
    disable_interrupts(INT_EXT);
    x=0;
    print_buffer_flag = 1;
  }
}

#int_ext1
void ext1_isr() //clock triggers ext1
{
 
  if(input(DATA_PIN))
  {
    byte_in |= bit_mask;
  }
  bit_mask = bit_mask << 1;
  if(bit_mask == 0x0200) //9 bits per byte
  {
    bit_mask = 0x0001;
    buffer[x] = byte_in;
    x++;
    byte_in = 0;
  }
}

void main ()
{
   setup_oscillator(OSC_PLL_ON) ;
   for(y=0;y<N;y++)
   {
     buffer[y] = 0;
   }
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_EXT);
   ext_int_edge(0, H_TO_L);   //enable is active low
   ext_int_edge(1, L_TO_H);   //clock is active high
   int_edge_flag = 1;         //flag to signify ext0 trigger edge  H_TO_L is 1, L_TO_H is 0
   while (TRUE)
   {
     if(print_buffer_flag)
     {
       for(y=0;y<N;y++)
       {
         printf("\n\r %Lu",buffer[y]);
       }
       print_buffer_flag = 0;
       enable_interrupts(INT_EXT);
     }
 
   }
   
 
   
}

Ttelmah
Guest







PostPosted: Sun Aug 10, 2008 2:46 am     Reply with quote

First comment is that this doesn't sound at all like 'I2C'. It sounds as if this is perhaps a logic based synchronous serial (more like the PS/2 protocol). Now, really the only answer is going to be to find out what it really is!....
However, if it is a synchronous clock based protocol, then I'd suggest cutting the interrupts to just one. The problem is that 100K, while not 'too fast' for the PIC to handle, _does_ require careful thought. If you can work out which edge of the clock corresponds to stable data, have just one interrupt, from this edge. Interrupts, cost a lot of time. If you are interrupting on both edges of something potentially changing at 100KHz, you have just 5uSec between these changes. The PIC won't handle this.
I'd suggest then, that you actually need to stay inside the data handler, when the active clock edge is received. Add a 'timeout', so if you miss an edge, the code will recover.
Though this goes against the 'keep interrupts as short as possible' mantra, at this sort of data rate, it is going to be needed.
So (In a sort of 'theoretical' form):
Code:


#intxxxxx
void active_clock_edge(void) {
   int16 data=0;
   int16 mask=1;
   int8 ctr;
   int1 temp;
   //Read the data ASAP
   tmp=input_bit(DATA_BIT);
   //Now set a timer, to timeout after perhaps 1.5 character times
   set_timerx(count);
   clear_interrupts(INT_TIMERX);
   //Program a bit statement, to access the interrupt flag for this timer
   //as TimerxIF
   if (tmp) data|=mask; //Put the first bit into the result
   for (ctr=0;ctr<8;ctr++) {
      //Now 8 more bits to handle
      while (input_bit(CLOCK_BIT)==ACTIVE) {
          if (TimerxIF) return; //Timeout if interrupt flag is set
      }
      //Now wait for the clock to go active again
      while (input_bit(CLOCK_BIT)!=ACTIVE) {
          if (TimerxIF) return; //Again timeout
      }
      mask<<=1; //setup the mask, and this rotation, according to the
      //order the bits arrive
      if (input_bit(DATA_BIT)) data|=mask;
   }
   //Here set a flag that 'data' has arrived, and copy the received character
   //to a temporary store.
}

Now, you will have to work out what timer to use for the timeout, what edge to set the interrupt to, and what levels are the 'active' ones etc., and generate the real code, but this is the sort of approach needed to receive such a data stream.

Best Wishes
Guest








PostPosted: Sun Aug 10, 2008 12:33 pm     Reply with quote

Actually, the ext0 is for the enable. ext1 is for the clock. The enable goes low for a couple of milliseconds, during which the clock and data line do their thing. I'm only changing the trigger edge for the enable, to know when the packet starts and ends.

The clocks interrupt is always positive edge triggered. The clock is a 100kHz signal, but its duty cycle is probably only 20% or less. The rising edge of the clock occurs in the center of a data bit.

There is also a delay between groupings of 9 clocks. I don't have the scope in front of me right now, but Im pretty certain this delay is longer than 90 us, the duration of one byte.

But what you've laid out makes sense.

Quote:
//Program a bit statement, to access the interrupt flag for this timer
//as TimerxIF



So for timer0, I would do some thing like this?

#define TIMER0IF bit_test(INTCON,5)
Guest








PostPosted: Sun Aug 10, 2008 2:13 pm     Reply with quote

This is what the first byte looks like on a scope
Code:
   ___                                           
ENA   |____________________________________________ ....
   

CLK_______|___|___|___|___|___|___|___|___|________ ....

             ___     ___     _______
DAT_________|   |___|   |___|       |______________ ....
    
          0   1   0   1   0   1   1   0   0


001101010 = 0x006A
Ttelmah
Guest







PostPosted: Sun Aug 10, 2008 3:10 pm     Reply with quote

#define TIMER0IF bit_test(INTCON,5)

No, I'd just define a bit.
so:

#bit TIMER0IF=INTCON.5

I'd use the rising edge of the clock then, to sample ASAP. Given the delays getting into the interrupt, it may still be borderline.

Best Wishes
Guest








PostPosted: Sun Aug 10, 2008 8:03 pm     Reply with quote

How can you calculate the total propagation delay of the interrupt, meaning the time between the signal changing, and the interrupt service routine starting?
Ttelmah
Guest







PostPosted: Mon Aug 11, 2008 2:40 am     Reply with quote

Count the instructions.
Normally the instruction at address 8, executes, a maximum of 14.25 clocks after the event. You then have the code to save the internal registers, which is slightly 'worse' on a 18chip, but then reduced a little by the presence of the RETFIE 1 instruction, which allows three registers to be skipped. Typically 15 double length instructions. Then the interrupt bit itself is tested, and it's enable, usually another 5 instruction times, before you arrive at the handler. So a total of about 155 clock cycles. Equivalent to just under 40 instruction times. With your clock, about 4.2uSec.
As you can see, this should be 'OK' with your clocks, but it doesn't leave a lot of spare time, especially if you leave the interrupt and return (it takes about as long to come out again), and code in the interrupt itself can take a surprising time.

Best Wishes
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