打印

91x_gpio.c中的函数存在Bug

[复制链接]
3159|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
seawwh|  楼主 | 2007-2-7 21:57 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
91x_gpio.c中的函数存在Bug ?

  91x_gpio.c中的函数 GPIO_Init的功能是对引脚进行初始化的函数,如果我们需要初始化
P9.0-P9.7,作为输出引脚,那么可以这样对引脚进行初始化:


  GPIO_DeInit(GPIO9);
  GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
  GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ;
  GPIO_InitStructure.GPIO_Alternate=GPIO_OutputAlt1;
  GPIO_Init (GPIO9, &GPIO_InitStructure);    


  事实上,通过程序单步跟踪可以发现,这样的操作会导致对SCU->GPIOOUT[GPIO_Number]   
寄存器的越界访问,详见下面函数的(2)处。因为GPIO_Number的值为9,而实际上SCU->GPIOOUT[]
的下标范围为0..7, 硬件上不存在SCU->GPIOOUT[8]和SCU->GPIOOUT[9]寄存器。

  建议增加语句(1),防止越界访问。
  
  我的实验表明这样的越界访问会导致程序通过CAPS+FlashLink下装之后不能够在CAPS的复位控制
下正常运行,好像引脚不是输出态,同时按动板上的复位按键也不能正常。但是,掉电复位之后,可以正常运行。
  一旦程序正常运行之后,按动复位按键,程序可以正常重新启动。但是,通过CAPS的复位,程序又不能正常运行。

  如果避免了越界访问,那么以上的3种复位都能正常。


void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
  /* Select pin direction */
  u8 PinNumber = 0;
  u8 Counter = 0;
  u8 GPIO_Number = 0;

  GPIO_Number = GPIO_GetGPIONumber(GPIOx);


  if(GPIO_InitStruct->GPIO_Direction == GPIO_PinOutput)
  {
  GPIOx->DDR |= GPIO_InitStruct->GPIO_Pin;
  }
  else
  {
   GPIOx->DDR &= ~GPIO_InitStruct->GPIO_Pin;
  }
 
    for (Counter = 0; Counter < 8;Counter++)
    {
     /*Search pin number*/
     PinNumber = (GPIO_InitStruct->GPIO_Pin & (1 <<Counter));
     if((PinNumber >> Counter) == 1)
     {
        if (GPIO_Number<8 )                                         //(1)
        {  
          /*Output ALternate 0*/
          SCU->GPIOOUT[GPIO_Number] &= ~(0x3 <<(Counter *2));
          if(GPIO_InitStruct->GPIO_Alternate == GPIO_OutputAlt1)
          {
            /*Output ALternate 1*/
            SCU->GPIOOUT[GPIO_Number] |= 1 << (Counter *2);      // (2)
          }
          if(GPIO_InitStruct->GPIO_Alternate == GPIO_OutputAlt2)
          {
            /*Output ALternate 2*/
            SCU->GPIOOUT[GPIO_Number] |= 0x2 << (Counter *2);
          }
          if(GPIO_InitStruct->GPIO_Alternate == GPIO_OutputAlt3)
          {
            /*Output ALternate 3*/
            SCU->GPIOOUT[GPIO_Number] |= 0x3 << (Counter *2);
          }
        }  
       /*Type configuration: PushPull or Open Collector*/
        SCU->GPIOTYPE[GPIO_Number] &= ~(0x1 << Counter) ;
       if(GPIO_InitStruct->GPIO_Type == GPIO_Type_OpenCollector)
       {
         /*Open Drain configuration*/
        SCU->GPIOTYPE[GPIO_Number] |= 0x1 << Counter;
       }

       /*IP Connected disable*/
       SCU->GPIOIN[GPIO_Number] &= ~(0x1 << Counter) ;
       if(GPIO_InitStruct->GPIO_IPConnected == GPIO_IPConnected_Enable)
       {
         /*IP Connected enable*/
         SCU->GPIOIN[GPIO_Number] |= 0x1 << Counter;
       }
    }
  }
}
 
沙发
香水城| | 2007-2-8 11:09 | 只看该作者

谢谢楼主的发现与建议

关于越界访问检测的问题,是使用方便性与代码效率的一对矛盾,在函数库中可以很容易的增加越界访问检测的语句,但结果是目标代码变长导致效率降低。

这个问题的一个最突出的体现是,我们做过一个试验,用我们提供的函数库向I/O口输出方波,它的速度比用寄存器直接访问要慢很多;这个例子说明,使用函数库提高了编程的方便性,但牺牲了代码效率。

在越界访问检测这个问题上,我认为程序员应对自己的程序加以控制,毕竟对I/O口访问方面出现越界访问不是一个复杂的程序问题,应可以很容易地得到避免;基于这种考虑,提高代码的效率就更加重要了。

使用特权

评论回复
板凳
gyt| | 2007-2-8 12:24 | 只看该作者

厉害

不错不错

使用特权

评论回复
地板
sparkman| | 2007-2-8 12:28 | 只看该作者

P9口可以作为GPIO来访问

试过了,可以配置,没有出错。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

145

主题

368

帖子

0

粉丝