uTenux操作系统在LM3S9b96上的移植问题



TI专家:

 悠龙咨询的开源、物联网嵌入式操作系统uTenux支持ARM公司的ARM7/9、Cortex M微控制器,可以作为uC/OS II的免费替代品,而且功能更强,详细地介绍可以参考www.uloong.cc网站或者www.tecoss.org社区。

 现在正在移植到LM3S9b96上,但调试时碰到了问题,问题如下:

 背景:

   1.uTenux移植时涉及到时钟、GPIO、UART、Flash;

       2.uTenux是直接使用汇编控制外设的寄存器进行初始化;

   3.使用的开发板是TI委托英蓓特生产的DK-LM3S9b96;

 问题:

 主要发生在时钟初始化时,参考了TI的Datasheet以及C库的代码,目的是使用PLL,设置系统时钟为50MHz,现在的初始化流程如下:

 1  SYSCTL_RCC |= 0x01<<11           旁路PLL

   2  SYSCTL_RCC &=~(0x01<<22)     不使用分频器

 3  SYSCTL_RCC &=~(0x1f<<6 )        设置MOSC频率为16MHz

   4  SYSCTL_RCC |= 0x15<<6

   5  SYSCTL_RCC &=~(0x03<<4 )       MOSC为时钟源

 6  SYSCTL_RCC &=~(0x01<<0)        MOSC使能

 7  If (SYSCTL_RIS&(0x1<<8) )            MOSC稳定?

   8    SYSCTL_MISC = 0x1<<8               清除锁定

 9  SYSCTL_RCC &=~(0x0f<<23 )      设置分频为4,主频50MHz

 10 SYSCTL_RCC |= 0x03<<23

 11 SYSCTL_RCC &=~(0x01<<13 )       PLL上电

12 If (SYSCTL_RIS&(0x1<<6) )              PLL稳定?

 13    SYSCTL_MISC = 0x1<<6        清除锁定

14 SYSCTL_RCC |= 0x01<<22        使用分频器

15 SYSCTL_RCC &=~(0x01<<11)        PLL输出到系统时钟

 但实际运行时,第7行和12行一直无法等待到RIS寄存器中MOSC稳定和PLL稳定相关位。

 建议:

 如果有类似的汇编代码直接初始化时钟的,麻烦发送一份。

 如果没有,麻烦告知以上流程的问题在哪里?

