cancel
Showing results for 
Search instead for 
Did you mean: 

I2C stm32F103

SIDRI.1
Associate III

Hi,

i come up with my question related to I2C communication using stm32F103,

I would like to interface my I2C LCD (slave) with MCU ( master), but i have a problem with the Transmit sequence

i have configured the GPIO's PB6 (SCL) and PB7(SDA) as open drain AF, then intialized the I2C, 

I have also followed the transmit sequence as described in the datasheet 

- Send start condition

- Check if the start condition is sent , if yes clear the SB flag by reading SR1 register (EV5).

- Transmit the slave adress ( 0x3F for LCD HDD44780 + pcf8574 ).

- Wait for ADDR flag in status register, if there was a match for this 

 slave address, clear flag by reading SR1 followed by teading SR2 ( 

 EV6)

- check if TXE is empty then send the data to data register (EV8_1)

- Check BTF flag 

this is the related code below

This is the sda and SCL traces captured with the logic analyzer. RXD--> SDA / DTR--> ClK

My questions are :

1) When i'm using the check condition : while (!(I2C1->SR1 & I2C_SR1_ADDR)) --> check if ADDR matched the slave

or while(!(I2C1->SR1 & I2C_SR1_TXE)) .

the SCL is stretched low permanently and SDA is pulled high, it seems that the master ( MCU) is blocked into these events ( EV6 or EV8_1).

but when i'm using if ((I2C1->SR1 & I2C_SR1_ADDR) ==0) with if, the problem get resolved and i can see the traces.

2) i cannot see the data that i have sent in the traces : as described in the main function I2C_send ( 0x3F, 0x55)

3) The LCD slave adress is 0x3F, but when i disconnect the LCD , i still receive the ACK ( Read and Write) as shown in the picture , is it normal ?

Thank you !

#include "stm32f10x.h"                  // Device header
#include "stdint.h"
#include <stdio.h>
 
 
void GPIO_Init(void);
void I2C1_Init(void);
void LCD_Init (void);
void DelayTimerUs1(int n);
void I2C_send (uint8_t slave_addr, uint8_t data);
void LCD_cmd(char cmd);
void LCD_Data( char Data);
 
void GPIO_Init(void)
{
	
	// Port B is used for I2C1 communication : 
	
	RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
 
	RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
	
	RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
	
    GPIOB->CRL &=~ (GPIO_CRL_MODE6_1 | GPIO_CRL_MODE7_1); 
	  GPIOB->CRL |=  GPIO_CRL_MODE6_0 | GPIO_CRL_MODE7_0;
	  GPIOB->CRL |=  GPIO_CRL_CNF6_0  | GPIO_CRL_CNF7_0;
	  GPIOB->CRL |=  GPIO_CRL_CNF6_1  | GPIO_CRL_CNF7_1;
		
}
 
void I2C1_Init(void)
	
{
	I2C1->CR1 |= I2C_CR1_SWRST;
	I2C1->CR1 &=~ I2C_CR1_SWRST;
 
	I2C1->CR2 |= 36;
 
	I2C1->CCR |= 180; // 100Khz
 
	I2C1->TRISE |= 37;
 
	I2C1->CR1 |= I2C_CR1_PE;
 
}
 
void I2C_send (uint8_t slave_addr, uint8_t data) // data can be either a command or Data
	
{
   uint16_t  temp2, temp0;
 
	//while (I2C1->SR2& I2C_SR2_BUSY){};
		
if ((I2C1->SR2 & I2C_SR2_BUSY) == 1	) {}
	
	I2C1->CR1 |= I2C_CR1_ACK;
	
	I2C1->CR1 |= I2C_CR1_START;
		
// 2) Check START condtion send
		
	while (!(I2C1->SR1 & I2C_SR1_SB)) {}
		
temp2 = I2C1->SR1;  // EV5  if the SB flag is not 1, do nothing,this means that the START //condtion was not sent yet
	
// 3) Transmit the slave addresse
		
	I2C1->DR = slave_addr; // 0x3F
 
	//while (!(I2C1->SR1 & I2C_SR1_ADDR))  // wait for ADDR flag in status register, if there was a match for this slave address, clear flag	
		
if ((I2C1->SR1 & I2C_SR1_ADDR) ==0) {}
		
  temp0 = I2C1->SR1 | I2C1->SR2;  // EV6 clear ADDR flag by reading SR2
	
 
// 4) Send the Data to data_register
		
		//while(!(I2C1->SR1 & I2C_SR1_TXE))  {}	
			
			  if ((I2C1->SR1 & I2C_SR1_TXE) == 0) {}
				
				I2C1->DR = data;
				
			if ( (I2C1->SR1 & I2C_SR1_BTF)==0){}
						
			//	while (! (I2C1->SR1 & I2C_SR1_BTF));
						
		//I2C1->CR1 = I2C_CR1_STOP;  // send another start condition if we have another //byte
		
	}
	
