前言

织女星开发板是OPEN-ISA社区为中国大陆地区定制的一款体积小、功耗超低和功能丰富的 RISC-V评估开发板,基于NXP半导体四核异构RV32M1主控芯片。

  • 两个RISC-V核:RI5CY + ZERO_RISCY。
  • 两个ARM核: Cortex-M4F + Cortex-M0+ 。

4个核被分为两个子系统,大核CM4F/RI5CY和小核CM0+/ZERO-RISCY,片上集成1.25 MB Flash 、384 KB SRAM,其中1 MB的Flash被大核所使用,起始地址0x0000_0000,另外的256 KB Flash被小核所使用,起始地址0x0100_0000。利用该开发板,用户可以快速建立一个使用 RV32M1 的 RISC-V应用和演示系统。详细的介绍可以参考: 真正的RISC-V开发板——VEGA织女星开发板开箱评测 ,本篇文章介绍如何基于RISC-V RI5CY/ZERO内核来点亮板载的RGB_LED/STS_LED、读取按键输入,演示GPIO的输入输出和外部中断功能。

准备工作

在进行以下操作之前,要确保开发环境已经搭建完成,而且能正常下载调试。

  • 织女星开发板RISC-V开发环境:Eclipse + riscv32 工具链 + OpenOCD调试工具
  • 织女星开发板SDK包:rv32m1_sdk_riscv
  • 织女星开发板的原理图
  • RV32M1参考手册

以上资料的获取、开发环境搭建和启动模式修改等教程,可以到官方中文论坛查找:www.open-isa.cn

或者是参考我分享的以下文章:

寄存器简介

根据RV32M1参考手册GPIO章节的介绍,我们可以获得关于GPIO相关寄存器信息:

各GPIO组的基地址:

  1. GPIOA——4802_0000h
  2. GPIOB——4802_0040h
  3. GPIOC——4802_0080h
  4. GPIOD——4802_00C0h
  5. GPIOE——4100_F000h

GPIO配置PCR寄存器

这是一个32位的寄存器,每一个引脚都有对应的一个PORTx_PCRn,用来配置GPIO的以下功能:

  • 上下拉配置
  • 翻转速率控制
  • 开漏使能
  • 无源输入滤波器
  • 寄存器锁定
  • 复用功能设置

以PA0控制寄存器,PORTA_PCR0为例:

通过查看参考手册,可以了解到各Bit的功能:

  • ISF:1位,中断状态标志
  • IRQC:4位,配置中断方式和DMA功能
  • LK:1位,是否锁定PCR寄存
  • MUX:3位,复用功能配置
  • ODE:1位,推挽开漏配置
  • PFE:1位,滤波器配置
  • SRE:1位,翻转速率配置
  • PE:1位,上下拉使能
  • PS:1位,上下拉配置

详细的配置介绍可以查看参考手册。官方库fsl_port中的


  1. PORT_SetPinConfig(PORT_Type *base, uint32_t pin, const port_pin_config_t *config)
  2. PORT_SetPinMux(PORT_Type *base, uint32_t pin, port_mux_t mux)
  3. PORT_SetPinInterruptConfig(PORT_Type *base, uint32_t pin, port_interrupt_t config)
  4. PORT_SetPinDriveStrength(PORT_Type* base, uint32_t pin, uint8_t strength)

这些函数就是控制的这个PCR寄存器。

GPIO控制寄存器

主要包括控制GPIO输入输出控制,读取输入,控制输出,方向控制等。

寄存器描述和地址偏移量:

RV32M1的GPIO共有6个32位的控制寄存器,从字面意思可以直接知道每个寄存器的功能:

  • PDOR:数据输出寄存器,指定位写入0/1,输出0/1
  • PSOR:端口置位输出寄存器,指定位写1,置位输出1,写0状态不变
  • PCOR:端口复位输出寄存器,指定位写1,复位输出0,写0状态不变
  • PTOR:端口反转输出寄存器,指定位写1,反转输出,写0状态不变
  • PDIR:端口输入寄存器,读取指定位输入状态
  • PDDR:端口方向配置寄存器,指定位写0作为输入,写1作为输出

