GD32450i-EVAL学习笔记 5 - I2C Master(硬件)

21 篇文章 36 订阅

目录

1 GPIO初始化

2 I2C初始化

2.1 RCU使能

2.2 频率设置

2.3 地址模式设置

2.4 使能I2C

2.5 使能ACK

3 I2C读

3.1 等待I2C空闲

 3.2 发送START起始位

3.3 发送slaveAddr

3.4 发送addr

3.5 再发送一次START

3.6 发送slaveAddr

3.7 接收数据

3.8 发送STOP

4 I2C写


2GD32F450最多支持3组硬件I2C,支持标速(100KHz)和快速(400KHz)。

1 GPIO初始化

以I2C0为例

//B6: SCL, B7: SDA
gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_6 | GPIO_PIN_7);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6 | GPIO_PIN_7);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);

2 I2C初始化

2.1 RCU使能

rcu_periph_clock_enable(RCU_I2C0);

2.2 频率设置

对应的API函数

void i2c_clock_config(uint32_t i2c_periph, uint32_t clkspeed, uint32_t dutycyc)

clkspeed最大400KHz。dutycyc仅对Fast模式有效,有2个值:I2C_DTCY_2和I2C_DTCY_16_9,分别表示占空比2(L)/ 2(H)和16(L)/9(L)。

i2c_clock_config(i2cmGroup[port], (uint32_t)baud, I2C_DTCY_2);

2.3 地址模式设置

void i2c_mode_addr_config(uint32_t i2c_periph, uint32_t mode, uint32_t addformat, uint32_t addr)

 mode: I2C_I2CMODE_ENABLE - I2C模式;I2C_SMBUSMODE_ENABLE - SMBUS模式

addformat:I2C_ADDFORMAT_7BITS - 7位地址模式,常用; I2C_ADDFORMAT_10BITS - 10位地址模式

addr:I2C地址

i2c_mode_addr_config(i2cmGroup[port], I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0);

2.4 使能I2C

i2c_enable(i2cmGroup[port]);

2.5 使能ACK

i2c_ack_config(i2cmGroup[port], I2C_ACK_ENABLE);

3 I2C读

实现读函数

bool_t i2cRead(uint8_t port, uint8_t slaveAddr, uint8_t addrbit, uint16_t addr, uint8_t *pdata, uint16_t len)
{
    
}

port:对应I2C的端口号,0-2

slaveAddr:I2C从设备地址

addrbit:设备内部地址宽度,有效值0,8,16

addr:设备内部地址

pdate:读入数据buffer指针

len:读入数据长度

注意,I2C初始化完后默认是使能ACK的。 

3.1 等待I2C空闲

while(i2c_flag_get(i2cmGroup[port], I2C_FLAG_I2CBSY));

 3.2 发送START起始位

i2c_start_on_bus(i2cmGroup[port]);
while(!i2c_flag_get(i2cmGroup[port], I2C_FLAG_SBSEND));

 使能I2C后I2C默认处于从设备的模式,发送一个START后,I2C硬件会设置SBSEND位然后进入主机模式。

3.3 发送slaveAddr

if(addrbit > 0)
{
    i2c_master_addressing(i2cmGroup[port], slaveAddr, I2C_TRANSMITTER);
    while(!i2c_flag_get(i2cmGroup[port], I2C_FLAG_ADDSEND));
    i2c_flag_clear(i2cmGroup[port],I2C_FLAG_ADDSEND);
    while(SET != i2c_flag_get(i2cmGroup[port], I2C_FLAG_TBE));
    ...    
}

 I2C_TRANSMITTER表示接下来是写,如果从设备的内部地址大于0,则表示接下来是需要写入这个地址的。然后等待I2C硬件设置ADDSEND标志位为1,为1后软件清除这个标志位,最后等待I2C的发送数据缓冲为空(I2C_FLAG_TBE)。

3.4 发送addr

if(addrbit == 16)
{
    i2c_data_transmit(i2cmGroup[port], (uint8_t)(addr >> 8));
    while(!i2c_flag_get(i2cmGroup[port], I2C_FLAG_BTC));
}
i2c_data_transmit(i2cmGroup[port], (uint8_t)(addr & 0xff));
while(!i2c_flag_get(i2cmGroup[port], I2C_FLAG_BTC));

3.5 再发送一次START

i2c_start_on_bus(I2C0);
while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));

如果地址大于0才需要再发送一次START,以便再写入SlaveAddr开启读数据过程。

3.6 发送slaveAddr

i2c_master_addressing(i2cmGroup[port], slaveAddr, I2C_RECEIVER);
while(!i2c_flag_get(i2cmGroup[port], I2C_FLAG_ADDSEND));
if(len == 1)
    i2c_ack_config(i2cmGroup[port],I2C_ACK_DISABLE);
i2c_flag_clear(i2cmGroup[port],I2C_FLAG_ADDSEND); 

 这里I2C_RECEIVER表示接下来是读数据。

在清除I2C_FLAG_ADDSEND前还需要判断一下需要读多少数据,如果是最后一个字节,需要把ACK关掉,这样读完最后一个字节发送的是NACK了。

3.7 接收数据

while(len > 0)
{
    if(i2c_flag_get(i2cmGroup[port], I2C_FLAG_RBNE))
    {
        if(len == 2)
            i2c_ack_config(i2cmGroup[port],I2C_ACK_DISABLE);
        *pdata = i2c_data_receive(i2cmGroup[port]);
        pdata++;
        len--;
    }
}

 当len等于2时,倒数第二个数据已经被写入DATA寄存器,ACK已经完成,在读DATA寄存器前将ACK设置为Disable,这样接下来读完DATA寄存器,I2C硬件会继续读入最后一个字节数据并发送NACK。

3.8 发送STOP

i2c_stop_on_bus(i2cmGroup[port]);
while(I2C_CTL0(i2cmGroup[port])&0x0200);
i2c_ack_config(i2cmGroup[port], I2C_ACK_ENABLE);

所有数据读完后,发送STOP,并等待结束,最后恢复ACK使能。

4 I2C写

流程与读类似,区别是只需要写一次salveAddr,也不需要处理ACK的使能。

bool_t i2cWrite(uint8_t port, uint8_t slaveAddr, uint8_t addrbit, uint16_t addr, uint8_t *pdata, uint16_t len)
{
    if(port >= HW_I2C_MAX)
        return FALSE;
    
    while(i2c_flag_get(i2cmGroup[port], I2C_FLAG_I2CBSY));
    
    i2c_start_on_bus(i2cmGroup[port]);
    while(!i2c_flag_get(i2cmGroup[port], I2C_FLAG_SBSEND));
    
    i2c_master_addressing(i2cmGroup[port], slaveAddr, I2C_TRANSMITTER);
    while(!i2c_flag_get(i2cmGroup[port], I2C_FLAG_ADDSEND));
    i2c_flag_clear(i2cmGroup[port],I2C_FLAG_ADDSEND);
    while(SET != i2c_flag_get(i2cmGroup[port] , I2C_FLAG_TBE));
    
    if(addrbit > 0)
    {
        if(addrbit == 16)
        {
            i2c_data_transmit(i2cmGroup[port], (uint8_t)(addr >> 8));
            while(!i2c_flag_get(i2cmGroup[port], I2C_FLAG_BTC));
        }
        i2c_data_transmit(i2cmGroup[port], (uint8_t)(addr & 0xff));
        while(!i2c_flag_get(i2cmGroup[port], I2C_FLAG_BTC));
    }
    
    while(len > 0)
    {
        i2c_data_transmit(i2cmGroup[port], *pdata);
        while(!i2c_flag_get(i2cmGroup[port], I2C_FLAG_BTC));
        pdata++;
        len--;
    }
    
    i2c_stop_on_bus(I2C0);
    while(I2C_CTL0(I2C0)&0x0200);
}

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值