|
|
View previous topic :: View next topic |
Author |
Message |
christian.koji
Joined: 12 May 2010 Posts: 16
|
i2c multimaster problem |
Posted: Fri May 21, 2010 11:30 am |
|
|
Hey guys I'm with a problems to make a multimaster system works...
I've written a master.c and a slave.c, both working and communicating with each other. Now I would like to merge them and make a multimaster code, but its not working.
On master.c I have to press a button to send some data or another to request data and I have some functions that send and receive data.
On slave.c I have an interrupt #int_ssp that interrupt on match address
I'm gonna put the codes here and in the end I'm gonna put the multimaster code I've done, that is not working...
If someone could help me...
master.c
Code: |
#include <18F452.h>
//#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
//#FUSES WRT_50% //Lower half of Program Memory is Write Protected
#use delay(clock=8000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use i2c(MULTI_MASTER, sda=PIN_C4,scl=PIN_C3, force_hw)
#BYTE SSPCON1 = 0xFC6
#BYTE SSPBUF = 0xFC9
#include <LCD_8B.c>
#define end_1 0xA0 //FIRST SLAVE
#define end_2 0xB0 //SECOND SLAVE
BYTE req_i2c(BYTE end_disp, BYTE end_mem)
{
BYTE result = 0;
i2c_start (); //begin communication
i2c_write (end_disp); //send slave address
i2c_write (end_mem); //request slave internal memory address for analogue data
//i2c_stop(); //stop write cycle to shift to read cycle
i2c_start (); //send repeated start command to begin read cycle
end_disp++;
i2c_write (end_disp); //add 1 to the address to send a write bit
result = i2c_read(0); //read analogue information from the slave
i2c_stop (); //terminate communication
delay_ms(10);
return result;
}
void envia_i2c(BYTE end_disp, BYTE mem_add, BYTE dado2, BYTE dado3)
{
i2c_start(); //begin transmission
i2c_write(end_disp); //select address of device to communicate with
i2c_write(mem_add); //send actual data1
i2c_write(dado2); //send actual data2
i2c_write(dado3); //send actual data3
i2c_stop(); //terminate communication
delay_ms(10); //debouncing delay
}
int16 make16(BYTE MSB, BYTE LSB){
int16 dado;
dado = MSB << 8;
dado = dado | LSB;
return dado;
}
void main()
{
lcd_ini();
delay_ms(500);
//set_tris_c(0b10100111);
set_tris_b(0xF0);
set_tris_d(0x00);
BYTE MSB,LSB;
int16 dado;
printf(lcd_escreve,"\fInicio..."); //print on LCD
output_b(0xFE);
while(TRUE)
{
if(!input(PIN_B4)){
printf(lcd_escreve,"\fVai enviar 1e3"); //print on LCD
envia_i2c(end_2, 0xFF, 1, 3); //send_i2c function
printf(lcd_escreve,"\f");
printf(lcd_escreve,"1e3 Enviado"); //print on LCD
}
if(!input(PIN_B7)){
printf(lcd_escreve,"\fVai enviar 2e4");
envia_i2c(end_2, 0xFF, 2, 4); //send_i2c function
printf(lcd_escreve,"\f2e4 Enviado");
}
if(!input(PIN_B5)){
printf(lcd_escreve,"\fRequisicao"); //print on LCD
MSB = req_i2c(end_2, 0x10); //request_i2c function
LSB = req_i2c(end_2, 0x20); //request_i2c function
dado = make16(MSB,LSB);
printf(lcd_escreve,"\fRecebido: %lx h", dado);
printf(lcd_escreve,"\nRecebido: %ld d", dado);
}
}
}
|
slave.c
Code: |
// -- SLAVE SOURCE CODE -- at address=0xB0
#include <18F4520.h>
#use delay(clock=8000000)
#include <LCD_8B.c>
//#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz)
#FUSES NOPUT //No Power Up Timer
#FUSES PROTECT //Code protected from reads
#FUSES NOBROWNOUT //No brownout reset
#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 //No Debug mode for ICD
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use i2c(SLAVE,sda=PIN_C4,scl=PIN_C3,address=0xB0, force_hw)
#BYTE SSPCON1 = 0xFC6
#BYTE SSPSTAT = 0xFC7
#BYTE SSPBUF = 0xFC9
#bit StartBit = SSPSTAT.3
#bit StopBit = SSPSTAT.4
#BIT SSPOV = 0xFC6.6 //Indicates overflow
#BIT BF = 0xFC7.0 //Buffer Full
#BIT CKP = 0xFC6.4
int i,j;
BYTE address, mem_add, data1, data2, data3, data4, buffer[10], info[0x21];
#INT_SSP
void ssp_interupt ()
{
j=1;
BYTE state, incoming;
state = i2c_isr_state();
if(state < 0x80) //master is sending data
{
incoming = i2c_read();
if(state == 0)
{
address = incoming;
}
if(state == 1) //first received byte is address
{
mem_add = incoming;
}
if(state == 2) //second received byte is data
{
buffer[i++] = incoming;
}
if(state == 3) //third received byte is data
{
buffer[i++] = incoming;
}
}
if(state == 0x80) //master is requesting data
{
i2c_write(info[mem_add]);
}
}
void main()
{
lcd_ini();
delay_ms(500);
set_tris_c(0xFF);
set_tris_d(0x00);
set_tris_b(0xF0); ;
output_b(0xFE);
printf(lcd_escreve,"\f Inicio..."); //print on LCD
enable_interrupts(INT_SSP); //enable I2C interrupts
enable_interrupts(GLOBAL);
info[0x10] = 0x25;
info[0x20] = 0x17;
i = 0;
while(TRUE)
{
if(i>=2) i=0;
data1 = buffer[0];
data2 = buffer[1];
if(j==1){
j=0;
printf(lcd_escreve,"\fE:%x M:%x", address, mem_add); //print on LCD
printf(lcd_escreve,"\n1:%x 2:%x", data1, data2); //print on LCD
}
if (SSPOV || BF)
{
SSPOV = 0;
BF = 0;
}
}
}
|
multimaster.c
Code: |
#include <18F452.h>
//#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
//#FUSES WRT_50% //Lower half of Program Memory is Write Protected
#use delay(clock=8000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use i2c(MULTI_MASTER, sda=PIN_C4,scl=PIN_C3, force_hw, address=0xC0)
#BYTE SSPCON1 = 0xFC6
#BYTE SSPBUF = 0xFC9
#BYTE SSPSTAT = 0xFC7
#bit StartBit = SSPSTAT.3
#bit StopBit = SSPSTAT.4
#BIT SSPOV = 0xFC6.6 //Indicates overflow
#BIT BF = 0xFC7.0 //Buffer Full
#BIT CKP = 0xFC6.4
#include <LCD_8B.c>
#define end_1 0xC0 //FIRST MASTER
#define end_2 0xB0 //SECOND MASTER
int i,j;
BYTE address, mem_add, data1, data2, buffer[10], info[0x21];
#INT_SSP
void ssp_interupt ()
{
j=1;
BYTE state, incoming;
state = i2c_isr_state();
if(state < 0x80) //master is sending data
{
incoming = i2c_read();
if(state == 0)
{
address = incoming;
}
if(state == 1) //first received byte is address
{
mem_add = incoming;
}
if(state == 2) //second received byte is data
{
buffer[i++] = incoming;
}
if(state == 3) //second received byte is data
{
buffer[i++] = incoming;
}
}
if(state == 0x80) //master is requesting data
{
i2c_write(info[mem_add]);
}
}
BYTE req_i2c(BYTE req_device_add, BYTE req_mem_add)
{
BYTE result = 0;
i2c_start (); //begin communication
i2c_write (req_device_add); //send slave address
i2c_write (req_mem_add); //request slave internal memory address for analogue data
//i2c_stop(); //stop write cycle to shift to read cycle
i2c_start (); //send repeated start command to begin read cycle
req_device_add++;
i2c_write (req_device_add); //add 1 to the address to send a write bit
result = i2c_read(0); //read analogue information from the slave
i2c_stop (); //terminate communication
delay_ms(10);
return result;
}
void envia_i2c(BYTE send_device_add, BYTE send_mem_add, BYTE send_data1, BYTE send_data2)
{
i2c_start(); //begin transmission
i2c_write(send_device_add); //select address of device to communicate with
i2c_write(send_mem_add); //send actual data1
i2c_write(send_data1); //send actual data2
i2c_write(send_data2); //send actual data3
i2c_stop(); //terminate communication
delay_ms(10); //debouncing delay
}
int16 make16(BYTE MSB, BYTE LSB){
int16 dado;
dado = MSB << 8;
dado = dado | LSB;
return dado;
}
void main()
{
lcd_ini();
delay_ms(500);
set_tris_b(0xF0);
//set_tris_c(0b10100111);
set_tris_d(0x00);
BYTE MSB,LSB;
int16 dado;
enable_interrupts(INT_SSP); //enable I2C interrupts
enable_interrupts(GLOBAL);
info[0x10] = 0x25;
info[0x20] = 0x17;
i = 0;
output_b(0xFE);
while(TRUE)
{
if(i>=2) i=0;
data1 = buffer[0];
data2 = buffer[1];
if(j==1){
j=0;
printf(lcd_escreve,"\fE:%x M:%x", address, mem_add); //print on LCD
printf(lcd_escreve,"\n1:%x 2:%x", data1, data2); //print on LCD
}
if (SSPOV || BF)
{
SSPOV = 0;
BF = 0;
}
if(!input(PIN_B4)){
envia_i2c(end_2, 0xFF, 1, 3); //send_i2c function
}
if(!input(PIN_B7)){
envia_i2c(end_2, 0xFF, 2, 4); //send_i2c function
}
if(!input(PIN_B5)){
MSB = req_i2c(end_2, 0x10); //request_i2c function
LSB = req_i2c(end_2, 0x20); //request_i2c function
dado = make16(MSB,LSB);
printf(lcd_escreve,"\fRecebido: %lx", dado); //print on LCD
printf(lcd_escreve,"\nRecebido: %ld", dado); //print on LCD
delay_ms(3000);
}
}
}
|
Well, I've made some changes and see that, if I take out the interrupt function, I mean erase the ssp_interrupt, I can send data to a slave and receive data from a slave, but I have to stay pressing the button for 1second. In the master.c I just have to click the button and it works o.O |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 21, 2010 12:07 pm |
|
|
Mark's multi-master code in the Code Library does collision detection.
This Microchip multi-master appnote also does collision detection:
http://ww1.microchip.com/downloads/en/AppNotes/00736a.pdf
Your code doesn't appear to do that. I didn't look at your code in
detail, but you should study those two samples for ideas. |
|
|
christian.koji
Joined: 12 May 2010 Posts: 16
|
|
Posted: Fri May 21, 2010 12:59 pm |
|
|
Yes, its not doing collision detection, i'm just trying to do first a functional communication, i'm gonna do as soon as it communicates =P
i read mark's code, but he doesn't use ccs library he wrote one by his own i would like to use ccs's, but yes, i can take some ideas there but i'm kinda lost on his code.. i'm not a too experient pic programmer
actually i'm trying to communicate the multimaster with the slave i post, it shouldnt be a problem yet =]
when i press the button, it doesn't even send the data =/
if i comment the ssp interrupt it works... o.O but i dont think its a problem in the interrupt, because it works in slave.c |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Mon May 24, 2010 2:44 am |
|
|
It took me awhile to get my multimaster mode working, I had to write my own i2c_start and i2c_stop routines as the slave address and master baud rate occupy the same register. Which is strange as the datasheet specifies that it supports multimaster mode, anyway this might help:-
Code: |
#use i2c(MULTI_MASTER, ADDRESS=0xA0, sda=PIN_C4, scl=PIN_C3, FORCE_HW, STREAM=I2C)
void i2c_init() {
i2c_state = 0;
i2c_data_len = 0;
i2c_data_pos = 0;
baud_rate = SSP1ADD;
SSP1CON1 = (SSP1CON1 & 0xF0) | 0x06; // Slave mode
SSP1CON2 |= 0x01; // Slave mode clock stretching
SSP1ADD = I2C_ADDRESS;
enable_interrupts(INT_BUSCOL);
enable_interrupts(INT_SSP);
}
// I2C multiMaster start
int8 i2c_mm_start(int8 address)
{
int8 ack;
disable_interrupts(INT_SSP);
SSP1CON2 &= ~0x01;
SSP1CON1 = (SSP1CON1 & 0xF0) | 0x08; // Master mode
SSP1ADD = baud_rate;
do {
i2c_start(I2C, 1);
ack = i2c_write(address); // Send address with WE (returns 0 = ACK, 1 = NOACK, 2 = Collision)
} while (ack == 2); // Bus Collision
return(ack);
}
// I2C multiMaster stop
void i2c_mm_stop()
{
i2c_stop();
while (SSP1ADD != baud_rate) {}
SSP1CON1 = (SSP1CON1 & 0xF0) | 0x06; // Slave mode
SSP1CON2 |= 0x01; // Slave mode clock stretching
SSP1ADD = I2C_ADDRESS; // Slave mode
clear_interrupt(INT_SSP);
enable_interrupts(INT_SSP);
}
|
|
|
|
christian.koji
Joined: 12 May 2010 Posts: 16
|
|
Posted: Mon May 24, 2010 7:42 am |
|
|
Hmm interesting, i'm gonna do this too, hope it works. I just didnt undertand the line u do while(SSP1ADD != baud_rate){} |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Mon May 24, 2010 8:12 am |
|
|
Good question, It has been awhile since I wrote this code.
Taken from the datasheet:-
Quote: | In I2C Master mode, the BRG reload value is placed in
the lower seven bits of the SSPxADD register
(Figure 18-19). When a write occurs to SSPxBUF, the
Baud Rate Generator will automatically begin counting.
The BRG counts down to 0 and stops until another
reload has taken place. The BRG count is decremented
twice per instruction cycle (TCY) on the Q2 and
Q4 clocks. In I2C Master mode, the BRG is reloaded
automatically. |
I must do this to ensure that the i2c has completely finished before switching back to slave mode. |
|
|
christian.koji
Joined: 12 May 2010 Posts: 16
|
|
Posted: Mon May 24, 2010 8:52 am |
|
|
Oh Ok, guess i understand...
BTW its working now i'm communicating the multimaster with a slave, i have a little problem in communicate one multimaster with another multimaster, but i guess its just some little mistake, i'm trying to fix it...
thanks Wayne, you were very helpfull |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Mon May 24, 2010 9:09 am |
|
|
I am not too sure about that test now, it may be the wrong way to do it but it seems to work. This is what re-visiting code does to you, makes you question your methods, sometimes it's good, sometimes it is not
Anyway glad to have helped. |
|
|
cheehow
Joined: 15 Sep 2010 Posts: 28
|
HI !! need your help =) |
Posted: Mon Sep 20, 2010 11:03 pm |
|
|
Can you please show me your hardware connection and the correct software that you have solved, since you have known where the problem comes from. I'm doing quite similar project with you. I'm using two MCU (PIC16F877A) to communication with each other by using i2c.
I'm using PIC C Compiler (CCS C Compiler) to write the codes.
The following are the codes that I wrote:
Master code:
Code: | #include "C:\Users\Tan Chee How\Desktop\testing I2C\master.h"
#define Device_SDA PIN_C3
#define Device_SCL PIN_C4
#USE I2C (MASTER, SDA=Device_SDA, SCL=Device_SCL)
int x;
BYTE Data;
void main()
{
SET_TRIS_C(0XFF);
SET_TRIS_B(0X00);
SET_TRIS_D(0X00);
OUTPUT_B(0X00);
WHILE(TRUE)
{
if(INPUT(PIN_D1))
OUTPUT_HIGH(PIN_B6);
delay_ms(500);
OUTPUT_LOW(PIN_B6);
delay_ms(500);
OUTPUT_HIGH(PIN_B7);
delay_ms(500);
OUTPUT_LOW(PIN_B7);
for(x=0; x<10; x++)
{
i2c_start();
i2c_write(0xA0);
i2c_write(x);
i2c_write(10-x);
i2c_stop();
delay_ms(100);
i2c_start();
i2c_write(0xA1);
Data=i2c_read(0);
i2c_stop();
delay_ms(100);
}
}
} |
and the slave codes:
Code: |
#include "C:\Users\Tan Chee How\Desktop\testing I2C\slave.h"
#define Device_SDA PIN_C3
#define Device_SCL PIN_C4
#use i2c (slave, SDA= Device_SDA, SCL=Device_SCL,address=0xA0, FORCE_HW)
#INT_SSP
BYTE address, buffer[0x10];
void ssp_interupt ()
{
BYTE incoming, state;
state = i2c_isr_state();
if(state < 0x80)
{
incoming = i2c_read();
if(state == 1)
address = incoming;
if(state == 2)
buffer[address] = incoming;
}
if(state == 0x80)
{
i2c_write(buffer[address]);
}
}
void main ()
{
SET_TRIS_C(0XFF);
SET_TRIS_B(0X00);
SET_TRIS_D(0X00);
OUTPUT_B(0X00);
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (TRUE) {}
} |
Hope that I can hear your reply as soon as possible, your help will be appreciated. Thxs a lot !!!! |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Tue Sep 21, 2010 2:17 am |
|
|
cheehow, do you require multimaster functionality as that is what this thread is about ?
Are you just hving problems getting your I2C to work (master -> slave) ?
Have you debugged your code to find out where the problem lies ?
With regards to the hardware, you need pullup resistors on both lines:-
Code: |
Master -------------------- Slave
VDD -----------------------
|
| | 4K7 pull up resistor
|
SDA ------------------------ SDA
VDD ------------------------
|
| | 4K7 pull up resistor
|
SCL ------------------------ SCL
|
|
|
|
cheehow
Joined: 15 Sep 2010 Posts: 28
|
|
Posted: Tue Sep 21, 2010 2:29 am |
|
|
hi, wayne ... yaya ... my i2c not functioning ... i have debugged it... not error contained. For the hardware part, i also got include the pullup resistor ... it does not work .... izit my code problem ?? i m using PIC C compiler (CCS c Compiler) ....... |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Tue Sep 21, 2010 6:59 am |
|
|
Ok, you didn't post the header files so I assume form this
SET_TRIS_C(0XFF);
SET_TRIS_B(0X00);
SET_TRIS_D(0X00);
you are using fast_io ?
Why do you need to use fast io ?
I sugest removing the fast io defines and the set_tris statements and let CCS deal with it. Even if you only do this to see if it works would help. |
|
|
cheehow
Joined: 15 Sep 2010 Posts: 28
|
|
Posted: Tue Sep 21, 2010 9:54 am |
|
|
I'm using the new PIC C compiler so once I start up the project wizard I choose the PIC controller that I want and all are defined already.
Just type set_tris_port abcd to choose the port that you want.
So I can directly type set_tris_b() as the IO function. Is anything wrong with that ??? |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Wed Sep 22, 2010 2:30 am |
|
|
Show us your master.h file.
Does it have
#use fast_io(b)
#use fast_io(c)
#use fast_io(d) |
|
|
cheehow
Joined: 15 Sep 2010 Posts: 28
|
|
Posted: Wed Sep 22, 2010 4:41 am |
|
|
#include <16F877A.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES LP //Low power osc < 200 khz
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES WRT_50% //Lower half of Program Memory is Write Protected
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
dun have ..... i didnt use #use fast_io() |
|
|
|
|
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
|