官方库中的fsl_gpio文件中实现的函数就是控制的这几个寄存器。


  1. void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *config)
  2. void GPIO_WritePinOutput(GPIO_Type *base, uint32_t pin, uint8_t output)
  3. void GPIO_SetPinsOutput(GPIO_Type *base, uint32_t mask)
  4. void GPIO_ClearPinsOutput(GPIO_Type *base, uint32_t mask)
  5. void GPIO_TogglePinsOutput(GPIO_Type *base, uint32_t mask)

库函数简介

和其他的MCU一样,由于RV32M1的寄存器众多,为了方便使用,增强程序的可读性,官方开发了库函数,来实现对寄存器的控制,本质上还是操作的寄存器。GPIO控制的库主要由fsl_gpio和fsl_port两个文件组成,其中fsl_gpio主要是对GPIO的控制,如读取输入,控制输出,清除中断标志等,而fsl_port主要实现对GPIO工作的模式进行配置,如复用功能,上拉下拉,开漏推挽,中断触发方式,DMA功能等进行设置。

下面简单介绍几个常用的函数:

PORT_SetPinConfig

配置GPIO的复用功能,驱动能力,推挽开漏,上下拉,滤波器,翻转速率等功能,基于PCR寄存器实现。


  1. port_pin_config_t config;
  2. config.driveStrength = kPORT_HighDriveStrength; //驱动能力配置
  3. config.mux = kPORT_MuxAsGpio; //通用GPIO
  4. config.openDrainEnable = kPORT_OpenDrainDisable; //推挽
  5. config.passiveFilterEnable = kPORT_PassiveFilterDisable;//滤波器
  6. config.pullSelect = kPORT_PullUp; //上拉
  7. config.slewRate = kPORT_FastSlewRate; //翻转速率
  8. PORT_SetPinConfig(PORTA, 22, &config); //配置GPIOA22

PORT_SetPinMux

配置GPIO的复用功能,基于PCR寄存器实现。

  1. //PA22作为普通GPIO使用
  2. PORT_SetPinMux(PORTA, 22, kPORT_MuxAsGpio);
  3. //PA25作为UART1_RX功能
  4. PORT_SetPinMux(PORTA, 25, kPORT_MuxAlt2);

具体复用为哪种功能,不同的引脚有不同的复用功能,对应的ALTn,可以查看参考手册RV32M1 Pinout介绍。

PORT_SetPinConfig已经包含了PORT_SetPinMux的功能,可以只使用PORT_SetPinConfig来GPIO功能的配置。PORT_SetPinMux函数不推荐和PORT_SetPinsConfig函数一起使用:

This function is NOT recommended to use together with the PORT_SetPinsConfig, because the PORT_SetPinsConfig need to configure the pin mux anyway (Otherwise the pin mux is reset to zero : kPORT_PinDisabledOrAnalog). This function is recommended to use to reset the pin mux

GPIO_PinInit

控制GPIO的输入输出方式,及默认输出电平,基于PDDR、PCOR、PSOR寄存器实现。


  1. gpio_pin_config_t io_init;
  2. //配置输出/输出模式
  3. io_init.outputLogic = 0; //默认输出0
  4. io_init.pinDirection = kGPIO_DigitalOutput; //数字输出
  5. GPIO_PinInit(LED_RGB_GPIO, LED_RED_Pin, &io_init); //LED引脚配置

GPIO_WritePinOutput

指定引脚输出高低电平,基于PCOR和PSOR寄存器实现。

  1. GPIO_WritePinOutput(GPIOA, 22, 1); //PA22输出1

GPIO_TogglePinsOutput

指定引脚输出翻转,基于PTOR寄存器实现

  1. GPIO_TogglePinsOutput(GPIOA, 1 << 22); //PA22输出翻转

GPIO_ReadPinInput

读取GPIO输入状态,基于PDIR寄存器实现

  1. in = GPIO_ReadPinInput(GPIOA, 22); //读取PA22输入状态

GPIO操作的函数还有很多,详细的介绍和实现可以直接查看库函数源码。

RGB LED的初始化

从原理图中我们可以得知,织女星开发板上共有4个用户可控制的LED,包括3个RGB LED和1个红色LED,均采用MOS来驱动,引脚输出高电平LED点亮,和GPIO的对应关系如下:

LED_RED——PTA24

LED_GREEN——PTA23

LED_BLUE——PTA22

LED_STS——PTE0

所以我们需要配置PTA22/PTA23/PTA24为普通推挽输出方式,然后输出高低电平就可以控制LED闪烁了。

