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/peripherals/i2c.h

525 lines
23 KiB

/**
**************************************************************************************************
* @file i2c.h
* @author Kerem Yollu & Edwin Koch
* @date 16.02.2023
* @version 1.2
**************************************************************************************************
* @brief I2C communitation based on the Standart I2C Protocol V7 Defined by NXP/Philips :
* following third Party Protocols based on I2C Bus are not going to be implemented : C-BUS SMBUS PMBUS IPMI DDC ATCA
* This will also not have a I3C support for the forseable futrue.
*
* **Detailed Description :**
*
* I2C communitation based on the Standart I2C Protocol V7 Defined by NXP/Philips :
* following third Party Protocols based on I2C Bus are not going to be implemented : C-BUS SMBUS PMBUS IPMI DDC ATCA
* This will also not have a I3C support for the forseable futrue.
*
* @todo
* - 26.07.2021 : Implement DMA
* - 26.07.2021 : Implement Interrupt
* - 26.07.2021 : Implement Sleep/WakeUp
* - 26.07.2021 : Implement Slave opperation
**************************************************************************************************
*/
#ifndef _I2C_H_
#define _I2C_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "pin.h"
#include "hwd_i2c.h"
/*! Enum of possible I2C opperation modes */
typedef enum{
i2c_mode_master, /*!< Master mode : In Master mode, the I2C interface initiates
a data transfer and generates the clock signal. **DEFAULT** */
i2c_mode_multyMaster, /*!< Multimaster Mode : In case if more than one master are present
in one I2C bus. In such case each device needs to be able to
cooperate knowing that another device could talking
therefore the bus is busy (Arbirtation).
For More information : https://www.i2c-bus.org/multimaster/ */
i2c_mode_slave /*!< Slave mode : A slave device has to always be ready to detect and
process a start condition and to recognize its address */
}i2c_mode_t;
/*! Enum of possible I2C speeds */
typedef enum{
i2c_clk_speed_standart, /*!< SM 100 kbits/s Standart i2c Speed **DEFAULT** */
i2c_clk_speed_fast, /*!< FM 400 kbits/s */
i2c_clk_speed_fastPlus, /*!< FM+ 1 Mbits/s */
i2c_clk_speed_hightSpeed, /*!< HS 3.4 Mbits/s */
i2c_clk_speed_ultraFast /*!< UFM 5 Mbits/s */
}i2c_clk_speed_t;
/*! Enum of possible I2C Adress sizes */
typedef enum{
i2c_address_size_7b, /*!< 7 Bits address size **DEFAULT** */
i2c_address_size_10b /*!< 10 Bits address size */
}i2c_address_size_t;
/*! Enum of possible I2C Address count */
typedef enum{
i2c_address_count_single, /*!< Only one address for communication **DEFAULT** */
i2c_address_count_dual /*!< Dual addresses for one device respondng to two addresses */
}i2c_address_count_t;
/*! Enum for clock strechning activation. Can only be implmented as Slave
* for more information : https://www.i2c-bus.org/clock-stretching/ */
typedef enum{
i2c_clk_stretching_disable, /*!< We assume that the master and slave have compatible
Clock frequencies **DEFAULT** */
i2c_clk_stretching_enable /*!< In situations where an I2C slave is not able to co-operate
with the clock speed given by the master and needs to slow down.
This is done by a mechanism referred to as clock stretching. */
}i2c_clk_stretching_t;
/*! Enum for diffenrent wake up methodes wehnin sleep mode */
typedef enum{
i2c_wake_disabled, /*!< No wake up is possible this is the default mode also means that
the sleep function is not implmentes **DEFAULT** */
i2c_wakeUp_address_match /*!< Wakes up on address match, this can be harware dependent */
}i2c_wake_types_t;
/*! typedef for the i2c states*/
typedef enum
{
i2c_hw_disabled, /*!< Hardware Is Disabled */
i2c_hw_reset, /*!< Hardware Is Reseted and in reset mode and need to be initialised */
i2c_hw_enabled, /*!< I2C Hardware is initilized but not neceserly ready */
i2c_hw_ready, /*!< Hardware Initialized and ready for use */
i2c_hw_sent_start, /*!< Generated the star condition */
i2c_hw_out_buff_full, /*!< The output buffer of the I2C Periferal is Full */
i2c_hw_out_buff_empty, /*!< The output buffer of the I2C Periferal is Empty */
i2c_hw_in_buff_full, /*!< The input buffer of the I2C Periferal Is Full */
i2c_hw_in_buff_empty, /*!< The input buffer of the I2C Periferal Is Empty */
i2c_hw_send_read, /*!< Sent read request */
i2c_hw_send_write, /*!< Sent write request */
i2c_hw_got_ack, /*!< Recieved ACK */
i2c_hw_got_nack, /*!< Recieved NACK */
i2c_hw_sent_ack, /*!< Sent ACK */
i2c_hw_sent_nack, /*!< Sent NACK */
i2c_hw_sent_stop, /*!< Generated the star condition */
i2c_hw_error /*!< Error */
} i2c_hw_state_t;
typedef enum
{
i2c_perif_disabled, /*!< Peripheral Is Disabled */
i2c_perif_reset, /*!< Peripheral Is Reseted and in reset mode and need to be initialised */
i2c_perif_enabled, /*!< I2C CHannle is initilized but not neceserly ready */
i2c_perif_ready, /*!< Peripheral Initialized and ready for use */
i2c_perif_address_sent, /*!< The Salve Address Was Sent to the bus */
i2c_perif_write, /*!< The prefiferal is configured for a write */
i2c_perif_read, /*!< The prefiferal is configured for a read */
i2c_perif_rx_ongoing, /*!< Recieving from the bus */
i2c_perif_rx_done, /*!< Recived everything from the bus */
i2c_perif_listening, /*!< Address Listen Mode is ongoing */
i2c_perif_listening_and_tx, /*!< Address Listen Mode and ongoing Data Transmission */
i2c_perif_listening_and_rx, /*!< Address Listen Mode and ongoing Data Reception */
i2c_perif_discovery, /*!< Discovery mode will cancel some error in order to be able to discover the devices on the bus */
i2c_perif_timeout, /*!< Timeout state */
i2c_perif_Error /*!< Error */
} i2c_perif_state_t;
/*! Struture a an i2c channel with all the required propereties*/
typedef struct i2c_t
{
i2cCh_t channelNo; /*!< The harware channel to be used */
i2c_mode_t mode; /*!< Master, Slave or Multymaster Modes */
uint16_t mainAddress; /*!< First and Main address of the device */
uint16_t secondAddress; /*!< Second address if dual addresse mode is configured */
i2c_address_count_t addressCount; /*!< Single or multiple */
i2c_address_size_t addressSize; /*!< 10 or 7 bit address size */
i2c_clk_speed_t speed; /*!< Bus Speed */
i2c_clk_stretching_t stretching; /*!< Clock Stretching enable only in slave mode */
i2c_wake_types_t wakeOn; /*!< Define on which type of action the i2c channel should
wake up. Only if de prefiral goes to sleep */
i2c_hw_state_t hardwareState; /*!< The current sitate of the I2C Bus */
i2c_perif_state_t periferalState; /*!< The current sitate of the I2C Bus */
}i2c_t;
/***************************************************************************************************
I2C Configuration functions
***************************************************************************************************/
/**
* @brief Initilize the I2C Hardware
* @param i2c_dev is the beforehand declared i2c channel.
*/
void i2c_init(i2c_t *i2c_dev); /*!< Pointer to I2C hardware Object */
/**
* @brief De-Initilise the I2C Hardware
* @param i2c_dev is the beforehand declared i2c channel.
*/
void i2c_deinitialise(i2c_t *i2c_dev);
/**
* @brief Set the i2c channel to master, slave or mutymaster modes
* @param Channel is the i2c hardware channel
* @param mode The mode for i2c : Master Slave or Multymaster
*/
void i2c_set_mode(i2c_t *i2c_dev, i2c_mode_t mode);
/**
* @brief Set the i2c channel's address
* @param i2c_dev is the i2c hardware channel
* @param address is the desired address for the device
*/
void i2c_set_address(i2c_t *i2c_dev, uint16_t address);
/**
* @brief Set the i2c channel's second address if the hardware allows it
* @param i2c_dev is the i2c hardware channel
* @param address The second address
*/
void i2c_set_address_second(i2c_t *i2c_dev, uint16_t address);
/**
* @brief Set the i2c Address Lenght to 7 or 10 bits, Master or Slave doesn't make any difference
* @param i2c_dev is the i2c hardware channel
* @param size Is the Adress isze to be used 7 Bit or 10 Bit
*/
void i2c_set_address_lenght(i2c_t *i2c_dev, i2c_address_size_t size);
/**
* @brief Stets the Communication speed
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param speed the different awailable speeds
*/
void i2c_set_clk_speed(i2c_t *i2c_dev, i2c_clk_speed_t speed);
/**
* @brief Ebales or disables clock stretching functionalities
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param The value to be written in the register. This will heavily depend on the hardware
*/
void i2c_set_clk_stretch(i2c_t *i2c_dev, i2c_clk_stretching_t stretching);
/**
* @brief Set the wakeup mode
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param wake the desider wakeup mode for now i have found only one mode.
*/
void i2c_set_wakeup(i2c_t *i2c_dev, i2c_wake_types_t wake);
/**
* @brief Configures Hardware implmente filters if there are any.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_set_filter(i2c_t *i2c_dev, uint8_t enable);
/**
* @brief Set the timeout to close the i2c wait time if a communication fails.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param timeout the desider timeout duration in ticks.
*/
void i2c_set_timeout(i2c_t *i2c_dev, uint8_t timeout);
/**
* @brief Resets the i2c Harware and register to it's factory deflauts.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_hardware_reset(i2c_t *i2c_dev);
/**
* @brief Enables I2C Hardware BUS & Clock & Pins
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_hardware_enable(i2c_t *i2c_dev);
/**
* @brief Disables I2C Hardware.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_hardware_disable(i2c_t *i2c_dev);
/**
* @brief Resets the i2c Periferal to it's inital state.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_periferal_reset(i2c_t *i2c_dev);
/**
* @brief Enables I2C Periferal core.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_periferal_enable(i2c_t *i2c_dev);
/**
* @brief Disables I2C Periferal core.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_periferal_disable(i2c_t *i2c_dev);
/**************************************************************************************************
I2C Communication functions independen of opperating mode
***************************************************************************************************/
/**
* @brief Writes the given amount of data to the selected device. This function will
* automaticaly choose between i2cMasterSend(); or i2cSlaveSend();
* Depending if the I2C channel was initiated as slave or master.
* this function will adapt himself to the selected oppeartion mode (Polling / Int / DMA)
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param slaveAddress is the address of the device to which the read command will be sent
* @param registerAddress is the regiter to be red from the device
* @param data is the data to be written
* @param dataLenght is the total quantity of 8 bit data to be written.
*/
void i2c_write(i2c_t *i2c_dev, uint16_t *slaveAddress, uint8_t *registerAddress, uint8_t *data, uint8_t *dataLenght);
/**
* @brief Reads the given amount of data to the selected device. This function will
* automaticaly choose between i2cMasterRecieve(); or i2cSlaveRecieve();
* Depending if the I2C channel was initiated as slave or master.
* this function will adapt himself to the selected oppeartion mode (Polling / Int / DMA)
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param slaveAddress is the address of the device to which the read command will be sent
* @param registerAddress is the regiter to be red from the device
* @param data is the data which has been red
* @paran dataLenght is the total quantity of 8 bit data to be red
*/
void i2c_read(i2c_t *i2c_dev, uint16_t *slaveAddress, uint8_t *registerAddress, uint8_t *data, uint8_t *dataLenght);
/**
* @brief Recieve a Single Byte as master from from the given devices register.
* this function will adapt himself to the selected oppeartion mode (Polling / Int / DMA)
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param slaveAddress is the address of the device to which the read command will be sent
* @param registerAddress is the regiter to be red from the device
* @param data is the data whic has been red
*/
void i2c_master_recieve(i2c_t *i2c_dev, uint16_t *slaveAddress, uint8_t *registerAddress, uint8_t *data);
/**
* @brief Sends a Single Byte as master to the given devices register.
* this function will adapt himself to the selected oppeartion mode (Polling / Int / DMA)
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param slaveAddress is the address of the device to which the send command will be sent
* @param registerAddress is the regiter to be written to the device
* @param data is the data to be sent
*/
void i2c_master_send(i2c_t *i2c_dev, uint16_t *slaveAddress, uint8_t *registerAddress, uint8_t *data);
/**
* @brief Recieve a Single Byte as slave from given devices register.
* this function will adapt himself to the selected oppeartion mode (Polling / Int / DMA)
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param slaveAddress is the address of the device to which the read command will be sent
* @param registerAddress is the regiter to be red from the device
* @param data is the data whic has been red
*/
void i2c_slave_recieve(i2c_t *i2c_dev, uint16_t *slaveAddress, uint8_t *registerAddress, uint8_t *data);
/**
* @brief Recieve a Single Byte as slave from the given devices register.
* this function will adapt himself to the selected oppeartion mode (Polling / Int / DMA)
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param slaveAddress is the address of the device to which the read command will be sent
* @param registerAddress is the regiter to be red from the device
* @param data is the data whic has been red
*/
void i2c_slave_send(i2c_t *i2c_dev, uint16_t *slaveAddress, uint8_t *registerAddress, uint8_t *data);
/**************************************************************************************************
I2C Hardware functions
***************************************************************************************************/
/**
* @brief Checks if the device is ready for any type of communication
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
uint8_t i2c_is_perif_ready(i2c_t *i2c_dev);
/**
* @brief Generates a Start condition.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_send_start(i2c_t *i2c_dev);
/**
* @brief Generates a Start condition.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_send_stop(i2c_t *i2c_dev);
/**
* @brief Generates a NACK condition.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_send_nack(i2c_t *i2c_dev);
/**
* @brief Checks If a NACK is recieved.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
uint8_t i2c_check_nack(i2c_t *i2c_dev);
/**
* @brief Generates a ACK condition.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_send_ack(i2c_t *i2c_dev);
/**
* @brief Initiates the communication by sending the slave address on the bus followed by a WRITE
* and waits for an ACK (aknowledge)
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param slaveAddress The address of the slave to be communicated
*/
uint8_t i2c_send_address_for_write(i2c_t *i2c_dev, uint16_t *slaveAddress);
/**
* @brief Initiates the communication by sending the slave address on the bus followed by a READ
* and waits for an ACK (aknowledge)
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param slaveAddress The address of the slave to be communicated
*/
uint8_t i2c_send_address_for_read(i2c_t *i2c_dev, uint16_t *slaveAddress);
/**
* @brief Sende the register adrres with which we want to communicate.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param registerAddress The register address of the slave device that we are communication with
*/
void i2c_send_reg_address(i2c_t *i2c_dev, uint8_t *registerAddress);
/**
* @brief Send the register that we want to read or write.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param registerAddress the register that need to be accessed
*/
void i2c_send_data(i2c_t *i2c_dev, uint8_t *data);
/**
* @brief Initiates a Write command with the previously set slave address.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_init_write_command(i2c_t *i2c_dev);
/**
* @brief Initiates a read command with the previously set slave address.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_init_read_command(i2c_t *i2c_dev);
/**
* @brief Is the output buffer full. This also means that there is data present in the ouput buffer
* is sent to the i2c BUS.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
uint8_t i2c_is_output_buffer_full(i2c_t *i2c_dev);
/**
* @brief Is the input buffer full. This also means that there is data present in the input buffer
* is sent to the i2c BUS.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @return 1 when input buffer is full | 0 whenthe input buffer is empty
*/
uint8_t i2c_is_input_buffer_full(i2c_t *i2c_dev);
/**
* @brief reads the I2C input buffer
* is sent to the i2c BUS.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param data pointer to the data that need to be read and returned
*/
void i2c_get_input_register(i2c_t *i2c_dev, uint8_t *data);
/**
* @brief writes to the I2C output buffer
* is sent to the i2c BUS.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param data pointer to the data that need to be read and returned
*/
void i2c_set_output_register(i2c_t *i2c_dev, uint8_t *data);
/**
* @brief Checks if transfer is complete
* is sent to the i2c BUS.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param data pointer to the data that need to be read and returned
* @return 1 when Transefer is complete | 0 When Transfer is ongoing
*/
uint8_t i2c_is_transfer_complete(i2c_t *i2c_dev);
/**
* @brief Defines the amount of transfers to be made. Address exchange and start conditon does not count
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param count amount o data to be transfered.
*/
void i2c_set_transfer_counter(i2c_t *i2c_dev, uint8_t count);
/**
* @brief Defines the amount of transfers to be made. Address exchange and start conditon does not count
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param count amount o data to be transfered.
*/
uint8_t i2c_get_transfer_counter(i2c_t *i2c_dev);
/**************************************************************************************************
I2C Arbitration Functions for Multymaster mode and slaves clock stretching
***************************************************************************************************/
void i2c_arbitrate_clk_sync(); // I2C Standart : Clock Syncronization
void i2c_arbitrate_multymaster_abort_tx(); // I2c Standart : Stop Communication for multimaster mode
void i2c_arbitrate(); // I2C Standart : Arbitration for multimaster mode to define the right master.
void i2c_arbitrate_soft_rst(); // I2C Standart : Software reset not supported by all hardware.
void i2c_arbitration_clear_bus(); // I2C Standart : in case if SCL is stuck
/**************************************************************************************************
I2C Extra functions that are not esential for the main functionality
***************************************************************************************************/
/**
* @brief This function will scan every for possible addresses to discover devices on the bus.
* And write them to the Devices list given to him. This function will not discover more
* devices than what he is told.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
uint8_t i2c_discover_devices(i2c_t *i2c_dev);
/**
* @brief This function will scan the given device to see if he responds
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param address is the address to be chekced
*/
uint8_t i2c_check_device(i2c_t *i2c_dev, uint16_t *device);
/**
* @brief This function will try to communicate with a device with every speed
* allowed by his hardware to find out the maximum communication sppeed possible.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param slaveAddress is the address of the device to which the read command will be sent
*/
i2c_clk_speed_t i2c_test_bus_speed(i2c_t *i2c_dev, uint16_t *slaveAddress);
/**
* @brief This function will read the device info register (if awailable) as follows :
* I2c Standart : 3 Bytes (24 bits) | 12 Bits : Manufacturer info | 9 Bits: Part Identification | 3 Bits DIE Rev.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
* @param slaveAddress is the address of the device to be red
*/
uint32_t i2c_get_device_info(i2c_t *i2c_dev, uint16_t *slaveAddress);
/**
* @brief The selected i2c channel is put on sleep.
* @param i2c_dev is the beforehand declared i2c channel with his opperation modes
*/
void i2c_sleep(i2c_t *i2c_dev);
/**
* @brief Error handling.
* @param error The error no generated.
*/
void i2c_throw_error(i2c_t *i2c_dev, uint8_t error);
uint8_t i2c_is_txis(i2c_t *i2c_dev);
#ifdef __cplusplus
}
#endif
#endif // _I2C_H_