AnsweredAssumed Answered

BF506F GENERAL PURPOSE TIMER INTERRUPT

Question asked by odemirci on Nov 9, 2011

Hello,


I am using EZ-KIT for BF506F. I have VisualDSP++5.0 Update 9.1. I made external hardware (32768Hz Clock) connection to the TIMER2 (TMR2) pin. When timer (TIMER_COUNTER) reaches TIMER_PERIOD=0x00028000 then it generates an interrupt. I jump to the interrupt service routine. Once the first TIMER_COUNTER=TIMER_PERIOD occurs then normally I get my first interrupt. But after that it keeps generates interrupt without checking the TIMER_COUNTER=TIMER_PERIOD condition.

 

I did read the hardware reference manual but I still could not resolve the problem. I am enclosing my small sample software. It generates core timer interrupt and TIMER2 interrupt.

 

Could you please help me?

 

Thank you,

 

Osman Demirci

TEP Electric
Istanbul Yolu 29.km
Saray Mahallesi
Kazan Ankara 06980
TURKEY

 

CODE

/*****************************************************************************
* myfirst.asm
*****************************************************************************/

#include <defBF506F.h>
#include <defBF50x_base.h>

/* Mark the beginning of a logical section mirroring an array of contiguous
   locations in processor memory. Statements between one '.SECTION' and the
   following '.SECTION' directive comprise the contents of a section. Here,
   we place the global symbol '_main' and the associated code into the
   'program' section.*/
.SECTION program;

/* The .ALIGN directive forces the address alignment of an instruction or
   data item. Here, ensure the first element of the section is aligned.*/
.ALIGN 4;

/* Set the scope of the '_main' symbol to global. This makes the symbol
   available for reference in object files that are linked to the current
   one. Use '.EXTERN' to refer to a global symbol from another file.*/
.GLOBAL _main;

/* Declare the '_main' symbol. */
_main:

// START: SET BF506F PINs 
  P0.L=LO(PORTF_FER); // 0xFFC0 3200: Port F Function Enable Register
  P0.H=HI(PORTF_FER); // 0:GPIO mode,1:Enable peripheral function
  R0.L=0x0400;        // pin10 is enabled for peripheral function (TIMER2)
  W[P0]=R0.L;

  P0.L=LO(PORTF_MUX); // 00= 1st peripheral function
  P0.H=HI(PORTF_MUX); // 01= 1st alternate peripheral function
  R0.L=0x0400;        // 10= 2nd alternate peripheral function
  W[P0]=R0.L;         // set bit11&10=01 for TMR2
 
  P0.L=LO(PORTFIO_DIR);  // 0xFFC0 0730:GPIO Direction Registers
  P0.H=HI(PORTFIO_DIR);  // 0:input, 1:output
  R0.L=0x0007;           // PF0=LED2,PF1=LED3,PF2=LED4 is outputs
  W[P0]=R0.L;            // PF3=PB0, PF4=PB1 and rest are inputs

  P0.L=LO(PORTFIO_INEN); // 0xFFC0 0740:GPIO Input Enable Registers
  P0.H=HI(PORTFIO_INEN); // 0:Input Buffer Disabled, 1:Input Buffer Enabled
  R0.L=0x0418;           // PF3 and PF4 are buffered inputs
  W[P0]=R0.L;            // PF3==PB0 and PF4=PB1
                         // Enable PF10=32768Hz Clock for TIMER2  
 
  // set port f polarity register
  P0.L = LO(PORTFIO_POLAR); // 0xFFC0 0734
  P0.H = HI(PORTFIO_POLAR);
  R0.H = 0x00000;    // 0:rising edge
  //R0.L = 0x00018;  // 1:falling edge
  W[P0] = R0.L;
// END: SET BF506F PINs  

 

 

