lcd not working after changing the prescalers of timers of arduino nano

hi! so i've been working on sine wave inverter project wherein i plan to use 20*4 i2c lcd. i really need to use all the timers for functions such as spwm generation,fan pwm control etc. So all the timers are utilized and work without prescaler. here is a code below :

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3,POSITIVE);  

int i= 0;
int OK = 0;
int x = 0;
int duty_50khz = 0;           // this value should not exceed 80
//float Var ; 
float Vin ;
int  temp;
const int shutdown_pin = 4;
const int trip_current = 1;
int sinPWM[]={1,2,5,7,10,12,15,17,19,22,24,27,30,32,34,37,39,42,
44,47,49,52,54,57,59,61,64,66,69,71,73,76,78,80,83,85,88,90,92,94,97,99,
101,103,106,108,110,113,115,117,119,121,124,126,128,130,132,134,136,138,140,142,144,146,
148,150,152,154,156,158,160,162,164,166,168,169,171,173,175,177,178,180,182,184,185,187,188,190,192,193,
195,196,198,199,201,202,204,205,207,208,209,211,212,213,215,216,217,219,220,221,222,223,224,225,226,227,
228,229,230,231,232,233,234,235,236,237,237,238,239,240,240,241,242,242,243,243,244,244,245,245,246,246,
247,247,247,248,248,248,248,249,249,249,249,249,255,255,255,255,249,249,249,249,249,248,
248,248,248,247,247,247,246,246,245,245,244,244,243,243,242,242,241,240,240,239,238,237,237,236,235,234,
233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,217,216,215,213,212,211,209,208,207,205,204,
202,201,199,198,196,195,193,192,190,188,187,185,184,182,180,178,177,175,173,171,169,168,166,164,162,160,
158,156,154,152,150,148,146,144,142,140,138,136,134,132,130,128,126,124,121,119,117,115,113,110,108,106,
103,101,99,97,94,92,90,88,85,83,80,78,76,73,71,69,66,64,61,59,57,54,52,49,47,44,42,39,37,34,32,30,
27,24,22,19,17,15,12,10,7,5,2,1};


const float calibration_multiplier = 1;
const float calibration_offset = 0.00;
const float calibration_offset2 = 0.3;
float rms_current ; 
int current_read;
 void initial()
  {
     for( int i=0; i<=19; i++)
        {
             lcd.setCursor(i,0);
             lcd.write(byte(4));
             lcd.setCursor(19-i,3);
             lcd.write(byte(4));
            delay(20);
}
             lcd.setCursor(3,1);
             
     for(int i=0 ; i <=7;i++)
       {
           lcd.print(text[i]);
           delay(50);
       }
            lcd.setCursor(12,1);
     for(int i = 0;i<=1; i++) 
       {
           lcd.print(text2[i]);
       }
 
     delay(2000);
     lcd.clear();                              
  }
 void setup() 
{
lcd.begin(20,4);  
initial();
lcd.createChar(0,degree_celcius);
digitalWrite(shutdown_pin,LOW);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
  //TIMER 1 SETUP FOR 50kHZ
DDRB |= (1<<DDB1)|(1<<DDB2);  //   digital pin 9 and 10 output
TCCR1A = B00000000 ;
TCCR1B = B00000000 ;
TCCR1A |= (1<< COM1A1)| (1<<COM1B1); ;    //  pin 9 non inverted mode and pin 10 inverted mode 
TCCR1A |= (1<<COM1B0) ; //
ICR1 = 160 ;
TCCR1B |= (1<<WGM13) | (1<<CS10);        // phase and frequency corrected pwm with no prescaler

cli();
TCCR0A = 0;
TCCR0B = 0;                    // timer 0 for spwm generation
TCNT0 = 0;                     // timer 1 for 50khz pwm for driving ferrite transformer
TCCR0A = B10100001 ;           // timer 2 for generating interrupts and fan pwm
TCCR0B = B00000001 ;

TCCR2A = 0;
TCCR2B = 0;
TCNT2 = 0;
TCCR2A = B10100001 ;
TIMSK2 |= (1<<OCIE2B) ;
OCR2B = 0 ;             // for interrupt
TCCR2B = B00000001 ;

sei(); 
  

OCR2A = 0 ;       // to control fan pwm              
}

