前言:
今天給大家介紹一下自己在使用航順32芯片中遇到的一些問(wèn)題。我用的是航順的HK32f103VET6的一顆芯片,其中使用其中SPI3外設(shè)復(fù)用功能時(shí),發(fā)現(xiàn)對(duì)應(yīng)官方庫(kù)的宏定義有些錯(cuò)誤。遂給大家分享一下使用修改過(guò)程。
順帶給大家介紹一下航順公司。
情節(jié)介紹:
我們使用MCU過(guò)程中會(huì)遇到一些IO外設(shè)進(jìn)行復(fù)用 (為了優(yōu)化64腳或100腳封裝的外設(shè)數(shù)目,可以把一些復(fù)用功能重新映射到其他引腳上。設(shè)置復(fù)用重映射和調(diào)試I/O配置寄存器(AFIO_MAPR)實(shí)現(xiàn)引腳的重新映射。這時(shí),復(fù)用功能不再映射到它們的原始分配上) 到非默認(rèn)的引腳。
我在使用航順芯片時(shí)候想把PD3、PD4、PD5、PD6使用為SPI引腳。
手冊(cè)配置查詢
經(jīng)過(guò)查詢對(duì)應(yīng)的數(shù)據(jù)手冊(cè)之后:(這是我查看手冊(cè)對(duì)應(yīng)的版本)
可以看到 PD3、PD4、PD5、PD6可以復(fù)用為SPI3功能引腳
一般我們都是看AFIO功能開(kāi)發(fā)手冊(cè)說(shuō)明,看對(duì)應(yīng)的IO的復(fù)用選項(xiàng)。
ST示例如下:
航順在開(kāi)發(fā)手冊(cè)中也有描述,但是沒(méi)有描述SPI3復(fù)用選項(xiàng)
所以緊接著我又去查看航順開(kāi)發(fā)手冊(cè),看里面AFIO的寄存器詳細(xì)描述:
其中SPI3歸屬在 航順新增的AFIO_MAPR2 復(fù)用寄存器中:
詳細(xì)對(duì)應(yīng)的關(guān)系可以看到, AFIO_MAPR2 是一個(gè)32位的寄存器,其中SPI3 在23位進(jìn)行配置,其中我需要進(jìn)行把 PD3、PD4、PD5、PD6可以復(fù)用為SPI3功能引腳,在此位進(jìn)行設(shè)置,只需要 把此位設(shè)置 為 1 。
函數(shù)對(duì)應(yīng)
我使用的航順的V1.0.4庫(kù)函數(shù)版本:
使用復(fù)用功能 我需要用到 void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState) 這個(gè)函數(shù)。
我使用
GPIO_PinRemapConfig(GPIO_Remap_SPI3,ENABLE);
發(fā)現(xiàn)該SPI功能無(wú)法實(shí)現(xiàn)。
所以我們需要更加深入的查看代碼:
在官方提供的hk32f10x_gpio .c 文件中你可以看到函數(shù)原型:
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;
}
}
其中最重要對(duì)MAPR2 對(duì)應(yīng)寄存器配置的是此處代碼:
if((GPIO_Remap & 0x80000000) == 0x80000000)
{
AFIO->MAPR2 = tmpreg;
}
else
{
AFIO->MAPR = tmpreg;
}
GPIO_Remap 參數(shù)有個(gè)掩碼,最高位是1的情況下,配置 MAPR2寄存器,否則就去配置 MAPR寄存器。
而我們需要去操作MAPR2寄存器配置SPI3復(fù)用功能。
通過(guò)IS_GPIO_REMAP
IS_GPIO_REMAP(GPIO_Remap)
我們可以看一下 對(duì)應(yīng)的GPIO_Remap參數(shù)定義。
這樣查看完,發(fā)現(xiàn)MAPR2寄存器對(duì)應(yīng)的SPI3宏定義最高位是0,中間填充的數(shù)據(jù)也是有問(wèn)題的。
因?yàn)槲覀冃枰{(diào)用GPIO_PinRemapConfig函數(shù)配置MAPR2寄存器的情況下,需要最高位是1
#define GPIO_Remap_SPI3 ((uint32_t)0x00201100)
而我們可以看到官方提供的hk32f10x_gpio .h文件中GPIO_Remap_SPI3的宏定義最高位不是1
這樣我們使用 GPIO_PinRemapConfig(GPIO_Remap_SPI3,ENABLE); 復(fù)用配置SPI3就會(huì)失敗
修改建議:
庫(kù)函數(shù)出現(xiàn)問(wèn)題,那我們就直接配置寄存器吧。
查看對(duì)應(yīng)的SPI3_REMAP對(duì)應(yīng)位,我們可以算出來(lái)32位為1對(duì)應(yīng)的16進(jìn)制值為 0x800000
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; //串行同步時(shí)鐘的空閑狀態(tài)為高電平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步時(shí)鐘的第二個(gè)跳變沿(上升或下降)數(shù)據(jù)被采樣
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信號(hào)由硬件(NSS管腳)還是軟件(使用SSI位)管理:內(nèi)部NSS信號(hào)有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定義波特率預(yù)分頻的值:波特率預(yù)分頻值為256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定數(shù)據(jù)傳輸從MSB位還是LSB位開(kāi)始:數(shù)據(jù)傳輸從MSB位開(kāi)始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值計(jì)算的多項(xiàng)式
SPI_Init(FLASH_SPI, &SPI_InitStructure); //根據(jù)SPI_InitStruct中指定的參數(shù)初始化外設(shè)SPIx寄存器
SPI_Cmd(FLASH_SPI, ENABLE); //使能SPI外設(shè)
FLASH_SPI_ReadWriteByte(0xff);//啟動(dòng)傳輸
最后代碼可以正常的使用。
結(jié)語(yǔ)
這就是我分享的項(xiàng)目中遇到一個(gè)HK官方庫(kù)使用的問(wèn)題,希望官方也可以查看一下,如果大家有更好的想法和需求,也歡迎大家加我好友交流分享哈。
作者:良知猶存