Skip to content

Fix eeprom write and erase #494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 20, 2024
Merged

Fix eeprom write and erase #494

merged 2 commits into from
Jan 20, 2024

Conversation

Eggtosch
Copy link
Contributor

Hey, i authored the Atmega164PA support at work with my colleague (see #452).
I took some spare time to look into the EEPROM issue once again (#406):

The various datasheets for the atmega* chips essentially state the following procedure :

  1. Wait for the EEPE bit to become zero.
  2. Write a logical one to the EEMPE bit while writing a zero to EEPE in EECR.
  3. Within four clock cycles after setting EEMPE, write a logical one to EEPE.

While we do step 1 and 2 correctly, for step 3, we use self.eecr.write(|w| w.eepe().set_bit()); which sets the EEPE bit, but also sets the rest of the register to zero.
This seems to cause some slightly different behavior on different boards, e.g. on my Arduino Uno (Atmega328p) on which i tested this, only a 0xff write fails, while on the atmega164pa an erase also fails.

Using self.eecr.modify(|_, w| w.eepe().set_bit()); fixes the issue, because it preserves the rest of the register.

Please let me know what you think :).

The various datasheets for the atmega* chips state that to start an
eeprom operation a 1 should be written to the eepe bit of the eecr
register. Using eecr.write actually clears the other bits of the
register and might lead to the eeprom operation failing.
@Eggtosch
Copy link
Contributor Author

Little update: I now have a better in detail explanation :).

Using self.eecr.write(|w| w.eepe().set_bit()); sets all bits except the eepe bit to zero. This does not lead to the eeprom operation failing, in fact it sets the eeprom operation to erase+write. This leads to different behaviors depending on the case that is entered in the raw_write_byte function.

  1. Some bits need to be programmed to 0 and some to 1: The erase+write mode is used and the data register is set, everything works as expected.
  2. All changed bits need to be set to 0: The write mode is used and the data register is set, everything works as expected.
  3. All changed bits need to be set to 1: The erase mode is used, but the data register is not set (of course, we normally wouldn't need the data register). But the bug then sets the erase+write mode instead and the data from the data register is used, in this case the value that was read at the beginning of the function, so the same value that is stored at the address is written again.

For the raw_erase_byte function, the data register also isn't set and whatever was written there before is used. The function worked for the atmega328p in my tests only because of my test setup, i was reading a 0xff from a different address before using the erase_byte function.

@Rahix Rahix linked an issue Jan 20, 2024 that may be closed by this pull request
Copy link
Owner

@Rahix Rahix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice work, thanks a lot for digging into the issue! This certainly is much better than the workaround ;)

@Rahix Rahix merged commit c54e5f5 into Rahix:main Jan 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unable to write 0xFF to the eeprom on atmega328p.
2 participants