库函数bug更改——GPIO_PinAFConfig()
在调试PWM输出函数过程中,发现一处MM32F031库函数的bug。样例代码库中TIM3_PWM_OUTPUT例程中使用的代码如下:
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); //¿ªÆôGPIOBʱÖÓ
//SYSCFG->CFGR|=0x1<<11;
GPIOB->AFRL=0x10000; //大家注意这条为寄存器操作方式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //TIM3_CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
。。。 。。。
}
这里大家注意到
GPIOB->AFRL = 0x10000;这行代码采用了寄存器操作方式,而不是函数库操作方式,感觉非常不协调,于是我改成HAL_gpio库中提供的函数
void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF)
经过测试,使用GPIO_PinAFConfig()函数后,PWM的输出就消失了。如下为源库文件中函数代码:
/**
注释省略
*/
void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF)
{
uint32_t temp = 0x00;
uint32_t temp_2 = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
assert_param(IS_GPIO_AF(GPIO_AF));
temp = ((uint32_t)(GPIO_AF) << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4));
if((GPIO_PinSource >> 0x03) ==0)
{
GPIOx->AFRL &= ~((uint32_t)0xF << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4));
temp_2 = GPIOx->AFRL | temp;
GPIOx->AFRL = temp_2;
}
else
{
GPIOx->AFRH &= ~((uint32_t)0xF << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4));
temp_2 = GPIOx->AFRH | temp;
GPIOx->AFRH = temp_2;
}
}
对照MM32F031的手册中的相关说明,AFRL和AFRH两个寄存器分别负责IO引脚序号为0-7和8-15的IO转换功能的配置,因此上述代码存在如下几处问题。
1、 ~((uint32_t)0xF << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4));该语句用于生成掩码时错误的。
2、temp = ((uint32_t)(GPIO_AF) << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4)); 该语句用于生成统一的IO引脚号0-15的或码也是错误的。
鉴于上述问题,我修改的代码如下两种:
修改如下
void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF)
{
uint32_t temp = 0x00;
uint32_t temp_2 = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
assert_param(IS_GPIO_AF(GPIO_AF));
// temp = ((uint32_t)(GPIO_AF) << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4));
if((GPIO_PinNum >> 0x03) ==0)
{
// GPIOx->AFRL &= ~((uint32_t)0xF << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4));
temp = ((uint32_t)(GPIO_AF) << ((uint32_t)GPIO_PinSource * 4));
GPIOx->AFRL &= ~((uint32_t)0xF<< ((uint32_t)GPIO_PinSource * 4));
temp_2 = GPIOx->AFRL | temp;
GPIOx->AFRL = temp_2;
}
else
{
// GPIOx->AFRH &= ~((uint32_t)0xF << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4));
temp = ((uint32_t)(GPIO_AF) << ((uint32_t)(GPIO_PinSource-8) * 4));
GPIOx->AFRH &= ~((uint32_t)0xF<< ((uint32_t)(GPIO_PinSource-8) * 4));
temp_2 = GPIOx->AFRH | temp;
GPIOx->AFRH = temp_2;
}
}
经过测试,修改后代码是有效的。
此内容由EEWORLD论坛网友我爱下载原创,如需转载或用于商业用途需征得作者同意并注明出处
本帖最后由 我爱下载 于 2018-10-18 16:30 编辑