mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
machine: make I2C usable in the simulator
This fixes/improves a few issues with I2C support:
* Validate I2C pins, so only pins that are supported by the hardware
can be used (similar to how it's done with PWM).
* Add address to Tx API (without it, the simulator can't really
simulate I2C).
* Add frequency when configuring. Not currently used, but might be
useful in the future and adding it now avoids possibly breaking
changes.
This is a breaking change, but since the simulator doesn't support I2C
yet that seems fine to me. (It does in my local changes, but those need
to be cleaned up before I can push them).
This commit is contained in:
committed by
Ron Evans
parent
35adbffa54
commit
f845b469b1
@@ -37,6 +37,9 @@ var (
|
||||
errI2COverflow = errors.New("I2C receive buffer overflow")
|
||||
errI2COverread = errors.New("I2C transmit buffer overflow")
|
||||
errI2CNotImplemented = errors.New("I2C operation not yet implemented")
|
||||
errI2CNoDevices = errors.New("i2c: bus has no devices") // simulator only
|
||||
errI2CMultipleDevices = errors.New("i2c: bus has address conflict") // simulator only
|
||||
errI2CWrongAddress = errors.New("i2c: bus has devices but none with this address") // simulator only
|
||||
)
|
||||
|
||||
// I2CTargetEvent reflects events on the I2C bus
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
//go:build !baremetal && (arduino || arduino_nano)
|
||||
|
||||
package machine
|
||||
|
||||
var I2C0 = &I2C{Bus: 0, PinsSDA: []Pin{PC4}, PinsSCL: []Pin{PC5}}
|
||||
@@ -43,3 +43,21 @@ var TCC2 = &timerType{
|
||||
{PA01, PA13, PA17}, // channel 1
|
||||
},
|
||||
}
|
||||
|
||||
var (
|
||||
// According to the datasheet, only some pins have I2C support. However it
|
||||
// looks like many boards just use any SERCOM I2C instance, even if the
|
||||
// datasheet says those don't support I2C. I guess they do work in practice,
|
||||
// then.
|
||||
// These are:
|
||||
// * PA00/PA01 for the Adafruit Circuit Playground Express (I2C1, SERCOM1).
|
||||
// * PB02/PB03 for the Adafruit Circuit Playground Express (I2C0, SERCOM5).
|
||||
// * PB08/PB09 for the Arduino Nano 33 IoT (I2C0, SERCOM4).
|
||||
// https://cdn.sparkfun.com/datasheets/Dev/Arduino/Boards/Atmel-42181-SAM-D21_Datasheet.pdf
|
||||
sercomI2CM0 = &I2C{Bus: 0, PinsSDA: []Pin{PA08}, PinsSCL: []Pin{PA09}}
|
||||
sercomI2CM1 = &I2C{Bus: 1, PinsSDA: []Pin{PA00, PA16}, PinsSCL: []Pin{PA01, PA17}}
|
||||
sercomI2CM2 = &I2C{Bus: 2, PinsSDA: []Pin{PA08, PA12}, PinsSCL: []Pin{PA09, PA13}}
|
||||
sercomI2CM3 = &I2C{Bus: 3, PinsSDA: []Pin{PA16, PA22}, PinsSCL: []Pin{PA17, PA23}}
|
||||
sercomI2CM4 = &I2C{Bus: 4, PinsSDA: []Pin{PA12, PB08, PB12}, PinsSCL: []Pin{PA13, PB09, PB13}}
|
||||
sercomI2CM5 = &I2C{Bus: 5, PinsSDA: []Pin{PA22, PB02, PB16, PB30}, PinsSCL: []Pin{PA23, PB03, PB17, PB31}}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
//go:build !baremetal && hifive1b
|
||||
|
||||
package machine
|
||||
|
||||
var I2C0 = &I2C{Bus: 0, PinsSDA: []Pin{P12}, PinsSCL: []Pin{P13}}
|
||||
@@ -4,6 +4,8 @@ package machine
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// Dummy machine package that calls out to external functions.
|
||||
@@ -227,7 +229,9 @@ func adcRead(pin Pin) uint16
|
||||
|
||||
// I2C is a generic implementation of the Inter-IC communication protocol.
|
||||
type I2C struct {
|
||||
Bus uint8
|
||||
Bus uint8
|
||||
PinsSCL []Pin
|
||||
PinsSDA []Pin
|
||||
}
|
||||
|
||||
// I2CConfig is used to store config info for I2C.
|
||||
@@ -239,7 +243,21 @@ type I2CConfig struct {
|
||||
|
||||
// Configure is intended to setup the I2C interface.
|
||||
func (i2c *I2C) Configure(config I2CConfig) error {
|
||||
i2cConfigure(i2c.Bus, config.SCL, config.SDA)
|
||||
if i2c.PinsSCL != nil {
|
||||
matchSCL := slices.Index(i2c.PinsSCL, config.SCL) >= 0
|
||||
matchSDA := slices.Index(i2c.PinsSDA, config.SDA) >= 0
|
||||
if !matchSCL && !matchSDA {
|
||||
return errors.New("i2c: SCL and SDA pins are incorrect for this I2C instance")
|
||||
} else if !matchSCL {
|
||||
return errors.New("i2c: SCL pin is incorrect for this I2C instance")
|
||||
} else if !matchSDA {
|
||||
return errors.New("i2c: SDA pin is incorrect for this I2C instance")
|
||||
}
|
||||
}
|
||||
if config.Frequency == 0 {
|
||||
config.Frequency = 100 * KHz
|
||||
}
|
||||
i2cConfigure(i2c.Bus, config.SCL, config.SDA, config.Frequency)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -261,19 +279,29 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
|
||||
rptr = &r[0]
|
||||
rlen = len(r)
|
||||
}
|
||||
i2cTransfer(i2c.Bus, wptr, wlen, rptr, rlen)
|
||||
// TODO: do something with the returned error code.
|
||||
return nil
|
||||
errCode := i2cTransfer(i2c.Bus, addr, wptr, wlen, rptr, rlen)
|
||||
switch errCode {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return errI2CNoDevices
|
||||
case 2:
|
||||
return errI2CMultipleDevices
|
||||
case 3:
|
||||
return errI2CWrongAddress
|
||||
default:
|
||||
return errI2CBusError // unknown error code
|
||||
}
|
||||
}
|
||||
|
||||
//export __tinygo_i2c_configure
|
||||
func i2cConfigure(bus uint8, scl Pin, sda Pin)
|
||||
func i2cConfigure(bus uint8, scl Pin, sda Pin, frequency uint32)
|
||||
|
||||
//export __tinygo_i2c_set_baud_rate
|
||||
func i2cSetBaudRate(bus uint8, br uint32)
|
||||
|
||||
//export __tinygo_i2c_transfer
|
||||
func i2cTransfer(bus uint8, w *byte, wlen int, r *byte, rlen int) int
|
||||
func i2cTransfer(bus uint8, addr uint16, w *byte, wlen int, r *byte, rlen int) int
|
||||
|
||||
type UART struct {
|
||||
Bus uint8
|
||||
@@ -336,15 +364,6 @@ var (
|
||||
sercomUSART4 = UART{4}
|
||||
sercomUSART5 = UART{5}
|
||||
|
||||
sercomI2CM0 = &I2C{0}
|
||||
sercomI2CM1 = &I2C{1}
|
||||
sercomI2CM2 = &I2C{2}
|
||||
sercomI2CM3 = &I2C{3}
|
||||
sercomI2CM4 = &I2C{4}
|
||||
sercomI2CM5 = &I2C{5}
|
||||
sercomI2CM6 = &I2C{6}
|
||||
sercomI2CM7 = &I2C{7}
|
||||
|
||||
sercomSPIM0 = &SPI{0}
|
||||
sercomSPIM1 = &SPI{1}
|
||||
sercomSPIM2 = &SPI{2}
|
||||
|
||||
@@ -10,5 +10,4 @@ var (
|
||||
UART1 = hardwareUART1
|
||||
SPI0 = &SPI{0}
|
||||
SPI1 = &SPI{1}
|
||||
I2C0 = &I2C{0}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
//go:build !baremetal && (microbit || pca10031 || hw_651)
|
||||
|
||||
package machine
|
||||
|
||||
var I2C0 = &I2C{Bus: 0}
|
||||
var I2C1 = &I2C{Bus: 1}
|
||||
@@ -58,3 +58,6 @@ var PWM3 = &timerType{
|
||||
nil, // channel 3
|
||||
},
|
||||
}
|
||||
|
||||
var I2C0 = &I2C{Bus: 0}
|
||||
var I2C1 = &I2C{Bus: 1}
|
||||
|
||||
@@ -94,3 +94,15 @@ var PWM7 = &timerType{
|
||||
{GPIO15}, // channel B (1)
|
||||
},
|
||||
}
|
||||
|
||||
var I2C0 = &I2C{
|
||||
Bus: 0,
|
||||
PinsSCL: []Pin{GPIO1, GPIO5, GPIO9, GPIO13, GPIO17, GPIO21},
|
||||
PinsSDA: []Pin{GPIO0, GPIO4, GPIO8, GPIO12, GPIO16, GPIO20},
|
||||
}
|
||||
|
||||
var I2C1 = &I2C{
|
||||
Bus: 0,
|
||||
PinsSCL: []Pin{GPIO3, GPIO7, GPIO11, GPIO15, GPIO19, GPIO27},
|
||||
PinsSDA: []Pin{GPIO2, GPIO6, GPIO10, GPIO14, GPIO18, GPIO26},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user