0

I'm currently writing a library for learning purposes and I've run into a weird problem.
So,
1. I have a function in the main body (main.c) that reads the DDRAM address of an LCD.
2. I move the exact same function into the library file (HD44780.c).
3. I include the header file (HD44780.h) in the main body.
When I call the function from the main body, I get a result of 64. Correct.
When I call the same function from the library, immediately after the previous call, I get a result of 87. False.
Maybe it has something to do with the library files and the reachability of the functions. My library is split into three files.

  • HD44780.h (includes HD44780_Config.h and HD44780.c and head guards)
  • HD44780.c (does not include anything)
  • HD44780_Config.h (includes HD44780.h and has head guards)

Any idea? If more information is needed, just ask.

Main.c

#define F_CPU 16000000L

#include <util/delay.h>
#include <avr/io.h>
#include "IO_macros.h"  
#include "HD44780.h"

uint8_t _read(void);

int main(void)
{
    uint8_t x1, x2;

    LCD_setup();

    LCD_gotoXY(0,1);
    x1 = _read();    //64, Correct answer
    x2 = LCD_read(); //87, False answer

    return 0;
}

uint8_t _read(void)
{
    uint8_t status = 0;

    pinMode(LCD_D4, INPUT);             //D7:D4 = Inputs
    pinMode(LCD_D5, INPUT);
    pinMode(LCD_D6, INPUT);
    pinMode(LCD_D7, INPUT);
    digitalWrite(LCD_RS, LOW);          //RS = 0
    digitalWrite(LCD_RW, HIGH);         //RW = 1

    //High nibble comes first
    digitalWrite(LCD_EN, HIGH);     
    _delay_us(LCD_PULSE_US);
    status |= digitalRead(LCD_D4)<<4;
    status |= digitalRead(LCD_D5)<<5;
    status |= digitalRead(LCD_D6)<<6;
    digitalWrite(LCD_EN, LOW);

    //Low nibble follows
    digitalWrite(LCD_EN, HIGH);     
    _delay_us(LCD_PULSE_US);
    status |= digitalRead(LCD_D4);
    status |= digitalRead(LCD_D5)<<1;
    status |= digitalRead(LCD_D6)<<2;
    status |= digitalRead(LCD_D7)<<3;
    digitalWrite(LCD_EN, LOW);

    pinMode(LCD_D4, OUTPUT);            //D7:D4 = Outputs
    pinMode(LCD_D5, OUTPUT);
    pinMode(LCD_D6, OUTPUT);
    pinMode(LCD_D7, OUTPUT);
    digitalWrite(LCD_RW, LOW);          //RW = 0

    return status;
}  

HD44780.h

#ifndef HD44780_H_  
#define HD44780_H_  

#include "HD44780_Config.h"  
//Irrelevant function definitions...
extern uint8_t LCD_read(void);

#endif

HD44780_Config.h

#ifndef HD44780_CONFIG_H_
#define HD44780_CONFIG_H_

#include "HD44780.h"

//----- Configuration --------------------------//
//Irrelevant definitons here
//----------------------------------------------//
#endif  

HD44780.c

//Irrelevant functions precede...
uint8_t LCD_read(void)
{
    uint8_t status = 0;

    pinMode(LCD_D4, INPUT);             //D7:D4 = Inputs
    pinMode(LCD_D5, INPUT);
    pinMode(LCD_D6, INPUT);
    pinMode(LCD_D7, INPUT);
    digitalWrite(LCD_RS, LOW);          //RS = 0
    digitalWrite(LCD_RW, HIGH);         //RW = 1

    //High nibble comes first
    digitalWrite(LCD_EN, HIGH);
    _delay_us(LCD_PULSE_US);
    status |= digitalRead(LCD_D4)<<4;
    status |= digitalRead(LCD_D5)<<5;
    status |= digitalRead(LCD_D6)<<6;
    digitalWrite(LCD_EN, LOW);

    //Low nibble follows
    digitalWrite(LCD_EN, HIGH);
    _delay_us(LCD_PULSE_US);
    status |= digitalRead(LCD_D4);
    status |= digitalRead(LCD_D5)<<1;
    status |= digitalRead(LCD_D6)<<2;
    status |= digitalRead(LCD_D7)<<3;
    digitalWrite(LCD_EN, LOW);

    pinMode(LCD_D4, OUTPUT);            //D7:D4 = Outputs
    pinMode(LCD_D5, OUTPUT);
    pinMode(LCD_D6, OUTPUT);
    pinMode(LCD_D7, OUTPUT);
    digitalWrite(LCD_RW, LOW);          //RW = 0

    return status;
}
//...irrelevant functions follow  

