Skip to content

Commit c91d757

Browse files
committed
teensy40: add I2C pin configuration
1 parent 45b25ed commit c91d757

File tree

5 files changed

+202
-2
lines changed

5 files changed

+202
-2
lines changed

src/machine/board_teensy40.go

+38
Original file line numberDiff line numberDiff line change
@@ -324,3 +324,41 @@ const (
324324
I2C3_SDA_PIN = D25
325325
I2C3_SCL_PIN = D24
326326
)
327+
328+
var (
329+
I2C1 = I2C{
330+
Bus: nxp.LPI2C1,
331+
muxSDA: muxSelect{ // D18 (PA17 [AD_B1_01])
332+
mux: nxp.IOMUXC_LPI2C1_SDA_SELECT_INPUT_DAISY_GPIO_AD_B1_01_ALT3,
333+
sel: &nxp.IOMUXC.LPI2C1_SDA_SELECT_INPUT,
334+
},
335+
muxSCL: muxSelect{ // D19 (PA16 [AD_B1_00])
336+
mux: nxp.IOMUXC_LPI2C1_SCL_SELECT_INPUT_DAISY_GPIO_AD_B1_00_ALT3,
337+
sel: &nxp.IOMUXC.LPI2C1_SCL_SELECT_INPUT,
338+
},
339+
}
340+
341+
I2C2 = I2C{
342+
Bus: nxp.LPI2C3,
343+
muxSDA: muxSelect{ // D17 (PA22 [AD_B1_06])
344+
mux: nxp.IOMUXC_LPI2C3_SDA_SELECT_INPUT_DAISY_GPIO_AD_B1_06_ALT1,
345+
sel: &nxp.IOMUXC.LPI2C3_SDA_SELECT_INPUT,
346+
},
347+
muxSCL: muxSelect{ // D16 (PA23 [AD_B1_07])
348+
mux: nxp.IOMUXC_LPI2C3_SCL_SELECT_INPUT_DAISY_GPIO_AD_B1_07_ALT1,
349+
sel: &nxp.IOMUXC.LPI2C3_SCL_SELECT_INPUT,
350+
},
351+
}
352+
353+
I2C3 = I2C{
354+
Bus: nxp.LPI2C4,
355+
muxSDA: muxSelect{ // D25 (PA13 [AD_B0_13])
356+
mux: nxp.IOMUXC_LPI2C4_SDA_SELECT_INPUT_DAISY_GPIO_AD_B0_13_ALT0,
357+
sel: &nxp.IOMUXC.LPI2C4_SDA_SELECT_INPUT,
358+
},
359+
muxSCL: muxSelect{ // D24 (PA12 [AD_B0_12])
360+
mux: nxp.IOMUXC_LPI2C4_SCL_SELECT_INPUT_DAISY_GPIO_AD_B0_12_ALT0,
361+
sel: &nxp.IOMUXC.LPI2C4_SCL_SELECT_INPUT,
362+
},
363+
}
364+
)

src/machine/i2c.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// +build avr nrf sam stm32,!stm32f407 fe310 k210
1+
// +build avr nrf sam stm32,!stm32f407 fe310 k210 nxp,mimxrt1062
22

33
package machine
44

src/machine/machine_mimxrt1062.go

+4
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ func (p Pin) Configure(config PinConfig) {
254254
gpio.GDIR.ClearBits(p.getMask())
255255
pad.Set(dse(7))
256256

257+
case PinInputAnalog:
258+
gpio.GDIR.ClearBits(p.getMask())
259+
pad.Set(padDSE(7))
260+
257261
case PinModeUARTTX:
258262
pad.Set(sre | dse(3) | spd(3))
259263

src/machine/machine_mimxrt1062_i2c.go

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// +build mimxrt1062
2+
3+
package machine
4+
5+
// I2C peripheral abstraction layer for the MIMXRT1062
6+
7+
import (
8+
"device/nxp"
9+
"errors"
10+
)
11+
12+
const (
13+
TWI_FREQ_DEFAULT = TWI_FREQ_100KHZ // default to StandardMode (100 kHz)
14+
TWI_FREQ_1MHZ = 1000000 // hardware supports FastModePlus (1 MHz)
15+
)
16+
17+
var (
18+
ErrI2CNotConfigured = errors.New("I2C interface is not yet configured")
19+
)
20+
21+
// I2CConfig is used to store config info for I2C.
22+
type I2CConfig struct {
23+
Frequency uint32
24+
SDA Pin
25+
SCL Pin
26+
}
27+
28+
func (c I2CConfig) getPins() (sda, scl Pin) {
29+
if 0 == c.SDA && 0 == c.SCL {
30+
// default pins if none specified
31+
return I2C_SDA_PIN, I2C_SCL_PIN
32+
}
33+
return c.SDA, c.SCL
34+
}
35+
36+
type I2C struct {
37+
Bus *nxp.LPI2C_Type
38+
39+
// these hold the input selector ("daisy chain") values that select which pins
40+
// are connected to the LPI2C device, and should be defined where the I2C
41+
// instance is declared (e.g., in the board definition). see the godoc
42+
// comments on type muxSelect for more details.
43+
muxSDA, muxSCL muxSelect
44+
45+
// these are copied from I2CConfig, during (*I2C).Configure(I2CConfig), and
46+
// should be considered read-only for internal reference (i.e., modifying them
47+
// will have no desirable effect).
48+
sda, scl Pin
49+
frequency uint32
50+
51+
// auxiliary state data used internally
52+
configured bool
53+
}
54+
55+
// Configure is intended to setup an I2C interface for transmit/receive.
56+
func (i2c *I2C) Configure(config I2CConfig) {
57+
58+
// init pins
59+
i2c.sda, i2c.scl = config.getPins()
60+
61+
// configure the mux and pad control registers
62+
i2c.sda.Configure(PinConfig{Mode: PinModeI2CSDA})
63+
i2c.scl.Configure(PinConfig{Mode: PinModeI2CSCL})
64+
65+
// configure the mux input selector
66+
i2c.muxSDA.connect()
67+
i2c.muxSCL.connect()
68+
69+
i2c.frequency = config.Frequency
70+
if 0 == i2c.frequency {
71+
i2c.frequency = TWI_FREQ_DEFAULT
72+
}
73+
74+
// reset clock and registers, and enable LPI2C module interface
75+
i2c.reset()
76+
77+
i2c.configured = true
78+
}
79+
80+
func (i2c *I2C) reset() {
81+
// software reset all interface registers
82+
i2c.Bus.MCR.Set(nxp.LPI2C_MCR_RST)
83+
// configure clock using receiver frequency
84+
i2c.setFrequency(i2c.frequency)
85+
}
86+
87+
func (i2c *I2C) setFrequency(freq uint32) {
88+
const i2cClockStretchTimeout = 15000 // microseconds
89+
90+
var (
91+
mccr0 uint32
92+
mcfgr1, mcfgr2, mcfgr3 uint32
93+
mfcr uint32
94+
// MCCR0
95+
mccr0CLKLO = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_CLKLO_Pos) & nxp.LPI2C_MCCR0_CLKLO_Msk }
96+
mccr0CLKHI = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_CLKHI_Pos) & nxp.LPI2C_MCCR0_CLKHI_Msk }
97+
mccr0DATAVD = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_DATAVD_Pos) & nxp.LPI2C_MCCR0_DATAVD_Msk }
98+
mccr0SETHOLD = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_SETHOLD_Pos) & nxp.LPI2C_MCCR0_SETHOLD_Msk }
99+
// MCFGR1/MCFGR2/MCFGR3
100+
mcfgr1PRESCALE = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR1_PRESCALE_Pos) & nxp.LPI2C_MCFGR1_PRESCALE_Msk }
101+
mcfgr2FILTSDA = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR2_FILTSDA_Pos) & nxp.LPI2C_MCFGR2_FILTSDA_Msk }
102+
mcfgr2FILTSCL = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR2_FILTSCL_Pos) & nxp.LPI2C_MCFGR2_FILTSCL_Msk }
103+
mcfgr2BUSIDLE = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR2_BUSIDLE_Pos) & nxp.LPI2C_MCFGR2_BUSIDLE_Msk }
104+
mcfgr3PINLOW = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR3_PINLOW_Pos) & nxp.LPI2C_MCFGR3_PINLOW_Msk }
105+
// MFCR
106+
mfcrRXWATER = func(n uint32) uint32 { return (n << nxp.LPI2C_MFCR_RXWATER_Pos) & nxp.LPI2C_MFCR_RXWATER_Msk }
107+
mfcrTXWATER = func(n uint32) uint32 { return (n << nxp.LPI2C_MFCR_TXWATER_Pos) & nxp.LPI2C_MFCR_TXWATER_Msk }
108+
)
109+
110+
if freq >= TWI_FREQ_1MHZ {
111+
// I2C FastModePlus 1 MHz
112+
mccr0 = mccr0CLKHI(9) | mccr0CLKLO(10) | mccr0DATAVD(4) | mccr0SETHOLD(7)
113+
mcfgr1 = mcfgr1PRESCALE(0)
114+
mcfgr2 = mcfgr2FILTSDA(1) | mcfgr2FILTSCL(1) | mcfgr2BUSIDLE(2400) // 100us timeout
115+
mcfgr3 = mcfgr3PINLOW(i2cClockStretchTimeout*24/256 + 1)
116+
} else if freq >= TWI_FREQ_400KHZ {
117+
// I2C FastMode 400 kHz
118+
mccr0 = mccr0CLKHI(26) | mccr0CLKLO(28) | mccr0DATAVD(12) | mccr0SETHOLD(18)
119+
mcfgr1 = mcfgr1PRESCALE(0)
120+
mcfgr2 = mcfgr2FILTSDA(2) | mcfgr2FILTSCL(2) | mcfgr2BUSIDLE(3600) // 150us timeout
121+
mcfgr3 = mcfgr3PINLOW(i2cClockStretchTimeout*24/256 + 1)
122+
} else {
123+
// I2C StandardMode 100 kHz
124+
mccr0 = mccr0CLKHI(55) | mccr0CLKLO(59) | mccr0DATAVD(25) | mccr0SETHOLD(40)
125+
mcfgr1 = mcfgr1PRESCALE(1)
126+
mcfgr2 = mcfgr2FILTSDA(5) | mcfgr2FILTSCL(5) | mcfgr2BUSIDLE(3000) // 250us timeout
127+
mcfgr3 = mcfgr3PINLOW(i2cClockStretchTimeout*12/256 + 1)
128+
}
129+
mfcr = mfcrRXWATER(1) | mfcrTXWATER(1) // set FIFO watermarks
130+
131+
i2c.Bus.MCR.Set(0) // disable interface
132+
i2c.Bus.MCCR0.Set(mccr0)
133+
i2c.Bus.MCFGR1.Set(mcfgr1)
134+
i2c.Bus.MCFGR2.Set(mcfgr2)
135+
i2c.Bus.MCFGR3.Set(mcfgr3)
136+
i2c.Bus.MCCR1.Set(i2c.Bus.MCCR0.Get())
137+
i2c.Bus.MCFGR0.Set(0)
138+
i2c.Bus.MFCR.Set(mfcr)
139+
i2c.Bus.MCR.Set(nxp.LPI2C_MCR_MEN) // re-enable interface
140+
}
141+
142+
func (i2c *I2C) setClock() bool {
143+
ret := false
144+
// take control of GPIO pins
145+
i2c.sda.Configure(PinConfig{Mode: PinOutput})
146+
i2c.scl.Configure(PinConfig{Mode: PinOutput})
147+
for i := 0; !ret && i <= 10; i++ {
148+
if ret = i2c.sda.Get() && i2c.scl.Get(); !ret {
149+
// both pins are not high, clear and re-set SCL
150+
i2c.scl.Set(false)
151+
i2c.scl.Set(true)
152+
}
153+
}
154+
// return control of pins to I2C
155+
i2c.sda.Configure(PinConfig{Mode: PinModeI2CSDA})
156+
i2c.scl.Configure(PinConfig{Mode: PinModeI2CSCL})
157+
return ret
158+
}

src/runtime/runtime_mimxrt1062_clock.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ func initClocks() {
166166
nxp.ClockIpLpi2c2.Enable(false) //
167167
nxp.ClockIpLpi2c3.Enable(false) //
168168
nxp.DivIpLpi2c.Div(0) // divide LPI2C_CLK_PODF (DIV1)
169-
nxp.MuxIpLpi2c.Mux(0) // LPI2C select PLL3_SW_60M
169+
nxp.MuxIpLpi2c.Mux(1) // LPI2C select OSC
170170

171171
nxp.ClockIpCan1.Enable(false) // disable CAN
172172
nxp.ClockIpCan2.Enable(false) //

0 commit comments

Comments
 (0)