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

i2c multimaster problem
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
christian.koji



Joined: 12 May 2010
Posts: 16

View user's profile Send private message

i2c multimaster problem
PostPosted: Fri May 21, 2010 11:30 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri May 21, 2010 12:07 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri May 21, 2010 12:59 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 24, 2010 2:44 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 24, 2010 7:42 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 24, 2010 8:12 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 24, 2010 8:52 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 24, 2010 9:09 am     Reply with quote

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 Smile

Anyway glad to have helped.
cheehow



Joined: 15 Sep 2010
Posts: 28

View user's profile Send private message

HI !! need your help =)
PostPosted: Mon Sep 20, 2010 11:03 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Sep 21, 2010 2:17 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Sep 21, 2010 2:29 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Sep 21, 2010 6:59 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Sep 21, 2010 9:54 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Sep 22, 2010 2:30 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Sep 22, 2010 4:41 am     Reply with quote

#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()
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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