Am I stupid? Polling a pin

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

Hello, I've been spending many hours by now polling a pin.

 

Usually, all Pins of DDRA of my Atmega1284 are configured as outputs (DDRA = 0b11111111). But at a certain point I want to poll PIND7 for a low state:

 

#define D7        PORTA7

...

DDRA &= ~(1 << D7);

// 		for (int i = 0; i < 50; i++)
// 		{
// 		    EN_HIGH;
// 		    _delay_us(tdel);
// 		    EN_LOW;
// 	            _delay_us(tdel);
// 		}
                
while(PINA & (1 << D7))
            
{
    EN_HIGH;
    _delay_us(tdel);
    EN_LOW;
    _delay_us(tdel);
}
    
DDRA |= (1 << D7);

 

When i run the the code from the commend, all works fine. That tells me, that the PORT is configured correctly. It just seems to be unable to read the pin.

 

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

What are EN_HIGH and EN_LOW?

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

Try this:

 

DDRA  = 0x7F;   //PortA7 input, all others output

while(PINA & 0x80)          //test PortA7 for logic high

{
    EN_HIGH;
    _delay_us(tdel);
    EN_LOW;
    _delay_us(tdel);
}

Untested.

 

Keep in mind you also will need to have a pull down resistor on PortA7 if you are going to apply a logic one to the pin. 

 

If you plan on pulling the pin to ground, then you will either have to add a pull up to the pin, OR use the internal pullup on the AVR.

 

Jim

 

EDIT:  Not sure you can out a variable in side the parenthesis for _delay_us()

 

 

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

Last Edited: Sun. Sep 17, 2017 - 08:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:

What are EN_HIGH and EN_LOW?

 

They are for the LCD (HD44780). I want to read the BUSY-Flag

Last Edited: Sun. Sep 17, 2017 - 08:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you reading the busy-bit of a character LCD display, perhaps?

 

[ EDIT: Yes you are ;-) ]

 

It is my opinion that there is a widespread misunderstanding of how the busy-bit works. Confusing data sheets helps to keep this misunderstanding alive.

 

The busy bit is a bit in an eight bit byte sent from the LCD controller when R/W is set to read the LCD. This eight bit byte is asserted on DB0..DB7 while the Enable signal is high.

 

I.e. : In order to get the busy bit you need to do a read of a complete byte.

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Sun. Sep 17, 2017 - 08:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:

Are you reading the busy-bit of a character LCD display, perhaps?

 

It is my opinion that there is a widespread misunderstanding of how the busy-bit works. Confusing data sheets helps to keep this misunderstanding alive.

 

The busy bit is a bit in an eight bit byte sent from the LCD controller when R/W is set to read the LCD. This eight bit byte is asserted on DB0..DB7 while the Enable signal is high.

 

So you are familiar with that problem? From the LCD's datasheed provided by the manufacturer it is not quite clear wether the enable-signal is a clock or something like the CS-signal of the SPI interface. So the only thing I have to to is: RS -> LOW, RW -> HIGH and EN -> HIGH and wait for D7 to go low?

 

EDIT:

 

D0 is the Enable Signal

D1 is RS

D2 is RW

D3 is D7

 

It takes about 1.5ms till D3 goes low which makes me strongly believe, that D7 is the busy flag (datasheet says 1.64ms for clearing the LCD).

 

As you can see, I send a few clock pulses and it semms to work. If I try to poll D7 it crashes.

 

EDIT: BOOOM I solved the problem!

Attachment(s): 

Last Edited: Sun. Sep 17, 2017 - 08:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You still do not understand. You have to read a whole byte, then once that byte is in your possession, you can test that one bit from the byte. Do not "poll" as port pin. Read the entire byte.

 

Jim

 

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

The character LCD displays have a 44780 controller on-board (or a compatible alternative). There are two data sheets available for the 44780, one from Optrex and one from Hitachi. I prefer the latter. Do download it, e.g. from here: https://www.sparkfun.com/datashe... .

 

Now, look at e.g figure 15 (p32). Admittedly that is not crystal clear either, but I believe it supports my case.

 

It's been a long time since I did any Busy-flag checking, so I'm working from memory here..

 

