⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at91.c

📁 四个独立按键的程序
💻 C
字号:

/*
 * $Revision: 1.7 $
 */

#include "config.h"

static void(*timer_function)();
static void(*rxrdy_function)();


//
// Clock initialization.
//

#if AT91_EB42
void AT91_EB42_PllStart()
{
#define PMC_PLL_LOCK   1     // PLL lock status 

  // Speed up the System Frequency to 32 MHz.

  // Stay at PLL B if already set up.
  if ((__PMC_CGMR & 0x80) == 0)
  {
    // Run from 32 kHz until PLL is stabilized.
    // PLLCOUNT = 197, MUL = 976, CSS = 0, MCKODS = 0, MCKOSS = 1, PLLS = 1, PRES = 0
    __PMC_CGMR = 0xc503d008;

    // Reading the PMC Status register to detect when the PLL is stabilized
    while ((__PMC_SR & PMC_PLL_LOCK) != PMC_PLL_LOCK) ;
  }

  // Commuting from 32 kHz (or other PLL speed) to PLL @ 32 MHz
  // PLLCOUNT = 197, MUL = 976, CSS = 1, MCKODS = 0, MCKOSS = 1, PLLS = 1, PRES = 0
  __PMC_CGMR = 0xc503d098;
  
  // Reading the PMC Status register to detect when the PLL is stabilized
  while ((__PMC_SR & PMC_PLL_LOCK) != PMC_PLL_LOCK) ;

  // Now the Master clock is the output of PLL @ 32MHz
}
#endif

#if AT91_EB55
void AT91_EB55_PllStart()
{
#define APMC_MOSCS      1     // Main oscillator status bit 
#define APMC_PLL_LOCK   2     // PLL lock status 

  int i;
  
  // Speed up the System Frequency.

  __APMC_CGMR = 0x002F0002; // MOSCEN = 1, OSCOUNT = 47  (1.4ms/30祍)

  // Reading the APMC Status register to detect when the oscillator is stabilized
  while ((__APMC_SR & APMC_MOSCS) != APMC_MOSCS) ;

  // Commuting from Slow Clock to Main Oscillator (16Mhz)
  __APMC_CGMR = 0x002F4002; // MOSCEN = 1, OSCOUNT = 47  (1.4ms/30祍)

  // Setup the PLL to 32 MHz clock
  __APMC_CGMR = 0x032F4102; // MUL = 1, PLLCOUNT = 3, CSS = 1

  // Reading the APMC Status register to detect when the PLL is stabilized
  // Wait a little extra to ensure stable PLL.
  for (i = 0; i < 1000; i++)
  {
    while ((__APMC_SR & APMC_PLL_LOCK) != APMC_PLL_LOCK) ;
  }

  // Commuting from 16Mhz to PLL @ 32MHz
  __APMC_CGMR = 0x032F8102; // CSS = 2, MUL = 1
  
  // Now the Master clock is the output of PLL @ 32MHz
}
#endif

void AT91EnablePeripheralClocks()
{
#if AT91_EB40 || AT91_EB40A
  // Switch on clocks to all peripherals.
  __PS_PCER = 0x00017c;
#else
  // Switch on clocks to all peripherals.
  __APMC_PCER = 0x0007effc;
#endif
}


//
// Interrupt handlers.
//

 /* Timer interrupt handler */
__irq __arm void heartbeat_irq(void)
{
  // Called at 1000 Hz rate.
  __AIC_IVR = 0; // Debug variant of vector read, protected mode is used.
  
  (*timer_function)(); // Call timer callback function.
    
  __TC_SRC0; // Read timer/counter 0 status register.
  __AIC_EOICR = 0; // Signal end of interrupt to AIC.
}


/* Serial port RX interrupt handler */
__irq __arm void usart0_rxrdy_interrupt(void)
{
  __AIC_IVR = 0; // Debug variant of vector read, protected mode is used.

  (*rxrdy_function)(); // Call RX callback function.
      
  __AIC_EOICR = 0; // Signal end of interrupt to AIC.
}


