ATmega328P: repetitive register write commands weird result after compilation

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just few days ago I moved from Arduiono IDE to Atmel Studio 7. I am trying to create my own 1602a LCD screen driver for ATmega 328P MCU. In course of writing an initialization procedure I have ran over a strange behavior of the compiled code that I can't understand nor overcome.

 

E input of the LCD is connected to the PINC2 of the MCU, and PINC2 configured as output. The following code:

    PINC = 0B00000100;
    _delay_us(1000);
    PINC = 0B00000000;
    _delay_us(1000);
    PINC = 0B00000100;
    _delay_us(1000);
    PINC = 0B00000000;
    _delay_us(1000);
    PINC = 0B00000100;  //<-- missed
    _delay_us(1000);
    PINC = 0B00000000;
    _delay_us(1000);
    PINC = 0B00000100;  //<-- missed

 

results in signals as shown on the screenshot: two last repetitions of 1 are missed.

 

In 4-bit mode to send a byte I require to set E high and low twice. If write 1 to PINC2 twice, the second 1 never appears on the MCU output.

 

I suspect this is somehow connected with the code optimisation that compiler does, but can't find any useful hints on how to overcome it. Please, help.

 

P.S. This is an Arduino VaNILLIN board. Fuses are configured as follows:

avrdude.exe: safemode: lfuse reads as 0
avrdude.exe: safemode: hfuse reads as 0
avrdude.exe: safemode: efuse reads as 0
avrdude.exe: safemode: Fuses OK (E:00, H:00, L:00)

 

MCU timed from external 16 MHz oscillator

Attachment(s): 

This topic has a solution.

Just to let you know...

Last Edited: Fri. Nov 20, 2020 - 10:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've compiled your bit of code with every optimization setting on both the C and C++ compilers and the generated code looks correct.

 

If those fuses readings are correct, the watchdog timer is enabled with the WTDON fuse. Maybe the watchdog is resetting before third pulse is generated.

 

What do you see if you half or double the delay values?

Last Edited: Fri. Nov 20, 2020 - 10:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nothing changes except the duty cycle. Tried both shortening and doubling the delays. Here is the screenshot with the doubled delays.

Attachment(s): 

Just to let you know...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And here is what I get when I repeat this code three times:

        PINC = 0B00000100;
	_delay_us(2000);
	PINC = 0B00000000;
	_delay_us(2000);
	PINC = 0B00000100;
	_delay_us(2000);
	PINC = 0B00000000;
	_delay_us(2000);
	PINC = 0B00000100;
	_delay_us(2000);
	PINC = 0B00000000;
	_delay_us(2000);
	PINC = 0B00000100;
	_delay_us(2000);
	PINC = 0B00000000;
	_delay_us(2000);
	PINC = 0B00000100;
	_delay_us(2000);
	PINC = 0B00000000;
	_delay_us(2000);
	PINC = 0B00000100;
	_delay_us(2000);
	PINC = 0B00000000;
	_delay_us(2000);
	PINC = 0B00000100;
	_delay_us(2000);
	PINC = 0B00000000;
	_delay_us(2000);
	PINC = 0B00000100;
	_delay_us(2000);
	PINC = 0B00000000;
	_delay_us(2000);
	PINC = 0B00000100;
	_delay_us(2000);
	PINC = 0B00000000;
	_delay_us(2000);

 

Attachment(s): 

Just to let you know...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is the LCD wired to the MCU?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are some interrupts getting it busty doing something else?  You would see those line grind to a halt for a while

 

Put it in a non-stop loop...what do you  get?

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yep! RS, RW, EN and D4...D7 lines, all are wired.

Just to let you know...

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

PINC is the input register, and when the pin is set to an output, writing a 1 to a PINC bit will toggle the output. Writing a 0 does nothing. So every time you write a 1 to PINC the pin output toggles, which I think matches what you see.

 

Replace PINC with PORTC and you will be closer the what you want, although using PINC (correctly) is a better idea so you can leave all the other port bits untouched.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

 

Note that you can put the image in the post - where we can see it:

 

 

See Tip #1 in my signature, below:

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Everything looks smooth, all the timings are perfectly equal.

 

        while(1)
	{
		PINC = 0B00000100;
		_delay_us(1000);
		PINC = 0B00000000;
		_delay_us(1000);
		PINC = 0B00000100;
		_delay_us(1000);
		PINC = 0B00000000;
		_delay_us(1000);
		PINC = 0B00000100;
		_delay_us(1000);
		PINC = 0B00000000;
		_delay_us(1000);
	}

 

Attachment(s): 

Just to let you know...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks! That helped! Obvious things are often left unnoticed nearby! :-)

Just to let you know...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the hint! Sorry, I am a novice here!

Just to let you know...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks to all who tried to help me! Really appreciate!

Just to let you know...