// START: Timer2 setup and interrupt
// Select Modes of Operation: External Event Counter
P0.L = LO(TIMER2_CONFIG);   // 0xFFC0 0620
P0.H = HI(TIMER2_CONFIG);
R0.L = 0x001F;   // Set Bit1&2=1 yani enable External Event Counter
W[P0] = R0.L;    // Set bit4=1 to enable IRQ_ENA

// Set TIMER2_PERIOD
P0.L = LO(TIMER2_PERIOD);   // 0xFFC0 0628
P0.H = HI(TIMER2_PERIOD);
R0.L = 0x8000;   // TIMER2_COUNTER=TIMER2_PERIOD(1,000,000) then generate intr.
R0.H = 0x0002;  
[P0] = R0;

// Enable TIMER2 counting
P0.L = LO(TIMER_ENABLE);  
P0.H = HI(TIMER_ENABLE);
R0.L = 0x0004;   // TIMER2_ENABLE bit3=1
W[P0] = R0.L;

// Enable TIMER2 interrupt. Set bit2=1
P0.L = LO(SIC_IMASK1);
P0.H = HI(SIC_IMASK1);
R0.L = 0x0004;  
R0.H = 0x0000; 
[P0] = R0;

// Set SIC_IAR4[11..8] Group equal 0 for IVG8(EVT8) priority
P0.L = LO(SIC_IAR4);
P0.H = HI(SIC_IAR4);
R0.L = 0x0100;  
R0.H = 0x0000;
[P0] = R0;

// initiate TIMER2 Interrupt and what to do next
P1.L = LO(IMASK);  // IMASK 0xFFE0 2104: Interrupt Controller
P1.H = HI(IMASK);
R0.L = LO(timer2_isr);
R0.H = HI(timer2_isr);
[P1 + EVT8 - IMASK] = R0;  // [p1 + 0xFFE0 2020 - 0xFFE0 2104]
R0 = [P1];
BITSET(R0, 8); // Enable IVG8 priority interrupt
[P1] = R0;
// END: Timer2 setup and interrupt

 

// START: CORE TIMER INTERRUPT SETUP  
// Register service routine at EVT6 and unmask interrupt
P1.L = LO(IMASK);  // IMASK: Interrupt Controller
P1.H = HI(IMASK);
R0.L = LO(core_timer_isr);
R0.H = HI(core_timer_isr);
[P1 + EVT6 - IMASK] = R0;  // EVT6: Event Vector Register 0xFFA0 0182
R0 = [P1];
BITSET(R0, bitpos(EVT_IVTMR));
[P1] = R0;
// TIMER SETUP
// Prescaler = 50, Period = 10,000,000, First Period = 20,000,000
P1.L = LO(TCNTL); // 0xFFE0 3000: Core Timer Control Register
P1.H = HI(TCNTL);
R0 = 50 (z);
[P1 + TSCALE - TCNTL] = R0;
R0.L = LO(1000000);
R0.H = HI(1000000);
[P1 + TPERIOD - TCNTL] = R0;
R0 <<= 1;
[P1 + TCOUNT - TCNTL] = R0;
// start in auto-reload mode
R0 = TAUTORLD | TMPWR | TMREN (z);
[P1] = R0;
// END: CORE TIMER INTERRUPT SETUP


  r3=0;
  r5=0;
  r6=0;
  r7=0;

_main.forever:

//P0.L = LO(PORTFIO_MASKA);  // 0xFFC0 0710
//P0.H = HI(PORTFIO_MASKA);
//R0 = [P0];
//CC = BITTST(R0,3); // test if bit7=1 in R0
//IF CC JUMP exit1;
  // Delay
//  P1.L = 8000;
//  P1.H=0;
//  LSETUP(start, end) LC0 = P1 ;
//  start:
//  nop;
//  end:

jump _main.forever;
_main.end:

 

// START: CORE TIMER INTERRUPT SERVICE ROUTINE
core_timer_isr:
R5+= 1;
 
  P0.L=LO(PORTFIO_TOGGLE); // 0xFFC0 070C
  P0.H=HI(PORTFIO_TOGGLE);
  R0.L=0x0004;       // W-1-to-toggle: LED2=0x0001, LED3=0x0002, LED4=0x0004
  W[P0]=R0.L;

