RISC-V内核中科蓝讯BT8922开发

Posted aron566

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RISC-V内核中科蓝讯BT8922开发相关的知识,希望对你有一定的参考价值。

RISC-V内核中科蓝讯BT8922开发

BT8922

GPIO配置

官方说明部分

GPIOAFEN      //0:当作通用GPIO使用   //1:当作其它功能性IO,如串口/SPI..
GPIOADE       //数字IO使能: 0为模拟IO, 1 为数字IO,    //如作为AUX/MIC输入的IO口就需要设置成模拟IO, 减少数字IO对AUX的干扰.
GPIOADIR      //控制IO的方向:  0为输出, 1为输入.
GPIOA         //IO方向为输入时,读此寄存器的值即得到引脚的高低状态  //IO为输出时, 设置此寄存器的高低即设置对应引脚的高低输出.
GPIOADRV      //0 输出驱动为8mA   //1 输出驱动为32 mA   //IO方向为输出时有效
  
//以下寄存器控制上拉或下拉, 注意只有当IO设置为输入时, 上下拉才有效.  //IO方向为输出时上下拉自动无效  
GPIOAPU          //10K上拉使能
GPIOAPD          //10K下拉使能
GPIOAPU200K      //200K上拉使能
GPIOAPD200K      //200K下拉使能
GPIOAPU300       //300欧上拉使能
GPIOAPD300       //300欧下拉使能

//作为输出时,输出电平的高低也可以通过设置GPIOASET/GPIOACLR来快速实现,注意GPIOASET/GPIOACLR只对写1的位有效.
GPIOASET = BIT(0);    //PA0输出高, 等效于 GPIOA |= BIT(0);其它位状态不变.
GPIOACLR = BIT(0);    //PA0输出低, 等效于GPIOA &= ~BIT(0);其它位状态不变.   

常见输入输出使用示例: 1. PA0输出高低(点LED灯)示例:

int main(void)

    //示例开始
    GPIOAFEN &= ~BIT(0);   //PA0作为GPIO使用
    GPIOADE  |= BIT(0);    //PA0设置为数字IO
    GPIOADIR &= ~BIT(0);   //PA0方向设置为输出
    WDT_DIS();          //测试程序关看门狗,防止看门狗复位
    while(1) 
        GPIOA |= BIT(0);       //PA0输出高, 等效于GPIOASET = BIT(0);
        delay_ms(100);
        GPIOA &= ~BIT(0);      //PA0输出低, 等效于GPIOACLR = BIT(0);
        delay_ms(100);

配置得到PA0引脚状态(作用输入)示例:

int main(void)

    //示例开始
    GPIOAFEN &= ~BIT(0);   //PA0作为GPIO使用
    GPIOADE  |= BIT(0);    //PA0设置为数字IO
    GPIOADIR |= BIT(0);    //PA0方向设置为输入
    GPIOAPU  |= BIT(0);    //作为输入,为了有稳定的输入状态(1或0),在外部没上拉或下拉时,需要根据实际情况开内部上拉或下拉
    WDT_DIS();             //测试程序关看门狗,防止看门狗复位
    while(1) 
        delay_ms(100);
        printf("GPIOA0 = 0x%X\\n",GPIOA & BIT(0));    //打印读到的PA0状态

关于 GPIOASET/ GPIOACLR: 只对写入为1的位有效, 写入为0的位则不影响它以前的状态的. 如PA0输出高低

GPIOASET = BIT(0);    //PA0输出高, 等效于 GPIOA |= BIT(0);
GPIOACLR = BIT(0);    //PA0输出低, 等效于GPIOA &= ~BIT(0);   

GPIO输出控制优化加速

此两个寄存器, 主要是优化IO输出高低电平而设置. 如设置PA0为高, 为了不影响GPIOA上的其它IO的操作, 以前程序一般这样写GPIOA |= BIT(0); 这里实际上有三个步骤:

1) 先读出GPIOA
2) 再把GPIOA | BIT(0)
3) 把或后的结果再写回GPIOA