/* Undefined interrupt handler */
__irq __arm void undefined_irq(void)
{
  __AIC_IVR = 0; // Debug variant of vector read, protected mode is used.

  // Do nothing.

  __AIC_EOICR = 0; // Signal end of interrupt to AIC.
}


//
// Interrupt functions.
//

void AT91InitInterrupt(void(*timer_func)(), void(*rxrdy_func)())
{
#if !ANGEL
  int      irq_id ;
#endif // ANGEL

  timer_function = timer_func;
  rxrdy_function = rxrdy_func;
  
#if !ANGEL
  // Disable all interrupts.
  __AIC_IDCR = 0xFFFFFFFF;
  // Clear all interrupts.
  __AIC_ICCR = 0xFFFFFFFF;

  // For each priority level.
  for (irq_id = 0; irq_id < 8; irq_id++)
  {
    // Unstack a level by writting in AIC_EOICR.
    // Value written has no effect.
    __AIC_EOICR = 0;
  }

  {
    // For each interrupt source.
    __REG32 volatile* aic_smr_base = &__AIC_SMR0;
    __REG32 volatile* aic_svr_base = &__AIC_SVR0;
    for (irq_id = 0; irq_id < 32; irq_id++)
    {
      // Priority is lowest.
      aic_smr_base[irq_id] = 0 ;
      // Interrupt routine is undefined.
      aic_svr_base[irq_id] = (unsigned long)&undefined_irq;
    }
  }
  
  __AIC_SPU = (unsigned long)&undefined_irq; // Spurious interrupt vector.
  __SF_PMR = 0x27a80020; // Run AIC in protected mode.
  // Initialize ARM IRQ vector to map to interrupt controller.
  *(unsigned long *)0x18 = 0xe51fff20; // ldr pc,[pc,#-0xf20]
#endif // ANGEL

#if ANGEL
  // The Angel ROM monitor code is written to allow AIC
  // protected mode. That means that from tis point it is
  // safe to look at the AIC registers from the memory and
  // register windows. Take care not to start up C-SPY with
  // AIC display active since the ROM monitor itself does not
  // Enable protected mode.
  __SF_PMR = 0x27a80020; // Run AIC in protected mode.
#endif // ANGEL
}


//
// Timer functions.
//

void AT91InitTimer()
{
  __TC_IDRC0 = 0xff; // Disable all timer/counter 0 interrupts.
#if AT91_EB40 || AT91_EB40A
  __AIC_SVR4 = (unsigned long)&heartbeat_irq;
  __AIC_SMR4 = 0x26;
#else
  __AIC_SVR6 = (unsigned long)&heartbeat_irq; // Timer/counter 0 interrupt vector.
  __AIC_SMR6 = 0x26; // SRCTYPE=1, PRIOR=6. Timer/counter 0 interrupt edge-triggered at prio 6.
#endif
  __AIC_ICCR_bit.tc0irq = 1; // Clears timer/counter 0 interrupt.
  __AIC_IECR_bit.tc0irq = 1; // Enable timer/counter 0 interrupt.
  
  __TC_CMRC0 = 0x00004002; // Capture mode, CPCTRG=1, TCCLKS=2 (/32).
  __TC_RCC0 = AT91_MCK / 32 / 1000; // Set RC (compare register), 1 ms interval.
  __TC_CCRC0 = 1; // Enable the clock.
  __TC_CCRC0 = 5; // Software trigger.
  __TC_CCRC0 = 1; // Clear trigger.
}

void AT91StartTimer()
{
#if AT91_EB40 || AT91_EB40A
  __AIC_ICCR = 0x10; // Clears timer/counter 0 interrupt.
#else
  __AIC_ICCR = 0x40; // Clears timer/counter 0 interrupt.
#endif
  __TC_SRC0; // Read timer/counter 0 status register to clear flags.
  __TC_IERC0_bit.cpcs = 1; // Interrupt on RC compare.
}


//
// Serial communication functions.
//

