zoukankan      html  css  js  c++  java
  • hk32(航顺)标准库使用spi3复用功能的问题

     5a8c55a7e3188fd1e5ccaabd32451eb9.png

    前言:

    今天给大家介绍一下自己在使用航顺32芯片中遇到的一些问题。我用的是航顺的HK32f103VET6的一颗芯片,其中使用其中SPI3外设复用功能时,发现对应官方库的宏定义有些错误。遂给大家分享一下使用修改过程。

    顺带给大家介绍一下航顺公司。

    495c309d04b515e944d54f6720607b9a.png

    作者:良知犹存

    转载授权以及围观:欢迎关注微信公众号:羽林君

    或者添加作者个人微信:become_me


    情节介绍:

    我们使用MCU过程中会遇到一些IO外设进行复用 (为了优化64脚或100脚封装的外设数目,可以把一些复用功能重新映射到其他引脚上。设置复用重映射和调试I/O配置寄存器(AFIO_MAPR)实现引脚的重新映射。这时,复用功能不再映射到它们的原始分配上) 到非默认的引脚。

    我在使用航顺芯片时候想把PD3、PD4、PD5、PD6使用为SPI引脚。

    b705a798ba60d2ee0d16072d52164a8f.png

    手册配置查询

    经过查询对应的数据手册之后:(这是我查看手册对应的版本)

    21c4aaeca7c136dab6cd181b7dcc3787.png

    可以看到 PD3、PD4、PD5、PD6可以复用为SPI3功能引脚

    04f69e0f4c31e58d05efc86d5ba81153.png

    一般我们都是看AFIO功能开发手册说明,看对应的IO的复用选项。

    ST示例如下:

    7649f03f41e62f71d315e3d5ad00ed19.png

    航顺在开发手册中也有描述,但是没有描述SPI3复用选项

    c8b0ca712414bf6e19aa066e7f40c556.png

    所以紧接着我又去查看航顺开发手册,看里面AFIO的寄存器详细描述:

    其中SPI3归属在 航顺新增的AFIO_MAPR2 复用寄存器中:

    08c7f2a49c901d9a57298d69ae3fd6c8.png

    详细对应的关系可以看到, AFIO_MAPR2  是一个32位的寄存器,其中SPI3 在23位进行配置,其中我需要进行把 PD3、PD4、PD5、PD6可以复用为SPI3功能引脚,在此位进行设置,只需要 把此位设置1

    c2b082505f9c938b5345e294bce988f1.pngdcbdc1ee6aacad52ad3684346395e2c3.png

    函数对应

    我使用的航顺的V1.0.4库函数版本:

    cab58673110bdbf800110c772c26acb6.png

    使用复用功能 我需要用到 void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)  这个函数。

    我使用

    GPIO_PinRemapConfig(GPIO_Remap_SPI3,ENABLE);

    发现该SPI功能无法实现。

    所以我们需要更加深入的查看代码:

    在官方提供的hk32f10x_gpio .c 文件中你可以看到函数原型:

    void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)
    {
      uint32_t tmp = 0x00, tmp1 = 0x00, tmpreg = 0x00, tmpmask = 0x00;
    
      /* Check the parameters */
      assert_param(IS_GPIO_REMAP(GPIO_Remap));
      assert_param(IS_FUNCTIONAL_STATE(NewState));  
      
      if((GPIO_Remap & 0x80000000) == 0x80000000)
      {
        tmpreg = AFIO->MAPR2;
      }
      else
      {
        tmpreg = AFIO->MAPR;
      }
    
      tmpmask = (GPIO_Remap & DBGAFR_POSITION_MASK) >> 0x10;
      tmp = GPIO_Remap & LSB_MASK;
    
      if ((GPIO_Remap & (DBGAFR_LOCATION_MASK | DBGAFR_NUMBITS_MASK)) == (DBGAFR_LOCATION_MASK | DBGAFR_NUMBITS_MASK))
      {
        tmpreg &= DBGAFR_SWJCFG_MASK;
        AFIO->MAPR &= DBGAFR_SWJCFG_MASK;
      }
      else if ((GPIO_Remap & DBGAFR_NUMBITS_MASK) == DBGAFR_NUMBITS_MASK)
      {
        tmp1 = ((uint32_t)0x03) << tmpmask;
        tmpreg &= ~tmp1;
        tmpreg |= ~DBGAFR_SWJCFG_MASK;
      }
      else
      {
        tmpreg &= ~(tmp << ((GPIO_Remap >> 0x15)*0x10));
        tmpreg |= ~DBGAFR_SWJCFG_MASK;
      }
    
      if (NewState != DISABLE)
      {
        tmpreg |= (tmp << ((GPIO_Remap >> 0x15)*0x10));
      }
    
      if((GPIO_Remap & 0x80000000) == 0x80000000)
      {
        AFIO->MAPR2 = tmpreg;
      }
      else
      {
        AFIO->MAPR = tmpreg;
      }  
    }

    其中最重要对MAPR2 对应寄存器配置的是此处代码:

    if((GPIO_Remap & 0x80000000) == 0x80000000)
    {
     AFIO->MAPR2 = tmpreg;
    }
    else
    {
     AFIO->MAPR = tmpreg;
    }

    GPIO_Remap 参数有个掩码,最高位是1的情况下,配置 MAPR2寄存器,否则就去配置 MAPR寄存器。

    而我们需要去操作MAPR2寄存器配置SPI3复用功能。

    通过IS_GPIO_REMAP

    IS_GPIO_REMAP(GPIO_Remap)

    我们可以看一下 对应的GPIO_Remap参数定义。

    1ba94a1b43ccfe85c494a68fd96a9ca6.png

    这样查看完,发现MAPR2寄存器对应的SPI3宏定义最高位是0,中间填充的数据也是有问题的。

    因为我们需要调用GPIO_PinRemapConfig函数配置MAPR2寄存器的情况下,需要最高位是1

    #define GPIO_Remap_SPI3             ((uint32_t)0x00201100)

    而我们可以看到官方提供的hk32f10x_gpio .h文件中GPIO_Remap_SPI3的宏定义最高位不是1

    这样我们使用 GPIO_PinRemapConfig(GPIO_Remap_SPI3,ENABLE); 复用配置SPI3就会失败

    修改建议:

    库函数出现问题,那我们就直接配置寄存器吧。

    0bf54089c7f13c6ca354b3546bbd18bb.png

    查看对应的SPI3_REMAP对应位,我们可以算出来32位为1对应的16进制值为 0x800000

    d142ae2d2b9ecd4d655c45e7ddfdef6b.png

    AFIO->MAPR2 |= 0x00800000;

    最终代码如下:

    GPIO_InitTypeDef GPIO_InitStructure;
        SPI_InitTypeDef  SPI_InitStructure;
    
     RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOD, ENABLE );
     RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI3,  ENABLE );
     
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化GPIOB
    
      GPIO_SetBits(GPIOD,GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6);  
      
      
    // GPIO_PinRemapConfig(GPIO_Remap_SPI3,ENABLE);
     AFIO->MAPR2 |= 0x00800000;
     
     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  
     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;  
     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;  
     SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;  //串行同步时钟的空闲状态为高电平
     SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;  //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;  //定义波特率预分频的值:波特率预分频值为256
     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
     SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
     SPI_Init(FLASH_SPI, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
     SPI_Cmd(FLASH_SPI, ENABLE); //使能SPI外设
     
     FLASH_SPI_ReadWriteByte(0xff);//启动传输

    最后代码可以正常的使用。

    结语

    这就是我分享的项目中遇到一个HK官方库使用的问题,希望官方也可以查看一下,如果大家有更好的想法和需求,也欢迎大家加我好友交流分享哈。


    作者:良知犹存,白天努力工作,晚上原创公号号主。公众号内容除了技术还有些人生感悟,一个认真输出内容的职场老司机,也是一个技术之外丰富生活的人,摄影、音乐 and 篮球。关注我,与我一起同行。

    ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

    推荐阅读

    【1】在球场上我向人民币玩家低了头

    【2】嵌入式底层开发的软件框架简述

    【3】CPU中的程序是怎么运行起来的 必读

    【4】cartographer环境建立以及建图测试

    【5】设计模式之简单工厂模式、工厂模式、抽象工厂模式的对比

    本公众号全部原创干货已整理成一个目录,回复[ 资源 ]即可获得。

  • 相关阅读:
    [swustoj 243] 又是一年CET46
    [转] 解析Qt资源文件使用
    [转] Qt 多线程学习
    USACO全部测试数据
    [HUD 1195] Open the Lock
    Vue-cli+webpack单页模式详解(转)
    关于vs code终端执行webpack命令报错问题(转)
    git使用相关记录
    关于flex布局兼容
    canvas绘画交叉波浪
  • 原文地址:https://www.cnblogs.com/conscience-remain/p/15389714.html
Copyright © 2011-2022 走看看