Efthymios
Efthymios

Reputation: 263

Same function within different files returns different results

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.

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.

Upvotes: 0

Views: 168

Answers (2)

Efthymios
Efthymios

Reputation: 263

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

Upvotes: 1

LPs
LPs

Reputation: 16223

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

Upvotes: 2

Related Questions