ISR (TIMER2_COMPA_vect)
{
  if(i>313 && OK==0)
    {// final value from vector for pin 6
    i=0;// go to first value of vector
    OK=1;//enable pin 5
    }
if(i>313 && OK==1)
  {// final value from vector for pin 5
   i=0;//go to firs value of vector
   OK=0;//enable pin 6
  }
 x=sinPWM[i];// x take the value from vector corresponding to position i(i is zero indexed)
 i=i+1;// go to the next position
 if(OK==0)
 {
  OCR0B=0;//make pin 5 0
  OCR0A=x;//enable pin 6 to corresponding duty cycle
 }
if(OK==1)
  {
   OCR0A=0;//make pin 6 0
   OCR0B=x;//enable pin 5 to corresponding duty cycle
  }
}
 void loop() {

                                              //  Var = voltage to arduino analog input
  Vin =  ((analogRead(A7)* 0.004882)/0.3197 ) ;
  if(Vin<10)
  {
  digitalWrite(shutdown_pin,HIGH);
  lcd.clear();
  lcd.setCursor(5,1);
  lcd.print("Battery Voltage low!");
  }
  
 if(Vin>10 && Vin<10.5)
  duty_50khz = 78;
  if(Vin>10.5 && Vin<11)
  duty_50khz = 70;
  if(Vin>11 && Vin<11.5)
  duty_50khz = 65;
  if(Vin>11.5 && Vin<12)
  duty_50khz = 60;
  if(Vin>12 && Vin<12.5)
  duty_50khz = 55;
  if(Vin>12.5 && Vin<13)
  duty_50khz = 50;
  OCR1A = duty_50khz;
  OCR1B = 160-duty_50khz ; 
  
   rms_current = (((analogRead(A3)-410.487)/57.11))-calibration_offset;
   if(rms_current >4.7)
    rms_current+= 0.25; 
   if( rms_current > trip_current)
   digitalWrite(shutdown_pin,HIGH);

 temp = analogRead(A0)*0.512;
 if( temp > 70)
 OCR2A = 255 ;
 if(temp< 70 && temp>60)
 OCR2A = 200 ; 
 if(temp<60 && temp>40)
 OCR2A = 150 ;
 if(temp<40 && temp>30)
 OCR2A = 100;
 if(temp < 30)
 OCR2A = 50 ; 

 lcd.setCursor(1,0);
 lcd.print("I:");
 lcd.print(rms_current);
 lcd.print("A");
 lcd.setCursor(0,1);
 lcd.print("Vin:");
 lcd.print(Vin);
 lcd.print("volts");
lcd.setCursor(0,2);
lcd.print("Temp:");
lcd.print(temp);
lcd.write(byte(0));

   
 
}

so basically, the function " initial" works perfectly and display work till that point. But not after that because i guess i am changing the clock prescaler and using the interrupts. Is that the reason behind lcd not working? any solution to overcome this problem? appreciate the help :slight_smile:
Thanks !

How is the I2C clock derived?

int sinPWM[]= You're wasting twice as many precious bytes of RAM as you need.

Better still, don't spend any RAM on a constant table.

Im using liquid crystal library for lcd. Also I need the integer array to store duty cycle values to produce spwm waveform. That doesn't seem to be problem to me, but the problem is to make i2c lcd work after changing the clock prescaler. Please help me out .

AWOL:
How is the I2C clock derived?

The SCL is derived directly from systems 16 MHz clock and then is divided as needed by the TWPS Bits of the TWI Status Register.

Rishi_kesh:
Also I need the integer array to store duty cycle values to produce spwm waveform.

The point was none of the array values are less than 0 or greater than 255. So, by storing them in an 'int' array, you're using twice as much memory as you need to. Make them 'uint8_t' and you get a 50% savings. Also, because your code never changes the values, the can be stored as PROGMEM constants which will use zero bytes of RAM.

Thanks ! That makes a lot of sense. I did not realize it. What about issue with lcd. Would the problem get solved after changing the SCL prescaler value ? Maybe if the scl frequency is high enough the lcd will do the job?

