Problem using timer and LCD / Serial

Hello,

I'm very new to Arduino but have quite some embedded programming experience (arm platforms) for a few years now. So I thought I know how thinks are working. :slight_smile:

It seems I'm wrong or missing something essential with my first Arduino experience.

The plan is to get analog value with a sample rate of 8kHz using timer 1 and ADC interrupt. Additionally a LCD, serial and I2C communication should be used on an Arduino Micro.

I started implementing my code and LCD and Serial output is working stand-alone. As soon as I setup timer1 interrupt my LCD doesn't show anything and also serial output is stopped. It seems that timer1 interrupt completely destroys everything since even uploading new code is only possible if I press the reset button and immediately upload code. If I wait until board is up /dev/ttyAMC0 disapears.

Problem occures if I enable the timer interrupt. When commenting the line setting TIMSK1 register LCD and serial works fine.

Here is my (stripped down) code.

#include <math.h>

#include <LiquidCrystal.h>

#define SAMPLE_RATE                 8000

LiquidCrystal lcd(12, 11, 10, 9, 8, 7, 6);

ISR(TIMER1_COMPA_vect)
{
    lcd.setCursor(0, 1);
    lcd.print(millis() / 1000);
}

void setup()
{
    // Start serial
    Serial.begin(9600);

    lcd.begin(20, 4);

    // Disable interrupts
    cli();

    /*
     * setup timer 1 to sample with SAMPLE_RATE Hz
     */
    // Normal operation and CTC mode
    TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(COM1B0) | _BV(WGM11) | _BV(WGM10));

    // CTC with reset on OCR1A and no prescaler
    TCCR1B &= ~(_BV(WGM13) | _BV(CS11) | _BV(CS12));
    TCCR1B |= _BV(WGM12) | _BV(CS11) | _BV(CS10);

    OCR1A = F_CPU / SAMPLE_RATE;

    // Enable OCR1A interrupt
    TIMSK1 |= OCIE1A;

    // Enable interrupts
    sei();

    lcd.print("Hallo Welt");
}

void loop()
{
}

Any idea, what I'm missing?

Thanks & Regards,
Olti

ISR routines should generally be short.

This probably isn't short enough:

ISR(TIMER1_COMPA_vect)
{
    lcd.setCursor(0, 1);
    lcd.print(millis() / 1000);
}

I suggest the timer1 compare ISR sets a flag which you can then test in your (currently empty) main loop and update the display.

As soon as I setup timer1 interrupt my LCD doesn't show anything and also serial output is stopped.

Since your posted code doesn't write to serial, you may be hiding the real problem. Don't do serial prints inside an ISR.

Serial printing uses interrupts which are off inside an ISR. Thus, it would hang.

Hello,

thanks a lot for the reply.

The code I posted was not the one I found the problem. I changed it a bit to find what causes the problem and also deleted not needed parts to post it here.

Moving the code from ISR (so it is completely empty) to loop() has exactly the same effect.
I also removed serial code because I thought that maybe serial uses timers and interrupts I break with my code. But I had a look at serial code and couldn't find any relationship to my timer.
Setting up the timer seems to be perfectly fine but as soon as I enable interrupt it stops working.

In my original code I used serial and LCD only in loop() for some debug outputs.

There's no reason to suppose the lcd library is re-entrant (technical term meaning
you can call its methods(*) from an ISR). In general few libraries are disigned to be
re-entrant, re-entrancy is difficult to achieve(+)

(*) In general methods that just return information without side-effects are likely to
work, but anything that causes output or has side-effects should not be called from
an ISR (as the library may already be executing).

(+) Some of the basic Arduino functions are re-entrant, like digitalWrite().

BTW I'm using "re-entrant" sloppily here, I'm mixing up "thread-safe" and "re-entrant"
I think.

Sorry, if I confused you. Kindly ignore the two lines in the ISR. I just added it for debugging. Didn't work before with empty ISR.

I deleted it and even the "Hallo Welt" in the setup routine is not printed on LCD. If I remove writing to TIMSK1 register this line is printed.

Well, don't post stripped down code.

http://snippets-r-us.com/

Post your whole code as an attachment.

How to use this forum

Sorry, I think you got me wrong. I stripped it down to find out the root cause on my own. Not to post it here. Unfortunately I didn't undo my change to copy the print to LCD from loop() to ISR.

Here is the original code including serial:

#include <math.h>

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 10, 9, 8, 7, 6);

ISR(TIMER1_COMPA_vect)
{
}

void setup()
{
    int32_t i = 0;

    pinMode(PIN_LCD_BL, OUTPUT);
    digitalWrite(PIN_LCD_BL, HIGH);

    // Start serial
    Serial.begin(9600);

    lcd.begin(20, 4);

    // Disable interrupts
    cli();

    /*
     * setup timer 1 to sample with SAMPLE_RATE Hz
     */
    // Normal operation and CTC mode
    TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(COM1B0) | _BV(WGM11) | _BV(WGM10));

    // CTC with reset on OCR1A and no prescaler
    TCCR1B &= ~(_BV(WGM13) | _BV(CS11) | _BV(CS12));
    TCCR1B |= _BV(WGM12) | _BV(CS11) | _BV(CS10);

    OCR1A = F_CPU / SAMPLE_RATE;

    // Enable OCR1A interrupt
    TIMSK1 |= OCIE1A;

    // Enable interrupts
    sei();

    lcd.print("Hallo Welt");
}

void loop()
{
    lcd.setCursor(0, 1);
    lcd.print(millis() / 1000);

    Serial.println(millis() / 1000);
}
sketch_sep08a.ino: In function ‘void setup()’:
sketch_sep08a:15: error: ‘PIN_LCD_BL’ was not declared in this scope
sketch_sep08a:36: error: ‘SAMPLE_RATE’ was not declared in this scope

Ups. Deleted 2 lines of "unused" defines to much. Sorry.

#define PIN_LCD_BL                        5
#define SAMPLE_RATE                     8000

I tested the code on a different Arduino (Uno) and problem occures too.

This line is wrong:

    TIMSK1 |= OCIE1A;

It should read:

    TIMSK1 |= _BV (OCIE1A);

Fixing that, it works.

Oh. That was too easy.
Checked that line all the time and didn't see it.

Thanks a lot.