2020-12-12 14:08:05 +01:00
/** library to communicate using I²C as master
2019-12-05 13:26:49 +01:00
* @ file
2017-04-03 13:07:03 +02:00
* @ author King Kévin < kingkevin @ cuvoodoo . info >
2020-06-06 14:35:55 +02:00
* @ copyright SPDX - License - Identifier : GPL - 3.0 - or - later
2020-02-11 12:20:13 +01:00
* @ date 2017 - 2020
2018-04-03 16:59:02 +02:00
* @ note peripherals used : I2C
2017-04-03 13:07:03 +02:00
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdlib.h> // general utilities
/* STM32 (including CM3) libraries */
2019-03-26 18:01:13 +01:00
# include <libopencm3/cm3/systick.h> // SysTick library
2019-03-26 18:35:46 +01:00
# include <libopencm3/cm3/assert.h> // assert utilities
2017-04-03 13:07:03 +02:00
# include <libopencm3/stm32/rcc.h> // real-time control clock library
# include <libopencm3/stm32/gpio.h> // general purpose input output library
2019-12-05 13:26:49 +01:00
# include <libopencm3/stm32/i2c.h> // I²C library
2017-04-03 13:07:03 +02:00
2018-02-18 15:21:18 +01:00
/* own libraries */
2017-04-03 13:07:03 +02:00
# include "global.h" // global utilities
2019-12-05 13:26:49 +01:00
# include "i2c_master.h" // I²C header and definitions
2017-04-03 13:07:03 +02:00
2020-12-12 14:08:05 +01:00
/** @defgroup i2c_master_i2c I²C peripheral used for I²C communication
* @ {
2017-04-03 13:07:03 +02:00
*/
2020-12-12 14:08:05 +01:00
# define I2C_MASTER_I2C 1 /**< I²C peripheral ID */
# define I2C_MASTER_SCL PB6 /**< GPIO pin for I²C SCL */
# define I2C_MASTER_SDA PB7 /**< GPIO pin for I²C SDA */
# define I2C_MASTER_AF GPIO_AF4 /**< alternate function for GPIO pin */
/** @} */
2017-04-03 13:07:03 +02:00
2020-12-12 14:08:05 +01:00
void i2c_master_setup ( uint16_t frequency )
2018-04-03 16:59:02 +02:00
{
2019-12-05 13:26:49 +01:00
// configure I²C peripheral
2020-12-12 14:08:05 +01:00
rcc_periph_clock_enable ( GPIO_RCC ( I2C_MASTER_SCL ) ) ; // enable clock for I²C I/O peripheral
gpio_set ( GPIO_PORT ( I2C_MASTER_SCL ) , GPIO_PIN ( I2C_MASTER_SCL ) ) ; // already put signal high to avoid small pulse
gpio_mode_setup ( GPIO_PORT ( I2C_MASTER_SCL ) , GPIO_MODE_AF , GPIO_PUPD_NONE , GPIO_PIN ( I2C_MASTER_SCL ) ) ; // set SCL pin to alternate function
gpio_set_output_options ( GPIO_PORT ( I2C_MASTER_SCL ) , GPIO_OTYPE_OD , GPIO_OSPEED_25MHZ , GPIO_PIN ( I2C_MASTER_SCL ) ) ; // set SCL pin output as open-drain
gpio_set_af ( GPIO_PORT ( I2C_MASTER_SCL ) , I2C_MASTER_AF , GPIO_PIN ( I2C_MASTER_SCL ) ) ; // set alternate function to I²C SCL pin
rcc_periph_clock_enable ( GPIO_RCC ( I2C_MASTER_SDA ) ) ; // enable clock for I²C I/O peripheral
gpio_set ( GPIO_PORT ( I2C_MASTER_SDA ) , GPIO_PIN ( I2C_MASTER_SDA ) ) ; // already put signal high to avoid small pulse
gpio_mode_setup ( GPIO_PORT ( I2C_MASTER_SDA ) , GPIO_MODE_AF , GPIO_PUPD_NONE , GPIO_PIN ( I2C_MASTER_SDA ) ) ; // set SDA pin to alternate function
gpio_set_output_options ( GPIO_PORT ( I2C_MASTER_SDA ) , GPIO_OTYPE_OD , GPIO_OSPEED_25MHZ , GPIO_PIN ( I2C_MASTER_SDA ) ) ; // set SDA pin output as open-drain
gpio_set_af ( GPIO_PORT ( I2C_MASTER_SDA ) , I2C_MASTER_AF , GPIO_PIN ( I2C_MASTER_SDA ) ) ; // set alternate function to I²C SDA pin
rcc_periph_clock_enable ( RCC_I2C ( I2C_MASTER_I2C ) ) ; // enable clock for I²C peripheral
i2c_reset ( I2C ( I2C_MASTER_I2C ) ) ; // reset peripheral domain
i2c_peripheral_disable ( I2C ( I2C_MASTER_I2C ) ) ; // I²C needs to be disable to be configured
I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) | = I2C_CR1_SWRST ; // reset peripheral
I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) & = ~ I2C_CR1_SWRST ; // clear peripheral reset
if ( 0 = = frequency ) { // don't allow null frequency
2018-04-03 16:59:02 +02:00
frequency = 1 ;
2019-03-26 18:25:23 +01:00
} else if ( frequency > 400 ) { // limit frequency to 400 kHz
2018-04-03 16:59:02 +02:00
frequency = 400 ;
}
2020-12-12 14:08:05 +01:00
i2c_set_clock_frequency ( I2C ( I2C_MASTER_I2C ) , rcc_apb1_frequency / 1000000 ) ; // configure the peripheral clock to the APB1 freq (where it is connected to)
if ( frequency > 100 ) { // use fast mode for frequencies over 100 kHz
i2c_set_fast_mode ( I2C ( I2C_MASTER_I2C ) ) ; // set fast mode (Fm)
i2c_set_ccr ( I2C ( I2C_MASTER_I2C ) , rcc_apb1_frequency / ( frequency * 1000 * 2 ) ) ; // set Thigh/Tlow to generate frequency (fast duty not used)
i2c_set_trise ( I2C ( I2C_MASTER_I2C ) , ( 300 / ( 1000 / ( rcc_apb1_frequency / 1000000 ) ) ) + 1 ) ; // max rise time for Fm mode (< 400) kHz is 300 ns
2018-04-03 16:59:02 +02:00
} else { // use fast mode for frequencies below 100 kHz
2020-12-12 14:08:05 +01:00
i2c_set_standard_mode ( I2C ( I2C_MASTER_I2C ) ) ; // set standard mode (Sm)
i2c_set_ccr ( I2C ( I2C_MASTER_I2C ) , rcc_apb1_frequency / ( frequency * 1000 * 2 ) ) ; // set Thigh/Tlow to generate frequency of 100 kHz
i2c_set_trise ( I2C ( I2C_MASTER_I2C ) , ( 1000 / ( 1000 / ( rcc_apb1_frequency / 1000000 ) ) ) + 1 ) ; // max rise time for Sm mode (< 100 kHz) is 1000 ns (~1 MHz)
2018-04-03 16:59:02 +02:00
}
2020-12-12 14:08:05 +01:00
i2c_peripheral_enable ( I2C ( I2C_MASTER_I2C ) ) ; // enable I²C after configuration completed
2018-04-03 16:59:02 +02:00
}
2020-12-12 14:08:05 +01:00
void i2c_master_release ( void )
2018-04-03 16:59:02 +02:00
{
2020-12-12 14:08:05 +01:00
i2c_reset ( I2C ( I2C_MASTER_I2C ) ) ; // reset I²C peripheral configuration
i2c_peripheral_disable ( I2C ( I2C_MASTER_I2C ) ) ; // disable I²C peripheral
rcc_periph_clock_disable ( RCC_I2C ( I2C_MASTER_I2C ) ) ; // disable clock for I²C peripheral
gpio_mode_setup ( GPIO_PORT ( I2C_MASTER_SCL ) , GPIO_MODE_INPUT , GPIO_PUPD_NONE , GPIO_PIN ( I2C_MASTER_SCL ) ) ; // set SCL pin back to input
gpio_mode_setup ( GPIO_PORT ( I2C_MASTER_SDA ) , GPIO_MODE_INPUT , GPIO_PUPD_NONE , GPIO_PIN ( I2C_MASTER_SDA ) ) ; // set SDA pin back to input
2018-04-03 16:59:02 +02:00
}
2020-12-12 14:08:05 +01:00
bool i2c_master_check_signals ( void )
2018-04-03 16:59:02 +02:00
{
2019-12-12 18:53:23 +01:00
// enable GPIOs to read SDA and SCL
2020-12-12 14:08:05 +01:00
rcc_periph_clock_enable ( GPIO_RCC ( I2C_MASTER_SDA ) ) ; // enable clock for I²C I/O peripheral
rcc_periph_clock_enable ( GPIO_RCC ( I2C_MASTER_SCL ) ) ; // enable clock for I²C I/O peripheral
2019-12-12 18:53:23 +01:00
2018-04-03 16:59:02 +02:00
// pull SDA and SDC low to check if there are pull-up resistors
2020-12-12 14:08:05 +01:00
const uint32_t sda_moder = GPIO_MODER ( GPIO_PORT ( I2C_MASTER_SDA ) ) ; // backup port configuration
const uint32_t sda_pupdr = GPIO_PUPDR ( GPIO_PORT ( I2C_MASTER_SDA ) ) ; // backup port configuration
const uint32_t scl_moder = GPIO_MODER ( GPIO_PORT ( I2C_MASTER_SCL ) ) ; // backup port configuration
const uint32_t scl_pupdr = GPIO_PUPDR ( GPIO_PORT ( I2C_MASTER_SCL ) ) ; // backup port configuration
gpio_mode_setup ( GPIO_PORT ( I2C_MASTER_SDA ) , GPIO_MODE_INPUT , GPIO_PUPD_PULLDOWN , GPIO_PIN ( I2C_MASTER_SDA ) ) ; // set SDA to input and pull down (weak) to check if there is an external pull up (strong)
gpio_mode_setup ( GPIO_PORT ( I2C_MASTER_SCL ) , GPIO_MODE_INPUT , GPIO_PUPD_PULLDOWN , GPIO_PIN ( I2C_MASTER_SCL ) ) ; // set SCL to input and pull down (weak) to check if there is an external pull up (strong)
sleep_us ( 100 ) ; // let signal settle
const bool to_return = ( gpio_get ( GPIO_PORT ( I2C_MASTER_SCL ) , GPIO_PIN ( I2C_MASTER_SCL ) ) & & gpio_get ( GPIO_PORT ( I2C_MASTER_SDA ) , GPIO_PIN ( I2C_MASTER_SDA ) ) ) ; // check if the signals are still pulled high by external stronger pull-up resistors
GPIO_MODER ( GPIO_PORT ( I2C_MASTER_SDA ) ) = sda_moder ; // restore port configuration
GPIO_PUPDR ( GPIO_PORT ( I2C_MASTER_SDA ) ) = sda_pupdr ; // restore port configuration
GPIO_MODER ( GPIO_PORT ( I2C_MASTER_SCL ) ) = scl_moder ; // restore port configuration
GPIO_PUPDR ( GPIO_PORT ( I2C_MASTER_SCL ) ) = scl_pupdr ; // restore port configuration
2018-04-03 16:59:02 +02:00
return to_return ;
}
2020-12-12 14:08:05 +01:00
void i2c_master_reset ( void )
2018-04-03 16:59:02 +02:00
{
2020-12-12 14:08:05 +01:00
i2c_peripheral_disable ( I2C ( I2C_MASTER_I2C ) ) ; // disable I²C peripheral
I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) | = I2C_CR1_SWRST ; // reset device
I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) & = ~ I2C_CR1_SWRST ; // reset device
i2c_peripheral_enable ( I2C ( I2C_MASTER_I2C ) ) ; // re-enable device
2017-04-03 13:07:03 +02:00
}
2020-12-12 14:08:05 +01:00
enum i2c_master_rc i2c_master_start ( void )
2017-04-03 13:07:03 +02:00
{
2019-03-26 18:01:13 +01:00
bool retry = true ; // retry after reset if first try failed
enum i2c_master_rc to_return ; // return code
2020-02-11 12:20:13 +01:00
uint16_t sr1 ; // read register once, since reading/writing other registers or other events clears some flags
2019-03-26 18:01:13 +01:00
try :
to_return = I2C_MASTER_RC_NONE ; // return code
2018-02-18 15:21:18 +01:00
// send (re-)start condition
2020-12-12 14:08:05 +01:00
if ( I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_CR1_START | I2C_CR1_STOP ) ) { // ensure start or stop operations are not in progress
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_START_STOP_IN_PROGESS ;
2017-04-03 13:07:03 +02:00
}
2019-12-05 13:26:49 +01:00
// prepare timer in case the peripheral hangs on sending stop condition (see errata 2.14.4 Wrong behavior of I²C peripheral in master mode after a misplaced Stop)
2019-03-26 18:01:13 +01:00
systick_counter_disable ( ) ; // disable SysTick to reconfigure it
systick_set_frequency ( 500 , rcc_ahb_frequency ) ; // set timer to 2 ms (that should be long enough to send a start condition)
systick_clear ( ) ; // reset SysTick (set to 0)
systick_interrupt_disable ( ) ; // disable interrupt to prevent ISR to read the flag
systick_get_countflag ( ) ; // reset flag (set when counter is going for 1 to 0)
2020-12-12 14:08:05 +01:00
i2c_send_start ( I2C ( I2C_MASTER_I2C ) ) ; // send start condition to start transaction
2019-03-26 18:01:13 +01:00
bool timeout = false ; // remember if the timeout has been reached
systick_counter_enable ( ) ; // start timer
2020-12-12 14:08:05 +01:00
while ( ( I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) & I2C_CR1_START ) & & ! ( ( sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ) & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) & & ! timeout ) { // wait until start condition has been accepted and cleared
2019-03-26 18:01:13 +01:00
timeout | = systick_get_countflag ( ) ; // verify if timeout has been reached
2018-04-03 16:59:02 +02:00
}
2020-12-12 14:08:05 +01:00
sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ; // be sure to get the current value
2020-02-11 12:20:13 +01:00
if ( sr1 & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) {
2019-03-26 18:01:13 +01:00
to_return = I2C_MASTER_RC_BUS_ERROR ;
}
2020-12-12 14:08:05 +01:00
while ( ! ( ( sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ) & ( I2C_SR1_SB | I2C_SR1_BERR | I2C_SR1_ARLO ) ) & & ! timeout & & I2C_MASTER_RC_NONE = = to_return ) { // wait until start condition is transmitted
2019-03-26 18:01:13 +01:00
timeout | = systick_get_countflag ( ) ; // verify if timeout has been reached
2018-04-03 16:59:02 +02:00
}
2020-12-12 14:08:05 +01:00
sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ; // be sure to get the current value
2020-02-11 12:20:13 +01:00
if ( sr1 & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) {
2019-03-26 18:01:13 +01:00
to_return = I2C_MASTER_RC_BUS_ERROR ;
2020-02-11 12:20:13 +01:00
} else if ( ! ( sr1 & I2C_SR1_SB ) ) { // the start bit has not been set although we the peripheral is not busy anymore
2019-03-26 18:01:13 +01:00
to_return = I2C_MASTER_RC_BUS_ERROR ;
2020-02-11 12:20:13 +01:00
} else if ( ! ( sr1 & I2C_SR2_MSL ) ) { // verify if in master mode
2019-03-26 18:01:13 +01:00
to_return = I2C_MASTER_RC_NOT_MASTER ;
} else if ( timeout ) { // timeout has been reached, i.e. the peripheral hangs
to_return = I2C_MASTER_RC_NOT_MASTER ;
2018-02-18 15:21:18 +01:00
}
2019-03-26 18:01:13 +01:00
if ( I2C_MASTER_RC_NOT_MASTER = = to_return & & retry ) { // error happened
retry = false ; // don't retry a second time
2020-12-12 14:08:05 +01:00
I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) | = I2C_CR1_SWRST ; // assert peripheral reset
I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) & = ~ I2C_CR1_SWRST ; // release peripheral reset
2019-03-26 18:01:13 +01:00
goto try ;
}
systick_counter_disable ( ) ; // we don't need to timer anymore
return to_return ;
2018-02-18 15:21:18 +01:00
}
2020-02-27 13:05:35 +01:00
/** wait until stop is sent and bus is released
* @ return I ² C return code
*/
2020-12-16 02:38:57 +01:00
static enum i2c_master_rc i2c_master_wait_stop ( void )
2020-02-27 13:05:35 +01:00
{
enum i2c_master_rc to_return = I2C_MASTER_RC_NONE ; // return code
// prepare timer in case the peripheral hangs on sending stop condition (see errata 2.14.4 Wrong behavior of I²C peripheral in master mode after a misplaced Stop)
systick_counter_disable ( ) ; // disable SysTick to reconfigure it
systick_set_frequency ( 500 , rcc_ahb_frequency ) ; // set timer to 2 ms (that should be long enough to send a stop condition)
systick_clear ( ) ; // reset SysTick (set to 0)
systick_interrupt_disable ( ) ; // disable interrupt to prevent ISR to read the flag
systick_get_countflag ( ) ; // reset flag (set when counter is going for 1 to 0)
bool timeout = false ; // remember if the timeout has been reached
systick_counter_enable ( ) ; // start timer
2020-12-12 14:08:05 +01:00
while ( ( I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) & I2C_CR1_STOP ) & & ! ( I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) & & ! timeout ) { // wait until stop condition is accepted and cleared
2020-02-27 13:05:35 +01:00
timeout | = systick_get_countflag ( ) ; // verify if timeout has been reached
}
2020-12-12 14:08:05 +01:00
if ( I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) {
2020-02-27 13:05:35 +01:00
to_return = I2C_MASTER_RC_BUS_ERROR ;
}
2020-12-12 14:08:05 +01:00
while ( ( I2C_SR2 ( I2C ( I2C_MASTER_I2C ) ) & I2C_SR2_MSL ) & & ! ( I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) & & ! timeout ) { // wait until bus released (non master mode)
2020-02-27 13:05:35 +01:00
timeout | = systick_get_countflag ( ) ; // verify if timeout has been reached
}
2020-12-12 14:08:05 +01:00
if ( I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) {
2020-02-27 13:05:35 +01:00
to_return = I2C_MASTER_RC_BUS_ERROR ;
}
2020-12-12 14:08:05 +01:00
while ( ( I2C_SR2 ( I2C ( I2C_MASTER_I2C ) ) & I2C_SR2_BUSY ) & & ! ( I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_SR1_BERR ) ) & & ! timeout ) { // wait until peripheral is not busy anymore
2020-02-27 13:05:35 +01:00
timeout | = systick_get_countflag ( ) ; // verify if timeout has been reached
}
2020-12-12 14:08:05 +01:00
if ( I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) {
2020-02-27 13:05:35 +01:00
to_return = I2C_MASTER_RC_BUS_ERROR ;
}
2020-12-12 14:08:05 +01:00
while ( ( 0 = = gpio_get ( GPIO_PORT ( I2C_MASTER_SCL ) , GPIO_PIN ( I2C_MASTER_SCL ) ) | | 0 = = gpio_get ( GPIO_PORT ( I2C_MASTER_SDA ) , GPIO_PIN ( I2C_MASTER_SDA ) ) ) & & ! timeout ) { // wait until lines are really high again
2020-02-27 13:05:35 +01:00
timeout | = systick_get_countflag ( ) ; // verify if timeout has been reached
}
if ( timeout ) { // I2C_CR1_STOP could also be used to detect a timeout, but I'm not sure when
if ( I2C_MASTER_RC_NONE = = to_return ) {
to_return = I2C_MASTER_RC_TIMEOUT ; // indicate timeout only when no more specific error has occurred
}
2020-12-12 14:08:05 +01:00
I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) | = I2C_CR1_SWRST ; // assert peripheral reset
I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) & = ~ I2C_CR1_SWRST ; // release peripheral reset
2020-02-27 13:05:35 +01:00
}
systick_counter_disable ( ) ; // we don't need to timer anymore
return to_return ;
}
2020-12-12 14:08:05 +01:00
enum i2c_master_rc i2c_master_stop ( void )
2020-02-27 13:05:35 +01:00
{
// sanity check
2020-12-12 14:08:05 +01:00
if ( ! ( I2C_SR2 ( I2C ( I2C_MASTER_I2C ) ) & I2C_SR2_BUSY ) ) { // release is not busy
2020-02-27 13:05:35 +01:00
return I2C_MASTER_RC_NONE ; // bus has probably already been released
}
2020-12-16 02:42:34 +01:00
if ( I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_CR1_START ) ) { // ensure start is not in progress
2020-02-27 13:05:35 +01:00
return I2C_MASTER_RC_START_STOP_IN_PROGESS ;
}
2020-12-12 14:08:05 +01:00
if ( ! ( ( I2C_SR2 ( I2C ( I2C_MASTER_I2C ) ) & I2C_SR2_TRA ) ) ) { // if we are in receiver mode
i2c_disable_ack ( I2C ( I2C_MASTER_I2C ) ) ; // disable ACK to be able to close the communication
2020-02-27 13:05:35 +01:00
}
2020-12-16 02:42:34 +01:00
if ( ! ( I2C_CR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_CR1_STOP ) ) ) { // ensure stop operations is not in progress
i2c_send_stop ( I2C ( I2C_MASTER_I2C ) ) ; // send stop to release bus
}
2020-12-16 02:38:57 +01:00
return i2c_master_wait_stop ( ) ;
2020-02-27 13:05:35 +01:00
}
2020-12-12 14:08:05 +01:00
enum i2c_master_rc i2c_master_select_slave ( uint16_t slave , bool address_10bit , bool write )
2018-02-18 15:21:18 +01:00
{
2019-12-05 13:26:49 +01:00
enum i2c_master_rc rc = I2C_MASTER_RC_NONE ; // to store I²C return codes
2020-02-11 12:20:13 +01:00
uint16_t sr1 , sr2 ; // read register once, since reading/writing other registers or other events clears some flags
2020-12-12 14:08:05 +01:00
if ( ! ( ( sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ) & I2C_SR1_SB ) ) { // start condition has not been sent
rc = i2c_master_start ( ) ; // send start condition
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-04-03 16:59:02 +02:00
return rc ;
2018-02-18 15:21:18 +01:00
}
2018-04-03 16:59:02 +02:00
}
2020-12-12 14:08:05 +01:00
if ( ! ( ( sr2 = I2C_SR2 ( I2C ( I2C_MASTER_I2C ) ) ) & I2C_SR2_MSL ) ) { // I²C device is not in master mode
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NOT_MASTER ;
2017-04-03 13:07:03 +02:00
}
// select slave
2020-12-12 14:08:05 +01:00
I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & = ~ ( I2C_SR1_AF ) ; // clear acknowledgement failure
2018-04-03 16:59:02 +02:00
if ( ! address_10bit ) { // 7-bit address
2020-12-12 14:08:05 +01:00
i2c_send_7bit_address ( I2C ( I2C_MASTER_I2C ) , slave , write ? I2C_WRITE : I2C_READ ) ; // select slave, with read/write flag
while ( ! ( ( sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ) & ( I2C_SR1_ADDR | I2C_SR1_AF | I2C_SR1_BERR | I2C_SR1_ARLO ) ) ) ; // wait until address is transmitted
2020-02-11 12:20:13 +01:00
if ( sr1 & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) {
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_BUS_ERROR ;
}
2020-02-11 12:20:13 +01:00
if ( sr1 & I2C_SR1_AF ) { // address has not been acknowledged
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NAK ;
}
} else { // 10-bit address
// send first part of address
2020-12-12 14:08:05 +01:00
I2C_DR ( I2C ( I2C_MASTER_I2C ) ) = 11110000 | ( ( ( slave > > 8 ) & 0x3 ) < < 1 ) ; // send first header (11110xx0, where xx are 2 MSb of slave address)
while ( ! ( ( sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ) & ( I2C_SR1_ADD10 | I2C_SR1_AF | I2C_SR1_BERR | I2C_SR1_ARLO ) ) ) ; // wait until first part of address is transmitted
2020-02-11 12:20:13 +01:00
if ( sr1 & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) {
return I2C_MASTER_RC_BUS_ERROR ;
}
if ( sr1 & I2C_SR1_AF ) { // address has not been acknowledged
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NAK ;
}
// send second part of address
2020-12-12 14:08:05 +01:00
I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & = ~ ( I2C_SR1_AF ) ; // clear acknowledgement failure
I2C_DR ( I2C ( I2C_MASTER_I2C ) ) = ( slave & 0xff ) ; // send remaining of address
while ( ! ( ( sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ) & ( I2C_SR1_ADDR | I2C_SR1_AF | I2C_SR1_BERR | I2C_SR1_ARLO ) ) ) ; // wait until remaining part of address is transmitted
2020-02-11 12:20:13 +01:00
if ( sr1 & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) {
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_BUS_ERROR ;
}
2020-02-11 12:20:13 +01:00
if ( sr1 & I2C_SR1_AF ) { // address has not been acknowledged
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NAK ;
}
// go into receive mode if necessary
if ( ! write ) {
2020-12-12 14:08:05 +01:00
rc = i2c_master_start ( ) ; // send start condition
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-04-03 16:59:02 +02:00
return rc ;
}
// send first part of address with receive flag
2020-12-12 14:08:05 +01:00
I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & = ~ ( I2C_SR1_AF ) ; // clear acknowledgement failure
I2C_DR ( I2C ( I2C_MASTER_I2C ) ) = 11110001 | ( ( ( slave > > 8 ) & 0x3 ) < < 1 ) ; // send header (11110xx1, where xx are 2 MSb of slave address)
while ( ! ( ( sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ) & ( I2C_SR1_ADDR | I2C_SR1_AF | I2C_SR1_BERR | I2C_SR1_ARLO ) ) ) ; // wait until remaining part of address is transmitted
2020-02-11 12:20:13 +01:00
if ( sr1 & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) {
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_BUS_ERROR ;
}
2020-02-11 12:20:13 +01:00
if ( sr1 & I2C_SR1_AF ) { // address has not been acknowledged
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NAK ;
}
}
2017-04-03 13:07:03 +02:00
}
2019-03-26 18:07:22 +01:00
// do not check I2C_SR2_TRA to verify if we really are in transmit or receive mode since reading SR2 also clears ADDR and starting the read/write transaction
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NONE ;
2018-02-18 15:21:18 +01:00
}
2017-04-03 13:07:03 +02:00
2020-12-12 14:08:05 +01:00
enum i2c_master_rc i2c_master_read ( uint8_t * data , size_t data_size )
2018-02-18 15:21:18 +01:00
{
// sanity check
2019-03-26 18:25:23 +01:00
if ( NULL = = data | | 0 = = data_size ) { // no data to read
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NONE ;
2019-03-26 18:12:21 +01:00
}
2020-02-11 12:20:13 +01:00
// I²C start condition check
2020-12-12 14:08:05 +01:00
uint16_t sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ; // read once
2020-02-11 12:20:13 +01:00
if ( ! ( sr1 & I2C_SR1_ADDR ) ) { // no slave have been selected
return I2C_MASTER_RC_NOT_READY ;
}
if ( sr1 & I2C_SR1_AF ) { // check if the previous transaction went well
return I2C_MASTER_RC_NOT_READY ;
}
2020-02-11 12:21:35 +01:00
// prepare (N)ACK (EV6_3 in RM0008)
2019-03-26 18:12:21 +01:00
if ( 1 = = data_size ) {
2020-12-12 14:08:05 +01:00
i2c_disable_ack ( I2C ( I2C_MASTER_I2C ) ) ; // NACK after first byte
2019-03-26 18:12:21 +01:00
} else {
2020-12-12 14:08:05 +01:00
i2c_enable_ack ( I2C ( I2C_MASTER_I2C ) ) ; // NAK after next byte
2019-03-26 18:12:21 +01:00
}
2020-12-12 14:08:05 +01:00
uint16_t sr2 = I2C_SR2 ( I2C ( I2C_MASTER_I2C ) ) ; // reading SR2 will also also clear ADDR in SR1 and start the transaction
2020-02-11 12:20:13 +01:00
if ( ! ( sr2 & I2C_SR2_MSL ) ) { // I²C device is not master
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NOT_MASTER ;
}
2020-02-11 12:20:13 +01:00
if ( ( sr2 & I2C_SR2_TRA ) ) { // I²C device not in receiver mode
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NOT_RECEIVE ;
}
2017-04-03 13:07:03 +02:00
// read data
2019-03-26 18:25:23 +01:00
for ( size_t i = 0 ; i < data_size ; i + + ) { // read bytes
2020-02-11 12:21:35 +01:00
// set (N)ACK (EV6_3, EV6_1)
if ( 1 = = data_size - i ) { // prepare to sent NACK for last byte
2020-12-12 14:08:05 +01:00
i2c_send_stop ( I2C ( I2C_MASTER_I2C ) ) ; // already indicate we will send a stop (required to not send an ACK, and this must happen before the byte is transferred, see errata)
i2c_nack_current ( I2C ( I2C_MASTER_I2C ) ) ; // (N)ACK current byte
i2c_disable_ack ( I2C ( I2C_MASTER_I2C ) ) ; // NACK received to stop slave transmission
2020-02-11 12:21:35 +01:00
} else if ( 2 = = data_size - i ) { // prepare to sent NACK for second last byte
2020-12-12 14:08:05 +01:00
i2c_nack_next ( I2C ( I2C_MASTER_I2C ) ) ; // NACK next byte
i2c_disable_ack ( I2C ( I2C_MASTER_I2C ) ) ; // NACK received to stop slave transmission
2017-04-03 13:07:03 +02:00
} else {
2020-12-12 14:08:05 +01:00
i2c_enable_ack ( I2C ( I2C_MASTER_I2C ) ) ; // ACK received byte to continue slave transmission
2017-04-03 13:07:03 +02:00
}
2020-12-12 14:08:05 +01:00
while ( ! ( ( sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ) & ( I2C_SR1_RxNE | I2C_SR1_BERR | I2C_SR1_ARLO ) ) ) ; // wait until byte has been received
2020-02-11 12:20:13 +01:00
if ( sr1 & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) {
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_BUS_ERROR ;
2017-04-03 13:07:03 +02:00
}
2020-12-12 14:08:05 +01:00
data [ i ] = i2c_get_data ( I2C ( I2C_MASTER_I2C ) ) ; // read received byte
2017-04-03 13:07:03 +02:00
}
2020-12-16 02:38:57 +01:00
return i2c_master_wait_stop ( ) ;
2018-02-18 15:21:18 +01:00
}
2020-12-12 14:08:05 +01:00
enum i2c_master_rc i2c_master_write ( const uint8_t * data , size_t data_size )
2018-02-18 15:21:18 +01:00
{
// sanity check
2019-03-26 18:25:23 +01:00
if ( NULL = = data | | 0 = = data_size ) { // no data to write
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NONE ;
2019-03-26 19:27:40 +01:00
}
2020-02-11 12:20:13 +01:00
// I²C start condition check
2020-12-12 14:08:05 +01:00
uint16_t sr1 = I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) ; // read once
2020-02-11 12:20:13 +01:00
if ( ! ( sr1 & I2C_SR1_ADDR ) ) { // no slave have been selected
return I2C_MASTER_RC_NOT_READY ;
}
if ( sr1 & I2C_SR1_AF ) { // check if the previous transaction went well
return I2C_MASTER_RC_NOT_READY ;
}
// master check
2020-12-12 14:08:05 +01:00
uint16_t sr2 = I2C_SR2 ( I2C ( I2C_MASTER_I2C ) ) ; // reading SR2 will also also clear ADDR in SR1 and start the transaction
2020-02-11 12:20:13 +01:00
if ( ! ( sr2 & I2C_SR2_MSL ) ) { // I²C device is not master
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NOT_MASTER ;
}
2020-02-11 12:20:13 +01:00
if ( ! ( sr2 & I2C_SR2_TRA ) ) { // I²C device not in transmitter mode
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NOT_TRANSMIT ;
}
2018-02-18 15:21:18 +01:00
// write data
2019-03-26 18:25:23 +01:00
for ( size_t i = 0 ; i < data_size ; i + + ) { // write bytes
2020-12-12 14:08:05 +01:00
I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & = ~ ( I2C_SR1_AF ) ; // clear acknowledgement failure
i2c_send_data ( I2C ( I2C_MASTER_I2C ) , data [ i ] ) ; // send byte to be written in memory
while ( ! ( I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_SR1_TxE | I2C_SR1_AF ) ) & & ! ( I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) ) ; // wait until byte has been transmitted
if ( I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & ( I2C_SR1_BERR | I2C_SR1_ARLO ) ) {
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_BUS_ERROR ;
}
2020-12-12 14:08:05 +01:00
if ( I2C_SR1 ( I2C ( I2C_MASTER_I2C ) ) & I2C_SR1_AF ) { // data has not been acknowledged
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NAK ;
2018-02-18 15:21:18 +01:00
}
}
2018-04-03 16:59:02 +02:00
return I2C_MASTER_RC_NONE ;
2018-02-18 15:21:18 +01:00
}
2020-12-12 14:08:05 +01:00
enum i2c_master_rc i2c_master_slave_read ( uint16_t slave , bool address_10bit , uint8_t * data , size_t data_size )
2017-04-03 13:07:03 +02:00
{
2019-12-05 13:26:49 +01:00
enum i2c_master_rc rc = I2C_MASTER_RC_NONE ; // to store I²C return codes
2020-12-12 14:08:05 +01:00
rc = i2c_master_start ( ) ; // send (re-)start condition
2019-12-05 13:26:49 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-04-03 16:59:02 +02:00
return rc ;
2017-04-03 13:07:03 +02:00
}
2020-12-12 14:08:05 +01:00
rc = i2c_master_select_slave ( slave , address_10bit , false ) ; // select slave to read
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2017-04-03 13:07:03 +02:00
goto error ;
}
2019-03-26 18:25:23 +01:00
if ( NULL ! = data & & data_size > 0 ) { // only read data if needed
2020-12-12 14:08:05 +01:00
rc = i2c_master_read ( data , data_size ) ; // read data (includes stop)
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-02-18 15:21:18 +01:00
goto error ;
}
2020-02-27 13:05:35 +01:00
} else {
2020-12-12 14:08:05 +01:00
i2c_master_stop ( ) ; // sent stop condition
2018-02-18 15:21:18 +01:00
}
2017-04-03 13:07:03 +02:00
2018-04-03 16:59:02 +02:00
rc = I2C_MASTER_RC_NONE ; // all went well
2018-02-18 15:21:18 +01:00
error :
2020-02-27 13:05:35 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2020-12-12 14:08:05 +01:00
i2c_master_stop ( ) ; // sent stop condition
2020-02-27 13:05:35 +01:00
}
2018-04-03 16:59:02 +02:00
return rc ;
2018-02-18 15:21:18 +01:00
}
2020-12-12 14:08:05 +01:00
enum i2c_master_rc i2c_master_slave_write ( uint16_t slave , bool address_10bit , const uint8_t * data , size_t data_size )
2018-02-18 15:21:18 +01:00
{
2019-12-05 13:26:49 +01:00
enum i2c_master_rc rc = I2C_MASTER_RC_NONE ; // to store I²C return codes
2020-12-12 14:08:05 +01:00
rc = i2c_master_start ( ) ; // send (re-)start condition
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-04-03 16:59:02 +02:00
return rc ;
2017-04-03 13:07:03 +02:00
}
2020-12-12 14:08:05 +01:00
rc = i2c_master_select_slave ( slave , address_10bit , true ) ; // select slave to write
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2017-04-03 13:07:03 +02:00
goto error ;
}
2019-03-26 18:25:23 +01:00
if ( NULL ! = data & & data_size > 0 ) { // write data only is some is available
2020-12-12 14:08:05 +01:00
rc = i2c_master_write ( data , data_size ) ; // write data
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2017-04-03 13:07:03 +02:00
goto error ;
}
}
2018-04-03 16:59:02 +02:00
rc = I2C_MASTER_RC_NONE ; // all went well
2018-02-18 15:21:18 +01:00
error :
2020-12-12 14:08:05 +01:00
i2c_master_stop ( ) ; // sent stop condition
2018-04-03 16:59:02 +02:00
return rc ;
2018-02-18 15:21:18 +01:00
}
2020-12-12 14:08:05 +01:00
enum i2c_master_rc i2c_master_address_read ( uint16_t slave , bool address_10bit , const uint8_t * address , size_t address_size , uint8_t * data , size_t data_size )
2018-02-18 15:21:18 +01:00
{
2019-12-05 13:26:49 +01:00
enum i2c_master_rc rc = I2C_MASTER_RC_NONE ; // to store I²C return codes
2020-12-12 14:08:05 +01:00
rc = i2c_master_start ( ) ; // send (re-)start condition
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-04-03 16:59:02 +02:00
return rc ;
}
2020-12-12 14:08:05 +01:00
rc = i2c_master_select_slave ( slave , address_10bit , true ) ; // select slave to write
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-04-03 16:59:02 +02:00
goto error ;
}
2018-02-18 15:21:18 +01:00
// write address
2019-03-26 18:25:23 +01:00
if ( NULL ! = address & & address_size > 0 ) {
2020-12-12 14:08:05 +01:00
rc = i2c_master_write ( address , address_size ) ; // send memory address
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-02-18 15:21:18 +01:00
goto error ;
}
}
// read data
2019-03-26 18:25:23 +01:00
if ( NULL ! = data & & data_size > 0 ) {
2020-12-12 14:08:05 +01:00
rc = i2c_master_start ( ) ; // send re-start condition
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-04-03 16:59:02 +02:00
return rc ;
2018-02-18 15:21:18 +01:00
}
2020-12-12 14:08:05 +01:00
rc = i2c_master_select_slave ( slave , address_10bit , false ) ; // select slave to read
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-02-18 15:21:18 +01:00
goto error ;
}
2020-12-12 14:08:05 +01:00
rc = i2c_master_read ( data , data_size ) ; // read memory (includes stop)
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2017-04-03 13:07:03 +02:00
goto error ;
}
2020-02-27 13:06:29 +01:00
} else {
2020-12-12 14:08:05 +01:00
i2c_master_stop ( ) ; // sent stop condition
2017-04-03 13:07:03 +02:00
}
2020-02-27 13:06:29 +01:00
rc = I2C_MASTER_RC_NONE ;
2017-04-03 13:07:03 +02:00
error :
2020-02-27 13:06:29 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) { // only send stop on error
2020-12-12 14:08:05 +01:00
i2c_master_stop ( ) ; // sent stop condition
2020-02-27 13:06:29 +01:00
}
2018-04-03 16:59:02 +02:00
return rc ;
2018-02-18 15:21:18 +01:00
}
2020-12-12 14:08:05 +01:00
enum i2c_master_rc i2c_master_address_write ( uint16_t slave , bool address_10bit , const uint8_t * address , size_t address_size , const uint8_t * data , size_t data_size )
2018-02-18 15:21:18 +01:00
{
2020-02-27 13:06:29 +01:00
if ( SIZE_MAX - address_size < data_size ) { // prevent integer overflow
return I2C_MASTER_RC_OTHER ;
}
if ( address_size + data_size > 10 * 1024 ) { // we won't enough RAM
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 ;
}
2018-02-18 15:21:18 +01:00
2020-02-27 13:06:29 +01:00
uint8_t buffer [ address_size + data_size ] ;
2019-12-05 13:26:49 +01:00
enum i2c_master_rc rc = I2C_MASTER_RC_NONE ; // to store I²C return codes
2020-12-12 14:08:05 +01:00
rc = i2c_master_start ( ) ; // send (re-)start condition
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-04-03 16:59:02 +02:00
return rc ;
2018-02-18 15:21:18 +01:00
}
2020-12-12 14:08:05 +01:00
rc = i2c_master_select_slave ( slave , address_10bit , true ) ; // select slave to write
2019-03-26 18:25:23 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
2018-02-18 15:21:18 +01:00
goto error ;
}
2018-04-03 16:59:02 +02:00
2020-02-27 13:06:29 +01:00
// we can't send the address then the data size short address will cause a stop (because of how crappy the STM32F10x I²C peripheral is)
if ( address ) {
for ( size_t i = 0 ; i < address_size ; i + + ) {
buffer [ i ] = address [ i ] ;
2018-02-18 15:21:18 +01:00
}
2017-04-03 13:07:03 +02:00
}
2020-02-27 13:06:29 +01:00
if ( data ) {
for ( size_t i = 0 ; i < data_size ; i + + ) {
buffer [ address_size + i ] = data [ i ] ;
2018-02-18 15:21:18 +01:00
}
}
2020-12-12 14:08:05 +01:00
rc = i2c_master_write ( buffer , address_size + data_size ) ; // send memory address
2020-02-27 13:06:29 +01:00
if ( I2C_MASTER_RC_NONE ! = rc ) {
goto error ;
}
2018-02-18 15:21:18 +01:00
error :
2020-12-12 14:08:05 +01:00
rc = i2c_master_stop ( ) ; // sent stop condition
2018-04-03 16:59:02 +02:00
return rc ;
2017-04-03 13:07:03 +02:00
}