Here's what I might do (8-bit mode, assuming DB0..7 is on a port called LCD_DATA, and RS, R/W and Enable is on a port LCD_CTRL on pins RS, RW and E). This is sketchy - I'm just typing this stuff into the forum from my head. Be warned!

 

#define LCD_DATA_DIR DDRD
#define LCD_DATA_PIN PIND
#define LCD_CTRL PORTB

#define RS 0
#define RW 1
#define E  2

#define BUSY_BIT 7

uint8_t LCD_read() {
    uint8_t retVal;
    
    // Set the data port to input
    LCD_DATA_DDR = 0x00;

    // Set R/W to "read"
    LCD_CTRL &= ~(1<<RW);
    
    // Assert the Enable signal
    LCD_CTRL |= (1<<E);
    
    // Might need a delay here
    
    // Get the byte
    retVal = LCD_DATA_PIN;
    
    
    // Clear the Enable signal
    LCD_CTRL &= ~(1<<E);
}

void someFunction() {
    
    // Wait for Busy flag to be clear
    while (LCD_read() & (1<<BUSY_BIT));
    
    // LCD now not busy
    .
    .
    .
}

Do note that I have been sloppy in the code above! E.g. no proper coding for the timing constraints of the RS, R/W and Enable signals. Also, I've ignored to reset the direction register, and the R/W pin after the wait is done. (Failing to get that right will give you a good head-ache while debugging unless you're in possession of a logic analyzer or a oscilloscope capable of doing a '"one-shot".) I'm only trying

 

So, as you can see there is some work involved to get this going. Some claim it's not worth it, and instead rely on spin-loop delays to guarantee that the display will not be overrun. IMO "it depends"..

 

Jacky_88 wrote:
So you are familiar with that problem?

Yes. The duscussion on the Busy flag has been here more or less from the start of the forum, i.e. about 15 years.

 

Jacky_88 wrote:
So the only thing I have to to is: RS -> LOW, RW -> HIGH and EN -> HIGH and wait for D7 to go low?

No. You need to read a byte from the LCD and isolate the Busy  bit in. IOW do a complete read cycle. Involves R/W, Enable and the direction of the port that the data pins are on. Please look in the data sheet I linked to for illustrations.

 


 

If you're actually in 4-bit mode (as you should be ;-) ) Then you need to do two reads to get both the high and low nibble. The Busy bit is in the high nibble (the first of the two nibbles).

 


 

 

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

cheeky(laugh)

 

Thank you for your help JohanEkdahl and ka7ehk. I will try to implement your solution tomorrow. For now, I'm happy it "works". One has to be very careful when to pulse the enable signal.

Attachment(s): 

Last Edited: Sun. Sep 17, 2017 - 09:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I.e. : In order to get the busy bit you need to do a read of a complete byte.

Wow, learn something every day.

 

I haven't written an LCD driver in quite a while, but I recall having trouble with the Busy Bit.

I finally gave up and put in a delay.

 

Now I know why it didn't work, I was trying to read, i.e. monitor, the status of just the bit...

 

JC 

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

I normally use the datasheet for the KS0066U (a HD44780U compatible) as backup. It seems more clear and concise, in my opinion.

 

Edit: there is indeed something very weird going on with that pdf. This one is searchable.

Last Edited: Sun. Sep 17, 2017 - 11:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, too long since I've dabbled with CLCDs to remember that. Good call El Tangas! Then it'll be figures 4 and 5 in that then (and of course the text re the busy flag...).

 

(But either my PDF reader is acting up, or that PDF is not searchable..)

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Why not simply use Peter Fleurys LCD library and forget about everything?
So much simpler

Jim

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

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

And some notes on my sketchy code above:

 

  • Consider isolating the functionality into a function like
    LCD_busy_wait();
    that blocks until the busy flag is clear.
  • Consider implementing a timeout mechanism, i.e. if the busy flag never clears then make it stop in some other way.
  • Consider letting it have a return value indicating if it timed out.
  • Consider using that return value.
  • Do not forget to reset signals and directions to what is needed to write to the LCD. Either let the LCD_busy_wait() function save the old values and when returning it resets everything to what it was (everything = RS, R/W and the port direction for the DB7..0 signals). Or make sure writes as well a reads, start out always setting signals and directions as they need them to be. 

