2131|3

32

帖子

1

TA的资源

一粒金砂(中级)

楼主
 

安路SF1系列FPGA(一)两种方式点灯与串口通信-2 [复制链接]

 
本帖最后由 瓜弟 于 2023-3-1 00:39 编辑

在上篇文章中,介绍了SF1系列FPGA的工程建立、下载调试等方法。本文将继续在上一篇的基础上介绍串口通信的使用和使用AHB总线进行LED点灯。

1、串口通信的使用

       实际上,在创建的软件工程里,system_nuclei.c文件里,函数void _init(void)已经进行了串口的初始化,但是会发现在使用中,上位机出现乱码。需要在system_nuclei.c文件中,更改SYSTEM_CLOCK宏定义,将默认的80MHz更改为实际中PLL输出的频率100MHz。

         在main.c中添加如下串口输出代码。理想情况下,串口会每秒输出一次。但是我们在串口上位机中设为波特率为115200后,会发现,接收到的仍是乱码,如果我们将波特率更改为57600(115200的一半)后,会发现能正常接收不乱码了,这是为何?

#include <stdio.h>
#include "nuclei_sdk_hal.h"
#include "anl_printf.h"
#include "nuclei_uart.h"

int main(void)
{
	gpio_enable_output(GPIO, 1);
	gpio_enable_input(GPIO, 2);


	while(1)
	{
		if(gpio_read(GPIO, 2) != 0)
		{
			gpio_toggle(GPIO, 1);
			delay_1ms(1000);
			printf("anlogic\n");
		}
	}
}

那就是串口外设的工作频率不是100MHz,在《TN817_SF1 MCU用户指南》中4.3章节中,可知,串口外设的工作频率与CPU工作频率一致,那么到底是多少?且为什么delay_1ms(1000)函数又能准确执行呢?因为delay_1ms使用滴答定时器实现,而滴答定时器的时钟输入又是单独的25MHz,在上篇文章中,RISCV核的例化使用了两个时钟,一个为100MHz的主时钟,另一个则是由晶振时钟引脚输入而来的25MHz。那么CPU到底实际工作频率是多少呢?在startup_anlogic.S文件中,有如下代码

 其中CLK_REG_ADDR的定义在riscv_encoding.h文件中,值为0xE0000010,在《TN817_SF1 MCU用户指南》中,可以查到该地址的寄存器如下

     

对比代码可知,此处进行了二分频,CPU、串口工作的频率实际上只有50MHz。那么将启动代码中的0x83改为0x81即可正常使用。

 

2、使用AHB总线读写寄存器进行点灯

        AHB是属于AMBA下的一个片内总线协议,为多主多从结构,通过将在FPGA侧的硬件代码依据AHB接口协议作为从机挂载在AHB总线上,并在硬件代码中指定地址,即可实现由RISCV-V硬核的软件代码通过指针对目标硬件代码功能的访问与控制。常用的片内总线还有AXI、APB、wishbone等,其中常见的是AXI、AHB、APB,wishbone常见于开源项目,在opencores.org可见许多项目使用wishbone。

        SF1器件的AHB总线的可用地址范围未在数据手册中找到,根据官方的参考例程mcu_ahb_to_fpga,以及《TN817_SF1 MCU用户指南》猜测AHB的可用地址范围为0x4000_0000 ~ 0x5FFF_FFFF。可能由于可用空间较小,RISCV的AHB接口未提供HSELx片选信号,所以在实现过程中,不能使用HSELx信号作为状态机启动标志。且当有多个模块连接值AHB总线时,HREADY、HRESP、HRDATA等输出信号需要注意三态处理,本文仅有有一个模块使用AHB总线,故常规处理。

        关于AHB总线的时许本文不再讲解,各种资料太多,但仍推荐阅读AMBA标准文档。本文在上一篇的基础上,使用一个reg型变量存储来自AHB写入的控制量,该变量将连接至LED的引脚(H5),地址为0x43214320,通过对该寄存器写0或1,实现对LED的点灯控制。代码如下