I think millis(), micros(), delay(), and delayMicroseconds() all depend on Timer 0. Does the I2C LCD library you’re using (and didn’t specify to us) need any of those functions?

Sorry, but I have no idea if the library is using these functions. Assuming the library uses those functions, what would be solution for this?Also, None of the timers will be free. Is that a good practise?

Rishi_kesh:
Sorry, but I have no idea if the library is using these functions.

The great thing about Arduino being open-source is that you have the source code for the library. Take a look at it and see.

Assuming the library uses those functions, what would be solution for this?

I don't know.

Also, None of the timers will be free. Is that a good practise?

It's acceptable if your project works the way you want it to.

Okay thanks. I will find out code for it and post my doubts if any.

Here is the code for i2c library i got from the github. There doesn't seem to be anything about delays here

#ifndef FDB_LIQUID_CRYSTAL_I2C_H
#define FDB_LIQUID_CRYSTAL_I2C_H

#include <inttypes.h>
#include <Print.h>

// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80

// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00

// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00

// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00

// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00

// flags for backlight control
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00

#define En B00000100  // Enable bit
#define Rw B00000010  // Read/Write bit
#define Rs B00000001  // Register select bit

/**
 * This is the driver for the Liquid Crystal LCD displays that use the I2C bus.
 *
 * After creating an instance of this class, first call begin() before anything else.
 * The backlight is on by default, since that is the most likely operating mode in
 * most cases.
 */
class LiquidCrystal_I2C : public Print {
public:
	/**
	 * Constructor
	 *
	 * @param lcd_addr	I2C slave address of the LCD display. Most likely printed on the
	 *					LCD circuit board, or look in the supplied LCD documentation.
	 * @param lcd_cols	Number of columns your LCD display has.
	 * @param lcd_rows	Number of rows your LCD display has.
	 * @param charsize	The size in dots that the display has, use LCD_5x10DOTS or LCD_5x8DOTS.
	 */
	LiquidCrystal_I2C(uint8_t lcd_addr, uint8_t lcd_cols, uint8_t lcd_rows, uint8_t charsize = LCD_5x8DOTS);

	/**
	 * Set the LCD display in the correct begin state, must be called before anything else is done.
	 */
	void begin();

	 /**
	  * Remove all the characters currently shown. Next print/write operation will start
	  * from the first position on LCD display.
	  */
	void clear();

	/**
	 * Next print/write operation will will start from the first position on the LCD display.
	 */
	void home();

	 /**
	  * Do not show any characters on the LCD display. Backlight state will remain unchanged.
	  * Also all characters written on the display will return, when the display in enabled again.
	  */
	void noDisplay();

	/**
	 * Show the characters on the LCD display, this is the normal behaviour. This method should
	 * only be used after noDisplay() has been used.
	 */
	void display();

	/**
	 * Do not blink the cursor indicator.
	 */
	void noBlink();

	/**
	 * Start blinking the cursor indicator.
	 */
	void blink();

	/**
	 * Do not show a cursor indicator.
	 */
	void noCursor();

	/**
 	 * Show a cursor indicator, cursor can blink on not blink. Use the
	 * methods blink() and noBlink() for changing cursor blink.
	 */
	void cursor();

	void scrollDisplayLeft();
	void scrollDisplayRight();
	void printLeft();
	void printRight();
	void leftToRight();
	void rightToLeft();
	void shiftIncrement();
	void shiftDecrement();
	void noBacklight();
	void backlight();
	bool getBacklight();
	void autoscroll();
	void noAutoscroll();
	void createChar(uint8_t, uint8_t[]);
	void setCursor(uint8_t, uint8_t);
	virtual size_t write(uint8_t);
	void command(uint8_t);

