/* ***************************************************************************** */ /* */ /* Purpose: Set up the 16-bit Timer/Counter */ /* */ /* We will use Timer Channel 0 to develop a 1 msec interrupt. */ /* */ /* The AT91SAM7S-EK board has a 18,432,000 hz crystal oscillator. */ /* */ /* MAINCK = 18432000 hz */ /* PLLCK = (MAINCK / DIV) * (MUL + 1) = 18432000/14 * (72 + 1) */ /* PLLCLK = 1316571 * 73 = 96109683 hz */ /* */ /* MCK = PLLCLK / 2 = 96109683 / 2 = 48054841 hz */ /* */ /* TIMER_CLOCK5 = MCK / 1024 = 48054841 / 1024 = 46928 hz */ /* */ /* TIMER_CLOCK5 Period = 1 / 46928 = 21.309239686 microseconds */ /* */ /* A little algebra: .001 sec = count * 21.3092396896*10**-6 */ /* count = .001 / 21.3092396896*10**-6 */ /* count = 46.928 */ /* */ /* */ /* Therefore: set Timer Channel 0 register RC to 46*milliseconds */ /* turn on capture mode WAVE = 0 */ /* enable the clock CLKEN = 1 */ /* select TIMER_CLOCK5 TCCLKS = 100 */ /* clock is NOT inverted CLKI = 0 */ /* enable RC compare CPCTRG = 1 */ /* enable RC compare interrupt CPCS = 1 */ /* disable all the other timer 0 interrupts */ /* */ /* Author: James P Lynch May 12, 2007 */ /* Modified by Steve Karg */ /* Changed timer to 1ms. */ /* Encapsulated the intialization */ /* ***************************************************************************** */ /********************************************************** Header files **********************************************************/ #include #include "board.h" #include "bacnet/datalink/dlmstp.h" #include "timer.h" /* global variable counts interrupts */ volatile unsigned long Timer_Milliseconds; /* MS/TP Silence Timer */ static volatile int SilenceTime; static void Timer0_Setup( int milliseconds) { /* TC Block Control Register TC_BCR (read/write) */ /* */ /* |------------------------------------------------------------------|------| */ /* | SYNC | */ /* |------------------------------------------------------------------|------| */ /* 31 1 0 */ /* */ /* SYNC = 0 (no effect) <===== take default */ /* SYNC = 1 (generate software trigger for all 3 timer channels simultaneously) */ /* */ /* create a pointer to TC Global Register structure */ AT91PS_TCB pTCB = AT91C_BASE_TCB; /* SYNC trigger not used */ pTCB->TCB_BCR = 0; /* TC Block Mode Register TC_BMR (read/write) */ /* */ /* |-------------------------------------|-----------|-----------|-----------| */ /* | TC2XC2S TCXC1S TC0XC0S | */ /* |-------------------------------------|-----------|-----------|-----------| */ /* 31 5 4 3 2 1 0 */ /* */ /* TC0XC0S Select = 00 TCLK0 (PA4) */ /* = 01 none <===== we select this one */ /* = 10 TIOA1 (PA15) */ /* = 11 TIOA2 (PA26) */ /* */ /* TCXC1S Select = 00 TCLK1 (PA28) */ /* = 01 none <===== we select this one */ /* = 10 TIOA0 (PA15) */ /* = 11 TIOA2 (PA26) */ /* */ /* TC2XC2S Select = 00 TCLK2 (PA29) */ /* = 01 none <===== we select this one */ /* = 10 TIOA0 (PA00) */ /* = 11 TIOA1 (PA26) */ /* */ /* external clocks not used */ pTCB->TCB_BMR = 0x15; /* TC Channel Control Register TC_CCR (read/write) */ /* */ /* |----------------------------------|--------------|------------|-----------| */ /* | SWTRG CLKDIS CLKENS | */ /* |----------------------------------|--------------|------------|-----------| */ /* 31 2 1 0 */ /* */ /* CLKEN = 0 no effect */ /* CLKEN = 1 enables the clock <===== we select this one */ /* */ /* CLKDIS = 0 no effect <===== take default */ /* CLKDIS = 1 disables the clock */ /* */ /* SWTRG = 0 no effect */ /* SWTRG = 1 software trigger aserted counter reset and clock starts <===== we select this one */ /* */ /* create a pointer to channel 0 Register structure */ AT91PS_TC pTC = AT91C_BASE_TC0; /* enable the clock and start it */ pTC->TC_CCR = 0x5; /* TC Channel Mode Register TC_CMR (read/write) */ /* */ /* |-----------------------------------|------------|---------------| */ /* | LDRB LDRA | */ /* |-----------------------------------|------------|---------------| */ /* 31 19 18 17 16 */ /* */ /* |----------|---------|--------------|------------|---------------| */ /* |WAVE = 0 CPCTRG ABETRG ETRGEDG | */ /* |----------|---------|--------------|------------|---------------| */ /* 15 14 13 11 10 9 8 */ /* */ /* |----------|---------|--------------|------------|---------------| */ /* | LDBDIS LDBSTOP BURST CLKI TCCLKS | */ /* |----------|---------|--------------|------------|---------------| */ /* 7 6 5 4 3 2 0 */ /* */ /* CLOCK SELECTION */ /* TCCLKS = 000 TIMER_CLOCK1 (MCK/2 = 24027420 hz) */ /* 001 TIMER_CLOCK2 (MCK/8 = 6006855 hz) */ /* 010 TIMER_CLOCK3 (MCK/32 = 1501713 hz) */ /* 011 TIMER_CLOCK4 (MCK/128 = 375428 hz) */ /* 100 TIMER_CLOCK5 (MCK/1024 = 46928 hz) <===== we select this one */ /* 101 XC0 */ /* 101 XC1 */ /* 101 XC2 */ /* */ /* CLOCK INVERT */ /* CLKI = 0 counter incremented on rising clock edge <===== we select this one */ /* CLKI = 1 counter incremented on falling clock edge */ /* */ /* BURST SIGNAL SELECTION */ /* BURST = 00 clock is not gated by any external system <===== take default */ /* 01 XC0 is anded with the clock */ /* 10 XC1 is anded with the clock */ /* 11 XC2 is anded with the clock */ /* */ /* COUNTER CLOCK STOPPED WITH RB LOADING */ /* LDBSTOP = 0 counter clock is not stopped when RB loading occurs <===== take default */ /* = 1 counter clock is stopped when RB loading occur */ /* */ /* COUNTER CLOCK DISABLE WITH RB LOADING */ /* LDBDIS = 0 counter clock is not disabled when RB loading occurs <===== take default */ /* = 1 counter clock is disabled when RB loading occurs */ /* */ /* EXTERNAL TRIGGER EDGE SELECTION */ /* ETRGEDG = 00 (none) <===== take default */ /* 01 (rising edge) */ /* 10 (falling edge) */ /* 11 (each edge) */ /* */ /* TIOA OR TIOB EXTERNAL TRIGGER SELECTION */ /* ABETRG = 0 (TIOA is used) <===== take default */ /* 1 (TIOB is used) */ /* */ /* RC COMPARE TRIGGER ENABLE */ /* CPCTRG = 0 (RC Compare has no effect on the counter and its clock) */ /* 1 (RC Compare resets the counter and starts the clock) <===== we select this one */ /* */ /* WAVE */ /* WAVE = 0 Capture Mode is enabled <===== we select this one */ /* 1 Waveform Mode is enabled */ /* */ /* RA LOADING SELECTION */ /* LDRA = 00 none) <===== take default */ /* 01 (rising edge of TIOA) */ /* 10 (falling edge of TIOA) */ /* 11 (each edge of TIOA) */ /* */ /* RB LOADING SELECTION */ /* LDRB = 00 (none) <===== take default */ /* 01 (rising edge of TIOA) */ /* 10 (falling edge of TIOA) */ /* 11 (each edge of TIOA) */ /* */ /* TCCLKS = 1 (TIMER_CLOCK5) */ /* CPCTRG = 1 (RC Compare resets the counter and restarts the clock) */ /* WAVE = 0 (Capture mode enabled) */ pTC->TC_CMR = 0x4004; /* TC Register C TC_RC (read/write) Compare Register 16-bits */ /* */ /* |----------------------------------|----------------------------------------| */ /* | not used RC | */ /* |----------------------------------|----------------------------------------| */ /* 31 16 15 0 */ /* */ /* Timer Calculation: What count gives 1 msec time-out? */ /* */ /* TIMER_CLOCK5 = MCK / 1024 = 48054841 / 1024 = 46928 hz */ /* */ /* TIMER_CLOCK5 Period = 1 / 46928 = 21.309239686 microseconds */ /* */ /* A little algebra: .001 sec = count * 21.3092396896*10**-6 */ /* count = .001 / 21.3092396896*10**-6 */ /* count = 46.928 */ /* */ /* STK: Even Simpler, let the compiler do the work: */ /* */ /* TIMER_CLOCK5 = (MCK / 1024) / 1000 */ /* = 48054841 / 1024 / 1000 = 46.928 */ pTC->TC_RC = ((MCK / 1024 / 1000) + 1) * milliseconds; /* TC Interrupt Enable Register TC_IER (write-only) */ /* */ /* */ /* |------------|-------|-------|-------|-------|--------|--------|--------|--------| */ /* | ETRGS LDRBS LDRAS CPCS CPBS CPAS LOVRS COVFS | */ /* |------------|-------|-------|-------|-------|--------|--------|--------|--------| */ /* 31 8 7 6 5 4 3 2 1 0 */ /* */ /* COVFS = 0 no effect <===== take default */ /* 1 enable counter overflow interrupt */ /* */ /* LOVRS = 0 no effect <===== take default */ /* 1 enable load overrun interrupt */ /* */ /* CPAS = 0 no effect <===== take default */ /* 1 enable RA compare interrupt */ /* */ /* CPBS = 0 no effect <===== take default */ /* 1 enable RB compare interrupt */ /* */ /* CPCS = 0 no effect */ /* 1 enable RC compare interrupt <===== we select this one */ /* */ /* LDRAS = 0 no effect <===== take default */ /* 1 enable RA load interrupt */ /* */ /* LDRBS = 0 no effect <===== take default */ /* 1 enable RB load interrupt */ /* */ /* ETRGS = 0 no effect <===== take default */ /* 1 enable External Trigger interrupt */ /* */ /* enable RC compare interrupt */ pTC->TC_IER = 0x10; /* TC Interrupt Disable Register TC_IDR (write-only) */ /* */ /* */ /* |------------|-------|-------|-------|-------|--------|--------|--------|--------| */ /* | ETRGS LDRBS LDRAS CPCS CPBS CPAS LOVRS COVFS | */ /* |------------|-------|-------|-------|-------|--------|--------|--------|--------| */ /* 31 8 7 6 5 4 3 2 1 0 */ /* */ /* COVFS = 0 no effect */ /* 1 disable counter overflow interrupt <===== we select this one */ /* */ /* LOVRS = 0 no effect */ /* 1 disable load overrun interrupt <===== we select this one */ /* */ /* CPAS = 0 no effect */ /* 1 disable RA compare interrupt <===== we select this one */ /* */ /* CPBS = 0 no effect */ /* 1 disable RB compare interrupt <===== we select this one */ /* */ /* CPCS = 0 no effect <===== take default */ /* 1 disable RC compare interrupt */ /* */ /* LDRAS = 0 no effect */ /* 1 disable RA load interrupt <===== we select this one */ /* */ /* LDRBS = 0 no effect */ /* 1 disable RB load interrupt <===== we select this one */ /* */ /* ETRGS = 0 no effect */ /* 1 disable External Trigger interrupt <===== we select this one */ /* */ /* disable all except RC compare interrupt */ pTC->TC_IDR = 0xEF; } /* ***************************************************************************** */ /* */ /* Timer 0 Interrupt Service Routine */ /* */ /* Entered when Timer0 RC compare interrupt asserts */ /* */ /* Author: James P Lynch May 12, 2007 */ /* Modified by Steve Karg */ /* simplified and changed to a millisecond count-up timer */ /* ***************************************************************************** */ static void Timer0IrqHandler( void) { volatile AT91PS_TC pTC = AT91C_BASE_TC0; /* pointer to timer channel 0 register structure */ volatile unsigned int dummy; /* temporary */ /* read TC0 Status Register to clear interrupt */ dummy = pTC->TC_SR; /* increment the tick count */ Timer_Milliseconds++; if (SilenceTime < 60000) { SilenceTime++; } (void)dummy; } int Timer_Silence( void) { return SilenceTime; } void Timer_Silence_Reset( void) { SilenceTime = 0; } /* ***************************************************************************** */ /* */ /* Timer 0 Initialization */ /* */ /* From James P Lynch main.c example code */ /* Modified by Steve Karg */ /* Moved timer startup code from main */ /* modified the peripheral clock init */ /* ***************************************************************************** */ void TimerInit( void) { unsigned int pcsr; /* enable the Timer0 peripheral clock */ volatile AT91PS_PMC pPMC = AT91C_BASE_PMC; pcsr = pPMC->PMC_PCSR; pPMC->PMC_PCER = pcsr | (1 << AT91C_ID_TC0); /* Set up the AIC registers for Timer 0 */ volatile AT91PS_AIC pAIC = AT91C_BASE_AIC; /* Disable timer 0 interrupt */ /* in AIC Interrupt Disable Command Register */ pAIC->AIC_IDCR = (1 << AT91C_ID_TC0); /* Set the TC0 IRQ handler address in */ /* AIC Source Vector Register[12] */ pAIC->AIC_SVR[AT91C_ID_TC0] = (unsigned int) Timer0IrqHandler; /* Set the interrupt source type and priority */ /* in AIC Source Mode Register[12] */ pAIC->AIC_SMR[AT91C_ID_TC0] = (AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE | 0x4); /* Clear the TC0 interrupt */ /* in AIC Interrupt Clear Command Register */ pAIC->AIC_ICCR = (1 << AT91C_ID_TC0); /* Remove disable timer 0 interrupt */ /* in AIC Interrupt Disable Command Reg */ pAIC->AIC_IDCR = (0 << AT91C_ID_TC0); /* Enable the TC0 interrupt */ /* in AIC Interrupt Enable Command Register */ pAIC->AIC_IECR = (1 << AT91C_ID_TC0); /* Setup timer0 to generate a 1 msec periodic interrupt */ Timer0_Setup(1); }