module AHB_LED
#(
    parameter LED_ADDR = 32'h43214320
)
(
    input wire HCLK,
    input wire HRSTn,

    input wire[1:0] HTRANS,
    input wire[31:0] HADDR,
    input wire HWRITE,
    input wire[2:0] HSIEZ,
    input wire[2:0] HBURST,
    input wire[3:0] HPROT,
    input wire[31:0] HWDATA,
    output reg[31:0] HRDATA,
    output reg HREADY,
    output reg[1:0] HRESP,

    output reg LED
);

parameter HTRANS_IDLE       = 2'b00;        //Slave忽略掉此时的传输
parameter HTRANS_BUSY       = 2'b01;        //表示master正在处理数据,slave需要忽略掉此时的传输
parameter HTRANS_NONSEQ     = 2'b10;        //表明当前是单笔的数据,或者是Burst的第一笔数据
parameter HTRANS_SEQ        = 2'b11;        //是Burst传输的剩余数据

parameter HBURST_SINGLE     = 3'b000;       //单笔数据传输
parameter HBURST_INCR       = 3'b000;       //不定长递增方式批量传输
parameter HBURST_WRAP4      = 3'b000;       //4个数据回绕方式批量传输
parameter HBURST_INCR4      = 3'b000;       //4个数据递增方式批量传输
parameter HBURST_WRAP8      = 3'b000;       //8个数据回绕方式批量传输
parameter HBURST_INCR8      = 3'b000;       //8个数据递增方式批量传输
parameter HBURST_WRAP16     = 3'b000;       //16个数据回绕方式批量传输
parameter HBURST_INCR16     = 3'b000;       //16个数据递增方式批量传输

parameter HREADY_REDY       = 1'b1;
parameter HREADY_BUSY       = 1'b0;

parameter HRESP_OKEY        = 2'b00;        //传输完成
parameter HRESP_ERROR       = 2'b01;        //传输错误
parameter HRESP_RETRY       = 2'b10;        //传输未完成,请求主设备重新开始一个传输,
                                            //arbiter会继续使用通常的优先级
parameter HRESP_SPLIT       = 2'b11;        //传输未完成,请求主设备分离一次传输,
                                            //arbiter会调整优先级方案以便其他请求总线的主设备可以访问总线

parameter HSIZE_8b          = 3'b000;
parameter HSIZE_16b         = 3'b001;
parameter HSIZE_32b         = 3'b010;
parameter HSIZE_64b         = 3'b011;
parameter HSIZE_128b        = 3'b100;
parameter HSIZE_256b        = 3'b101;
parameter HSIZE_512b        = 3'b110;
parameter HSIZE_1024b       = 3'b111;

parameter HWRITE_WR         = 1'b1;
parameter HWRITE_RD         = 1'b0;

parameter FSM_IDLE          = 4'h0;
//parameter FSM_ADDR          = 4'h1;
parameter FSM_WR            = 4'h2;
parameter FSM_RD            = 4'h4;
reg[3:0] FSM_Current;
reg[3:0] FSM_Next;

always@(posedge HCLK or negedge HRSTn)
begin
    if(HRSTn == 0)
        begin
            FSM_Current <= FSM_IDLE;
        end
    else
        begin
            FSM_Current <= FSM_Next;
        end
end

always @(*) begin
    if(HRSTn == 0)
        begin
            FSM_Next <= FSM_IDLE;
        end
    else
        begin
            case(FSM_Current)
                FSM_IDLE:
                    begin
                        if( (HTRANS == HTRANS_NONSEQ) && (HADDR == LED_ADDR) )
                            begin
                                if(HWRITE == HWRITE_WR)
                                    begin
                                        FSM_Next <= FSM_WR;
                                    end
                                else
                                    begin
                                        FSM_Next <= FSM_RD;
                                    end
                            end
                        else
                            begin
                                FSM_Next <= FSM_IDLE;
                            end
                    end
                FSM_WR:
                    begin
                        FSM_Next <= FSM_IDLE;
                    end
                FSM_RD:
                    begin
                        FSM_Next <= FSM_IDLE;
                    end
                default:
                    begin
                        FSM_Next <= FSM_IDLE;
                    end
            endcase
        end
end

