2009年5月2日土曜日

フェーズ1 GPIO テスト NXP LPC2388

NXP LPC2388の GPIO を以下のとおり検証した。


概要 4つのLEDをTIMER0で点滅させる。


タイマ割り込みハンドラは startup.s で設定されたハンドラ CPU_IRQInterrupt を main() ソースファイルに、準備する。


1.GPIO使用 main()関数側
  1)初期設定
    GPIO_InitTypeDef GPIO_InitStructure;
     // GPIO 0
    GPIO_InitStructure.GPIO_ID = GPIO_Port_0;
    GPIO_InitStructure.GPIO_Pins = GPIO_Pin_27;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_FAST;
    GPIO_InitStructure.GPIO_ModeIO = GPIO_Mode_OUTPUT;
    GPIO_InitStructure.GPIO_ModePin = GPIO_ModePin_PULLDOWN;
    GPIO_Init(&GPIO_0,&GPIO_InitStructure);

 ※ システムコントロールレジスタ SCS(0xE01FC1A0) に0x01をセットするとGPIO0,GPIO1はFGPIOに設定されるが、設定の有無による違い未だ実感出来ず。(高速IFが必要にならない限り実感できないと思う。)

 2)GPIO出力 
   GPIO ポート1の18番ピンに1出力 付録基板LED1消燈
   GPIO ポート1の19番、22番ピンに0出力 外付けLEDが点灯
     GPIO_SetBits(&GPIO_1,GPIO_Pin_18);
     GPIO_ResetBits(&GPIO_1, GPIO_Pin_19 GPIO_Pin_22);
