Reputation: 263
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
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!
Upvotes: 1
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