github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_mimxrt1062_i2c.go (about)

     1  //go:build mimxrt1062
     2  
     3  package machine
     4  
     5  // I2C peripheral abstraction layer for the MIMXRT1062
     6  
     7  import (
     8  	"device/nxp"
     9  )
    10  
    11  // I2CConfig is used to store config info for I2C.
    12  type I2CConfig struct {
    13  	Frequency uint32
    14  	SDA       Pin
    15  	SCL       Pin
    16  }
    17  
    18  type I2C struct {
    19  	Bus *nxp.LPI2C_Type
    20  
    21  	// these pins are initialized by each global I2C variable declared in the
    22  	// board_teensy4x.go file according to the board manufacturer's default pin
    23  	// mapping. they can be overridden with the I2CConfig argument given to
    24  	// (*I2C) Configure(I2CConfig).
    25  	sda, scl Pin
    26  
    27  	// these hold the input selector ("daisy chain") values that select which pins
    28  	// are connected to the LPI2C device, and should be defined where the I2C
    29  	// instance is declared (e.g., in the board definition). see the godoc
    30  	// comments on type muxSelect for more details.
    31  	muxSDA, muxSCL muxSelect
    32  }
    33  
    34  type i2cDirection bool
    35  
    36  const (
    37  	directionWrite i2cDirection = false
    38  	directionRead  i2cDirection = true
    39  )
    40  
    41  func (dir i2cDirection) shift(addr uint16) uint32 {
    42  	if addr <<= 1; dir == directionRead {
    43  		addr |= 1
    44  	}
    45  	return uint32(addr) & 0xFF
    46  }
    47  
    48  // I2C enumerated types
    49  type (
    50  	resultFlag   uint32
    51  	statusFlag   uint32
    52  	transferFlag uint32
    53  	commandFlag  uint32
    54  	stateFlag    uint32
    55  )
    56  
    57  const (
    58  	// general purpose results
    59  	resultSuccess         resultFlag = 0x0 // success
    60  	resultFail            resultFlag = 0x1 // fail
    61  	resultReadOnly        resultFlag = 0x2 // read only failure
    62  	resultOutOfRange      resultFlag = 0x3 // out of range access
    63  	resultInvalidArgument resultFlag = 0x4 // invalid argument check
    64  	// I2C-specific results
    65  	resultBusy                 resultFlag = 0x0384 + 0x0 // the controller is already performing a transfer
    66  	resultIdle                 resultFlag = 0x0384 + 0x1 // the peripheral driver is idle
    67  	resultNak                  resultFlag = 0x0384 + 0x2 // the peripheral device sent a NAK in response to a byte
    68  	resultFifoError            resultFlag = 0x0384 + 0x3 // FIFO under run or overrun
    69  	resultBitError             resultFlag = 0x0384 + 0x4 // transferred bit was not seen on the bus
    70  	resultArbitrationLost      resultFlag = 0x0384 + 0x5 // arbitration lost error
    71  	resultPinLowTimeout        resultFlag = 0x0384 + 0x6 // SCL or SDA were held low longer than the timeout
    72  	resultNoTransferInProgress resultFlag = 0x0384 + 0x7 // attempt to abort a transfer when one is not in progress
    73  	resultDmaRequestFail       resultFlag = 0x0384 + 0x8 // DMA request failed
    74  	resultTimeout              resultFlag = 0x0384 + 0x9 // timeout polling status flags
    75  )
    76  
    77  const (
    78  	statusTxReady         statusFlag = nxp.LPI2C_MSR_TDF  // transmit data flag
    79  	statusRxReady         statusFlag = nxp.LPI2C_MSR_RDF  // receive data flag
    80  	statusEndOfPacket     statusFlag = nxp.LPI2C_MSR_EPF  // end Packet flag
    81  	statusStopDetect      statusFlag = nxp.LPI2C_MSR_SDF  // stop detect flag
    82  	statusNackDetect      statusFlag = nxp.LPI2C_MSR_NDF  // NACK detect flag
    83  	statusArbitrationLost statusFlag = nxp.LPI2C_MSR_ALF  // arbitration lost flag
    84  	statusFifoErr         statusFlag = nxp.LPI2C_MSR_FEF  // FIFO error flag
    85  	statusPinLowTimeout   statusFlag = nxp.LPI2C_MSR_PLTF // pin low timeout flag
    86  	statusI2CDataMatch    statusFlag = nxp.LPI2C_MSR_DMF  // data match flag
    87  	statusBusy            statusFlag = nxp.LPI2C_MSR_MBF  // busy flag
    88  	statusBusBusy         statusFlag = nxp.LPI2C_MSR_BBF  // bus busy flag
    89  
    90  	// all flags which are cleared by the driver upon starting a transfer
    91  	statusClear statusFlag = statusEndOfPacket | statusStopDetect | statusNackDetect |
    92  		statusArbitrationLost | statusFifoErr | statusPinLowTimeout | statusI2CDataMatch
    93  
    94  	// IRQ sources enabled by the non-blocking transactional API
    95  	statusIrq statusFlag = statusArbitrationLost | statusTxReady | statusRxReady |
    96  		statusStopDetect | statusNackDetect | statusPinLowTimeout | statusFifoErr
    97  
    98  	// errors to check for
    99  	statusError statusFlag = statusNackDetect | statusArbitrationLost | statusFifoErr |
   100  		statusPinLowTimeout
   101  )
   102  
   103  // LPI2C transfer modes
   104  const (
   105  	transferDefault       transferFlag = 0x0 // transfer starts with a start signal, stops with a stop signal
   106  	transferNoStart       transferFlag = 0x1 // don't send a start condition, address, and sub address
   107  	transferRepeatedStart transferFlag = 0x2 // send a repeated start condition
   108  	transferNoStop        transferFlag = 0x4 // don't send a stop condition
   109  )
   110  
   111  // LPI2C FIFO commands
   112  const (
   113  	commandTxData commandFlag = (0x0 << nxp.LPI2C_MTDR_CMD_Pos) & nxp.LPI2C_MTDR_CMD_Msk // transmit
   114  	commandRxData commandFlag = (0x1 << nxp.LPI2C_MTDR_CMD_Pos) & nxp.LPI2C_MTDR_CMD_Msk // receive
   115  	commandStop   commandFlag = (0x2 << nxp.LPI2C_MTDR_CMD_Pos) & nxp.LPI2C_MTDR_CMD_Msk // generate STOP condition
   116  	commandStart  commandFlag = (0x4 << nxp.LPI2C_MTDR_CMD_Pos) & nxp.LPI2C_MTDR_CMD_Msk // generate (REPEATED)START and transmit
   117  )
   118  
   119  // LPI2C transactional states
   120  const (
   121  	stateIdle              stateFlag = 0x0
   122  	stateSendCommand       stateFlag = 0x1
   123  	stateIssueReadCommand  stateFlag = 0x2
   124  	stateTransferData      stateFlag = 0x3
   125  	stateStop              stateFlag = 0x4
   126  	stateWaitForCompletion stateFlag = 0x5
   127  )
   128  
   129  func (i2c *I2C) setPins(c I2CConfig) (sda, scl Pin) {
   130  	// if both given pins are defined, or either receiver pin is undefined.
   131  	if 0 != c.SDA && 0 != c.SCL || 0 == i2c.sda || 0 == i2c.scl {
   132  		// override the receiver's pins.
   133  		i2c.sda, i2c.scl = c.SDA, c.SCL
   134  	}
   135  	// return the selected pins.
   136  	return i2c.sda, i2c.scl
   137  }
   138  
   139  // Configure is intended to setup an I2C interface for transmit/receive.
   140  func (i2c *I2C) Configure(config I2CConfig) error {
   141  	// init pins
   142  	sda, scl := i2c.setPins(config)
   143  
   144  	// configure the mux and pad control registers
   145  	sda.Configure(PinConfig{Mode: PinModeI2CSDA})
   146  	scl.Configure(PinConfig{Mode: PinModeI2CSCL})
   147  
   148  	// configure the mux input selector
   149  	i2c.muxSDA.connect()
   150  	i2c.muxSCL.connect()
   151  
   152  	freq := config.Frequency
   153  	if 0 == freq {
   154  		freq = 100 * KHz
   155  	}
   156  
   157  	// reset clock and registers, and enable LPI2C module interface
   158  	i2c.reset(freq)
   159  
   160  	return nil
   161  }
   162  
   163  // SetBaudRate sets the communication speed for I2C.
   164  func (i2c I2C) SetBaudRate(br uint32) error {
   165  	// TODO: implement
   166  	return errI2CNotImplemented
   167  }
   168  
   169  func (i2c I2C) Tx(addr uint16, w, r []byte) error {
   170  	// perform transmit transfer
   171  	if nil != w {
   172  		// generate start condition on bus
   173  		if result := i2c.start(addr, directionWrite); resultSuccess != result {
   174  			return errI2CSignalStartTimeout
   175  		}
   176  		// ensure TX FIFO is empty
   177  		if result := i2c.waitForTxEmpty(); resultSuccess != result {
   178  			return errI2CBusReadyTimeout
   179  		}
   180  		// check if communication was successful
   181  		if status := statusFlag(i2c.Bus.MSR.Get()); 0 != (status & statusNackDetect) {
   182  			return errI2CAckExpected
   183  		}
   184  		// send transmit data
   185  		if result := i2c.controllerTransmit(w); resultSuccess != result {
   186  			return errI2CWriteTimeout
   187  		}
   188  	}
   189  
   190  	// perform receive transfer
   191  	if nil != r {
   192  		// generate (repeated-)start condition on bus
   193  		if result := i2c.start(addr, directionRead); resultSuccess != result {
   194  			return errI2CSignalStartTimeout
   195  		}
   196  		// read received data
   197  		if result := i2c.controllerReceive(r); resultSuccess != result {
   198  			return errI2CReadTimeout
   199  		}
   200  	}
   201  
   202  	// generate stop condition on bus
   203  	if result := i2c.stop(); resultSuccess != result {
   204  		return errI2CSignalStopTimeout
   205  	}
   206  
   207  	return nil
   208  }
   209  
   210  // WriteRegisterEx transmits first the register and then the data to the
   211  // peripheral device.
   212  //
   213  // Many I2C-compatible devices are organized in terms of registers. This method
   214  // is a shortcut to easily write to such registers. Also, it only works for
   215  // devices with 7-bit addresses, which is the vast majority.
   216  func (i2c I2C) WriteRegisterEx(address uint8, register uint8, data []byte) error {
   217  	option := transferOption{
   218  		flags:          transferDefault,  // transfer options bit mask (0 = normal transfer)
   219  		peripheral:     uint16(address),  // 7-bit peripheral address
   220  		direction:      directionWrite,   // directionRead or directionWrite
   221  		subaddress:     uint16(register), // peripheral sub-address (transferred MSB first)
   222  		subaddressSize: 1,                // byte length of sub-address (maximum = 4 bytes)
   223  	}
   224  	if result := i2c.controllerTransferPoll(option, data); resultSuccess != result {
   225  		return errI2CWriteTimeout
   226  	}
   227  	return nil
   228  }
   229  
   230  // ReadRegisterEx transmits the register, restarts the connection as a read
   231  // operation, and reads the response.
   232  //
   233  // Many I2C-compatible devices are organized in terms of registers. This method
   234  // is a shortcut to easily read such registers. Also, it only works for devices
   235  // with 7-bit addresses, which is the vast majority.
   236  func (i2c I2C) ReadRegisterEx(address uint8, register uint8, data []byte) error {
   237  	option := transferOption{
   238  		flags:          transferDefault,  // transfer options bit mask (0 = normal transfer)
   239  		peripheral:     uint16(address),  // 7-bit peripheral address
   240  		direction:      directionRead,    // directionRead or directionWrite
   241  		subaddress:     uint16(register), // peripheral sub-address (transferred MSB first)
   242  		subaddressSize: 1,                // byte length of sub-address (maximum = 4 bytes)
   243  	}
   244  	if result := i2c.controllerTransferPoll(option, data); resultSuccess != result {
   245  		return errI2CWriteTimeout
   246  	}
   247  	return nil
   248  }
   249  
   250  func (i2c *I2C) reset(freq uint32) {
   251  	// disable interface
   252  	i2c.Bus.MCR.ClearBits(nxp.LPI2C_MCR_MEN)
   253  
   254  	// software reset all interface registers
   255  	i2c.Bus.MCR.Set(nxp.LPI2C_MCR_RST)
   256  
   257  	// RST remains set until manually cleared!
   258  	i2c.Bus.MCR.ClearBits(nxp.LPI2C_MCR_RST)
   259  
   260  	// disable host request
   261  	i2c.Bus.MCFGR0.Set(0)
   262  
   263  	// enable ACK, use I2C 2-pin open drain mode
   264  	i2c.Bus.MCFGR1.Set(0)
   265  
   266  	// set FIFO watermarks (RX=1, TX=1)
   267  	mfcr := (uint32(0x1) << nxp.LPI2C_MFCR_RXWATER_Pos) & nxp.LPI2C_MFCR_RXWATER_Msk
   268  	mfcr |= (uint32(0x1) << nxp.LPI2C_MFCR_TXWATER_Pos) & nxp.LPI2C_MFCR_TXWATER_Msk
   269  	i2c.Bus.MFCR.Set(mfcr)
   270  
   271  	// configure clock using receiver frequency
   272  	i2c.setFrequency(freq)
   273  
   274  	// clear reset, and enable the interface
   275  	i2c.Bus.MCR.Set(nxp.LPI2C_MCR_MEN)
   276  
   277  	// wait for the I2C bus to idle
   278  	for i2c.Bus.MSR.Get()&nxp.LPI2C_MSR_BBF != 0 {
   279  	}
   280  }
   281  
   282  func (i2c *I2C) setFrequency(freq uint32) {
   283  	var (
   284  		bestPre   uint32 = 0
   285  		bestClkHi uint32 = 0
   286  		bestError uint32 = 0xFFFFFFFF
   287  	)
   288  
   289  	// disable interface
   290  	wasEnabled := i2c.Bus.MCR.HasBits(nxp.LPI2C_MCR_MEN)
   291  	i2c.Bus.MCR.ClearBits(nxp.LPI2C_MCR_MEN)
   292  
   293  	// baud rate = (24MHz/(2^pre))/(CLKLO+1 + CLKHI+1 + FLOOR((2+FILTSCL)/(2^pre)))
   294  	// assume: CLKLO=2*CLKHI, SETHOLD=CLKHI, DATAVD=CLKHI/2
   295  	for pre := uint32(1); pre <= 128; pre *= 2 {
   296  		if bestError == 0 {
   297  			break
   298  		}
   299  		for clkHi := uint32(1); clkHi < 32; clkHi++ {
   300  			var absError, rate uint32
   301  			if clkHi == 1 {
   302  				rate = (24 * MHz / pre) / (1 + 3 + 2 + 2/pre)
   303  			} else {
   304  				rate = (24 * MHz / pre) / (3*clkHi + 2 + 2/pre)
   305  			}
   306  			if freq > rate {
   307  				absError = freq - rate
   308  			} else {
   309  				absError = rate - freq
   310  			}
   311  			if absError < bestError {
   312  				bestPre = pre
   313  				bestClkHi = clkHi
   314  				bestError = absError
   315  				// if the error is 0, then we can stop searching because we won't find a
   316  				// better match
   317  				if absError == 0 {
   318  					break
   319  				}
   320  			}
   321  		}
   322  	}
   323  
   324  	var (
   325  		clklo   = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_CLKLO_Pos) & nxp.LPI2C_MCCR0_CLKLO_Msk }
   326  		clkhi   = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_CLKHI_Pos) & nxp.LPI2C_MCCR0_CLKHI_Msk }
   327  		datavd  = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_DATAVD_Pos) & nxp.LPI2C_MCCR0_DATAVD_Msk }
   328  		sethold = func(n uint32) uint32 { return (n << nxp.LPI2C_MCCR0_SETHOLD_Pos) & nxp.LPI2C_MCCR0_SETHOLD_Msk }
   329  	)
   330  	// StandardMode, FastMode, FastModePlus, and UltraFastMode
   331  	mccr0 := clkhi(bestClkHi)
   332  	if bestClkHi < 2 {
   333  		mccr0 |= (clklo(3) | sethold(2) | datavd(1))
   334  	} else {
   335  		mccr0 |= clklo(2*bestClkHi) | sethold(bestClkHi) | datavd(bestClkHi/2)
   336  	}
   337  	i2c.Bus.MCCR0.Set(mccr0)
   338  	i2c.Bus.MCCR1.Set(i2c.Bus.MCCR0.Get())
   339  
   340  	for i := uint32(0); i < 8; i++ {
   341  		if bestPre == (1 << i) {
   342  			bestPre = i
   343  			break
   344  		}
   345  	}
   346  	preMask := (bestPre << nxp.LPI2C_MCFGR1_PRESCALE_Pos) & nxp.LPI2C_MCFGR1_PRESCALE_Msk
   347  	i2c.Bus.MCFGR1.Set((i2c.Bus.MCFGR1.Get() & ^uint32(nxp.LPI2C_MCFGR1_PRESCALE_Msk)) | preMask)
   348  
   349  	var (
   350  		filtsda = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR2_FILTSDA_Pos) & nxp.LPI2C_MCFGR2_FILTSDA_Msk }
   351  		filtscl = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR2_FILTSCL_Pos) & nxp.LPI2C_MCFGR2_FILTSCL_Msk }
   352  		busidle = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR2_BUSIDLE_Pos) & nxp.LPI2C_MCFGR2_BUSIDLE_Msk }
   353  		pinlow  = func(n uint32) uint32 { return (n << nxp.LPI2C_MCFGR3_PINLOW_Pos) & nxp.LPI2C_MCFGR3_PINLOW_Msk }
   354  
   355  		mcfgr2, mcfgr3 uint32
   356  	)
   357  	const i2cClockStretchTimeout = 15000 // microseconds
   358  	if freq >= 5*MHz {
   359  		// I2C UltraFastMode 5 MHz
   360  		mcfgr2 = 0 // disable glitch filters and timeout for UltraFastMode
   361  		mcfgr3 = 0 //
   362  	} else if freq >= 1*MHz {
   363  		// I2C FastModePlus 1 MHz
   364  		mcfgr2 = filtsda(1) | filtscl(1) | busidle(2400) // 100us timeout
   365  		mcfgr3 = pinlow(i2cClockStretchTimeout*24/256 + 1)
   366  	} else if freq >= 400*KHz {
   367  		// I2C FastMode 400 kHz
   368  		mcfgr2 = filtsda(2) | filtscl(2) | busidle(3600) // 150us timeout
   369  		mcfgr3 = pinlow(i2cClockStretchTimeout*24/256 + 1)
   370  	} else {
   371  		// I2C StandardMode 100 kHz
   372  		mcfgr2 = filtsda(5) | filtscl(5) | busidle(3000) // 250us timeout
   373  		mcfgr3 = pinlow(i2cClockStretchTimeout*12/256 + 1)
   374  	}
   375  	i2c.Bus.MCFGR2.Set(mcfgr2)
   376  	i2c.Bus.MCFGR3.Set(mcfgr3)
   377  
   378  	// restore controller mode if it was enabled when called
   379  	if wasEnabled {
   380  		i2c.Bus.MCR.SetBits(nxp.LPI2C_MCR_MEN)
   381  	}
   382  }
   383  
   384  // checkStatus converts the status register to a resultFlag for return, and
   385  // clears any errors if present.
   386  func (i2c *I2C) checkStatus(status statusFlag) resultFlag {
   387  	result := resultSuccess
   388  	// check for error. these errors cause a stop to be sent automatically.
   389  	// we must clear the errors before a new transfer can start.
   390  	if status &= statusError; 0 != status {
   391  		// select the correct error code ordered by severity, bus issues first.
   392  		if 0 != (status & statusPinLowTimeout) {
   393  			result = resultPinLowTimeout
   394  		} else if 0 != (status & statusArbitrationLost) {
   395  			result = resultArbitrationLost
   396  		} else if 0 != (status & statusNackDetect) {
   397  			result = resultNak
   398  		} else if 0 != (status & statusFifoErr) {
   399  			result = resultFifoError
   400  		}
   401  		// clear the flags
   402  		i2c.Bus.MSR.Set(uint32(status))
   403  		// reset fifos. these flags clear automatically.
   404  		i2c.Bus.MCR.SetBits(nxp.LPI2C_MCR_RRF | nxp.LPI2C_MCR_RTF)
   405  	}
   406  	return result
   407  }
   408  
   409  func (i2c *I2C) getFIFOSize() (rx, tx uint32) { return 4, 4 }
   410  func (i2c *I2C) getFIFOCount() (rx, tx uint32) {
   411  	mfsr := i2c.Bus.MFSR.Get()
   412  	return (mfsr & nxp.LPI2C_MFSR_RXCOUNT_Msk) >> nxp.LPI2C_MFSR_RXCOUNT_Pos,
   413  		(mfsr & nxp.LPI2C_MFSR_TXCOUNT_Msk) >> nxp.LPI2C_MFSR_TXCOUNT_Pos
   414  }
   415  
   416  func (i2c *I2C) waitForTxReady() resultFlag {
   417  	result := resultSuccess
   418  	_, txSize := i2c.getFIFOSize()
   419  	for {
   420  		_, txCount := i2c.getFIFOCount()
   421  		status := statusFlag(i2c.Bus.MSR.Get())
   422  		if result = i2c.checkStatus(status); resultSuccess != result {
   423  			break
   424  		}
   425  		if txSize-txCount > 0 {
   426  			break
   427  		}
   428  	}
   429  	return result
   430  }
   431  
   432  func (i2c *I2C) waitForTxEmpty() resultFlag {
   433  	result := resultSuccess
   434  	for {
   435  		_, txCount := i2c.getFIFOCount()
   436  		status := statusFlag(i2c.Bus.MSR.Get())
   437  		if result = i2c.checkStatus(status); resultSuccess != result {
   438  			break
   439  		}
   440  		if 0 == txCount {
   441  			break
   442  		}
   443  	}
   444  	return result
   445  }
   446  
   447  // isBusBusy checks if the I2C bus is busy, returning true if it is busy and we
   448  // are not the ones driving it, otherwise false.
   449  func (i2c *I2C) isBusBusy() bool {
   450  	status := statusFlag(i2c.Bus.MSR.Get())
   451  	return (0 != (status & statusBusBusy)) && (0 == (status & statusBusy))
   452  }
   453  
   454  // start sends a START signal and peripheral address on the I2C bus.
   455  //
   456  // This function is used to initiate a new controller mode transfer. First, the
   457  // bus state is checked to ensure that another controller is not occupying the
   458  // bus. Then a START signal is transmitted, followed by the 7-bit peripheral
   459  // address. Note that this function does not actually wait until the START and
   460  // address are successfully sent on the bus before returning.
   461  func (i2c *I2C) start(address uint16, dir i2cDirection) resultFlag {
   462  	// return an error if the bus is already in use by another controller
   463  	if i2c.isBusBusy() {
   464  		return resultBusy
   465  	}
   466  	// clear all flags
   467  	i2c.Bus.MSR.Set(uint32(statusClear))
   468  	// turn off auto-stop
   469  	i2c.Bus.MCFGR1.ClearBits(nxp.LPI2C_MCFGR1_AUTOSTOP)
   470  	// wait until there is room in the FIFO
   471  	if result := i2c.waitForTxReady(); resultSuccess != result {
   472  		return result
   473  	}
   474  
   475  	// issue start command
   476  	i2c.Bus.MTDR.Set(uint32(commandStart) | dir.shift(address))
   477  	return resultSuccess
   478  }
   479  
   480  // stop sends a STOP signal on the I2C bus.
   481  //
   482  // This function does not return until the STOP signal is seen on the bus, or
   483  // an error occurs.
   484  func (i2c *I2C) stop() resultFlag {
   485  	const tryMax = 0 // keep waiting forever
   486  	// wait until there is room in the FIFO
   487  	result := i2c.waitForTxReady()
   488  	if resultSuccess != result {
   489  		return result
   490  	}
   491  	// send the STOP signal
   492  	i2c.Bus.MTDR.Set(uint32(commandStop))
   493  	// wait for the stop detected flag to set, indicating the transfer has
   494  	// completed on the bus. also check for errors while waiting.
   495  	try := 0
   496  	for resultSuccess == result && (0 == tryMax || try < tryMax) {
   497  		status := statusFlag(i2c.Bus.MSR.Get())
   498  		result = i2c.checkStatus(status)
   499  		if (0 != (status & statusStopDetect)) && (0 != (status & statusTxReady)) {
   500  			i2c.Bus.MSR.Set(uint32(statusStopDetect))
   501  			break
   502  		}
   503  		try++
   504  	}
   505  	if 0 != tryMax && try >= tryMax {
   506  		return resultTimeout
   507  	}
   508  	return result
   509  }
   510  
   511  // controllerReceive performs a polling receive transfer on the I2C bus.
   512  func (i2c *I2C) controllerReceive(rxBuffer []byte) resultFlag {
   513  	const tryMax = 0 // keep trying forever
   514  	rxSize := len(rxBuffer)
   515  	if rxSize == 0 {
   516  		return resultSuccess
   517  	}
   518  	// wait until there is room in the FIFO
   519  	result := i2c.waitForTxReady()
   520  	if resultSuccess != result {
   521  		return result
   522  	}
   523  	sizeMask := (uint32(rxSize-1) << nxp.LPI2C_MTDR_DATA_Pos) & nxp.LPI2C_MTDR_DATA_Msk
   524  	i2c.Bus.MTDR.Set(uint32(commandRxData) | sizeMask)
   525  
   526  	// receive data
   527  	for rxSize > 0 {
   528  		// read LPI2C receive FIFO register. the register includes a flag to
   529  		// indicate whether the FIFO is empty, so we can both get the data and check
   530  		// if we need to keep reading using a single register read.
   531  		var data uint32
   532  		try := 0
   533  		for 0 == tryMax || try < tryMax {
   534  			// check for errors on the bus
   535  			status := statusFlag(i2c.Bus.MSR.Get())
   536  			result = i2c.checkStatus(status)
   537  			if resultSuccess != result {
   538  				return result
   539  			}
   540  			// read received data, break if FIFO was non-empty
   541  			data = i2c.Bus.MRDR.Get()
   542  			if 0 == (data & nxp.LPI2C_MRDR_RXEMPTY_Msk) {
   543  				break
   544  			}
   545  			try++
   546  		}
   547  		// ensure we didn't timeout waiting for data
   548  		if 0 != tryMax && try >= tryMax {
   549  			return resultTimeout
   550  		}
   551  		// copy data to RX buffer
   552  		rxBuffer[len(rxBuffer)-rxSize] = byte(data & nxp.LPI2C_MRDR_DATA_Msk)
   553  		rxSize--
   554  	}
   555  	return result
   556  }
   557  
   558  // controllerTransmit performs a polling transmit transfer on the I2C bus.
   559  func (i2c *I2C) controllerTransmit(txBuffer []byte) resultFlag {
   560  	txSize := len(txBuffer)
   561  	for txSize > 0 {
   562  		// wait until there is room in the FIFO
   563  		result := i2c.waitForTxReady()
   564  		if resultSuccess != result {
   565  			return result
   566  		}
   567  		// write byte into LPI2C data register
   568  		i2c.Bus.MTDR.Set(uint32(txBuffer[len(txBuffer)-txSize] & nxp.LPI2C_MTDR_DATA_Msk))
   569  		txSize--
   570  	}
   571  	return resultSuccess
   572  }
   573  
   574  type transferOption struct {
   575  	flags          transferFlag // transfer options bit mask (0 = normal transfer)
   576  	peripheral     uint16       // 7-bit peripheral address
   577  	direction      i2cDirection // directionRead or directionWrite
   578  	subaddress     uint16       // peripheral sub-address (transferred MSB first)
   579  	subaddressSize uint16       // byte length of sub-address (maximum = 4 bytes)
   580  }
   581  
   582  func (i2c *I2C) controllerTransferPoll(option transferOption, data []byte) resultFlag {
   583  	// return an error if the bus is already in use by another controller
   584  	if i2c.isBusBusy() {
   585  		return resultBusy
   586  	}
   587  	// clear all flags
   588  	i2c.Bus.MSR.Set(uint32(statusClear))
   589  	// turn off auto-stop
   590  	i2c.Bus.MCFGR1.ClearBits(nxp.LPI2C_MCFGR1_AUTOSTOP)
   591  
   592  	cmd := make([]uint16, 0, 7)
   593  	size := len(data)
   594  
   595  	direction := option.direction
   596  	if option.subaddressSize > 0 {
   597  		direction = directionWrite
   598  	}
   599  	// peripheral address
   600  	if 0 == (option.flags & transferNoStart) {
   601  		addr := direction.shift(option.peripheral)
   602  		cmd = append(cmd, uint16(uint32(commandStart)|addr))
   603  	}
   604  	// sub-address (MSB-first)
   605  	rem := option.subaddressSize
   606  	for rem > 0 {
   607  		rem--
   608  		cmd = append(cmd, (option.subaddress>>(8*rem))&0xFF)
   609  	}
   610  	// need to send repeated start if switching directions to read
   611  	if (0 != size) && (directionRead == option.direction) {
   612  		if directionWrite == direction {
   613  			addr := directionRead.shift(option.peripheral)
   614  			cmd = append(cmd, uint16(uint32(commandStart)|addr))
   615  		}
   616  	}
   617  	// send command buffer
   618  	result := resultSuccess
   619  	for _, c := range cmd {
   620  		// wait until there is room in the FIFO
   621  		if result = i2c.waitForTxReady(); resultSuccess != result {
   622  			return result
   623  		}
   624  		// write byte into LPI2C controller data register
   625  		i2c.Bus.MTDR.Set(uint32(c))
   626  	}
   627  	// send data
   628  	if option.direction == directionWrite && size > 0 {
   629  		result = i2c.controllerTransmit(data)
   630  	}
   631  	// receive data
   632  	if option.direction == directionRead && size > 0 {
   633  		result = i2c.controllerReceive(data)
   634  	}
   635  	if resultSuccess != result {
   636  		return result
   637  	}
   638  	if 0 == (option.flags & transferNoStop) {
   639  		result = i2c.stop()
   640  	}
   641  	return result
   642  }