led_driver.c文件内容


  1. #include "led_driver.h"
  2. void LED_RGB_Init(void)
  3. {
  4. gpio_pin_config_t io_init;
  5. port_pin_config_t config;
  6. //配置输出/输出模式
  7. io_init.outputLogic = 0;
  8. io_init.pinDirection = kGPIO_DigitalOutput;
  9. config.driveStrength = kPORT_HighDriveStrength; //驱动能力
  10. config.lockRegister = kPORT_LockRegister; //PCR寄存器被锁定,不能再次改变
  11. config.mux = kPORT_MuxAsGpio; //通用GPIO
  12. config.openDrainEnable = kPORT_OpenDrainDisable; //推挽输出
  13. config.passiveFilterEnable = kPORT_PassiveFilterDisable;//滤波器
  14. config.pullSelect = kPORT_PullUp; //上拉
  15. config.slewRate = kPORT_FastSlewRate; //翻转速率
  16. CLOCK_EnableClock(LED_RGB_Clk_Name);
  17. CLOCK_EnableClock(LED_STS_Clk_Name); //GPIOE时钟必须一直开启
  18. CLOCK_EnableClock(kCLOCK_Rgpio1); //GPIOE配置需要使能这个时钟
  19. /*以下两个函数都可以配置端口功能*/
  20. PORT_SetPinConfig(LED_RGB_Port, LED_RED_Pin, &config); //配置功能更详细
  21. PORT_SetPinConfig(LED_RGB_Port, LED_GREEN_Pin, &config);
  22. PORT_SetPinConfig(LED_RGB_Port, LED_BLUE_Pin, &config);
  23. PORT_SetPinConfig(LED_STS_Port, LED_STS_Pin, &config);
  24. // PORT_SetPinMux(LED_RGB_Port, LED_RED_Pin, kPORT_MuxAsGpio); //只能配置是否复用
  25. // PORT_SetPinMux(LED_RGB_Port, LED_GREEN_Pin, kPORT_MuxAsGpio);
  26. // PORT_SetPinMux(LED_RGB_Port, LED_BLUE_Pin, kPORT_MuxAsGpio);
  27. // CLOCK_DisableClock(LED_RGB_Clk_Name); //可以在配置完成之后关闭时钟,不影响使用
  28. GPIO_PinInit(LED_RGB_GPIO, LED_RED_Pin, &io_init);
  29. GPIO_PinInit(LED_RGB_GPIO, LED_GREEN_Pin, &io_init);
  30. GPIO_PinInit(LED_RGB_GPIO, LED_BLUE_Pin, &io_init);
  31. GPIO_PinInit(LED_STS_GPIO, LED_STS_Pin, &io_init);
  32. }

要注意的是,时钟使能要放在GPIO配置之前,否则不能访问GPIO配置寄存器,在配置完成之后可以关闭时钟,也可以一直开启。其中GPIOE非常特殊,要想使用GPIOE,必须使能Rgpio1快速时钟,其他的GPIO配置不需要,这是因为GPIOE属于快速GPIO,和其他几组GPIO不是同一个总线。


  1. CLOCK_EnableClock(kCLOCK_Rgpio1); //GPIOE配置需要使能这个时钟

