I2C MASTER DRIVER SPEC
tx,rx message size predefined
messages sent every 10ms
for read data send command and wait for not busy
#ifndef I2C_Master_Driver_h
#define I2C_Master_Driver_h 1
#include "Types.h" // definitions of bool,byte
#include "IO_Map.h" // hardware definitions
// The Master I2C driver can command a TX or RX message to
// any slave.
// A Tx or Rx message is initiated with the slave address
// and then an interrupt is generated by the device after
// each byte is sent or received.
// The length of the messages can be different for each
// slave.
// Max message size 16 bytes.
// Get_Busy_Status returns True whilst bus active
// Use Get_Busy_Status to indicate message transaction
// complete before Get_Read_Bytes.
#define IIC_DIV 0x00 // mult 1, ICR 00 (SCL div = 20, SDA hold = 7)
// 4MHz / (1 * 20) = 200K, SDA hold time = (1/4Mhz) * 7 = 1.75us
#define IIC_BUFFER_SIZE 16
// Initailise the I2C module for master mode
extern void Init_I2CM(void );
// Interrupt handler to manage all master events on the I2C
// link
extern interrupt void I2C_ISR(void );
// Reports True during transmission
extern bool I2CM_Get_Busy_Status(void );
// Return the success of the last transmission.
extern bool I2CM_Get_No_Resp_Status(void );
// Starts an I2C transmission to read a number of bytes
// from a slave at an address. When complete use Get_Read_
// Bytes for data received.
extern void I2CM_Read_Bytes(byte Slave_Addr, byte Number_Of_Bytes);
// Copies data received to pointer location supplied.
// Only copies the number of bytes that was requested in
// the message.
extern void I2CM_Get_Read_Data(byte* Data);
// Starts an I2C transmission to write a number of bytes to
// a slave at an address. Copies data from pointer
// location, only copies number of bytes requested..
extern void I2CM_Write_Bytes(byte Slave_Addr, byte Number_Of_Bytes, const byte* Data);
#endif
BODY
#include "I2C_Master_Driver.h"
#define IIC_ERROR_STATUS 0
#define IIC_READY_STATUS 1
#define IIC_HEADER_SENT_STATUS 2
#define IIC_DATA_TRANSMISSION_STATUS 3
#define IIC_DATA_SENT_STATUS 4
static byte I2CM_RX_Data[IIC_BUFFER_SIZE];
static byte I2CM_TX_Data[IIC_BUFFER_SIZE];
static byte I2CM_Counter = 0;
static byte I2CM_Step = IIC_READY_STATUS;
static byte I2CM_Length = 1;
static byte I2CM_Data_Direction = 0;
static byte Last_But_One = 0;
static bool No_Resp = TRUE;
void Init_I2CM(void )
{
_IIC1C.Bits.IICEN = 1; /* Enable IIC module */
_IIC1F.Byte = IIC_DIV; /* Set IIC frequency = 100K Baud */
I2CM_Step = IIC_READY_STATUS;
_IIC1C.Bits.IICIE = 1; /* Enable IIC interrupts */
}
interrupt void I2C_ISR(void )
{
byte Temp;
/* Interrupts generated after the slave address has been sent and after each data byte
,write or read mode, when performing a read the IIC needs to be disabled straight after the data
byte is read or another interrupt will be generated.*/
Temp = _IIC1S.Byte; /* ACK the interrupt */
_IIC1S.Bits.IICIF=1;
/* Verify the Arbitration lost status */
if(_IIC1S.Bits.ARBL==1){
_IIC1S.Bits.ARBL = 1; // clear=1
_IIC1C.Bits.MST = 0; // reset master bit
_IIC1C.Bits.IICEN = 0;
I2CM_Step = IIC_ERROR_STATUS;
return;
}
/* if State = Header Sent */
if(I2CM_Step == IIC_HEADER_SENT_STATUS){
if(_IIC1S.Bits.RXAK==1){
_IIC1C.Bits.MST = 0; // reset master bit
_IIC1C.Bits.IICEN = 0;
I2CM_Step = IIC_READY_STATUS;
return;
}
else {
_IIC1C.Bits.TX = I2CM_Data_Direction; // set direction
I2CM_Step = IIC_DATA_TRANSMISSION_STATUS; // set next state
if(_IIC1C.Bits.TX == 0){ /* If we are reading data clock in first slave byte */
Temp = _IIC1D.Byte; // read data byte
return;
}
}
}
/* If state = byte transmision is in progress.*/
if(I2CM_Step == IIC_DATA_TRANSMISSION_STATUS){
if(_IIC1C.Bits.TX == 1) { /* If Master is sending data to slave */
_IIC1D.Byte = I2CM_TX_Data[I2CM_Counter]; /* Send the next byte */
I2CM_Counter += 1;
/* Mark we are done sending Bytes */
if(I2CM_Length == I2CM_Counter) {
I2CM_Step = IIC_DATA_SENT_STATUS;
}
}
else { // reading data from slave
if(I2CM_Counter == Last_But_One) { // last byte ?
I2CM_RX_Data[I2CM_Counter] = _IIC1D.Byte; /* Read the byte */
_IIC1C.Bits.MST = 0; // reset master bit to
// Generate a stop condition
_IIC1C.Bits.IICEN = 0; // disable IIC
I2CM_Counter += 1; // do not optimise by moving above
I2CM_Step = IIC_READY_STATUS; //finished
No_Resp = FALSE;
}
else {
I2CM_RX_Data[I2CM_Counter] = _IIC1D.Byte; /* Read the next byte */
I2CM_Counter += 1;
}
/* Master should not ACK the last byte */
if(I2CM_Counter == Last_But_One) _IIC1C.Bits.TXAK = 1; /* If penultimate byte indicate end of transfer */
}
}
/* if state = We are done with the transmition.*/
else {
_IIC1C.Bits.TX = 0; // set RX mode
_IIC1C.Bits.MST = 0; // reset master bit to
// Generate a stop condition
_IIC1C.Bits.IICEN = 0; // disable IIC
I2CM_Step = IIC_READY_STATUS; // finished
No_Resp = FALSE;
}
}
bool I2CM_Get_Busy_Status(void )
{
return (I2CM_Step > IIC_READY_STATUS);
}
bool I2CM_Get_No_Resp_Status(void )
{
// return TRUE if no response from last requested slave
return No_Resp;
}
void I2CM_Read_Bytes(byte Slave_Addr, byte Number_Of_Bytes)
{
byte Temp;
_IIC1C.Bits.IICEN = 0;
I2CM_Length = Number_Of_Bytes;
Last_But_One = Number_Of_Bytes - 1; // save time calculating later
I2CM_Counter = 0; // reset counter
I2CM_Step = IIC_HEADER_SENT_STATUS;
I2CM_Data_Direction = 0; // set for read
No_Resp = TRUE;
_IIC1C.Bits.IICEN = 1;
/* Format the Address to fit in the IICA register and place a 1 on the R/W bit. */
Slave_Addr <<=1; // shift left 1 bit
Slave_Addr &= 0xFE;
Slave_Addr |= 0x01; /* Set the Read from slave bit. */
Temp = _IIC1S.Byte; /* Clear any pending interrupt */
_IIC1S.Bits.IICIF=1;
_IIC1C.Bits.MST = 0; // reset master bit
_IIC1C.Bits.TX = 1; /* Select Transmit Mode */
_IIC1C.Bits.MST = 1; /* Select Master Mode (Send Start Bit)*/
_IIC1D.Byte=Slave_Addr; /* Send selected slave address */
}
void I2CM_Get_Read_Data(byte* Data)
{
byte Temp;
for(Temp=0; Temp<I2CM_Length; Temp++)
Data[Temp] = I2CM_RX_Data[Temp];
}
void I2CM_Write_Bytes(byte Slave_Addr, byte Number_Of_Bytes, const byte* Data)
{
byte Temp;
_IIC1C.Bits.IICEN = 0;
I2CM_Length = Number_Of_Bytes;
I2CM_Counter =0;
I2CM_Step = IIC_HEADER_SENT_STATUS;
I2CM_Data_Direction = 1;
No_Resp = TRUE;
// copy data into buffer
for(Temp=0; Temp<Number_Of_Bytes; Temp++)
I2CM_TX_Data[Temp] = Data[Temp];
_IIC1C.Bits.IICEN = 1;
/* Format the Address to fit in the IICA register and place a 0 on the R/W bit.*/
Slave_Addr <<=1; // shift left 1 bit
Slave_Addr &= 0xFE;
Temp = _IIC1S.Byte; /* Clear any pending interrupt */
_IIC1S.Bits.IICIF = 1;
_IIC1C.Bits.MST = 0; // reset master bit
_IIC1S.Bits.SRW = 0;
_IIC1C.Bits.TX = 1; /* Select Transmit Mode */
_IIC1C.Bits.MST = 1; /* Select Master Mode (Send Start Bit) */
_IIC1D.Byte = Slave_Addr; /* Send selected slave address */
}
Message Edited by mad_dad on
2009-01-06 03:42 PMMessage Edited by mad_dad on
2009-01-06 03:50 PM