This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

C672x Interrupts

I am trying to implement an FIR filter, so I need to time the samples precisely.  I plan on using one of the Counters to accomplish this.  I know I could simply poll for a clock overflow, but I would like to be able to use an interrupt for this time sampling.  I have no idea where to start with this.

The main stumbling block I have is how to setup the interrupt service table and the ISFP required.

After doing some research in the Programmer's Guide and CPU/Instruction Set, I still do not have a clear understanding of how to accomplish this.

Question:  Can you really move the IST to a section of CPUROM as shown in the CPU/Instruction Set (PG 5-9) or would this be moved to RAM say the 10000000 section?

Question:  Each interrupt has its own service packet and this packet is called based on the IFR register?

I see in the Programmer's Guide that you can make a specialized C function for handling the interrupt:

interrupt void int_handler()
{
unsigned int flags;
...
}

Question:  Is this a universal handler for all interrupts or does this represent one ISFP?

Question:  if this is one for each, how do you line up all these functions into a packet section/map?

Is there any templates or short examples on which to work from?

 

Any help is greatly appreciated.

 

  • First off, this is all REALLY easy using DSP/BIOS as it handles all this for you.  However, this is still a good question if for some reason you can't use DSP/BIOS.

    dan kantorski said:

    Question:  Can you really move the IST to a section of CPUROM as shown in the CPU/Instruction Set (PG 5-9) or would this be moved to RAM say the 10000000 section?

    On older c671x devices the 0x800 address in the example was RAM, so for c672x an address such as 0x10000000 would be more typical.

    dan kantorski said:

    Question:  Each interrupt has its own service packet and this packet is called based on the IFR register?

    When an interrupt occurs the CPU simply branches to the value contained in the ISTP register.  The upper bits of that register specify where in memory your vector table is located.  The lower bits change depending on what the highest-priority enabled interrupt happens to be, i.e. the lowest bit set in IFR that is also set in IER.  Hence this HPEINT field will be an offset within your vector table.

    Since the service packet that is branched to only has 8 instructions, it generally just branches to the "real" ISR which is located elsewhere.

    dan kantorski said:

    I see in the Programmer's Guide that you can make a specialized C function for handling the interrupt:

    interrupt void int_handler()
    {
    unsigned int flags;
    ...
    }

    Question:  Is this a universal handler for all interrupts or does this represent one ISFP?

    The interrupt keyword causes the compiler to save ALL cpu registers rather than only saving a subset, i.e. the "save on call" registers, like it normally would.  It does not represent a universal handler nor does it represent an ISFP.  The ISFP would contain a branch instruction to this ISR.

    dan kantorski said:

    Question:  if this is one for each, how do you line up all these functions into a packet section/map?

    Is there any templates or short examples on which to work from?

    Any help is greatly appreciated.

    I've uploaded a simple project I wrote a few years ago.  The key things are:

    • vectors.asm file has the "template" for the vector table.  That is, it use a .sect command to place it into its own section called "vectors" for linker allocation, and it has 8 instructions per ISFP.
    • padk.cmd file defines a memory section VEC that is located at 0x10000000, and then it places the section "vectors" into VEC
    • main.c sets ISTP = 0x10000000 to match the linker command file.

    Note that in my vectors.asm I used the "lazy" way to branch to the ISR.  I just used a relative branch.  This will have a limitation in that your ISR will need to be within 1MB (forget the exact reach, I think it might be +/- 2MB).  So if your vector table is in internal memory then your ISR will also need to be in internal memory.  In order to go anywhere in the memory map you would need a register for "scratch", but in order to use the register you would need to push and pop around the use of it so as to not destroy the contents.

     

    dMAX.zip
  • Thank you very much for your sample program.  It is a great reference.

    One more quick topic.

    The beginning of my disassembled code starts like this:

    10000000 00000000            NOP          
    10000004 00000000            NOP          
    10000008 00000000            NOP          
    1000000C 00000000            NOP          
    10000010 00000000            NOP          
    10000014 00000000            NOP          
    10000018 00000000            NOP          
    1000001C 00000000            NOP          
    10000020          TISecondaryBoot_bootstart:
    10000020 01BC54F6            STW.D2T2      B3,*SP--[2]
    10000024 00002000            NOP           2
    10000028 07C6BE2A            MVK.S2        0xffff8d7c,SP
    1000002C 0788006A            MVKH.S2       0x10000000,SP
    10000030 07BF07A2            AND.S2        -8,SP,SP
    10000034 0745002A            MVK.S2        0xffff8a00,DP
    10000038 0708006A            MVKH.S2       0x10000000,DP

    Should the vector table be placed at 10000000 in general?   Or, in my case, should I place the vector section in memory somewhere off the initial boot/entry point?

  • Hi Dan,

    I'm glad the sample program clarified things for you.  The only requirement for the vector table is that you align it to a 1KB boundary (i.e. 10 LSBs = 0).  You could put it at the end of internal RAM if that's easier for you.

    Brad

  • Hi Brad:

    I have implemented an ISR complete with a Vectors section. Funny I never see an interrupt occur.  Using the timer1 for the periodic interrupt generator,  I setup the following:

        //Setup Timer1 Interrupt
        ISTP=0x10001800;            //Establish Interrupt Service Table Pointer
        *RTI_GCTRL=0x00000000;        //Stop Counters
        *RTI_COMPCTRL=0x00000010;    //CompReg1 to Timer1 CR0 to T0
        *RTI_FRC1=0x00000000;        //Reset Free Run Counter 1
        *RTI_UC1=0x00000000;        //Reset Up Counter 1
        *RTI_CPUC1=0x00004E20;        //Load compare counter1 w/ADC sampling time 5k samples/sec
        *RTI_COMP1=0x00000001;        //Set Compare Reg 1 with 1 FRC1 count
        *RTI_UDCP1=0x00000001;        //Set autoinc to compare reg 1 as 1
        *RTI_SETINT=0x00000002;     //Enable INT1 Compare Reg 1

    Later in the program after other initializations, I turn on the generator.

    //Intialize interrupts and start the interrupt generator(Counter1)
        IER |= 0x00000022;            //Enable INT5 and NMIE
        CSR |= 0x00000001;         //set GIE
        *RTI_GCTRL=0x00000002;        //Start Counter1

    Stopping with the Emulator, I read this on the RTI registers:

    CFGRTI                  00000000    RTICAFRC0    00000000    RTIUDCP0    00000000    RTICLEARINT       00000002
    RTIGCTRL             00000002    RTICAUC0      00000000    RTICOMP1    00072A16    RTIINTFLAG          0000000E
    Reserved               00000000    RTIFRC1         00072A15    RTIUDCP1    00000001    RTIDWDCTRL      5312ACED
    RTICAPCTRL        00000000    RTIUC1           00001397    RTICOMP2    00000000    RTIDWDPRLD      00000FFF
    RTICOMPCTRL    00000010    RTICPUC1      00004E20    RTIUDCP2    00000000    RTIWDSTATUS    00000000
    RTIFRC0                00000002    RTICAFRC1    00000000    RTICOMP3    00000000    RTIWDKEY            0000A35C
    RTIUC0                  00000009    RTICAUC1      00000000    RTIUDCP3    00000000    RTIDWDCNTR      01FFFFFF
    RTICPUC0            00000032    RTICOMP0      10000000    RTISETINT    00000002       

    This is showing me that Timer 1 is counting up incrementing FRC1 RTICOMP1 is always maintaining 1 above FRC1.  Compare Reg1 is set for FRC1. RTISETINT is set for trigger of Compare Reg 1.  and RTIINTFLAG shows interrupts are pending based on Comp Reg 1, 2 and 3 (Comp Reg 0 set very high and did not set).

    And this on the Core Registers:

    ISTP    10001800
    IFR    00000000
    IER    00000022
    IRP    100056E0
    NRP    B9E23EDC
    AMR    00000000
    CSR    03000183

    IER Showing interrupt enabled for INT5 (Bit 5, RTI INT 1, 2, 3, 4, & overflow Ints) and NMIE.  Strange that the RESET bit is not read as "1" would have expected 0x23 in IER

    Also shows that GIE is enabled.

    Yet when in the emulator and I try to run to cursor (inside of the Interrupt routine) I never stop there and IFR does not reflect an interrupt ever occurring.

    Is there something I am missing in the setups?

     

  • Try setting a breakpoint in the vector table at interrupt 5 to see if it ever gets there.

    Another test is to clear IER.bit5 intentionally and then look to see if IFR.bit5 ever gets set.  If it does not then your issue is in the peripheral rather than the CPU.

  • Putting a breakpoint in the vector table did not show a stop either.

    I did try writing this code for my main loop

    //Main loop
        tval=*RTI_FRC1;
        while(1){
        frc1=*RTI_FRC1;
        if (tval != frc1){
            tval=frc1;
            ISR=0x0020;}
        asm(" NOP");
        asm(" NOP");
        asm(" NOP");
        asm(" NOP");
        asm(" NOP");
        };
    }

    Which is essentially polling for a change of the FRC1 register and setting the interrupt flag.  When I run this code, the interrupt service routine is performing as it should.  This means that the RTI interrupt which seems to be occurring based on  RTIINTFLAG=0000000E is not triggering the main IFR flag??? 

  • I have figured it out.  The RTIINTFLAG register must be cleared to clear the interrupt to allow retriggering. 

    So by performing this operation:

    *RTI_INTFLAG=0x00000002;

    before starting the clock and performing the step at the end of the ISR allows retriggering of the Interrupt handling by the CPU.

    The documentation on this point is lacking, in my opinion.  No where in the SPRU717 document does it describe how this RTIINTFLAG register integrates into the interrupt scheme or how to actually clear the flag.  I started by trying to clear it by writing all 0s.  Who was to know to clear you needed to write a 1 to the bits you want to reset.

    Thank you for the help.

  • I think everyone would agree that the documentation is lacking on that point!  Good job figuring it out.

    Generically speaking, since INT5 on 672x is tied to RTI1-3 you would need to check the INTFLAG register to determine which was the source of the interrupt and then you would clear the corresponding flag.