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 CCS Technical Support

Problem Master Receiving from Slave (I2C)

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



Joined: 06 Jul 2015
Posts: 6

View user's profile Send private message

Problem Master Receiving from Slave (I2C)
PostPosted: Thu Jul 09, 2015 9:11 am     Reply with quote

Hey,

Last week I posted here asking for some help with SPI addressing to more than one slave without a SS line and was told that I2C is a better option for this case. I am now trying to build a connection between a master and a single slave but the master is not reading correctly. Instead of 21 (sent to slave from master and then sent back from slave to master), it is reading -128. Does anyone know what the problem is?

MASTER CODE
Code:

#include <16F877A.h>
#FUSES NOWDT,XT,NOPUT,NOPROTECT,NODEBUG,NOBROWNOUT,NOLVP,NOCPD
#use delay(clock = 20000000)
#use i2c(MASTER,sda=PIN_C4,scl=PIN_C3)

#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#include <stdio.h>
#include <lcd.c>

// These pins are for the Microchip PicDem2-Plus board,
// which is what I used to test the driver.  Change these
// pins to fit your own board.

#define LCD_DB4   PIN_D4
#define LCD_DB5   PIN_D5
#define LCD_DB6   PIN_D6
#define LCD_DB7   PIN_D7       

#define LCD_E     PIN_D0
#define LCD_RS    PIN_D1

// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.

// #define USE_LCD_RW   1     

//========================================

#BIT SSPOV = 0x14.6     //Indicates overflow
#BIT BF = 0x94.0           //Buffer Full

BYTE data;

BYTE slave_1 = 0x10;
int Cont = 1;

void send_i2c(BYTE slave_ads, BYTE info)
{
   i2c_start(); // Start
   delay_ms(10);
   i2c_write(slave_ads); // Call specific slave
   delay_ms(10);
   i2c_write(20); // Write data1 -> recv1 in slave
   delay_ms(10);
   i2c_write(30); // Write data2 -> recv2 in slave
   delay_ms(10);
   i2c_stop(); // Stop
   delay_ms(10);
}

int receive_i2c(BYTE slave_ads, BYTE instruction)
{
   BYTE read1,read2;
   
   i2c_start(); //Start
   delay_ms(10);
   i2c_write(slave_ads); // Call specific slave
   delay_ms(10);
   i2c_write(instruction); // Write instruction -> recv1 in slave
   delay_ms(10);
   i2c_stop(); // Stop
   delay_ms(10);
   i2c_start(); // Start Read cycle
   delay_ms(10);
   i2c_write(slave_ads + 1); //Read Mode
   delay_ms(10);
   read1 = i2c_read(0);
   printf(lcd_putc,"\r\n Read1 is %d .",read1);
   delay_ms(10);
   i2c_stop();
   delay_ms(10);
   
   return 0;
   
}
void main (void)
 {
   lcd_init();
   delay_ms(300);
   printf(lcd_putc,"\r\nInitialized");
   while (Cont == 1)
   {
      output_high(PIN_A0);
      delay_ms(100);
      output_low(PIN_A0);
     
     
      //send_i2c(slave_1,data);
     
      Cont = receive_i2c(slave_1,21);
   }
 }


SLAVE CODE
Code:

#include <16F877A.h>
#FUSES NOWDT,XT,NOPUT,NOPROTECT,NODEBUG,NOBROWNOUT,NOLVP,NOCPD
#use i2c(SLAVE,sda=PIN_C4,scl=PIN_C3,address=0x10)
#use delay(clock=20000000)

#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#include <stdio.h>
#include <lcd.c>

// These pins are for the Microchip PicDem2-Plus board,
// which is what I used to test the driver.  Change these
// pins to fit your own board.

#define LCD_DB4   PIN_D4
#define LCD_DB5   PIN_D5
#define LCD_DB6   PIN_D6
#define LCD_DB7   PIN_D7       

#define LCD_E     PIN_D0
#define LCD_RS    PIN_D1

// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.

// #define USE_LCD_RW   1     

//========================================

#BIT SSPOV = 0x14.6     //Indicates overflow
#BIT BF = 0x94.0           //Buffer Full

BYTE state,recv1,recv2,read;

#INT_SSP NOCLEAR
void ssp_interrupt()
{
clear_interrupt(int_SSP);
   
   state = i2c_isr_state();
   //lcd_gotoxy(1,1);              // point LCD cursor to col1 row1
   //printf(lcd_putc,"\r\n State is %d .",state);
   if (state <0x80)
   {
      read = i2c_read();
      //printf(lcd_putc,"\r\n Read is %d .",read);
      if (state == 0)
      {
    recv1 = read;
      }
      if (state == 1)
      {
    recv2 = read;
      }
      if (state == 2)
      {
      }
   }
   if (state == 0x80)
   {
      printf(lcd_putc,"\r\n Sending %d .",recv1);
      SSPOV = 0;
      BF = 0;
      i2c_write(recv1);
      delay_ms(10);
   }
}

