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:
Uusing (MicroC Pro For Arm
) program.
#include <stdint.h>
#include <stdio.h>
uint8_t temp=0;
void begin(uint8_t addr);
void end(void);
void Write (uint8_t dat);
void main() {
// Enable the I2C CLOCK and GPIO CLOCK
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);
begin(0x08);
Write(0x01);
end();
}
void begin(uint8_t addr){
//join I2C as a master mode
//Generate a start condition
I2C1_CR1 |= (1<<10); // Enable the ACK
I2C1_CR1 |= (1<<8); // Generate START
while (!(I2C1_SR1 & (1<<0))); // Wait for SB bit to set to 1
//Send the Slave Address to the DR Register
I2C1_DR = addr; // send the address
while (!(I2C1_SR1 & (1<<1))); //
temp = I2C1_SR1 | I2C1_SR2; // read SR1 and SR2 to clear the ADDR bit
// 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 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_APB1ENR |= (1<<21); // enable I2C CLOCK -
RCC_AHB1ENR |= (1<<1); // Enable GPIOB CLOCK
RCC_AHB1ENR |= (1<<0); // Enable GPIOA CLOCK
GPIOA_MODER |=(1<<0); //set pin 0 as output
// 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);
begin(0x08);
state = Read();
end();
if (state == 0x01){
GPIOA_ODR |=(1<<0);//set 1 for pin 0
}
}
void begin(uint8_t addr){
//join I2C bus as a slave mode
I2C1_CR2 |= (42<<0); // PCLK1 FREQUENCY in MHz
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;
}
I try to make a simulation on Proteus, but there is nothing to change, the led still off
. So, I want to know how I make the simulation
on Proteus, and if there any problem in my provided code, I followed the datasheet
and manual
of STM32F401xx to write this simple driver.
proteus
connection of two STM32F401xx MCU :
Your master's "begin" function does something strange. How is
I2C1_TRISE = 43;
after you set the start bit? You are trying to use I2C before you configure it. TRISE must be one of the first things you do to I2C before you use any acknowledge or start bits. The whole function does things in weird order."Start bit" in the register doesn't enable start bit functionality. It physically tries to send a start bit immediately when you write to it, and in your code, it happens before you you set TRISE or even before you enable I2C peripheral. Thus the behavior is unpredictable.
I checked out the peripheral of F401, it's exactly identical to the one of F103 with the exception that F401 has one extra register for analog & digital noise filter controls. Other than that, they are identical and map one to another perfectly. (and F401 doesn't have the same silicon bug as F103 with filter glitch, as per errata sheets).
So here is the sequence of actions I do to use this peripheral, skipping the obvious GPIO alternate function setup, so only I2C registers here. This is I2C master config, but the general setup is the same, the difference between slave and master device configuration comes after these necessary steps:
Now if you write start bit, you can load data into DR and have it sent as a master. You don't need to write anything into Start bit until now, and you don't need to write anything into ACK bit, those bits are used in the middle of ongoing communication, not for configuration.
For a slave, you do similar setup, but also need to configure its slave address, obviously.
I think you're rushing too much. Start with just a master MCU and make sure you can see something on the I2C lines first.