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

How i2c_isr_state works after an interrupt
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
itzalak
Guest







How i2c_isr_state works after an interrupt
PostPosted: Mon Sep 24, 2007 4:31 am     Reply with quote

Hi;


I have some problems with an I2C communcation and 16F88 pics. When an SSP interrupt occurs, the software goes to the interrupt routine and the i2c_isr_state takes the "0" value (address match) and increments his value when a second byte arrives, but my question is:

If I send 4 bytes continuousy, the first one generates an interrupt in the SSP module but the three others will generate interrupts too or the are received meanwhile the interrupt routine is working? in other words, does the system go out from te interrupt for each byte received?


Thansk a lot.
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Mon Sep 24, 2007 8:23 am     Reply with quote

Each byte will cause an interrupt. The value of i2c_isr_state() depends on what has happened. Address match, instruction to receive data or instruction to send data. I, personally, don't use this function as I look at the registers directly so I can't tell you what the values, for each state, will be.

Ronald
itzalak2
Guest







PostPosted: Mon Sep 24, 2007 10:31 am     Reply with quote

Thanck you very much. I suposse that but I have somthing strange on the pic behaviour.

I'm sending 3 bytes (to use with the ex_slave.c but with FORCR_HW added).

start_i2c;
i2c_write(0xA0); //PIC SLAVE ADDRESS
delay_ms(100);
i2c_write(0x00); //BUFFER ADDRESS
delay_ms(100);
i2c_write(0x22); //DATA
i2c_stop();

The slave PIC16F88 has the EX_SLAVE.C file code and I send every 100 seconds. I put a break point in the BLACK LINE BELOW and the master needs to send data twice to achieve this point so I don't know why it happens. It should be achieved sending data only once, no?


/*********************************************************/
#use delay(clock=8000000)

#use I2C(slave,SDA=PIN_B1,SCL=PIN_B4,force_hw,address=0xA0)

BYTE a;
BYTE address, buffer[0x10];

#INT_SSP
void i2c_isr ()
{
BYTE incoming, state;

state = i2c_isr_state();

if(state < 0x80) //Master is sending data
{
incoming = i2c_read();
if(state == 0) //First received byte is address
address = incoming;

if(state == 1) //Second received byte is data
(*) buffer[address] = incoming; //BREAK POINT
}
if(state == 0x80) //Master is requesting data
{
i2c_write(buffer[address]);
}
}

/*********************************************************/

Thanks a lot for all your help
Ttelmah
Guest







PostPosted: Mon Sep 24, 2007 3:14 pm     Reply with quote

No.

You are sending two bytes of data. The '00', and the '22'. It is _you_, who make the distinction, to decide that the first byte sent is a local 'address'.

It is a problem in I2C 'thinking'. As far as the communication interface is concerned, there is only the 'device address' byte (the 'A0'), and then bytes sent or received. The idea of a second 'buffer address' byte, is not implicit in I2C. So, the counter increments for each data byte received. Your code, then decides ttreat the first data byte as a local 'address', but as far as the conter is concerned, it is just another data byte. Hence you are sending two data bytes, so the counter increments by 2.

Best Wishes
itzalak
Guest







PostPosted: Tue Sep 25, 2007 12:20 am     Reply with quote

Ok, I know the second byte is my own buffer address but my problem is:

1) If I put a breakpoint int he black line above the master needs to send all data twice (address, buffer_address, data, address, buffer_address, data) to achieve this point when I should achive it with the first three bytes.

2) I have seen that the i2c_state doesn't reset every time I send data so, as the state always goes incrementing the program goes to the interrupt routine but never enters due to the state number.


Any idea?


Thanks a lot again.
itzalak
Guest







PostPosted: Tue Sep 25, 2007 4:00 am     Reply with quote

Hello:

I've solved pat of the problem. Now the i2c interrupt acts incrementing state for each byte and resetting the i2c state. The problem is that in the fist interrupt I receive data perfectly but after it data is corrupted.

I send always this

i2c_start();
i2c_write(0xA0); // SLAVE ADDRESS
delay_ms(10);
i2c_write(11); // BUFFER DATA
delay_ms(10);
i2c_write(22); // BUFFER DATA
delay_ms(10);
i2c_write(33); // BUFFER DATA
i2c_stop();

and the first time I receive (0xA0,11,22,33) OK but the next times de data "moves" or repeats as for example (11,11,22,33) an I don't know why.

SLAVE CODE:

#INT_SSP
void ssp_interupt ()
{
BYTE incoming, state;

disable_interrupts(GLOBAL);
disable_interrupts(INT_SSP);


state = i2c_isr_state();

if(state < 80) //Master is sending data
{
incoming = i2c_read();

if(state == 0)
buffer[0x00] = incoming;
if(state == 1)
buffer[0x01] = incoming;
if(state == 2)
buffer[0x02] = incoming;
if(state == 3)
buffer[0x03] = incoming;

}
if(state == 0x80) //Master is requesting data
{
i2c_write(buffer[address]);
}
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
clear_interrupt(INT_SSP);
}

void main ()
{
reset_var();

while(1)
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (TRUE)
{
delay_ms(40000);
}
}
}

void reset_var()
{
unsigned int8 i=0;

delay_ms(100);

set_tris_B(0b11111111);

for (i=0; i<4; i++)
buffer[i]=0;


}
Ttelmah
Guest







PostPosted: Tue Sep 25, 2007 4:20 am     Reply with quote