void main (void)
{
   lcd_init();
   delay_ms(100);
   printf(lcd_putc,"Initialized");
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
   while (TRUE)
   {
      if (SSPOV || BF)
      {
         output_high(pin_a0);
         SSPOV = 0;
         BF = 0;         
      }   
      else output_low(pin_a0);
   }
}


Just before sending recv1 to the master:
Code:
if (state == 0x80)
   {
      printf(lcd_putc,"\r\n Sending %d .",recv1);
      SSPOV = 0;
      BF = 0;
      i2c_write(recv1);
      delay_ms(10);
   }

The slave prints on the LCD recv1 and the value is correct (21). Any thoughts?
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Thu Jul 09, 2015 10:58 am     Reply with quote

Use the CCS example as your starting point.

You have taken code from an INT_SSP, designed for _SPI_ reception, and bodged parts of it onto an I2C routine. Not correct.
Parts of the interrupt handler you have are only applicable to an SPI slave....
SSPOV, has no meaning when using I2C.

Then the delay in the receive interrupt should be considered a 'capital offence'. The buffer needs to be loaded _before_ the master requests the data. The slave has the long print _and_ the delay, before it loads the data. The master only has the delay. So the data will never be loaded in time.

Then 'XT', 20MHz?....

Read the data sheet.
jaos699



Joined: 06 Jul 2015
Posts: 6

View user's profile Send private message

PostPosted: Thu Jul 09, 2015 5:28 pm     Reply with quote

to be honest I have no idea what I am doing, I have just gathered some information from other posts and tried to make it work. Thanks for the help, I'll check the data sheet!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jul 09, 2015 6:24 pm     Reply with quote

Here is a demo program for one i2c master and one slave.
http://www.ccsinfo.com/forum/viewtopic.php?t=39242&start=6
Later on in that thread (on page 2), there is code for one i2c master
with three slaves.

This i2c bus scanner program can be a useful diagnostic to check if your
slave devices are responding properly to the master:
http://www.ccsinfo.com/forum/viewtopic.php?t=49713
Be sure to look at the schematic of required pullup resistors and
connections at the end of that post.
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Fri Jul 10, 2015 1:28 am     Reply with quote

Well done Jaos. We can all 'live' with an admission like that, and have been there ourselves sometime. Smile

It also explains why there are bits of 'SPI' code left in your routines. Though SPI and I2C are handled by the same peripheral, they are very different internally.

PCM_Programmer has pointed you to some I2C examples.

On the XT, the 'point' is that the chip has different oscillator options. XT selects a 'low gain' drive for the crystal, designed for crystals up to about 4MHz (it'll often work well over this), but is unlikely to work above perhaps 8MHz. So your chips are unlikely to be running 'right', with XT selected and a 20Mhz crystal.... However there is a separate 'high gain' option selectable 'HS', designed for faster crystals, up to 20MHz.

The key difference about I2C, is that instead of the bus being driven high and driven low, it's an 'open collector' bus. The devices only drive it low, and there have to be resistors to pull the lines high (note comment from PCM_programmer). The devices respond to their programmed address. When a device is not 'talking', it turns it's drivers off, and allows the bus to float, so another device can be on the same bus. It is designed so that multiple devices can exist on the one pair of wires. Smile
jaos699



Joined: 06 Jul 2015
Posts: 6

View user's profile Send private message

PostPosted: Fri Jul 10, 2015 4:56 am     Reply with quote

Beautiful! It is finally working! 1 master 2 slaves,writing and reading perfectly. Thank you very much for the help Ttelmah and PCM programmer.
I though that I could choose more than one option for the same oscillator Rolling Eyes and it magically would make it change the clock frequency lol.

Just one more thing, when I try to connect to a slave that is not working (lost power or any other problem), it looks like that the master gets stuck in the i2c_start() and cant move on, is there any way that I can just ignore the slave if it is not working?
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Fri Jul 10, 2015 8:01 am     Reply with quote

Yes.

Look at the bus scanner example that PCM_Programmer pointed to (and wrote). It scans the bus, and tells you all the devices it finds, so has to avoid problems if a device is not there!. It uses the acknowledge status when an address is sent.
The code won't hang on 'start', but will hiccup it you try to perform any read, on a device that is not present.
jaos699



Joined: 06 Jul 2015
Posts: 6

View user's profile Send private message

PostPosted: Fri Jul 10, 2015 9:06 am     Reply with quote

I will add this scan so my program can be more reliable, but actually my problem was something related to the electronic part, when I unplugged the power off one of the slave prototyping boards but the wires were still in the circuit, the master could not send any signal to other powered slaves. I just have to unplug everything, including the wires lol.
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Fri Jul 10, 2015 1:03 pm     Reply with quote

Problem there is if the device is switched 'off', it will pull both the lines low, via the internal protection diodes.

If you want to test for this, read the two inputs (use input_state), while not driving them, and if either reads as '0', then you have a device shorting the bus....
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