Skip to main content
Mistake with timer prescaler. Seting CS02 result in a scale by 256 not 128
Source Link
/*
 * TryLCD.cpp
 *
 * Created: 11.01.2020 12:49:58
 * Author : Ludwig Füchsl
 * Description: Evaluation code for driving an static lcd glass directly with an ATTiny
 */ 
// 8MHz internal oscillator
#define F_CPU 8000000UL

// Include atmel libs
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// Bit for common high low
bool bit = false;
// Segment a desired value
bool a = false;
// Segment b desired value
bool b = false;

// Output compare match interrupt 
ISR(TIM0_COMPA_vect){
    // Invert common every clock cycle to generate alternating field in lcd
    bit = !bit;

    // Set the current common state
    if(bit)     PORTA |=  (1UL << 0);
    else        PORTA &= ~(1UL << 0);

    // Determinate segment a state via xor with common
    if(bit ^ a) PORTA |=  (1UL << 1);
    else        PORTA &= ~(1UL << 1);
    
    // Determinate segment b state via xor with common
    if(bit ^ b) PORTA |=  (1UL << 2);
    else        PORTA &= ~(1UL << 2);
}

// Main program
int main(void){
    cli();

    // == Setup IO ==
    // Port A output
    DDRA    = 0xFF;
    // Port A all off
    PORTA   = 0x00;

    // == Setup Timer Meta ==
    // Clear on compare
    TCCR0A |=  (1UL << WGM01);
    // Timer prescaler clk/128256
    TCCR0B |=  (1UL << CS02);

    // Setup Time Interrupt
    // Compare match A on 255
    OCR0A = 0xFF;
    // Compare match a A interrupt enable
    TIMSK0 |= (1UL << OCIE0A);

    // Interrupts on
    sei();

    // Setup default segment values
    a = true;
    b = false;
    
    // Main loop
    while (1) {
        // Wait for 1s
        _delay_ms(1000);
        // Invert a and b
        a = !a;
        b = !b;
    }
}
/*
 * TryLCD.cpp
 *
 * Created: 11.01.2020 12:49:58
 * Author : Ludwig Füchsl
 * Description: Evaluation code for driving an static lcd glass directly with an ATTiny
 */ 
// 8MHz internal oscillator
#define F_CPU 8000000UL

// Include atmel libs
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// Bit for common high low
bool bit = false;
// Segment a desired value
bool a = false;
// Segment b desired value
bool b = false;

// Output compare match interrupt 
ISR(TIM0_COMPA_vect){
    // Invert common every clock cycle to generate alternating field in lcd
    bit = !bit;

    // Set the current common state
    if(bit)     PORTA |=  (1UL << 0);
    else        PORTA &= ~(1UL << 0);

    // Determinate segment a state via xor with common
    if(bit ^ a) PORTA |=  (1UL << 1);
    else        PORTA &= ~(1UL << 1);
    
    // Determinate segment b state via xor with common
    if(bit ^ b) PORTA |=  (1UL << 2);
    else        PORTA &= ~(1UL << 2);
}

// Main program
int main(void){
    cli();

    // == Setup IO ==
    // Port A output
    DDRA    = 0xFF;
    // Port A all off
    PORTA   = 0x00;

    // == Setup Timer Meta ==
    // Clear on compare
    TCCR0A |=  (1UL << WGM01);
    // Timer prescaler clk/128
    TCCR0B |=  (1UL << CS02);

    // Setup Time Interrupt
    // Compare match A on 255
    OCR0A = 0xFF;
    // Compare match a A interrupt enable
    TIMSK0 |= (1UL << OCIE0A);

    // Interrupts on
    sei();

    // Setup default segment values
    a = true;
    b = false;
    
    // Main loop
    while (1) {
        // Wait for 1s
        _delay_ms(1000);
        // Invert a and b
        a = !a;
        b = !b;
    }
}
/*
 * TryLCD.cpp
 *
 * Created: 11.01.2020 12:49:58
 * Author : Ludwig Füchsl
 * Description: Evaluation code for driving an static lcd glass directly with an ATTiny
 */ 
// 8MHz internal oscillator
#define F_CPU 8000000UL

// Include atmel libs
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// Bit for common high low
bool bit = false;
// Segment a desired value
bool a = false;
// Segment b desired value
bool b = false;

