蜂鸟E203系列—— SPI 设计

欲观原文,请君移步

参考文章《SPI》

原理图

GPIO 可以通过 IOF0 和 IOF1 功能,使得 SOC 中的外设能够复用 GPIO 的 32 根引脚与芯片外设进行通信,其接口分配表如下所示:

GPIO编号 IOF0 IOF1
GPIO0 - PWM0_0
GPIO1 - PWM0_1
GPIO2 QSPI1:SS0 PWM0_2
GPIO3 QSPI1:SD0/MOSI PWM0_3
GPIO4 QSPI1:SD1/MISO -
GPIO5 QSPI1:SCK -
GPIO6 QSPI1:SD2 -
GPIO7 QSPI1:SD3 -
GPIO8 QSPI1:SS1 -
GPIO9 QSPI1:SS2 -
GPIO10 QSPI1:SS3 PWM2_0
GPIO11 - PWM2_1
GPIO12 IIC:SDA PWM2_2
GPIO13 IIC:SCL PWM2_3
GPIO14 - -
GPIO15 - -
GPIO16 UART0:RX -
GPIO17 UART0:TX -
GPIO18 - -
GPIO19 - PWM1_1
GPIO20 - PWM1_0
GPIO21 - PWM1_2
GPIO22 - PWM1_3
GPIO23 - -
GPIO24 UART1:RX -
GPIO25 UART1:TX -
GPIO26 QSPI2:SS -
GPIO27 QSPI2:SD0/MOSI -
GPIO28 QSPI2:SD1/MISO -
GPIO29 QSPI2:SCK -
GPIO30 QSPI2:SD2 -
GPIO31 QSPI2:SD3 -

源码

嵌入式软件通过SPI发送十进制数据 “33” 给底层硬件

/*
 * spi.c
 *
 *  Created on: 2020年7月14日
 *      Author: anytao
 */


#include <stdio.h>

#include <stdlib.h>
#include "platform.h"
#include <string.h>
#include "plic/plic_driver.h"
#include "encoding.h"
#include <unistd.h>
#include "stdatomic.h"


#define SPI2_MOSI_GPIO_OFFSET 27
#define SPI2_MISO_GPIO_OFFSET 28

#define SPI2_SCK_GPIO_OFFSET   29
#define SPI2_SCKMODE_CPOL 1
#define SPI2_SCKMODE_CPHA 0
#define SPI2_CS_GPIO_OFFSET     26     //



#define DATA_SIZE 20
int8_t spi_tx_data[DATA_SIZE];




void spi_init2()
{
	//GPIO IOF0  //SPI2   IOF0_SPI2_MASK
	GPIO_REG(GPIO_IOF_SEL)&= ~ ((0x1 << SPI2_MOSI_GPIO_OFFSET) |(0x1 << SPI2_SCK_GPIO_OFFSET)|(0x1 << SPI2_MISO_GPIO_OFFSET));
	//GPIO IOF0 Enable //SPI2   IOF (0x1 << SPI2_CS_GPIO_OFFSET)
	GPIO_REG(GPIO_IOF_EN)|= ((0x1 << SPI2_MOSI_GPIO_OFFSET)|(0x1 << SPI2_SCK_GPIO_OFFSET) |(0x1 << SPI2_MISO_GPIO_OFFSET));

	//禁止MOSI,SCK,CS的输入
	GPIO_REG(GPIO_INPUT_EN)     &= ~((0x1 << SPI2_MOSI_GPIO_OFFSET) |  (0x1 << SPI2_SCK_GPIO_OFFSET)|(0x1 << SPI2_CS_GPIO_OFFSET));
	//使能MOSI,SCK,CS的输出
	GPIO_REG(GPIO_OUTPUT_EN)    |=  ((0x1 << SPI2_MOSI_GPIO_OFFSET) |  (0x1 << SPI2_SCK_GPIO_OFFSET)|(0x1 << SPI2_CS_GPIO_OFFSET));
	//禁止MMISO的输出
	GPIO_REG(GPIO_OUTPUT_EN)    &= ~(0x1 << SPI2_MISO_GPIO_OFFSET);
	//使能MMISO的输入
	GPIO_REG(GPIO_INPUT_EN)     |=  (0x1 << SPI2_MISO_GPIO_OFFSET);

	//配置时钟寄存器:SCK的极性和相位,极性为0表示空闲状态为0,时钟的“前沿”为上升沿
	//相位为0,则数据在发送端的时钟后沿改变,在接收端的下一个时钟前沿被采样
	SPI2_REG(SPI_REG_SCKMODE) &= ~((0x1 << SPI2_SCKMODE_CPOL)|(0x1 << SPI2_SCKMODE_CPHA));
	//配置时钟频率分频系数寄存器
	//若SPI所处时钟域Freq_SPI
	//则分频系数=Freq_SPI/(2*(div+1))
	SPI2_REG(SPI_REG_SCKDIV)=0x08;

}


void Delay(unsigned int time){
	volatile unsigned int repeatcnt=0;
	repeatcnt=time;
	while(repeatcnt--);
}


uint8_t SPI_Send_ReadByte(uint8_t dat)   //SPI写数据,返回SPI的读数据
{
    SPI2_REG(SPI_REG_TXFIFO) = dat;
    Delay(50);
	return SPI2_REG(SPI_REG_RXFIFO)&0xff;
}


void main(){
	int i=0;
	//初始化SPI发送的数组
	for(i=0;i<DATA_SIZE;i=i+1){
		spi_tx_data[i]=i;
	}
	printf("spi is start");

	//SPi初始化
	spi_init2();

	//CS片选拉低
	GPIO_REG(GPIO_OUTPUT_VAL)&=~(0x1<<SPI2_CS_GPIO_OFFSET);
	Delay(50);
	//SPI发送数据
	SPI_Send_ReadByte(33);
	//CS片选拉高
	Delay(50);
	GPIO_REG(GPIO_OUTPUT_VAL)|=(0x1<<SPI2_CS_GPIO_OFFSET);
}


实验结果

在 verilog 中添加 SPI 解串程序,也就是将 MOSI 发出来的串行信号进行解串。

通过加入ILA可以看到发送的数据如下图所示。

可以看到数据从 MSB 到 LSB 被解串出来,分别为0-0-1-0-0-0-0-1,对应十进制数 “33

工程获取

嵌入式spi.rar:嵌入式软件的工程(window环境:Eclipse+OpenOCD)

FPGA_nucleikit_spi.rar:FPGA程序

image

获取资料方法一:集赞

关注小编公众号后,将本文转发至朋友圈,集齐6个赞,截图发送到后台,小编会在24小时之内回复。备注:【领取RISCV SPI工程】即可领取资料

获取资料方法二:转发群

关注小编公众号后,将本文转发至不低于100人的群(RISCV相关行业),截图发送到后台,小编会在24小时之内回复。备注:【领取RISCV SPI工程】即可领取资料

原文地址:https://www.cnblogs.com/xiguazai/p/13358696.html