mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-12 23:13:40 +00:00
avr: unify GPIO pin/port code
All the AVRs that I've looked at had the same pin/port structure, with the possible states being input/floating, input/pullup, low, and high (with the same PORT/DDR registers). The main difference is the number of available ports and pins. To reduce the amount of code and avoid duplication (and thus errors) I decided to centralize this, following the design used by the atmega2560 but while using a trick to save tracking a few registers. In the process, I noticed that the Pin.Get() function was incorrect on the atmega2560 implementation. It is now fixed in the unified code.
This commit is contained in:
committed by
Ron Evans
parent
424d775bf4
commit
da505a6b17
@@ -5,6 +5,7 @@ package machine
|
||||
import (
|
||||
"device/avr"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type PinMode uint8
|
||||
@@ -14,6 +15,41 @@ const (
|
||||
PinOutput
|
||||
)
|
||||
|
||||
// In all the AVRs I've looked at, the PIN/DDR/PORT registers followed a regular
|
||||
// pattern: PINx, DDRx, PORTx in this order without registers in between.
|
||||
// Therefore, if you know any of them, you can calculate the other two.
|
||||
//
|
||||
// For now, I've chosen to let the PORTx register be the one that is returned
|
||||
// for each specific chip and to calculate the others from that one. Setting an
|
||||
// output port (done using PORTx) is likely the most common operation and the
|
||||
// one that is the most time critical. For others, the PINx and DDRx register
|
||||
// can trivially be calculated using a subtraction.
|
||||
|
||||
// Configure sets the pin to input or output.
|
||||
func (p Pin) Configure(config PinConfig) {
|
||||
port, mask := p.getPortMask()
|
||||
// The DDRx register can be found by subtracting one from the PORTx
|
||||
// register, as this appears to be the case for many (most? all?) AVR chips.
|
||||
ddr := (*volatile.Register8)(unsafe.Pointer(uintptr(unsafe.Pointer(port)) - 1))
|
||||
if config.Mode == PinOutput {
|
||||
// set output bit
|
||||
ddr.SetBits(mask)
|
||||
} else {
|
||||
// configure input: clear output bit
|
||||
ddr.ClearBits(mask)
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the current value of a GPIO pin.
|
||||
func (p Pin) Get() bool {
|
||||
port, mask := p.getPortMask()
|
||||
// As noted above, the PINx register is always two registers below the PORTx
|
||||
// register, so we can find it simply by subtracting two from the PORTx
|
||||
// register address.
|
||||
pin := (*volatile.Register8)(unsafe.Pointer(uintptr(unsafe.Pointer(port)) - 2)) // PINA, PINB, etc
|
||||
return (pin.Get() & mask) > 0
|
||||
}
|
||||
|
||||
// Set changes the value of the GPIO pin. The pin must be configured as output.
|
||||
func (p Pin) Set(value bool) {
|
||||
if value { // set bits
|
||||
|
||||
Reference in New Issue
Block a user