led_driver.h文件内容


  1. #ifndef __LED_DRIVER_H__
  2. #define __LED_DRIVER_H__
  3. #include "fsl_gpio.h"
  4. #include "fsl_port.h"
  5. #include "fsl_clock.h"
  6. /*
  7. LED_RGB_BLUE - A22
  8. LED_RGB_GREEN - A23
  9. LED_RGB_RED - A24
  10. LED_STS - E0
  11. */
  12. #define LED_RED_Pin 24
  13. #define LED_GREEN_Pin 23
  14. #define LED_BLUE_Pin 22
  15. #define LED_RGB_Port PORTA
  16. #define LED_RGB_GPIO GPIOA
  17. #define LED_RGB_Clk_Name kCLOCK_PortA
  18. #define LED_STS_Pin 0
  19. #define LED_STS_Port PORTE
  20. #define LED_STS_GPIO GPIOE
  21. #define LED_STS_Clk_Name kCLOCK_PortE
  22. #define LED_STS_ON GPIO_WritePinOutput(LED_STS_GPIO, LED_STS_Pin, 1)
  23. #define LED_STS_OFF GPIO_WritePinOutput(LED_STS_GPIO, LED_STS_Pin, 0)
  24. #define LED_STS_TOGGLE GPIO_TogglePinsOutput(LED_STS_GPIO, 1 << LED_STS_Pin)
  25. #define LED_RED_ON GPIO_WritePinOutput(LED_RGB_GPIO, LED_RED_Pin, 1)
  26. #define LED_RED_OFF GPIO_WritePinOutput(LED_RGB_GPIO, LED_RED_Pin, 0)
  27. #define LED_RED_TOGGLE GPIO_TogglePinsOutput(LED_RGB_GPIO, 1 << LED_RED_Pin)
  28. #define LED_GREEN_ON GPIO_WritePinOutput(LED_RGB_GPIO, LED_GREEN_Pin, 1)
  29. #define LED_GREEN_OFF GPIO_WritePinOutput(LED_RGB_GPIO, LED_GREEN_Pin, 0)
  30. #define LED_GREEN_TOGGLE GPIO_TogglePinsOutput(LED_RGB_GPIO, 1 << LED_GREEN_Pin)
  31. #define LED_BLUE_ON GPIO_WritePinOutput(LED_RGB_GPIO, LED_BLUE_Pin, 1)
  32. #define LED_BLUE_OFF GPIO_WritePinOutput(LED_RGB_GPIO, LED_BLUE_Pin, 0)
  33. #define LED_BLUE_TOGGLE GPIO_TogglePinsOutput(LED_RGB_GPIO, 1 << LED_BLUE_Pin)
  34. void LED_RGB_Init(void);
  35. #endif

头文件中通过宏定义的方式实现了LED的亮灭和翻转控制。

板载按键初始化

按键部分硬件原理图,按下为低电平。

