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

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

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

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

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

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

四、实验步骤
  • 用数据线将iCore3的USB-OTG口与电脑相连,将供电跳帽选择为OTG供电;
  • 将代码包中的custom_spi.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_21_2.jpg

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


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

  8. # 定义SPI对象,定义cs:D8, clk:D9, mosi:D10, miso:D11 (iCore3硬件连接)
  9. fpga_spi = SPI('D8','D9','D10','D11')

  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.         fpgare = fpga_spi.write_str(re.decode('ascii')+'\r\n')
  29.         fpgare += fpga_spi.read(4)      # 再读入四字节
  30.         U4.write(fpgare)                # 将从FPGA接收到的内容再发给串口4
  1. # -*- coding: utf-8-*-
  2. # custom_spi.py -- put your code here!
  3. from pyb import Pin, udelay  # 导入相关模块

  4. # 普通IO模拟SPI驱动
  5. class SPI(object):
  6.     """创建SPI对象时传入四个参数
  7.         cs:   片选信号
  8.         clk:  主机时钟信号
  9.         mosi: 主机输出(从机输入)信号
  10.         miso: 主机输入(从机输出)信号
  11.     """
  12.     # 对象创建时,自动初始化
  13.     def __init__(self, cs, clk, mosi, miso):
  14.         super(SPI, self).__init__()
  15.         self.SPI_CS = Pin(cs, Pin.OUT_PP)              #片选信号输出
  16.         self.SPI_CLK = Pin(clk, Pin.OUT_PP)            #时钟输出
  17.         self.SPI_MOSI = Pin(mosi, Pin.OUT_PP)          #SPI输出
  18.         self.SPI_MISO = Pin(miso, Pin.IN, Pin.PULL_UP) #SPI输入
  19.         self.SPI_CS.high()                             #片选信号拉高
  20.         self.SPI_CS.low()                              #片选信号拉低
  21.         self.SPI_CLK.high()                            #时钟拉高
  22.         self.SPI_CLK.low()                             #时钟拉低
  23.         self.SPI_MOSI.high()                           #输入拉高
  24.         self.SPI_MOSI.low()                            #输入拉低
  25.         self.SPI_MISO.value()                          #输出

  26.     # SPI发送一字节函数,传入一字节
  27.     def _write_byte(self, data):
  28.         temp = 0                     # 定义接收变量接收返回字节
  29.         for i in range(7):           # 循环七次,发送七比特
  30.             if data & 0x80:          # 发送最高位的一比特
  31.                 self.SPI_MOSI.high() # 输出信号线拉高
  32.             else:
  33.                 self.SPI_MOSI.low()  # 输出信号线拉低

  34.             self.SPI_CLK.low()       # 时钟信号线拉低
  35.             udelay(5)                # 等输出信号线稳定

  36.             if self.SPI_MISO.value():# 读取输入信号线
  37.                 temp |= 1            # 接收变量按位赋值
  38.             else:
  39.                 temp |= 0

  40.             self.SPI_CLK.high()      # 时钟信号线拉高,从机接收数据
  41.             udelay(5)
  42.             data <<= 1               # 数据左移一位
  43.             temp <<= 1               # 接收变量左移一位

  44.         if data & 0x80:              # 发送最后一比特,不左移
  45.             self.SPI_MOSI.high()
  46.         else:
  47.             self.SPI_MOSI.low()

  48.         self.SPI_CLK.low()
  49.         udelay(5)

  50.         if self.SPI_MISO.value():
  51.             temp |= 1
  52.         else:
  53.             temp |= 0

  54.         self.SPI_CLK.high()
  55.         udelay(5)

  56.         return(chr(temp))             # 将ascii转换为字符并返回

  57.     # 发送字符串,传入要发送的字符串
  58.     def write_str(self, str):
  59.         res = ''
  60.         self.SPI_CS.high()                   # 片选信号拉高
  61.         for i in str:                        # 逐个发送字符
  62.             res += self._write_byte(ord(i))  # 将字符转换为ascii码值,传给写字节函数
  63.         self.SPI_CS.low()                    # 片选信号拉低

  64.         return(res)

  65.     # 读字节函数,传入读取字节数
  66.     def read(self, l):
  67.         res = ''
  68.         self.SPI_CS.low()
  69.         for i in range(l):
  70.             res += self._write_byte(0x00)    # 主机发送0x00,获取从机数据
  71.         self.SPI_CS.high()

  72.         return(res)

代码包.zip (803.25 KB, 下载次数: 1)



您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

66

帖子

0

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