void AT91UartInit()
{
// Don't use the serial port when run in Angel mode.
#if !ANGEL
#if AT91_EB40 || AT91_EB40A
  __PIO_PDR = 0x000c000; // Disable PIO control of P14/TXD and P15/RXD.
#endif
#if AT91_EB42
  __PIO_PDR = 0x000000c0; // Disable PIO control of PA6/TXD0 and PA7/RXD0.
#endif
#if AT91_EB55 || AT91_EB63
  __PIO_PDR = 0x00018000; // Disable PIO control of PA15/TXD0 and PA16/RXD0.
#endif

  __US_MR = 0x000008c0; // Normal mode, 1 stop bit, no parity, async mode, 8 bits, MCK.
  __US_IDR = 0xffffffff; // Disable all USART interrupts.
  __US_IER = 1; // Interrupt on RXRDY.
  __US_TTGR = 5; // Transmit time guard in number of bit periods.
  __US_BRGR = AT91_MCK / BAUD_RATE / 16; // Set baud rate.

  __AIC_SVR2 = (unsigned long)&usart0_rxrdy_interrupt; // Usart 0 interrupt vector.
  __AIC_SMR2 = 0x63; // SRCTYPE=1, PRIOR=3. USART 0 interrupt positive edge-triggered at prio 3.
  __AIC_ICCR_bit.us0irq = 1; // Clears timer/counter 0 interrupt.
  __AIC_IECR_bit.us0irq = 1; // Enable timer/counter 0 interrupt.
  
  __AIC_ICCR = 1 << US0IRQ; // Clears usart 0 interrupt.

  __US_CR = 0x000000a0; // Disable receiver, disable transmitter.
  __US_CR = 0x0000010c; // Reset status bits, reset rx/tx.
  __US_CR = 0x00000050; // Enable receiver, enable transmitter.
#endif // ANGEL
}


int AT91UartGetchar()
{
// Don't use the serial port when run in Angel mode.
#if ANGEL
  return '?';
#else
  return __US_RHR;
#endif // ANGEL
}


void AT91UartPutchar(int ch)
{
// Don't use the serial port when run in Angel mode.
#if !ANGEL
  unsigned char status;

  do {
    status = __US_CSR;
  } while ((status & 0x02) == 0); // Wait for TXRDY

  __US_THR = ch;
#endif // ANGEL
}


//
// Parallel I/O functions.
//

unsigned int AT91GetButtons()
{
  unsigned long pa; // Port A value.
  unsigned long pb; // Port B value.
  unsigned int sw1; // SW1 button.
  unsigned int sw2; // SW2 button.
  unsigned int sw3; // SW3 button.
  unsigned int sw4; // SW4 button.
  unsigned int mask; // Bit mask of buttons.

#if AT91_EB40
  // SW3 - P12, SW4 - P5, SW6 - P9
  pa = pb = ~__PIO_PDSRB; // Switch on P5, P9, P12
  sw2 = !!(pb & 0x00000020); // p5
  sw3 = !!(pb & 0x00000200); // p9
  sw1 = !!(pa & 0x00001000); // p12
  sw4 = 1;
#endif

#if AT91_EB40A
  // SW1 - P12, SW2 - P9, SW3 - P1, SW4 - P2
  pa = pb = ~__PIO_PDSRB; // Switch on P5, P9, P12
  sw3 = !!(pa & 0x00000002); // p1
  sw4 = !!(pb & 0x00000004); // p2
  sw2 = !!(pb & 0x00000200); // p9
  sw1 = !!(pa & 0x00001000); // p12
#endif

#if AT91_EB42
  // As seen from card edge: SW4 - PB21, SW3 - PB6, SW2 - PA0, SW1 - PB7
  pa = ~__PIO_PDSR; // Switch on PA0
  pb = ~__PIO_PDSRB; // Switch on PB6, PB7, PB21
  sw2  = !!(pa & 0x00000001); // pa0
  sw3 = !!(pb & 0x00000040); // pb6
  sw1 = !!(pb & 0x00000080); // pb7
  sw4 = !!(pb & 0x00200000); // pb21
#endif

#if AT91_EB55
  // As seen from card edge: SW4 - PB19, SW3 - PB17, SW2 - PA9, SW1 - PB20
  pa = ~__PIO_PDSR; // Switch on PA9
  pb = ~__PIO_PDSRB; // Switch on PB17, PB19, PB20
  sw2  = !!(pa & 0x00000200); // pa9
  sw3 = !!(pb & 0x00020000); // pb17
  sw4 = !!(pb & 0x00080000); // pb19
  sw1 = !!(pb & 0x00100000); // pb20
#endif

#if AT91_EB63
  // As seen from card edge: SW4 - PA9, SW3 - PB5, SW2 - PB4, SW1 - PB3
  pa = ~__PIO_PDSR; // Switch on PA9
  pb = ~__PIO_PDSRB; // Switch on PB3, PB4, PB5
  sw4 = !!(pa & 0x00000200); // pa9
  sw1 = !!(pb & 0x00000008); // pb3
  sw2 = !!(pb & 0x00000010); // pb4
  sw3 = !!(pb & 0x00000020); // pb5
#endif

  mask = (sw1 << 3) | (sw2 << 2) | (sw3 << 1) | sw4;

  return mask;
}


