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

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

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

  • when I start the program, I can send one character 'u' via the usart - but that's it.

    johannes

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

    Try configuring the AIC before doing everything else (especially enabling interrupts) during the initialization of ST (or any other peripheral). It might not be the problem here, but sticking with this convention may save you some debugging headaches later on.

    void ST_interrupt(void)
    {
    

    You may want to add the __irq keyword here, like this:

    void ST_interrupt(void) __irq
    {
    

    Also:

    void timer()
    {
             unsigned int st_interval;                              // intveral st timer
    
             initialize_usart1();
             initialize_st();
    
             *(AT91C_ST_PIMR) = st_interval;                // value for the st timer
    

    You are still assigning the value of an uninitialized local variable to something else. This is a very bad idea. C convention does not require uninitialized local variables to have any particular value by default - they could have _any_ value. You're basically using a (bad) random number generator to set the value of ST_PIMR here.

    The compiler should be printing a warning message here. Warning messages usually have a good reason.

  • when I start the program, I can send one character 'u' via the usart - but that's it.

    Do you have access to an emulator (i.e. can you set breakpoints in the program and single-step through it) ?

    If so, try setting a breakpoint inside the ST interrupt handler. Also, try setting one inside the ST initialization function and single-step through it (you should also be able to watch the contents of the ST registers change).

  • thanks for your help...

    I set breakpoints in the initialize_st() and the ST_interrupt(void) function. When I run the programm, the initialization and the ST_interrupt method are executed and then the program ends in the while(1) loop - doing nothing. Therefore I get only a message via the usart. the status register is 1 after the line

    status = Timer0->ST_SR;
    

    here is the whole code again

    #define    MCK     60000000                                        /* Clock-Rate für USART */
    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;
    
    }
    
     AT91PS_ST Timer0 = AT91C_BASE_ST;
     AT91PS_AIC pAic = AT91C_BASE_AIC;
    
    
     void ST_interrupt(void)
    {
             volatile int status;
    
            //clear ST_SR - muss ausgelesen werden
            status = Timer0->ST_SR;
    
            //usart1
            while( !(COM1_1->US_CSR  & AT91C_US_TXRDY) )
                        continue;
    
            AT91F_US_PutChar (COM1_1,'n');
            //clear the interrupt - zurücksetzen des Interrupts
            AT91F_AIC_ClearIt( AT91C_BASE_AIC,AT91C_ID_SYS );
    
        //the end of interrupt durch lesen dieses Registers - letzte Aktion
        AT91C_BASE_AIC->AIC_EOICR = 0x0;
    }
    
    
    void initialize_st()
    {
            //config AIC
            AT91F_AIC_ConfigureIt(pAic, AT91C_ID_SYS, AT91C_AIC_PRIOR_HIGHEST - 6, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, ST_interrupt);
    
            //unsigned int period;
            Timer0 =  AT91C_BASE_ST;                        /* Base Address for the ST Timer */
    
            //period = 0x0;
            // Set Periodic Interval Interrupt (AT91C_ST_PITS = Period Interval Timer Interrupt; Timer0 = Basis Adresse für ST)
            AT91F_ST_SetPeriodInterval(Timer0, AT91C_ST_PITS);
    
            //#define AT91C_ST_PITS         ((unsigned int) 0x1 <<  0) -> 0x1 = 0001 -> gesetzt ST_IMR Register (Interrupt enabled)
            AT91F_ST_EnableIt(Timer0, AT91C_ST_PITS);
    
    
    
            AT91F_AIC_EnableIt( pAic, AT91C_ID_SYS);
    
            // enable all mIRQ interrupts
            AT91C_BASE_AIC->AIC_CISR = 0x1 << 1;
    
    }
    
    void timer()
    {
             initialize_usart1();
             initialize_st();
             while(1);
    }
    

    When I add this line

    void ST_interrupt(void) __irq
    {
    

    what's the right request in the line

    AT91F_AIC_ConfigureIt(pAic, AT91C_ID_SYS, AT91C_AIC_PRIOR_HIGHEST - 6, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, ST_interrupt);
    

    Could there be something wrong in the startup-file? I sue the startup-file from keil.

    johannes

  • You most definitely must use the __irq keyword for the interrupt handler - unless you write in assembler and yourself write the correct code for entering/leaving the interrupt handler.

    Please don't sue the startup file - this world is already too full of busy lawyers ;)

  • could you explain me how I have to change this line

    AT91F_AIC_ConfigureIt(pAic, AT91C_ID_SYS, AT91C_AIC_PRIOR_HIGHEST - 6, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, ST_interrupt __irq);
    

  • Please read all the comments above, and then explain why you think that you should use the __irq keyword in the function call.

    The information you have received is that your Interrupt Service Routine (ISR) should be declared with the __isr keyword. You have even received an explicit example how that source line should be written.

    Have you looked at _any_ example code for your processor? You can hardly find any example code that doesn't contain at least one ISR.