手机扫码
链接直达
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 外设,其结构框图如下图所示:
其寄存器地址分配和功能描述如下表所示
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信息,主要区别是这个工程中添加了红框中的代码。
红框中的代码一一解释如下:
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代码下进板子,
最后用FD下载软件代码到板子。
然后点debug进行固件下载。
下载之后可以在串口终端看到如下图红框中所示的信息
没有回复内容