I am trying to write and read data from EEPROM (microcontroller ATmega2560), which gives me the wrong answer. When I debug it, I see that only the last character is being read though I see that data is being written on different addresses.
At uiAddress = 1, the data is A
, at uiAddress = 2 the data is B
, uiAddress=3 data=67'C', and so on. So when you read from uiAddress = 0 to the last address, you should get ABCDE. I am reading one bit, one character at a time.
EESAVE is enabled.
Why is that happening? (I've tried to include as much code as possible, the original file is too big. But this is the concerned area).
#include<avr/io.h>
#include<avr/eeprom.h>
#include<avr/interrupt.h>
volatile UINT intrs, i = 1, count, switch_pressed = 0, uiAdd, uiAddEnd, flag_led_intr;
volatile UINT record, play_recorded_keys, flag_serial_receiver;
volatile unsigned char get_switch=0, data, TX_complete开发者_如何学编程, TX, RX;
extern void __vector_25 (void) __attribute__ ((signal)); //Interrupt vector
#define LED_DELAY 10
#define F_CPU 2000000L
#define BAUDRATE 9600
#define BAUD_PRESCALER (((F_CPU/(BAUDRATE * 16UL)))-1)
void ReadWriteSerialPort(void)
{
while(((UCSR0A) & (1<<UDRE0)) == 0)
;
UDR0 = RX;
if(RX == 0x1A) //CRTL-z
{
record = !record;
play_recorded_keys = 0;
}
else
if(RX == 0x19) //CRTL-y
{
record = 0;
uiAdd = 0;
play_recorded_keys = !play_recorded_keys;
}
if(record == 1)
{
EEPROM_write(uiAdd++, RX);
}
if(uiAdd == 4096)
{
record = 0;
uiAddEnd = 4096;
}
else
uiAddEnd = uiAdd;
}
void initialize(void)
{
cli(); //Stop all interrupts
flag_led_intr = 0;
record = 0;
play_recorded_keys = 0;
RX = 0;
TX = 0;
flag_serial_receiver = 0;
uiAdd = 0;
uiAddEnd = 0;
enable_ports();
usart_init();
sei();
}
void enable_ports() //Enables PORTB, PORTD
{
DDRB = 0xff; //PORTB as output for leds
PORTB = 0xff; //Initialize PORTB
DDRD = 0x00; //PORTD as input for switches
}
void usart_init(void) //Enables USART
{
/* Set baud rate */
UBRR0L = BAUD_PRESCALER);
UBRR0H = (BAUD_PRESCALER>>8);
/* Set frame format: 8 bit data + start bit + stop bit */
UCSR0C = 0x06;
/* Enable reciever and transmitter */
UCSR0B = 0x98;
}
void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
while(EECR & (1<<EEPE)); /* Wait for completion of previous write */
EEARH = (uiAddress>>8); /* Set up address and Data Registers */
EEARL = uiAddress;
EEDR = ucData;
cli();
EECR |= (1<<EEMPE); /* Write logical one to EEMPE */
EECR |= (1<<EEPE); /* Start eeprom write by setting EEPE */
sei();
}
unsigned char EEPROM_read(unsigned int uiAddress)
{
while(EECR & (1<<EEPE)); /* Wait for completion of previous write */
EEARH = (uiAddress>>8); /* Set up address register */
EEARL = uiAddress;
EECR |= (1<<EERE); /* Start eeprom read by writing EERE */
return EEDR; /* Return data from Data Register */
}
void __vector_25 (void)
{
RX = UDR0;
flag_serial_receiver = 1;
sei();
}
int main(void)
{
initialize();
while(1)
{
if(flag_serial_receiver == 1)
{
ReadWriteSerialPort();
flag_serial_receiver = 0;
}
if(play_recorded_keys)
{
TX = EEPROM_read(uiAdd);
uiAdd++;
if(uiAdd == 4096 || uiAdd >= uiAddEnd)
{
play_recorded_keys = 0;
uiAdd = 0;
}
while(((UCSR0A) & (1<<UDRE0)) == 0)
;
UDR0 = TX;
}
}
return(0);
}
Code found as in the AVR DATA BOOK with addition of two macros.
#define sbi(port,bit) __asm__ __volatile__ ( "sbi %0, %1" :: "I" (_SFR_IO_ADDR(port)),"I" (bit))
#define cbi(port,bit) __asm__ __volatile__ ( "cbi %0, %1" :: "I" (_SFR_IO_ADDR(port)),"I" (bit))
//Write data to EEPROM
void EEPROM_WRITE(unsigned int uiAddress, unsigned char ucData)
{
/* Wait for completion of previous write */
while(EECR & (1<<EEPE));
/* Set up address and Data Registers */
EEAR = uiAddress;
EEDR = ucData;
/* Write logical one to EEMPE */
//EECR |= (1<<EEMPE);
sbi(EECR,EEMPE);
/* Start eeprom write by setting EEPE */
//EECR |= (1<<EEPE);
sbi(EECR,EEPE); //You need to set EEPE within four clock cycles to `enter code here`initiate writing.
}
Using GCC with the optimizer set -O0 take too long, thus more than 4 clock cycle and therefore it will not write. A couple of simple macros that over come this problem.
I would bet that either your write or read or both is not happening. Please verify that you are constructing the flag bits correctly as ruslik hinted in comments by using a debugger or debug output to manually check the configuration register contents against the chip data sheet.
A useful test would be to set EEDR to an unexpected test value before calling the read. If the read returns this unexpected value, you know you didn't actually read but just got a stale value of EEDR. That could be due to either not setting the right flags, or perhaps needing to wait for the read to complete but not doing so.
You could also try playing with the order or writes and reads - for example, writing in increasing order but reading out in decreasing.
Experiment around with constructing such tests that would reveal different sorts of errors, and I'm sure you will figure it out quickly.
精彩评论