谢谢。

 uTenux已经支持的MCU有:ATMEL的AT91SAM7、SAM9、SAM3;NXP的LPC2100、FUJITSU的FM3、SUMSANG的S3C2440等.

  • TI的Stellaris系列MCU有专门的驱动库StellarisWare支持,使用起来很方便。同时对于系统时钟的初始化在驱动库里    

    SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);这个函数去支持。推荐使用StellarisWare驱动库去做Stellaris的开发。

    SysCtlClockSet这个函数源代码如下

    void

    SysCtlClockSet(unsigned long ulConfig)

    {

       unsigned long ulDelay, ulRCC, ulRCC2;

       //

       // See if this is a Sandstorm-class device and clocking features from newer

       // devices were requested.

       //

       if(CLASS_IS_SANDSTORM && (ulConfig & SYSCTL_RCC2_USERCC2))

       {

           //

           // Return without changing the clocking since the requested

           // configuration can not be achieved.

           //

           return;

       }

       //

       // Get the current value of the RCC and RCC2 registers.  If using a

       // Sandstorm-class device, the RCC2 register will read back as zero and the

       // writes to it from within this function will be ignored.

       //

       ulRCC = HWREG(SYSCTL_RCC);

       ulRCC2 = HWREG(SYSCTL_RCC2);

       //

       // Bypass the PLL and system clock dividers for now.

       //

       ulRCC |= SYSCTL_RCC_BYPASS;

       ulRCC &= ~(SYSCTL_RCC_USESYSDIV);

       ulRCC2 |= SYSCTL_RCC2_BYPASS2;

       //

       // Write the new RCC value.

       //

       HWREG(SYSCTL_RCC) = ulRCC;

       HWREG(SYSCTL_RCC2) = ulRCC2;

       //

       // See if either oscillator needs to be enabled.

       //

       if(((ulRCC & SYSCTL_RCC_IOSCDIS) && !(ulConfig & SYSCTL_RCC_IOSCDIS)) ||

          ((ulRCC & SYSCTL_RCC_MOSCDIS) && !(ulConfig & SYSCTL_RCC_MOSCDIS)))

       {

           //

           // Make sure that the required oscillators are enabled.  For now, the

           // previously enabled oscillators must be enabled along with the newly

           // requested oscillators.

           //

           ulRCC &= (~(SYSCTL_RCC_IOSCDIS | SYSCTL_RCC_MOSCDIS) |

                     (ulConfig & (SYSCTL_RCC_IOSCDIS | SYSCTL_RCC_MOSCDIS)));

           //

           // Write the new RCC value.

           //

           HWREG(SYSCTL_RCC) = ulRCC;

           //

           // Wait for a bit, giving the oscillator time to stabilize.  The number

           // of iterations is adjusted based on the current clock source; a

           // smaller number of iterations is required for slower clock rates.

           //

           if(((ulRCC2 & SYSCTL_RCC2_USERCC2) &&

               (((ulRCC2 & SYSCTL_RCC2_OSCSRC2_M) == SYSCTL_RCC2_OSCSRC2_30) ||

                ((ulRCC2 & SYSCTL_RCC2_OSCSRC2_M) == SYSCTL_RCC2_OSCSRC2_32))) ||

              (!(ulRCC2 & SYSCTL_RCC2_USERCC2) &&

               ((ulRCC & SYSCTL_RCC_OSCSRC_M) == SYSCTL_RCC_OSCSRC_30)))

           {

               //

               // Delay for 4096 iterations.

               //

               SysCtlDelay(4096);

           }

           else

           {

               //

               // Delay for 524,288 iterations.

               //

               SysCtlDelay(524288);

           }

       }

       //

       // Set the new crystal value, oscillator source, and PLL configuration.

       // Since the OSCSRC2 field in RCC2 overlaps the XTAL field in RCC, the

       // OSCSRC field has a special encoding within ulConfig to avoid the

       // overlap.

       //

       ulRCC &= ~(SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M |

                  SYSCTL_RCC_PWRDN | SYSCTL_RCC_OEN);

       ulRCC |= ulConfig & (SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M |

                            SYSCTL_RCC_PWRDN | SYSCTL_RCC_OEN);

       ulRCC2 &= ~(SYSCTL_RCC2_USERCC2 | SYSCTL_RCC2_OSCSRC2_M |

                   SYSCTL_RCC2_PWRDN2);

       ulRCC2 |= ulConfig & (SYSCTL_RCC2_USERCC2 | SYSCTL_RCC_OSCSRC_M |

                             SYSCTL_RCC2_PWRDN2);

       ulRCC2 |= (ulConfig & 0x00000008) << 3;

       //

       // Clear the PLL lock interrupt.

       //

       HWREG(SYSCTL_MISC) = SYSCTL_INT_PLL_LOCK;

       //

       // Write the new RCC value.

       //

       if(ulRCC2 & SYSCTL_RCC2_USERCC2)

       {

           HWREG(SYSCTL_RCC2) = ulRCC2;

           HWREG(SYSCTL_RCC) = ulRCC;

       }

       else

       {

           HWREG(SYSCTL_RCC) = ulRCC;

           HWREG(SYSCTL_RCC2) = ulRCC2;

       }

       //

       // Wait for a bit so that new crystal value and oscillator source can take

       // effect.

       //

       SysCtlDelay(16);

       //

       // Set the requested system divider and disable the appropriate

       // oscillators.  This will not get written immediately.

       //

       ulRCC &= ~(SYSCTL_RCC_SYSDIV_M | SYSCTL_RCC_USESYSDIV |

                  SYSCTL_RCC_IOSCDIS | SYSCTL_RCC_MOSCDIS);

       ulRCC |= ulConfig & (SYSCTL_RCC_SYSDIV_M | SYSCTL_RCC_USESYSDIV |

                            SYSCTL_RCC_IOSCDIS | SYSCTL_RCC_MOSCDIS);

       ulRCC2 &= ~(SYSCTL_RCC2_SYSDIV2_M);

       ulRCC2 |= ulConfig & SYSCTL_RCC2_SYSDIV2_M;

       if(ulConfig & SYSCTL_RCC2_DIV400)

       {

           ulRCC |= SYSCTL_RCC_USESYSDIV;

           ulRCC2 &= ~(SYSCTL_RCC_USESYSDIV);

           ulRCC2 |= ulConfig & (SYSCTL_RCC2_DIV400 | SYSCTL_RCC2_SYSDIV2LSB);

       }

       else

       {

           ulRCC2 &= ~(SYSCTL_RCC2_DIV400);

       }

       //

       // See if the PLL output is being used to clock the system.

       //

       if(!(ulConfig & SYSCTL_RCC_BYPASS))

       {

           //

           // Wait until the PLL has locked.

           //

           for(ulDelay = 32768; ulDelay > 0; ulDelay--)

           {

               if(HWREG(SYSCTL_RIS) & SYSCTL_INT_PLL_LOCK)

               {

                   break;

               }

           }

           //

           // Enable use of the PLL.

           //

           ulRCC &= ~(SYSCTL_RCC_BYPASS);

           ulRCC2 &= ~(SYSCTL_RCC2_BYPASS2);

       }

       //

       // Write the final RCC value.

       //

       HWREG(SYSCTL_RCC) = ulRCC;

       HWREG(SYSCTL_RCC2) = ulRCC2;

       //

       // Delay for a little bit so that the system divider takes effect.

       //

       SysCtlDelay(16);

    }