模式
以example为例了解工程结构与配置
一、了解SDK目录结构
安装完SDK后,首先了解下SDK工作路径下的文件结构:
比如,安装路径在D:\AGM_WORK\
下的,首先看到工程路径:D:\AGM_WORK\AgRV_pio
如下图:

对上边的packages
目录展开,可以看到:

再对platform
展开,可以看到:

以上几个红色标圈的目录,是在后续编写代码时常用的几个目录。
其中:
framework-agrv_sdk
是整个SDK的基础支撑部分。包含全部的驱动代码、board代码、输出重定向代码。该framework是开发者在创建自己工程时必须依赖的framework(所有examples样例工程中都可以看到该项)。- 其中的
ips/lwip/usb
,是第三方的库,开发者根据自己需求决定是否使用它们。 - 目前支持的四个操作系统:
ucos/rtthread/freertos/embos
,也在这里可以看到。
点开framework-agrv_sdk
目录,src
中包含全部的驱动代码。 了解完依赖包,再看
examples
。
examples
中包含了众多的样例工程:example
(基础驱动)、各种OS使用、lwip
使用、usb
使用,...
其中的example
工程,包含了基础驱动的举例:

二、打开第一个工程:example
看完目录结构,再来打开第一个样例工程(examples/example
样例工程)。
打开方式:Vscode (左上角)【文件】 -> 【打开文件夹】 -> 弹出框中选该工程。
VSCODE打开后如图:

上图的main()
函数,是example
工程的主入口。
然后,board_init
函数中,会进行时钟初始化、GPIO初始化、log串口初始化;
INT_EnableIRQ
是使能某种类型的中断;
再接下来,就是对各驱动的测试函数。需要测试时,放开对应项。
上边展示的环境,就是AG32芯片的开发环境。
在这个IDE中,开发者可以编写代码、修改配置、编译、调试、烧录。
事实上,在example
工程中,除了上图的代码,还有两处重要的配置文件:
example_board.ve
管脚配置:位于路径:
AgRV_pio\platforms\AgRV\examples\example
该配置文件中,会配置芯片主频及pin脚映射。
platformio.ini
工程配置:位于路径:
AgRV_pio\platforms\AgRV\examples\example
该文件是工程配置文件,里边定义IDE的编译/烧录/仿真及工程宏的选项。
三、工程配置
接上述,了解工程配置。
两部分工程配置:platformio.ini
和 example_board.ve
注:不仅example
工程需要这两个配置,所有的工程都需要这两个配置文件。
其中:
platformio.ini
配置 工程的编译、烧录、仿真的选项;与IDE相关。example_board.ve
配置 芯片系统时钟频率、芯片IO引脚映射等;
该文件中的配置是要被烧写到flash中的,做为该芯片独特的配置。与用到的芯片有关。
A. platformio.ini配置项:
这里的配置项,就是配置项目如何进行编译、烧录、仿真,以及使用芯片型号、引用库等。
以下对常用的几个配置项做简单的描述。
(更多的配置项,在随后其他模块中使用到时,会相应列出)
ini
boards_dir = boards //指定board对应的工作路径(用于代码编译的path)
board = agrv2k_103 //使用boards_dir路径下的哪个硬件版本
//注:boards_dir和board共同组成了完整path。
//如:以上对应路径\platforms\AgRV\boards\agrv2k_103。
//这个路径下的.c和.h会被编译到工程,这个路径下的资源被默认查找;
board_logic.ve = example_board.ve
//工程使用到的ve配置文件(每个工程必须指定自己的ve文件)
//如果用相对路径,是相对于platformio.ini所在的路径(即:工程路径)
framework = agrv_sdk, agrv_lwip //使用工程中的哪些库。SDK是必带的。
//工程中可添加的库,具体参考工程注释中的描述;
//使用多个库时名字中间加逗号隔开。
program = agm_example //工程名,可自定义,仅作用于生成的bin名称
src_dir = . //参与编译的c文件基目录(路径相对于工程路径)
include_dir = . //参与链接的h文件基目录(路径相对于工程路径)
//注意,如果工程内文件夹比较多,这里不要再使用./src(而是使用.)
build_src_filter = "-<*> +<*.c> +<print/*.c> "
//参与编译的c文件路径列表
//*用于通配,+增加,-去除,**用于匹配所有子目录
//路径基于上边src_dir给出的路径
build_flags = -Isrc -Iuser -Iuser/print //头文件路径列表
//-I后边是一个个文件夹,各项之间用空格来分开
board_logic.device = AGRV2KL100 //芯片类型配置
//64脚的封装应配置为 AGRV2KL64
logger_if = UART0 //芯片输出log用的串口号(对应代码中printf函数)
//注意:UART0同时用于代码烧录,但烧录和log输出并不冲突
//如果用串口1输出log,这里设置为:UART1
monitor_speed = 115200 //芯片输出log用的波特率 (sdk1.5.0之后新增)
//注意:用宏BAUD_RATE=115200的方式也能设置波特率(1.5.0之前是用宏方式)
upload_protocol = jlink-openocd //烧录固件的方式
//可选方式:jlink、dap(官方烧录器)、serial,字段名称参考注释部分
debug_tool = jlink-openocd //仿真时使用的工具,同上
B. example_board.ve 配置项:
AG32芯片和其他芯片(比如ST、GD)在使用上有一个很大的差异点,是AG32的IO引脚并不是定死的,而是配置的。
比如,ST的gpio的PA1,是定死指定到某个PIN脚的;
但是,AG32的所有gpio,对应到哪个PIN脚是配置的。必须在VE里配置绑定后,程序里操作这个gpio(比如,置高置低)才会最终作用到PIN脚上。
除了gpio,其他的很多外设(如spi,iic,can,uart等)都是需要配置引脚的。
Mcu里用到哪个信号就在VE里配置对应引脚,没用到的不用配置。
这种方式下:
- 可以节省大量引脚(开发者只需要配置自己使用到的外设引脚即可)
- PCB布线可以非常方便(引脚随意指定,不用再考虑走线时绕来绕去)
在引脚配置上,也有一些限制,参后续描述。
ve配置方式(以example_board.ve
为例):
ini
SYSCLK 100 #配置系统时钟频率,M为单位。407最高频率可到248M
HSECLK 8 #使用的外部晶振频率,M为单位,建议取值范围 4~16
UART0_UARTRXD PIN_69 #串口0的收引脚
UART0_UARTTXD PIN_68 #串口0的发引脚
GPIO6_2 PIN_23 #IO_Button1
GPIO6_4 PIN_24 #IO_xxxx
I2C0_SDA PIN_36 #I2C0
I2C0_SCL PIN_35 #I2C0
……
GPTIMER1_CH0 PIN_7 #配置GpTimer1的channal 0 输出到管脚7
……
在书写格式中,前边为信号量的名称,后边为PIN脚编号。
(如果用到mcu和cpld联合开发,cpld信号量也在ve配置,这里不做细述)
这里着重描述一下GPIO的使用:
AG32芯片内共有10组GPIO(GPIO0 – GPIO9),每组8个IO(0~7)。所以,可用的GPIO共有80个。(100pin/64pin/48pin只是外部封装的区别,不影响内部GPIO的定义和数量)
虽然总数有80个,但真正在VE里绑定了PIN脚的那些gpio才会“有效”。
GPIOx_y
表示的是第x组第y个IO。
比如上图中,GPIO6_2
表示的就是第6组的第2个IO。程序里操作GPIO6_2
实际操作的就是PIN_23
引脚。
VE里这些使用到的左列的信号名称,请从文档《AGRV2K_逻辑设置.pdf》中查找。
配置的限制:
只有少数几个外设不能配置引脚(芯片定死了引脚):
包括:ADC/DAC/CMP、USB、MAC,以及硬件的JTAG/OSC/RTC/VDD/GND。
如果使用到这些外设,只能使用对应引脚。
如果不用这些外设,空闲出来的引脚可以被用于其他用途。
在可配置的项中,注意相互间的少量冲突;
在《AGRV2K_逻辑设置.pdf》中有详细描述。
另外:不可配置的引脚(ADC、USB这些),在32pin/48pin/64pin/100pin上的对应是不同的。注意区分。
关于管脚配置和GPIO的更详细描述,请参考《AG32下驱动的使用.pdf》。
四、代码讲解
这里只是初步的讲解和描述。从main函数开始:

小技巧:Ctrl + 鼠标左键
,点击函数名,可以跳转到函数定义中(相当于vs中的F12快捷键)
上图中:
board_init()
是芯片初始化入口,根据自己需求调整里边的内容即可。plic_isr[BUT_GPIO_IRQ] = Button_isr;
这句代码,是设置按键的中断函数。(该Button在board_init
里初始化过了,这里是开启中断。)INT_EnableIRQ(BUT_GPIO_IRQ, PLIC_MAX_PRIORITY);
这句代码,是使能按键的中断。INT_SetIRQThreshold(MIN_IRQ_PRIORITY);
这句代码,则是设置中断开启的阈值。当优先级大于这个参数时,才会触发中断。
最下边的框,则是各个驱动的测试样例入口。每个函数对应一个.c驱动文件。
接下来进入board_init
函数:


在example
样例中,使用的是外部8M时钟,pll后系统跑在100M主频。
看完board_init
,再看后续对gpio测试样例的调用。(表现就是led灯的闪烁)