Update #1
I'm using the Atmel Studio 6 to compile. Default optimization level (-O1).
Update #2
I've checked the preprocessor outputs and they're also identical.
Update #3
Consequtive readings has false result due to the address being increased/decreased with each reading. The problem still persists though. It has to do with the location of the function, but I do not know what it is.
If I call the function in the main.c, it works.
If I call it from HD44780.c, it doesn't work properly.
#Update #4
A guy in another forum solved my problem. You may check my answer below.

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
Efthymios
  • 253
  • 3
  • 10
  • Is there (in HD44780.h) the prototype of function? – LPs Nov 15 '16 at 13:09
  • 2
    Simplify your code. Take stuff out until you have a minimal repro case. – John Zwinck Nov 15 '16 at 13:14
  • how do you compile and link it all? – Michał Walenciak Nov 15 '16 at 13:16
  • I have included only the relevant code. I've also included the code of the function just to show you it is the same in both files. Please re-read now. – Efthymios Nov 15 '16 at 13:17
  • Sounds like a difference in defined preprocessor symbols. I suggest you set compiler to output preprocessed source code for both functions, and then compare the results. – user694733 Nov 15 '16 at 13:34
  • How is this possible? All the definitions are contained within the same file (**HD44780.h**) and are not changed throughout the program. – Efthymios Nov 15 '16 at 13:37
  • Why is LCD_read() in HD44780.h declared "extern"? – Rev Nov 15 '16 at 14:06
  • Shouldn't it be extern? "Extern" being present or not doesn't seem to change anything in the outcome. – Efthymios Nov 15 '16 at 14:12
  • @user694733 I've no understood what you've said to me. I've checked the preprocessor outputs for both files and they' re identical. – Efthymios Nov 15 '16 at 14:36
  • You have a circular dependency. `HD44780.h` includes `HD44780_Config.h` that include `HD44780.h` – LPs Nov 15 '16 at 14:55
  • @LPs Too bad this wasn't the case. I have just tested it out. Also, the head guards in header files prevent the latter from being included twice. – Efthymios Nov 15 '16 at 15:15
  • What does `_read` and `LCD_read` actually try to read? Are you sure that repeated reads are supposed to return the same value? Do you get same results if you call `LCD_read` *before* `_read`? – user694733 Nov 15 '16 at 15:26
  • You are partially right. It has something to do with the consequtive readings. If I switch the order, then I get correct the first one in order and false the second one. To take one step further, I did the following. Goto (0,1), Read1, Goto (0,1), Read2 I'm still getting the same false results. – Efthymios Nov 15 '16 at 15:37
  • Hm... pretty interesting and weird behavior.. the code is the same.. have you checked its register and signals using hardware tools? To list possibilities, some kind of variables could have been changed between the operation or maybe timing. I also would like to know what caused different behavior. – Sean83 Nov 16 '16 at 04:29
  • How about once you operate the first one, alternatively for a temporary solution, reinit the LCD / connection and run it again like you are running it for the first time. – Sean83 Nov 16 '16 at 04:34
  • the posted code is missing the statement: `#include ` which is needed for the type: `uint8_t` – user3629249 Nov 16 '16 at 08:23
  • @user3629249 This is not the case. – Efthymios Nov 16 '16 at 09:15
  • @Sean84The problem persists even if I keep only one read. If I use the function in the **main.c**, it works. If I use the one in **HD44780.c**, it doesn't. I'm currently working on Proteus (which supports HW simulation). Proteus has never dissapointed me as far as the simulation is concerned. I'll get the chance to use the HW in about a week. – Efthymios Nov 16 '16 at 09:17
  • It is solved! A guy in another forum pointed the cause to me. You may check the answer below. – Efthymios Nov 16 '16 at 12:04
  • Please understand that Stack Overflow is not a forum, and we have different rules here. For example, please don't include [tags] in your title. – Jonathon Reinhart Nov 16 '16 at 12:15

2 Answers2

2

Looking at the controller manual at page 31:

After a read, the entry mode automatically increases or decreases the address by 1

That means that two consecutive read commands read two different address data.

EDIT

The previous designation determines whether CG or DDRAM is to be read. Before entering this read instruction, either CGRAM or DDRAM address set instruction must be executed. If not executed, the first read data will be invalid. When serially executing read instructions, the next address data is normally read from the second read. The address set instructions need not be executed just before this read instruction when shifting the cursor by the cursor shift instruction (when reading out DDRAM). The operation of the cursor shift instruction is the same as the set DDRAM address instruction.

Emphasis mine

LPs
  • 16,045
  • 8
  • 30
  • 61
  • You are partially right. After reading your comment, I tried re-placing the cursor again to the same position just to re-read it once more. **Goto**, **Read**, **Goto**, **Read** and I'm getting the same false results. I have to test it out further. – Efthymios Nov 15 '16 at 15:40
  • Having myself applied the whole day to this particular problem, made me dizzy. I'm able to understand neither your point nor the quote, although it seems you may have found the solution. May you put it simply please? – Efthymios Nov 15 '16 at 16:09
  • 1
    So, when I read from the LCD, the address is increased/decreased. If I want to re-read, I have to write something first, so the address is reset properly. I've managed to understand that and I've also tested it and it works as expected. The main problem persists though. If I keep only one read in program, I still the get correct one when I call the function in **main.c** and the false result when I call the one in **HD44780.c**. Thank you for spending your time trying to help me though. – Efthymios Nov 15 '16 at 16:30
1

The problem was at the definition of F_CPU.
It wasn't defined in the HD44780.c file. Every .c file is a standalone compilation unit that is linked with the rest .c files at compile time.
I defined the F_CPU only in main.c, so the _delay_us in HD44780.c had wrong F_CPU value. As a solution, I declared the F_CPU in the makefile of the solution so it's visible to ALL files. The cause and its solution are due to a guy in another forum, where I've asked the same question desperately.
Thank you all for your time!

http://www.avrfreaks.net/comment/2029541#comment-2029541

Efthymios
  • 253
  • 3
  • 10