而使用GPIOASET效优化后, 直接一步GPIOASET = BIT(0);
即达到 上面三步才能达到的效.
GPIOADE  &= ~BIT(7);//模拟:0 or 数字:1

/* 功能选择 */
GPIOAFEN &= ~BIT(7);//普通IO:0 or 复用IO:1

/* 上下拉控制 */
GPIOAPU  &= ~BIT(7);//10Kohm 上拉使能(输入有效) 0不用 1使能
GPIOAPU200K  &= ~BIT(7);//200Kohm 上拉使能(输入有效) 0不用 1使能
GPIOAPU300  &= ~BIT(7);//300ohm 上拉使能(输入有效) 0不用 1使能
GPIOAPD  &= ~BIT(7);//10Kohm 下拉使能(输入有效) 0不用 1使能
GPIOAPD300  &= ~BIT(7);//300ohm 下拉使能(输入有效) 0不用 1使能
GPIOAPD200K  &= ~BIT(7);//200Kohm 下拉使能(输入有效) 0不用 1使能

/* 输入输出控制 */
GPIOADIR |= BIT(7);//方向选择 0输出 1输入

/* 驱动能力控制 */
GPIOADRV |= BIT(7);//驱动电流 写0 8 or 写1 32mA

/* 端口功能映射控制 */
FUNCMCON0 =31:28】UART1 RX mapping
0000: no affect
0001: map to G1
0010: map to G2
0011: map to TX pin by UT1TXMAP select
1111: Clear these bits
【27:24】UART1 TX mapping
0000: no affect
0001: map to G1
0010: map to G2
1111: Clear these bits
【15:12】UART0 RX mapping
0000: no affect
0001: map to G1
0010: map to G2
0011: map to G3
0100: map to G4
0101: map to G5
0110: map to G6
0111: map to TX pin by UT0TXMAP select
1111: Clear these bits
【11:8】UART0 TX mapping  
0000: no affect
0001: map to G1
0010: map to G2
0011: map to G3
0100: map to G4
0101: map to G5
0110: map to G6
0111: map to G7
1111: Clear these bits
【7:4】SPI0 mapping
0000: no affect
0001: map to G1
0010: map to G2
0011: map to G3
1111: Clear these bits
【3:0】SD0 mapping
0000: no affect
0001: map to G1
0010: map to G2
0011: map to G3
0100: map to G4
0101: map to G5
0110: map to G6
1111: Clear these bits
 
FUNCMCON1 =11:8】UART2 RX mapping 
0000: no affect
0001: map to G1
0010: map to G2
0011: map to TX pin by UT2TXMAP select
1111: Clear these bits
【7:4】UART2 TX mapping
0000: no affect
0001: map to G1
0010: map to G2
1111: Clear these bits
  
FUNCMCON2 = /* 设置定时器 */
  
FUNCMCON2 = /* 设置MPDM interface mapping 和 PDM interface mapping */  

对于G1这种IO组合名称定义,查阅config_define.h,以及在Datasheet文件中找到相关定义

配置一个端口为串口

GPIOADE  |= BIT(7);//数字
GPIOAPU  |= BIT(7);//上拉10Kohm
GPIOADIR |= BIT(7);//方向选择1输入
GPIOAFEN |= BIT(7);//功能复用IO
GPIOADRV |= BIT(7);//驱动电流32mA
#define URX0MAP_TX	(7<<12) //0111 0000 0000 0000
#define UTX0MAP_PA7 (1 << 8)//0000 0001 0000 0000
FUNCMCON0 = URX0MAP_TX | UTX0MAP_PA7;//RX0 Map To TX0, TX0 Map to G1

通过对照手册,设定UART1的相关寄存器设置,在config_define.h中

PS:数据手册中对UART1的RX脚没有G2相关描述,不过控制寄存器中存在G2组,这是datasheet无法与用户手册对应的地方!!!

/*****************************************************************************
 * Module    : uart1 Mapping选择列表 用户手册与数据手册冲突,以数据手册为准
 *****************************************************************************/
#define UTX1MAP_PA7     (1 << 24)        //G1 uart1 tx: PA7
#define UTX1MAP_VUSB    (3 << 24)        //G3 uart1 tx: VUSB