注意的是,这里使用的EXT_GPIO
, EXT_GPIO_BITS
,就是board_init()
里初始化过的ext的gpio。GPIO_Toggle
函数是对gpio进行翻转,也没什么难理解的。
这里比较难理解的,是宏定义 EXT_GPIO_BITS = 0b1110
。意思就是同时对 bit1/bit2/bit3
进行操作。
gpio操作时,不仅支持对某个gpio的操作,也支持对一组(多个gpio)的操作。这里就是对一组内多个gpio操作的示例。
五、介绍gpio和串口的使用
举例gpio的使用:
举例:用 pin3
引脚接led灯,并控制亮灯(高为亮),则需要做:
- ve文件中设置:
GPIO4_5 PIN_3
- 代码中定义三个宏:c
#define LED_G_GPIO GPIO4 #define LED_G_GPIO_MASK APB_MASK_GPIO4 #define LED_G_GPIO_BITS GPIO_BIT5
- 代码中调用:c
SYS_EnableAPBClock(LED_G_GPIO_MASK); GPIO_SetOutput(LED_G_GPIO, LED_G_GPIO_BITS); GPIO_SetHigh(LED_G_GPIO, LED_G_GPIO_BITS);
- 先烧录ve部分;
- 再编译烧录代码部分;
以上代码的解释:
不管外部封装是多少pin(48pin/64pin/100pin),芯片内部可用gpio都有80个。
在使用gpio时,需要把使用到的gpio关联到外部pin脚。
(没被关联的gpio,即使在代码中操作它,也不会传导到外部pin脚)
这步关联动作是在ve文件中进行的。
ve文件里的配置,
GPIOx_y PIN_z
,就是关联的语句。PIN_z
,对应外部哪个引脚。z取值范围(48脚封装:0~47;64脚封装:0~63)GPIOx_y
,对应内部哪个GPIO。x取值范围(0~9),y取值范围(0~7);80个gpio分为10组,每组8个。用
GPIOx_y
的格式来表达。如:GPIO0_1
对应第0组的第1个IO;GPIO4_5
对应第4组的第5个IO;GPIO9_7
对应第9组的第7个IO…
在代码中如何操作GPIO:
仍以
GPIO4_5
举例:在代码里定义:
c#define LED_G_GPIO GPIO4 #define LED_G_GPIO_BITS (1 << 5) (或用宏 GPIO_BIT5)
则意味着LED对应到了
GPIO4_5
。调用函数
GPIO_SetOutput
设置改IO为输出模式:cGPIO_SetOutput(LED_G_GPIO, LED_G_GPIO_BITS);
然后就可以通过
GPIO_SetHigh/GPIO_SetLow
来置高置低IO口。如果要设置上拉下拉,请参考文档《AG32驱动的使用.pdf》中对gpio部分的详述。
关于gpio的使用的更多介绍,请进入AG32驱动介绍。
举例log输出:
通过串口烧录mcu程序时,是固定使用mcu的uart0。建议mcu在运行时也使用uart0来输出log。
在VE里设置后,代码中的printf
函数将通过uart0来输出。
在ve中配置输出Log的串口:
inilogger_if = UART0 build_flags = -DBAUD_RATE=115200 //增加系统宏 BAUD_RATE 为 115200
从SDK1.5.0之后,最好使用
monitor_speed = 115200
替代这种宏的用法。在ve中设置串口0的映射引脚,如:
iniUART0_UARTRXD PIN_69 UART0_UARTTXD PIN_68
在程序的
board_init()
函数中,有UART0的初始化:在该初始化中,会设置串口的波特率、位宽、停止位、奇偶位。

ini
logger_if = UART1
UART1_UARTRXD PIN_xx
UART1_UARTTXD PIN_xx
即可。
关于系统的宏定义:
在代码中出现的宏,在VSCode中通过鼠标停留在上边,可以看到其定义值。
这些宏,除了代码中定义的外,还有“系统预制宏”也可以被代码中使用。
系统宏的两类:
定义在
platformio.ini
中的build_flags
字段中;如 上边定义的波特率:
build_flags = -DBAUD_RATE=115200
在
build_flags
后边用-D
表示是系统宏。后边的紧跟的字符串BAUD_RATE=115200
(字符串中间不能有空格),则相当于C代码中的#define BAUD_RATE 115200
如果有多个宏,则
-D
与下个-D
之间用空格 隔开。在
platformio.ini
中定义后再由main.py
经过转换拼接,才最终使用的宏。比如上边截图中的
LOGGER_UART
。这个宏并没有在代码中定义,也没在
build_flags
中定义。但它是在agrv_sdk.py
中引用 时再拼接的。
第二种方式了解即可,不要使用。开发者使用第一种就够了。
.
这篇讲述了开发工程的配置,example代码。下篇将讲述如何在VScode下编译、调试、烧录。