// Output compare match interrupt 
ISR(TIM0_COMPA_vect){
    // Invert common every clock cycle to generate alternating field in lcd
    bit = !bit;

    // Set the current common state
    if(bit)     PORTA |=  (1UL << 0);
    else        PORTA &= ~(1UL << 0);

    // Determinate segment a state via xor with common
    if(bit ^ a) PORTA |=  (1UL << 1);
    else        PORTA &= ~(1UL << 1);
    
    // Determinate segment b state via xor with common
    if(bit ^ b) PORTA |=  (1UL << 2);
    else        PORTA &= ~(1UL << 2);
}

// Main program
int main(void){
    cli();

    // == Setup IO ==
    // Port A output
    DDRA    = 0xFF;
    // Port A all off
    PORTA   = 0x00;

    // == Setup Timer Meta ==
    // Clear on compare
    TCCR0A |=  (1UL << WGM01);
    // Timer prescaler clk/256
    TCCR0B |=  (1UL << CS02);

    // Setup Time Interrupt
    // Compare match A on 255
    OCR0A = 0xFF;
    // Compare match a A interrupt enable
    TIMSK0 |= (1UL << OCIE0A);

    // Interrupts on
    sei();

    // Setup default segment values
    a = true;
    b = false;
    
    // Main loop
    while (1) {
        // Wait for 1s
        _delay_ms(1000);
        // Invert a and b
        a = !a;
        b = !b;
    }
}
Source Link

Thanks Spehro Pefhany for your answer and the nice discussion! I just want to summerice the discussion and my additional research combined with some images and a C++ code file.

The lcd mentioned in the Question is an static drive display. It is not valid to apply a static dc field between the segment electrode and the common electrode! It will destroy the display. The best way to avoid that is to alternate the voltage on the common pin between ground and vcc. Every segment that is on, must have the oposite potential than the common pin (ex.: Common: Hight --> Segment: Low). Every segment that is off, must have the same potential then the common pin (ex.: Common: Hight --> Segment: Hight). Normally an lcd is driven with a frequency around 30-60Hz (higher is not a fault, it just consumes more power)

For evaluation purpose I connected the common of the display to PA.0 of an ATTiny. In addition i connected two segments, one to PA.1 the other to PA.2: LCD Test setup

I used a timer and the compare interrupt to trigger the io change operation. The following cpp File was used to alternate between two segments:

/*
 * TryLCD.cpp
 *
 * Created: 11.01.2020 12:49:58
 * Author : Ludwig Füchsl
 * Description: Evaluation code for driving an static lcd glass directly with an ATTiny
 */ 
// 8MHz internal oscillator
#define F_CPU 8000000UL

// Include atmel libs
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// Bit for common high low
bool bit = false;
// Segment a desired value
bool a = false;
// Segment b desired value
bool b = false;

// Output compare match interrupt 
ISR(TIM0_COMPA_vect){
    // Invert common every clock cycle to generate alternating field in lcd
    bit = !bit;

    // Set the current common state
    if(bit)     PORTA |=  (1UL << 0);
    else        PORTA &= ~(1UL << 0);

    // Determinate segment a state via xor with common
    if(bit ^ a) PORTA |=  (1UL << 1);
    else        PORTA &= ~(1UL << 1);
    
    // Determinate segment b state via xor with common
    if(bit ^ b) PORTA |=  (1UL << 2);
    else        PORTA &= ~(1UL << 2);
}

// Main program
int main(void){
    cli();

    // == Setup IO ==
    // Port A output
    DDRA    = 0xFF;
    // Port A all off
    PORTA   = 0x00;

    // == Setup Timer Meta ==
    // Clear on compare
    TCCR0A |=  (1UL << WGM01);
    // Timer prescaler clk/128
    TCCR0B |=  (1UL << CS02);

    // Setup Time Interrupt
    // Compare match A on 255
    OCR0A = 0xFF;
    // Compare match a A interrupt enable
    TIMSK0 |= (1UL << OCIE0A);

    // Interrupts on
    sei();

    // Setup default segment values
    a = true;
    b = false;
    
    // Main loop
    while (1) {
        // Wait for 1s
        _delay_ms(1000);
        // Invert a and b
        a = !a;
        b = !b;
    }
}

Using my test setup and this code, i took some measurement with my scope. On Chanel 1 (yellow) is the common. On Chanel 2 (green) is segment A (In this case the segment is NOT lit). On Chanel 3 (orange) is segment B (In this case the segment is lit) Scope measurement for lcd driving

Please note that if you are not using an static lcd (Multiple commons) the lcd needs to be multiplexed! This results in the need of more that two voltage levels! For more information please also read this document by microchip: Application Notice 658