2.GPIO使用 LPC用GPIO関数側
 1)GPIO設定構造体
    typedef struct
    {
    GPIOPortID_TypeDef GPIO_ID;
    u32 GPIO_Pins;
    GPIOMode_TypeDef GPIO_Mode;
    GPIOModeIO_TypeDef GPIO_ModeIO;
    GPIOModePin_TypeDef GPIO_ModePin;
    }GPIO_InitTypeDef;

 2)GPIO構造体
    typedef struct
    {
    vu32 *pIOPIN;
    vu32 *pIOSET;
    vu32 *pIODIR;
    vu32 *pIOCLR;
    vu32 *pFIODIR;
    vu32 *pFIOMASK;
    vu32 *pFIOPIN;     
    vu32 *pFIOSET;
    vu32 *pFIOCLR;
    } GPIO_TypeDef;


    EXTERN GPIO_TypeDef GPIO_0;
    EXTERN GPIO_TypeDef GPIO_1;
    EXTERN GPIO_TypeDef GPIO_2;
    EXTERN GPIO_TypeDef GPIO_3;
    EXTERN GPIO_TypeDef GPIO_4;


 3)関数 GPIO_Init
    void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
    {
     u32 i;
     u32 *pPINSEL_H;
     u32 *pPINSEL_L;
     u32 *pPINMODE_H;
     u32 *pPINMODE_L;
     vu32 bitpattern;
       
    switch(GPIO_InitStruct->GPIO_ID)
    {
      case GPIO_Port_0:  //ポート0のピン選択レジスタポインタをセット
        pPINSEL_L = (u32 *)(PINSEL_BASE_ADDR + 0x00);
        pPINSEL_H = (u32 *)(PINSEL_BASE_ADDR + 0x04);
        pPINMODE_L = (u32 *)(PINSEL_BASE_ADDR + 0x40);
        pPINMODE_H = (u32 *)(PINSEL_BASE_ADDR + 0x44);
        break;
      case GPIO_Port_1:
        pPINSEL_L = (u32 *)(PINSEL_BASE_ADDR + 0x08);
        pPINSEL_H = (u32 *)(PINSEL_BASE_ADDR + 0x0c);
    ///////////////////////////////////////////
      default:
         return;
    }
      /* Setting Low Bits . for use GPIO (Bit Patern "00")*/
    for(i=0;i<16;i++)
    {
      if( GPIO_InitStruct->GPIO_Pins & (0x00000001 << i))
      {  // ピン選択レジスタの設定 Pin0-15
        bitpattern = 0x0000003 << (2*i);
        bitpattern ^= 0xFFFFFFFF;
        *pPINSEL_L &= bitpattern;
        //Bit Clear and Pin use GPIO
        *pPINMODE_L &= bitpattern;
        //Bit Clear
        bitpattern = GPIO_InitStruct->GPIO_ModePin << (2*i);
        *pPINMODE_L = bitpattern;
      }
    }
    for(i=0;i<16;i++)
    {
      if( GPIO_InitStruct->GPIO_Pins & (0x00000001 << (i+16)))
      { // ピン選択レジスタの設定 Pin16-31
        bitpattern = 0x0000003 << (2*i);
        bitpattern ^= 0xFFFFFFFF;
        *pPINSEL_H &= bitpattern;
        //Bit Clear and Pin use GPIO
        *pPINMODE_H &= bitpattern;
        //Bit Clear
        bitpattern = GPIO_InitStruct->GPIO_ModePin << (2*i);
        *pPINMODE_H = bitpattern;
      }
    }
    if( GPIO_InitStruct->GPIO_Mode == GPIO_Mode_REGACY)
    {
      switch(GPIO_InitStruct->GPIO_ID)
      { // GPIOレジスタポインタのGPIO構造体への登録
         case GPIO_Port_0:
          GPIOx->pIOPIN = (u32 *)(GPIO_BASE_ADDR + 0x00);
          GPIOx->pIOSET = (u32 *)(GPIO_BASE_ADDR + 0x04);
          GPIOx->pIOSET = (u32 *)(GPIO_BASE_ADDR + 0x04);
          GPIOx->pIODIR = (u32 *)(GPIO_BASE_ADDR + 0x08); // Pin Control Reg. (0:input 1:output)
          GPIOx->pIOCLR = (u32 *)(GPIO_BASE_ADDR + 0x0c); // Output Clear Reg.
         break;
        case GPIO_Port_1:
          GPIOx->pIOPIN = (u32 *)(GPIO_BASE_ADDR + 0x10);
          GPIOx->pIOSET = (u32 *)(GPIO_BASE_ADDR + 0x14);
          GPIOx->pIODIR = (u32 *)(GPIO_BASE_ADDR + 0x18);
          GPIOx->pIOCLR = (u32 *)(GPIO_BASE_ADDR + 0x1c);
          break;
        default:
          return;
      }
      GPIOx->pFIODIR = NULL;
      GPIOx->pFIOMASK = NULL;
      GPIOx->pFIOPIN = NULL;
      GPIOx->pFIOSET = NULL;
      GPIOx->pFIOCLR = NULL;
      for(i=0;i<32;i++)
      {  // 各ピンの入出力の設定
        if( GPIO_InitStruct->GPIO_Pins & (0x00000001 << i))
        {
          if(GPIO_InitStruct->GPIO_ModeIO == GPIO_Mode_INPUT)
          {
            bitpattern = 0x0000001 << i;
            bitpattern ^= 0xFFFFFFFF;
            *(GPIOx->pIODIR) &= bitpattern; // Input Mode bit off
          }
          else
          {
            bitpattern = 0x0000001 << i;
            *(GPIOx->pIODIR) = bitpattern; // Output Mode bit on
          }
        }
      }
    }
     else
    {
     /* Fast GPIO Mode */
      switch(GPIO_InitStruct->GPIO_ID)
      {  // GPIOレジスタ群のポインタをGPIO構造体へ登録
        case GPIO_Port_0:
          GPIOx->pFIODIR = (u32 *)(FIO_BASE_ADDR + 0x00); //Pin Control Reg. (0:input 1:output)
          pFIOMASK = (u32 *)(FIO_BASE_ADDR + 0x10); //Pin Mask Reg. (0:input 1:output)
          GPIOx->pFIOMASK = (u32 *)(FIO_BASE_ADDR + 0x10); //Pin Mask Reg. (0:input 1:output)
          GPIOx->pFIOPIN = (u32 *)(FIO_BASE_ADDR + 0x14); // Pin Value Reg.
          GPIOx->pFIOSET = (u32 *)(FIO_BASE_ADDR + 0x18); // Output Set Reg.
          GPIOx->pFIOCLR = (u32 *)(FIO_BASE_ADDR + 0x1c); // Output Clear Reg.
          break;
          case GPIO_Port_1:
          GPIOx->pFIODIR = (u32 *)(FIO_BASE_ADDR + 0x20);
       ///////////////////////////////////////////
         default:
           return;
      }
      GPIOx->pIOPIN = NULL;
      GPIOx->pIOSET = NULL;
      GPIOx->pIODIR = NULL;
      GPIOx->pIOCLR = NULL;
      for(i=0;i<32;i++)
      {  // 各ピンの入出力の設定
        if( GPIO_InitStruct->GPIO_Pins & (0x00000001 << i))
        {
          if(GPIO_InitStruct->GPIO_ModeIO == GPIO_Mode_INPUT)
          {
            bitpattern = 0x0000001 << i;
            bitpattern ^= 0xFFFFFFFF;
            *(GPIOx->pFIODIR) &= bitpattern; // Input Mode bit off
          }
          else
          {
            bitpattern = 0x0000001 << i;
            *(GPIOx->pFIODIR) = bitpattern; // Output Mode bit on
          }
          bitpattern = 0x0000001 << i;
          bitpattern ^= 0xFFFFFFFF;
          *(GPIOx->pFIOMASK) &= bitpattern; // Mask bit off
         }
        }
       }
       return;
    }
 4)関数 GPIO_SetBits ポート単位でのPin設定 
   GPIO ポートビットセットレジスタを使い Pinに”1”(High)を設定
    void GPIO_SetBits(GPIO_TypeDef* GPIOx, u32 GPIO_Pin)
    {
     if(GPIOx->pFIOSET != NULL) // FGPIOの判断
     {
        *(GPIOx->pFIOSET) = GPIO_Pin; 
      }
      else
      {
        *(GPIOx->pIOSET) = GPIO_Pin;  
      }
    }
 5)関数 GPIO_ResetBits ポート単位でのPinクリア
   GPIO ポートビットクリアレジスタを使い Pinに”0”(Low)を設定
    void GPIO_ResetBits(GPIO_TypeDef* GPIOx, u32 GPIO_Pin)
    {
       if(GPIOx->pFIOCLR != NULL)
      {
        *(GPIOx->pFIOCLR) = GPIO_Pin;
      }
      else
      {
        *(GPIOx->pIOCLR) = GPIO_Pin;
      }
    }

