cancel
Showing results for 
Search instead for 
Did you mean: 

How to configure I2C on STM32L4 Discovery kit IoT node using register

Nickos
Associate

Hello everyone, I have a B-L475E-IOT01A board and I'm trying to configure I2C to communicate with a digital barometer (LPS22HB). But I have a problem, I can't get the SCL signal to be generated. I appreciate your help in solving my problem

#include <stdio.h>
#include <stm32l4xx.h>
 
void system_clock_msi_init(void)
{
    RCC->CR |= RCC_CR_MSION; // MSI clock enable
    RCC->CFGR |= RCC_CFGR_SW_MSI; // MSI oscillator selection as system clock
    while((RCC->CR & RCC_CR_MSIRDY) == 0);
    RCC->CR &= RCC_CR_MSIRANGE_Pos; 
    RCC->CR |= RCC_CR_MSIRANGE_7; // MSI clock ranges 7 around 8 MHz
    RCC->CR |= RCC_CR_MSIRGSEL; // Internal Multi Speed oscillator (MSI) range selection
    while((RCC->CR & RCC_CR_MSIRDY) == 0);
}
 
void clock_enable_init(void)
{
    RCC->APB1ENR1 |= RCC_APB1ENR1_I2C2EN; // enable I2C Clock
    RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN; // enable GPIOB Clock
    RCC->CCIPR |= RCC_CCIPR_I2C2SEL_0 ; // System clock (SYSCLK) selected as I2C2 clock
}
 
void GPIO_I2C_Init(void)
{
    GPIOB->MODER = 0xFF0FFEBF; //  Reset MODER B
    GPIOB->MODER |= GPIO_MODER_MODE10_1 | GPIO_MODER_MODE11_1; // Alternate function mode
    GPIOB->OTYPER |= GPIO_OTYPER_OT10 | GPIO_OTYPER_OT11; // Output open-drain
    GPIOB->OSPEEDR |= GPIO_OSPEEDR_OSPEED10_Msk |  GPIO_OSPEEDR_OSPEED11_Msk; // Very high speed
    GPIOB->PUPDR |= GPIO_PUPDR_PUPD10_0 | GPIO_PUPDR_PUPD11_0; // pull-up
    GPIOB->AFR[0] |= GPIO_AFRL_AFSEL4_2;
}
 
void I2C_Config (void)
{ 
    I2C2->CR1 |= I2C_CR1_PE; // Peripheral enable
    while((I2C2->CR1 & I2C_CR1_PE) == 0);
    I2C2->CR1 &= I2C_CR1_PE_Pos; // Peripheral  not enable, Reset the I2C
    while((I2C2->CR1 & I2C_CR1_PE) == 1);
 
    I2C2->CR1 &= I2C_CR1_ANFOFF_Pos; // Analog noise filter ON      
    I2C2->CR1 &= I2C_CR1_DNF_Pos; // Digital noise filter OFF
 
    I2C2->TIMINGR |= 0x0 << I2C_TIMINGR_PRESC_Pos;
    I2C2->TIMINGR |= 0x9 << I2C_TIMINGR_SCLL_Pos;
    I2C2->TIMINGR |= 0x3 << I2C_TIMINGR_SCLH_Pos;
    I2C2->TIMINGR |= 0x1 << I2C_TIMINGR_SDADEL_Pos;
    I2C2->TIMINGR |= 0x3 << I2C_TIMINGR_SCLDEL_Pos;
 
    I2C2->CR1 |= I2C_CR1_NOSTRETCH; // Clock stretching disable  
 
    I2C2->CR1 |= I2C_CR1_PE; // Peripheral enable
    while((I2C2->CR1 & I2C_CR1_PE) == 0);
}
 
void I2C_Master_Init(void)
{
    I2C2->CR2 &= ~I2C_CR2_ADD10;  // 0: The master operates in 7-bit addressing mode
    I2C2->CR2 |=  0xBA << I2C_CR2_SADD_Pos; // slave address 1011101b  
    I2C2->CR2 &= ~I2C_CR2_RD_WRN; // 0: Master requests a write transfer
    I2C2->CR2 |=  0x1 << I2C_CR2_NBYTES_Pos; // The number of bytes is 1
}
 
int main(void) 
{
    system_clock_msi_init();
    clock_enable_init();
    GPIO_I2C_Init();
    I2C_Config();
    I2C_Master_Init();
 
    while(1)
    {   
        I2C2->CR2 |=  I2C_CR2_START; // Generate START
        while (!(I2C2->ISR & I2C_ISR_BUSY));
        I2C2->TXDR = 0xBA;
        while(!(I2C2->ISR & I2C_ISR_TXIS));
    }
    return 0;
}

