Skip to content

avr: added EEPROM support for ATmega boards #3306

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

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from

Conversation

SoleimanyBen
Copy link

This adds general EEPROM support for AVR devices through the EEPROM struct.

First MR here so I was hoping to get feedback on what I could improve and what I did wrong here.

It looks like it goes against convention to not have a Configure() function for hardware structures, but I did not see how It could make sense in this instance.

Also, should there be a specific EEPROM0 constant for each machine file that is then populated within the specific board file?

Thanks again, glad to be able to contribute to such a great project! :)

p.s. im an idiot, sorry about the other PR with the wrong branch selected 😅

@SoleimanyBen
Copy link
Author

SoleimanyBen commented Nov 21, 2022

also now that im thinking about it, maybe the eepromSize constant should also be within board specific files?

edit: I have made changes to this commit so this comment does not apply anymore

@SoleimanyBen SoleimanyBen marked this pull request as draft November 22, 2022 22:19
@SoleimanyBen SoleimanyBen marked this pull request as ready for review November 23, 2022 01:09
Copy link
Member

@aykevl aykevl left a comment

Choose a reason for hiding this comment

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

I have a number of nits, but overall the code looks quite reasonable.

Can you also make a PR to https://github.com/tinygo-org/tinygo-site with API documentation on the EEPROM? At least the machine package, but if you could also write something in here (https://tinygo.org/docs/concepts/peripherals/) that would be great.

var EEPROM0 = EEPROM{}

// setAddress sets the address for a given read or write into the MCUs EEARH/L register.
func (e EEPROM) setAddress(addr int64) error {
Copy link
Member

Choose a reason for hiding this comment

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

This is an unexported function, so it's best to use the most efficient data type available. In this case, int16 (or even uint16).

Suggested change
func (e EEPROM) setAddress(addr int64) error {
func (e EEPROM) setAddress(addr int16) error {

Copy link
Author

Choose a reason for hiding this comment

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

If I make this change, within this function there is a comparison between an int64 and int16. Should I be casting the int16 into an int64 to perform this check, or should I change the result of the Size() function to return int16 instead?

Copy link
Member

Choose a reason for hiding this comment

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

In this case you know it will never be bigger than an int16 so casting to the most efficient type is best (for AVR that is int16).

@@ -11,6 +11,11 @@ import (

const irq_USART0_RX = avr.IRQ_USART0_RX

// Size returns the size of the EEPROM for this machine.
func (e EEPROM) Size() int64 {
return 4096
Copy link
Member

Choose a reason for hiding this comment

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

I believe this constant is part of the .atdf files, but that can be fixed in a future patch. (It needs a change to tools/gen-device-avr).

@SoleimanyBen
Copy link
Author

I have a number of nits, but overall the code looks quite reasonable.

Can you also make a PR to https://github.com/tinygo-org/tinygo-site with API documentation on the EEPROM? At least the machine package, but if you could also write something in here (https://tinygo.org/docs/concepts/peripherals/) that would be great.

Absolutely. I'll make a write up once I fix the other issues you mentioned!

// setAddress sets the address for a given read or write into the MCUs EEARH/L register.
func (e EEPROM) setAddress(addr int16) error {
if addr < 0 || addr > int16(e.Size()) {
return errors.New("address provided is out of bounds")
Copy link
Member

Choose a reason for hiding this comment

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

Please define a global constant with this error message to return. For example:

var errEEPROMAddress = errors.New("eeprom: address out of bounds")

Otherwise this forces a heap allocation when the error is triggered, which is not good.


// setAddress sets the address for a given read or write into the MCUs EEARH/L register.
func (e EEPROM) setAddress(addr int16) error {
if addr < 0 || addr > int16(e.Size()) {
Copy link
Member

Choose a reason for hiding this comment

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

I think this is an off-by-one.

Suggested change
if addr < 0 || addr > int16(e.Size()) {
if addr < 0 || addr >= int16(e.Size()) {

var EEPROM0 = EEPROM{}

// setAddress sets the address for a given read or write into the MCUs EEARH/L register.
func (e EEPROM) setAddress(addr int64) error {
Copy link
Member

Choose a reason for hiding this comment

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

In this case you know it will never be bigger than an int16 so casting to the most efficient type is best (for AVR that is int16).

@SoleimanyBen
Copy link
Author

Sorry for the extreme delay on these changes, will go ahead and add them this week.

@deadprogram
Copy link
Member

@SoleimanyBen I was looking at this PR today, and had a couple ideas. Seems to me that it would be great to implement the ReadWriteCloser interface for EEPROM as the main API developers would use.

Imaginary code:

func main() {
    store := machine.EEPROM.Open(address)
    defer store.Close()

    var data [12]byte
    _, err := store.Read(data)
    if err != nil {
        panic("nope")
    }

    println(string(data))


    store.Write([]byte("Hola, mundo!))
}

@SoleimanyBen
Copy link
Author

@deadprogram That's a great idea! I'll write up those changes when I make the other adjustments later this week. :)

@aykevl
Copy link
Member

aykevl commented Feb 21, 2023

@SoleimanyBen I was looking at this PR today, and had a couple ideas. Seems to me that it would be great to implement the ReadWriteCloser interface for EEPROM as the main API developers would use.

Why though? It seems to me that ReaderAt and WriterAt are a much closer fit to the underlying hardware. With ReadWriteClose you have to:

  • Open/close the EEPROM, which is not something the hardware needs
  • Keep track of the read/write offset, which again isn't natively supported by the hardware

If an application really wanted to layer a ReadWriteCloser on top, you could easily write a new package that wraps the EEPROM to provide these methods. But for the machine API, I think it only adds unnecessary overhead.

@deadprogram
Copy link
Member

@SoleimanyBen I think the interface to create here is actually the BlockDevice one, same as https://github.com/tinygo-org/tinyfs/blob/release/tinyfs.go#L42-L69

This is what I have been doing in my Flash PR #3472

@aykevl
Copy link
Member

aykevl commented Apr 27, 2023

@deadprogram EEPROM is not quite the same as flash though. Unlike flash, you can erase and rewrite individual bytes easily so "page size" (a big part of BlockDevice) doesn't make much sense.

In my opinion, this PR is almost ready, it just needs a few small changes to mergeable.

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.

3 participants