|
|
#include "i2c.h"
|
|
|
#include "usart.h"
|
|
|
#include "delay.h"
|
|
|
|
|
|
|
|
|
#define I2C_BASE ((I2C_TypeDef*)i2cBase_Addr_List[i2c_dev->channelNo])
|
|
|
|
|
|
void i2c_hardware_enable(i2c_t *i2c_dev)
|
|
|
{
|
|
|
i2c_hardware_reset(i2c_dev);
|
|
|
|
|
|
// Enables the i2c bus
|
|
|
RCC->APB1ENR |= (1 << i2cBus_En_bitPos[i2c_dev->channelNo]);
|
|
|
i2c_dev->hardwareState = i2c_hw_enabled;
|
|
|
|
|
|
pinInit(pinA9);
|
|
|
pinInit(pinA10);
|
|
|
pinConfig(pinA9, alternate, openDrain, pullUp, fast);// I2C SCL
|
|
|
pinConfig(pinA10, alternate, openDrain, pullUp, fast);// I2C CSA
|
|
|
pinSetAlternate(pinA9, 4);
|
|
|
pinSetAlternate(pinA10, 4);
|
|
|
i2c_dev->hardwareState = i2c_hw_ready;
|
|
|
}
|
|
|
|
|
|
// Resets the I2C hardware using the reset registers,
|
|
|
// This will init the device to it's defualt configuration established by STM
|
|
|
void i2c_hardware_reset(i2c_t *i2c_dev)
|
|
|
{
|
|
|
RCC->APB1RSTR |= (1 << i2cBus_Rst_bitPos[i2c_dev->channelNo]);
|
|
|
RCC->APB1RSTR &= ~(1 << i2cBus_Rst_bitPos[i2c_dev->channelNo]);
|
|
|
i2c_dev->hardwareState = i2c_hw_reset;
|
|
|
}
|
|
|
|
|
|
//enables periferal
|
|
|
void i2c_periferal_enable(i2c_t *i2c_dev)
|
|
|
{
|
|
|
I2C_BASE->CR1 |= I2C_CR1_PE;
|
|
|
i2c_dev->periferalState = i2c_perif_enabled;
|
|
|
//Wait untill periferal is ready for communication
|
|
|
while(!i2c_is_perif_ready(i2c_dev));
|
|
|
i2c_dev->periferalState = i2c_perif_ready;
|
|
|
}
|
|
|
|
|
|
void i2c_periferal_disable(i2c_t *i2c_dev)
|
|
|
{
|
|
|
I2C_BASE->CR1 &= ~I2C_CR1_PE;
|
|
|
i2c_dev->periferalState = i2c_perif_disabled;
|
|
|
}
|
|
|
|
|
|
|
|
|
void i2c_set_mode(i2c_t *i2c_dev, i2c_mode_t mode)
|
|
|
{
|
|
|
//This device will set himself automatically to master mode
|
|
|
if(i2c_dev->mode == i2c_mode_master)
|
|
|
{
|
|
|
|
|
|
}
|
|
|
else if(i2c_dev->mode == i2c_mode_slave)
|
|
|
{
|
|
|
// to be written.
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void i2c_set_address_lenght(i2c_t *i2c_dev, i2c_address_size_t size)
|
|
|
{
|
|
|
if(i2c_dev->mode == i2c_mode_master)
|
|
|
{
|
|
|
if(i2c_dev->addressSize == i2c_address_size_10b)
|
|
|
{
|
|
|
I2C_BASE->CR2 |= I2C_CR2_ADD10; // 10 Bit addressing
|
|
|
I2C_BASE->CR2 &= ~I2C_CR2_HEAD10R; // 7 Bit header read turned on DEFAULT
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
I2C_BASE->CR2 &= ~I2C_CR2_ADD10; // 7 Bit addressing DEFAULT
|
|
|
I2C_BASE->CR2 |= I2C_CR2_HEAD10R; // 7 Bit header read turned off DEFAULT
|
|
|
}
|
|
|
}
|
|
|
else if(i2c_dev->mode == i2c_mode_slave)
|
|
|
{
|
|
|
// to be written.
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void i2c_set_clk_stretch(i2c_t *i2c_dev, i2c_clk_stretching_t stretching)
|
|
|
{
|
|
|
if(i2c_dev->stretching == i2c_clk_stretching_enable)
|
|
|
{
|
|
|
I2C_BASE->CR1 &=~ I2C_CR1_NOSTRETCH;
|
|
|
}
|
|
|
else if(i2c_dev->stretching == i2c_clk_stretching_disable)
|
|
|
{
|
|
|
I2C_BASE->CR1 |= I2C_CR1_NOSTRETCH;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void i2c_set_clk_speed(i2c_t *i2c_dev, i2c_clk_speed_t speed)
|
|
|
{
|
|
|
switch(speed)
|
|
|
{
|
|
|
case i2c_clk_speed_standart:
|
|
|
I2C_BASE->TIMINGR = 0x2000090E;
|
|
|
break;
|
|
|
|
|
|
case i2c_clk_speed_fast:
|
|
|
break;
|
|
|
|
|
|
case i2c_clk_speed_fastPlus:
|
|
|
break;
|
|
|
|
|
|
case i2c_clk_speed_hightSpeed:
|
|
|
break;
|
|
|
|
|
|
case i2c_clk_speed_ultraFast:
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void i2c_set_filter(i2c_t *i2c_dev, uint8_t enable)
|
|
|
{
|
|
|
if(enable)
|
|
|
{
|
|
|
//Anlalog filter is on
|
|
|
I2C_BASE->CR1 &= ~I2C_CR1_ANFOFF;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
//Anlalog filter is off
|
|
|
I2C_BASE->CR1 |= I2C_CR1_ANFOFF;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**************************************************************************************************
|
|
|
I2C Hardware functions
|
|
|
***************************************************************************************************/
|
|
|
void i2c_send_start(i2c_t *i2c_dev)
|
|
|
{
|
|
|
I2C_BASE->CR2 &=~ I2C_CR2_STOP;
|
|
|
I2C_BASE->CR2 |= I2C_CR2_START;
|
|
|
|
|
|
//Wait until the start condition in generated.
|
|
|
//Bit 15BUSY: Bus busy
|
|
|
//This flag indicates that a communication is in progress on the bus. It is set by hardware when a
|
|
|
//START condition is detected. It is cleared by hardware when a Stop condition is detected, or
|
|
|
//when PE=0.
|
|
|
while(!(I2C_BASE->ISR & (I2C_ISR_BUSY)));
|
|
|
|
|
|
i2c_dev->hardwareState = i2c_hw_sent_start;
|
|
|
}
|
|
|
|
|
|
void i2c_send_stop(i2c_t *i2c_dev)
|
|
|
{
|
|
|
// Send stop command
|
|
|
I2C_BASE->CR2 |= I2C_CR2_STOP;
|
|
|
I2C_BASE->CR2 &=~ I2C_CR2_START;
|
|
|
i2c_dev->hardwareState = i2c_hw_sent_stop;
|
|
|
}
|
|
|
|
|
|
uint8_t i2c_is_perif_ready(i2c_t *i2c_dev)
|
|
|
{
|
|
|
if((I2C_BASE->ISR & (I2C_ISR_BUSY))!=I2C_ISR_BUSY)
|
|
|
{
|
|
|
i2c_dev->periferalState = i2c_perif_ready;
|
|
|
return 1;
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
void i2c_set_transfer_counter(i2c_t *i2c_dev, uint8_t count)
|
|
|
{
|
|
|
I2C_BASE->CR2 &= ~(0xFF << I2C_CR2_NBYTES_Pos);
|
|
|
I2C_BASE->CR2 |= (count << I2C_CR2_NBYTES_Pos);
|
|
|
}
|
|
|
|
|
|
uint8_t i2c_get_transfer_counter(i2c_t *i2c_dev)
|
|
|
{
|
|
|
return (I2C_BASE->CR2 & I2C_CR2_NBYTES) >> I2C_CR2_NBYTES_Pos;
|
|
|
}
|
|
|
|
|
|
void i2c_init_write_command(i2c_t *i2c_dev)
|
|
|
{
|
|
|
I2C_BASE->CR2 &= ~I2C_CR2_RD_WRN;
|
|
|
i2c_dev->hardwareState = i2c_hw_send_write;
|
|
|
}
|
|
|
|
|
|
void i2c_init_read_command(i2c_t *i2c_dev)
|
|
|
{
|
|
|
I2C_BASE->CR2 |= I2C_CR2_RD_WRN;
|
|
|
i2c_dev->hardwareState =i2c_hw_send_read;
|
|
|
}
|
|
|
|
|
|
|
|
|
uint8_t i2c_send_address_for_write(i2c_t *i2c_dev, uint16_t *slaveAddress)
|
|
|
{
|
|
|
//Automatic end mode (master mode) disabled Enablede as default
|
|
|
I2C_BASE->CR2 &= ~I2C_CR2_AUTOEND;
|
|
|
|
|
|
// On This chip this shoudl be done before the start condition
|
|
|
i2c_init_write_command(i2c_dev);
|
|
|
|
|
|
// The Slave addrress is automatically place on the output buffer (must be done before the start condition)
|
|
|
I2C_BASE->CR2 |= (*slaveAddress & 0xff) << 1; // The bit no 0 is not taken in concideration in 7bit mode
|
|
|
|
|
|
// This device places the salve address automaticaly in the output buffer before sending the star condition
|
|
|
i2c_send_start(i2c_dev);
|
|
|
while(i2c_is_output_buffer_full(i2c_dev));
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
uint8_t i2c_send_address_for_read(i2c_t *i2c_dev, uint16_t *slaveAddress)
|
|
|
{
|
|
|
// On This chip this shoudl be done before the start condition
|
|
|
i2c_init_read_command(i2c_dev);
|
|
|
|
|
|
// The Slave addrress is automatically place on the output buffer (must be done before the start condition)
|
|
|
I2C_BASE->CR2 |= (*slaveAddress & 0xff) << 1; // The bit no 0 is not taken in concideration in 7bit mode
|
|
|
// This device places the salve address automaticaly in the output buffer before sending the star condition
|
|
|
i2c_send_start(i2c_dev);
|
|
|
while(i2c_is_output_buffer_full(i2c_dev));
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
uint8_t i2c_is_output_buffer_full(i2c_t *i2c_dev)
|
|
|
{
|
|
|
/*
|
|
|
Bit 0 TXE: Transmit data register empty (transmitters)
|
|
|
This bit is set by hardware when the I2C_TXDR register is empty. It is cleared when the next
|
|
|
data to be sent is written in the I2C_TXDR register.
|
|
|
This bit can be written to ‘1’ by software in order to flush the transmit data register I2C_TXDR.
|
|
|
Note: This bit is set by hardware when PE=0.
|
|
|
*/
|
|
|
if(I2C_BASE->ISR & I2C_ISR_TXE)
|
|
|
{
|
|
|
i2c_dev->hardwareState = i2c_hw_out_buff_empty;
|
|
|
return 0;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
i2c_dev->hardwareState = i2c_hw_out_buff_full;
|
|
|
return 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
uint8_t i2c_is_txis(i2c_t *i2c_dev)
|
|
|
{
|
|
|
if(I2C_BASE->ISR & I2C_ISR_TXIS)
|
|
|
{
|
|
|
i2c_dev->hardwareState = i2c_hw_out_buff_empty;
|
|
|
return 0;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
i2c_dev->hardwareState = i2c_hw_out_buff_full;
|
|
|
return 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void i2c_send_reg_address(i2c_t *i2c_dev, uint8_t *registerAddress)
|
|
|
{
|
|
|
I2C_BASE->TXDR = *registerAddress;
|
|
|
i2c_dev->hardwareState = i2c_hw_out_buff_full;
|
|
|
while(i2c_is_output_buffer_full(i2c_dev));
|
|
|
}
|
|
|
|
|
|
void i2c_send_data(i2c_t *i2c_dev, uint8_t *data)
|
|
|
{
|
|
|
I2C_BASE->TXDR = *data;
|
|
|
i2c_dev->hardwareState = i2c_hw_out_buff_full;
|
|
|
while(i2c_is_output_buffer_full(i2c_dev));
|
|
|
}
|
|
|
|
|
|
uint8_t i2c_is_transfer_complete(i2c_t *i2c_dev)
|
|
|
{
|
|
|
/*
|
|
|
TC: Transfer Complete (master mode)
|
|
|
This flag is set by hardware when RELOAD=0, AUTOEND=0 and NBYTES data have been
|
|
|
transferred. It is cleared by software when START bit or STOP bit is set.
|
|
|
Note: This bit is cleared by hardware when PE=0.
|
|
|
*/
|
|
|
if(I2C_BASE->ISR & I2C_ISR_TC)
|
|
|
{
|
|
|
return 1;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
uint8_t i2c_is_input_buffer_full(i2c_t *i2c_dev)
|
|
|
{
|
|
|
if(I2C_BASE->ISR & I2C_ISR_RXNE)
|
|
|
{
|
|
|
i2c_dev->hardwareState = i2c_hw_in_buff_full;
|
|
|
return 1;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
i2c_dev->hardwareState = i2c_hw_in_buff_empty;
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void i2c_get_input_register(i2c_t *i2c_dev, uint8_t *data)
|
|
|
{
|
|
|
while(!i2c_is_input_buffer_full(i2c_dev));
|
|
|
*data = I2C_BASE->RXDR;
|
|
|
while(!i2c_is_transfer_complete(i2c_dev));
|
|
|
}
|
|
|
|
|
|
void i2c_send_nack(i2c_t *i2c_dev)
|
|
|
{
|
|
|
if(i2c_dev->mode == i2c_mode_master)
|
|
|
{
|
|
|
//IN master mode this ic geretes NACK's otomatically
|
|
|
i2c_dev->hardwareState = i2c_hw_sent_nack;
|
|
|
}
|
|
|
else if(i2c_dev->mode == i2c_mode_slave)
|
|
|
{
|
|
|
// to be written.
|
|
|
}
|
|
|
}
|
|
|
|
|
|
uint8_t i2c_check_nack(i2c_t *i2c_dev)
|
|
|
{
|
|
|
delayMs(2);
|
|
|
return(I2C_BASE->ISR & I2C_ISR_NACKF);
|
|
|
}
|
|
|
|
|
|
void i2c_set_address(i2c_t *i2c_dev, uint16_t address){}
|
|
|
void i2c_set_address_second(i2c_t *i2c_dev, uint16_t address){}
|
|
|
|