void LCD_cmd(char cmd){
	
 uint8_t CMD_H     = (cmd & 0xF0);   // Isoler Bit poids Fort de la cmd avec le masque 0x0F
  uint8_t CMD_Een   = (CMD_H |0x0C);  // Parametrer bit de config(poid faible), RE=1; E=1 ; 
  RW=0; RS=0
	uint8_t CMD_Edis  = (CMD_H |0x08);  // RE=1; E=0 ; RW=0; RS=0
	uint8_t CMD_Shift = ((cmd<<4) & 0xF0);
	
	I2C_send (0x3F, CMD_Een);  // envoi de la cmd avec E=1
	I2C_send (0x3F, CMD_Edis); // envoi de la cmd avec E=0;
 
	I2C_send (0x3F, CMD_Shift | 0x0C); // envoi cmd decalée (4bits de poids faible) avec E=1
	I2C_send (0x3F, CMD_Shift | 0x08); // envoi cmd decalée (4bits de poids faible) avec E=0 
		
}
 
void LCD_Data( char Data){
	
	uint8_t data_H     = (Data & 0xF0);   // Isoler Bit poids Fort de la donnée avec le masque 0x0F
  uint8_t data_Een   = (data_H |0x0D);  // Parametrer bit de config(poid faible), RE=1; E=1 ; RW=0; RS=1
	uint8_t data_Edis  = (data_H |0x09);  // RE=1; E=0 ; RW=0; RS=1
	uint8_t data_Shift = ((Data<<4) & 0xF0);
	
	I2C_send (0x3F, data_Een);  // envoi de la cmd avec E=1
	I2C_send (0x3F, data_Edis); // envoi de la cmd avec E=0;
	
	I2C_send (0x3F, data_Shift | 0x0D); // envoi data decalée avec E=1
	I2C_send (0x3F, data_Shift | 0x09); // envoi data decalée avec E=0
 
}
 
void DelayTimerUs1(int n){
	// 1 Mhz ---> 1Us
	//ARR = n (n=1 --> 1us) (n=2 --> 2us) ....
// n = 30000 for 30ms delay
	RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
	TIM2->PSC = 36;
	TIM2->ARR = n;
	TIM2->CNT = 0;
	TIM2->CR1 = TIM_CR1_CEN;
	
	for( int i =0; i<n; i++){
		
		  while (!(TIM2->SR & (1<<0))) {}
		}
	TIM2->SR &=~ (1<<0);
		
	TIM2->CR1 &=~ TIM_CR1_CEN;
	}
 
 
void LCD_Init (void)
{
	
	GPIO_Init();
	
	DelayTimerUs1(10000);  // 10 ms delay
	LCD_cmd(0x30);
	DelayTimerUs1(10000);
	LCD_cmd(0x30);
	DelayTimerUs1(10000);
	LCD_cmd(0x30);
	DelayTimerUs1(10000);
	
	
	LCD_cmd (0x28);     // 0x20 tells the lcd controller that we want to communicate in 4-bit mode with 2 lines Row
	LCD_cmd (0x02);    //  Home (move cursor to top/left character position)
	//LCD_cmd (0x14);   //   Move cursor one character right
	
}
 
 
int main (void){
	
	  GPIO_Init();
	  
	  I2C1_Init();
	
	  LCD_Init();
 
	while(1)
		
	{ 
		
		I2C_send(0x3F, 0x55);
 
		LCD_Data('s');
	
	}
	
	}

0693W00000ANH9uQAH.png

0 REPLIES 0