本帖最后由 如意不如意 于 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发送至串口调试器。原理示意图如下所示:
排针引脚连接对照表:
SPI信号线 | ARM引脚 | FPGA引脚 | 时钟信号(SCLK) | PD9 | F7 | 片选信号(CS) | PD8 | D8 | 主入从出信号(MISO) | PD11 | C6 | 主出从入信号(MOSI) | PD10 | E7 |
注意: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-LED | FPGA-LED | ledr | 红灯亮 | 红灯亮 | ledg | 绿灯亮 | 绿灯亮 | ledb | 蓝灯亮 | 蓝灯亮 |
五、实验现象
在发送区编辑完要发送的数据后,点击发送即可观察到RAM-LED、FPGA-LED变化,并在接收区收到iCore3的回复信息,如下图所示:
六、实验程序- # -*- coding: utf-8-*-
- # main.py -- put your code here!
- from pyb import udelay, LED, UART # 导入相关模块
- from custom_spi import SPI # 从定制spi模块中导入SPI对象
-
-
- # 主函数
- # 定义串口4对象,波特率9600
- U4 = UART(4,9600)
-
- # 定义SPI对象,定义cs:D8, clk:D9, mosi:D10, miso:D11 (iCore3硬件连接)
- fpga_spi = SPI('D8','D9','D10','D11')
-
- while True:
- re = U4.readline() # 缓冲区读取一行内容
- if re != None: # 若内容不为空
- udelay(5000) # 延时5ms,等内容接受完整,视内容长短而定,若时间过短则会通信失败
- re = re + U4.readline() # 将内容合并
-
- if re == b'ledr': # 控制命令匹配
- LED(1).on() # 红灯亮
- LED(2).off()
- LED(3).off()
- elif re == b'ledg': # 绿灯亮
- LED(1).off()
- LED(2).on()
- LED(3).off()
- elif re == b'ledb': # 蓝灯亮
- LED(1).off()
- LED(2).off()
- LED(3).on()
-
- # 将命令发送给FPAG
- fpgare = fpga_spi.write_str(re.decode('ascii')+'\r\n')
- fpgare += fpga_spi.read(4) # 再读入四字节
- U4.write(fpgare) # 将从FPGA接收到的内容再发给串口4
- # -*- coding: utf-8-*-
- # custom_spi.py -- put your code here!
- from pyb import Pin, udelay # 导入相关模块
-
- # 普通IO模拟SPI驱动
- class SPI(object):
- """创建SPI对象时传入四个参数
- cs: 片选信号
- clk: 主机时钟信号
- mosi: 主机输出(从机输入)信号
- miso: 主机输入(从机输出)信号
- """
- # 对象创建时,自动初始化
- def __init__(self, cs, clk, mosi, miso):
- super(SPI, self).__init__()
- self.SPI_CS = Pin(cs, Pin.OUT_PP) #片选信号输出
- self.SPI_CLK = Pin(clk, Pin.OUT_PP) #时钟输出
- self.SPI_MOSI = Pin(mosi, Pin.OUT_PP) #SPI输出
- self.SPI_MISO = Pin(miso, Pin.IN, Pin.PULL_UP) #SPI输入
- self.SPI_CS.high() #片选信号拉高
- self.SPI_CS.low() #片选信号拉低
- self.SPI_CLK.high() #时钟拉高
- self.SPI_CLK.low() #时钟拉低
- self.SPI_MOSI.high() #输入拉高
- self.SPI_MOSI.low() #输入拉低
- self.SPI_MISO.value() #输出
-
- # SPI发送一字节函数,传入一字节
- def _write_byte(self, data):
- temp = 0 # 定义接收变量接收返回字节
- for i in range(7): # 循环七次,发送七比特
- if data & 0x80: # 发送最高位的一比特
- self.SPI_MOSI.high() # 输出信号线拉高
- else:
- self.SPI_MOSI.low() # 输出信号线拉低
-
- self.SPI_CLK.low() # 时钟信号线拉低
- udelay(5) # 等输出信号线稳定
-
- if self.SPI_MISO.value():# 读取输入信号线
- temp |= 1 # 接收变量按位赋值
- else:
- temp |= 0
-
- self.SPI_CLK.high() # 时钟信号线拉高,从机接收数据
- udelay(5)
- data <<= 1 # 数据左移一位
- temp <<= 1 # 接收变量左移一位
-
- if data & 0x80: # 发送最后一比特,不左移
- self.SPI_MOSI.high()
- else:
- self.SPI_MOSI.low()
-
- self.SPI_CLK.low()
- udelay(5)
-
- if self.SPI_MISO.value():
- temp |= 1
- else:
- temp |= 0
-
- self.SPI_CLK.high()
- udelay(5)
-
- return(chr(temp)) # 将ascii转换为字符并返回
-
- # 发送字符串,传入要发送的字符串
- def write_str(self, str):
- res = ''
- self.SPI_CS.high() # 片选信号拉高
- for i in str: # 逐个发送字符
- res += self._write_byte(ord(i)) # 将字符转换为ascii码值,传给写字节函数
- self.SPI_CS.low() # 片选信号拉低
-
- return(res)
-
- # 读字节函数,传入读取字节数
- def read(self, l):
- res = ''
- self.SPI_CS.low()
- for i in range(l):
- res += self._write_byte(0x00) # 主机发送0x00,获取从机数据
- self.SPI_CS.high()
-
- return(res)
代码包.zip
(803.25 KB, 下载次数: 1)
|