View previous topic :: View next topic |
Author |
Message |
muhibraza1
Joined: 26 Jul 2013 Posts: 23
|
Transmitting int16 value through i2c |
Posted: Fri Jul 26, 2013 3:04 am |
|
|
Hello, can someone help me find a way for sending 16 bit data through i2c with PIC18F452 ? |
|
|
mdemuth
Joined: 16 Apr 2007 Posts: 71 Location: Stuttgart, Germany
|
|
Posted: Fri Jul 26, 2013 3:43 am |
|
|
Nothing special about it, just send two bytes e.g.
Code: | void Init_PCA9554()
{
i2c_start();
i2c_write(0b01000000); // adress byte
i2c_write(0x00); // command byte
i2c_stop();
}
|
Use make8 and make16 functions to convert 16bit into 2x8bit and back. |
|
|
muhibraza1
Joined: 26 Jul 2013 Posts: 23
|
|
Posted: Fri Jul 26, 2013 4:28 am |
|
|
Thank you for your help. But I was asking about 1 address byte and 2 data bytes. Not 1 address and 1 data. The Slave is also a PIC18f452 and I am using Ex_slave.c code on it.
I tried the following code but its not working.
Code: |
#include <18f452.h>
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
//====================================
void main()
{
long data , datah , datal ;
data = 720 ;
do
{
//Write data to slave board.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_write(data);
i2c_write(data>>8);
i2c_stop();
printf("write %Lu \n\r", data);
// Read from the slave board and display the data.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
datal = i2c_read();
datah = i2c_read(0);
i2c_stop();
datah = datah<<8;
data = datah | datal ;
printf("read %Lu \n\r", data);
}while(TRUE);
}
|
The output never comes. The hyperterminal prints nothing.
While the following code is working absolutely fine.
Code: |
#include <18f452.h>
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
//====================================
void main()
{
do
{
// Write the letter 'B' to the slave board.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_write('B');
i2c_stop();
// Read from the slave board and display the data.
i2c_start();
i2c_write(0xA0);
i2c_write(0x00);
i2c_start();
i2c_write(0xA1);
data = i2c_read(0);
i2c_stop();
printf("read %c \n\r", data);
}while(TRUE);
}
|
The output of this program is
Read B
Read B
Read B
and it continues....
Could anybody tell what is it that I am doing wrong with the 16 bit data ? |
|
|
muhibraza1
Joined: 26 Jul 2013 Posts: 23
|
|
Posted: Fri Jul 26, 2013 4:38 am |
|
|
I also tried online debugging on the Master PIC using ICD-U64. I found out that the program never goes beyond this :
Code: |
#include <18f452.h>
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
//====================================
void main()
{
long data , datah , datal ;
data = 720 ;
do
{
//Write data to slave board.
i2c_start();
i2c_write(0xA0);
|
It gets stuck here. While the other program which I used for transmitting 8 bit data is working absolutely fine.
Just thought that it may be helpful for you in understanding the problem. |
|
|
muhibraza1
Joined: 26 Jul 2013 Posts: 23
|
|
Posted: Sat Jul 27, 2013 1:28 am |
|
|
anyone ?? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sat Jul 27, 2013 5:52 am |
|
|
The situation as you describe it is strange, and then with strange I mean that something is going wrong not caused by your program but by some other cause. Both programs are identical up to the point where you say the program stops so that program line by itself can't be the problem cause.
How do you know the program stops at the I2C line? Tell us how you found this out because your debug method might be what causes the problem.
Have you tried your first program again and is this still working?
What is the value of the pull-up resistors at the I2C lines you use? And at which lines do you have these pull-up resistors?
What is the length of the cable between your master and slave PIC?
ALWAYS post your compiler version number!
A general comment is to always add the 'ERRORS' parameter to the #use RS232 line. This will make the compiler to add error clearing code when the UART has a receive buffer overflow. Without the ERRORS directive the UART will stop working until the error condition is cleared by you. |
|
|
muhibraza1
Joined: 26 Jul 2013 Posts: 23
|
|
Posted: Thu Aug 01, 2013 2:18 am |
|
|
Quote: | How do you know the program stops at the I2C line? Tell us how you found this out because your debug method might be what causes the problem. |
I have done online debugging with ICD-U64 on CCS PICC Compiler V4.124. I clicked on single step and it worked fine before the program reached this line
At this line the debugger shows the status of the program as "running" and then takes forever to complete this step. :/
Quote: | Have you tried your first program again and is this still working? |
Yes, it does. It always works fine.
Quote: | What is the value of the pull-up resistors at the I2C lines you use? And at which lines do you have these pull-up resistors? |
I am using 4.7K resistors on SDA and SCL line.
Quote: | What is the length of the cable between your master and slave PIC? |
Its around 4 or 5 inches.
And I don't think that this may be the problem because the same hardware is working fine with the 8 bit program. It must not be the hardware.
Quote: | ALWAYS post your compiler version number! |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Thu Aug 01, 2013 3:39 am |
|
|
Do you have the CCS IDE?.
If so, try using the device editor, going to the errata section, and ticking the one that says "Don't do BSR15".
Re-compile, and see if it makes any difference.
About 95% of 18F452's, have this as an erratum. Basically if a register access is performed with the BSR set to 15, it clears a status bit in the I2C peripheral. Result can be I2C hanging.....
It only applies if you use I2C, and makes accessing the top bank of RAM slower, so CCS leave it off by default. However if you want to use I2C, with these chips, it needs to be on.
Personally, I'd really strongly suggest switching to the 4520 instead. Generally it is cheaper, and has a lot less faults (on the later revisions).
Best Wishes |
|
|
muhibraza1
Joined: 26 Jul 2013 Posts: 23
|
|
Posted: Thu Aug 01, 2013 6:04 am |
|
|
Ohh. Thanks for providing this great info. Does this problem occur in PIC18F252 or any other controllers too or is it specfic to this 18F452 ? |
|
|
snock
Joined: 10 Oct 2011 Posts: 24
|
|
Posted: Thu Aug 01, 2013 6:25 am |
|
|
Thanks for the head's up on the BSR15 issue. We've been having issues with the i2c on PIC16F882s so I will try it with it off. It's a very intermittent problem and hopefully this fixes it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Fri Aug 02, 2013 1:28 am |
|
|
The 16F882, does not have this issue.
However it has a lot of other errata for the I2C....
If you are a master device, then consider switching to software I2C (FORCE_SW). If this fixes the problems, then you have to decide whether the gain from using the hardware is worthwhile (small)....
If you are working as a slave device, then look at errata 5. If you are a slave with SS enabled, look at errata 7.
Best Wishes |
|
|
snock
Joined: 10 Oct 2011 Posts: 24
|
|
Posted: Fri Aug 02, 2013 6:21 am |
|
|
Well, another peculiarity is that the code when compiled with version 4.050 will function properly but when compiled with version 4.124 does not function.
Here is the code which does not function when compiled with 4.124:
Code: |
#include<16f882.h>
#fuses XT, MCLR, WDT, NOLVP, NOBROWNOUT, NODEBUG, NOFCMEN, PUT
#use delay(clock=4MHz)
#use fast_io(b)
#use fast_io(c)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa0, force_hw, slow)
// * PORT A DEFINITIONS ********************************************************
#define IO_FLT PIN_A5
// *****************************************************************************
// * PORT B DEFINITIONS ********************************************************
#define Q0 PIN_B0
#define Q1 PIN_B1
#define Q2 PIN_B2
#define Q3 PIN_B3
#define Q4 PIN_B4
#define Q5 PIN_B5
#define Q6 PIN_B6
#define Q7 PIN_B7
// *****************************************************************************
// * PORT C DEFINITIONS ********************************************************
#define ADDR0 PIN_C0
#define ADDR1 PIN_C1
#define ADDR2 PIN_C2
#define SCL PIN_C3
#define SDA PIN_C4
// *****************************************************************************
// * PORT E DEFINITIONS ********************************************************
#define SHDN PIN_E3
// *****************************************************************************
// * PROGRAM DEFINITIONS *******************************************************
// *****************************************************************************
#zero_ram
#byte ANSEL=0x188
static int8 mem_addr;
static int8 card_data[20];
// * I2C INTERRUPT HANDLER *****************************************************
#int_ssp
void i2c_handler(void) {
int8 state;
state=i2c_isr_state();
if(state<0x80) { // Master is sending data
if(state==1) mem_addr=i2c_read(1); // Store the address
if(state==2) card_data[mem_addr]=i2c_read(1); // Read and store the data
}
if(state>=0x80) { // Master is requesting data
i2c_write(card_data[mem_addr]); // Write the memory over i2c
}
}
// *****************************************************************************
// * MAIN ROUTINE **************************************************************
void main(void) {
int8 i2c_address;
set_tris_b(0b00000000); // Set port B direction
set_tris_c(0b00011111); // Set port C direction
set_tris_e(0b00001000); // Set port E direction
setup_adc_ports(NO_ANALOGS);
setup_comparator(NC_NC_NC_NC);
ANSEL=0; // Bug work around
output_b(0); // Clear relays on port B
output_float(IO_FLT); // Float the I/O fault line
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
setup_wdt(WDT_36MS);
i2c_address=(~input_c() & 0x07)<<5; // Read address switch at startup
if(i2c_address==0) i2c_address=2<<5; // Default if not set
i2c_slaveaddr(i2c_address); // Assign i2c address
while(TRUE) { // Loop forever
restart_wdt();
card_data[0]=0x09; // Card is a QR8 relay card
card_data[1]=0; // Set status byte, do more with later
output_b(card_data[10]); // Write to relay output register
}
}
// *****************************************************************************
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Fri Aug 02, 2013 8:21 am |
|
|
Some little comments:
1) A slave does not have a 'speed'. On older compilers this can result in invalid values being loaded into the configuration registers.
2) As posted, the code does not do a read on state==0. This can result in the I2C getting hung, since it won't release the clock stretch till the read is done.
It may well be that CCS have added fixes for these (then have done for '1' on the later V4 compilers.
Best Wishes |
|
|
snock
Joined: 10 Oct 2011 Posts: 24
|
|
Posted: Fri Aug 02, 2013 8:32 am |
|
|
Ttelmah, thanks for the pointers. I guess I am still a little confused. I thought that state==0 is the i2c address. So you are saying to insert a
Code: | if(state==0) i2c_read(); | into my code? Hanging i2c is the problem with this program however it only happens rarely. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Fri Aug 02, 2013 9:03 am |
|
|
Yes, The address still has to be 'read', to release the I2C transaction. If clock stretching is not being used, this doesn't cause a problem (except on some chips), but if it is, the chip holds the clock, until the read is performed.
Look at the ccs example. They perform a read for every state _up to and including 0x80_. 0x80, is the other 'gotcha' one, since this is the address being received, _for_ a write. So on this one, the chip has to read, and then write.
Best Wishes |
|
|
|