赞
踩
目录
在这里就不介绍SPI原理了,需要的同学自行查阅。我使用的硬件环境为STM32F407VET6和DE0-nano,如下图。
使用cubemx配置工程,FPGA使用Quartus软件,时序仿真图如下
txd_signal信号为上升沿触发,led0,1,2为调试灯,可去掉。
一个SCK周期为16个clk周期,我测试时使用50MHz晶振,故SPI时钟为3.125MHz。
需要改动通信速率可以通过改动cnt1相关值改变。
时钟相位参考STM32从机配置
- //时钟极性高,采样沿上升沿
- module SPI_Master(
- clk, // 系统时钟
- rst, // 复位,低有效
- txd_flag, // 高电平表示发送完成处于忙碌状态,低电平表示处于空闲状态
- sck, // 时钟输出
- cs, // 片选输出
- mosi, // 主设备输出信号
- miso, // 主设备输入信号
- txd_signal, // 发送触发信号,给一个信号发送8bit
- rxd_out, // 接收的数据
- txd_in, // 发送的数据
- led0,
- led1,
- led2
- );
- //调试引脚
- output led0,led1,led2;
- assign led0=txd_signal;
- assign led1=txd_flag;
- assign led2=cs;
- // 输入信号
- input clk, rst, miso, txd_signal;
- // 输出信号
- output reg mosi, txd_flag;
- output wire sck, cs;
- output reg [7:0] rxd_out;
- input [7:0] txd_in;
-
- // 内部寄存器和变量
- reg [2:0] txd_start;
- reg [2:0] txd_start_outside;
- reg [3:0] cnt;
- reg [3:0] cnt1;
- reg csr;
- assign sck = cnt1[3];
- assign cs = csr;
-
- // 任务:根据计数器 cnt1 的值更新时钟状态
- task clk_states;
- if (cnt1 == 4'b0000) begin
- cnt1 <= 4'b1111;
- cnt <= cnt + 1'b1;
- end else
- cnt1 <= cnt1 - 1'b1;
- endtask
-
- // always 块:根据时钟和复位信号控制发送过程和计数器的更新
- always @(posedge clk or negedge rst) begin
- if (!rst) begin
- // 复位所有状态和寄存器
- txd_flag <= 1'b0;
- txd_start <= 3'd1;
- cnt <= 4'd0;
- cnt1 <= 4'b1111;
- csr <= 1'b1;
- end else begin
- if (txd_start == txd_start_outside) begin
- csr <= 1'b0;
- txd_flag <= 1'b1; // txd_flag 信号与 cs 信号相反,电路当处于通信时为高电平,表示忙碌状态
- case (cnt) // 为低电平表示空闲状态
- 0: clk_states();//进八次cnt加1,SCK经过一个周期,SCK高电平持续时间为4和CLK
- 1: clk_states();
- 2: clk_states();
- 3: clk_states();
- 4: clk_states();
- 5: clk_states();
- 6: clk_states();
- 7: begin
- if (cnt1 == 4'b0000) begin
- cnt1 <= 4'b1111;
- cnt <= 4'd8;
- end else
- cnt1 <= cnt1 - 1'b1;
- end
- 8: begin
- // 多加一个状态延长 cs 的低电平时间,给从机足够的时间接收数据
- txd_start <= txd_start + 1'b1;
- cnt <= 4'd0;
- end
- endcase
- end else begin
- csr <= 1'b1;
- txd_flag <= 1'b0;
- end
- end
- end
-
- // always 块:外部触发发送脉冲,上升沿触发发送一次
- always @(posedge txd_signal or negedge rst) begin
- if (!rst)
- txd_start_outside <= 1'b0;
- else begin
- if (!txd_flag)
- txd_start_outside <= txd_start_outside + 1'b1;
- else;
- end
- end
-
- // always 块:sck 上升沿采样数据
- reg [7:0] rxd_outr;
- reg [2:0] rec_cnt;
- always @(posedge sck or negedge rst) begin
- if (!rst) begin
- rxd_out <= 8'h00;
- rec_cnt <= 3'd0;
- end else begin
- case (rec_cnt)
- 0: begin
- rxd_outr[7] <= miso;
- rec_cnt <= 3'd1;
- end
- 1: begin
- rxd_outr[6] <= miso;
- rec_cnt <= 3'd2;
- end
- 2: begin
- rxd_outr[5] <= miso;
- rec_cnt <= 3'd3;
- end
- 3: begin
- rxd_outr[4] <= miso;
- rec_cnt <= 3'd4;
- end
- 4: begin
- rxd_outr[3] <= miso;
- rec_cnt <= 3'd5;
- end
- 5: begin
- rxd_outr[2] <= miso;
- rec_cnt <= 3'd6;
- end
- 6: begin
- rxd_outr[1] <= miso;
- rec_cnt <= 3'd7;
- end
- 7: begin
- rxd_outr[0] <= miso;
- rxd_out <= {rxd_outr[7:1], miso};
- rec_cnt <= 3'd0;
- end
- default:;
- endcase
- end
- end
-
- // always 块:sck 下降沿时发送数据
- reg [2:0] send_cnt;
- always @(negedge sck or negedge rst) begin
- if (!rst)
- send_cnt <= 3'd0;
- else begin
- case (send_cnt)
- 0: begin
- mosi <= txd_in[7];
- send_cnt <= 3'd1;
- end
- 1: begin
- mosi <= txd_in[6];
- send_cnt <= 3'd2;
- end
- 2: begin
- mosi <= txd_in[5];
- send_cnt <= 3'd3;
- end
- 3: begin
- mosi <= txd_in[4];
- send_cnt <= 3'd4;
- end
- 4: begin
- mosi <= txd_in[3];
- send_cnt <= 3'd5;
- end
- 5: begin
- mosi <= txd_in[2];
- send_cnt <= 3'd6;
- end
- 6: begin
- mosi <= txd_in[1];
- send_cnt <= 3'd7;
- end
- 7: begin
- mosi <= txd_in[0];
- send_cnt <= 3'd0;
- end
- default:;
- endcase
- end
- end
-
- endmodule
- int main(void)
- {
- /* USER CODE BEGIN 1 */
-
- /* USER CODE END 1 */
-
- /* MCU Configuration--------------------------------------------------------*/
-
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
-
- /* USER CODE BEGIN Init */
-
- /* USER CODE END Init */
-
- /* Configure the system clock */
- SystemClock_Config();
-
- /* USER CODE BEGIN SysInit */
-
- /* USER CODE END SysInit */
-
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_DMA_Init();
- MX_SPI1_Init();
- MX_USART1_UART_Init();
- /* USER CODE BEGIN 2 */
- uint8_t data=0;
- HAL_SPI_Receive_DMA(&hspi1,&data,1);
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- //FPGA RESET
- HAL_GPIO_WritePin(RST_GPIO_Port,RST_Pin,GPIO_PIN_RESET);
- HAL_Delay(10);
- HAL_GPIO_WritePin(RST_GPIO_Port,RST_Pin,GPIO_PIN_SET);
- //等待发送空闲
- while(HAL_GPIO_ReadPin(txd_flag_GPIO_Port,txd_flag_Pin)==GPIO_PIN_SET){
- };
- //延迟便于观察串口输出
- HAL_Delay(2000);
- //上升沿触发FPGA主机发送
- HAL_GPIO_WritePin(txd_signal_GPIO_Port,txd_signal_Pin,GPIO_PIN_SET);
- HAL_Delay(100);
- HAL_GPIO_WritePin(txd_signal_GPIO_Port,txd_signal_Pin,GPIO_PIN_RESET);
- //串口打印data查看数据
- printf("data is %d \r\n",data);
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。