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

INT_EXT

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



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

INT_EXT
PostPosted: Sat Mar 09, 2019 7:57 am     Reply with quote

Hello,

I have a problem with external interrupt on 18f4520. I'm listening to I2C communication. The idea is to catch START and STOP conditions. My problem is that the interrupt fires regardless of the edge I set (or try to set), meaning that I should see a 0 on PIN_B0 when I come to START and SCK is high. Instead, it's fully random. Sometimes 0, sometimes 1. Probably my reasoning is wrong.


Code:

#INT_EXT
void  EXT_isr(void) {                       // we come here with interrupt edge set H_TO_L 
   clear_interrupt(INT_EXT);
   delay_cycles(1);                   
   switch(START_OR_STOP){
// wait I2C start condition (SDA HIGH TO LOW transition, SCK HIGH at that time)
      case START:{
         if(input_state(SCK) == 1){          // allowed only when START condition
            Got_Start = 1;
            Bit_Position = 8;                // data is transfered MSB first, so we'll write 8th bit first
            START_OR_STOP = STOP;                             
            ext_int_edge(0,L_TO_H);            // change the interrupt edge     
            ext_int_edge(0,L_TO_H);            // change the interrupt edge     
            READ_DATA = IDLE;
            delay_cycles(1);             
         }                                                   
         break;                                                     
      }
                                                     
// wait I2C stop condition (SDA LOW TO HIGH transition, SCK HIGH at that time)                   
      case STOP:{
         if(input_state(SCK) == 1){          // allowed only when STOP condition
            Got_Start = 0;                                                                                   
            START_OR_STOP = START;                                                       
            ext_int_edge(0,H_TO_L);            // change the interrupt edge     
            ext_int_edge(0,H_TO_L);            // change the interrupt edge     
         }
         break;                                   
      }                                                                                           
   }                                                                   
                                                                             
}
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 7:59 am     Reply with quote

BTW, levels are correct. 5V all around.
temtronic



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

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 9:50 am     Reply with quote

comments.
1) do you preset the 'START_OR_STOP' variable before the interrupt occours?
2) how is 'SCK' defined ?

Either of these not being correct could cause random problems, especially if SCK is NOT correct !.
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 10:11 am     Reply with quote

Code:

#define SDA PIN_B0
#define SCK PIN_B4

#define START 0
#define STOP 1
int1 Got_Start = 0;
int8 START_OR_STOP  = START;
                                         

#define CLK_LOW 0
#define SAMPLE_DATA 1                     
#define IDLE 2
int8 READ_DATA = CLK_LOW;

#define BUFFER_SIZE 64                       //create 255 byte large buffer
char buffer[BUFFER_SIZE];       
int8 next_in = 0;
                                                                             
int8 Bit_Position = 8; 
int16 TMP = 0;                                // storage for sampled data
int16 counter = 0;


and interrupts:

Code:

   enable_interrupts(INT_TIMER0);
   enable_interrupts(INT_TIMER1);
//   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);

   clear_interrupt(INT_EXT);                // prevent INT_EXT to fire on reset
   ext_int_edge(0,H_TO_L);                     // init interrupt triggering for                           
   ext_int_edge(0,H_TO_L); 
   enable_interrupts(INT_EXT); 

PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 10:24 am     Reply with quote

Right now, Bit_Position never comes to 6. I do have a logic analyzer, so I do see how SCL and SDA are moving. As I say, there must be some basic error with the way I designed this. And me being me, it'll take time to spot where I made a mistake.

Code:

void main() {

   enable_interrupts(INT_TIMER0);
   enable_interrupts(INT_TIMER1);
//   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);

   clear_interrupt(INT_EXT);                // prevent INT_EXT1 to fire on reset
   ext_int_edge(0,H_TO_L);                     // init interrupt triggering for button press                             
   ext_int_edge(0,H_TO_L); 
   enable_interrupts(INT_EXT); 

                                                 
   while(TRUE){                                         
     
      while(Got_Start){                                   
     
         switch(READ_DATA){
// ............................................................................         
            case CLK_LOW:{
               delay_cycles(1);
               while(input_state(SCK) == 0);        // WAIT SCK high, then read data
               READ_DATA = SAMPLE_DATA;
                                                   
            break;                             
            }
// ............................................................................           
            case SAMPLE_DATA:{
               delay_cycles(1);
               if(input_state(SDA)){
                  bit_set(TMP, Bit_Position);                                                                                 
               }                         
               else{                                                         
                  bit_clear(TMP, Bit_Position);
               }
               Bit_Position--;                        // do it for 8 bits, ninth bit is ACK             
               
               if(Bit_Position == 6){
                  delay_cycles(1);
               }                                 
               READ_DATA = IDLE;                      // go wait for SCK to be low
            break;                                               
                                                 
            }                                           
// ............................................................................           
            case IDLE:{
               delay_cycles(1);
               while(input_state(SCK) == 1);
               READ_DATA = CLK_LOW;                                                       
            break;                                               
                                                                                   
            }
// ............................................................................           
         }     // switch                       
     
      }  // while(Got_Start)
     
     
                                                     
   
   }    // while(TRUE)                 

}       // MAIN                           
temtronic



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

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 10:32 am     Reply with quote

