cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F401 I2C driver using register

AH25
Associate

I want to use two STM32F401xx MCU in proteus. One of them is to be a master and the other is to be a slave.

This is my code for the master:

 

 #include <stdint.h>
 #include <stdio.h>
 uint8_t temp=0;
 void begin();
 void end(void);
 void Write (uint8_t);
 void star(void);
 void address(uint8_t addr);
 uint8_t value = 0x00 ;
void main() {
         begin();
         star();
         address(0x08);
         Write(0x01);
         end();
}
void begin(){
          //join I2C as a master mode
          RCC_APB1ENR |= (1<<21);  // enable I2C CLOCK
          RCC_AHB1ENR |= (1<<1);  // Enable GPIOB CLOCK
          // Configure the I2C PINs for ALternate Functions
          //PB8 and PB9 are connected to I2C1_SCL and I2C1_SDA
          GPIOB_MODER |= (1<<16)|(1<<18);
          GPIOB_OTYPER |= ((1<<8) | (1<<9));
          GPIOB_OSPEEDR |= ((3<<16) | (3<<18));
          GPIOB_PUPDR |= ((1<<16) | (1<<18));
          GPIOB_AFRH |= ((4<<0) | (4<<4));
            // Reset the I2C
            I2C1_CR1 |= (1<<15); //I2C Peripheral under reset state -->page.493 manual
            I2C1_CR1 &= ~(1<<15); //I2C Peripheral not under reset  -->page.493 manual
            // Program the peripheral input clock in I2C_CR2 Register in order to generate correct timings
            I2C1_CR2 |= (42 <<0);  // PCLK1 FREQUENCY in MHz
            I2C1_CCR |= (210<<0);  // Configure the clock control registers
            I2C1_TRISE = 43;  // Configure the rise time register
            I2C1_CR1 |= (1<<0);  // Enable I2C

}
void star(void){
              //Generate a start condition
            I2C1_CR1 |= (1<<8);  // Generate START
            while (!(I2C1_SR1 & (1<<0)));  // Wait for SB bit to set to 1
}
void address(uint8_t addr){
            I2C1_DR = addr;  //  send the address
            while (!(I2C1_SR1 & (1<<1)));// wait until the address recieved success
            temp = I2C1_SR1 | I2C1_SR2; //clear ADDR
}

 void end(void)  {

           I2C1_CR1 |= (1<<9);//stop generation
            // Wait until the STOP condition is complete
           while (I2C1_SR2 & (1<<0)); //Cleared by hardware after detecting a Stop condition on the bus
           // Clear the STOP bit
           I2C1_CR1 &= ~(1<<9);
  }

  void  Write (uint8_t dat)
  {
          while (!(I2C1_SR1 & (1<<7)));  // wait for TXE bit to set
          I2C1_DR = dat   ;  // wait for BTF bit to set
          while (!(I2C1_SR1 & (1<<2))); //waiting while BTF=0 but when BTF=1; Data byte transfer succeeded

  }

 

code for the slave:

 

 #include <stdint.h>
 #include <stdio.h>
 uint8_t temp=0;
 uint8_t state =0x00;
 void begin(uint8_t addr);
 void end(void);
 uint8_t Read ();
void main() {
          RCC_AHB1ENR |= (1<<0);  // Enable GPIOA CLOCK
          GPIOA_MODER |=(1<<0);//set pin 0 as output
          begin(0x08);
          state =  Read();
          end();
          
          if (state == 0x01){
            GPIOA_ODR |=(1<<0);//set 1 for pin 0
         }
}
void begin(uint8_t addr){
          RCC_APB1ENR |= (1<<21);  // enable I2C CLOCK -
          RCC_AHB1ENR |= (1<<1);  // Enable GPIOB CLOCK

          // Configure the I2C PINs for ALternate Functions
          //PB8 and PB9 are connected to I2C1_SCL and I2C1_SDA
          GPIOB_MODER |= (2<<16) | (2<<18);
          GPIOB_OTYPER |= (1<<8) | (1<<9);
          GPIOB_OSPEEDR |= (3<<16) | (3<<18);
          GPIOB_PUPDR |= (1<<16) | (1<<18);
          GPIOB_AFRH |= (4<<0) | (4<<4);

            I2C1_CR2 |= (42 <<0);  // PCLK1 FREQUENCY in MHz
            I2C1_CCR |= (210<<0);  // Configure the clock control registers
            I2C1_TRISE = 43;  // Configure the rise time register
            I2C1_CR1 |= (1<<0);  // Enable I2C
            //join I2C bus as a slave mode
            I2C1_OAR1 = addr;//own address interface
            I2C1_CR1 |= (1<<0);  // Enable I2C
            I2C1_CR1 |= (1<<10);  // Enable the ACK ,indicate that a byte is received
            
}
 void end(void)  {
           I2C1_CR1 |= (1<<9);//stop generation
            // Wait until the STOP condition is complete
           while (I2C1_SR2 & (1<<0)); //Cleared by hardware after detecting a Stop condition on the bus
           // Clear the STOP bit
           I2C1_CR1 &= ~(1<<9)
  }
 uint8_t Read (){
           uint8_t receivedData = 0;
          I2C1_CR1 &= ~(1<<10);  // clear the ACK bit
            temp = I2C1_SR1 | I2C1_SR2;  // read SR1 and SR2 to clear the ADDR bit.... EV6 condition
           I2C1_CR1 |= (1<<9);  // Stop I2C
            while (!(I2C1_SR1 & (1<<6)));  // wait for RxNE to set
           receivedData = I2C1_DR; // Read the data from the DATA REGISTER
        return receivedData;
     }

 

when i run the simulation there is nothing happened , the LED still off and PB8 , PB9 haven`t change , i want to know , if there any problem in my provided code, I followed the datasheet and manual of STM32F401xx to write this simple driver. is this the correct address will be passed to begin(addr) ? 

address.PNG

and this is the simulation connection in proteus:

proteus.PNG

 

 

2 REPLIES 2
SofLit
ST Employee

Hello,

You can start with using HAL or LL then if all worked fine, inspire from it to access directly to the registers.

And frankly, if I was you, I don't rely on this kind of simulation. 

I suggest to run your tests on a real HW!

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.
Andrew Neil
Evangelist

"i want to know , if there any problem in my provided code"

So what have you done to investigate & debug your code?

You're using Proteus - so you have both software & hardware debug facilities available to you...

AndrewNeil_1-1702557900138.png

 

AndrewNeil_0-1702557784456.png

https://www.labcenter.com/tutorials/ 

https://www.youtube.com/@LabcenterElectronicsLtd