button_driver.c文件内容


  1. #include "button_driver.h"
  2. #include "delay.h"
  3. #include "led_driver.h"
  4. //按键使用普通输入GPIO方式
  5. void Button_Init(void)
  6. {
  7. gpio_pin_config_t io_init;
  8. port_pin_config_t config;
  9. io_init.outputLogic = 0;
  10. io_init.pinDirection = kGPIO_DigitalInput;
  11. config.mux = kPORT_MuxAsGpio; //通用GPIO
  12. config.lockRegister = kPORT_LockRegister; //PCR寄存器被锁定,不能再次改变
  13. config.pullSelect = kPORT_PullUp; //上拉
  14. config.slewRate = kPORT_FastSlewRate; //翻转速率
  15. config.lockRegister = kPORT_LockRegister; //PCR寄存器被锁定,不能再次改变
  16. config.passiveFilterEnable = kPORT_PassiveFilterEnable; //滤波器
  17. CLOCK_EnableClock(BTN_SW2_Clk_Name);
  18. CLOCK_EnableClock(BTN_SW3_Clk_Name);
  19. // CLOCK_EnableClock(BTN_SW4_Clk_Name);
  20. // CLOCK_EnableClock(BTN_SW5_Clk_Name);
  21. CLOCK_EnableClock(kCLOCK_Rgpio1); //GPIOE配置需要使能这个时钟
  22. //以下两个函数功能一样
  23. PORT_SetPinConfig(BTN_SW2_Port, BTN_SW2_Pin, &config);
  24. PORT_SetPinConfig(BTN_SW3_Port, BTN_SW3_Pin, &config);
  25. PORT_SetPinConfig(BTN_SW4_Port, BTN_SW4_Pin, &config);
  26. PORT_SetPinConfig(BTN_SW5_Port, BTN_SW5_Pin, &config);
  27. // PORT_SetPinMux(BTN_SW2_Port, BTN_SW2_Pin, kPORT_MuxAsGpio); //设置IO模式为通用GPIO
  28. // PORT_SetPinMux(BTN_SW3_Port, BTN_SW3_Pin, kPORT_MuxAsGpio); //设置IO模式为通用GPIO
  29. // PORT_SetPinMux(BTN_SW4_Port, BTN_SW4_Pin, kPORT_MuxAsGpio); //设置IO模式为通用GPIO
  30. // PORT_SetPinMux(BTN_SW5_Port, BTN_SW5_Pin, kPORT_MuxAsGpio); //设置IO模式为通用GPIO
  31. GPIO_PinInit(BTN_SW2_GPIO, BTN_SW2_Pin, &io_init);
  32. GPIO_PinInit(BTN_SW3_GPIO, BTN_SW3_Pin, &io_init);
  33. GPIO_PinInit(BTN_SW4_GPIO, BTN_SW4_Pin, &io_init);
  34. GPIO_PinInit(BTN_SW5_GPIO, BTN_SW5_Pin, &io_init);
  35. }
  36. //按键使用外部中断初始化函数
  37. void ButtonInterruptInit(void)
  38. {
  39. gpio_pin_config_t io_init;
  40. port_pin_config_t config;
  41. io_init.outputLogic = 0;
  42. io_init.pinDirection = kGPIO_DigitalInput;
  43. config.mux = kPORT_MuxAsGpio; //通用GPIO
  44. config.lockRegister = kPORT_LockRegister; //PCR寄存器被锁定,不能再次改变
  45. config.pullSelect = kPORT_PullUp; //上拉
  46. config.slewRate = kPORT_FastSlewRate; //翻转速率
  47. config.lockRegister = kPORT_LockRegister; //PCR寄存器被锁定,不能再次改变
  48. config.passiveFilterEnable = kPORT_PassiveFilterEnable; //滤波器
  49. CLOCK_EnableClock(BTN_SW2_Clk_Name);
  50. CLOCK_EnableClock(BTN_SW3_Clk_Name);
  51. // CLOCK_EnableClock(BTN_SW4_Clk_Name);
  52. // CLOCK_EnableClock(BTN_SW5_Clk_Name);
  53. CLOCK_EnableClock(kCLOCK_Rgpio1); //GPIOE配置需要使能这个时钟
  54. //以下两个函数功能一样
  55. PORT_SetPinConfig(BTN_SW2_Port, BTN_SW2_Pin, &config);
  56. PORT_SetPinConfig(BTN_SW3_Port, BTN_SW3_Pin, &config);
  57. PORT_SetPinConfig(BTN_SW4_Port, BTN_SW4_Pin, &config);
  58. PORT_SetPinConfig(BTN_SW5_Port, BTN_SW5_Pin, &config);
  59. //设置中断触发方式
  60. PORT_SetPinInterruptConfig(BTN_SW2_Port, BTN_SW2_Pin, kPORT_InterruptFallingEdge); //下降沿触发中断
  61. PORT_SetPinInterruptConfig(BTN_SW3_Port, BTN_SW3_Pin, kPORT_InterruptFallingEdge);
  62. PORT_SetPinInterruptConfig(BTN_SW4_Port, BTN_SW4_Pin, kPORT_InterruptFallingEdge);
  63. PORT_SetPinInterruptConfig(BTN_SW5_Port, BTN_SW5_Pin, kPORT_InterruptFallingEdge);
  64. #if defined(CPU_RV32M1_ri5cy)
  65. //RI5CY Core GPIOE需要使能以下两个函数, ZERO Core不用
  66. INTMUX_Init(INTMUX0);
  67. INTMUX_EnableInterrupt(INTMUX0, 0, PORTE_IRQn);
  68. #endif
  69. EnableIRQ(BTN_SW2_IRQ);
  70. EnableIRQ(BTN_SW3_IRQ);
  71. // EnableIRQ(BTN_SW4_IRQ);
  72. // EnableIRQ(BTN_SW5_IRQ);
  73. GPIO_PinInit(BTN_SW2_GPIO, BTN_SW2_Pin, &io_init);
  74. GPIO_PinInit(BTN_SW3_GPIO, BTN_SW3_Pin, &io_init);
  75. GPIO_PinInit(BTN_SW4_GPIO, BTN_SW4_Pin, &io_init);
  76. GPIO_PinInit(BTN_SW5_GPIO, BTN_SW5_Pin, &io_init);
  77. }
  78. void PORTA_IRQHandler(void)
  79. {
  80. GPIO_ClearPinsInterruptFlags(BTN_SW2_GPIO, 1U << BTN_SW2_Pin);
  81. LED_STS_TOGGLE;
  82. LOG("sw2 is pressed \r\n");
  83. }
  84. //GPIOE外部中断函数
  85. void PORTE_IRQHandler(void)
  86. {
  87. uint32_t flag;
  88. flag = GPIO_GetPinsInterruptFlags(BTN_SW3_GPIO);
  89. GPIO_ClearPinsInterruptFlags(BTN_SW3_GPIO, 1U << BTN_SW3_Pin);
  90. GPIO_ClearPinsInterruptFlags(BTN_SW4_GPIO, 1U << BTN_SW4_Pin);
  91. GPIO_ClearPinsInterruptFlags(BTN_SW5_GPIO, 1U << BTN_SW5_Pin);
  92. if(flag & (1 << BTN_SW3_Pin)) //SW3产生中断
  93. {
  94. LED_RED_TOGGLE;
  95. LOG("sw3 is pressed \r\n");
  96. }
  97. else if(flag & (1 << BTN_SW4_Pin))
  98. {
  99. LED_GREEN_TOGGLE;
  100. LOG("sw4 is pressed \r\n");
  101. }
  102. else if(flag & (1 << BTN_SW5_Pin))
  103. {
  104. LED_BLUE_TOGGLE;
  105. LOG("sw5 is pressed \r\n");
  106. }
  107. }
  108. //轮询方式获取按键状态
  109. uint8_t GetKey(void)
  110. {
  111. uint8_t key = 1;
  112. //按键按下为0
  113. if(BTN_SW2_IN && BTN_SW3_IN && BTN_SW4_IN && BTN_SW5_IN)
  114. {
  115. Delay_ms(10);
  116. if(!BTN_SW2_IN)
  117. key = 2;
  118. else if(!BTN_SW3_IN)
  119. key = 3;
  120. else if(!BTN_SW4_IN)
  121. key = 4;
  122. else if(!BTN_SW5_IN)
  123. key = 5;
  124. while(!(BTN_SW2_IN && BTN_SW3_IN && BTN_SW4_IN && BTN_SW5_IN));
  125. }
  126. return key;
  127. }

