Atmega328 portc malfunction

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

This thread was originally created by jas823 in the Project forum and it seems to have disappeared while trying to move it.

Please don't pm people with questions, keep it public.

 

Hello,

I am having a issue with writing digital output to portC of the atmega328. When I write the output it somehow gets cleared and I see it on my logic analyzer. I am using pointers to access the ports since I save the pin mappings for an LCD connection. When using Portd or PortB I have no issues with the code, but when I put any of the pins of the LCD to portC it doen't work. I was wondering if there is a hidden issue with alternative functions that I am not seeing and wanted to know if you seen this issue before? I added my code and two waveforms from the logic analyzer. Waveform.png is the working waveform with the LCD rs pin on portb, and that is changed in the init function. If i put it on portc pin 5, the resulting waveform is the brokenwaveform.png.

 

Thanks,

 

Justin

Attachment(s): 

Image icon waveform.png

File lcd_4_bit.c

File lcd_4_bit.h

File main.c

Image icon BrokenWaveform.PNG

 

jas823

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

js wrote:
If i put it on portc pin 5, the resulting waveform is the brokenwaveform.png.

data->rs.pin = 3;
    data->rs.port = &PORTC;
    data->rs.portd = &DDRC;

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Editorial note:  IMO, what a convoluted mess for "generic" init.  And one still has to examine and tailor every line that might be pertinent.

 

Someone (perhaps the same person that encouraged gratuitous use of |= ) must have brainwashed trained that pointers and a level of indirection is the One True Way.  Regardless of cycle efficiency or code size efficiency or introducing possible RMW effects.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

PORTC is powered from AVCC while the rest runs from VCC.

Maybe AVCC is loose / unreliable?

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

If you put it on any portc pin the result is the same brokenwaveform.png

jas823

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

I will look into this, I didn't think to look at that fact.

jas823

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

I don't understand your comment with the |= ...? how else would you set values to the port with not affecting other bits of that port. Also how could I clean up the Init function but still have the same affect as what its doing now? As of now that was the only way I could think about doing it without touching the rest of the functions so that I can easily put the wires on any port/pin combination. I wanted to make it so that way whatever pin was available after wiring up sensors and such, it would only be a few lines of code to change. The way it is now all the pins are isolated from one another in a sense.

jas823

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

Paulvdh wrote:
PORTC is powered from AVCC while the rest runs from VCC. Maybe AVCC is loose / unreliable?

Not really true -- on that series, port C power is split.

AV
CC is the supply voltage pin for the A/D Converter, PC3:0, and ADC7:6.
 

...but while OP says

jas823 wrote:
If you put it on any portc pin the result is the same brokenwaveform.png

...the worked example is not consistent on channel.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Sorry if it seems inconsistent! The result of using portc pin 3 or 5 results in the same brokenwaveform.png. Currently I didn’t hook up the AVcc pin , I didn’t realize it was a requirement. I read the data sheet and will try hooking it up later after work. However, pinc5 and pinc4 appear to be powered with digital power (Vcc) and the rest of port c is from Avcc. As I mentioned previously the code responds the same way as the brokenwavform.png when on pin 5 regardless of what the code shows I tried them all! The only thing I didn’t try is connecting Avcc.

Thanks
Justin

jas823

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

jas823 wrote:
Currently I didn’t hook up the AVcc pin , I didn’t realize it was a requirement.

Well, if you don't do that you are violating Absolute Maximum Ratings; you will be in permanent brown-out (you ARE using a brown-out detector, aren't you?) depending how the pin floats and the load; you will get intermittent port operation; and probably other interesting symptoms.

 

So I still come back to the inconsistent code -- indeed I might expect your symptoms on PC3.  But as you said PC5 I discounted that.  There is a reason for each question I ask.

 

Interestingly, your setup might well work on a Mega8 or Mega8A.  The reason is left as an exercise for the reader.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

jas823 wrote:
Currently I didn’t hook up the AVcc pin , I didn’t realize it was a requirement
A curious statement.  Page 3 of the datasheet:

1.1.7
AV CC
AV CC is the supply voltage pin for the A/D Converter, PC3:0, and ADC7:6. It should be externally connected to V CC ,
even if the ADC is not used.
If the ADC is used, it should be connected to V CC through a low-pass filter. Note that
PC6...4 use digital supply voltage, V CC .

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Thanks for the reply,

 

I am not using a brown-out detector. This is a simple project Im working on and Im in just trying to create some libraries at the moment. I found the first statement about maximum ratings interesting, how did you deduce that from the datasheet. I don't know much about using the brown out detector since I never had the need.

 

