Search code examples
cembeddedavravr-gccatmelstudio

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.

  • 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.


Solution

  • 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