|
|
View previous topic :: View next topic |
Author |
Message |
itzalak Guest
|
How i2c_isr_state works after an interrupt |
Posted: Mon Sep 24, 2007 4:31 am |
|
|
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
|
|
Posted: Mon Sep 24, 2007 8:23 am |
|
|
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
|
|
Posted: Mon Sep 24, 2007 10:31 am |
|
|
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
|
|
Posted: Mon Sep 24, 2007 3:14 pm |
|
|
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
|
|
Posted: Tue Sep 25, 2007 12:20 am |
|
|
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
|
|
Posted: Tue Sep 25, 2007 4:00 am |
|
|
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
|
|
Posted: Tue Sep 25, 2007 4:20 am |
|
|
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
|
|
Posted: Tue Sep 25, 2007 9:02 am |
|
|
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
|
|
Posted: Tue Sep 25, 2007 10:52 am |
|
|
>>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
|
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Tue Sep 25, 2007 11:35 am |
|
|
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
|
|
Posted: Tue Sep 25, 2007 12:15 pm |
|
|
try tinypic.com i use it alot ... VERY simple |
|
|
Aimar
Joined: 05 Mar 2007 Posts: 4
|
|
Posted: Wed Sep 26, 2007 12:43 am |
|
|
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
|
|
Posted: Wed Sep 26, 2007 12:04 pm |
|
|
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
|
|
Posted: Thu Sep 27, 2007 1:10 am |
|
|
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) |
|
|
|
|
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
|