OK if you're trying to code your own software I2C, then why not just let the compiler make one for you ? You can see how they do it by dumping the listing.
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 10:33 am     Reply with quote

First mistake, I should start with IDLE state in main(), because I come there with SCK high and I need to see low before reading data. But it doesn't change anything regarding my interrupt problem.
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 10:42 am     Reply with quote

I don't want to create I2C communication. The goal is to listen to an existing and working communication, and when I get the sequence I need, do something. The setup is like this: the main unit is sending data over I2C to the slave unit, that in turn writes stuff to an LCD display. It is a custom made thing, 18f67J10 is sending data to 18f2550 which in turn controls the LCD. My "sniffer" is just listening. Data protocol is simple, I can see the sequence that is written on LCD as ASCII bytes sent from master to slave. All I want to do is to record all bytes between START and STOP into the buffer and act if the right message appears on the line.
temtronic



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

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 10:55 am     Reply with quote

It'd be a lot simpler and more reliable if you'd use a PIC with I2C and use it as your 'sniffer'.From both HW and SW I don't see why this won't work. All data that the sniffer detects can go into a buffer, where you can 'process'( parse' to look for the 'sequence' you need.
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 11:06 am     Reply with quote

How can I set my "sniffer" PIC to listen to everything? I have 5 units here and addresses that master sends are not the same. I don't know how they did it, but the slave is responding to 0x28 and 0x54
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 11:14 am     Reply with quote

That is the reason I went for software decoding. The communication is slow, 50kHz.
temtronic



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

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 1:08 pm     Reply with quote

You should be able to set the 'sniffer' (a slave..) to address '0x00' and it'll receive ALL transmissions. That's from my foggy, old memory. Pretty sure 00 was one of the special reserved addresses that Philips set aside. Other's will know for sure or just check an I2C handbook online. Heck I can't member who bought Philips....


edit Update: OK, NXP bought out Philips...so I downloaded the I2C pdf... address 0x00 is the 'broadcast' address. Master sends out TO every I2C device, you want to 'listen' to all I2C , so a 'receive all'. That leads me back to 'cut code for a CCS SW I2C' and dump the listing. ALL of the CCS code will appear....You just want the 'listen and decode' chunk BEFORE the PIC compares the incoming address and it's own. If you buffer that data, then YOU can parse/decode/act upon the data.

Jay


Last edited by temtronic on Sat Mar 09, 2019 3:43 pm; edited 1 time in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19215

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 2:25 pm     Reply with quote

Your approach is basically not going to work.

First, the 'state' machine, would need to be able to handle 'restart'
conditions as well as just start and stop.
Then while 'start' is signalled by a drop on SDA, while SCL is high, 'stop'
involves SDA going high while SCL is high.
To decode in software, you need to use the INT_RB abaility to find
every edge on both lines, and then build a state machine based upon
these specific conditions to trigger the state changes, and then use the
rising edge of SCL to sample the data and build the byte, based upon
the machine state.
Currently your approach will be seeing every data bit as a stop or
start... Sad
PrinceNai



Joined: 31 Oct 2016
Posts: 452
Location: Montenegro

View user's profile Send private message

PostPosted: Sat Mar 09, 2019 10:07 pm     Reply with quote

This is the data I need to extract. Only ASCII bits (Check card). No restart condition, ever. I sampled 100s of data and it never happens.

https://imgur.com/a/P9WddMe
Ttelmah



Joined: 11 Mar 2010
Posts: 19215

View user's profile Send private message

PostPosted: Sun Mar 10, 2019 3:30 am     Reply with quote

You still need to remember that the interrupt is going to be called on
every data edge, so will see the data bits as well as the start and stop.
The key thing with I2C, is you need to be always looking/responding
to _both_ lines.

Your current test will be seeing every SDA _data_ transition, as well as
the one that represents start and stop. Hence it's 'randomness'.
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