You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
KED/csl/stm32f042k6t6/implementation/imp_i2c.c

336 lines
8.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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){}