当前位置:   article > 正文

【第五届集创赛备赛】七、紫光同创李星钢和王斌赛题培训(2021年4月13日)_基于紫光同创pango pgl fpga与risc-v的嵌入式系统 开发验证实训平台

基于紫光同创pango pgl fpga与risc-v的嵌入式系统 开发验证实训平台

讲师介绍:

  • FPGA应用方案工程师 李星钢
  • FAE工程师 王斌

培训内容:

  • 1、PDS软件使用经验分享
  • 2、赛题仿真设计及注意事项
  • 3、互动答疑

一、仿真

//UDP_HW_SPEEDUP--------------------------------------------------------
    wire HSEL_temp;
    assign HSEL_temp = HSEL && (HADDR[31:28] == 4'h7);

	reg [7:0] test_datai;
	reg       test_dbusy;
    wire      dready;

	always @(posedge HCLK or negedge SYSRESETn) begin
      if (~SYSRESETn) begin
        test_datai <= {8{1'b0}};
	    test_dbusy <= 1'b0;
	  end
      else if(dready) begin
        test_datai <= test_datai + 1'b1;
		test_dbusy <= 1'b1;
	  end
      else begin
        test_datai <= {8{1'b0}};
	    test_dbusy <= 1'b0;
	  end
    end

    assign udp_tpnd = tsmac_tpnd && udp_cs;

    // UDP SPEEDUP is driven from the AHB
    generate if (`CORTEXM1_AHB_UDP == 1) begin : gen_udp_hw_speedup_0
    udp_hw_speedup u_udp_hw_speedup(
        .HCLK                   (HCLK),         // system bus clock
        .HRESETn                (SYSRESETn),    // system bus reset
                                      
        .datai                  (test_datai),   // source data
        .dbusy                  (test_dbusy),   // source data valid  
        .dready                 (dready),       // hw_speedup_ready
                                                                                            
        .HSEL                   (HSEL_temp),    // AHB peripheral select
        .HREADY                 (HREADY),       // AHB ready input
        .HTRANS                 (HTRANS),       // AHB transfer type
        .HSIZE                  (HSIZE),        // AHB hsize
        .HWRITE                 (HWRITE),       // AHB hwrite
        .HADDR                  (HADDR),        // AHB address bus
        .HWDATA                 (HWDATA),       // AHB write data bus  
                         
        .HREADYOUT              (HREADYOUT_udp),// AHB ready output to S->M mux
        .HRESP                  (HRESP_udp),    // AHB response
        .HRDATA                 (HRDATA_udp),
    
        .udp_tdata              (udp_tdata),    // TSMAC tx data
        .udp_tstart             (udp_tstart),   // TSMAC tx start
        .udp_tpnd               (udp_tpnd),     // TSMAC tx going
        .udp_tlast              (udp_tlast),    // TSMAC tx end

        .udp_cs                 (udp_cs)        // UDP tx valid
    );
    end else
    begin : gen_no_udp_hw_speedup_0
      assign dready               = 1'b0;
    
      assign HREADYOUT_udp        = 1'b1;
      assign HRESP_udp            = 1'b0;
      assign HRDATA_udp           = {32{1'b0}};
    
      assign udp_tdata            = {8{1'b0}};
      assign udp_tstart           = 1'b0;
      assign udp_tlast            = 1'b0;
    
      assign udp_cs               = 1'b0;
    end endgenerate
    
//MEM-------------------------------------------------------------------
    wire a_wr_en;
    assign a_wr_en = w_en | ~r_en;

    wire [31:0] rdata0;
    assign rdata = rdata0;

    TEST_RAM u_TEST_RAM (
      .wr_data                  (wdata),        // input  [31:0]
      .wr_addr                  (waddr[7:0]),   // input  [7:0]
      .wr_en                    (a_wr_en),      // input
      .wr_clk                   (HCLK),         // input
      .wr_clk_en                (mem_cs[0]),    // input
      .wr_rst                   (1'b0),         // input

      .rd_addr                  (raddr[7:0]),   // input  [7:0]
      .rd_data                  (rdata0),       // output [31:0]
      .rd_clk                   (HCLK),         // input
      .rd_rst                   (1'b0)          // input
    );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

直接挂在顶层,需要的GPIO直接拖到模块里面就行了。自己建个.v文件把它放到顶层即可。通过定义的地址段,通过软核操作它的地址偏移量,就可以直接操作它了。

为什么不能直接用提供的SPI模块,通过片选控制SPI读写什么的?
本次大赛的目的锻炼总线的方式挂载自己的模块,通过软核控制,这三个东西需要互动起来。如果直接用提供好的GPIO模块去访问自己的东西,相当于直接脱节了,相当于什么都没做。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

GPIO_SetBit 实现如下:

void GPIO_SetBit(GPIO_TypeDef* GPIOx,uint32_t GPIO_Pin)
{
	GPIOx->DATAOUT |= GPIO_Pin;
}
  • 1
  • 2
  • 3
  • 4

注意,GPIOx->DATAOUT |= GPIO_Pin;等价于GPIOx->DATAOUT = GPIOx->DATAOUT | GPIO_Pin;,即先把GPIOx->DATAOUT寄存器中的值读出来,然后再与 GPIO_Pin 进行或操作。故,仿真结果不是单纯的0和1的切换,往里面写0写1,就是高低电平,可能默认的DATAOUT 是有数据的,不是预期的高低切换!

在这里插入图片描述
全局,临时变量的等的空间分配都是从0x30000000这个地址开始的!

TEST_ADDR = temp_cnt++;
  • 1

第一次运行到该语句时,TEST_ADDR 的值为 temp_cnt 自加之前的值,temp_cnt的值为自加之后的值。

temp_cnt 是一个全局变量,是系统自动分配的,在数据段地址内随机分配。

TEST_ADDR = 127; 对应地址:0x7000 1000;对应时间:441360000000 fs
temp_cnt = 128; 对应地址:0x3000 0028;对应时间:441460000000 fs
TEST_ADDR = 128; 对应地址:0x7000 1000;对应时间:442060000000 fs

上述的仿真是特殊的地址赋值,评审把结果做成视频,找一些特殊的点,跟C代码结合,如何快速的看到你这个仿真确实是跑起来了!

SD卡模块也要做成一个仿真。参赛队伍比较多,不可能一个个去看,会去抽查5个里面抽1个,进行实实在在的跑,更多的时候是看大家的仿真结果,要更直观的去凸显自己的仿真记过,不仅仅去录视频还要有文档去讲解。


#define TEST_ADDR (*(__IO uint32_t*)(0x70001000))
int temp_cnt = 0;


int main(void)
{
	SystemInit();
//	TimerInit();
	GpioInit();
//	UartInit();
//	SPIInit0();
//	I2CInit();
//	SystickInit();
//	NVIC_SetPriority(SysTick_IRQn, 1);								
	WatchDogInit(WATCH_DOG,2);									
	DEBUG_P("PANGO Cortex-M1 Start Run......\r\n");
	DEBUG_P("JEDEC  id = 0x%x\n",SFLASH_ReadJEDEC_ID());

	while(1)
	{
//		if(key_flag)
//		{
//			Delay(1000);
//			if(!(GPIO_ReadBits(GPIO0)&0x0001))
//			{
//				DEBUG_P("Key interrupt OK.....\r\n");
//			}
//			key_flag = false;
//		}
//		Timer_test(timer_counter);
		
		GPIO_SetBit(GPIO0,LED_PIN);
		GPIO_ResetBit(GPIO0,LED_PIN);
		TEST_ADDR = temp_cnt++;
	}
}





  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

仿真需要使用make_hex128.exe生成3个.data文件(仿真用的);make_hex.exe 生成4个itcm文件(BootLoader用的)。

BootLoader不存在.data

在这里插入图片描述

在这里插入图片描述

而后放置到仿真的目录下.\pgr_FPGA_Cortex-M1_eval\rtl_design\pgr_ARM_Cortex_M1_PGL22_324_eval_4_6\simulation

在这里插入图片描述

直接覆盖,而后重新运行sim.bat文件

二、上板

I2C文件修改

EEPROM地址是8bit位宽,不需要用到16bit,故直接注释掉PANGO_i2c_eeprom.c读写里面的高8位操作:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

接着在PANGO_i2c_eeprom.h文件中,修改I2C_PageSize 为16

为什么合成sfc文件时,选的.bin文件偏移地址必须是0x000C0000呢?这个是由BootLoader确定的,如下图:

BootLoader工程地址:

.\pgr_FPGA_Cortex-M1_eval\software_design\boot\Cortex-M1_spi_flash_bootloader
  • 1

在这里插入图片描述
BootLoader去引导C语言从FLASH中去读数据,读数据去加载到DDR里,它的起始读地址,是从0xC0000开始的。

APP_BIN_SIZE 大小为409664,即644K = 256K,最大位流为256K。

故没必要修改BootLoader,即时跑LWIP和FreeRTOS,位流大小也够用!

BootLoader打印是看BootLoader起来了没,方便定位是BootLoader问题,还是应用程序问题!

仿真用的BootLoader和实际在板子上跑用的BootLoader是不一样的,也就是说4个ITCM文件不一样!

等功能没问题了,再去改或测试BootLoader。

黑金板下载到FLASH之后需要复位,或者掉电再运行!

在这里插入图片描述

上述点不了是因为,黑金的SPI线没有引出来!

答疑

片上跑,必须依赖块RAM,块RAM很珍贵!

不带操作系统十几个KB

跑操作系统和LWIP,代码段都有70+KB.

片上资源放不了,加Cache,把代码放到DDR。Cache的原理是:片上开一小块RAM,执行到哪一个段,从DDR里去取,如果命中了,直接在块RAM中去取,如果没有命中,去DDR里去取,地址和数据全部取出来,才能进行下一步处理。

实现SD卡的功能,即便没有挂到软核上去,但是逻辑端已经实现了这个功能。仿真也能跑起来。

0xC0000能不能改?

可以,需要改两个地方

  • 1、BootLoader工程里面的C0000需要改
  • 2、PDS工程合成SFC文件时的地址也需要改
  • 3、位流大小不能超过FLASH的余量

AHB总线使用:

只要看顶层,AHB总线就那么点东西,根据地址去做判断,去做偏移量处理,地址段在哪一段,数据是什么,怎么去处理什么的。

SD接口,怎么分配引脚?
参考UDP加速,总线定义好之后,在模块里例化GPIO就可以了。

黑金开发板SD卡引脚支持的是SPI模式,并不是SDIO模式。

没关系,什么模式。现在大赛需要做的是,通过AHB 总线接口去SD卡,总线怎么去操作,把模块规定一个起始地址,往这个寄存器里面去写数据,去控制SD卡读写。读操作相当于访问了一个SD卡的读操作。

开放的目的是给你们参考,看一下内部一个简单的寄存器读写怎么实现的,外设内部的所有动作都通过这些寄存器实现的。m1通过AHB总线写某个约定好的寄存器,就可以将需要实现的功能发给外设模块,比如m1通过AHB总线写地址为0×00000004寄存器的第一个bit位,这个bit位约定为进行i2c的start操作,外设内部逻辑一旦检测到改bit位有效,就开始造出i2c的是start波形。这个过程就实现了m1完成i2c的start操作

即要把软核和SD卡这个纯逻辑的东西联合

坏区检测思路
每个块都进行一个读写校验,看它有没有错。

不希望大家直接使用现有的SPI接口去访问SD卡!

在这里插入图片描述

SD卡仿真要求?
单独写激励,能仿真起来就可以了。能结合软核一起跑,通过软核即C语言,控制寄存器跑起来,这样也是可以的!这样晋级的概率更大!

在这里插入图片描述

是的,无法挂。

在这里插入图片描述
自己写1个模块,挂载AHB总线上,实现SD卡的读写,这样也是可以的!不一定拿黑金的代码来!只要能实现SD卡的读写,并且挂载AHB总线上,没有用现成的东西,这个就是可以的!

在这里插入图片描述
初审不要求LWIP仿真,也没法跑,做TCP/IP的激励也很复杂

在这里插入图片描述
这样没有通过网线与PC机交互,算是附加功能。

在这里插入图片描述

??

在这里插入图片描述
上板的BootLoader工程和仿真的BootLoader文件是不一样的(4个ITCM文件不一样)!分别放在了工程里面!不需要动!在完成了功能之后,再去尝试这些功能!

在这里插入图片描述
底下配有说明文档,用的更多的是查核?

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

存储空间不用担心,使用了CACHE之后,DDR的寻址范围,CACHE都是可以访问的!

ICACHE指令起始地址必须配置为:0x10000000,DDR颗粒映射范围:0x10000000~0x10FFFFFF(16MB)
DCACHE数据起始地址必须配置为:0x30000000,DDR颗粒映射范围:0x30000000~0x3FFFFFFF(256MB)

除了0x10000000前面十几M的代码段外,后面的数据段,全部都是可以映射到DDR,即几百兆的空间都是可以通过软核申请操作的!

对应映射的实际物理地址,映射到了DDR中,实际地址是多少呢?需要通过C语言去把地址读出来,读出来过后,与实际DDR地址对应起来。

数据段地址,在keil中可以通过魔术棒配置为0x30001000,那么0x30000000 ~ 0x30001000之间的地址去哪了呢?它还是实际存在的,实际映射到DDR上,相当于静态存储空间,可以通过C语言直接访问地址的!可参考工程:

.\pgr_FPGA_Cortex-M1_eval\software_design\boot\Cortex-M1_Icache_Dcache_my_mem //参考这个工程,了解如何使用静态存储空间!
  • 1

这个功能对需要大存储空间的需求特别重要!还可以知道实际的Buffer地址是多少!0x30000000 ~ 0x30001000之间的地址段就是静态的,系统在编译的时候不会编译到这个代码段,而这个代码段的用处就可以访问了。这个就很方便,可以随意使用,与DDR交互,只需要知道与DDR对应的地址是多少就可以了!比如0x30000000对应的DDR地址在xxxx,

上面那个Cortex-M1_Icache_Dcache_my_mem 工程,使用了ICACHE,但是数据段是放到了DTCM上面!只是把DCACHE当成了一个外部设备!起始地址是0x30000000,通过指针的方式直接对它进行读写,8位读写,16位,32位读写都可以!

在这里插入图片描述

???

在这里插入图片描述

基本要求必须满足,其他看SD卡读写速度,图像传输稳定,图像传输不卡顿,显示很流畅,实时性比较高(前面放一个遮挡物,上位机延时比较短),并不是功能多谁就厉害,还需要看性能!性能越高,得分越高!

在这里插入图片描述

GPIO绑定正确,自己去操作偏移量即可!

在这里插入图片描述

在这里插入图片描述

首先要明白软核和纯逻辑之间的纯逻辑是什么,用C语言怎么去控制纯逻辑代码,通过一个地址,这个地址可以在AHB总线上也可以在APB总线上!现在要求SD模块挂在AHB总线上!通过总线实现,AHB总线地址为0x7000 1000的初始地址,通过C语言往这个地址里面写1个1,你的AHB总线(verilog的input)收到了你的这个数据,把这个地址里面的数据值读出来是1,然后在自己的逻辑里面去做相应的操作!1是实现SD卡的读或写,0x7000 1004这个地址里面写个1,对应SD卡的操作(读或写)。比赛的目的,通过C语言,通过总线地址,去控制SD卡外设的动作!

本身纯逻辑就可以做这个事情,软核下发指令去做这个事情!

首先要想成功编译BootLoader工程,做如下修改:
在这里插入图片描述

在这里插入图片描述

解决方法:修改堆栈空间,默认分配的很大!魔术棒里面的IROM1和IRAM1分配的很小!

Stack_Size      EQU      0x00001000
Heap_Size       EQU      0x00001000
  • 1
  • 2

改为:

Stack_Size      EQU      0x00000100
Heap_Size       EQU      0x00000100
  • 1
  • 2

在这里插入图片描述
注意上图中的,Use MircroLIB勾不要去掉,下面的IROM1和IRAM1默认就行!

上面的配置之后,已经可以正常编译BootLoader工程了,仿真和上板的BootLoader工程区别即main.c中的SIMULATION宏有没有打开,打开就是仿真,不打开就是上板!

#define SIMULATION
  • 1

仿真不需要引导过程,即不需要从SPI-FLASH中把数据读出来进而写入DDR。因为我们是把3个.data文件数据直接放到了DDR里,故省略了这样一个过程!

BootLoader只要能跑起来,代码量没有超过256K,就真的没有必要去改!BootLoader仅仅只是个引导,BootLoader的作用是把你的应用程序加载起来!

应用程序里面完全没有必要勾选#RUN2,即make_hex.exe生成的4个ITCM文件是没有用的!不需要去关心ITCM文件,只需要关系bin文件即可!

在这里插入图片描述

1、软核本身的仿真,直观的看到软核跑起来!

2、SD卡的纯逻辑代码仿真,硬件代码已经初步实现,只差上板。或者更进一步SD卡与软核的通过C语言联合仿真。

在这里插入图片描述
更好的方式,是上位机上的按键,通过LWIP下发指令等!使用开发板上的物理按键也是可以的,上位机也是需要自己写的,界面功能!

在这里插入图片描述

没有标明外设名称的中断,表示软核本身的,暂时是没有用到的!
在这里插入图片描述

在这里插入图片描述

AHB总线基地址为0x4000 0000,现有的外设到了0x4900 0000,其后的0x4A00 0000 ~ 0x4F00 0000都是可以用的!
在这里插入图片描述

UDP加速模块的基地址为:0x70000000

在这里插入图片描述

一共用到了0x20,剩余的是都可以用的!即0x7000 0020之后的都可以用!

在这里插入图片描述

验证

1、PDS工程重新编译后的sbit与ICACHE_DCACHE_DEMO工程生成的.bin文件放到板子上看看是否可以运行呢?

没有问题!

2、


参考

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/396403
推荐阅读
相关标签
  

闽ICP备14008679号