3.タイマ設定 main()側
 1) タイマ設定および 割り込み設定
    /* タイマコントローラへの供給クロック分周設定 */
    *CLK_PCLKSEL0 = (*CLK_PCLKSEL0 & 0xfffffff3); /* 1/4 */ /* タイマ0のパラメータ設定 */
    *TIMER_T0PR = 0x00000000;    /* プリスケール無し */
    *TIMER_T0MR0 = 1000000;    /* 供給クロック周波数=1秒 */
    *TIMER_T0MCR = 0x00000003;    /* Match時にTCクリア&割り込み */
    *TIMER_T0TCR = 1;   /* タイマスタート*/
    /* 割り込みコントローラ設定 */
    *VIC_IntSelect = *VIC_IntSelect & (~0x10); /* IRQ選択 */
    *VIC_IntEnable = *VIC_IntEnable 0x10; /* タイマ0のみ有効 */
    /* 割り込み許可 */
    CPU_EnableInterrupt();
  2)割り込みハンドラ
    IRQ割り込みでCALLされるハンドラをTIMER0の割り込みハンドラとして利用。
    void CPU_IRQInterrupt(void)
    {
      if( toggle == 0 ) {
        toggle = 1;
    ***************************************  
     *TIMER_T0IR =1; /* タイマ割り込みクリア */
    }

4.startup.s
   ここで IRQ割り込みを登録
 CQ出版IF誌のサンプル使用
.text
.extern main
.extern _sp_base
#======================================
# Initialize vectors
#======================================
    B _startup
    nop
    nop
    nop
    nop
    nop
    B _IRQ_handle
    nop
    .org 0x20
    .global _startup
_startup:
#IRQ通知を受け取るように設定する
    MRS R0, cpsr
    eor R0, R0, #0x80
    MSR cpsr, R0
#プロセッサモードをIRQモードへ
    MRS r1, CPSR
    BIC R1, R1, #0x1F
    ORR R1, R1, #0x12
    MSR CPSR, R1
#例外ハンドラ用スタックを設定
    LDR sp, = _exception_sp_base
#プロセッサモードをスーパーバイザモードへ戻す
    MRS r1, CPSR
    BIC R1, R1, #0x1F
    ORR R1, R1, #0x13
    MSR CPSR, R1
# スタックを設定
    LDR R13,=_sp_base
    BL main
    .align 0x4
_IRQ_handle:
#例外用スタックにレジスタ退避
    STMDB sp!,{r0-r12, r14}
    MRS r0, spsr
    STMDB sp!, {r0}
    bl CPU_IRQInterrupt
#例外用スタックからレジスタ復帰
    LDMIA sp!, {r0}
    MSR spsr_cf, r0
    LDMIA sp!,{r0-r12,r14}
    SUBS PC, R14, #4

0 件のコメント:

コメントを投稿