FPGA通过SPI驱动0.96寸OLED小屏幕,按键切换OLED显示内容,分别是全白和条纹
SSD1306驱动芯片:
SSD1306 是0.96OLED的驱动芯片,数据/命令的发送有三种接口可选择:6800/8000 串口,I2C 接口或 SPI 接口。这里采用的是七针OLED屏幕,通过SPI发送数据/命令的方式。
虽然SPI是全双工的,但是oled模块不会向主机写数据,因此在SPI的数据传输中,只需要两根线就可以了,及MOSI和CLK。
OLED模块接口定义
GND | VCC | D0 | D1 | RES | D/C | CS |
电源地 | 电源(3~5V) | 在SPI驱动方式中为时钟线 | 在SPI驱动方式中为数据线 | 复位引脚 | 数据/命令控制引脚,0为命令,1为数据 | 片选信号 |
FPGA实现SPI主站发送:
因为OLED不会发送数据给控制器,因此只需要写SPI的发送端即可
`timescale 1ns / 1ps
// 这个模块实现了以下功能:
// 在IDLE状态下等待start信号。
// 当start信号有效时,进入START状态,准备开始发送数据。
// 在TRANSFER状态下,通过sclk和mosi信号逐位发送数据。
// 发送完8位数据后,进入STOP状态,拉高cs_n信号,并设置done信号为高,表示发送完成。
module SPI_send_driver(
input wire clk, // 系统时钟
input wire rst_n, // 复位信号,低电平有效
input wire [7:0] data_in, // 要发送的数据
input wire start, // 开始发送信号
output reg sclk, // SPI时钟
output reg mosi, // 主输出从输入
output reg cs_n, // 片选信号,低电平有效
output reg done // 低电平SPI发送中,高电平为空闲
);
reg [2:0] state; // 状态机状态
reg [2:0] bit_cnt; // 位计数器
reg [7:0] shift_reg; // 移位寄存器
localparam IDLE = 3'b000;
localparam START = 3'b001;
localparam TRANSFER = 3'b010;
localparam STOP = 3'b011;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= IDLE;
sclk <= 1'b1;
mosi <= 1'b0;
cs_n <= 1'b1;
done <= 1'b1;
bit_cnt <= 'd0;
shift_reg <= 8'b00000000;
end
else begin
case(state)
IDLE: begin
if(start) begin
done <= 1'b0;
shift_reg <= data_in;
cs_n <= 1'b0;
state <= START;
end
end
START: begin
sclk <= 1'b0;
mosi <= shift_reg[7];
shift_reg <= {shift_reg[6:0], 1'b0};
bit_cnt <= 3'b000;
state <= TRANSFER;
end
TRANSFER: begin
if(bit_cnt < 'd7) begin
sclk <= ~sclk;
if(sclk) begin
bit_cnt <= bit_cnt + 1;
shift_reg <= {shift_reg[6:0], 1'b0};
mosi <= shift_reg[7];
end
end
else begin
state <= STOP;
sclk <= 1'b1;
end
end
STOP: