mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-18 11:33:59 +00:00
i2c: implement target mode for rp2040 and nrf
This commit is contained in:
@@ -9,19 +9,25 @@ import (
|
||||
|
||||
// I2C on the NRF528xx.
|
||||
type I2C struct {
|
||||
Bus *nrf.TWIM_Type
|
||||
Bus *nrf.TWIM_Type // Called Bus to align with Bus field in nrf51
|
||||
BusT *nrf.TWIS_Type
|
||||
mode I2CMode
|
||||
}
|
||||
|
||||
// There are 2 I2C interfaces on the NRF.
|
||||
var (
|
||||
I2C0 = &I2C{Bus: nrf.TWIM0}
|
||||
I2C1 = &I2C{Bus: nrf.TWIM1}
|
||||
I2C0 = &I2C{Bus: nrf.TWIM0, BusT: nrf.TWIS0}
|
||||
I2C1 = &I2C{Bus: nrf.TWIM1, BusT: nrf.TWIS1}
|
||||
)
|
||||
|
||||
func (i2c *I2C) enableAsController() {
|
||||
i2c.Bus.ENABLE.Set(nrf.TWIM_ENABLE_ENABLE_Enabled)
|
||||
}
|
||||
|
||||
func (i2c *I2C) enableAsTarget() {
|
||||
i2c.BusT.ENABLE.Set(nrf.TWIS_ENABLE_ENABLE_Enabled)
|
||||
}
|
||||
|
||||
func (i2c *I2C) disable() {
|
||||
i2c.Bus.ENABLE.Set(0)
|
||||
}
|
||||
@@ -86,6 +92,99 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Listen starts listening for I2C requests sent to specified address
|
||||
//
|
||||
// addr is the address to listen to
|
||||
func (i2c *I2C) Listen(addr uint8) error {
|
||||
i2c.BusT.ADDRESS[0].Set(uint32(addr))
|
||||
i2c.BusT.CONFIG.Set(nrf.TWIS_CONFIG_ADDRESS0_Enabled)
|
||||
|
||||
i2c.BusT.EVENTS_STOPPED.Set(0)
|
||||
i2c.BusT.EVENTS_ERROR.Set(0)
|
||||
i2c.BusT.EVENTS_RXSTARTED.Set(0)
|
||||
i2c.BusT.EVENTS_TXSTARTED.Set(0)
|
||||
i2c.BusT.EVENTS_WRITE.Set(0)
|
||||
i2c.BusT.EVENTS_READ.Set(0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WaitForEvent blocks the current go-routine until an I2C event is received (when in Target mode).
|
||||
//
|
||||
// The passed buffer will be populated for receive events, with the number of bytes
|
||||
// received returned in count. For other event types, buf is not modified and a count
|
||||
// of zero is returned.
|
||||
//
|
||||
// For request events, the caller MUST call `Reply` to avoid hanging the i2c bus indefinitely.
|
||||
func (i2c *I2C) WaitForEvent(buf []byte) (evt I2CTargetEvent, count int, err error) {
|
||||
i2c.BusT.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&buf[0]))))
|
||||
i2c.BusT.RXD.MAXCNT.Set(uint32(len(buf)))
|
||||
|
||||
i2c.BusT.TASKS_PREPARERX.Set(nrf.TWIS_TASKS_PREPARERX_TASKS_PREPARERX_Trigger)
|
||||
|
||||
i2c.Bus.TASKS_RESUME.Set(1)
|
||||
|
||||
for i2c.BusT.EVENTS_STOPPED.Get() == 0 &&
|
||||
i2c.BusT.EVENTS_READ.Get() == 0 {
|
||||
gosched()
|
||||
|
||||
if i2c.BusT.EVENTS_ERROR.Get() != 0 {
|
||||
i2c.BusT.EVENTS_ERROR.Set(0)
|
||||
return I2CReceive, 0, twisError(i2c.BusT.ERRORSRC.Get())
|
||||
}
|
||||
}
|
||||
|
||||
count = 0
|
||||
evt = I2CFinish
|
||||
err = nil
|
||||
|
||||
if i2c.BusT.EVENTS_WRITE.Get() != 0 {
|
||||
i2c.BusT.EVENTS_WRITE.Set(0)
|
||||
|
||||
// Data was sent to this target. We've waited for
|
||||
// READ or STOPPED event, so transmission should be
|
||||
// complete.
|
||||
count = int(i2c.BusT.RXD.AMOUNT.Get())
|
||||
evt = I2CReceive
|
||||
} else if i2c.BusT.EVENTS_READ.Get() != 0 {
|
||||
i2c.BusT.EVENTS_READ.Set(0)
|
||||
|
||||
// Data is requested from this target, hw will stretch
|
||||
// the controller's clock until there is a reply to
|
||||
// send
|
||||
evt = I2CRequest
|
||||
} else if i2c.BusT.EVENTS_STOPPED.Get() != 0 {
|
||||
i2c.BusT.EVENTS_STOPPED.Set(0)
|
||||
evt = I2CFinish
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Reply supplies the response data the controller.
|
||||
func (i2c *I2C) Reply(buf []byte) error {
|
||||
i2c.BusT.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&buf[0]))))
|
||||
i2c.BusT.TXD.MAXCNT.Set(uint32(len(buf)))
|
||||
|
||||
i2c.BusT.EVENTS_STOPPED.Set(0)
|
||||
|
||||
// Trigger Tx
|
||||
i2c.BusT.TASKS_PREPARETX.Set(nrf.TWIS_TASKS_PREPARETX_TASKS_PREPARETX_Trigger)
|
||||
|
||||
// Block, waiting for Tx to complete
|
||||
for i2c.BusT.EVENTS_STOPPED.Get() == 0 {
|
||||
gosched()
|
||||
|
||||
if i2c.BusT.EVENTS_ERROR.Get() != 0 {
|
||||
return twisError(i2c.BusT.ERRORSRC.Get())
|
||||
}
|
||||
}
|
||||
|
||||
i2c.BusT.EVENTS_STOPPED.Set(0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// twiCError converts an I2C controller error to Go
|
||||
func twiCError(val uint32) error {
|
||||
if val == 0 {
|
||||
@@ -100,3 +199,18 @@ func twiCError(val uint32) error {
|
||||
|
||||
return errI2CBusError
|
||||
}
|
||||
|
||||
// twisError converts an I2C target error to Go
|
||||
func twisError(val uint32) error {
|
||||
if val == 0 {
|
||||
return nil
|
||||
} else if val&nrf.TWIS_ERRORSRC_OVERFLOW_Msk == nrf.TWIS_ERRORSRC_OVERFLOW {
|
||||
return errI2COverflow
|
||||
} else if val&nrf.TWIS_ERRORSRC_DNACK_Msk == nrf.TWIS_ERRORSRC_DNACK {
|
||||
return errI2CAckExpected
|
||||
} else if val&nrf.TWIS_ERRORSRC_OVERREAD_Msk == nrf.TWIS_ERRORSRC_OVERREAD {
|
||||
return errI2COverread
|
||||
}
|
||||
|
||||
return errI2CBusError
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user