void AT91InitPIO()
{
#if ANGEL
// In Angel mode the serial port is already initialized and
// used by the Angel monitor.

  // Initialize port B.
#if AT91_EB40
  __PIO_PERB = 0x1236; // enable register
  __PIO_PDRB = 0x0000; // disable register
  __PIO_OERB = 0x0016; // output enable
  __PIO_ODRB = 0x1220; // output disable
  __PIO_SODRB = 0x0016; // LED's off
  __PIO_IDRB = 0x1220;
#elif AT91_EB40A
  __PIO_PERB = 0xf127e; // enable register
  __PIO_PDRB = 0x00000; // disable register
  __PIO_OERB = 0xf0078; // output enable
  __PIO_ODRB = 0x01206; // output disable
  __PIO_SODRB = 0xf0078; // LED's off
  __PIO_IDRB = 0x1206;
#else
  __PIO_PERB = 0xff00; // enable register
  __PIO_OERB = 0xff00; // output enable
  __PIO_SODRB = 0xff00; // LED's off
#endif

#else // ANGEL

  // Initialize port A.
#if AT91_EB42
  __PIO_PER = 0x0040; // enable register (uart TX bit)
  __PIO_OER = 0x0040; // output enable (uart TX bit)
  __PIO_SODR = 0x0040; // inactive TX line
#endif

#if AT91_EB55 || AT91_EB63
  __PIO_PER = 0x8000; // enable register (uart TX bit)
  __PIO_OER = 0x8000; // output enable (uart TX bit)
  __PIO_SODR = 0x8000; // inactive TX line
#endif

  // Initialize port B.
#if AT91_EB40
  __PIO_PERB = 0x5236; // enable register
  __PIO_PDRB = 0x8000; // disable register
  __PIO_OERB = 0x4016; // output enable
  __PIO_ODRB = 0x1220; // output disable
  __PIO_SODRB = 0x4016; // LED's off
  __PIO_IDRB = 0x1220;
#elif AT91_EB40A
  __PIO_PERB = 0xf527e; // enable register
  __PIO_PDRB = 0x08000; // disable register
  __PIO_OERB = 0xf4078; // output enable
  __PIO_ODRB = 0x01206; // output disable
  __PIO_SODRB = 0xf4078; // LED's off
  __PIO_IDRB = 0x1206;
#else
  __PIO_PERB = 0xff00; // enable register
  __PIO_OERB = 0xff00; // output enable
  __PIO_SODRB = 0xff00; // LED's off
#endif

#endif // ANGEL
}


//
// LED output drivers.
//

static void led_on(unsigned int mask)
{
#if AT91_EB40
  __PIO_CODRB = mask & 0x16;
#elif AT91_EB40A
  __PIO_CODRB = (mask & 0x0f) << 16 | (mask & 0xf0) >> 1;
#else
  __PIO_CODRB = mask << 8;
#endif
}

static void led_off(unsigned int mask)
{
#if AT91_EB40
  __PIO_SODRB = mask & 0x16;
#elif AT91_EB40A
  __PIO_SODRB = (mask & 0x0f) << 16 | (mask & 0xf0) >> 1;
#else
  __PIO_SODRB = mask << 8;
#endif
}

void AT91LedSet(unsigned int mask)
{
  led_off(0xff); // Switch off all LED's.
  led_on(mask);  // Switch on selected LED's.
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -