Something I don't understand (loops and interrupts)

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Something I don't understand (loops and interrupts)

BERTRAND Joël
        Hello,

        I'm trying to use avr-gcc to write a trivial firmare and my code
doesn't run as expected. I have tried to find a solution without any result.

        My current source code is available on

https://hilbert.systella.fr/test.tar.gz

        I have designed a PCB with an ATmega1284. On this board, I have
soldered 10 leds to debug an external sensor and I have written a piece
of code to turn on these leds. These leds are switched off by an
interrupt after 1/5th of second.

        Each led is associated to a struct:

typedef volatile struct
{
    volatile uint8_t    *port;
    volatile uint8_t    *pin;
    volatile uint8_t    bitNo;
    volatile int8_t     timer;
} gpio_t;

enum { i_work = 0, i_wait, i_meas_in_progress, i_meas_ready,
        i_send_data, i_watchdog_reset, i_comm_rx, i_comm_tx, i_comm_ok,
        i_irq, i_max};

static gpio_t i_led[i_max] =
        {
                { &PORTD, &PIND, 3, 0 },
                { &PORTD, &PIND, 4, 0 },
                { &PORTD, &PIND, 5, 0 },
                { &PORTD, &PIND, 6, 0 },
                { &PORTD, &PIND, 7, 0 },
                { &PORTB, &PINB, 0, 0 },
                { &PORTB, &PINB, 1, 0 },
                { &PORTB, &PINB, 2, 0 },
                { &PORTB, &PINB, 3, 0 },
                { &PORTB, &PINB, 4, 0 }
        };


        I don't understant why some leds are switched off and why some others
leds aren't! Thus, I have tried to debug TIMER1_COMPA_vect. In this
interrupt, I have written:

ISR(TIMER1_COMPA_vect, ISR_BLOCK)
{
    uint8_t     i;

    interrupt_counter = (interrupt_counter + 1) % 25;

    if (interrupt_counter == 0) // 1 s
    {
        gpio_toggle(&i_led[i_work]);
    }

    // Switch debug leds off
    for(i = 0; i < i_max; i++)
    {
        if (interrupt_counter == 0) serial_send_byte(i);
        if (i_led[i].timer > 0)
        {
            i_led[i].timer--;

            if (i_led[i].timer == 0)
            {
                gpio_off(&i_led[i]);
            }
        }
    }

    return;
}

        serial_send_byte is a trivial function:

void
serial_send_byte(uint8_t byte)
{
    while(!(UCSR0A & (1 << UDRE0)));
    UDR0 = byte;
    gpio_on(&i_led[i_comm_tx], 5);

    return;
}

        MCU enters in this interrupt (25 times each second). I have checked
that gpio_toggle(&i_led[i_work]) generates 1 Hz signal. But I don't
understand why for(i = 0; i < i_max; i++) doesn't run as expected. I
obtain on serial line (115200, 8N1):

10:23:00: 7
10:23:00: 8
10:23:00: 9
10:23:00: 4
10:23:01: 5
10:23:01: 6
10:23:01: 7
10:23:01: 8
10:23:01: 9
10:23:01: 4
10:23:02: 5
10:23:02: 6
10:23:02: 7
10:23:02: 8
10:23:02: 9
10:23:02: 0
10:23:03: 4
10:23:03: 5
10:23:03: 6
10:23:03: 7
10:23:03: 8
10:23:03: 9
10:23:03: 4
10:23:04: 5
10:23:04: 6
10:23:04: 7
10:23:04: 8
10:23:04: 9
10:23:04: 4
10:23:05: 5
10:23:05: 6
10:23:05: 7
10:23:05: 8
10:23:05: 9

        Value of i_max: 10. But why i doesn't contains values between 0 and 3 ?

        Best regards,

        JB

Reply | Threaded
Open this post in threaded view
|

Re: Something I don't understand (loops and interrupts)

Jim Jackson

Not looked too closely, but ...

On Fri, 3 Apr 2020, BERTRAND Joël wrote:

> ISR(TIMER1_COMPA_vect, ISR_BLOCK)
> {
>     uint8_t     i;
>
>     interrupt_counter = (interrupt_counter + 1) % 25;
>
>     if (interrupt_counter == 0) // 1 s
>     {
>         gpio_toggle(&i_led[i_work]);
>     }
>
>     // Switch debug leds off
>     for(i = 0; i < i_max; i++)
>     {
>         if (interrupt_counter == 0) serial_send_byte(i);
This gets called every time the for loop iterates, so will get called i_max
times, all but the first call will cuase serial_send_byte(i) to loop
waiting for the transmit buffer to empty. You do NOT want to be calling
serial_send_byte(i) in an ISR anyway. Check for interrupt_counter == 0 in
the main loop, and make sure it's declared volatile.

>         if (i_led[i].timer > 0)
>         {
>             i_led[i].timer--;
>
>             if (i_led[i].timer == 0)
>             {
>                 gpio_off(&i_led[i]);
>             }
>         }
>     }
>
>     return;
> }
>
> serial_send_byte is a trivial function:
>
> void
> serial_send_byte(uint8_t byte)
> {
>     while(!(UCSR0A & (1 << UDRE0)));
>     UDR0 = byte;
>     gpio_on(&i_led[i_comm_tx], 5);
>
>     return;
> }
>
> MCU enters in this interrupt (25 times each second). I have checked
> that gpio_toggle(&i_led[i_work]) generates 1 Hz signal. But I don't
> understand why for(i = 0; i < i_max; i++) doesn't run as expected. I
> obtain on serial line (115200, 8N1):
>
> 10:23:00: 7
> 10:23:00: 8
> 10:23:00: 9
> 10:23:00: 4
> 10:23:01: 5
> 10:23:01: 6
> 10:23:01: 7
> 10:23:01: 8
> 10:23:01: 9
> 10:23:01: 4
> 10:23:02: 5
> 10:23:02: 6
> 10:23:02: 7
> 10:23:02: 8
> 10:23:02: 9
> 10:23:02: 0
> 10:23:03: 4
> 10:23:03: 5
> 10:23:03: 6
> 10:23:03: 7
> 10:23:03: 8
> 10:23:03: 9
> 10:23:03: 4
> 10:23:04: 5
> 10:23:04: 6
> 10:23:04: 7
> 10:23:04: 8
> 10:23:04: 9
> 10:23:04: 4
> 10:23:05: 5
> 10:23:05: 6
> 10:23:05: 7
> 10:23:05: 8
> 10:23:05: 9
>
> Value of i_max: 10. But why i doesn't contains values between 0 and 3 ?
>
> Best regards,
>
> JB
>
Reply | Threaded
Open this post in threaded view
|

Re: Something I don't understand (loops and interrupts)

BERTRAND Joël
Jim Jackson a écrit :

>
> Not looked too closely, but ...
>
> On Fri, 3 Apr 2020, BERTRAND Joël wrote:
>
>> ISR(TIMER1_COMPA_vect, ISR_BLOCK)
>> {
>>     uint8_t     i;
>>
>>     interrupt_counter = (interrupt_counter + 1) % 25;
>>
>>     if (interrupt_counter == 0) // 1 s
>>     {
>>         gpio_toggle(&i_led[i_work]);
>>     }
>>
>>     // Switch debug leds off
>>     for(i = 0; i < i_max; i++)
>>     {
>>         if (interrupt_counter == 0) serial_send_byte(i);
>
> This gets called every time the for loop iterates, so will get called i_max
> times, all but the first call will cuase serial_send_byte(i) to loop
> waiting for the transmit buffer to empty. You do NOT want to be calling
> serial_send_byte(i) in an ISR anyway. Check for interrupt_counter == 0 in
> the main loop, and make sure it's declared volatile.

        I agree, but I dont have any other solution to debug. I only try to
discover why several leds are not switched off.

        For example: in main(), I call gpio_on(&i_led[i_comm_ok], 5);
Thus, i_comm_ok should be turned off after 0.25 s. And this led remains
on...

        Regards,

        JB

Reply | Threaded
Open this post in threaded view
|

[solved] Re: Something I don't understand (loops and interrupts)

BERTRAND Joël
In reply to this post by BERTRAND Joël
        I have written in a header :

static gpio_t i_led[i_max] =
            {
                    { &PORTD, &PIND, 3, 0 },
                    { &PORTD, &PIND, 4, 0 },
                    { &PORTD, &PIND, 5, 0 },
                    { &PORTD, &PIND, 6, 0 },
                    { &PORTD, &PIND, 7, 0 },
                    { &PORTB, &PINB, 0, 0 },
                    { &PORTB, &PINB, 1, 0 },
                    { &PORTB, &PINB, 2, 0 },
                    { &PORTB, &PINB, 3, 0 },
                    { &PORTB, &PINB, 4, 0 }
            };

        Note the "static" keyword. With this keyword, table is different in
each file that includes this header ! Solution is :

typedef volatile struct
{
    volatile uint8_t    *port;
    volatile uint8_t    *pin;
    volatile uint8_t    bitNo;
    volatile int8_t     timer;
} gpio_t;

#ifdef __MAIN__
    volatile gpio_t i_led[i_max] =
            {
                    { &PORTD, &PIND, 3, 0 },
                    { &PORTD, &PIND, 4, 0 },
                    { &PORTD, &PIND, 5, 0 },
                    { &PORTD, &PIND, 6, 0 },
                    { &PORTD, &PIND, 7, 0 },
                    { &PORTB, &PINB, 0, 0 },
                    { &PORTB, &PINB, 1, 0 },
                    { &PORTB, &PINB, 2, 0 },
                    { &PORTB, &PINB, 3, 0 },
                    { &PORTB, &PINB, 4, 0 }
            };
#else
    extern volatile gpio_t i_led[i_max];
#endif

        And my firmware runs as expected.

        Regards,

        JKB