This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ST timer problems

Hello,

Could you help to install the ST timer on the AT91Rm9200? I don't know how to setup the AIC registers correct. Maybe there are more than one big mistake.

void initialize_pit()
{
        unsigned int  flag, period, irq_id, mask, oldHandler, src_type, priority;
        volatile int status;
        void *newHandler;

        //period
    Timer0->ST_PIMR = period << 5;

        AT91F_ST_SetPeriodInterval(Timer0, period);
        //state
        //status = Timer0->ST_SR;

        //enable interrupt
        flag=1;
        Timer0->ST_IER = flag;

        AT91F_ST_EnableIt( Timer0, flag);

        //enable PMC
        AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, 1 << AT91C_ID_IRQ0);

        //config AIC
        irq_id = 0;
        oldHandler = pAic->AIC_SVR[irq_id];
        mask = 0x1 << irq_id;
        pAic->AIC_IDCR = mask ;
        pAic->AIC_SVR[irq_id] = (unsigned int) newHandler ;

        //* Store the Source Mode Register
    pAic->AIC_SMR[irq_id] = src_type | priority  ;


        AT91F_AIC_ConfigureIt(pAic, irq_id, priority, src_type, newHandler);

        //enable AIC
        AT91F_AIC_EnableIt(pAic, 1);
}

I hope somebody could help me with this problem...

best regards
johannes

Parents
  • Timer0->ST_PIMR = period << 5;
    

    Your code doesn't show the definition/declaration of Timer0. If the problem is there, it's impossible for anyone not having access to the code to spot.

    //enable PMC
            AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, 1 << AT91C_ID_IRQ0);
    

    I'm not sure what this line is supposed to do. The AIC is continuously clocked (see device datasheet, p. 241, 22.6.2.).

         irq_id = 0;
    

    IRQ ID 0 is the interrupt of the AIC itself. The system interrupts have the IRQ ID 1. Refer to the device datasheet, p. 21.

    pAic->AIC_SVR[irq_id] = (unsigned int) newHandler ;
    

    I don't think the code assigns a value to newHandler anywhere. Basically, this sets the interrupt vector to a random address. That's a surefire way to get undefined behavior.

    pAic->AIC_SMR[irq_id] = src_type | priority  ;
    

    priority never has a value assigned to it anywhere. This doesn't just set the priority to a random value, it may also set the source type to a random value.
    Oh. src_type also never has a value assigned to it, either.

    AT91F_AIC_ConfigureIt(pAic, irq_id, priority, src_type, newHandler);
    

    The code first tries to configure the interrupt "by hand" and then does so again by using the function.

Reply
  • Timer0->ST_PIMR = period << 5;
    

    Your code doesn't show the definition/declaration of Timer0. If the problem is there, it's impossible for anyone not having access to the code to spot.

    //enable PMC
            AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, 1 << AT91C_ID_IRQ0);
    

    I'm not sure what this line is supposed to do. The AIC is continuously clocked (see device datasheet, p. 241, 22.6.2.).

         irq_id = 0;
    

    IRQ ID 0 is the interrupt of the AIC itself. The system interrupts have the IRQ ID 1. Refer to the device datasheet, p. 21.

    pAic->AIC_SVR[irq_id] = (unsigned int) newHandler ;
    

    I don't think the code assigns a value to newHandler anywhere. Basically, this sets the interrupt vector to a random address. That's a surefire way to get undefined behavior.

    pAic->AIC_SMR[irq_id] = src_type | priority  ;
    

    priority never has a value assigned to it anywhere. This doesn't just set the priority to a random value, it may also set the source type to a random value.
    Oh. src_type also never has a value assigned to it, either.

    AT91F_AIC_ConfigureIt(pAic, irq_id, priority, src_type, newHandler);
    

    The code first tries to configure the interrupt "by hand" and then does so again by using the function.