Finally:

  • Unless this is for your own learning experience, consider using one of the established CLCD "libraries" out there. E.g. Google "Fleury character LCD", "danni character LCD". Let us know if you need absolute links.
    EDIT: I see Jim was anticipating this last advice of mine ;-) Links: http://homepage.hispeed.ch/peter...http://www.avrfreaks.net/forum/t...

 

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Sun. Sep 17, 2017 - 11:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Forgot this:

 

From time to time I've seen people doing the busy-wait right after sending something to the LCD. Don't do this. It will only unnecessarily waste CPU cycles.

 

Instead, do the busy-wait just before you send something to the LCD. This way, there is a higher likelihood that the LCD will not be busy, or that the waiting time will be shorter.

 

In other words: Your AVR can do other meaningful things while the LCD starts processing what you've sent, rather than immediately after a write hang and wait for the busy-flag to clear.

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

DocJC wrote:
but I recall having trouble with the Busy Bit. I finally gave up and put in a delay.

 

History is starting to come into focus.

 

As a busy-bit reader, I've been well-scoffed here over the years.  "No need!"  "Takes extra time!"  (and it usually turns out that comes from those in the 'delay' camp that take extra time on each operation)

 

Perhaps the non-Busy people just gave up.  What is that parable -- sour grapes?

 

===============

Back to OP's OP:  What does PD7 have to do with PA7?  But the eventual guess of busy-bit clears it up some.

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

JohanEkdahl wrote:

If you're actually in 4-bit mode (as you should be ;-) ) Then you need to do two reads to get both the high and low nibble. The Busy bit is in the high nibble (the first of the two nibbles).

Good point - you need to complete the entire 2-nybble read, or the device will probably be stuck in some weird in-between state.  This should already be abstracted out into a read_lcd_byte() function of some sort anyway.

 

Quote:

From time to time I've seen people doing the busy-wait right after sending something to the LCD. Don't do this. It will only unnecessarily waste CPU cycles.

 

Instead, do the busy-wait just before you send something to the LCD. This way, there is a higher likelihood that the LCD will not be busy, or that the waiting time will be shorter.

 

In other words: Your AVR can do other meaningful things while the LCD starts processing what you've sent, rather than immediately after a write hang and wait for the busy-flag to clear.

Yes, this is an excellent principle for using anything that must turn from 'busy' to 'ready' before you can use it.  Sending chars on a UART is another good example.  Only wait when you must wait - that is, just before you're ready to load some new data into the device, or whatever it might be.

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

I've got a HD44780 library as a project here that you can look through as an example.

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

kk6gm wrote:
Yes, this is an excellent principle for using anything that must turn from 'busy' to 'ready' before you can use it. Sending chars on a UART is another good example. Only wait when you must wait - that is, just before you're ready to load some new data into the device, or whatever it might be.

 

Just some thoughts on this process

 

Store the data to be sent in a buffer & use a timed interrupt routine to perform the actual write/send.

check for busy on entry to the IRQ & if busy exit immediately,  this way you code never waits.

 

The wait time should never bee too long on an LCD anyway so with a bit of care you should even be able to detect some fault conditions  (ie nothing has been removed from the buffer for an excessive period of time) & possibly attempt to recover.

 

 

 

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

Ohh, the discussion went on - while I slept laugh
 
Today I started using D6-D0 as well. The screenshot (E -> D0, RS -> D1, RW -> D2, D0:D7 -> D8:D15) shows whats going while waiting for the busy flag.

Im doing this as learning project, so it just needs to work - there are no further requirements to meet. I think it's ok to just look at D7, since this is my opinion the busy flag. I don't see any necessity to read the complete byte (or am I wrong?). But on the other hand this is good practice for reading a parallel bus or to write a reading method to do a check on the existing data in the controller.

Why should I use the display in 4bit-mode?

