[ARM7--LPC2478]带USB功能的启动代码的分析

简述

LPC2478支持USB Host/Device/OTG功能。使用的是OHCI架构的USB。结合对LPC2478的了解,记录下其启动代码的分析,用于了解其USB的工作方式以及配置流程。

启动代码的流程

从IC上电开始,LPC2478应当首先会执行其内部固话的Boot Loader code,具体是做什么以及源代码不知道,NXP并不会开源的,这部分涉及到IC设计了。

Boot Loader阶段

Boot Loader code的作用就是检查哪块memory进行启动,并做判断,然后对User code做一些初始化,然后跳转到对应memory区域的User code中去。这里一般都是用的Flash Memory启动了,别的也是类似。

User code汇编代码阶段

这里的汇编代码是指NXP提供的.s的汇编代码。因为从Boot Loader结束到跳入User code,还需要有些初始化的配置的,不过NXP都写好了示例的。从NXP的启动代码看到:
- 对各中断模式以及用户代码Stack以及Heap大小的设置;
- 中断向量跳转地址设定;
- Reset Handler的处理:这部分应当是用来跳入User code的前奏了,先设置好各个模式的堆栈(通过CPSR_c寄存器来切换到各模式),当然,最后一个被设置堆栈的模式是User code模式,然后调用TargetResetInit()函数,接着跳入main()函数真正进入到User code中去执行。

TargetResetInit函数

这个函数的作用就是,在跳进main函数之前初始化自己的LPC2478板子的一些配置。

void TargetResetInit(void)
{
#ifdef __DEBUG_RAM 
  MEMMAP = 0x2;         /* remap to internal RAM */
#endif
#ifdef __DEBUG_FLASH 
  MEMMAP = 0x1;         /* remap to internal flash */
#endif

#if USE_USB
  PCONP |= 0x80000000;      /* Turn On USB PCLK, PCONP寄存器通过bit来控制其中的外设模块的使能与否,类似STM32中的XXXCmd接口的作用 */
#endif
  /* Configure PLL, switch from IRC to Main OSC */
  ConfigurePLL();

  /* Set system timers for each component */
#if (Fpclk / (Fcclk / 4)) == 1
  PCLKSEL0 = 0x00000000;    /* PCLK is 1/4 CCLK */
  PCLKSEL1 = 0x00000000;
#endif
#if (Fpclk / (Fcclk / 4)) == 2
  PCLKSEL0 = 0xAAAAAAAA;    /* PCLK is 1/2 CCLK */
  PCLKSEL1 = 0xAAAAAAAA;     
#endif
#if (Fpclk / (Fcclk / 4)) == 4
  PCLKSEL0 = 0x55555555;    /* PCLK is the same as CCLK */
  PCLKSEL1 = 0x55555555;    
#endif 
  /* Set memory accelerater module*/
  MAMCR = 0;
#if Fcclk < 20000000
  MAMTIM = 1;
#else
#if Fcclk < 40000000
  MAMTIM = 2;
#else
  MAMTIM = 3;
#endif
#endif
  MAMCR = 2;  
 // GPIOResetInit();
  init_VIC(); 
  return;
}

PLL配置

TargetResetInit函数中有ConfigurePLL这个函数,这里看下LPC2478的PLL:

PLL的框图以及频率输入输出配置的公式

[ARM7--LPC2478]带USB功能的启动代码的分析_第1张图片
公式中的F_IN是图中pllclkin,F_CCO是图中CCO的输出处288MHz的位置,M是M-DIVIDER,N是N-DIVIDER。
图中PLLC和PLLE是表征PLL的状态的:
[ARM7--LPC2478]带USB功能的启动代码的分析_第2张图片

ConfigurePLL

/****************************************************************************** ** Function name: ConfigurePLL ** ** Descriptions: Configure PLL switching to main OSC instead of IRC ** at power up and wake up from power down. ** This routine is used in TargetResetInit() and those ** examples using power down and wake up such as ** USB suspend to resume, ethernet WOL, and power management ** example ** parameters: None ** Returned value: None ** ******************************************************************************/
void ConfigurePLL ( void )
{
  unsigned long  MValue, NValue;

  /* Get PLLC: PLL connected or not. */
  if ( PLLSTAT & (1 << 25) )    
  {
    /* PLL connected when boot loader */
    PLLCON = 1;             /* Enable PLL, disconnected */
    /* Feed sequence make PLLCON and PLLCFG take effect */
    PLLFEED = 0xaa;
    PLLFEED = 0x55;
  }
  PLLCON = 0;               /* Disable PLL, disconnected */
  PLLFEED = 0xaa;
  PLLFEED = 0x55;

  SCS |= 0x20;          /* Enable main OSC */
  while( !(SCS & 0x40) );   /* Wait until main OSC is usable */

  CLKSRCSEL = 0x1;      /* select main OSC, 12MHz, as the PLL clock source */

  /* PLL_MValue = 11, PLL_NValue = 0 */
  PLLCFG = PLL_MValue | (PLL_NValue << 16);
  PLLFEED = 0xaa;
  PLLFEED = 0x55;

  PLLCON = 1;               /* Enable PLL, disconnected */
  PLLFEED = 0xaa;
  PLLFEED = 0x55;

  CCLKCFG = CCLKDivValue;   /* Set clock divider, 5 */
#if USE_USB
  USBCLKCFG = USBCLKDivValue;       /* usbclk = 288 MHz/6 = 48 MHz */
#endif

  while ( ((PLLSTAT & (1 << 26)) == 0) );   /* Check lock bit status */

  MValue = PLLSTAT & 0x00007FFF;
  NValue = (PLLSTAT & 0x00FF0000) >> 16;
  while ((MValue != PLL_MValue) && ( NValue != PLL_NValue) ); 
  PLLCON = 3;               /* enable and connect */
  PLLFEED = 0xaa;
  PLLFEED = 0x55;
  while ( ((PLLSTAT & (1 << 25)) == 0) );   /* Check connect bit status */
  return;
}

首先需要关闭PLL(因为Boot阶段可能会用到PLL的),然后选择Main OSB作为时钟源,我们的板子使用的是12MHz的,这个时钟源即为上面PLL图中的F_IN,接下来通过PLL_MValue和PLL_NValue分别配置好M和N的值,这样F_CCO就可以计算出来了。接着是配置好USB和系统时钟的分频。最后在检查确认参数是否配置成功。
其中PLL_MValue,PLL_NValue,CCLKDivValue,USBCLKDivValue的值在使用实际值换算时都需要加上1的。这样,可以得出这段PLL config代码的时钟输出为:

F_CCO = (2 * 12 * 12)/1 = 288 MHz
F_USB = F_CCO/6 = 48 MHz
F_CCLK = F_CCO/6 = 48 MHz

你可能感兴趣的:(分析,usb,ARM,启动代码,LPC2478)