2402|3

20

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

国产FPGA安路 高集成低功耗SF1系列FPSoC新品测评【使用SF1 RISCV IP 核驱动 oled】 [复制链接]

  本帖最后由 Grayson__ 于 2023-3-19 11:14 编辑

        在本期测评中,我们使用安路 SF1 的 RISCV IP 核控制 oled 的显示功能,参考资料有安路 SF1 的 DS800、SF1 DEMO板的原理图、TN816、TN817、TN818。本次测评分为两个部分:FPGA与MCU,分别使用 TD 与 FD 软件进行编写。

        首先是 TD 部分,打开 TD 软件,新建名为 oled 的工程。首先调用 RISCV IP核,具体设置如下图:

        调用 PLL IP 核,具体设置如下图,DEMO外部晶振为25MHz,所以PLL输入时钟为25MHz,生成的100MHz用于驱动MCU:

  

        新建 gpio_ctrl.v 文件,用于控制gpio的输入或输出:

module gpio_ctrl( 
	input	gpio_dir,	//1'b0:input  1'b1:output
    input	gpio_out,
    
    inout	gpio,		//对应fpga端口
    output	gpio_in	
);

assign	gpio = gpio_dir ? gpio_out:1'bz;
assign 	gpio_in = gpio;	//当作为输入时,直接将输入值赋值给gpio_in

endmodule

        新建 ps_wrapper.v 用于例化 gpio_ctrl 与 MCU 模块:

module ps_wrapper( 
    input wire        clk,			//MCU的100MHz时钟
    input wire        rst,
	input wire        timer_clk,	//fpga的25MHz时钟

    input wire        jtag_tck,
    output wire       jtag_tdo,
    input wire        jtag_tms,
    input wire        jtag_tdi,

    input wire        uart_rx,
    output wire       uart_tx,

    inout wire        gpio_0,
    inout wire        gpio_1,
    inout wire        gpio_2,
    inout wire        gpio_3,
    inout wire        gpio_4
);

wire gpio0_out;
wire gpio1_out;
wire gpio2_out;
wire gpio3_out;
wire gpio4_out;

wire gpio0_dir;
wire gpio1_dir;
wire gpio2_dir;
wire gpio3_dir;
wire gpio4_dir;

wire gpio0_in;
wire gpio1_in;
wire gpio2_in;
wire gpio3_in;
wire gpio4_in;

gpio_ctrl u0_gpio_ctrl( 
	.gpio_dir(gpio0_dir),
    .gpio_out(gpio0_out),
    .gpio(gpio_0),
    .gpio_in(gpio0_in)	
);

gpio_ctrl u1_gpio_ctrl( 
	.gpio_dir(gpio1_dir),
    .gpio_out(gpio1_out),
    .gpio(gpio_1),	
    .gpio_in(gpio1_in)	
);

gpio_ctrl u2_gpio_ctrl( 
	.gpio_dir(gpio2_dir),
    .gpio_out(gpio2_out),
    .gpio(gpio_2),	
    .gpio_in(gpio2_in)	
);

gpio_ctrl u3_gpio_ctrl( 
	.gpio_dir(gpio3_dir),	
    .gpio_out(gpio3_out),
    .gpio(gpio_3),	
    .gpio_in(gpio3_in)	
);

gpio_ctrl u4_gpio_ctrl( 
	.gpio_dir(gpio4_dir),
    .gpio_out(gpio4_out),
    .gpio(gpio_4),	
    .gpio_in(gpio4_in)	
);

