0,0 → 1,320 |
#include "defines.h" |
#include "I2C1.h" |
|
extern I2C1_DATA i2c_data; |
|
// Set up the data structures for the base_I2C.code |
// Should be called once before any i2c routines are called |
void I2C1_Init(void) { |
i2c_data.buffer_in_len = 0; |
i2c_data.buffer_in_read_ind = 0; |
i2c_data.buffer_in_write_ind = 0; |
|
i2c_data.operating_state = I2C_IDLE; |
i2c_data.return_status = 0; |
|
i2c_data.master_dest_addr = 0; |
i2c_data.master_status = I2C_MASTER_IDLE; |
|
// Enable I2C interrupt |
PIE1bits.SSP1IE = 1; |
} |
|
// Setup the PIC to operate as a master. |
void I2C1_Configure_Master(uint8_t speed) { |
// i2c_data.operating_mode = I2C_MODE_MASTER; |
|
I2C_1_CLK_TRIS = 1; |
I2C_1_DAT_TRIS = 1; |
|
SSP1STAT = 0x0; |
SSP1CON1 = 0x0; |
SSP1CON2 = 0x0; |
SSP1CON3 = 0x0; |
SSP1CON1bits.SSPM = 0x8; // I2C Master Mode |
if (speed == 0x01) { |
SSP1ADD = 0x13; // Operate at 400KHz (32MHz) |
SSP1STATbits.SMP = 1; // Disable Slew Rate Control |
} else if (speed == 0x02) { |
SSP1ADD = 0x07; // Operate at 1Mhz (32Mhz) |
SSP1STATbits.SMP = 1; // Disable Slew Rate Control |
} else { |
SSP1ADD = 0x4F; // Operate at 100KHz (32MHz) |
SSP1STATbits.SMP = 0; // Enable Slew Rate Control |
} |
SSP1CON1bits.SSPEN = 1; // Enable MSSP1 Module |
} |
|
// Sends length number of bytes in msg to specified address (no R/W bit) |
void I2C1_Master_Send(uint8_t address, uint8_t length, uint8_t *msg) { |
if (length == 0) |
return; |
|
// Copy message to send into buffer and save length/address |
for (uint8_t i = 0; i < length; i++) { |
i2c_data.buffer_in[i] = msg[i]; |
} |
i2c_data.buffer_in_len = length; |
i2c_data.master_dest_addr = address; |
i2c_data.buffer_in_read_ind = 0; |
i2c_data.buffer_in_write_ind = 0; |
|
// Change status to 'next' operation |
i2c_data.operating_state = I2C_SEND_ADDR; |
i2c_data.master_status = I2C_MASTER_SEND; |
|
// Generate start condition |
SSP1CON2bits.SEN = 1; |
} |
|
// Reads length number of bytes from address (no R/W bit) |
void I2C1_Master_Recv(uint8_t address, uint8_t length) { |
if (length == 0) |
return; |
|
// Save length and address to get data from |
i2c_data.buffer_in_len = length; |
i2c_data.master_dest_addr = address; |
i2c_data.buffer_in_read_ind = 0; |
i2c_data.buffer_in_write_ind = 0; |
|
// Change status to 'next' operation |
i2c_data.operating_state = I2C_SEND_ADDR; |
i2c_data.master_status = I2C_MASTER_RECV; |
|
// Generate start condition |
SSP1CON2bits.SEN = 1; |
} |
|
// Writes msg to address then reads length number of bytes from address |
void I2C1_Master_Restart(uint8_t address, uint8_t msg, uint8_t length) { |
uint8_t c; |
if (length == 0) { |
c = msg; |
I2C1_Master_Send(address, 1, &c); |
return; |
} |
|
// Save length and address to get data from |
i2c_data.buffer_in[0] = msg; |
i2c_data.buffer_in_len = length; |
i2c_data.master_dest_addr = address; |
i2c_data.buffer_in_read_ind = 0; |
i2c_data.buffer_in_write_ind = 0; |
|
// Change status to 'next' operation |
i2c_data.operating_state = I2C_SEND_ADDR; |
i2c_data.master_status = I2C_MASTER_RESTART; |
|
// Generate start condition |
SSP1CON2bits.SEN = 1; |
} |
|
void I2C1_Interrupt_Handler() { |
// If we are in the middle of sending data |
if (i2c_data.master_status == I2C_MASTER_SEND) { |
switch (i2c_data.operating_state) { |
case I2C_IDLE: |
break; |
case I2C_SEND_ADDR: |
// Send the address with read bit set |
i2c_data.operating_state = I2C_CHECK_ACK_SEND; |
SSP1BUF = (i2c_data.master_dest_addr << 1) | 0x0; |
break; |
case I2C_CHECK_ACK_SEND: |
// Check if ACK is received or not |
if (!SSP1CON2bits.ACKSTAT) { |
// If an ACK is received, send next byte of data |
if (i2c_data.buffer_in_read_ind < i2c_data.buffer_in_len) { |
SSP1BUF = i2c_data.buffer_in[i2c_data.buffer_in_read_ind]; |
i2c_data.buffer_in_read_ind++; |
} else { |
// If no more data is to be sent, send stop bit |
i2c_data.operating_state = I2C_IDLE; |
SSP1CON2bits.PEN = 1; |
i2c_data.master_status = I2C_MASTER_IDLE; |
i2c_data.return_status = I2C_SEND_OK; |
} |
} else { |
// If a NACK is received, stop transmission and send error |
i2c_data.operating_state = I2C_IDLE; |
SSP1CON2bits.PEN = 1; |
i2c_data.master_status = I2C_MASTER_IDLE; |
i2c_data.return_status = I2C_SEND_FAIL; |
} |
break; |
} |
// If we are in the middle of receiving data |
} else if (i2c_data.master_status == I2C_MASTER_RECV) { |
switch (i2c_data.operating_state) { |
case I2C_IDLE: |
break; |
case I2C_SEND_ADDR: |
// Send address with write bit set |
i2c_data.operating_state = I2C_CHECK_ACK_RECV; |
uint8_t tmp = (i2c_data.master_dest_addr << 1); |
tmp |= 0x01; |
SSP1BUF = tmp; |
break; |
case I2C_CHECK_ACK_RECV: |
// Check if ACK is received |
if (!SSP1CON2bits.ACKSTAT) { |
// If an ACK is received, set module to receive 1 byte of data |
i2c_data.operating_state = I2C_RCV_DATA; |
SSP1CON2bits.RCEN = 1; |
} else { |
// If a NACK is received, stop transmission and send error |
i2c_data.operating_state = I2C_IDLE; |
SSP1CON2bits.PEN = 1; |
i2c_data.master_status = I2C_MASTER_IDLE; |
i2c_data.return_status = I2C_RECV_FAIL; |
} |
break; |
case I2C_RCV_DATA: |
// On receive, save byte into buffer |
// TODO: Handle I2C buffer overflow |
i2c_data.buffer_in[i2c_data.buffer_in_write_ind] = SSP1BUF; |
i2c_data.buffer_in_write_ind++; |
if (i2c_data.buffer_in_write_ind < i2c_data.buffer_in_len) { |
// If we still need to read, send an ACK to the slave |
i2c_data.operating_state = I2C_REQ_DATA; |
SSP1CON2bits.ACKDT = 0; // ACK |
SSP1CON2bits.ACKEN = 1; |
} else { |
// If we are done reading, send an NACK to the slave |
i2c_data.operating_state = I2C_SEND_STOP; |
SSP1CON2bits.ACKDT = 1; // NACK |
SSP1CON2bits.ACKEN = 1; |
} |
break; |
case I2C_REQ_DATA: |
// Set module to receive one byte of data |
i2c_data.operating_state = I2C_RCV_DATA; |
SSP1CON2bits.RCEN = 1; |
break; |
case I2C_SEND_STOP: |
// Send the stop bit and copy message to send to Main() |
i2c_data.operating_state = I2C_IDLE; |
SSP1CON2bits.PEN = 1; |
i2c_data.master_status = I2C_MASTER_IDLE; |
i2c_data.return_status = I2C_RECV_OK; |
break; |
} |
} else if (i2c_data.master_status == I2C_MASTER_RESTART) { |
switch (i2c_data.operating_state) { |
case I2C_IDLE: |
break; |
case I2C_SEND_ADDR: |
// Send the address with read bit set |
i2c_data.operating_state = I2C_CHECK_ACK_SEND; |
SSP1BUF = (i2c_data.master_dest_addr << 1) | 0x0; |
break; |
case I2C_CHECK_ACK_SEND: |
// Check if ACK is received or not |
if (!SSP1CON2bits.ACKSTAT) { |
// If an ACK is received, send first byte of data |
SSP1BUF = i2c_data.buffer_in[0]; |
i2c_data.operating_state = I2C_CHECK_ACK_RESTART; |
} else { |
// If a NACK is received, stop transmission and send error |
i2c_data.operating_state = I2C_IDLE; |
SSP1CON2bits.PEN = 1; |
i2c_data.master_status = I2C_MASTER_IDLE; |
i2c_data.return_status = I2C_SEND_FAIL; |
} |
break; |
case I2C_CHECK_ACK_RESTART: |
if (!SSP1CON2bits.ACKSTAT) { |
SSP1CON2bits.RSEN = 1; |
i2c_data.operating_state = I2C_SEND_ADDR_2; |
} else { |
// If a NACK is received, stop transmission and send error |
i2c_data.operating_state = I2C_IDLE; |
SSP1CON2bits.PEN = 1; |
i2c_data.master_status = I2C_MASTER_IDLE; |
i2c_data.return_status = I2C_SEND_FAIL; |
} |
break; |
case I2C_SEND_ADDR_2: |
// Send the address with read bit set |
i2c_data.operating_state = I2C_CHECK_ACK_RECV; |
uint8_t tmp = (i2c_data.master_dest_addr << 1); |
tmp |= 0x01; |
SSP1BUF = tmp; |
break; |
case I2C_CHECK_ACK_RECV: |
// Check if ACK is received |
if (!SSP1CON2bits.ACKSTAT) { |
// If an ACK is received, set module to receive 1 byte of data |
i2c_data.operating_state = I2C_RCV_DATA; |
SSP1CON2bits.RCEN = 1; |
} else { |
// If a NACK is received, stop transmission and send error |
i2c_data.operating_state = I2C_IDLE; |
SSP1CON2bits.PEN = 1; |
i2c_data.master_status = I2C_MASTER_IDLE; |
i2c_data.return_status = I2C_RECV_FAIL; |
} |
break; |
case I2C_RCV_DATA: |
// On receive, save byte into buffer |
// TODO: Handle I2C buffer overflow |
i2c_data.buffer_in[i2c_data.buffer_in_write_ind] = SSP1BUF; |
i2c_data.buffer_in_write_ind++; |
if (i2c_data.buffer_in_write_ind < i2c_data.buffer_in_len) { |
// If we still need to read, send an ACK to the slave |
i2c_data.operating_state = I2C_REQ_DATA; |
SSP1CON2bits.ACKDT = 0; // ACK |
SSP1CON2bits.ACKEN = 1; |
} else { |
// If we are done reading, send an NACK to the slave |
i2c_data.operating_state = I2C_SEND_STOP; |
SSP1CON2bits.ACKDT = 1; // NACK |
SSP1CON2bits.ACKEN = 1; |
} |
break; |
case I2C_REQ_DATA: |
// Set module to receive one byte of data |
i2c_data.operating_state = I2C_RCV_DATA; |
SSP1CON2bits.RCEN = 1; |
break; |
case I2C_SEND_STOP: |
// Send the stop bit |
i2c_data.operating_state = I2C_IDLE; |
SSP1CON2bits.PEN = 1; |
i2c_data.master_status = I2C_MASTER_IDLE; |
i2c_data.return_status = I2C_RECV_OK; |
break; |
} |
} |
} |
|
/* Returns 0 if I2C module is currently busy, otherwise returns status code */ |
uint8_t I2C1_Get_Status() { |
// if (i2c_data.operating_mode == I2C_MODE_MASTER) { |
if (i2c_data.master_status != I2C_MASTER_IDLE || i2c_data.buffer_in_len == 0) { |
return 0; |
} else { |
return i2c_data.return_status; |
} |
} |
|
uint8_t I2C1_Buffer_Len() { |
return i2c_data.buffer_in_len; |
} |
|
/* Returns 0 if I2C module is currently busy, otherwise returns buffer length */ |
uint8_t I2C1_Read_Buffer(uint8_t *buffer) { |
uint8_t i = 0; |
while (i2c_data.buffer_in_len != 0) { |
buffer[i] = i2c_data.buffer_in[i2c_data.buffer_in_read_ind]; |
i++; |
if (i2c_data.buffer_in_read_ind == MAXI2C1BUF-1) { |
i2c_data.buffer_in_read_ind = 0; |
} else { |
i2c_data.buffer_in_read_ind++; |
} |
i2c_data.buffer_in_len--; |
} |
return i; |
} |