2023-03-03 09:05 AM
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;
}
Solved! Go to Solution.
2023-03-06 07:14 AM
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.
2023-03-06 07:14 AM
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.
2023-03-29 12:58 AM
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;
}