/** * @file * @brief Contains source code of i2c_drv.h. */ #include "xc.h" #include "i2c_drv.h" //----------------------------------------------------------------------------// //private constants-----------------------------------------------------------// //----------------------------------------------------------------------------// /* * @version : 1.0 * @description : Holds values to en-/disable i2c1 hardware. */ enum { I2C_DRV_ENABLE = 1, I2C_DRV_DISABLE = 0, } i2c_drv_enable; /* * @version : 1.0 * @description : Holds values to trigger i2c1 start sequence. */ enum { I2C_DRV_ENABLE_START = 1, I2C_DRV_DISABLE_START = 0, } i2c_drv_start_enable; /* * @version : 1.0 * @description : Holds values to trigger i2c1 restart sequence. */ enum { I2C_DRV_ENABLE_RESTART = 1, I2C_DRV_DISABLE_RESTART = 0, } i2c_drv_restart_enable; /* * @version : 1.0 * @description : Holds values to trigger i2c1 stop sequence. */ enum { I2C_DRV_ENABLE_STOP = 1, I2C_DRV_DISABLE_STOP = 0, } i2c_drv_stop_enable; /* * @version : 1.0 * @description : Holds values to indicate which acknowledge was received. */ enum { I2C_DRV_GET_NACK = 1, I2C_DRV_GET_ACK = 0, } i2c_drv_nack_ack_get; /* * @version : 1.0 * @description : Holds values to choose which acknowledge will be send * during acknowledge sequence. */ enum { I2C_DRV_SET_NACK = 1, I2C_DRV_SET_ACK = 0, } i2c_drv_nack_ack_set; /* * @version : 1.0 * @description : Holds values to trigger i2c1 ack sequence. */ enum { I2C_DRV_ENABLE_ACK = 1, I2C_DRV_DISABLE_ACK = 0, } i2c_drv_ack_enable; /* * @version : 1.0 * @description : Holds values to trigger i2c1 nack sequence. */ enum { I2C_DRV_ENABLE_NACK = 1, I2C_DRV_DISABLE_NACK = 0, } i2c_drv_nack_enable; /* * @version : 1.0 * @description : Holds values to check if i2c1 transmission is finished. */ enum { I2C_DRV_TRANSMIT_DONE = 0, I2C_DRV_TRANSMIT_DOING = 1, } i2c_drv_transmit_done; /* * @version : 1.0 * @description : Holds values to check if i2c1 receive buffer is full. */ enum { I2C_DRV_RECEIVE_BUF_FULL = 1, I2C_DRV_RECEIVE_BUF_EMPTY = 0, } i2c_drv_receive_buf; /* * @version : 1.0 * @description : Holds values to trigger i2c1 receiving sequence. */ enum { I2C_DRV_RECEIVE_ENABLE = 1, I2C_DRV_RECEIVE_DISABLE = 0, } i2c_drv_receive_enable; /* * @version : 1.0 * @description : Holds values to check if i2c1 transmit buffer is full. */ enum { I2C_DRV_TRANSMIT_BUF_FULL = 1, I2C_DRV_TRANSMIT_BUF_EMPTY = 0, } i2c_drv_transmit_buf; //----------------------------------------------------------------------------// //private data----------------------------------------------------------------// //----------------------------------------------------------------------------// //----------------------------------------------------------------------------// //private function declarations-----------------------------------------------// //----------------------------------------------------------------------------// //----------------------------------------------------------------------------// //private function definitions------------------------------------------------// //----------------------------------------------------------------------------// //----------------------------------------------------------------------------// //public functions------------------------------------------------------------// //----------------------------------------------------------------------------// exit_state i2c_drv_init(void) { //init i2c module I2C1CON = 0x1000; //reset I2C1 controle register I2C1CONbits.SIDL = ENABLE; //turn of in idle I2C1CONbits.ON = DISABLE; //turn off I2C1 for safety I2C1CONbits.DISSLW = TRUE; // Disable slew rate for 100kHz I2C1BRG = 110; //sets SCL frequency to 100kHz I2C1CONbits.ON = ENABLE; return EXIT_SUCCESS; } exit_state i2c_drv_deinit(void) { I2C1CONbits.I2CEN = I2C_DRV_DISABLE; return EXIT_SUCCESS; } //start-----------------------------------------------------------------------// exit_state i2c_drv_tx_start(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } I2C1CONbits.SEN = SET; return EXIT_SUCCESS; } exit_state i2c_drv_tx_start_handler(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } if (I2C1CONbits.SEN == CLEAR) { return EXIT_SUCCESS; } return EXIT_FAILURE; } //restart---------------------------------------------------------------------// exit_state i2c_drv_tx_restart(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } I2C1CONbits.RSEN = I2C_DRV_ENABLE_RESTART; return EXIT_SUCCESS; } exit_state i2c_drv_tx_restart_handler(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } if (I2C1CONbits.RSEN == I2C_DRV_DISABLE_RESTART) { return EXIT_SUCCESS; } return EXIT_FAILURE; } //stop------------------------------------------------------------------------// exit_state i2c_drv_tx_stop(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } I2C1CONbits.PEN = I2C_DRV_ENABLE_STOP; return EXIT_SUCCESS; } exit_state i2c_drv_tx_stop_handler(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } if (I2C1CONbits.PEN == I2C_DRV_DISABLE_STOP) { return EXIT_SUCCESS; } return EXIT_FAILURE; } //ack-------------------------------------------------------------------------// //set exit_state i2c_drv_tx_ack(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } I2C1CONbits.ACKDT = I2C_DRV_SET_ACK; I2C1CONbits.ACKEN = I2C_DRV_ENABLE_ACK; return EXIT_SUCCESS; } exit_state i2c_drv_tx_ack_handler(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } if (I2C1CONbits.ACKEN == I2C_DRV_DISABLE_ACK) { return EXIT_SUCCESS; } return EXIT_FAILURE; } //get exit_state i2c_drv_rx_ack(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } if (I2C1STATbits.ACKSTAT == I2C_DRV_GET_ACK) { return EXIT_SUCCESS; } return EXIT_FAILURE; } exit_state i2c_drv_rx_ack_handler(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } if (I2C1STATbits.TRSTAT == I2C_DRV_TRANSMIT_DONE) { return EXIT_SUCCESS; } return EXIT_FAILURE; } //nack------------------------------------------------------------------------// //Set exit_state i2c_drv_tx_nack(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } I2C1CONbits.ACKDT = I2C_DRV_SET_NACK; I2C1CONbits.ACKEN = I2C_DRV_ENABLE_NACK; return EXIT_SUCCESS; } exit_state i2c_drv_tx_nack_handler(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } if (I2C1CONbits.ACKEN == I2C_DRV_DISABLE_NACK) { return EXIT_SUCCESS; } return EXIT_FAILURE; } //get exit_state i2c_drv_rx_nack(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } if (I2C1STATbits.ACKSTAT == I2C_DRV_GET_NACK) { return EXIT_SUCCESS; } return EXIT_FAILURE; } exit_state i2c_drv_rx_nack_handler(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } if (I2C1STATbits.TRSTAT == I2C_DRV_TRANSMIT_DONE) { return EXIT_SUCCESS; } return EXIT_FAILURE; } //transmit--------------------------------------------------------------------// /** * @todo rewrite code to use ringbuffer.h */ exit_state i2c_drv_tx_data(uint8_t data) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } I2C1TRN = data; return EXIT_SUCCESS; } exit_state i2c_drv_tx_data_handler(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } if (I2C1STATbits.TBF == I2C_DRV_TRANSMIT_BUF_EMPTY) { return EXIT_SUCCESS; } return EXIT_FAILURE; } //receive---------------------------------------------------------------------// /** * @bug Get caught in infty loop and breaks up message transmission */ exit_state i2c_drv_rx_data(uint8_t* data) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } *data = I2C1RCV; } exit_state i2c_drv_rx_data_handler(void) { if (i2c_drv_module_check() == EXIT_FAILURE) { return EXIT_FAILURE; } static int rcen_flag = CLEAR; if (I2C1STATbits.RBF == I2C_DRV_RECEIVE_BUF_EMPTY && rcen_flag == CLEAR) { rcen_flag = SET; I2C1CONbits.RCEN = I2C_DRV_RECEIVE_ENABLE; return EXIT_FAILURE; } if (I2C1STATbits.RBF == I2C_DRV_RECEIVE_BUF_FULL && rcen_flag == SET) { rcen_flag = CLEAR; return EXIT_SUCCESS; } return EXIT_FAILURE; //buffer is not empty, read data from I2C1RCV first } //error management------------------------------------------------------------// exit_state i2c_drv_module_check(void) { if (i2c_drv_error_check() == EXIT_FAILURE) { return EXIT_FAILURE; } if (i2c_drv_busy_check() == EXIT_FAILURE) { return EXIT_FAILURE; } return EXIT_SUCCESS; } exit_state i2c_drv_error_check(void) { if ( IFS3bits.I2C1BIF == SET || I2C1STATbits.IWCOL == SET || I2C1STATbits.BCL == SET || I2C1STATbits.I2COV == SET ) { //any bus collision occured return EXIT_FAILURE; } return EXIT_SUCCESS; } exit_state i2c_drv_busy_check(void) { //according to datasheet no write to 5 lsb of I2C1CON allowed when atleast //one ist set if ( I2C1CONbits.SEN == SET || I2C1CONbits.RSEN == SET || I2C1CONbits.PEN == SET || I2C1CONbits.RCEN == SET || I2C1CONbits.ACKEN == SET || I2C1STATbits.TRSTAT == SET || IFS3bits.I2C1MIF == SET //check if master interrupt is cleared (set by finishing any master event) || IFS3bits.I2C1SIF == SET //check if slave interrupt is cleared (set by receiving any slave event) ) { IFS3bits.I2C1MIF = CLEAR; IFS3bits.I2C1SIF = CLEAR; return EXIT_FAILURE; } return EXIT_SUCCESS; }