#define URX1MAP_PA6     (1 << 28)        //G1 uart1 rx: PA6

/*****************************************************************************
 * Module    : uart2 Mapping选择列表 以数据手册为准
 *****************************************************************************/
#define UTX2MAP_PB2     (2 << 4)        //G2 uart2 tx: PB2
#define UTX2MAP_VUSB    (3 << 4)        //G3 uart2 tx: VUSB
#define UTX2MAP_CLR     (0xF << 4)      //清除映射

#define URX2MAP_PB1     (2 << 8)        //G2 uart2 rx: PB1
#define URX2MAP_CLR     (0xF << 8)      //清除映射

配置为普通GPIO

/*****************************************************************************
* Module    : GPIO list
*****************************************************************************/
#define IO_NONE             0
#define IO_PA0              1
#define IO_PA1              2
#define IO_PA2              3
#define IO_PA3              4
#define IO_PA4              5
#define IO_PA5              6
#define IO_PA6              7
#define IO_PA7              8
#define IO_PB0              9
#define IO_PB1              10
#define IO_PB2              11
#define IO_PB3              12
#define IO_PB4              13
#define IO_PE0              14
#define IO_PE1              15
#define IO_PE2              16
#define IO_PE3              17
#define IO_PE4              18
#define IO_PE5              19
#define IO_PE6              20
#define IO_PE7              21
#define IO_PF0              22
#define IO_PF1              23
#define IO_PF2              24
#define IO_PF3              25
#define IO_PB5              26
#define IO_MAX_NUM          26

#define IO_MUX_SDCLK        27
#define IO_MUX_SDCMD        28
#define IO_MUX_PWRKEY       29
#define IO_MUX_MICL         30

typedef struct 
    psfr_t sfr;             //GPIO SFR ADDR
    u8 num;
    u8 type;                //type = 1,高压IO,没有300R的强上下拉电阻。 type = 0, 普通IO, 有内部300R上下拉电阻。
 gpio_t;

/* 配置IO,io_num就是上表中数字 */
gpio_cfg_init(gpio_t *g, u8 io_num);

简化普通GPIO配置

/* GPIO基础配置 */
#define GET_GPIO_DE_REG(port)             GPIO##port##DE
#define GET_GPIO_FEN_REG(port)            GPIO##port##FEN
#define GET_GPIO_DIR_REG(port)            GPIO##port##DIR
#define GET_GPIO_DRV_REG(port)            GPIO##port##DRV
#define GET_GPIO_DATA_REG(port)           GPIO##port
#define GET_GPIO_SET_REG(port)            GPIO##port##SET
#define GET_GPIO_CLR_REG(port)            GPIO##port##CLR

/* 上拉控制 */
#define GET_GPIO_10K_PUP_REG_ADDR(port)   GPIO##port##PU
#define GET_GPIO_200K_PUP_REG_ADDR(port)  GPIO##port##PU200K
#define GET_GPIO_300_PUP_REG_ADDR(port)   GPIO##port##PU300
#define GET_GPIO_10K_PUP_REG_ADDR(port)   GPIO##port##PU

/* 下拉控制 */
#define GET_GPIO_10K_PD_REG_ADDR(port)    GPIO##port##PD
#define GET_GPIO_200K_PD_REG_ADDR(port)   GPIO##port##PD200K
#define GET_GPIO_300_PD_REG_ADDR(port)    GPIO##port##PD300
#define GET_GPIO_10K_PD_REG_ADDR(port)    GPIO##port##PD

/**
 * @brief 配置32mA电流输出端口
 * @param port 端口
 * @param pin  引脚号PAx
 * 
 */
#define GPIO_CONFIG_OUTPUT_MODE(port, pin) \\
  do \\
    GET_GPIO_DE_REG(port) |= BIT(pin); \\
    GET_GPIO_FEN_REG(port) &= ~BIT(pin); \\
    GET_GPIO_DIR_REG(port) &= ~BIT(pin); \\
    GET_GPIO_DRV_REG(port) |= BIT(pin); \\
    GET_GPIO_CLR_REG(port) = BIT(pin); \\
  while(0)