按键配置为上拉输入模式,同样如果使用GPIOE作为通用GPIO输入,还需要使能Rgpio1时钟


  1. CLOCK_EnableClock(kCLOCK_Rgpio1); //GPIOE配置需要使能这个时钟

如果使用GPIOE的外部中断功能,还需要使能INTMUX


  1. #if defined(CPU_RV32M1_ri5cy)
  2. //RI5CY Core GPIOE需要使能以下两个函数, ZERO Core不用
  3. INTMUX_Init(INTMUX0);
  4. INTMUX_EnableInterrupt(INTMUX0, 0, PORTE_IRQn);
  5. #endif

button_driver.h文件内容


  1. #ifndef __BUTTON_DRIVER_H__
  2. #define __BUTTON_DRIVER_H__
  3. #include "fsl_gpio.h"
  4. #include "fsl_port.h"
  5. #include "fsl_intmux.h"
  6. /*
  7. * SW2 - A0
  8. * SW3 - E12
  9. * SW4 - E8
  10. * SW5 - E9
  11. * */
  12. //按下为低电平
  13. #define BTN_SW2_GPIO GPIOA
  14. #define BTN_SW3_GPIO GPIOE
  15. #define BTN_SW4_GPIO GPIOE
  16. #define BTN_SW5_GPIO GPIOE
  17. #define BTN_SW2_Pin 0
  18. #define BTN_SW3_Pin 12
  19. #define BTN_SW4_Pin 8
  20. #define BTN_SW5_Pin 9
  21. #define BTN_SW2_Port PORTA
  22. #define BTN_SW3_Port PORTE
  23. #define BTN_SW4_Port PORTE
  24. #define BTN_SW5_Port PORTE
  25. #define BTN_SW2_IRQ PORTA_IRQn
  26. #define BTN_SW3_IRQ PORTE_IRQn
  27. #define BTN_SW4_IRQ PORTE_IRQn
  28. #define BTN_SW5_IRQ PORTE_IRQn
  29. #define BTN_SW2_Clk_Name kCLOCK_PortA
  30. #define BTN_SW3_Clk_Name kCLOCK_PortE
  31. #define BTN_SW4_Clk_Name kCLOCK_PortE
  32. #define BTN_SW5_Clk_Name kCLOCK_PortE
  33. #define BTN_SW2_IN GPIO_ReadPinInput(BTN_SW2_GPIO, BTN_SW2_Pin)
  34. #define BTN_SW3_IN GPIO_ReadPinInput(BTN_SW3_GPIO, BTN_SW3_Pin)
  35. #define BTN_SW4_IN GPIO_ReadPinInput(BTN_SW4_GPIO, BTN_SW4_Pin)
  36. #define BTN_SW5_IN GPIO_ReadPinInput(BTN_SW5_GPIO, BTN_SW5_Pin)
  37. /*
  38. #define BTN_SW2_IN ReadGPIO(BTN_SW2_GPIO, BTN_SW2_Pin)
  39. #define BTN_SW3_IN ReadGPIO(BTN_SW3_GPIO, BTN_SW3_Pin)
  40. #define BTN_SW4_IN ReadGPIO(BTN_SW4_GPIO, BTN_SW4_Pin)
  41. #define BTN_SW5_IN ReadGPIO(BTN_SW5_GPIO, BTN_SW5_Pin)
  42. */
  43. void Button_Init(void);
  44. uint8_t GetKey(void);
  45. void ButtonInterruptInit(void);
  46. #endif

