Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions src/machine/machine_atmega.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,95 @@ package machine

import (
"device/avr"
"errors"
"runtime/interrupt"
"runtime/volatile"
"unsafe"
)

// EEPROM on ATMega
type EEPROM struct {
}

var EEPROM0 = EEPROM{}

// 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()) {

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.

}

avr.EEARH.Set(uint8(addr >> 8))
avr.EEARL.Set(uint8(addr & 0xFF))

return nil
}

// WriteAt writes len(data) bytes in the EEPROMs at the provided offset.
func (e EEPROM) WriteAt(data []byte, off int64) (int, error) {
written := 0
for i, value := range data {
if err := e.WriteByteAt(value, off+int64(i)); err != nil {
return written, err
}
written++
}
return written, nil
}

// WriteByteAt performs the logic to writes a byte into the EEPROM at the given address.
func (e EEPROM) WriteByteAt(value byte, addr int64) error {
for avr.EECR.HasBits(avr.EECR_EEPE) {
}

if err := e.setAddress(int16(addr)); err != nil {
return err
}

avr.EEDR.Set(value)

avr.EECR.SetBits(avr.EECR_EEMPE)
avr.EECR.SetBits(avr.EECR_EEPE)

return nil
}

// ReadAt reads exactly len(buf) into buf at the offset. It will return the amount of bytes copied or an error if one exists.
// The buffer cannot be empty, and an an error is thrown if fewer bytes are read than the size of the buffer.
func (e EEPROM) ReadAt(buf []byte, off int64) (int, error) {
if len(buf) == 0 {
return 0, nil
}

read := 0
for i := 0; i < len(buf); i++ {
val, err := e.ReadByteAt(off + int64(i))
if err != nil {
return read, err
}

buf[i] = val

read++
}

return len(buf), nil
}

// ReadByteAt reads and returns the byte at the specified address. An error is returned if there is a failure to read.
func (e EEPROM) ReadByteAt(addr int64) (byte, error) {
for avr.EECR.HasBits(avr.EECR_EEPE) {
}

if err := e.setAddress(int16(addr)); err != nil {
return byte(0), err
}

avr.EECR.SetBits(avr.EECR_EERE)

return avr.EEDR.Get(), nil
}

// I2C on AVR.
type I2C struct {
}
Expand Down
5 changes: 5 additions & 0 deletions src/machine/machine_atmega1280.go
Original file line number Diff line number Diff line change
Expand Up @@ -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).

}

const (
portA Pin = iota * 8
portB
Expand Down
5 changes: 5 additions & 0 deletions src/machine/machine_atmega1284p.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,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
}

// Return the current CPU frequency in hertz.
func CPUFrequency() uint32 {
return 20000000
Expand Down
5 changes: 5 additions & 0 deletions src/machine/machine_atmega2560.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ const irq_USART1_RX = avr.IRQ_USART1_RX
const irq_USART2_RX = avr.IRQ_USART2_RX
const irq_USART3_RX = avr.IRQ_USART3_RX

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

const (
portA Pin = iota * 8
portB
Expand Down
5 changes: 5 additions & 0 deletions src/machine/machine_atmega328p.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import (

const irq_USART0_RX = avr.IRQ_USART_RX

// Size returns the size of the EEPROM for this machine.
func (e EEPROM) Size() int64 {
return 1024
}

// getPortMask returns the PORTx register and mask for the pin.
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
switch {
Expand Down
5 changes: 5 additions & 0 deletions src/machine/machine_atmega328pb.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,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 1024
}

// getPortMask returns the PORTx register and mask for the pin.
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
switch {
Expand Down