1 ACCEPTED SOLUTION

Accepted Solutions
Foued_KH
ST Employee

Hello @Nickos​ ,

First of all ,for the Start you need to enable the ACK :

1. Send the START condition 

2. Wait for the SB ( Bit 0 in SR1) to set. This indicates that the start condition is generated

I2C1->CR1 |= (1<<10);  // Enable the ACK
I2C1->CR1 |= (1<<8);  // Generate START
while (!(I2C1->SR1 & (1<<0)));  // Wait fror SB bit to set

Then you should send the address :

I2C1->DR = Address;  //  send the address
while (!(I2C1->SR1 & (1<<1)));  // wait for ADDR bit to set
uint8_t temp = I2C1->SR1 | I2C1->SR2;  // read SR1 and SR2 to clear the ADDR bit

And finally for the Write :

1. Wait for the TXE (bit 7 in SR1) to set. This indicates that the DR is empty

2. Send the DATA to the DR Register

3. Wait for the BTF (bit 2 in SR1) to set. This indicates the end of LAST DATA transmission

while (!(I2C1->SR1 & (1<<7))); // wait for TXE bit to set
I2C1->DR = data;
while (!(I2C1->SR1 & (1<<2))); // wait for BTF bit to set

Foued.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

View solution in original post

2 REPLIES 2
Foued_KH
ST Employee

Hello @Nickos​ ,

First of all ,for the Start you need to enable the ACK :

1. Send the START condition 

2. Wait for the SB ( Bit 0 in SR1) to set. This indicates that the start condition is generated

I2C1->CR1 |= (1<<10);  // Enable the ACK
I2C1->CR1 |= (1<<8);  // Generate START
while (!(I2C1->SR1 & (1<<0)));  // Wait fror SB bit to set

Then you should send the address :

I2C1->DR = Address;  //  send the address
while (!(I2C1->SR1 & (1<<1)));  // wait for ADDR bit to set
uint8_t temp = I2C1->SR1 | I2C1->SR2;  // read SR1 and SR2 to clear the ADDR bit

And finally for the Write :

1. Wait for the TXE (bit 7 in SR1) to set. This indicates that the DR is empty

2. Send the DATA to the DR Register

3. Wait for the BTF (bit 2 in SR1) to set. This indicates the end of LAST DATA transmission

while (!(I2C1->SR1 & (1<<7))); // wait for TXE bit to set
I2C1->DR = data;
while (!(I2C1->SR1 & (1<<2))); // wait for BTF bit to set

Foued.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Thank you for your response. @KHALSI_Foued it helped me.

Here's what I got

#include <stdio.h>
#include <stm32l4xx.h>
 
#define WHO_AM_I 0x0F
#define Addres 0xBA
uint8_t data_read;
 
 
 
void system_clock_msi_init(void)
{
    RCC->CR |= RCC_CR_MSION; // MSI clock enable
    RCC->CFGR |= RCC_CFGR_SW_MSI; 
    while((RCC->CR & RCC_CR_MSIRDY) == 0);
    RCC->CR &= RCC_CR_MSIRANGE_Pos; 
    //RCC->CR |= RCC_CR_MSIRANGE_7; 
    RCC->CR |= RCC_CR_MSIRANGE_8;
    //RCC->CR |= RCC_CR_MSIRANGE_11;
    RCC->CR |= RCC_CR_MSIRGSEL;
    while((RCC->CR & RCC_CR_MSIRDY) == 0);
}
 