通过GPIO读取函数来获取按键输入状态,或者是通过中断标志来判断输入状态。

主函数应用

使用外部中断方式读取按键输入状态。


  1. #include "main.h"
  2. extern uint32_t SystemCoreClock;
  3. int main(void)
  4. {
  5. BOARD_BootClockRUN(); //ϵͳʱ֓Ťփ
  6. UART0_Init();
  7. Delay_Init();
  8. LOG("SystemCoreClock: %ld \r\n", SystemCoreClock);
  9. #if defined(CPU_RV32M1_ri5cy)
  10. LOG("RV32M1 RISC-V RI5CY Core Demo \r\n");
  11. #elif defined(CPU_RV32M1_zero_riscy)
  12. LOG("RV32M1 RISC-V ZERO Core Demo \r\n");
  13. #endif
  14. LED_RGB_Init();
  15. // Button_Init();
  16. ButtonInterruptInit();
  17. // LPMTR2_Init();
  18. // LPIT1_CH3_Init();
  19. while (1)
  20. {
  21. }
  22. }

代码下载

织女星开发板VEGA_Lite支持从4个核启动,所以在进行程序下载之前,要确认当前的启动模式和当前的工程是对应的。如当前工程是使用RISC-V RI5CY核来驱动GPIO,那么就需要配置芯片启动模式为RI5CY核启动。否则会不能下载。关于启动模式的修改可以参考:织女星开发板启动模式修改

总结

RV32M1芯片的GPIOE与其他几组GPIO配置方法稍有不同,使用时要特别注意。

参考资料

推荐阅读


  • 个人博客:www.wangchaochao.top
  • 我的公众号:mcu149

织女星开发板使用RISC-V核驱动GPIO的更多相关文章

  1. 织女星开发板启动模式修改——从ARM M4核启动

    前言 刚开始玩织女星开发板的时候,想先从熟悉的ARM核入手,连上Jlink,打开MDK版本的Demo程序,编译OK,却检测不到芯片,仔细看了一下文档,原来RV32M1芯片默认从RISC-V核启动,如果 ...

  2. 真正的RISC-V开发板——VEGA织女星开发板开箱评测

    前言 由于最近ARM公司要求员工"停止所有与华为及其子公司正在生效的合约.支持及未决约定",即暂停与华为的相关合作,大家纷纷把注意力投向了另一个的处理器架构RISC-V,它是基于精 ...

  3. 手把手教你搭建织女星开发板RISC-V开发环境

    前言 Windows环境下搭建基于Eclipse + RISC-V gcc编译器的RISC-V开发环境,配合openocd调试软件,可以实现RISC-V内核程序的编译.下载和调试. 准备工作 工欲善其 ...

  4. 织女星开发板RISC-V内核实现微秒级精确延时

    前言 收到VEGA织女星开发板也有一段时间了,好久没玩了,想驱动个OLED屏,但是首先要实现IIC协议,而实现IIC协议,最基本的就是需要一个精确的延时函数,所以研究了一下如何来写一个精确的延时函数. ...

  5. 织女星开发板调试器升级为Jlink固件

    前言 为了能使用板载的FreeLink调试器来调试RISC-V内核,我们需要把默认的CMSIC-DAP固件,升级为JLink固件,固件升级之后,通过选择使用不同的驱动程序,来支持ARM内核还是RISC ...

  6. NXP恩智浦VEGA织女星开发板免费申请!

    前言 大概两周前申请了一块NXP恩智浦的开发板,今天终于收到了!在这里推荐给大家,官方网站刚上线一个月左右,目前申请的人还不算多,感兴趣的朋友可以申请一个,体验一下这个四核性能怪兽.大厂就是大气,包装 ...

  7. 飞凌OK6410开发板SDIO无线8189WIFI模块驱动移植

    为什么要移植?开发板不是已经提供了无线驱动吗? 貌似是这样的..本来是好用的.加入自己第三方驱动后发现WIFI用不了...最后发现飞凌提供的内核里面没有8189芯片的代码...问售后他们说那边是好的. ...

  8. 【安富莱】V6,V5开发板用户手册,重在BSP驱动包设计方法,HAL库的框架学习,授人以渔(2019-11-04)

    说明: 1.本教程重在BSP驱动包设计方法和HAL库的框架学习,并将HAL库里面的各种弯弯绕捋顺,从而方便我们的程序设计. 2.本次工程延续以往的代码风格,从底层BSP驱动包到应用代码,变量命名,文件 ...

  9. 友善RK3399/NanoPC-T4开发板wiringPi的C语言访问GPIO外设实例讲解 -【申嵌视频】

    1 wiringPi简介 wiringPi库最早是由Gordon Henderson所编写并维护的一个用C语言写成的类库,除了GPIO库,还包括了I2C库.SPI库.UART库和软件PWM库等,由于w ...