I am going to try connecting the AVcc to power though and get a new wavform of the LCD pins to see if the new connection helps. Intersingly enough though, both PC5 and PC3 go high as intended but go low before sending the Nibbles, but if I comment out the three lines in the init function and switch the rs pin to use portb or portd the code works as intended. so with that, it seems strange that there is a code fault. I will keep on chugging along,

 

Thanks

jas823

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

jas823 wrote:

I don't understand your comment with the |= ...? how else would you set values to the port with not affecting other bits of that port.

Note that that isn't really what I said...

Someone (perhaps the same person that encouraged gratuitous use of |= ) must have brainwashed trained that pointers and a level of indirection is the One True Way.  Regardless of cycle efficiency or code size efficiency or introducing possible RMW effects.

In no particular order:

-- Why are you trying to make your own 4-bit HD44780-compatible LCD driver?  What is wrong with the existing implementations?

-- There are other "generic" implementations like Fluery...

-- ... but they resolve things at compile time, and are thus fairly efficient.

-- Generally, when common 'Freaks like me create an AVR8 app, it is a microcontroller and we try to make things compact and efficient..

-- Your approach will be bloated on code size.  It will be bloated in cycles used.  It will waste microcontroller time at the millisecond level.

-- Depending on the rest of the app it opens the possibility of RMW effects.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

jas823 wrote:
I found the first statement about maximum ratings interesting, how did you deduce that from the datasheet.

 

There are many other places (at least six) in the datasheet that make it clear you must connect AVCC.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

This isn't like a professional project, I like and prefer to try and code my own things. Its nice tho because problems like this help me and others learn. I just found the problem and fixed it.

 

1) I connected AVcc to power and that didn't fix the issue

 

2) to fix the issue, in the header file  I changed my struct to volatile uint_8 and now the code works. So now I can just change the mappings in the init function and I can put the LCD pins anywhere.

 

typedef struct{

      volatile uint8_t pin;

      volatile uint8_t *port;

      volatile uint8_t *portd;

}PINDATA;

 

typedef struct{

      PINDATA d7;

      PINDATA d6;

      PINDATA d5;

      PINDATA d4;

      PINDATA rs;

      PINDATA enable;

      PINDATA backlight;

}LCD;

 

I realize this is not how others would implement this but I was trying something different,

 

Thanks for all the guidance, your comments forced me to look further into other topics and it was quite useful

jas823

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

1) I connected AVcc to power and that didn't fix the issue

Yeah, but... you >>still<< need to connect AVCC.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Well not really...the chip will eventually die...but you don't have to do anything, it's a free country....devil

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Yea I did connect Avcc, i left it connected

 

jas823

Last Edited: Mon. Sep 10, 2018 - 09:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jas823 wrote:

This isn't like a professional project, I like and prefer to try and code my own things.

When you were old enough to want to drive an automobile, did you build your own?

 

2) to fix the issue, in the header file  I changed my struct to volatile uint_8 and now the code works.

I was pondering your symptoms, even in the light of inconsistent example evidence.  Then, when you presented your "fix", more pondering ensued.

 

This is one of the cases where indirect access to I/O can bite.  As mentioned earlier, OP loves pointers and indirection.  Without the volatile a simple extract of your code such as

     *data->enable.port |= 1 << data->enable.pin;
    ...
    *data->enable.port &= ~(1 << data->enable.pin);

 

...looks like it "doesn't work", as the optimizing compiler will see that the code sequence does nothing useful.  Did you look at the "doesn't work" generated code, or present it to us for examination?

 

Now, why port B "works" is levt as an exercise for the student.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

lol no I never wanted build a car from scratch haha

 

but the very first attachment at the top of this thread has the code that doesn't work. But even before adding the volatile keywords, for some reason portb and portd worked fine? That has me puzzled since the compiler didn't optimize that code out. When adding the keyword, the code works fine, I since tried moving pins around the microcontroller and redefining the pins and haven't been able to bug it out. What would be a good way to do what my code is doing without using pointers.

Just use defines?

 

Thanks

jas823

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

jas823 wrote:
but the very first attachment at the top of this thread has the code that doesn't work.

I'm talking about the compiler-generated code to implement your source.

jas823 wrote:
for some reason portb and portd worked fine? That has me puzzled since the compiler didn't optimize that code out.

Context-context-context.

theusch wrote:
Did you look at the "doesn't work" generated code, or present it to us for examination?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.