/**
 * @brief 配置8mA低电流驱动输出
 * @param port 端口
 * @param pin  引脚号PAx
 * 
 */
#define GPIO_CONFIG_SAMALL_OUTPUT_MODE(port, pin) \\
  do \\
    GET_GPIO_DE_REG(port) |= BIT(pin); \\
    GET_GPIO_FEN_REG(port) &= ~BIT(pin); \\
    GET_GPIO_DIR_REG(port) &= ~BIT(pin); \\
    GET_GPIO_DRV_REG(port) &= ~BIT(pin); \\
    GET_GPIO_CLR_REG(port) = BIT(pin); \\
  while(0)

/**
 * @brief 配置引脚输入模式,默认10K上拉
 * @param port 端口
 * @param pin  引脚号PAx
 * 
 */
#define GPIO_CONFIG_INPUT_MODE(port, pin) \\
  do \\
    GET_GPIO_DE_REG(port) |= BIT(pin); \\
    GET_GPIO_FEN_REG(port) &= ~BIT(pin); \\
    GET_GPIO_DIR_REG(port) |= BIT(pin); \\
    GET_GPIO_DRV_REG(port) |= BIT(pin); \\
    GET_GPIO_10K_PUP_REG_ADDR(port) |= BIT(pin); \\
  while(0)

/**
 * @brief 设置引脚高电平
 * @param port 端口
 * @param pin  引脚号PAx
 * 
 */
#define SET_GPIO_TO_HIGH(port, pin) \\
  do \\
    GET_GPIO_SET_REG(port) = BIT(pin); \\
  while(0)

/**
 * @brief 设置引脚低电平
 * @param port 端口
 * @param pin  引脚号PAx
 * 
 */
#define SET_GPIO_TO_LOW(port, pin) \\
  do \\
    GET_GPIO_CLR_REG(port) = BIT(pin); \\
  while(0)

/**
 * @brief 获取引脚电平
 * @param port 端口
 * @param pin  引脚号PAx
 * 
 */
#define GET_GPIO_DATA(port, pin) \\
  (GET_GPIO_DATA_REG(port) & BIT(pin))

  
static void Test_GPIO_Init(void)

  // /* 使能数字GPIO PE5 */
  // GPIOEDE |= BIT(5);

  // /* 普通IO口功能 */
  // GPIOEFEN &= ~BIT(5);

  // /* 设置为输出 */
  // GPIOEDIR &= ~BIT(5);

  // /* 设置高电流驱动 */
  // GPIOEDRV |= BIT(5);

  // /* 设置为低电平 */
  // GPIOE &= ~BIT(5);
  GPIO_CONFIG_OUTPUT_MODE(E, 5);


static void Test_GPIO_Out(uint8_t GPIO_State)

  if(GPIO_State)
  
    // GPIOE |= BIT(5);
    SET_GPIO_TO_HIGH(E, 5);
  
  else
  
    // GPIOE &= ~BIT(5);
    SET_GPIO_TO_LOW(E, 5);
  

简化后的GPIO配置自定义LED

蓝讯有配置LED闪烁方式的工具(download),默认高电平点亮,内部配置IO看不到,所以在自己的电路中如果灯是低电平点亮,就无法使用工具进行配置LED,需要我们做下修改(配置IO、设置高低电平的接口由我们自己代码定义,闪烁周期方式由配置工具定义
并不推荐这么做,功能由sdk实现的就尽量不动里面的代码,对后续升级sdk方便一点
1、在port_led.c文件中增加如下接口

我们在bsp_led.c中实现这些接口:注意代码放置在.com区域

#必看-中科蓝讯开发环境搭建-基础开发环境搭建说明

必看 - 中科蓝讯开发环境搭建 - 基础开发环境搭建说明

Linux 内核加速支持 Rust 开发;中科院计划每半年升级一次 RISC-V 芯片;Python 3.10.1 发布 | 开源日报

RT-Thread X RISC-V创新应用大赛,500套开发板免费送!

中科院发布国产RISC-V处理器“香山”,已成功运行Linux,7月流片

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