First thing to get rid of, are your lines enabling/disabling the interrupts in the ISR. You must _never_ enable the global interrupt in the ISR. This is an absolute 'no no' on the PIC, and will cause data corruption. The probelms is tht as soon as the interrupt is enabled, and interrupt can occur. Since the PIC does not support recursion (calling a routine ffrom inside itself), you can thereby get problems. Interrupts are already automatically disabled by the hardware, when the main interrupt handler is called, and are automatically re-enabled by the return command at the end of the main handler, after it has executed, to avoid this problem. These cmmands may be causing your problem.

Best Wishes
itzalak
Guest







PostPosted: Tue Sep 25, 2007 9:02 am     Reply with quote

After many many probes, I have discovered that the clk and sda lines has a strange behaviour.

I have seen that the last clock pulse is shorter than others and the last data is faster than previous pulses.

How can I put a image?
ELCouz



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

View user's profile Send private message

PostPosted: Tue Sep 25, 2007 10:52 am     Reply with quote

>>How can I put a image?

use the img tag ex: [IMG]http://www.google.com/intl/en/images/about_logo.gif[/IMG]

besure that Disable BBCode in this post is unchecked
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

View user's profile Send private message Visit poster's website

PostPosted: Tue Sep 25, 2007 11:15 am     Reply with quote

And your images can be hosted here
http://imageshack.us/
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Tue Sep 25, 2007 11:35 am     Reply with quote

imageshack might not be a good place to place images since some companies (mine is one of them) block that site.
ELCouz



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

View user's profile Send private message

PostPosted: Tue Sep 25, 2007 12:15 pm     Reply with quote

try tinypic.com i use it alot ... VERY simple Razz
Aimar



Joined: 05 Mar 2007
Posts: 4

View user's profile Send private message

PostPosted: Wed Sep 26, 2007 12:43 am     Reply with quote

Hello:


See how the "logic 0" after SDA last 2 bits are faster than previous, and see how the las clock (i2c_stop condition) goes high too early.

I've "tuned" the clock to make i2c work exactly at 40 KHz.



rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Wed Sep 26, 2007 12:04 pm     Reply with quote

That looks like a normal waveform to me. The ACK/NOACK clock pulse has been made and the master is releasing the SCK line. It's obvious that the slave is not talking back since you received a NOACK.

From looking at the waveform it looks like you're sending address 0xAA to the slave. If your slave is set to 0xA0 then it's not going to communicate. Are you using code that is different from what is posted? Double check your code to make sure you're sending the correct value to it.

Ronald
Aimar



Joined: 05 Mar 2007
Posts: 4

View user's profile Send private message

PostPosted: Thu Sep 27, 2007 1:10 am     Reply with quote

In the graph above I was sending 0xAA (0b10101010) to see clearly each bit and ack/nack signal.

The "complete program" is the next one. with this code I receive the 4 bytes sent only once, later the recepcion changes and some bytes are buffered twice, and so on.


This s the MASTER CODE:

#include "D:\PROYECTOS\06 MANDO VARIADOR\PROGRAMACION\FIRMWARE BOTONERA DIGITAL\MASTER.h"

void reset_variables();
void mandar_codigo();

void main ()
{

reset_variables();

While(1)
{
mandar_codigo();

delay_ms(6000);

}
}

void reset_variables()
{

setup_adc_ports(sAN0|sAN1|sAN3|VSS_VDD);
setup_adc(ADC_CLOCK_INTERNAL/*ADC_CLOCK_DIV_2*/);
setup_timer_0(T1_DISABLED /*RTCC_INTERNAL|RTCC_DIV_1*/);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);

DISABLE_INTERRUPTS(GLOBAL);
setup_SPI(SPI_SS_DISABLED);
OSCTUNE=0b00101000;
}

void mandar_codigo()

{
i2c_start();
i2c_write(0xA0); // SLAVE ADDRESS
i2c_write(0x11); // BUFFER DATA
i2c_write(0x22); // BUFFER DATA
i2c_write(0x33); // BUFFER DATA
i2c_stop();
}


My library MASTER.h:

#include <16F88.h>
#device ICD=TRUE
#device adc=10

#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc
#FUSES NOPUT //No Power Up Timer
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOBROWNOUT //Reset when brownout detected
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //Debug mode for use with ICD
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOIESO //Internal External Switch Over mode disabled

#use delay(internal=8M)
#use i2c(master,sda=PIN_B1,scl=PIN_B4,fast=50000) // A 50 KHz


And the SLAVE CODE:

#include "D:\PROYECTOS\06 MANDO VARIADOR\PROGRAMACION\FIRMWARE BOTONERA DIGITAL\EX_SLAVE.h"

void reset_var();

BYTE address, buffer[4];

#INT_SSP
void ssp_interupt ()
{
BYTE incoming, state;

state = i2c_isr_state();

if(state < 80) //Master is sending data
{
incoming = i2c_read();

if(state == 0)
buffer[0x00] = incoming;
if(state == 1)
buffer[0x01] = incoming;
if(state == 2)
buffer[0x02] = incoming;
if(state == 3)
buffer[0x03] = incoming;
}

if(state == 0x80) //Master is requesting data
{
i2c_write(buffer[address]);
}
}

void main ()
{
reset_var();

while(1)
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (TRUE)
}
}

void reset_var()
{
unsigned int8 i=0;

OSCTUNE=0b00101000;

for (i=0; i<4; i++)
buffer[i]=0;


}


The library EX_SLAVE.h:

#include <16F88.h>
#device ICD=TRUE
#device adc=10

#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc
#FUSES NOPUT //No Power Up Timer
#FUSES MCLR //Master Clear pin used for I/O
#FUSES NOBROWNOUT //Reset when brownout detected
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES DEBUG //Debug mode for use with ICD
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOIESO //Internal External Switch Over mode disabled

#use delay(clock=8000000)
#use i2c(Slave,sda=PIN_B1,scl=PIN_B4,force_hw,address=0xA0)
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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