AG32下fpga/cpld的使用入门 23 min read AG32入门文档 在AG32 芯片(所有型号)中,都有内嵌2K 的逻辑门,可供fpga/cpld 来使用。也就是说,使用AG32 的芯片时,有三种选择:1. 只使用mcu 部分;2. 只使用cpld 部分;3. 同时使用mcu 和cpld(即:mcu 和cpld 联合编程);如果:用于1(仅用做mcu),不必关注此文档。用于2(仅用做cpld),硬件设计和操作流程,请参考《MANUAL_AGRV2K_3.0.pdf》,也不必关注此文档。用于3(mcu 和cpld 联合编程):请按照该文档的描述,先完整走一个流程。 一、基础了解 1. AG32 整颗芯片包含两部分:mcu 和cpld。这两部分是相互独立的(各自编译、各自下载),但又可以相互连通起来(信号连通)。芯片要把这两部分的bin 都烧录进去,才能运行起来。2. mcu 和cpld 到外部PIN 脚的连通,是通过VE 来配置的。跟ST 芯片每个GPIO 固定对应某个PIN 脚不同,在AG32 中,所有的GPIO/大部分的外设,对外引脚并不是定死的。而是需要在VE 文件中指定对应。VE 中,除了配置GPIO 到PIN 的关联,还可以配置mcu 到cpld 之间的信号关联。3. Mcu+cpld 联合编程时,cpld 工程是由vscode 的“prepare LOGIC”命令自动生成的。注意:联合编程时,cpld 工程不能手工通过supra 建立。cpld 的操作也是依托vscode 工程来的,不再是孤立的。cpld 中的top module 的信号输入,是关联到mcu 工程的(由VE 配置出来)。4. cpld 在联合编程中的定位:整颗芯片运行时,需要两个bin:mcu 的bin 和cpld 的bin。如果芯片中只使用mcu 不使用cpld:此时,VE 文件里只配置mcu 用到的PIN 脚即可。这种情况下,vscode 工程中点“upload LOGIC”时,会自动生成默认logic(该logic 中“用户逻辑”为空而已),并编译出bin 并烧录。整个过程中,logic 部分对开发者来说是无感的。如果芯片中同时使用mcu 和cpld:那么工程配置是“自定义logic”。此时VE 文件里需要配置用到的mcu 和pin 之间、mcu 和cpld 之间、cpld 和pin 之间,三种情况下的信号关联。这种情况下,vsode 下点“prepare LOGIC”按钮,会为开发者生成cpld 的框架工程。开发者需要在这个框架下完成cpld 逻辑的编写。这个编写调试中,开发者持有主动权。等全部开发完成,并编译出bin,烧录就又回到VSCODE 去烧录。这个过程,除了logic 需要用户自己编写编译外,更外层的流程还是跟“默认Logic”是相同的。5. cpld 开发流程的简要描述:A. 在vscode 里定义好VE 配置;B. 在vscode 里使用prepare LOGIC 命令,生成cpld 的工程框架;C. 用quartus 打开该工程并添加自己的逻辑代码,最后转换工程,生成vo;D. 用supra 打开转换后的工程,编译出bin。以上都是精简描述,先有一个整体印象。下边是详细描述。 二、CPLD 使用流程 该部分会对AG32 下使用cpld 的过程做详细介绍。1、安装工具软件:fpga/cpld 需要使用Supra 和Altera Quartus II 两个软件来编程。其中:Supra.exe 软件在安装完SDK 后,已经在SDK 路径下了,可直接使用(无需额外安装Supra)。(注:如果在SDK 路径下没有找到Supra.exe,可进入AgRV_pio\packages\tool-agrv_logic\bin去打开。同时建议手工新建一个快捷方式到SDK 路径下以方便后续使用)Altera Quartus II 软件需要用户自行安装,安装后再安装对应的器件库。(注意:Quartus 不能使用Lite 版本,需要使用Full 版本。最好使用版本:Quartus II 64-Bit Version 13.0.1 Build 232 06/12/2013 SJ Full Version)在这两个软件中,Quartus 工具用来编写vlog 代码并导出vo 文件,Supra 工具使用vo 文件来生成最终的bin。2、建立cpld 空工程:这里默认是安装过VSCODE 以及mcu 的SDK 开发包的。如果没有安装,请参考《AG32 开发环境搭建.pdf》先搭建mcu 开发环境。搭建好SDK 环境后,这里以example(路径:…\AgRV_pio\platforms\AgRV\examples\example)为例建立工程。在example 样例程序中,默认是没有打开自定义ip 的。首先,要通过配置打开自定义ip:方法:在platformio.ini 中打开以下两项:ip_name = analog_iplogic_dir = logic注意:这两行去掉注释的时候,前边不要留空格。要顶格写。打开以上两项后,才能在左边栏看到创建logic 框架工程的选项(prepare LOGIC): 点击该功能【Prepare LOGIC】后,可以看到在example 工程目录下生成一个logic 文件夹,自动生成的文件如下图: 这里生成的logic 文件夹,就是后续编写cpld 的模板。 关于改写文件名:这里的文件名字,是根据platformio.ini 里边的配置项来的:board_logic.ve = example_board.veip_name = analog_iplogic_dir = logic如果想改文件名字,可先在platformio.ini 中更改名字,更改后再点生成按钮来自动生成。可更改的名字,就是上边的三项:board_logic.ve 对应logic 文件夹内example_board.v 的名字Ip_name 对应logic 文件夹内analog_ip.v 的名字Logic_dir 对应文件夹logic 的文件夹名字 在生成后的文件夹内,注意其中的两个.v 文件:analog_ip.v 和example_board.v。这两个文件是vlog 的源码文件。其中:analog_ip.v 是一份空的模板,用户自己要实现的功能,就在这个空模板上展开;这个空的模板里边,主要就是module analog_ip 的接口定义。example_board.v 是根据工程中example_board.ve 里的pin 配置,Logic prepare 时自动转换出来的v 源码,也是supra 工程的top module。这部分不要手工改动。到这里,空工程建立完毕。 注意:后期修改完VE 的配置后,Prepare LOGIC 时,会重新生成cpld 工程模板,这个模板文件都仍然存到logic文件夹下,且仍然是这两个.v 文件。只不过analog_ip.v 对应新增出analog_ip_tmpl.v 文件,而example_board.v 则是直接覆盖。由于analog_ip.v 是用户程序的入口,用户程序会从这里开始写。这个文件一定是会修改的。所以,每次prepare LOGIC 时,这个文件会对应生成analog_ip_tmpl.v 文件,而不是覆盖。生成出analog_ip_tmpl.v 后,用户要根据自己的情况,把新接口手动合并到analog_ip.v 去。注:这里只是以example 来举例。实际应用中,在导出空工程前,需要先配置好platformio.ini的其他项和example_board.ve 所需要的引脚。包括:board_logic.device 配置32/48/64/100 脚。 3、打开工程:使用前边安装的Quartus II,打开example\logic 下的工程。如果是初次使用Quartus II,在安装完器件库后,AG32 要选用器件库中里Cyclone IV E 的EP4CE75F23C8 来模拟。(默认打开example\logic 工程后已经是该项了,确认下即可)工程如下: 这里除了example_board.v 和analog_ip.v 外,还有个系统的alta_sim.v,这个文件是提供芯片系统的功能,类似函数库,可不用关注。此时,这个工程是个空的工程,用户要根据需求在analog_ip.v 中实现功能。再次回顾下3 个.v 文件:1. analog_ip.v:用户自定义logic 的入口。用户logic 实现在这里展开;2. example_board.v:整个logic 的top module。会关联analog_ip 的module 和atla_sim 下的各module。不要修改该文件。3. alta_sim.v:封装过的跟AG32 相关的各module。不要修改该文件。接下来进行空工程的转换和编译。注意:这里的空工程不能马上添加自己的代码,首先要进行工程转换(参考下个步骤) 4、工程转换:工程转换的目的,是把cpld 模板工程真正转换成quartus 实际运行的状态。操作步骤:打开Quartus 菜单的【tools】->【Tcl Scripts…】,弹出框如下图: 【Run】运行成功后,可以看到该logic 占用的资源数量。 这个转换的过程,顺便进行了cpld 工程的编译。上图中斜杠前边标识的大小就是所占的逻辑单元数(后续使用中逻辑单元不能超过2K)。注意:第一次导入工程,必须执行上图的方式来转换。后续编写和修改cpld 代码后,可以仍然执行上图方式,也可以直接点下图的“编译”按钮来编译。 执行到这里,会在logic 下生成vo 文件出来(在\logic\simulation\modelsim 下),Quartus工具的任务完成。接下来打开Supra 来继续生成bin 文件。 5、supra 编译:在Supra 工具里,打开该工程(example\logic)。然后,点击【左上角Tool】-> 【Compile】,在弹出的画面中点右下角的【run】 编译成功后,画面会有提示。Compile design example_board done with code 0然后在logic 路径下可以看到新编译出来的bin。这个bin 就是要烧录到芯片的cpld.bin。执行到这里,supra 工具的任务完成。 6、烧录:烧录需要回到vscode 下烧录。如果在vscode 下烧录,如下图: 到这里,新建一个空工程、转换、编译、烧录的整个流程描述完毕。注意:后续如果在VE 里修改过配置,则需要走一个全过程:vscode 下prepare LOGIC 再生成一遍cpld 模板、合并analog_ip_tmpl.v 到analog_ip.v 中去、启动quartus 去转换、supra 下编译,回到vscode 下烧录logic。后续如果只是在quartus 下编写cpld 代码,需要走的几步:quartus 下编译、supra 下编译、回到vscode 下烧录logic。 三、上述过程中的说明: 上述流程中涉及两个比较关键的点:1. 自定义模块的命名:自定义的逻辑,自定义文件名必须与自定义模块名相同,就是在platformio.ini 中设置的ip_name 的名字。这个对应关系,在上述流程点prepare LOGIC 自动生成代码时,会自动完成。如果是手工编辑的逻辑代码,或者对这里的命名进行过改动,会出现后续Quartus 中使用的异常。2. Ve 中定义的信号关联:在AG32 中,mcu 和cpld 和外部引脚,三者是相互独立的。1. mcu 用的IO,在ve 里,可以关联到外部引脚Pin_xx;2. cpld 用的IO,在ve 里,可以关联到外部引脚pin_xx;3. mcu 的某一路信号又可以直接和cpld 的某一路信号,在ve 里,关联起来;所以,ve 是很关键的一个桥梁。在ve 中定义好以后,运行prepare LOGIC 会自动产生cpld 的顶层模块的输入输出接口,这些接口就是cpld 和mcu 与外部引脚关联的信号通路。 这里着重描述下3 种情况在VE 文件里的定义。1. mcu 和外部引脚的关联:比如,定义gpio 到外部引脚:GPIO4_3 PIN_32比如,定义串口0 到外部引脚:UART0_UARTRXD PIN_31 定义格式为:mcu 的FunctionName + 空格+ PIN 脚ID。这部分在mcu 使用里描述的很多了,不再赘述。2. cpld 和外部引脚的关联:比如,定义led 到外部引脚:LED_D3 PIN_32:OUTPUT 定义格式为:cpld 信号名称+ 空格+ pin 脚ID: 方向其中,cpld 信号名称,是自定义名称,这个名称随后可以在cpld 中引用;方向,有3 种:OUTPUT、INPUT 和INOUT(这个方向是cpld 对外部引脚来说的)。方向是可选的,可加可不加。如果不加,则是默认的INOUT(双向)。上述定义在ve 里添加后,执行prepare LOGIC 命令,在自动生成的cpld 工程中,可以看到输出到cpld 顶层模块接口中的item 如下: 那么,input BTN_L1: 是pin 到cpld 的信号;output LED_D2: 是cpld 到pin 的信号;output LED_D3: 是cpld 到pin 的信号;然后在cpld 代码中操作LED_D3 这个信号的高低,最终操作的PIN_32 管脚的高低。(注:VE 里每行最后定义的方向是可选的) 3. mcu 和cpld 之间的信号关联:比如,定义gpio 信号到cpld:GPIO4_1 iocvt_chn比如,定义串口1 的tx 信号到cpld:UART1_UARTTXD txd_chn 定义格式为:MCU 的FunctionName + 空格+ cpld 信号名称其中,这里的FunctionName,同1 中的FunctionName,就是mcu 里的通路定义。更多定义参考《AGRV2K_逻辑设置.pdf》,里边有全部的mcu 端可用的FunctionName 列表。除了mcu 的FunctionName(映射到引脚)外,mcu 对cpld 还开放出更多的内核级通路接口,如:mem_ahb_各通道,dma 各通道,mcu 的reset 和stop 等信号,具体定义也参考《AGRV2K_逻辑设置.pdf》。这里定义后,执行prepare LOGIC 命令,在自动生成的cpld 工程中,可以看到输出到cpld 顶层模块接口的item 如下: 对于iocvt_chn 来说,对应的是没有指定方向的普通gpio(GPIO4_3)口,则这里生成的信号同时包含有输入和输出两种。注:这里的输入和输出,是相对于cpld 端来说的。蓝色的input/output,就是该信号的方向。比如:output iocvt_chn_in:是cpld 输出到mcu 的信号;input iocvt_chn_out_data:是mcu 输出到cpld 的信号;input iocvt_chn_out_en:是mcu 输出到cpld 的信号(en 信号很少用,一般可忽略);对于txd_chn 来说,由于mcu 的串口TX 是定义好方向的,是mcu 的output 方向。所以在cpld 里只有两个item 项:input txd_chn_out_data:是mcu 输出到cpld 的信号;input txd_chn_out_en:是mcu 输出到cpld 的信号(en 信号很少用,一般可忽略);如果对普通GPIO 也设置了方向,则导出到cpld 的方向也就只有对应方向的信号了。如:VE 里设置GPIO4_1 iocvt_chn 为mcu 的输出: 则prepare LOGIC 后生成的item 只有input 的两项。如下: 注意:在mcu 和cpld 信号连接中,mcu 的output 就是cpld 的input。 四、可参考样例: 这里的参考样例,只是先建立一个初步的印象。1. cpld 控制pin 脚(LED 闪烁):样例对应网盘上“1.led 灯闪烁”。解压后可以看到logic 的部分。这个样例logic 实现一个非常简单的功能:在cpld 里驱动两个led 灯的闪烁。这个样例中展示:cpld 中如何和外部pin 脚关联、如何通过clk 来驱动led 的闪烁。这个logic 就是在Prepare Logic 后的空工程上,添加了analog_ip.v 文件中的函数关联而形成的。建立的过程:ve 里配置IO 口-> prepare LOGIC -> 用Quartus 打开并转换-> 编辑代码->Quartus 编译-> 用Supra 编译。 大致描述:A. 在ve 中定义cpld 和引脚的关联: B. VSCODE 中点prepare LOGIC,自动生成的analog_ip 中包含了LED_D2 和LED_D3 通路; C. 然后在代码中定义led 的module(功能为:通过时钟clk 来定时改变led 的高低); D. 最后,在analog_ip.v 里关联该led module。 2. Adc/dac/cmp 样例:注:这个样例可尝试理解下,如果困难,请跳过,直接看下个文档《AG32 中cpld 的基础.pdf》样例对应网盘上“2.adcDac 例程”。解压后可以看到logic 的部分。这个样例使用了AG32 下默认的analog 工程(工程在\examples\analog)。这个样例中的cpld 代码也是AG32 官方使用的ADC 源码。这里可以参考第一步来创建logic 工程,也可以直接vscode 中打开examples\analog 例程来创建logic。ADC 的cpld 模块存在的原因:在AG32 芯片中,内置了A/D 转换器。但转换器本身对外的接口是串行接口,并不是希望的并行接口,在mcu 使用时显然是不合适的。而这里的ADC 模块,就是在cpld 中把串行数据转换为并行数据,并做为mcu 可接受的apb 外设来使用。接下来,对这个ADC 的典型样例进行拆解,从中找到可借鉴的部分。看例程中的cpld 代码部分(4 个.v):my_board.v、alta_sim.v、analog_ip.v、ahb2apb.v A. my_board.v:和上边描述的一样:该.v 是根据工程中board.ve 里的pin 配置,prepare LOGIC 时自动转换出来的.v 源码,也是supra 工程的top module。这部分不要手工改动。在这个文件中,关联了alta_sim 中的几个module,完成和mcu 的基础交互支撑;同时,还关联了analog_ip module,把analog_ip 接入进来: 这里的analog_ip module,就是接入用户代码的总入口。B. alta_sim.v:该文件是AG32 提供的系统module 的集合,位于SDK 路径下。功能方面,主要提供系统支撑,可不用关注。C. ahb2apb.v:该文件实现特定的功能:把数据从高频的ahb 总线转到低频的apb 总线。只有一个module:ahb2apb。该功能在ADC 数据转换时会被用到,在analog_ip.v 中被使用。D. analog_ip.v:该文件是用户级module 的入口。ADC 的转换功能也是在这个文件中实现的。过程大致描述如下: 1) 信号接入:在analog_ip 入口,会看到一长串的信号输入:clock、mem_ahb、slave_ahb、dma 这些信号都是由top module 关联进来的(my_board.v 中)。 再往上回溯,可以看到:sys_clock 是由my_board 中pll 分频后输出的sys_clk;bus_clock 是和sys_clk 关联的;(可通过VE 来重定义bus_clk 频率)mem_ahb_xxx 是由my_board 中通过alta_rv32 module 关联进来的;其他的,slave_ahb_xxx,ext_dma_xxx,local_int,也是由alta_rv32 关联进来的。这些信号,是cpld 和mcu 之间关联的桥梁。在这个工程中,cpld 和mcu 之间,就通过这些信号进行交互。(如果cpld 和外部引脚有交互,像led 样例,这里还会有外部引脚的信号名)“MCU 和CPLD 之间通过AHB 交互”,说的就是这里的ahb 信号组。在《AGRV2K 逻辑设置.pdf》有对这里信号的描述: sys_clock:mcu 输出到cpld 的clock。就是在ve 里配置的那个SYSCLK bus_clock:mcu 输出到cpld 的另一个clock。可以在ve 里定义: 如果ve 里没有定义BUSCLK,则bus_clock 和sys_clock 同频。BUSCLK 必须是SYSCLK 的整数分频。bus_clock 其实就是随后cpld 里边的apb 总线,速度低于或等于sysclk(ahb)。Mem_ahb_xxx:mcu 端访问寄存器时会触发的信号组。在mcu 的统一寻址中,cpld 的所有寄存器定义在0x6000000-0x7fffffff 之间。在mcu 端的analog_ip.h 中看到的定义: 这部分的地址,就是mcu 访问cpld 的“寄存器”。对于mcu 来说,操作这里的寄存器就可以了。mcu 在操作寄存器的时候,会被自动分解成ahb 的addr 和data 数据、自动进行总线使用。(这部分动作mcu 的应用代码已经无需关注)在cpld 里,也有对应的体现(cpld 中默认从0x6000000 开始,只定义偏移即可): mcu 和cpld 的数据通过AHB 交互:对mcu 来说,就是操作0x6000000 开始的一组寄存器;对cpld 来说,就是这组连进来的ahb 信号线,根据信号线的变化来执行对应动作。可以认为:cpld 相当于挂在ahb 上的一个外设,会跟mcu 和dma 抢占总线的外设。Slave_ahb_xxx:这组信号是cpld 写入ahb 的信号组。ADC 样例中没有用到。Ext_dma_xxx:Dma 部分的信号组。ADC 支持DMA,这里也会用到。 2) 功能描述:在analog_ip.v 中,共有4 个module:analog_ip、apb_adc、apb_dac、apb_cmp。实现了3 路adc,2 路dac,1 路cmp。在analog_ip 中,通过ahb2apb #(ADDR_BITS, DATA_BITS) ahb2apb_inst 来实例化一个ahb2apb 模块,传参(ADDR_BITS, DATA_BITS)下去。ahb2apb 这个模块是将ahb 转为apb 的数据。然后,用generate 生成3 路adc、2 路dac、1 路cmp 的硬件逻辑。再然后,是三个module 的逻辑实现部分。在apb_adc 的入口处,有各信号的输入,最后是一个data 的输出。 3) Ahb2apb:这块功能较为固定。对信号从ahb 转到apb 上。这个样例中,可参考的3 部分:mcu 到ahb 的数据怎么传递、ahb 转apb 信号、adc 中对各信号的处理。 说明:这里的ADC 模块包括3 路ADC/2 路DAC/1 路CMP,单纯这里编译出来都占了1.2K 的逻辑单元。如果自己项目中用到cpld 并且使用到的ADC 较少,可以自行对这部分进行裁剪。如果在自己的cpld 上还要加adc 的逻辑,(鉴于ADC 逻辑较为独立)建议过程:VE 里配置好-> prepare LOGIC 产生logic 工程-> 实现自己的cpld 逻辑-> 把adc 部分合并进来(合并的入口,就是analog_ip)。另外,ADC/DAC/CMP 的外部管脚是固定的,在VE 里不用体现,也不能在VE 里重映射到其他管脚。 注:以上两个样例,只是有个初步印象。(其中ADC 样例涉及比较多,暂时理不清楚也没关系)请阅读接下来的文档《AG32 中cpld 的基础.pdf》,在该文档中有更多的拆解和描述。 PREVIOUS ← CPLD使用基础 NEXT STEP analog中对ADC的剪裁 →