2021-07-21 23:33:29 +02:00
/** library to communicate using I²C as master
* @ file
* @ author King Kévin < kingkevin @ cuvoodoo . info >
* @ copyright SPDX - License - Identifier : GPL - 3.0 - or - later
* @ date 2017 - 2021
* @ note the I ² C peripheral is not well specified and does not cover all cases . The following complexity is the best I could do to cope with it
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdbool.h> // boolean types
# include <stdlib.h> // general utilities
/* own libraries */
# include "stm8s.h" // STM8S definitions
# include "i2c_master.h" // I²C header and definitions
2021-08-16 13:21:14 +02:00
bool i2c_master_setup ( uint16_t freq_khz )
2021-07-21 23:33:29 +02:00
{
// configure I²C peripheral
2021-08-16 13:21:14 +02:00
I2C_CR1 & = ~ I2C_CR1_PE ; // disable I²C peripheral to configure it
/*
2021-07-21 23:33:29 +02:00
if ( ! i2c_master_check_signals ( ) ) { // check the signal lines
return false ;
}
2021-08-16 13:21:14 +02:00
*/
2021-07-21 23:33:29 +02:00
I2C_FREQR = 16 ; // the peripheral frequency (must match CPU frequency)
2021-08-16 13:21:14 +02:00
if ( freq_khz > 100 ) {
uint16_t ccr = ( I2C_FREQR * 1000 ) / ( 3 * freq_khz ) ;
if ( ccr > 0x0fff ) {
ccr = 0x0fff ;
}
I2C_CCRL = ( ccr & 0xff ) ; // set SCL at 320 kHz (for less error)
I2C_CCRH = ( ( ccr > > 8 ) & 0x0f ) | ( I2C_CCRH_FS ) ; // set fast speed mode
I2C_TRISER = ( ( I2C_FREQR * 3 / 10 ) + 1 ) ; // set rise time
2021-07-21 23:33:29 +02:00
} else {
2021-08-16 13:21:14 +02:00
uint16_t ccr = ( I2C_FREQR * 1000 ) / ( 2 * freq_khz ) ;
if ( ccr > 0x0fff ) {
ccr = 0x0fff ;
}
I2C_CCRL = ( ccr & 0xff ) ; // set SCL at 320 kHz (for less error)
I2C_CCRH = ( ( ccr > > 8 ) & 0x0f ) ; // set fast speed mode
I2C_TRISER = ( I2C_FREQR + 1 ) ; // set rise time
2021-07-21 23:33:29 +02:00
}
I2C_CR1 | = I2C_CR1_PE ; // enable I²C peripheral
return true ;
}
void i2c_master_release ( void )
{
I2C_CR1 & = ~ I2C_CR1_PE ; // disable I²C peripheral
}
bool i2c_master_check_signals ( void )
{
i2c_master_release ( ) ; // ensure PB4/PB5 are not used as alternate function
GPIO_PB - > CR1 . reg & = ~ ( PB4 | PB5 ) ; // operate in open-drain mode
GPIO_PB - > DDR . reg | = ( PB4 | PB5 ) ; // set SCL/SDA as output to test pull-up
GPIO_PB - > ODR . reg | = PB4 ; // ensure SCL is high
GPIO_PB - > ODR . reg & = ~ PB5 ; // set SDA low (start condition)
2021-08-16 13:21:14 +02:00
for ( volatile uint8_t t = 0 ; t < 10 ; t + + ) ; // wait a bit to be sure signal is low
2021-07-21 23:33:29 +02:00
GPIO_PB - > ODR . reg | = PB5 ; // set SDA high (stop condition)
GPIO_PB - > DDR . reg & = ~ ( PB4 | PB5 ) ; // set SCL/SDA as input before it is used as alternate function by the peripheral
2021-08-16 13:21:14 +02:00
for ( volatile uint8_t t = 0 ; t < 50 ; t + + ) ; // wait 10 us for pull-up to take effect
2021-07-21 23:33:29 +02:00
return ( ( GPIO_PB - > IDR . reg & PB4 ) & & ( GPIO_PB - > IDR . reg & PB5 ) ) ; // test if both lines are up
}
void i2c_master_reset ( void )
{
I2C_CR2 | = I2C_CR2_STOP ; // release lines
// don't check if BUSY is cleared since its state might be erroneous
// rewriting I2C_CR2 before I2C_CR2_STOP is cleared might cause a second STOP, but at this point we don't care
I2C_CR2 | = I2C_CR2_SWRST ; // reset peripheral, in case we got stuck and the dog bit
2021-08-16 13:21:14 +02:00
// be sure a watchdog is present as this can take forever
2021-07-21 23:33:29 +02:00
while ( ( 0 = = ( GPIO_PB - > IDR . reg & PB4 ) & & ( 0 = = ( GPIO_PB - > IDR . reg & PB5 ) ) ) ) ; // wait for SDA/SCL line to be released
I2C_CR2 & = ~ I2C_CR2_SWRST ; // release reset
I2C_CR1 & = ~ I2C_CR1_PE ; // disable I²C peripheral to clear some bits
}
enum i2c_master_rc i2c_master_start ( void )
{
// send (re-)start condition
if ( I2C_CR2 & ( I2C_CR2_START | I2C_CR2_STOP ) ) { // ensure start or stop operations are not in progress
return I2C_MASTER_RC_START_STOP_IN_PROGESS ;
}
2021-08-16 13:21:14 +02:00
// don't check BUSY flag as this might be for a re-start
2021-07-21 23:33:29 +02:00
I2C_CR2 | = I2C_CR2_START ; // sent start condition
2021-08-16 13:21:14 +02:00
I2C_SR2 = 0 ; // clear error flags
2021-08-16 14:59:27 +02:00
rim ( ) ; // enable interrupts
2021-08-16 13:21:14 +02:00
while ( ( I2C_CR2 & I2C_CR2_START ) | | ! ( I2C_SR1 & I2C_SR1_SB ) | | ! ( I2C_SR3 & I2C_SR3_MSL ) ) { // wait until start condition has been accepted, send, and we are in aster mode
2021-08-16 16:28:10 +02:00
if ( I2C_SR2 ) {
2021-08-16 13:21:14 +02:00
return I2C_MASTER_RC_BUS_ERROR ;
}
if ( I2C_CR2 & I2C_CR2_STOP ) {
return I2C_MASTER_RC_TIMEOUT ;
}
2021-08-16 14:59:27 +02:00
I2C_ITR = ( I2C_ITR_ITEVTEN | I2C_ITR_ITERREN ) ; // enable I²C interrupts
wfi ( ) ; // got to sleep to prevent EMI causing glitches
2021-07-21 23:33:29 +02:00
}
return I2C_MASTER_RC_NONE ;
}
/** wait until stop is sent and bus is released
* @ return I ² C return code
*/
static enum i2c_master_rc i2c_master_wait_stop ( void )
{
2021-08-16 13:21:14 +02:00
I2C_SR2 = 0 ; // clear error flags
while ( I2C_CR2 & I2C_CR2_STOP ) { // wait until stop condition is accepted and cleared
2021-08-16 16:28:10 +02:00
if ( I2C_SR2 ) {
2021-08-16 13:21:14 +02:00
return I2C_MASTER_RC_BUS_ERROR ;
}
2021-08-16 16:20:44 +02:00
// there is no interrupt flag we can use here
2021-07-21 23:33:29 +02:00
}
// this time we can't use I2C_CR2_STOP to check for timeout
if ( I2C_SR3 & I2C_SR3_MSL ) { // ensure we are not in master mode anymore
return I2C_MASTER_RC_BUS_ERROR ;
}
if ( I2C_SR3 & I2C_SR3_BUSY ) { // ensure bus is released
return I2C_MASTER_RC_BUS_ERROR ;
}
2021-08-16 13:21:14 +02:00
/*
2021-07-21 23:33:29 +02:00
if ( ! i2c_master_check_signals ( ) ) { // ensure lines are released
return I2C_MASTER_RC_BUS_ERROR ;
}
2021-08-16 13:21:14 +02:00
*/
2021-07-21 23:33:29 +02:00
return I2C_MASTER_RC_NONE ;
}
enum i2c_master_rc i2c_master_stop ( void )
{
// sanity check
if ( ! ( I2C_SR3 & I2C_SR3_BUSY ) ) { // ensure bus is not already released
return I2C_MASTER_RC_NONE ; // bus has probably already been released
}
if ( I2C_CR2 & ( I2C_CR2_START | I2C_CR2_STOP ) ) { // ensure start or stop operations are not in progress
return I2C_MASTER_RC_START_STOP_IN_PROGESS ;
}
I2C_CR2 | = I2C_CR2_STOP ; // send stop to release bus
return i2c_master_wait_stop ( ) ;
}
enum i2c_master_rc i2c_master_select_slave ( uint16_t slave , bool address_10bit , bool write )
{
if ( ! ( I2C_SR1 & I2C_SR1_SB ) ) { // start condition has not been sent yet
enum i2c_master_rc rc = i2c_master_start ( ) ; // send start condition
if ( I2C_MASTER_RC_NONE ! = rc ) {
return rc ;
}
}
if ( ! ( I2C_SR3 & I2C_SR3_MSL ) ) { // I²C device is not in master mode
return I2C_MASTER_RC_NOT_MASTER ;
}
// select slave
I2C_SR2 & = ~ ( I2C_SR2_AF ) ; // clear acknowledgement failure
if ( ! address_10bit ) { // 7-bit address
I2C_DR = ( slave < < 1 ) | ( write ? 0 : 1 ) ; // select slave, with read/write flag
2021-08-16 13:21:14 +02:00
I2C_SR2 = 0 ; // clear error flags
2021-08-16 14:59:27 +02:00
rim ( ) ; // enable interrupts
2021-08-16 13:21:14 +02:00
while ( ! ( I2C_SR1 & I2C_SR1_ADDR ) ) { // wait until address is transmitted (or error)
if ( I2C_CR2 & I2C_CR2_STOP ) {
return I2C_MASTER_RC_TIMEOUT ;
}
if ( I2C_SR2 & I2C_SR2_AF ) { // address has not been acknowledged
return I2C_MASTER_RC_NAK ;
2021-08-16 16:28:10 +02:00
} else if ( I2C_SR2 ) {
return I2C_MASTER_RC_BUS_ERROR ;
2021-08-16 13:21:14 +02:00
}
2021-08-16 14:59:27 +02:00
I2C_ITR = ( I2C_ITR_ITEVTEN | I2C_ITR_ITERREN ) ; // enable relevant I²C interrupts
wfi ( ) ; // got to sleep to prevent EMI causing glitches
2021-07-21 23:33:29 +02:00
}
} else { // 10-bit address
// send first part of address
I2C_DR = 11110000 | ( ( ( slave > > 8 ) & 0x3 ) < < 1 ) ; // send first header (11110xx0, where xx are 2 MSb of slave address)
2021-08-16 13:21:14 +02:00
I2C_SR2 = 0 ; // clear error flags
2021-08-16 14:59:27 +02:00
rim ( ) ; // enable interrupts
2021-08-16 13:21:14 +02:00
while ( ! ( I2C_SR1 & I2C_SR1_ADD10 ) ) { // wait until address is transmitted (or error)
if ( I2C_CR2 & I2C_CR2_STOP ) {
return I2C_MASTER_RC_TIMEOUT ;
}
if ( I2C_SR2 & I2C_SR2_AF ) { // address has not been acknowledged
return I2C_MASTER_RC_NAK ;
2021-08-16 16:28:10 +02:00
} else if ( I2C_SR2 ) {
return I2C_MASTER_RC_BUS_ERROR ;
2021-08-16 13:21:14 +02:00
}
2021-08-16 14:59:27 +02:00
I2C_ITR = ( I2C_ITR_ITEVTEN | I2C_ITR_ITERREN ) ; // enable relevant I²C interrupts
wfi ( ) ; // got to sleep to prevent EMI causing glitches
2021-07-21 23:33:29 +02:00
}
// send second part of address
I2C_SR2 & = ~ ( I2C_SR2_AF ) ; // clear acknowledgement failure
I2C_DR = ( slave & 0xff ) ; // send remaining of address
2021-08-16 13:21:14 +02:00
I2C_SR2 = 0 ; // clear error flags
2021-08-16 14:59:27 +02:00
rim ( ) ; // enable interrupts
2021-08-16 13:21:14 +02:00
while ( ! ( I2C_SR1 & I2C_SR1_ADDR ) ) { // wait until address is transmitted (or error)
if ( I2C_CR2 & I2C_CR2_STOP ) {
return I2C_MASTER_RC_TIMEOUT ;
}
if ( I2C_SR2 & I2C_SR2_AF ) { // address has not been acknowledged
return I2C_MASTER_RC_NAK ;
2021-08-16 16:28:10 +02:00
} else if ( I2C_SR2 ) {
return I2C_MASTER_RC_BUS_ERROR ;
2021-08-16 13:21:14 +02:00
}
2021-08-16 14:59:27 +02:00
I2C_ITR = ( I2C_ITR_ITEVTEN | I2C_ITR_ITERREN ) ; // enable relevant I²C interrupts
wfi ( ) ; // got to sleep to prevent EMI causing glitches
2021-07-21 23:33:29 +02:00
}
// go into receive mode if necessary
if ( ! write ) {
enum i2c_master_rc rc = i2c_master_start ( ) ; // send start condition
if ( I2C_MASTER_RC_NONE ! = rc ) {
return rc ;
}
// send first part of address with receive flag
I2C_SR2 & = ~ ( I2C_SR2_AF ) ; // clear acknowledgement failure
I2C_DR = 11110001 | ( ( ( slave > > 8 ) & 0x3 ) < < 1 ) ; // send header (11110xx1, where xx are 2 MSb of slave address)
2021-08-16 13:21:14 +02:00
I2C_SR2 = 0 ; // clear error flags
while ( ! ( I2C_SR1 & I2C_SR1_ADDR ) ) { // wait until address is transmitted (or error)
if ( I2C_CR2 & I2C_CR2_STOP ) {
return I2C_MASTER_RC_TIMEOUT ;
}
if ( I2C_SR2 & I2C_SR2_AF ) { // address has not been acknowledged
return I2C_MASTER_RC_NAK ;
2021-08-16 16:28:10 +02:00
} else if ( I2C_SR2 ) {
return I2C_MASTER_RC_BUS_ERROR ;
2021-08-16 13:21:14 +02:00
}
2021-08-16 14:59:27 +02:00
I2C_ITR = ( I2C_ITR_ITEVTEN | I2C_ITR_ITERREN ) ; // enable relevant I²C interrupts
wfi ( ) ; // got to sleep to prevent EMI causing glitches
2021-07-21 23:33:29 +02:00
}
}
}
2021-08-16 13:21:14 +02:00
// I2C_SR3_TRA should be set after I2C_SR1_ADDR is cleared (end of address transmission), but this is not the case and the TRM/errata does not provide more info
2021-07-21 23:33:29 +02:00
// verify if we are in the right mode
2021-08-16 13:21:14 +02:00
// final check
2021-07-21 23:33:29 +02:00
if ( write & & ! ( I2C_SR3 & I2C_SR3_TRA ) ) {
return I2C_MASTER_RC_NOT_TRANSMIT ;
} else if ( ! write & & ( I2C_SR3 & I2C_SR3_TRA ) ) {
return I2C_MASTER_RC_NOT_RECEIVE ;
}
return I2C_MASTER_RC_NONE ;
}
enum i2c_master_rc i2c_master_read ( uint8_t * data , uint16_t data_size )
{
if ( NULL = = data | | 0 = = data_size ) { // no data to read
return I2C_MASTER_RC_OTHER ; // we indicate an error because we don't send a stop
}
if ( ! ( I2C_SR3 & I2C_SR3_MSL ) ) { // I²C device is not in master mode
return I2C_MASTER_RC_NOT_MASTER ;
}
// we can't check if the address phase it over since ADDR has been cleared when checking for mode
if ( I2C_SR3 & I2C_SR3_TRA ) { // ensure we are in receive mode
return I2C_MASTER_RC_NOT_RECEIVE ;
}
// read data
2021-08-16 13:21:14 +02:00
I2C_CR2 | = I2C_CR2_ACK ; // enable ACK by default
I2C_SR2 = 0 ; // clear error flags
2021-08-16 14:59:27 +02:00
rim ( ) ; // enable interrupts
2021-07-21 23:33:29 +02:00
for ( uint16_t i = 0 ; i < data_size ; i + + ) { // read bytes
2021-08-16 13:21:14 +02:00
IWDG - > KR . fields . KEY = IWDG_KR_KEY_REFRESH ; // reset watchdog
2021-07-21 23:33:29 +02:00
// set (N)ACK (EV6_3, EV6_1)
2021-08-16 13:21:14 +02:00
if ( 1 = = ( data_size - i ) ) { // prepare to sent NACK for last byte
2021-07-21 23:33:29 +02:00
I2C_CR2 & = ~ ( I2C_CR2_ACK ) ; // disable ACK
I2C_CR2 | = I2C_CR2_STOP ; // prepare to send the stop
}
2021-08-16 14:59:27 +02:00
rim ( ) ; // enable interrupts
2021-08-16 13:21:14 +02:00
while ( ! ( I2C_SR1 & I2C_SR1_RXNE ) ) { // wait until data is received (or error)
2021-08-16 16:28:10 +02:00
if ( I2C_SR2 ) { // an error occurred
2021-08-16 13:21:14 +02:00
return I2C_MASTER_RC_BUS_ERROR ;
}
2021-08-16 14:59:27 +02:00
I2C_ITR = ( I2C_ITR_ITBUFEN | I2C_ITR_ITEVTEN | I2C_ITR_ITERREN ) ; // enable all I²C interrupts
wfi ( ) ; // got to sleep to prevent EMI causing glitches
2021-07-21 23:33:29 +02:00
}
data [ i ] = I2C_DR ; // read the received byte
}
return i2c_master_wait_stop ( ) ;
}
enum i2c_master_rc i2c_master_write ( const uint8_t * data , uint16_t data_size )
{
if ( NULL = = data | | 0 = = data_size ) { // no data to read
2021-08-16 13:21:14 +02:00
return I2C_MASTER_RC_NONE ; // we don't indicate an error because the stop is done separately
2021-07-21 23:33:29 +02:00
}
if ( ! ( I2C_SR3 & I2C_SR3_MSL ) ) { // I²C device is not in master mode
return I2C_MASTER_RC_NOT_MASTER ;
}
// we can't check if the address phase it over since ADDR has been cleared when checking for mode
if ( ! ( I2C_SR3 & I2C_SR3_TRA ) ) { // ensure we are in transmit mode
return I2C_MASTER_RC_NOT_TRANSMIT ;
}
// write data
for ( uint16_t i = 0 ; i < data_size ; i + + ) { // write bytes
I2C_SR2 & = ~ ( I2C_SR2_AF ) ; // clear acknowledgement failure
2021-08-16 13:21:14 +02:00
( void ) ( I2C_SR1 & I2C_SR1_BTF ) ; // clear BTF (when followed by write) in case the clock is stretched because there was no data to send on the next transmission slot
2021-07-21 23:33:29 +02:00
I2C_DR = data [ i ] ; // send byte
2021-08-16 13:21:14 +02:00
I2C_SR2 = 0 ; // clear error flags
2021-08-16 14:59:27 +02:00
rim ( ) ; // enable interrupts
2021-08-16 13:21:14 +02:00
while ( ! ( I2C_SR1 & I2C_SR1_TXE ) ) { // wait until byte has been transmitted
IWDG - > KR . fields . KEY = IWDG_KR_KEY_REFRESH ; // reset watchdog
if ( I2C_CR2 & I2C_CR2_STOP ) {
return I2C_MASTER_RC_TIMEOUT ;
}
if ( I2C_SR2 & I2C_SR2_AF ) { // data has not been acknowledged
return I2C_MASTER_RC_NAK ;
2021-08-16 16:28:10 +02:00
} else if ( I2C_SR2 ) {
return I2C_MASTER_RC_BUS_ERROR ;
2021-08-16 13:21:14 +02:00
}
2021-08-16 14:59:27 +02:00
I2C_ITR = ( I2C_ITR_ITBUFEN | I2C_ITR_ITEVTEN | I2C_ITR_ITERREN ) ; // enable all I²C interrupts
wfi ( ) ; // got to sleep to prevent EMI causing glitches
2021-07-21 23:33:29 +02:00
}
}
return I2C_MASTER_RC_NONE ;
}
enum i2c_master_rc i2c_master_slave_read ( uint16_t slave , bool address_10bit , uint8_t * data , uint16_t data_size )
{
enum i2c_master_rc rc = I2C_MASTER_RC_NONE ; // to store I²C return codes
rc = i2c_master_start ( ) ; // send (re-)start condition
if ( I2C_MASTER_RC_NONE ! = rc ) {
return rc ;
}
rc = i2c_master_select_slave ( slave , address_10bit , false ) ; // select slave to read
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
if ( NULL ! = data & & data_size > 0 ) { // only read data if needed
rc = i2c_master_read ( data , data_size ) ; // read data (includes stop)
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
} else {
i2c_master_stop ( ) ; // sent stop condition
}
rc = I2C_MASTER_RC_NONE ; // all went well
error :
if ( I2C_MASTER_RC_NONE ! = rc ) {
i2c_master_stop ( ) ; // sent stop condition
}
return rc ;
}
enum i2c_master_rc i2c_master_slave_write ( uint16_t slave , bool address_10bit , const uint8_t * data , uint16_t data_size )
{
enum i2c_master_rc rc = I2C_MASTER_RC_NONE ; // to store I²C return codes
rc = i2c_master_start ( ) ; // send (re-)start condition
if ( I2C_MASTER_RC_NONE ! = rc ) {
return rc ;
}
rc = i2c_master_select_slave ( slave , address_10bit , true ) ; // select slave to write
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
if ( NULL ! = data & & data_size > 0 ) { // write data only is some is available
rc = i2c_master_write ( data , data_size ) ; // write data
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
}
rc = I2C_MASTER_RC_NONE ; // all went well
error :
i2c_master_stop ( ) ; // sent stop condition
return rc ;
}
enum i2c_master_rc i2c_master_address_read ( uint16_t slave , bool address_10bit , const uint8_t * address , uint16_t address_size , uint8_t * data , uint16_t data_size )
{
enum i2c_master_rc rc = I2C_MASTER_RC_NONE ; // to store I²C return codes
rc = i2c_master_start ( ) ; // send (re-)start condition
if ( I2C_MASTER_RC_NONE ! = rc ) {
return rc ;
}
rc = i2c_master_select_slave ( slave , address_10bit , true ) ; // select slave to write
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
// write address
if ( NULL ! = address & & address_size > 0 ) {
rc = i2c_master_write ( address , address_size ) ; // send memory address
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
}
// read data
if ( NULL ! = data & & data_size > 0 ) {
rc = i2c_master_start ( ) ; // send re-start condition
if ( I2C_MASTER_RC_NONE ! = rc ) {
return rc ;
}
rc = i2c_master_select_slave ( slave , address_10bit , false ) ; // select slave to read
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
rc = i2c_master_read ( data , data_size ) ; // read memory (includes stop)
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
} else {
i2c_master_stop ( ) ; // sent stop condition
}
rc = I2C_MASTER_RC_NONE ;
error :
if ( I2C_MASTER_RC_NONE ! = rc ) { // only send stop on error
i2c_master_stop ( ) ; // sent stop condition
}
return rc ;
}
enum i2c_master_rc i2c_master_address_write ( uint16_t slave , bool address_10bit , const uint8_t * address , uint16_t address_size , const uint8_t * data , uint16_t data_size )
{
if ( UINT16_MAX - address_size < data_size ) { // prevent integer overflow
return I2C_MASTER_RC_OTHER ;
}
if ( address_size > 0 & & NULL = = address ) {
return I2C_MASTER_RC_OTHER ;
}
if ( data_size > 0 & & NULL = = data ) {
return I2C_MASTER_RC_OTHER ;
}
enum i2c_master_rc rc ; // to store I²C return codes
rc = i2c_master_start ( ) ; // send (re-)start condition
if ( I2C_MASTER_RC_NONE ! = rc ) {
return rc ;
}
rc = i2c_master_select_slave ( slave , address_10bit , true ) ; // select slave to write
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
if ( address_size & & address ) {
rc = i2c_master_write ( address , address_size ) ; // send memory address
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
}
if ( data_size & & data ) {
rc = i2c_master_write ( data , data_size ) ; // send memory data
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
}
2021-08-16 13:21:14 +02:00
rc = i2c_master_stop ( ) ; // sent stop condition
2021-07-21 23:33:29 +02:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2021-08-16 13:21:14 +02:00
goto error ;
2021-07-21 23:33:29 +02:00
}
2021-08-16 13:21:14 +02:00
rc = I2C_MASTER_RC_NONE ; // all went fine
error :
2021-07-21 23:33:29 +02:00
return rc ;
}
2021-08-16 14:59:27 +02:00
void i2c_master_isr ( void ) __interrupt ( IRQ_I2C ) // I²C event or error happened
{
I2C_ITR = 0 ; // disable all interrupt sources to stop looping in ISR and let current loop check the right status flags
}