ssync; // sync system
RTI;                   /* return from interrupt */
core_timer_isr.end: 
// END: CORE TIMER INTERRUPT SERVICE ROUTINE

 

 

 

// START: TIMER2 INTERRUPT SERVICE ROUTINE
timer2_isr:
[--sp] = astat;
[--sp] = (r7:7, p5:5); /* push used registers */

// clear interrupt request first
P5.L = LO(TIMER_STATUS);
P5.H = HI(TIMER_STATUS);
R7.L = HI(TIMIL2); 
R7.H = LO(TIMIL2); 
[P5] = R7;

/* place user code here */
  R3+=1;
  P0.L=LO(PORTFIO_TOGGLE); // 0xFFC0 070C
  P0.H=HI(PORTFIO_TOGGLE);
  R0.L=0x0001;       // W-1-to-toggle: LED2=0x0001, LED3=0x0002, LED4=0x0004
  W[P0]=R0.L;
 
 
ssync; /* sync system, pop registers and exit */
(r7:7, p5:5) = [sp++];
astat = [sp++];
rti;
timer2_isr.end:
// END: TIMER2 INTERRUPT SERVICE ROUTINE

 

 

 

 


HARDWARE REFERENCE MANUAL
Clearing Interrupt Requests
When the processor services a core event, it automatically clears the
requesting bit in the ILAT register and no further action is required by the
interrupt service routine. It is important to understand that the SIC controller
does not provide any interrupt acknowledgment feedback
mechanism from the CEC controller back to the peripherals. Although
the ILAT bits clear in the same way when a peripheral interrupt is serviced,
the signalling peripheral does not release its level-sensitive request until it
is explicitly instructed by software to do so. If the request is not cleared by
software, the peripheral keeps requesting the interrupt, and the respective
ILAT bit is immediately set again. This causes the processor to vector to
the service routine again as soon as the RTI instruction is executed.
Every software routine that services peripheral interrupts must clear the
signalling interrupt request in the respective peripheral. The individual
peripherals provide customized mechanisms for how to clear interrupt
requests. Receive interrupts, for example, are cleared when received data is
read from the respective buffers. Transmit requests typically clear when
software (or DMA) writes new data into the transmit buffers. These
implicit acknowledge mechanisms avoid the need for cycle-consuming
software handshakes in streaming interfaces. Other peripherals such as
timers, GPIOs, and error requests require explicit acknowledge instructions,
which are typically performed by efficient W1C (write-1-to-clear)
operations.Clearing Interrupt Requests
When the processor services a core event, it automatically clears the
requesting bit in the ILAT register and no further action is required by the
interrupt service routine. It is important to understand that the SIC controller
does not provide any interrupt acknowledgment feedback
mechanism from the CEC controller back to the peripherals. Although
the ILAT bits clear in the same way when a peripheral interrupt is serviced,
the signalling peripheral does not release its level-sensitive request until it
is explicitly instructed by software to do so. If the request is not cleared by
software, the peripheral keeps requesting the interrupt, and the respective
ILAT bit is immediately set again. This causes the processor to vector to
the service routine again as soon as the RTI instruction is executed.
Every software routine that services peripheral interrupts must clear the
signalling interrupt request in the respective peripheral. The individual
peripherals provide customized mechanisms for how to clear interrupt
requests. Receive interrupts, for example, are cleared when received data is
read from the respective buffers. Transmit requests typically clear when
software (or DMA) writes new data into the transmit buffers. These
implicit acknowledge mechanisms avoid the need for cycle-consuming
software handshakes in streaming interfaces. Other peripherals such as
timers, GPIOs, and error requests require explicit acknowledge instructions,
which are typically performed by efficient W1C (write-1-to-clear)
operations.

Outcomes