PotatoPie 4.0 实验教程(44) —— FPGA实现RISC-V 扩展I2C功能-Anlogic-安路社区-FPGA CPLD-ChipDebug

PotatoPie 4.0 实验教程(44) —— FPGA实现RISC-V 扩展I2C功能

手机扫码

20240416075513933-1713225291635

链接直达

https://item.taobao.com/item.htm?ft=t&id=776516984361

工程介绍

该工程主要用于验证RISC-V的I2C读写测试。该工程首先向OV5640这个摄像头sensor发送读取ID的指令,然后获取返回的ID值来确认I2C读写是否正常,正常读出的值应是0x5640。

APB-I2C_Master软核介绍

RISC-V中的I2C硬件电路是通过在FPGA中启用安路的APB-I2C_Master软核来实现的,我们的RISC-V TD demo工程中默认开启了该配置。该IP的代码是开放的,就在工程中,可以自行查看。

APB-I2C Master 外设,其结构框图如下图所示:

20240610152445361-image

其寄存器地址分配和功能描述如下表所示

APB-I2C_Master 寄存器分配表

地址 功能
0x0 I2C 控制寄存器
0x4 I2C 命令状态寄存器
0xC I2C 收发缓存
0x0 I2C 控制寄存器
[31:24] [23] [22] [21:16] [15:0]
保留 I2C 模块使能 I2C 中断使能 保留 I2C 分频计数值
0x4 I2C 命令状态寄存器
[15] [14] [13] [12:10] [9] [8] [7:0]
接收 ACK I2C 模块忙 仲裁失败 保留 发送忙 中断标志 命令
I2C 命令定义
[7] [6] [5] [4] [3] [2:1] [0]
启动传输 终止传输 执行读 执行写 ACK 选择 保留 中断清除
0xC I2C 收发缓存
读取 I2C 接收缓存
写入 I2C 发送缓存

I2C速率分频值计算

以100KHZ的I2C为例,其分频寄存器的值计算式为:𝐶_𝑃𝑟𝑒𝑠𝑐𝑎𝑙𝑒 = f_sysclk/(5*100kHZ) -1, 其中f_sysclk为系统时钟,

代码分析

代码的其它部分与前面的UART和SPI工程没有什么差别,都是先打印banner信息,主要区别是这个工程中添加了红框中的代码。

20240610151742122-image

红框中的代码一一解释如下:

ov5640_PWDN_GPIO_PORT->GPIO_INTMASK =0x00000000;用于设置GPIO的中断

ov5640_PWDN_GPIO_PORT->OUTPUT_ENABLE=0x000000FF; 配置GPIO的输出使能

下面这三代码用于测试GPIO的输出,方便调试。

ov5640_PWDN_GPIO_PORT->OUTPUT |=0x00000003;
ov5640_PWDN_GPIO_PORT->OUTPUT =0x00000000;
ov5640_PWDN_GPIO_PORT->OUTPUT |=0x00000003;

i2c_init(I2C, SYS_FREQ/(5*300000), True, False); 初始化I2C接口

ov5640_init(); 初始化OV5640摄像头,这部分实现的功能与前面纯FPGA代码初始化摄像头的功能是一样的,验证ID读取的功能也是在ov5640_init()中实现的。

RISC-V I2C相关函数说明

下面是I2C所有相关函数的说明,代码是开放的,可以自行查看。

i2c_init(I2c_Reg *reg, uint16_t psc, uint8_t i2c_enable,uint8_t int_enable)
参数 *reg I2c_Reg 寄存器指针
psc I2C 分频器计数值 Psc = 𝑓𝑆𝑦𝑠
5∗100𝐾𝐻𝑧
i2c_enable I2C 使能,非 0 则使能
int_enable I2C 操作完成中断使能,非 0 则使能
返回值
文件 StdPeriphLib/i2c.h
作用 进行 I2C 配置
uint8_t i2c_flag_get(I2c_Reg *reg,uint8_t req)
参数 *reg I2c_Reg 寄存器指针
req 读取目标选择
RXACK 从机响应 BUSY I2C 控制器忙 TIP 传输进行中 IRQ 中断等待)
返回值 返回非零,对应状态有效
文件 StdPeriphLib/i2c.h
作用 读取 I2C 状态
i2c_write_addr(I2c_Reg *reg,uint8_t addr,uint8_t dir)
参数 *reg I2c_Reg 寄存器指针
addr 从机地址
dir 数据读写选择
返回值
文件 StdPeriphLib/i2c.h
作用 启动传输,并向 I2C 总线发送地址
i2c_data_transmit(I2c_Reg *reg,uint8_t data)
参数 *reg I2c_Reg 寄存器指针
data 发送数据
返回值
文件 StdPeriphLib/i2c.h
作用 I2C 发送数据
uint8_t i2c_data_receive(I2c_Reg *reg)
参数 *reg I2c_Reg 寄存器指针
返回值 接收数据字节
文件 StdPeriphLib/i2c.h
作用 进行 I2C 接收
i2c_send_stop(I2c_Reg *reg)
参数 *reg I2c_Reg 寄存器指针
返回值
文件 StdPeriphLib/i2c.h
作用 I2C 总线停止传输
i2c_clear_intflag(I2c_Reg *reg)
参数 *reg I2c_Reg 寄存器指针
返回值
文件 StdPeriphLib/i2c.h
作用 清除 I2C 中断状态标志

用户操作流程:

发起访问需要首先使用 i2c_write_addr()函数向 I2C 总线写外设地址,并通过返回的 ACK 判断是否成功和外设握手。如需继续进行写传输,则使用 i2c_data_transmit()函数向 I2C 总线发送数据, 并从返回的 ACK 位判断从机是否有正常响应。如需从 I2C 总线上读取,则使用 i2c_data_receive()函数从 I2C 上获得数据(注意该函数返回值中不包含 ACK,如果需要读取 ACK 状态, 需要用户自行使用 i2c_get_rxack()函数获取)。

ov5640_init函数说明

uint16_t chip_id;
    /* ov5640模块硬件初始化 */
    ov5640_hw_init();
    /* ov5640模块退出掉电模式 */
    ov5640_exit_power_down();
    /* ov5640模块硬件复位 */
    ov5640_hw_reset();
    
    chip_id = ov5640_get_chip_id();
    anl_printf("ID:0x%04x\r\n",chip_id);
    if (chip_id != ov5640_CHIP_ID)
    {
        return ov5640_ERROR;
    }

    ov5640_sw_reset();
    ov5640_init_reg();

上面的代码先是进行摄像头控制IO的电平初始化,然后让摄像头进入掉电模式,然后复位摄像头。接下来ov5640_get_chip_id()用于读取摄像头传感器ID。如果读取的ID获合预期,则对OV5640进一一个软复位,然后对其进行初始化寄存器的配置。

上板验证

首先将板子的串口同PC连接,然后用串口终端工具连接板子。

然后用TD将FPGA代码下进板子,

20240610155923118-image

最后用FD下载软件代码到板子。

20240610160003250-image

然后点debug进行固件下载。

20240610160056903-image

下载之后可以在串口终端看到如下图红框中所示的信息

20240610171057912-image

 

请登录后发表评论

    没有回复内容