【银杏科技ARM+FPGA双核心应用】MicroPython系列二十二:RAM-FPG...

[复制链接]
733|6
 楼主| 如意不如意 发表于 2020-8-4 16:41 | 显示全部楼层 |阅读模式
本帖最后由 如意不如意 于 2020-8-4 16:41 编辑

例程二十二:【MicroPython】RAM-FPGA I2C通信
一、实验目的与意义
了解I2C总线通信的基本原理;掌握RAM与FPGA的I2C通信方法;掌握Quartus II集成环境使用方法。

二、实验设备及平台
  • iCore3双核心板点击购买
  • Micro USB线
  • Blaster(或相同功能)仿真器
  • Quartus II开发平台
  • 串口调试器
  • 电脑

三、实验原理
通过FPGA建立的I2C模块对外提供SCL、SDA接口,与STM32模拟的I2C接口相连接,串口调试器与STM32通过串口连接,实现三者之间的通信。本实验中,以STM32作为主机,FPGA作为从机,串口调试器向STM32发送数据,STM32的串口4接收数据,然后通过I2C将数据发送至FPGA,STM32起到一个桥梁的作用。程序运行后,FPGA收到数据后向STM32发送数据,经过STM32发送至串口调试器。原理示意图如下所示:
fetch.php?media=icore3:icore3_micropython_21_1.jpg
排针引脚连接对照表:
SPI信号线
ARM引脚
FPGA引脚
时钟信号(SCL)
PD8
D8
数据信号(SDA)
PD9
F7

注意:iCore3核心板已经将以上引脚相连。

四、实验步骤
  • 用数据线将iCore3的USB-OTG口与电脑相连,将供电跳帽选择为OTG供电;
  • 将代码包中的custom_i2c.py、main.py文件替换到PYBFLASH磁盘中,弹出磁盘(必须!),拔下数据线将iCore3断电;
  • 将USB-Blaster与iCore3的JTAG调试口相连;
  • 将跳线帽选为USB UART,并将数据线连接到USB UART;
  • 将数据线连接到电脑,iCore3上电Python代码运行;
  • 打开QuartusII开发环境,打开实验工程,编译工程,下载FPGA代码;
  • 打开串口调试器,连接到对应串口并打开,发送命令,观察实验现象;
  • 命令格式如下:
命令字符串RAM-LEDFPGA-LED
ledr
红灯亮
红灯亮
ledg
绿灯亮
绿灯亮
ledb
蓝灯亮
蓝灯亮


五、实验现象
在发送区编辑完要发送的数据后,点击发送即可观察到RAM-LED、FPGA-LED变化,并在接收区收到iCore3的回复信息,如下图所示:
fetch.php?media=icore3:icore3_micropython_22_2.jpg

六、实验程序
  1. # -*- coding: utf-8-*-
  2. # main.py -- put your code here!
  3. from pyb import Pin, udelay, LED, UART  # 导入相关模块
  4. from custom_i2c import I2C  # 从定制i2c模块中导入I2C对象

  5. # 主函数
  6. # 定义串口4对象,波特率9600
  7. U4 = UART(4,9600)

  8. # 定义I2C对象,定义 sda:D9, scl:D8 (iCore3硬件连接)
  9. fpga_i2c = I2C(Pin('D9'), Pin('D8'))

  10. while True:
  11.     re = U4.readline()           # 缓冲区读取一行内容
  12.     if re != None:               # 若内容不为空
  13.         udelay(5000)             # 延时5ms,等内容接受完整,视内容长短而定,若时间过短则会通信失败
  14.         re = re + U4.readline()  # 将内容合并

  15.         if re == b'ledr':        # 控制命令匹配
  16.             LED(1).on()          # 红灯亮
  17.             LED(2).off()
  18.             LED(3).off()
  19.         elif re == b'ledg':      # 绿灯亮
  20.             LED(1).off()
  21.             LED(2).on()
  22.             LED(3).off()
  23.         elif re == b'ledb':      # 蓝灯亮
  24.             LED(1).off()
  25.             LED(2).off()
  26.             LED(3).on()

  27.         # 将命令发送给FPAG
  28.         data = re.decode('ascii')+'\r\n'
  29.         fpga_i2c.write_nbyte(0x03, 0X8F, data)
  30.         res = fpga_i2c.read_nbyte(0x02,0x0F,0x06)      # 再读入六字节
  31.         U4.write(res)                 # 将从FPGA接收到的内容再发给串口4
  1. # -*- coding: utf-8-*-
  2. # custom_i2c.py -- put your code here!
  3. from pyb import Pin, udelay   # 导入相关模块

  4. # 普通IO模拟I2C驱动
  5. class I2C(object):
  6.     """创建I2C对象时传入两个参数
  7.         sda:   数据信号
  8.         scl:   时钟信号
  9.     """
  10.     # 对象创建时,自动初始化
  11.     def __init__(self, sda, scl):
  12.         super(I2C, self).__init__()
  13.         self.sdapin = sda                           # sda引脚编号
  14.         self.sclpin = scl                           # scl引脚编号
  15.         self.I2C_SDA = Pin(self.sdapin, Pin.OUT_PP) # 数据信号线输出
  16.         self.I2C_SCL = Pin(self.sclpin, Pin.OUT_PP) # 时钟信号线输出
  17.         self.I2C_SDA.high()        # SDA拉高
  18.         self.I2C_SCL.high()        # 时钟拉高
  19.         self.i2c_flag = 0          # 应答标志
  20.         self.us = 10               # 信号稳定延时

  21.     # 起始信号
  22.     def start(self):
  23.         self.I2C_SDA.high()
  24.         udelay(self.us)
  25.         self.I2C_SCL.high()
  26.         udelay(self.us)
  27.         self.I2C_SDA.low()
  28.         udelay(self.us)
  29.         self.I2C_SCL.low()
  30.         udelay(self.us)

  31.     # 停止信号
  32.     def stop(self):
  33.         self.I2C_SDA = Pin(self.sdapin, Pin.OUT_PP)
  34.         self.I2C_SDA.low()
  35.         udelay(self.us)
  36.         self.I2C_SCL.high()
  37.         udelay(self.us)
  38.         self.I2C_SDA.high()
  39.         udelay(self.us)

  40.     # 应答信号
  41.     def ack(self, char):
  42.         self.I2C_SDA = Pin(self.sdapin, Pin.OUT_PP)
  43.         if char:                   # 若成功读取数据,则将数据线拉低
  44.             self.I2C_SDA.low()
  45.         else:
  46.             self.I2C_SDA.high()
  47.         udelay(self.us)

  48.         self.I2C_SCL.high()
  49.         udelay(self.us)
  50.         self.I2C_SCL.low()
  51.         udelay(self.us)

  52.     # 写一字节
  53.     def write(self, data):
  54.         self.I2C_SDA = Pin(self.sdapin, Pin.OUT_PP)
  55.         for i in range(8):           # 循环八次,发送一字节
  56.             if data & 0x80:          # 发送最高位的一比特
  57.                 self.I2C_SDA.high()  # 数据信号线拉高
  58.             else:
  59.                 self.I2C_SDA.low()   # 数据信号线拉低

  60.             udelay(self.us)
  61.             self.I2C_SCL.high()
  62.             udelay(self.us)
  63.             self.I2C_SCL.low()
  64.             data <<= 1               # 数据位左移一位

  65.         # 再第九个时钟周期,从机回复一个ACK信号,主机将数据线设置为输入模式
  66.         self.I2C_SDA = Pin(self.sdapin, Pin.IN, Pin.PULL_UP)
  67.         udelay(self.us)
  68.         udelay(self.us)
  69.         self.I2C_SCL.high()
  70.         udelay(self.us)

  71.         if self.I2C_SDA.value():    # 若SDA没有被拉低,则代表接受异常
  72.             self.i2c_flag = 0     
  73.         else:
  74.             self.i2c_flag = 1       # SDA被拉低代表接受正常,将i2c_flag赋值为1

  75.         self.I2C_SCL.low()          # 主机将数据线设置为输出模式
  76.         self.I2C_SDA = Pin(self.sdapin, Pin.OUT_PP)
  77.         udelay(self.us)

  78.     # 发送n字节,参数为sla:设备地址,suba:寄存器地址,s:字符串
  79.     def write_nbyte(self, sla, suba, s):
  80.         self.I2C_SDA = Pin(self.sdapin, Pin.OUT_PP)
  81.         self.start()                # 发送起始信号
  82.         self.write(sla)             # 发送设备地址
  83.         self.write(suba)            # 发送寄存器地址
  84.         for i in range(len(s)):     # 逐个发送字符
  85.             self.write(ord(s[i]))   # 将字符转换位ascii码值
  86.         self.stop()                 # 发送停止信号

  87.         return(1)

  88.     # 读一字节
  89.     def read(self):
  90.         retc = 0
  91.         self.I2C_SDA.high()
  92.         self.I2C_SDA = Pin(self.sdapin, Pin.IN, Pin.PULL_UP)

  93.         for i in range(8):
  94.             udelay(self.us)
  95.             self.I2C_SCL.low()
  96.             udelay(self.us)
  97.             self.I2C_SCL.high()
  98.             udelay(self.us)
  99.             retc <<= 1
  100.             if self.I2C_SDA.value(): # 读取输入信号线
  101.                 retc += 1            # 接收变量按位赋值
  102.             udelay(self.us)

  103.         self.I2C_SCL.low()
  104.         udelay(self.us)
  105.         self.I2C_SDA = Pin(self.sdapin, Pin.OUT_PP)

  106.         return(chr(retc))            # 将ascii码转换为字符

  107.     # 读取n字节,参数为sla:设备地址,suba:寄存器地址,no:字节长度
  108.     def read_nbyte(self, sla, suba, no):
  109.         re = ''
  110.         self.start()                 # 发送起始信号
  111.         self.write(sla)              # 发送设备地址
  112.         self.write(suba)             # 发送寄存器地址

  113.         for i in range(no-1):
  114.             re += self.read()
  115.             self.ack(1)              # 发送应答信号
  116.         re += self.read()
  117.         self.ack(0)
  118.         self.stop()                  # 发送停止信号

  119.         return(re)                   # 返回接收到的字符串