随机推荐

  1. 《master the game of GO wtth deep neural networks and tree search》研究解读

    现在”人工智能“如此火爆的一大直接原因便是deepmind做出的阿尔法狗打败李世石,从那时开始计算机科学/人工智能成为了吹逼的主流.记得当时还是在学校晚新闻的时候看到的李世石输的消息,这个新闻都是我给 ...

  2. ORA-00845 startup启动不起来关于磁盘空间扩充

    问题描述:今天在虚拟机下进行startup的操作,但是没有起来,系统报错:ORA-00845: MEMORY_TARGET not supported on this system 1.startup ...

  3. linux字符集修改

    首先介绍一下变量. 1.变量类型:本地变量.环境变量.局部变量.特殊变量(内置).参数变量.只读变量. 2.bash的配置文件:profile类和bashrc类 profile类:为交互式登录的she ...

  4. css三大特效之优先级

    1.什么是优先级作用:当多个选择器选中同一个标签,并且给同一个标签设置相同的属性时,如何层叠就由优先级来确定

  5. 有效的减少代码中太多的if、else?-策略模式

    写这篇文章的目的和上一篇单例模式一样,策略模式也是一种常用的设计模式,太多的if-else不仅看着不太美观而且不好维护,对于自己来说也等于复习了一遍策略模式.先说一下策略 模式的定义: 策略模式封装了 ...

  6. 多进程使用同一log4j配置导致的日志丢失与覆盖问题

    最近接手了一个流传很多手的魔性古早代码,追日志时发现有明显缺失.对log4j不熟,不过可以猜测日志出问题肯定和多进程使用同一个log4j配置有关.经多次排查,终于捋清了其中逻辑.本文对排查过程进行复盘 ...

  7. ASP.NET Core 中的 ObjectPool 对象重用(二)

    前言 上一篇文章主要介绍了ObjectPool的理论知识,再来介绍一下Microsoft.Extensions.ObjectPool是如何实现的. 核心组件 ObjectPool ObjectPool ...

  8. Git实战指南----跟着haibiscuit学Git(第一篇)

    笔名:  haibiscuit 博客园: https://www.cnblogs.com/haibiscuit/ Git地址: https://github.com/haibiscuit?tab=re ...

  9. python基础-网络编程part02

    TCP协议 TCP是传输控制协议,建立双向通道. 三次握手,建立连接 客户端向服务端发送建立连接的请求 服务端接收请求返回确认信息给客户端,并向客户端发送建立连接的请求 客户端接收请求返回确认信息给服 ...

  10. 【数据结构】之栈(C语言描述)

    栈(Stack)是编程中最常用的数据结构之一. 栈的特点是“后进先出”,就像堆积木一样,堆的时候要一块一块堆到最上面,拆的时候需要从最上面一块一块往下拆.栈的原理也一样,只不过它的操作不叫堆和拆,而是 ...