always@(posedge HCLK or negedge HRSTn)
begin
    if(HRSTn == 0)
        begin
            LED <= 1'b0;
            HRDATA <= 32'hZ;
            HREADY <= HREADY_REDY;
            HRESP <= HRESP_OKEY;
        end
    else
        begin
            case(FSM_Current)
                FSM_IDLE:
                    begin
                        if( (HTRANS == HTRANS_NONSEQ) && (HADDR == LED_ADDR) )
                            begin
                                LED <= LED;
                                HRDATA <= 32'hZZZZ_ZZZZ;
                                HREADY <= HREADY_BUSY;
                                HRESP <= HRESP_OKEY;
                            end
                        else
                            begin
                                LED <= LED;
                                HRDATA <= 32'h0;
                                HREADY <= HREADY_REDY;
                                HRESP <= HRESP_OKEY;
                            end
                    end
                FSM_WR:
                    begin
                        LED <= HWDATA[0:0];
                        HRDATA <= 32'h0;
                        HREADY <= HREADY_REDY;
                        HRESP <= HRESP_OKEY;
                    end
                FSM_RD:
                    begin
                        LED <= LED;
                        HRDATA <= {31'h0, LED};
                        HREADY <= HREADY_REDY;
                        HRESP <= HRESP_OKEY;
                    end
                default:
                    begin
                        LED <= 1'b0;
                        HRDATA <= 32'hZ;
                        HREADY <= HREADY_REDY;
                        HRESP <= HRESP_OKEY;
                    end
            endcase
        end
end


endmodule

在原有的代码的基础上,例化RISCV硬核时,将AHB总线信号例化,代码如下

module SOC(
    input wire clk,
    input wire clk_low,
    input wire rstn,
    
    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,
    
    output wire[2:0] htrans,
    output wire hwrite,
    output wire[31:0] haddr,
    output wire[2:0] hsize,
    output wire [2:0] hburst,
    output wire[3:0] hprot,
    output wire hmastlock,
    output wire[31:0] hwdata,
    input wire hclk,
    input wire[31:0] hrdata,
    input wire[1:0] hresp,
    input wire hready
);

	wire ps_gpio0_out;
	wire ps_gpio0_dir;
	wire ps_gpio0_in ;
	wire ps_gpio1_out;
	wire ps_gpio1_dir;
	wire ps_gpio1_in ;


gpio u1(
    .gpio_dir(ps_gpio0_dir),
    .gpio_out(ps_gpio0_out),
    .gpio_in(ps_gpio0_in),
    .pin(gpio_0)
);

gpio u2(
    .gpio_dir(ps_gpio1_dir),
    .gpio_out(ps_gpio1_out),
    .gpio_in(ps_gpio1_in),
    .pin(gpio_1)
);

RISCV u3(
    .core_clk(clk),
    .core_reset(rstn),
    .timer_clk        ( clk_low ),
    .jtag_tck         ( jtag_tck  ),
    .jtag_tdo         ( jtag_tdo  ),
    .jtag_tms         ( jtag_tms  ),
    .jtag_tdi         ( jtag_tdi  ),

    .soft_ip_apbm_en  ( 1'b0       ),
    .qspi0cfg1_mode   ( 1'b1       ),
    .qspi0cfg2_mode   ( 1'b1       ),

    .uart_tx          ( uart_tx  ),
    .uart_rx          ( uart_rx  ),

    .gpio0_out        ( ps_gpio0_out  ),
    .gpio0_dir        ( ps_gpio0_dir  ),
    .gpio0_in         ( ps_gpio0_in   ),

    .gpio1_out        ( ps_gpio1_out  ),
    .gpio1_dir        ( ps_gpio1_dir  ),
    .gpio1_in         ( ps_gpio1_in   ),

    .htrans           ( htrans      ),
    .hwrite           ( hwrite      ),
    .haddr            ( haddr       ),
    .hsize            ( hsize       ),
    .hburst           ( hburst      ),
    .hprot            ( hprot       ),
    .hmastlock        ( hmastlock   ),
    .hwdata           ( hwdata      ),
    .hclk             ( hclk        ),
    .hrdata           ( hrdata      ),
    .hresp            ( hresp       ),
    .hready           ( hready      )
);

endmodule

配置PLL,使其输出第二路时钟信号50MHz,作为AHB总线的时钟频率

 

在TOP层,将各模块组装起来

module TOP( 
	input wire clk_25MHz,
    input wire rstn,
    
    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,

    output wire     LED
);

wire clk_100MHz;
wire hclk;

pll U1(
     .refclk(clk_25MHz),
  	.reset(~rstn),
  	.clk0_out(clk_100MHz),
    .clk1_out(hclk)
);

 wire[2:0] htrans;
 wire hwrite;
 wire[31:0] haddr;
 wire[2:0] hsize;
 wire [2:0] hburst;
 wire[3:0] hprot;
 wire hmastlock;
 wire[31:0] hwdata;
 wire[31:0] hrdata;
 wire[1:0] hresp;
 wire hready;

SOC U2(
    .clk(clk_100MHz),
    .clk_low(clk_25MHz),
    .rstn(~rstn),
    
    .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(gpio_0),
    .gpio_1(gpio_1),

    .htrans           ( htrans      ),
    .hwrite           ( hwrite      ),
    .haddr            ( haddr       ),
    .hsize            ( hsize       ),
    .hburst           ( hburst      ),
    .hprot            ( hprot       ),
    .hmastlock        ( hmastlock   ),
    .hwdata           ( hwdata      ),
    .hclk             ( hclk        ),
    .hrdata           ( hrdata      ),
    .hresp            ( hresp       ),
    .hready           ( hready      )
    
);

AHB_LED U3(
	//ports
	.HCLK   		( hclk   		),
	.HRSTn  		( rstn  		),
	.HTRANS 		( htrans 		),
	.HADDR  		( haddr  		),
	.HWRITE 		( hwrite 		),
	.HSIEZ  		( hsize  		),
	.HBURST 		( hburst 		),
	.HPROT  		( hprot  		),
	.HWDATA 		( hwdata 		),
	.HRDATA 		( hrdata 		),
	.HREADY 		( hready 		),
	.HRESP  		( hresp  		),
	.LED    		( LED    		)
);

endmodule

经过综合后,补充LED引脚的约束

set_pin_assignment	{ LED }	{ LOCATION = H5; }
set_pin_assignment	{ clk_25MHz }	{ LOCATION = D7; }
set_pin_assignment	{ gpio_0 }	{ LOCATION = J5; }
set_pin_assignment	{ gpio_1 }	{ LOCATION = H3; }
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	{ rstn }	{ LOCATION = H2; }
set_pin_assignment	{ uart_rx }	{ LOCATION = E4; }
set_pin_assignment	{ uart_tx }	{ LOCATION = A4; }

以上就完成了硬件设计,软件设计很简单,对0x43214320地址进行写操作即可,代码如下

#include <stdio.h>
#include "nuclei_sdk_hal.h"
#include "anl_printf.h"
#include "nuclei_uart.h"



int main(void)
{
	gpio_enable_output(GPIO, 1);
	gpio_enable_input(GPIO, 2);

	unsigned char st = 1;

	while(1)
	{
		if(gpio_read(GPIO, 2) != 0)
		{
			gpio_toggle(GPIO, 1);
			delay_1ms(1000);
			*((unsigned long *)0x43214320) = st;
			st = ~st;
			printf("anlogic\n");
		}
	}
}

代码编译完成后,按照上一篇文章的教程,下载完成后,就可见H5引脚对应的LED的闪烁

47c7511287fa21b9cfdd3c8e1e1c9e72

 

附件为硬件与软件两个完整工程:

 

P1_RISCV_GPIO_UART.zip

728.3 KB, 下载次数: 6

硬件工程

P1_UART_LED_KEY.zip

373.02 KB, 下载次数: 4

软件工程

最新回复

我启动文件中更改为0x81后,会导致自己绑定的复位按键无法正常复位   详情 回复 发表于 2024-9-29 13:41
点赞 关注
 
 

回复
举报

6587

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

串口通信的使用和使用AHB总线进行LED点灯效果还行

 
 
 

回复

32

帖子

1

TA的资源

一粒金砂(中级)

板凳
 
Jacktang 发表于 2023-3-8 07:38 串口通信的使用和使用AHB总线进行LED点灯效果还行

 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

4
 

我启动文件中更改为0x81后,会导致自己绑定的复位按键无法正常复位

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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

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

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

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