代码包.zip (1.43 MB, 下载次数: 1)




xiaolin1111 发表于 2020-9-11 14:39 | 显示全部楼层
这个micropython是不是集成了C语言的固件库
 楼主| 如意不如意 发表于 2020-9-14 11:49 | 显示全部楼层
xiaolin1111 发表于 2020-9-11 14:39
这个micropython是不是集成了C语言的固件库

嗯,micropython本身就是c语言编写的,可以嵌入c代码。
xiaolin1111 发表于 2020-9-16 10:12 | 显示全部楼层
如意不如意 发表于 2020-9-14 11:49
嗯,micropython本身就是c语言编写的,可以嵌入c代码。

哦哦  那这个micropython相对与C的优势是啥
 楼主| 如意不如意 发表于 2020-9-29 15:55 | 显示全部楼层
xiaolin1111 发表于 2020-9-16 10:12
哦哦  那这个micropython相对与C的优势是啥

开发特别简单,可以快速开发验证,要是对效率要求特别高,再用c写一遍
xiaorenwuu 发表于 2020-10-9 14:36 | 显示全部楼层
需要添加哪些库呢?
 楼主| 如意不如意 发表于 2020-10-30 17:57 | 显示全部楼层
xiaorenwuu 发表于 2020-10-9 14:36
需要添加哪些库呢?

只需要烧录固件就可以了,一些第三方驱动可以作为模块文件来加载。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

66

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部