void clock_enable_init(void)
{
    RCC->CCIPR |= RCC_CCIPR_I2C2SEL_0 ;
    RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;
    RCC->APB1ENR1 |= RCC_APB1ENR1_I2C2EN;
}
 
 
void GPIO_I2C_Init(void)
{
    GPIOB->MODER &= ~GPIO_MODER_MODE10_Msk 
    & ~GPIO_MODER_MODE11_Msk; 
    GPIOB->MODER |= GPIO_MODER_MODE10_1 
    | GPIO_MODER_MODE11_1; 
    GPIOB->OTYPER |= GPIO_OTYPER_OT10 
    | GPIO_OTYPER_OT11;
    GPIOB->OSPEEDR |= GPIO_OSPEEDR_OSPEED10_Msk 
    | GPIO_OSPEEDR_OSPEED11_Msk; 
    GPIOB->PUPDR &= ~GPIO_PUPDR_PUPD10_Msk 
    & ~GPIO_PUPDR_PUPD11_Msk; 
    GPIOB->AFR[1] |= GPIO_AFRH_AFSEL10_2  
    | GPIO_AFRH_AFSEL11_2; 
}
 
 
void I2C_Intit_Seting(void)
{
    /* Software reset *//*
    I2C2->CR1 |= I2C_CR1_PE; // Peripheral enable
    while((I2C2->CR1 & I2C_CR1_PE) == 0);
    I2C2->CR1 &= I2C_CR1_PE_Pos; // Peripheral  not enable, Reset the I2C
    while((I2C2->CR1 & I2C_CR1_PE) == 1);
    */
 
    I2C2->CR1 |= I2C_CR1_DNF; // Digital noise filter ON
    I2C2->CR1 |= I2C_CR1_ANFOFF; // Analog noise filter ON  
     
    /* Timings settings for fI2CCLK = 16 MHz mode 10 kHz*/
    I2C2->TIMINGR |= 0x3 << I2C_TIMINGR_PRESC_Pos;
    I2C2->TIMINGR |= 0xC7 << I2C_TIMINGR_SCLL_Pos;   
    I2C2->TIMINGR |= 0xC3 << I2C_TIMINGR_SCLH_Pos;
    I2C2->TIMINGR |= 0x2 << I2C_TIMINGR_SDADEL_Pos;
    I2C2->TIMINGR |= 0x4 << I2C_TIMINGR_SCLDEL_Pos;
 
    /* Timings settings for fI2CCLK 16 MHz mode 100 kHz*//*
    I2C2->TIMINGR |= 0x13 << I2C_TIMINGR_SCLL_Pos;   
    I2C2->TIMINGR |= 0xF << I2C_TIMINGR_SCLH_Pos;
    I2C2->TIMINGR |= 0x2 << I2C_TIMINGR_SDADEL_Pos;
    I2C2->TIMINGR |= 0x4 << I2C_TIMINGR_SCLDEL_Pos;
    I2C2->TIMINGR |= 0xB << I2C_TIMINGR_PRESC_Pos;
    */
 
    I2C2->CR1 &= ~I2C_CR1_NOSTRETCH;  
    I2C2->CR1 |= I2C_CR1_PE; // Peripheral enable
    while((I2C2->CR1 & I2C_CR1_PE) == 0);
}
 
void Master_init(void)
{
    I2C_Intit_Seting();
    /*Enable interrupts*/
    I2C2->CR1 |= I2C_CR1_ERRIE; 
    I2C2->CR1 |= I2C_CR1_TCIE;
    I2C2->CR1 |= I2C_CR1_STOPIE; 
    I2C2->CR1 |= I2C_CR1_NACKIE; 
    I2C2->CR1 |= I2C_CR1_TXIE; 
    I2C2->CR1 |= I2C_CR1_RXIE; 
}
 
 
void I2C_Master_transmit(uint8_t SADD, uint8_t Size)
{
    I2C2->CR2 &= ~I2C_CR2_ADD10;  
    I2C2->CR2 |=  Addres << I2C_CR2_SADD_Pos;
    I2C2->CR2 &= ~I2C_CR2_RD_WRN;
    I2C2->CR2 |=  Size << I2C_CR2_NBYTES_Pos; 
    I2C2->CR2 &= ~I2C_CR2_AUTOEND_Msk;
    I2C2->CR2 |=  I2C_CR2_START;
    
    while(!(I2C2->ISR & (I2C_ISR_TXIS & ~I2C_ISR_NACKF)));
    while(Size > 0)
    {
        I2C2->TXDR = WHO_AM_I;
        Size--;
    } 
    while(!(I2C2->ISR & I2C_ISR_TC));
}
 
void I2C_Master_receiver(uint8_t SADD, uint8_t Size)
{
    I2C2->CR2 |=  Addres << I2C_CR2_SADD_Pos;
    I2C2->CR2 |=  0x1 << I2C_CR2_NBYTES_Pos; 
    I2C2->CR2 &= ~I2C_CR2_AUTOEND_Msk;
    I2C2->CR2 |=  I2C_CR2_RD_WRN;
    I2C2->CR2 |=  I2C_CR2_START;
    while(!(I2C2->ISR & I2C_ISR_RXNE));
    while(Size > 0)
    {
         data_read = I2C2->RXDR;
         Size--;
    }
    while(!(I2C2->ISR & I2C_ISR_TC));
    I2C2->CR2 |= I2C_CR2_STOP;
    while(!(I2C2->ISR & I2C_ISR_STOPF));
    I2C2->ICR |= I2C_ICR_STOPCF;
}
 
 
int main(void)
{
    system_clock_msi_init();
    clock_enable_init();
    GPIO_I2C_Init();
    Master_init();
 
    while(1)
    {
        I2C_Master_transmit(Addres,1);
        I2C_Master_receiver(Addres,1);
    }
    return 0;
}