What I realy need to do ist to rewrite my LCD "framework". Yesterday I had the idea to use a timer for generating the enable signal and change data on the port on the rising edge. The difficulty was to "find" the rising edge. Using a timer in CTC mode fires an interrupt event when OCRnA is reached. Then OCnA is toggled and generates a square wave of a frequency defined by OCRnA. I tried reading the OCnA status but it takes a few us which makes the method unreliable with higher speeds

 

P.S.: How do I make a timeout?

Attachment(s): 

Last Edited: Mon. Sep 18, 2017 - 03:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You don't need to read the complete byte, but you do need to keep pulsing Enable with RW high and RS low, or the flag won't be updated (the output is a latch).

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

Are you wrong? Time will tell..

But it is clear that in 4 bit mode you MUST do a read in order to get the bysy bit. My basis for the need for a read is that it makes no sense that 8 bit mode should be different in this respect.

No logic analyzer/scope, then?

Having the Enable as a steady pulse train is...just weird. If you for some reason get stuck in another part of the program for just a teeny while you'll send something unintended to the LCD.

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

JohanEkdahl wrote:
Having the Enable as a steady pulse train is...just weird.
;)

Here is my "busy" routine.  Quite a bit of noise for you innocent bystanders to work through, as it is "soft" to not hang forever, and configuration info is buried in some of the variables.

unsigned char _lcd_ready(void)
{

#asm
	ldi r24, __lcd_lcount	; load to a register
    in    r26,__lcd_direction
    andi  r26,0xf                 ;set as input
    out   __lcd_direction,r26
    sbi   __lcd_signal_port,__lcd_rd     ;RD=1
    cbi   __lcd_signal_port,__lcd_rs     ;RS=0
__lcd_busy:
	dec r24			; one less of the allowed loops
	breq __lcd_busy_abort	; timeout; log the error
    rcall __lcd_delay
    sbi   __lcd_signal_port,__lcd_enable ;EN=1
    rcall __lcd_delay
    in    r26,__lcd_pin
    cbi   __lcd_signal_port,__lcd_enable ;EN=0
    rcall __lcd_delay
    sbi   __lcd_signal_port,__lcd_enable ;EN=1
    rcall __lcd_delay
    cbi   __lcd_signal_port,__lcd_enable ;EN=0
    sbrc  r26,__lcd_busy_flag
    rjmp  __lcd_busy
__lcd_busy_ret:
	ret
__lcd_busy_abort:
#endasm
// Too many wait loops--log an error
	_lcd_ecount++;
}

 

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

IPguru wrote:

Store the data to be sent in a buffer & use a timed interrupt routine to perform the actual write/send.

check for busy on entry to the IRQ & if busy exit immediately,  this way you code never waits.

I've done this but without even bothering to check for busy, because the interrupt intervals were guaranteed longer than the maximum LCD busy time.  Never had a problem.

 

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

Jacky_88 wrote:

Why should I use the display in 4bit-mode?

Because GPIO are usually valuable commodities, and you can probably find a good use for the 4 GPIO that you save by using 4-bit mode.  You might even be able to use a smaller and cheaper micro.

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

kk6gm wrote:
I've done this but without even bothering to check for busy, because the interrupt intervals were guaranteed longer than the maximum LCD busy time.
Certainly one can use inherent intervals as a timing mechanism.

 

So you send one character from a buffer each ISR.  You "know" the positioning, so you only need to send the data byte?  I guess that infers that the only thing your "driver" does is send data bytes to next screen location.

 

No cursor on/off, or other similar positioning?

 

You "burn" ISR overhead for each character.  I guess we could call the overhead a couple microseconds, depending on AVR clock rate.  I don't have a datasheet with the timings handy; I guess the few microseconds for the ISR handling is not much different than the wait time for a vanilla write?

 

As discussed in some prior threads, in some apps I "prove" [or at least test for] display present and functioning with read-back.  I suppose that is an unnecessary frill.

 

 

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

JohanEkdahl wrote:

Are you wrong? Time will tell..

But it is clear that in 4 bit mode you MUST do a read in order to get the bysy bit. My basis for the need for a read is that it makes no sense that 8 bit mode should be different in this respect.

A representative HD44780[U] datasheet has a timing diagram for both 8-bit and 4-bit modes.  The diagrams reinforce what has been said.

8 bit:

4 bit:

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.