|
|
View previous topic :: View next topic |
Author |
Message |
nehallove
Joined: 16 Jan 2008 Posts: 61
|
i2c master and i2c slave implementation problems |
Posted: Thu Feb 18, 2010 7:13 pm |
|
|
Hi All,
I am bit stuck now. I want to implement PIC18F25k20 controller in both master and slave mode. And with CCS functions I am not able to do that.
I have to use
Code: |
#use i2c(Master,Slow,sda=PIN_C4,scl=PIN_C3,force_hw)
#use I2C(slave,sda=PIN_C4,scl=PIN_C3, address=0xa0,FORCE_HW) |
Now these use statements cannot be modified during run time, and I can't switch back to master mode to slave mode and vice versa.
Does anyone know how to implement this requirement?
Please let me know.
Thank you,
nehal _________________ nehal |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Fri Feb 19, 2010 2:58 am |
|
|
What you want is multi master mode.
I too had trouble finding the information on how to do this and in the end wrote my own routines. I use i2c interrupts for slave mode and switch to master mode when needed to send data.
I have listed the code snippets below. I know this is not a full program but it should show you how I managed to get it working.
I have cut out some of the irrelevent code so hopefully you will get the idea of how it works and be able to impliment your own!
There are also some defines, globals etc missing. If you have trouble understanding it I will try and help.
Code: |
// from a i2c.h file
#byte SSP1CON2 = 0xFC5
#byte SSP1CON1 = 0xFC6
#byte SSP1STAT = 0xFC7
#byte SSP1ADD = 0xFC8
#byte SSP1BUF = 0xFC9
#bit SSP1STAT_BF = SSP1STAT.0 // Buffer Full
#bit SSP1STAT_UA = SSP1STAT.1 // Update Address bit (10 bit slave address)
#bit SSP1STAT_RW = SSP1STAT.2 // Read (1), Write (0)
#bit SSP1STAT_S = SSP1STAT.3 // Start
#bit SSP1STAT_P = SSP1STAT.4 // Stop
#bit SSP1STAT_DA = SSP1STAT.5 // Data (1), Address Match (0)
#bit SSP1STAT_CKE = SSP1STAT.6 // SMBus Select Bit
#bit SSP1STAT_SMP = SSP1STAT.7 // Slew Rate Control 100kHz (1), 400kHz (0)
#bit SSP1CON1_CKP = SSP1CON1.4
#define I2C_NO_CMD 0
#define I2C_ESE_CMD 1
#define I2C_AUDIO_CMD 2
#define I2C_STATUS_REQ 3
#define I2C_CONFIG_REQ 4
#define I2C_SOFTWARE_UPD 5
#define I2C_ADDRESS_REQ 6
#define I2C_DONE_REQ 7
int1 bus_collision = false;
int8 i2c_state;
int8 i2c_data[80];
int8 i2c_cmd[80];
int8 i2c_data_len;
int8 i2c_data_pos;
int1 i2c_command_flag = false;
|
Code: |
#use i2c(MULTI_MASTER, ADDRESS=0xA0, sda=PIN_C4, scl=PIN_C3, FORCE_HW, STREAM=I2C)
#INT_BUSCOL
void buscol_isr() {
bus_collision = true;
}
#INT_SSP
void i2c_isr() {
int c;
int8 sign_bit, carry_bit;
union {
float grad;
int8 array[4];
} grad_u;
if (!SSP1STAT_DA) // Address Match
{
i2c_data_pos = 0;
c = SSP1BUF; // c = Address, Clears BF flag!
if (!SSP1STAT_RW) { // Colibri Write Data
SSP1CON1_CKP = 1;
return;
}
}
if (SSP1STAT_DA && SSP1STAT_BF) // BF is low for a read
{
c = SSP1BUF; // Clears BF flag!
switch(i2c_state)
{
case 0: // Command state
switch(c)
{
case I2C_AUDIO_CMD:
i2c_data_pos = 0;
i2c_state = 2;
break;
case I2C_DONE_REQ:
i2c_data[0] = i2c_command_flag;
i2c_data_len = 1;
i2c_state = 1;
break;
default:
i2c_data_pos = 0;
i2c_state = 0;
break;
}
break;
case 1: // Data request state
break;
case 2: // Command state
i2c_cmd[i2c_data_pos++] = c;
if (i2c_data_pos == i2c_cmd[0])
{
i2c_state = 0;
i2c_command_flag = true;
}
break;
case 3: // Software update data
break;
default:
i2c_state = 0; // Reset state, used to bypass data
break;
}
}
// Load data if we have some to send back
if (SSP1STAT_RW) // CPU Read Data
{
SSP1BUF = i2c_data[i2c_data_pos++];
if (i2c_data_pos == i2c_data_len) // Last byte
{
i2c_data_pos = 0;
i2c_data_len = 0;
if (i2c_state != 3)
i2c_state = 0;
}
}
SSP1CON1_CKP = 1;
}
void i2c_init() {
i2c_state = 0;
i2c_data_len = 0;
i2c_data_pos = 0;
baud_rate = SSP1ADD;
if (ese_mode == REPEATER) {
SSP1CON1 = (SSP1CON1 & 0xF0) | 0x06; //0x0E; // 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; //0x0E; // Slave mode
SSP1CON2 |= 0x01; // Slave mode clock stretching
SSP1ADD = I2C_ADDRESS; // Slave mode
clear_interrupt(INT_SSP);
enable_interrupts(INT_SSP);
}
void func()
{
int val = 123;
i2c_mm_start(COLIBRI_ADDRESS << 1);
ack = i2c_write(val); // ack (0=ACK, 1=NOACK, 2=Collision)
i2c_mm_stop();
}
|
This seems to work quite well for my system. |
|
|
|
|
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
|