|
|
View previous topic :: View next topic |
Author |
Message |
jaos699
Joined: 06 Jul 2015 Posts: 6
|
Problem Master Receiving from Slave (I2C) |
Posted: Thu Jul 09, 2015 9:11 am |
|
|
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
|
|
Posted: Thu Jul 09, 2015 10:58 am |
|
|
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
|
|
Posted: Thu Jul 09, 2015 5:28 pm |
|
|
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
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Jul 10, 2015 1:28 am |
|
|
Well done Jaos. We can all 'live' with an admission like that, and have been there ourselves sometime.
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. |
|
|
jaos699
Joined: 06 Jul 2015 Posts: 6
|
|
Posted: Fri Jul 10, 2015 4:56 am |
|
|
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 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
|
|
Posted: Fri Jul 10, 2015 8:01 am |
|
|
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
|
|
Posted: Fri Jul 10, 2015 9:06 am |
|
|
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
|
|
Posted: Fri Jul 10, 2015 1:03 pm |
|
|
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.... |
|
|
|
|
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
|