MCU u_MCU(
		.soft_ip_apbm_en	(1'b0), 
        .qspi0cfg1_mode 	(1'b1), 
        .qspi0cfg2_mode 	(1'b1), 
        
        .jtag_tck			(jtag_tck), 
        .jtag_tdo			(jtag_tdo), 
        .jtag_tms			(jtag_tms), 
        .jtag_tdi			(jtag_tdi), 
        
        .apb_clk			(	), 
        
        .apb_paddr			(	), 
        .apb_pwrite			(	), 
        .apb_penable		(	), 
        .apb_pprot			(	), 
        .apb_pstrobe		(	), 
        .apb_psel			(	), 
        .apb_pwdata			(	), 
        .apb_prdata			(	), 
        .apb_pready			(	), 
        .apb_pslverr		(	), 
        
        .uart_tx			(uart_tx), 
        .uart_rx			(uart_rx), 
        
        .gpio0_out			(gpio0_out), 
        .gpio0_dir			(gpio0_dir), 
        .gpio0_in 			(gpio0_in ), 
        .gpio1_out			(gpio1_out), 
        .gpio1_dir			(gpio1_dir), 
        .gpio1_in 			(gpio1_in ), 
        .gpio2_out			(gpio2_out), 
        .gpio2_dir			(gpio2_dir), 
        .gpio2_in 			(gpio2_in ), 
        .gpio3_out			(gpio3_out), 
        .gpio3_dir			(gpio3_dir), 
        .gpio3_in 			(gpio3_in ), 
        .gpio4_out			(gpio4_out), 
        .gpio4_dir			(gpio4_dir), 
        .gpio4_in 			(gpio4_in ), 
        
        .core_clk			(clk), 
        .timer_clk			(timer_clk),
        .core_reset			(rst), 
        
        .mtip				(	),
        .nmi				(	), 
        .clic_irq			(	), 
        .sysrstreq			(	), 
        .apb_clk_down		(	), 
        .apb_paddr_down		(	), 
        .apb_penable_down	(	), 
        .apb_pprot_down		(	), 
        .apb_prdata_down	(	), 
        .apb_pready_down	(	), 
        .apb_pslverr_down	(	), 
        .apb_pstrobe_down	(	), 
        .apb_pwdata_down	(	), 
        .apb_pwrite_down	(	), 
        .apb_psel0_down		(	), 
        .apb_psel1_down		(	), 
        .apb_psel2_down     (	)
);


endmodule

        新建 top.v ,用于例化 PLL 与 ps_wrapper 模块,需要注意的是,为了简化代码,我们只使用了4个GPIO:

module top( 
	input		clk_25m,
    input		rst_n,
    
    input		jtag_tck,
    input       jtag_tms,
    input       jtag_tdi,
    output      jtag_tdo,
    
    input		uart_rx,
    output		uart_tx,
    
    output		oled_scl,		
    inout		oled_sda,		
    output		oled_rst_n,
    output		led		   
);

wire		clk_100m;
wire		rst;

assign rst = ~rst_n;

pll u_pll(
  .refclk(clk_25m),
  .reset(rst),
  .clk0_out(clk_100m)
);

ps_wrapper u_ps_wrapper( 
	.clk(clk_100m),		//MCU的100MHz时钟
    .rst(rst),
    .timer_clk(clk_25m),	//fpga的25MHz时钟

    .jtag_tck(jtag_tck),
    .jtag_tdo(jtag_tdo),
    .jtag_tms(jtag_tms),		
    .jtag_tdi(jtag_tdi),
    
    .uart_rx(uart_rx),
    .uart_tx(uart_tx),

    .gpio_0(oled_scl),
    .gpio_1(oled_sda),
    .gpio_2(oled_rst_n),
    .gpio_3(led)
);

endmodule

        编译无误后添加管脚约束,之后重新编译综合,无误后 FPGA 部分的设置即完成:

set_pin_assignment	{ clk_25m }	{ LOCATION = D7; }
set_pin_assignment	{ jtag_tck }	{ LOCATION = C7; }
set_pin_assignment	{ jtag_tdi }	{ LOCATION = D5; }
set_pin_assignment	{ jtag_tdo }	{ LOCATION = C6; }
set_pin_assignment	{ jtag_tms }	{ LOCATION = D6; }
set_pin_assignment	{ led }	{ LOCATION = J5; }
set_pin_assignment	{ oled_rst_n }	{ LOCATION = H2; }
set_pin_assignment	{ oled_scl }	{ LOCATION = G4; }
set_pin_assignment	{ oled_sda }	{ LOCATION = J2; }
set_pin_assignment	{ rst_n }	{ LOCATION = H3; }
set_pin_assignment	{ uart_rx }	{ LOCATION = E4; }
set_pin_assignment	{ uart_tx }	{ LOCATION = A4; }

        oled 的 scl 与 sda 引脚约束参考TN816:

 

        下面进行 MCU 部分的设置,DEMO板上使用的是0.91寸 128*32 的 oled ,官方资料中没有讲述 oled 的具体型号,不过从官方例程来看,应该与0.91寸的SSD1306相同。程序编写步骤为:

        

        主函数如下,需要注意的是,oled 的复位功能我们使用的是 DEMO上的 KEY1,但是main函数中我们将anlogic_log_display函数放在while循环外面,所以复位功能并未使用到,感兴趣的可以修改程序:

#include "stdio.h"
#include "nuclei_sdk_hal.h"
#include "iic.h"


int main(void)
{
	anlogic_log_display();
    while(1)
    {

       	LED_High();
       	display_horizontal_scroll_enable();
    	delay_1ms(2270);
    	LED_Low();
    	display_horizontal_scroll_disable();
    	delay_1ms(4000);
    }
    return 0;
}

         iic.c如下:

#include "iic.h"
#include "nuclei.h"
#include "gpio_ctrl.h"
//========================IIC协议操作===========================
//拉高SCL,GPIO 0
void SCL_High(void)
{
	gpio_wr(0,1);
}

//拉低SCL,GPIO 0
void SCL_Low(void)
{
	gpio_wr(0,0);
}

//SDA拉低,GPIO 1
void SDA_Low(void)
{
	gpio_wr(1,0);
}

//SDA拉高,GPIO 1
void SDA_High(void)
{
	gpio_wr(1,1);
}

//SDA读取数据,GPIO 1
int SDA_read(void)
{
	int temp;

	temp = gpio_rd(1);

	if(temp == 1)
		return 1;
	else
		return 0;
}

//LED输出高,GPIO 3
void LED_High(void)
{
	gpio_wr(3,1);
}

//LED输出低,GPIO 3
void LED_Low(void)
{
	gpio_wr(3,0);
}

//延时1us
void delay1us(void)
{
	delay_1us(1);
}

void IIC_START(void)
{
	SCL_Low();		// SCL拉低 防止可能出现的各种误动作
	delay1us();
	SDA_High();		// SDA拉高
	SCL_High();		// SCL拉高 准备发出起始信号
	delay1us();
	SDA_Low();		// SDA拉低 发出起始信号
	SCL_Low();		// SCL拉低 开始传输
}

void IIC_STOP(void)
{
	SCL_Low();		// SCL拉低 防止可能出现的各种误动作
	SDA_Low();		// SDA拉低
	delay1us();
	SCL_High();		// SCL拉高 准备发出结束信号
	delay1us();
	SDA_High();		// SDA拉高 发出结束信号
}

int IIC_WaitACK(void)
{
	int s;
	SCL_Low();		// 拉低SCL
	delay1us();
	SDA_High();		// 拉高SDA 主机释放总线
	delay1us();
	SCL_High();		// 拉高SCL
	delay1us();
	s = SDA_read();		// 采集SDA信号线状态
	delay1us();
	SCL_Low();		// 拉低SCL 结束询问ACK
	if(s)
		return 0;	// 无应答(ACK)
	else
		return 1;	// 有应答(ACK)
}

void IIC_Write(int dat)
{
	int i;
	int temp;

	for(i=0; i<8; i++)
	{
		temp = dat & 0x80;
		if(temp == 0x80)
			SDA_High();
		else
			SDA_Low();
		dat <<= 1;			// 数据格式:高位在前
		delay1us();
		SCL_High();			// 拉高SCL 发送数据
		delay1us();
		SCL_Low();			// 拉低SCL 结束发送
	}
}

//=============================OLED驱动设置=============================
void oled_display_reset()		//显示复位
{
	gpio_wr(2,0);		//GPIO 2,即 oled_rst_n
	delay_1us(10000);
	gpio_wr(2,1);
	delay_1us(10000);
}

void OLED_Write_cmd(int cmd)	//写入命令
{
	IIC_START();
	IIC_Write(0X78);	// 写从机地址'0111 100' 读写符号'0'
	IIC_WaitACK();
	IIC_Write(0X00);	// 写命令
	IIC_WaitACK();
	IIC_Write(cmd);
	IIC_WaitACK();
}

void OLED_Write_dat(int dat)		//写数据
{
	IIC_START();		// 通信开始
	IIC_Write(0X78);	// 写从机地址'0111 100' 读写符号'0'
	IIC_WaitACK();
	IIC_Write(0X40);	// 写数据
	IIC_WaitACK();
	IIC_Write(dat);
	IIC_WaitACK();
}

void OLED_Init(void)			//OLED初始化
{
	oled_display_reset();

	OLED_Write_cmd(0XAE);		// 关OLED显示
	// 基础设置
	OLED_Write_cmd(0XA4);		// 输出GDDRAM内容
	OLED_Write_cmd(0XA6);		// 正常显示(1亮0灭)
	OLED_Write_cmd(0X81);		// 设置对比度
	OLED_Write_cmd(0X7F);		// 第127级对比度
	// COM和SEG输出设置
	OLED_Write_cmd(0XD3);		// 设置垂直显示偏移(向上)
	OLED_Write_cmd(0X00);		// 偏移0行
	OLED_Write_cmd(0X40);		// 设置GDDRAM起始行 0
	OLED_Write_cmd(0XA8);		// 设置MUX数 (显示行数)
	OLED_Write_cmd(0X3F);		//  MUX=63	 (显示63行)
	OLED_Write_cmd(0XA1);		// 左右反置关(段重映射)
	OLED_Write_cmd(0XC8);		// 上下反置关(行重映射)
	OLED_Write_cmd(0XDA);		// 设置COM引脚配置
	OLED_Write_cmd(0X02);		// 序列COM配置,禁用左右反置
	// 时钟设置
	OLED_Write_cmd(0XD5);		// 设置DCLK分频和OSC频率
	OLED_Write_cmd(0X80);		// 无分频,第8级OSC频率
	// 开OLED
	OLED_Write_cmd(0X8D);		// 启用电荷泵
	OLED_Write_cmd(0X14);		// 启用电荷泵
	OLED_Write_cmd(0XAF);		// 开OLED显示

	IIC_STOP();
}

void OLED_Clear(void)			//清屏
{
	int i,j;

	OLED_Write_cmd(0X00);		// 水平寻址模式
	OLED_Write_cmd(0X21);		// 设置列起始和结束地址
	OLED_Write_cmd(0X00);		// 列起始地址 0
	OLED_Write_cmd(0X7F);		// 列终止地址 127
	OLED_Write_cmd(0X22);		// 设置页起始和结束地址
	OLED_Write_cmd(0X00);		// 页起始地址 0
	OLED_Write_cmd(0X07);		// 页终止地址 7

	for(i=0; i<8; i++)		// 写入一帧'0'
		for(j=0; j<128; j++)
			OLED_Write_dat(0X00);

	IIC_STOP();
}

void OLED_Frame(int P[8][128])		//写入图像数据
{
	int i,j;

	OLED_Write_cmd(0X20);	// 设置GDDRAM模式
	OLED_Write_cmd(0X00);	// 水平寻址模式
	OLED_Write_cmd(0X21);	// 设置列起始和结束地址
	OLED_Write_cmd(0X00);	// 列起始地址 0
	OLED_Write_cmd(0X7F);	// 列终止地址 127
	OLED_Write_cmd(0X22);	// 设置页起始和结束地址
	OLED_Write_cmd(0X00);	// 页起始地址 0
	OLED_Write_cmd(0X07);	// 页终止地址 7

	for(i=0; i<8; i++)		// 写入一帧数据
	{
		for(j=0; j<128; j++)
		{
			OLED_Write_dat(P[i][j]);
			IIC_STOP();
		}

	}
	IIC_STOP();
}

void display_horizontal_scroll_enable()
{
	OLED_Write_cmd(0x2f);//开启滚动
}

void display_horizontal_scroll_disable()
{
	OLED_Write_cmd(0x2e);//关闭滚动
}

void anlogic_log_display(void)
{
	int index=0;
	int oled_display_data[8][128];
    int anlogic_log_data[512] =	{0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00,
			0x0f, 0x80, 0x00, 0x00, 0x0f, 0x80, 0x00, 0xf0, 0x0f, 0x80, 0x00, 0xf8, 0x0f, 0x80, 0x00, 0x78,
			0x07, 0x80, 0x00, 0x78, 0x07, 0xc0, 0x00, 0x78, 0x07, 0xc0, 0x00, 0x78, 0x07, 0xc0, 0x00, 0x78,
			0x03, 0xe0, 0x00, 0x78, 0x03, 0xf0, 0x00, 0xf8, 0x01, 0xf8, 0x00, 0xf8, 0x00, 0xfc, 0x01, 0xf8,
			0x00, 0x7f, 0xc7, 0xf0, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xc0,
			0x00, 0x03, 0xff, 0x80, 0x07, 0x00, 0x18, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00,
			0x07, 0xff, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xf8,
			0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0x00,
			0x07, 0xc1, 0xe0, 0x00, 0x07, 0xc0, 0xff, 0x00, 0x07, 0x80, 0xff, 0xf0, 0x07, 0x80, 0xff, 0xf0,
			0x07, 0x80, 0x7f, 0xf0, 0x07, 0x80, 0x71, 0xf8, 0x07, 0x80, 0x20, 0xf8, 0x07, 0x80, 0x20, 0x78,
			0x07, 0x80, 0x00, 0x78, 0x07, 0xc0, 0x00, 0x78, 0x03, 0xc0, 0x00, 0x78, 0x03, 0xe0, 0x00, 0xf8,
			0x03, 0xf0, 0x00, 0xf8, 0x01, 0xf8, 0x00, 0xf8, 0x00, 0xfc, 0x01, 0xf8, 0x00, 0x7f, 0x87, 0xf0,
			0x00, 0x3f, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x03, 0xff, 0x80,
			0x00, 0x00, 0x7f, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x00, 0xff, 0xf8, 0x00,
			0x01, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x3f, 0xe0,
			0x0f, 0xc0, 0x0f, 0xe0, 0x0f, 0x80, 0x03, 0xf0, 0x0f, 0x80, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0xf8,
			0x0f, 0x80, 0x00, 0x78, 0x07, 0x80, 0x00, 0x78, 0x07, 0x80, 0x00, 0x78, 0x07, 0xc0, 0x00, 0x78,
			0x03, 0xe0, 0x00, 0x78, 0x03, 0xf8, 0x00, 0xf8, 0x01, 0xfe, 0x01, 0xf8, 0x00, 0xff, 0x07, 0xf8,
			0x00, 0x7f, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xe0, 0x00, 0x07, 0xff, 0xc0,
			0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x78,
			0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x07, 0x00, 0x00, 0x78,
			0x07, 0xf0, 0x00, 0x78, 0x07, 0xff, 0x80, 0x78, 0x07, 0xff, 0xf8, 0x78, 0x07, 0xff, 0xff, 0xf8,
			0x07, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xf8,
			0x08, 0x00, 0x00, 0x78, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00,
			0x09, 0x24, 0x00, 0x00, 0x09, 0x24, 0x00, 0x00, 0x09, 0x24, 0x80, 0x00, 0x09, 0x24, 0x90, 0x00,
			0x09, 0x24, 0x90, 0x00, 0x09, 0x24, 0x94, 0x00, 0x09, 0x24, 0x94, 0x80, 0x09, 0x24, 0x94, 0x90,
			0x09, 0x24, 0x94, 0x80, 0x09, 0x24, 0x94, 0x30, 0x09, 0x24, 0x90, 0xf0, 0x09, 0x24, 0x93, 0xf0,
			0x09, 0x24, 0x8f, 0xf0, 0x09, 0x24, 0x3f, 0xf0, 0x09, 0x24, 0xff, 0xe0, 0x09, 0x23, 0xff, 0x80,
			0x09, 0x0f, 0xfe, 0x00, 0x08, 0x3f, 0xf8, 0x10, 0x08, 0xff, 0xe0, 0x70, 0x03, 0xff, 0x80, 0xf0,
			0x07, 0xff, 0x00, 0xf0, 0x03, 0xff, 0xc0, 0xf0, 0x00, 0x7f, 0xf0, 0xf0, 0x00, 0x1f, 0xfc, 0xf0,
			0x00, 0x07, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x1f, 0xf0,
			0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x10};


    //图像数据映射为SSD1306的显示数据
	for(int j=0; j<128; j++)
	{
		for(int i=7; i>=0; i--)
		{
			if(i > 3)
			{
				oled_display_data[i][j] = anlogic_log_data[index];
				index++;
			}
			else
				oled_display_data[i][j] = 0x00;
		}
	}

	OLED_Init();      //初始化

	OLED_Clear();     //清屏

	OLED_Write_cmd(0x2e);//关闭滚动

	OLED_Frame(oled_display_data);  //写入图像

	OLED_Write_cmd(0x27);  //水平向左或者右滚动 26/27
	OLED_Write_cmd(0x00);  //虚拟字节
	OLED_Write_cmd(0x00);  //起始页 0
	OLED_Write_cmd(0x07);  //滚动时间间隔
	OLED_Write_cmd(0x07);  //终止页 7
	OLED_Write_cmd(0x00);  //虚拟字节
	OLED_Write_cmd(0xff);  //虚拟字节
	OLED_Write_cmd(0x2f);  //开启滚动
}


        需要注意的是,在iic.c文件中使用到了delay_1ms与delay_1us函数,头文件nuclei.h中只存在delay_1ms,我们需进入nuclei_common.c中添加delay_1us函数,并在nuclei.h声明,delay_1us函数参考的是官方例程。

 

        gpio_ctrl.c用于控制4个gpio输入输出:

#include "gpio_ctrl.h"
#include "global.h"

void gpio_wr(int index,int wr_data)		//GPIO输出
{
	switch(index)
	{
		case 0:		//GPIO 0,即 scl 控制
			gpio_in_en  = gpio_in_en & 0xfffffffe;	//IEN寄存器值共32位,GPIO 0为第0位,输入不使能
			if(wr_data == 1)
				gpio_out = gpio_out | 0x00000001;	//OVAL寄存器值共32位,GPIO 0为第0位,输出1
			else
				gpio_out = gpio_out & 0xfffffffe;	//输出0
			gpio_out_en = gpio_out_en | 0x00000001;	//OEN寄存器值共32位,GPIO 0为第0位,输出使能
		break;
		case 1:		//GPIO 1,即 sda 控制
			gpio_in_en  = gpio_in_en & 0xfffffffd;	//IEN寄存器值共32位,GPIO 1为第1位,输入不使能
			if(wr_data == 1)
				gpio_out = gpio_out | 0x00000002;	//OVAL寄存器值共32位,GPIO 1为第1位,输出1
			else
				gpio_out = gpio_out & 0xfffffffd;	//输出0
			gpio_out_en = gpio_out_en | 0x00000002;	//OEN寄存器值共32位,GPIO 1为第1位,输出使能
		break;
		case 2:		//GPIO 2,即 oled_rst_n 控制
			gpio_in_en  = gpio_in_en & 0xfffffffb;
			if(wr_data == 1)
				gpio_out = gpio_out | 0x00000004;
			else
				gpio_out = gpio_out & 0xfffffffb;
			gpio_out_en = gpio_out_en | 0x00000004;
		break;
		case 3:		//GPIO 3,即 led 控制
			gpio_in_en  = gpio_in_en & 0xfffffff7;
			if(wr_data == 1)
				gpio_out = gpio_out | 0x00000008;
			else
				gpio_out = gpio_out & 0xfffffff7;
			gpio_out_en = gpio_out_en | 0x00000008;
		break;
		case 4:		//GPIO 4,未使用
			gpio_in_en  = gpio_in_en & 0xffffffef;
			if(wr_data == 1)
				gpio_out = gpio_out | 0x00000010;
			else
				gpio_out = gpio_out & 0xffffffef;
			gpio_out_en = gpio_out_en | 0x00000010;
		break;
		case 5:		//GPIO 5,未使用
			gpio_in_en  = gpio_in_en & 0xffffffdf;
			if(wr_data == 1)
				gpio_out = gpio_out | 0x00000020;
			else
				gpio_out = gpio_out & 0xffffffdf;
			gpio_out_en = gpio_out_en | 0x00000020;
			break;
		case 6:		//GPIO 6,未使用
			gpio_in_en  = gpio_in_en & 0xffffffbf;
			if(wr_data == 1)
				gpio_out = gpio_out | 0x00000040;
			else
				gpio_out = gpio_out & 0xffffffbf;
			gpio_out_en = gpio_out_en | 0x00000040;
			break;
		case 7:		//GPIO 7,未使用
			gpio_in_en  = gpio_in_en & 0xffffff7f;
			if(wr_data == 1)
				gpio_out = gpio_out | 0x00000080;
			else
				gpio_out = gpio_out & 0xffffff7f;
			gpio_out_en = gpio_out_en | 0x00000080;
			break;
		default:
		break;
	}
}

int gpio_rd(int index)		//GPIO输入
{
	int temp;
	switch(index)
	{
		case 0: 		//GPIO 0,即 scl 控制
			gpio_in_en  = gpio_in_en | 0x00000001;	//IEN寄存器值共32位,GPIO 0为第0位,输入使能
			gpio_out_en = gpio_out_en & 0xfffffffe; //OEN寄存器值共32位,GPIO 0为第0位,输出不使能
			temp = gpio_in;
			temp = temp & 0x00000001;
			if(temp == 0x00000001)
				return 1;
			else
				return 0;
			break;
		case 1: 		//GPIO 1,即 sda 控制
			gpio_in_en  = gpio_in_en | 0x00000002;
			gpio_out_en = gpio_out_en & 0xfffffffd;
			temp = gpio_in;
			temp = temp & 0x00000002;
			if(temp == 0x00000002)
				return 1;
			else
				return 0;
			break;
		case 2: 		//GPIO 2,即 oled_rst_n 控制
			gpio_in_en  = gpio_in_en | 0x00000004;
			gpio_out_en = gpio_out_en & 0xfffffffb;
			temp = gpio_in;
			temp = temp & 0x00000004;
			if(temp == 0x00000004)
				return 1;
			else
				return 0;
			break;
		case 3: 		//GPIO 1,即 led 控制
			gpio_in_en  = gpio_in_en | 0x00000008;
			gpio_out_en = gpio_out_en & 0xfffffff7;
			temp = gpio_in;
			temp = temp & 0x00000008;
			if(temp == 0x00000008)
				return 1;
			else
				return 0;
			break;
		case 4:
			gpio_in_en  = gpio_in_en | 0x00000010;
			gpio_out_en = gpio_out_en & 0xffffffef;
			temp = gpio_in;
			temp = temp & 0x00000010;
			if(temp == 0x00000010)
				return 1;
			else
				return 0;
			break;
		case 5:
			gpio_in_en  = gpio_in_en | 0x00000020;
			gpio_out_en = gpio_out_en & 0xffffffdf;
			temp = gpio_in;
			temp = temp & 0x00000020;
			if(temp == 0x00000020)
				return 1;
			else
				return 0;
			break;
		case 6:
			gpio_in_en  = gpio_in_en | 0x00000040;
			gpio_out_en = gpio_out_en & 0xffffffbf;
			temp = gpio_in;
			temp = temp & 0x00000040;
			if(temp == 0x00000040)
				return 1;
			else
				return 0;
			break;
		case 7:
			gpio_in_en  = gpio_in_en | 0x00000080;
			gpio_out_en = gpio_out_en & 0xffffff7f;
			temp = gpio_in;
			temp = temp & 0x00000080;
			if(temp == 0x00000080)
				return 1;
			else
				return 0;
			break;
	}
	return 0;
}



        其中global.h文件中声明了对 IVAL、 IEN、 OEN、 OVAL 四个寄存器的地址,将其单独拿出来声明是为了防止出现多重定义的警告,GPIO器件地址在官方资料中没有找到,在官方给的例程中可以找到,IVAL、 IEN、 OEN、 OVAL 四个寄存器的地址及使用方法在TN817中有介绍:

 

 

        于是global.h文件中定义如下:

#ifndef APPLICATION_GLOBAL_H_
#define APPLICATION_GLOBAL_H_

#define GPIO_BASE_ADDRESS 0xE0020000


long unsigned int *GPIO_IVAL = GPIO_BASE_ADDRESS + 0x00000000;
long unsigned int *GPIO_IEN  = GPIO_BASE_ADDRESS + 0x00000004;
long unsigned int *GPIO_OEN  = GPIO_BASE_ADDRESS + 0x00000008;
long unsigned int *GPIO_OVAL = GPIO_BASE_ADDRESS + 0x0000000c;




#define gpio_in     *GPIO_IVAL
#define gpio_in_en  *GPIO_IEN
#define gpio_out_en *GPIO_OEN
#define gpio_out    *GPIO_OVAL



#endif /* APPLICATION_GLOBAL_H_ */

        编译无误后 FD 部分完成,我们打开 TD 下载 bit 与 hex 文件至芯片中,下载方法在前几期中均已讲述,本期测评的下载方式与之前一致:

         

显示效果是安路logo按一定时间滚动,并且在滚动时LEDB亮,不滚动时LEDB熄灭。

源码在上文中均已给出,相关注释也已加上,需要的可以参考。

对于 oled 驱动不熟悉的可以参考0.91寸的SSD1306 ,需要注意的是 DEMO 板上标示的 oled  SDA是J4,而资料中给的是J2,这里是板子上标错了。

与同行测评的一篇 oled 对比来看,本测评中并未添加时钟约束,而 FPGA JTAG 与 MCU JTAG 均能连接,产生区别的原因尚未找到。

最新回复

支持国产,希望国产芯片各方面都快速展起来,让国内工厂不再承受高价的国外芯片。   详情 回复 发表于 2023-3-19 11:56
点赞(1) 关注
 
 

回复
举报

20

帖子

0

TA的资源

一粒金砂(中级)

沙发
 
OLED.zip (886.59 KB, 下载次数: 7)

本次测评的完整工程。

 
 
 

回复

210

帖子

3

TA的资源

一粒金砂(高级)

板凳
 

支持国产,希望国产芯片各方面都快速展起来,让国内工厂不再承受高价的国外芯片。

 
 
 

回复

20

帖子

0

TA的资源

一粒金砂(中级)

4
 

错误提示:在 IVAL、 IEN、 OEN、 OVAL寄存器部分的表格中,OEN 和 OVAL 处的名称标错了。

 
 
 

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

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表