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
  • 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

Reply
  • 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

Children
  • What do you think happen when you do:

    priority = 1;
    src_type = 0x01;
    

    and then:

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

    Think about the line:

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

    With src_type = 1 and priority = 1, what use do you think that or operation makes? Are you spending any time trying to understand the answers you receive? What does the data sheet say about initializing the AIC_SMR register with the value 1?

  • Also, you may want to use the __irq keyword for the interrupt service routine (or use some other way to make sure the the interrupt service routine is compiled in ARM mode and not in THUMB mode. I do not know what setting uVision uses as a default. Interrupt service routines must always be in ARM mode, however).

  • The priority level can be between 0 (lowest) and 7 (highest).

    so I select the value 1 for the priority - I don't see any disadvantages about it.

    SCR_TYPE
    0 0 high-level sensitive
    0 1 positive edge-triggerd (is this not right to use this mode)?

    0 1 are the bits 5 and 6 so it's 0x0000 0001 or not?

    Or is this configuration false for the ST timer?

    johannes

  • Very wrong. Look again at the data sheet. You are trying to store source type and priority in the same bits. Obviously that does not work. Have you read the data sheet? They normally very clearly shows what data is stored in the different bits of a register.

    Also, Christoph Franck have already written in an earlier post what values you may use for the source type. I can't see how you can manage to call the least significant bit "bit 5" or "bit 6".

  • 0 1 are the bits 5 and 6 so it's 0x0000 0001 or not?

    You just posted the piece of code that provides the answer to the question:

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

    There is nothing in here that shifts src_type 5 bit positions to the left, is there ?

    Also, you may want to work with the #define constants in the #include file instead of numeric values:

    #define AT91C_AIC_SRCTYPE         (0x3 <<  5) // (AIC) Interrupt Source Type
    #define         AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE  (0x0 <<  5) // (AIC) Internal Sources Code Label Level Sensitive
    #define         AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED   (0x1 <<  5) // (AIC) Internal Sources Code Label Edge triggered
    #define         AT91C_AIC_SRCTYPE_EXT_HIGH_LEVEL       (0x2 <<  5) // (AIC) External Sources Code Label High-level Sensitive
    #define         AT91C_AIC_SRCTYPE_EXT_POSITIVE_EDGE    (0x3 <<  5) // (AIC) External Sources Code Label Positive Edge triggered
    

  • thanks for the hint...

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

    I don't work - I think there are many other mistakes in my code...

    __irq keyword for the interrupt service routine?

    do you mean I have to use this for the interrupt routine?

     void ST_interrupt(void)
    {
    
    
            AT91F_US_PutChar (COM1_1,'u');
            while( !(COM1_1->US_CSR  & AT91C_US_TXRDY) )
                        continue;
    
    }
    

    Could you explain it a little bit for me?

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

    As I mentioned earlier, you probably want the interrupt to be level-triggered, not edge-triggered. If the interrupt line was high before you enabled the interrupt, the AIC will never see an edge and hence never call your interrupt service routine.

    You will also need to read ST_SR somewhere in your interrupt routine in order to clear the interrupt. One way of doing this is doing something along the lines of AIC_EOICR = ST_SR, which both reads ST_SR (clearing the ST interrupt) and writes to AIC_EOICR (telling the AIC that the interrupt service routine has finished).

  • thank for your answer...

    AT91PS_ST pST = AT91C_BASE_ST;
     void ST_interrupt(void)
    {
            volatile int status;
    
            //clear ST_SR
            status = pST->ST_SR;
    
    
            AT91F_US_PutChar (COM1_1,'u');
            while( !(COM1_1->US_CSR  & AT91C_US_TXRDY) )
                        continue;
    
        // Here acknowledge the end of interrupt
        AT91C_BASE_AIC->AIC_EOICR = 0x0;
    
    
    }
    

    and I changed the value

    irq_id = 1;
            priority = 1;
            AT91F_AIC_ConfigureIt(pAic, irq_id, priority, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, ST_interrupt);
    

    johannes

  • AT91PS_ST Timer0;                                          /* Variable (pointer) Timer0 für die Struct AT91S_ST definieren */
     AT91PS_AIC pAic = AT91C_BASE_AIC;
    
     AT91PS_ST pST = AT91C_BASE_ST;
     void ST_interrupt(void)
    {
            volatile int status;
    
            //clear ST_SR
            status = pST->ST_SR;
    
    
            AT91F_US_PutChar (COM1_1,'u');
            while( !(COM1_1->US_CSR  & AT91C_US_TXRDY) )
                        continue;
    
        // Here acknowledge the end of interrupt
        AT91C_BASE_AIC->AIC_EOICR = 0x0;
    
    
    }
    
    
    void initialize_st()
    {
     unsigned int  flag, period, irq_id, priority;
    
            Timer0 =  AT91C_BASE_ST;                        /* Base Address for the ST Timer */
    
            //period for the pit timer
            period = 1;
            AT91F_ST_SetPeriodInterval(Timer0, period);
    
            // enable interrupts
            flag=1;
            AT91F_ST_EnableIt( Timer0, flag);
    
            //config AIC
            irq_id = 1;
            priority = 1;
            AT91F_AIC_ConfigureIt(pAic, irq_id, priority, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, ST_interrupt);
    
            //enable AIC
            AT91F_AIC_EnableIt(pAic, irq_id);
    
    }
    
    void timer()
    {
             unsigned int st_interval;                              // intveral st timer
    
             initialize_usart1();
             initialize_st();
    
             *(AT91C_ST_PIMR) = st_interval;                // value for the st timer
    
             while(1)
             {
    
             }
    
    }
    

    Is there another stupid mistake in this code - because it doesn't work...

    johannes

  • irq_id = 1;
    priority = 1;

    you must write 0x1 instead of 1.

  • No, that is desinformation. 0x1 and 1 are exactly the same - just two numeric representations of the same value.

  • Per could you tell me which parts of the code are not correct?

    johannes

  • I'm not working with that line of chips myself. I am using NXP chips.

    To tell you why your code does not work, I would have to retrieve the datasheet for your chip - and probably also take a peek at the sample code or application notes for your chip.

    What time have you spent with the datasheet and with the available sample code? Have you looked for application notes?

    I'm not too much into distributed programming/debugging. I prefer distributed computing.

  • Per could you tell me which parts of the code are not correct?

    It looks fairly correct now.

    How do you test it ? Are you working with an emulator/ICE and are able to set a breakpoint in the ISR ? Are you waiting for the chip to send something over the USART (which may or may not be initialized correctly, your code doesn't show that part nor any calls to an initialization function) ?

    Personally, I am working with the fairly similar AT91SAM7S, and did get the PIT to work.

  • the usart is working correct - I test it. Therefore there must be still a problem that the ST_interrupt function don't run.

    AT91PS_USART COM1_1;                                               /* Variable COM1 für die Struct _AT91S_USART definieren */
    void initialize_usart1()
    {
    
            COM1_1= AT91C_BASE_US1;                         /* AT91C_BASE_US1 ist die Base-Adresse für den UART1 */
    
            /* Define RXD and TXD as peripheral     */
        AT91F_PIO_CfgPeriph(AT91C_BASE_PIOB,AT91C_PB21_RXD1 | AT91C_PB20_TXD1,0);
    
            // First, enable the clock of the PIOB (for the USART)
            AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1<<AT91C_ID_US1 ) ;
    
            // Usart Configure
            AT91F_US_Configure (COM1_1, MCK,AT91C_US_ASYNC_MODE, 115200, 0);
    
            // Enable usart
            COM1_1->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
            // setzen der beiden Variablen im US_CR Register
    
            AT91F_US_PutChar (COM1_1,'X');
    
            while( !(COM1_1->US_CSR  & AT91C_US_TXRDY) )
                         continue;
    }
    

    I'm working with uvision3 and ulink2.

    johannes