[AT-START-F425 Review] + Hardware I2C and software simulation I2C speed comparison
[Copy link]
1. Introduction
This article uses AT32F425 to drive SSD1306 OLED to test the I2C rate. For detailed code operations on OLED, please refer to [GD32L233C-START Review] 6. Hardware I2C drive 0.96-inch OLED .
2. About I2C of AT32F425
There are two I2Cs, this article uses I2C1.
3. I2C rate
Standard mode ( up to 100kHz )
Fast mode ( up to 400kHz )
Fast mode plus ( up to 1 MHz )
4. I2C clock
Here PCLK1 is 96MHZ
I2C clock configuration is relatively complex, so the official tool is provided
The I2C clock frequency in the tool is PCLK1, which is 96000KHZ.
5. Code implementation
(1) Hardware I2C
#define I2C_OWN_ADDRESS7 0x72
#define I2C_SLAVE_ADDRESS7 0x78
void I2cInit(void)
{
gpio_init_type gpio_init_structure;
/* i2c periph clock enable */
crm_periph_clock_enable(CRM_I2C1_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
/* gpio configuration */
gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE6, GPIO_MUX_1);
gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE7, GPIO_MUX_1);
/* configure i2c pins: scl */
gpio_init_structure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_structure.gpio_mode = GPIO_MODE_MUX;
gpio_init_structure.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
gpio_init_structure.gpio_pull = GPIO_PULL_UP;
gpio_init_structure.gpio_pins = GPIO_PINS_6;
gpio_init(GPIOB, &gpio_init_structure);
/* configure i2c pins: sda */
gpio_init_structure.gpio_pins = GPIO_PINS_7;
gpio_init(GPIOB, &gpio_init_structure);
/* reset i2c peripheral */
i2c_reset(I2C1);
/* config i2c */
//0x2170FAFA //10K
//0x80E06565 //50K
//0x80E03030 //100K
//0x20E0355F //200K
//0x20E0192C //400k
//0x10900E19 //1000k
//0x10900C16 //1000k
i2c_init(I2C1, 0, 0x10900C16);
i2c_own_address1_set(I2C1, I2C_ADDRESS_MODE_7BIT, I2C_OWN_ADDRESS7);
/* i2c peripheral enable */
i2c_enable(I2C1, TRUE);
}
void OledWriteCmd(uint8_t var)
{
/* wait for the busy falg to be reset */
while(i2c_flag_get(I2C1, I2C_BUSYF_FLAG) );
/* start transfer */
i2c_transmit_set(I2C1, I2C_SLAVE_ADDRESS7, 2, I2C_SOFT_STOP_MODE, I2C_GEN_START_WRITE);
i2c_start_generate(I2C1);
while(i2c_flag_get(I2C1, I2C_ADDRF_FLAG) );
while(!i2c_flag_get(I2C1, I2C_TDIS_FLAG) );
i2c_data_send(I2C1, 0x00);
while(!i2c_flag_get(I2C1, I2C_TDIS_FLAG) );
i2c_data_send(I2C1, var);
i2c_stop_generate(I2C1);
while(!i2c_flag_get(I2C1, I2C_STOPF_FLAG) );
i2c_flag_clear(I2C1, I2C_STOPF_FLAG);
}
void OledWriteData(uint8_t var)
{
/* wait for the busy falg to be reset */
while(i2c_flag_get(I2C1, I2C_BUSYF_FLAG) );
/* start transfer */
i2c_transmit_set(I2C1, I2C_SLAVE_ADDRESS7, 2, I2C_AUTO_STOP_MODE, I2C_GEN_START_WRITE);
while(!i2c_flag_get(I2C1, I2C_TDIS_FLAG) );
i2c_data_send(I2C1, 0x40);
while(!i2c_flag_get(I2C1, I2C_TDIS_FLAG) );
i2c_data_send(I2C1, var);
while(!i2c_flag_get(I2C1, I2C_STOPF_FLAG) );
i2c_flag_clear(I2C1, I2C_STOPF_FLAG);
}
When using hardware I2C, configure it to a 1MHz rate.
(2) Software I2C
#define _SCL_PORT GPIOB
#define _SCL_PIN GPIO_PINS_6
#define _SDA_PORT GPIOB
#define _SDA_PIN GPIO_PINS_7
void _I2C_Init(void)
{
gpio_init_type gpio_init_struct;
/* enable the led clock */
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
/* set default parameter */
gpio_default_para_init(&gpio_init_struct);
/* configure the led gpio */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_6|GPIO_PINS_7;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
}
void _SDA_IN(void)
{
gpio_init_type gpio_init_struct;
/* enable the led clock */
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
/* set default parameter */
gpio_default_para_init(&gpio_init_struct);
/* configure the led gpio */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_7;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
}
void _SDA_OUT(void)
{
gpio_init_type gpio_init_struct;
/* enable the led clock */
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
/* set default parameter */
gpio_default_para_init(&gpio_init_struct);
/* configure the led gpio */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_7;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
}
void _I2C_Start(void)
{
_SDA_OUT(); //
gpio_bits_set(_SDA_PORT,_SDA_PIN); //SDA=1
delay_us(10);
gpio_bits_set(_SCL_PORT,_SCL_PIN); //SCL=1
delay_us(10);
gpio_bits_reset(_SDA_PORT,_SDA_PIN);//SDA=0
delay_us(10);
gpio_bits_reset(_SCL_PORT,_SCL_PIN);//SCL=0
delay_us(10);
}
void _I2C_Stop(void)
{
_SDA_OUT();
gpio_bits_reset(_SDA_PORT,_SDA_PIN);//SDA=0
delay_us(10);
gpio_bits_set(_SCL_PORT,_SCL_PIN); //SCL=1
delay_us(10);
gpio_bits_set(_SDA_PORT,_SDA_PIN); //SDA=1
delay_us(10);
}
void _I2C_Ack(void)
{
_SDA_OUT();
gpio_bits_reset(_SDA_PORT,_SDA_PIN);//SDA=0
delay_us(5);
gpio_bits_set(_SCL_PORT,_SCL_PIN); //SCL=1
delay_us(5);
gpio_bits_reset(_SCL_PORT,_SCL_PIN); //SCL=0
}
void _I2C_NAck(void)
{
gpio_bits_set(_SDA_PORT,_SDA_PIN); //SDA=1
delay_us(10);
gpio_bits_set(_SCL_PORT,_SCL_PIN); //SCL=1
delay_us(10);
gpio_bits_reset(_SCL_PORT,_SCL_PIN); //SCL=0
delay_us(10);
}
uint8_t _I2C_Wait_Ack(void)
{
uint8_t ucErrTime=0;
gpio_bits_set(_SDA_PORT,_SDA_PIN); //释放总线
_SDA_IN();
delay_us(5);
gpio_bits_set(_SCL_PORT,_SCL_PIN); //SCL=1
delay_us(5);
while(gpio_input_data_bit_read(_SDA_PORT,_SDA_PIN)) //gpio_input_data_bit_read
{
ucErrTime++;
if(ucErrTime>250)
{
_I2C_Stop();
return 1;
}
}
gpio_bits_reset(_SCL_PORT,_SCL_PIN); //SCL=0
delay_us(5);
return 0;
}
uint8_t _I2C_Read_Byte(uint8_t ack)
{
uint8_t i,rxdata=0;
gpio_bits_set(_SDA_PORT,_SDA_PIN); //释放总线
_SDA_IN();
for(i=0;i<8;i++ )
{
gpio_bits_reset(_SCL_PORT,_SCL_PIN); //SCL=0
delay_us(5);
gpio_bits_set(_SCL_PORT,_SCL_PIN); //SCL=1
delay_us(5);
rxdata<<=1;
if(gpio_input_data_bit_read(_SDA_PORT,_SDA_PIN))
{
rxdata|=0x01;
}
delay_us(5);
}
if (!ack)
_I2C_NAck();//nACK
else
_I2C_Ack(); //ACK
return rxdata;
}
void _I2C_Send_Byte(uint8_t txd)
{
uint8_t i;
_SDA_OUT();
gpio_bits_reset(_SCL_PORT,_SCL_PIN); //SCL=0
for(i=0;i<8;i++)
{
if((txd&0x80)==0x80)
gpio_bits_set(_SDA_PORT,_SDA_PIN);
else
gpio_bits_reset(_SDA_PORT,_SDA_PIN);
txd<<=1;
delay_us(5);
gpio_bits_set(_SCL_PORT,_SCL_PIN); //SCL=1
delay_us(5);
gpio_bits_reset(_SCL_PORT,_SCL_PIN); //SCL=0
delay_us(5);
}
}
void _SSD1306_WriteCmd(uint8_t var)
{
_I2C_Start();
_I2C_Send_Byte(I2C_SLAVE_ADDRESS7); //write addr
_I2C_Wait_Ack();
_I2C_Send_Byte(0x00);
_I2C_Wait_Ack();
_I2C_Send_Byte(var);
_I2C_Wait_Ack();
_I2C_Stop();
}
void _SSD1306_WriteData(uint8_t var)
{
_I2C_Start();
_I2C_Send_Byte(I2C_SLAVE_ADDRESS7); //write addr
_I2C_Wait_Ack();
_I2C_Send_Byte(0x40);
_I2C_Wait_Ack();
_I2C_Send_Byte(var);
_I2C_Wait_Ack();
_I2C_Stop();
}
6. Speed test
Here we use the logic analyzer to capture packets directly.
(1) Hardware I2C
It can be seen that the rate jumps between 800kHz and 1MHz.
(2) Software I2C
It can be seen that the rate is between 58kHz and 59kHz.
From the above comparative measurements, we can find that the hardware I2C rate is greater than the software I2C. Therefore, in order to improve the CPU utilization, hardware I2C should be used as much as possible.
|