Children
  • thanks for your answer

    AT91PS_ST Timer0;
    
    AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, 1 << AT91C_ID_IRQ0);
    

    enable the peripherie clock for the ST timer.

    >The code first tries to configure the interrupt "by >hand" and then does so again by using the function.

    it is enough to use this line of code?

       AT91F_AIC_ConfigureIt(pAic, irq_id, priority, src_type, newHandler);
    

    I don't know what I have to use for "newHandler"?
    Moreover I changed the irq_id to 1.

    best regards
    johannes

  • AT91PS_ST Timer0;
    

    Does Timer0 have a value assigned to it anywhere ? If it is just declared as a global variable, then its value will be 0 by default.

    enable the peripherie clock for the ST timer.

    The system timer is continuously clocked (device datasheet, p. 294, 24.4.1).

    I don't know what I have to use for "newHandler"?

    The address of an interrupt service routine, which you'll most likely have to write yourself.

  • thanks...

       Timer0 = 10000;
    
            //Periode für den Timer
            period = 5;
            AT91F_ST_SetPeriodInterval(Timer0, period);
    
            // Interrupt enablen - gesetzt wenn ST_IER=1
            flag=1;
            AT91F_ST_EnableIt( Timer0, flag);
    
            //config AIC
            irq_id = 1;
            mask = 0x1 << irq_id;
            pAic->AIC_IDCR = mask ;
            pAic->AIC_SVR[irq_id] = (unsigned int) newHandler ;
    
            //* Store the Source Mode Register
        pAic->AIC_SMR[irq_id] = src_type | priority  ;
    
            AT91F_AIC_ConfigureIt(pAic, irq_id, priority, src_type, newHandler);
    
            //enable AIC
            AT91F_AIC_EnableIt(pAic, irq_id);
    

    Could you give me a small example for the newHandler?

    best regards
    johannes

  • ok I only have to use such a function, which works,when the interrupt occurs - right?

    void ST_interrupt(void)
    {
    AT91F_PIO_SetOutput(AT91C_BASE_PIOB, AT91B_LED1);
    AT91F_PIO_ClearOutput(AT91C_BASE_PIOB, AT91B_LED1);
    }
    

    best regards
    johannes

  • ok I only have to use such a function, which works,when the interrupt occurs - right?

    I'm afraid it is almost, but not quite that simple.

    What an interrupt handler needs to do is explained in the device datasheet (I hope you have a copy of it), in the chapter about the AIC. An interrupt handler must, for example, indicate to the AIC that it has finished processing the current interrupt. The exact way to this (you guessed it) is described in the datasheet.

    It is generally a very good idea to thoroughly read the chapters in the datasheet about the peripherals and features you are going to use. Some things aren't quite intuitive. And have a copy of the datasheet handy in order to read through the chapters again while programming the device.

  • thank for your answer - now this is my current code... could you tell me, what's wrong?

    initialization of the pit timer

    void initialize_pit()
    {
     unsigned int  flag, period, irq_id, mask, src_type, priority;
            volatile int status;
    
    
            Timer0 =  AT91C_BASE_ST;                        /* Base Address for the ST Timer */
    
            //period for the pit timer
            period = 500;
            AT91F_ST_SetPeriodInterval(Timer0, period);
    
            // enable interrupts
            flag=1;
            AT91F_ST_EnableIt( Timer0, flag);
    
            //config AIC
            irq_id = 1;
    
            AT91F_AIC_ConfigureIt(pAic, irq_id, priority, src_type, ST_interrupt);
    
            //enable AIC
            AT91F_AIC_EnableIt(pAic, irq_id);
    
    }
    

    pit timer interrupt handler

    void ST_interrupt(void)
    {
       AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF;                                    //disable all interrupts
       AT91C_BASE_AIC->AIC_ICCR = 0x00000001;                                    // clear pit interrupt
    
       AT91F_PIO_SetOutput(AT91C_BASE_PIOC, AT91C_PIO_PC1);
       AT91F_PIO_ClearOutput(AT91C_BASE_PIOC, AT91C_PIO_PC1);
    
       AT91C_BASE_AIC->AIC_IECR = 0x00000001;                                    // interrupt enable command
       AT91C_BASE_AIC->AIC_EOICR = 0x0;                                                  // end of interrupt
    
    }
    

    main method

    void timer()
    {
             unsigned int tick;                                             // timer
             unsigned int pit_interval;                             // intveral pit timer
    
             initialize_pit();
    
             *(AT91C_ST_PIMR) = pit_interval;               // value for the pit timer
             tick = *(AT91C_ST_CRTR);                               //variable tick has the current value of the PIT timer
    
             while(1)
             {
    
                    while (tick == *(AT91C_ST_CRTR));
                            tick = *(AT91C_ST_CRTR);
    
             }
    
    }
    

    best regards
    johannes

  • AT91F_AIC_ConfigureIt(pAic, irq_id, priority, src_type, ST_interrupt);
    

    src_type and priority don't have any values assigned to them !

    I'm pretty sure that the compiler is issuing warnings about variables being used before having been assigned a value here. Compiler warnings are there for a reason and usually indicate that there is a problem with your code.

    void ST_interrupt(void)
    {
       AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF;                                    //disable all interrupts
       AT91C_BASE_AIC->AIC_ICCR = 0x00000001;
    

    This is unnecessary and useless at best. Since you probably want the ST interrupt to be level-sensitive, the AIC_ICCR will have no effect. The interrupt will be cleared by reading ST_SR instead.

  • You still have uninitialized variables. Have you turned on all compiler warnings, and then made sure to clean out any warnings you get?

    Another thing:

    while(1)
             {
    
                    while (tick == *(AT91C_ST_CRTR));
                            tick = *(AT91C_ST_CRTR);
    
             }
    
    


    Notice 1: The semicolon at the end of the while() line menas that you have a while statement with an empty body - the indented second line isn't part of the while loop...

    Notice 2: Is your loop intended as a delay? If all you want is the tick variable to be updated when the timer steps, you should let the interrupt service routine (ISR) assign a new value to tick on each interrupt. But then again - if the specific register in the timer is tha value you need, there is no reason to make a copy of it to a variable.

  • ok - now I get no warnings or errors... but the call for the ST_interrupt routine doesn't work...

    void timer()
    {
             unsigned int pit_interval;                             // intveral pit timer
    
             initialize_usart1();
             initialize_pit();
    
             *(AT91C_ST_PIMR) = pit_interval;               // value for the pit timer
    
             while(1)
             {
                    //do nothing
             }
    
    }
    

    The ST_SR register tell's me only if there has been a interrupt since if red it the last time..

    best regards
    johannes

  •    irq_id = 1;
            priority = 1;
            src_type = 0x01;
            AT91F_AIC_ConfigureIt(pAic, irq_id, priority, src_type, ST_interrupt);
    

    that is my configuration for the AIC.

    best regards
    johannes

  • The ST_SR register tell's me only if there has been a interrupt since if red it the last time..

    No - the ST_SR is the direct cause for the ST interrupt line being asserted. There's a "hard-wired" connection on the chip that says "(ST_SR AND ST_IMR) -> Status of the ST interrupt line.

    that is my configuration for the AIC.

    You can find #defined values for the source type and the priority in AT91RM9200_inc.h.

    0x01 for the source type isn't even a valid value, since the source type field consists of bits 5 and 6 in the AIC_SMR.

  • I set the value for the src_type to 1.

    but what's the reason, that my ST_interrupt(void) method never run?

    Is the only solution to say if(ST_SR == 1) go to ST_interrupt(void) ?

    johannes

  • AT91F_AIC_EnableIt(pAic, irq_id);
    

    Where's the definition of pAic, and where does it get a value assigned to it ?

    I set the value for the src_type to 1.

    The src_type field consists of bits 5 and 6 of the AIC_SMRx. So valid values for src_type are 0x00, 0x20, 0x40 and 0x60.

    but what's the reason, that my ST_interrupt(void) method never run?

    Something's still wrong with your code.

    Is the only solution to say if(ST_SR == 1) go to ST_interrupt(void) ?

    No, that would just mess up things completely. The solution is getting the AIC and the ST programmed correctly. Maybe you need to recapitulate the appropriate chapters in the datasheet instead of trying to depend on others trying poke through code snippets and find out what exactly is wrong with your code. Maybe having another look inside a C textbook might be a good idea, too - might be a good idea judging from the use of uninitialized local variables.

  • AT91PS_AIC pAic = AT91C_BASE_AIC;
    

    that's the definition for AIC

    __inline unsigned int AT91F_AIC_ConfigureIt (
            AT91PS_AIC pAic,  // \arg pointer to the AIC registers
            unsigned int irq_id,     // \arg interrupt number to initialize
            unsigned int priority,   // \arg priority to give to the interrupt
            unsigned int src_type,   // \arg activation and sense of activation
            void (*newHandler) (void) ) // \arg address of the interrupt handler
    {
            unsigned int oldHandler;
        unsigned int mask ;
    
        oldHandler = pAic->AIC_SVR[irq_id];
    
        mask = 0x1 << irq_id ;
        //* Disable the interrupt on the interrupt controller
        pAic->AIC_IDCR = mask ;
        //* Save the interrupt handler routine pointer and the interrupt priority
        pAic->AIC_SVR[irq_id] = (unsigned int) newHandler ;
        //* Store the Source Mode Register
        pAic->AIC_SMR[irq_id] = src_type | priority  ;
        //* Clear the interrupt on the interrupt controller
        pAic->AIC_ICCR = mask ;
    
            return oldHandler;
    }
    
    irq_id = 1;
            priority = 1;
            src_type = 1;
            AT91F_AIC_ConfigureIt(pAic, irq_id, priority, src_type, ST_interrupt);
    

    johannes