一、时钟的配置 二、管脚的配置 1. 信号线和关键的分离 2.管脚的配置方法 1. 信号线名称 2. 注意不可配置的管脚 三、GPIO的使用 1.配置为输出(举例) 2.配置为输入(举例) 3.GPIO高级用法 四、MTimer的使用
一、时钟的配置:AG32 通常使用 HSE 外部晶体(范围:4M~16M)。
AG32 中不需要手动设置 PLL 时钟(时钟树由系统自动配置,无须用户关注)。用户只需在配置文件中给出外部晶振频率和系统主频即可。
配置方式:
在 ve 文件中配置如下:
这里配置的值,会在mcu的系统初始化时,代码中自动获取并使能。
系统主频的可配置范围:参考 datasheet 中各型号的最高主频(通常是 248M)
外部晶振的可配置范围:4 ~ 16
这里是最简单的描述,只是使用MCU时可以简单如上配置。 如果需要使用外部有源晶振,或者使用内部振荡器(内部振荡器有 5%以内误差),或者 cpld 中需要额外主频输入。
二、管脚的配置:1. 信号线和关键的分离:这里先描述两个概念:信号线和管脚。 信号线,是指MCU里能操作的信号线,比如gpio1_1/uart0_tx/spi_cs等等,在连接在mcu内核上的信号接点; 管脚,就是芯片裸露在外边的引脚(32PIN的有32个管脚,64PIN的有64个管脚...) 在传统芯片里(如ST、GD等),一颗芯片出来后,信号线和管脚是绑定死的(最多一个管脚可以复用成几种信号)。 但在AG32里,信号线和管脚是彻底分离的。 也就是说,可以把任意信号线绑定到任意引脚。 打个比方,比如管脚1,这个管脚用于什么功能,完全是由用户来自行配置的。用户可以把它配置成uart0_tx,也可以配置成GPIO1_2,还可以配置成spi_cs,等等。 这种管脚可配置性,为应用设计带来巨大的便利性: 首先,为PCB布线带来了很大的便利性。按最近的引脚走线,不用绕来绕去。 其次,可以提升管脚利用度(应用中没用到的外设不去配置,那它就不会占用管脚)。 比如,本来需要100脚的ST才能满足的外设需求,用AG芯片可能32脚的就够了。 2.管脚的配置方法:管脚的配置,在ve文件中 信号线<->管脚 一行一行对应即可。 如:GPIO0_0 PIN_2
本文后续会逐项讲述各种外设怎么配置信号和管脚。 先概述下配置引脚的两个注意项: 1. 信号线名称:信号线名称是在VE里配置使用的。 比如:uart0的tx信号线名称是UART0_UARTTXD,gpio第0组的第0个信号线名称是 GPIO0_0。 那么,对于mcu端来说,共有哪些信号线呢? mcu的信号线名称,全部定义在《AGRV2K_逻辑设置.pdf》中的“Function_Pin 列表”。 配置举例: - 配置GPIO0_1为PIN2,则定义:GPIO0_1 PIN_2
- 配置UART1_TX为PIN3,则定义:UART1_UARTTXD PIN_3
- 配置SPI0的clk为PIN4,则定义:SPI0_SCK PIN_4
- 配置CAN0的TX为PIN5,则定义:CAN0_TX0 PIN_5
2. 注意不可配置的管脚上述描述的“任意信号线可以绑定到任意引脚”,只是便于理解。真实使用时,有少量管脚是不可配置的。 不可配置包括:基础类(电源、时钟、地、RESET、BOOT0)、ADC(DAC/CMP)、USB。 除去这些,其他的外设均为配置管脚。 另外,其中的ADC和USB的管脚,如果不接ADC和USB,仍然是可以被用做普通IO的。 具体每种封装下管脚的详细定义,请参考文档《AG32_pinout_100_64_48_32_2K.xlsx》。 打开后,如下图:
凡是带有IO的,都是可以被配置的管脚。 比如:上图的PIN_33,如果ADC的channal14在使用,那这个管脚只能用于这路ADC。如果这路adc没有使能,则PIN_33可以配置为其他信号线(用于其他功能)。 32/48/64/100,各种封装下的引脚定义是不同的,注意找到跟实际匹配的那组。 . 三、GPIO的使用:可用GPIO(非管脚): AG32芯片内部可用gpio共有80个,分为10组,每组8个。 代码中各组对应为:GPIO0、GPIO1、GPIO2、... GPIO9 组内各IO用bit表示:GPIO_BIT0、GPIO_BIT1、GPIO_BIT2、...、GPIO_BIT7 使用时,用【组ID+组内id】来标识唯一的IO。 这里和ST是相仿的,ST分为GPIOA/GPIOB/GPIOC..., PIN_1/PIN_2/PIN_3... AG32为:GPIO0/GPIO1/GPIO2..., GPIO_BIT0/GPIO_BIT1/GPIO_BIT2... 在VE中的命名方式如:GPIO0_0,表示的是第0组的第0个IO。 对外映射: 上边已经讲述过,AG32中MCU信号线和管脚是分离的,GPIO信号线也不例外。 程序中用到的GPIO要连接到管脚PIN,才能最终使用。 GPIO在ve文件中配置如下图:
上图的示例,就是把 gpio4_1映射到管脚92。 (VE中的#为注释) 在AG32中,必须映射后,代码中操作gpio时,才会真正使能到硬件管脚。 这里GPIOx_y的角标取值范围:x (0 ~ 9), y (0 ~ 7) PIN_z的取值范围:z小于所用芯片的最大引脚数 在取值范围内,满足限制条件下,任意GPIOx_y可以映射到任意PIN_z。 (“哪些管脚不能被使用”的限制条件,参考文档:AGRV2K_逻辑设置.pdf) 这里配置的GPIO0_0,等同于代码中的 (GPIO0, GPIO_BIT0)。 对SDK下gpio样例代码的解释: 在examples/example/example_gpio.c里,只有最简单的一个IO翻转示例:
GPIO_Toggle是反转函数。从这个函数点进去(Ctrl +鼠标左键),可以看到gpio函数集:
EXT_GPIO和EXT_GPIO_BITS是定义的gpio宏。 注:这里能用GPIO_Toggle,是因为在前边的board_init()函数里已经初始化过该gpio了。 点进去EXT_GPIO宏可以看到定义
注意,这里的EXT_GPIO_BITS值为0b1110(即:0x0e),意思是BIT1/BIT2/BIT3的3位一 起操作。0b1110这里等价为:GPIO_BIT1|GPIO_BIT2|GPIO_BIT3。 那么,GPIO_Toggle(EXT_GPIO, EXT_GPIO_BITS) 这句代码的意思,就是对GPIO4_1/GPIO4_2 /GPIO4_3的3个IO一起反转。 在样例的VE里,定义引脚如下:
那么,跑样例时,就可以看到开发板上的3个LED(LED1 LED2和LED3)闪烁了。 而LED4因为没有操作该IO,LED4依然是灭的状态。 1.配置为输出(举例)用 pin3 引脚接 led 灯,并控制亮灯(高为亮)。 步骤一: 先在ve文件中定义引脚映射(gpio使用 4-1):
步骤二: 定义使用的宏:(也可以不定义,直接在代码中使用)
步骤三: 代码中调用:
步骤四: 编译并烧录ve文件,编译并烧录code; 补充,驱动开放的API包含: GPIO_SetOutput/GPIO_SetInput ---设置IO为输入输出 GPIO_SetHigh/GPIO_SetLow ---置高置低 GPIO_Toggle ---高低切换 GPIO_IntConfig ---配置中断触发方式 GPIO_EnableInt/GPIO_DisableInt/GPIO_ClearInt ---中断控制 GPIO_AF_ENABLE/GPIO_AF_DISABLE ---切换GPIO模式(如果有复用) Gpio中断函数SDK中已经默认指定:GPIOx_isr 如果要重定向为函数,通过 plic_isr[GPIOx_IRQn] = gpio_xxx_isr 的方式来设置; 2.配置为输入(举例)用pin96接外部按键,处理按键消息; 步骤一: 在ve文件中配置gpio4_5映射到pin96;
步骤二: 在测试代码中,编写IO初始化,并实现中断函数:
注:这里的中断函数GPIO4_isr无需程序中再次指定。 步骤三: 如果外部电路没有上拉设计,需要内部上拉。设置方式(二选一): - 在工程的example_board.asf文件中,
- 或者在\platforms\AgRV\boards\agrv2k_x0x\board.asf 文件中(不建议),
添加以下红框内的语句:
内容:set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to PIN_96 或者使用:set_instance_assignment -name CFG_KEEP -to PIN_96 2'b10 -extension (以上两个上拉的语句意义等价,使用时二选一) 注意:如果是cpld中要实现上拉,这里的PIN_96要用cpld里的信号名字。 如果设置下拉,则使用以下方式:
内容:set_instance_assignment -name CFG_KEEP -to PIN_32 2'b01 -extension 注意:如果是cpld中要实现下拉,这里的PIN_32要用cpld里的信号名字。 注意:上边一行添加完后,务必在后边添加回车换行(保证这行不是文件最后一行)。 步骤四: 编译并烧录ve文件,编译并烧录code; 结束。 . 3.GPIO高级用法1. 设置内部上拉/下拉: 参考上边步骤3的描述。 2. 引脚复用: AG32中也有引脚复用。 常见的复用引脚,默认都是IO功能。用做复用功能(如uart_rx/uart_tx)时,需要使用函数GPIO_AF_ENABLE来设置(参考具体的样例代码)。 特别的,JTAG引脚(JNTRST、JTDO、JTDI、JTMS、JTCK),默认是JTAG功能,而不是IO功能。用作普通IO时,需要先切换设置。 可使用如下函数来设置(在main函数进入后调用即可): SYS_DisableNJTRST()、SYS_DisableJTDI()、SYS_DisableJTDO(). (AG32默认使用jtag的swd模式,保留JTMS、JTCK即可通过jtag烧录仿真)。 3. 设置为OD模式(开漏输出): IO默认输出是PP模式(推挽输出)。 如果要设置为OD模式,有两种方式(二选一): 方式一、在ve里定义引脚如下(以34脚为例): GPIO4_1 PIN_34:OUTPUT:!PIN_34_out_data 方式二、在asf文件(工程中example_board.asf)中设置: set_instance_assignment -name AUTO_OPEN_DRAIN_PINS ON -to PIN_34 两种方式的输出效果是一样的。 注意: 如果用gpio模拟I2c的数据线,则只能使用第2种方式。 如果一定要使用方式一,必须要新增一个GPIO做为输入,绑定到一个PIN上。如:GPIO4_2 PIN_34:INPUT,然后在程序里SDA切换读的时候就用这个GPIO。 4. 配置电流输出驱动能力: 同上边上拉/下拉的设置文件(example_board.asf 文件),加入: set_instance_assignment -name CURRENT_STRENGTH -to PIN_32 16MA 驱动电流默认为8MA,支持4MA/8MA/12MA/16MA。
四、MTimer的使用:MTime是risc-v中定义的一个64位系统定时器。 在STM32中,我们一般用systick(滴答计时器)作为时基,而在riscv中我们用mechine timer(简称mtime)作为时基。 MTime中有两个主要寄存器:mtime和mtimecmp; 当mtime使能后,mtime寄存器里的值会随着tick自增,当自增到 大于等于 mtimecmp 寄存器的值时(无符号比较),就触发MTimer中断。 在移植操作系统时,mtime一般被用于系统时间片的调度定时。 相关函数: INT_SetMtime:设置寄存器的值; INT_SetMtimeCmp:设置比较寄存器的值; INT_EnableIntTimer:打开timer中断; 中断函数SDK中已默认指定:void MTIMER_isr() 如果要重定向函数,通过clint_isr[IRQ_M_TIMER] = MTIMER_user_isr 来设置;
如果要设置1ms触发一次的连续定时,需要调用:
NT_SetMtime(0); INT_SetMtimeCmp(SYS_GetSysClkFreq() / 1000); //1ms 然后在中断里重新计时: INT_SetMtime(0);
完整代码样例请参考example部分:
MTIME较为简单,用法上只有上述用法。
联系海振远科技
|