	inline void blink_on() { blink(); }
	inline void blink_off() { noBlink(); }
	inline void cursor_on() { cursor(); }
	inline void cursor_off() { noCursor(); }

// Compatibility API function aliases
	void setBacklight(uint8_t new_val);				// alias for backlight() and nobacklight()
	void load_custom_character(uint8_t char_num, uint8_t *rows);	// alias for createChar()
	void printstr(const char[]);

private:
	void send(uint8_t, uint8_t);
	void write4bits(uint8_t);
	void expanderWrite(uint8_t);
	void pulseEnable(uint8_t);
	uint8_t _addr;
	uint8_t _displayfunction;
	uint8_t _displaycontrol;
	uint8_t _displaymode;
	uint8_t _cols;
	uint8_t _rows;
	uint8_t _charsize;
	uint8_t _backlightval;
};

#endif //

That's just the class declaration. Try looking in the actual implementation file.

Where can i find this file? I have liquid crystal library in my computer. Is it possible to view its code ?

It will probably be called LiquidCrystal_I2C.cpp.

Okay, so i check liquidcrystal.cpp and it does have delay() as well as delayMicroseconds() function in it. Here is a little bit of code

#include "LiquidCrystal_I2C.h"
#include <inttypes.h>
#include <Arduino.h>
#include <Wire.h>

// When the display powers up, it is configured as follows:
//
// 1. Display clear
// 2. Function set:
//    DL = 1; 8-bit interface data
//    N = 0; 1-line display
//    F = 0; 5x8 dot character font
// 3. Display on/off control:
//    D = 0; Display off
//    C = 0; Cursor off
//    B = 0; Blinking off
// 4. Entry mode set:
//    I/D = 1; Increment by 1
//    S = 0; No shift
//
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
// LiquidCrystal constructor is called).

LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_addr, uint8_t lcd_cols, uint8_t lcd_rows, uint8_t charsize)
{
	_addr = lcd_addr;
	_cols = lcd_cols;
	_rows = lcd_rows;
	_charsize = charsize;
	_backlightval = LCD_BACKLIGHT;
}

void LiquidCrystal_I2C::begin() {
	Wire.begin();
	_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;

	if (_rows > 1) {
		_displayfunction |= LCD_2LINE;
	}

	// for some 1 line displays you can select a 10 pixel high font
	if ((_charsize != 0) && (_rows == 1)) {
		_displayfunction |= LCD_5x10DOTS;
	}

	// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
	// according to datasheet, we need at least 40ms after power rises above 2.7V
	// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
	delay(50);

	// Now we pull both RS and R/W low to begin commands
	expanderWrite(_backlightval);	// reset expanderand turn backlight off (Bit 8 =1)
	delay(1000);

	//put the LCD into 4 bit mode
	// this is according to the hitachi HD44780 datasheet
	// figure 24, pg 46

	// we start in 8bit mode, try to set 4 bit mode
	write4bits(0x03 << 4);
	delayMicroseconds(4500); // wait min 4.1ms

	// second try
	write4bits(0x03 << 4);
	delayMicroseconds(4500); // wait min 4.1ms

	// third go!
	write4bits(0x03 << 4);
	delayMicroseconds(150);

	// finally, set to 4-bit interface
	write4bits(0x02 << 4);

	// set # lines, font size, etc.
	command(LCD_FUNCTIONSET | _displayfunction);

	// turn the display on with no cursor or blinking default
	_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
	display();

	// clear it off
	clear();

	// Initialize to default text direction (for roman languages)
	_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;

	// set the entry mode
	command(LCD_ENTRYMODESET | _displaymode);

	home();
}

So as you said earlier,these functions (delay, delayMicroseconds) need timer 0 in normal mode. But i have changed prescaler and as well as pwm mode for it. I am guessing i cant use lcd in my project. Any idea on how i can make this work? Maybe if i modify the library code so that it may work? What kind of changes does it need? And how to make changes in .cpp files?

Rishi_kesh:
Any idea on how i can make this work?

No.

Maybe if i modify the library code so that it may work? What kind of changes does it need?

I'm not familiar with that library.

And how to make changes in .cpp files?

You can copy them (and the .h files) into your sketch folder and they will show up as tabs in the IDE.

I'd look for a board that has more timer resources and also with an available LCD library that doesn't require the timers you need. Maybe a Teensy 3.x or a SAMD-based board.

I could have used a parallel display instead :confused: but anyways Thanks :slight_smile: