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

     1  //go:build rp2040
     2  
     3  package machine
     4  
     5  import (
     6  	"device/rp"
     7  	"errors"
     8  	"internal/itoa"
     9  )
    10  
    11  // I2C on the RP2040.
    12  var (
    13  	I2C0  = &_I2C0
    14  	_I2C0 = I2C{
    15  		Bus: rp.I2C0,
    16  	}
    17  	I2C1  = &_I2C1
    18  	_I2C1 = I2C{
    19  		Bus: rp.I2C1,
    20  	}
    21  )
    22  
    23  // The I2C target implementation is based on the C implementation from
    24  // here: https://github.com/vmilea/pico_i2c_slave
    25  
    26  // Features: Taken from datasheet.
    27  // Default controller mode, with target mode available (not simulataneously).
    28  // Default target address of RP2040: 0x055
    29  // Supports 10-bit addressing in controller mode
    30  // 16-element transmit buffer
    31  // 16-element receive buffer
    32  // Can be driven from DMA
    33  // Can generate interrupts
    34  // Fast mode plus max transfer speed (1000kb/s)
    35  
    36  // GPIO config
    37  // Each controller must connect its clock SCL and data SDA to one pair of GPIOs.
    38  // The I2C standard requires that drivers drivea signal low, or when not driven the signal will be pulled high.
    39  // This applies to SCL and SDA. The GPIO pads should beconfigured for:
    40  //  Pull-up enabled
    41  //  Slew rate limited
    42  //  Schmitt trigger enabled
    43  // Note: There should also be external pull-ups on the board as the internal pad pull-ups may not be strong enough to pull upexternal circuits.
    44  
    45  // I2CConfig is used to store config info for I2C.
    46  type I2CConfig struct {
    47  	Frequency uint32
    48  	// SDA/SCL Serial Data and clock pins. Refer to datasheet to see
    49  	// which pins match the desired bus.
    50  	SDA, SCL Pin
    51  	Mode     I2CMode
    52  }
    53  
    54  type I2C struct {
    55  	Bus          *rp.I2C0_Type
    56  	mode         I2CMode
    57  	txInProgress bool
    58  }
    59  
    60  var (
    61  	ErrInvalidI2CBaudrate  = errors.New("invalid i2c baudrate")
    62  	ErrInvalidTgtAddr      = errors.New("invalid target i2c address not in 0..0x80 or is reserved")
    63  	ErrI2CGeneric          = errors.New("i2c error")
    64  	ErrRP2040I2CDisable    = errors.New("i2c rp2040 peripheral timeout in disable")
    65  	errInvalidI2CSDA       = errors.New("invalid I2C SDA pin")
    66  	errInvalidI2CSCL       = errors.New("invalid I2C SCL pin")
    67  	ErrI2CAlreadyListening = errors.New("i2c already listening")
    68  	ErrI2CWrongMode        = errors.New("i2c wrong mode")
    69  	ErrI2CUnderflow        = errors.New("i2c underflow")
    70  )
    71  
    72  // Tx performs a write and then a read transfer placing the result in
    73  // in r.
    74  //
    75  // Passing a nil value for w or r skips the transfer corresponding to write
    76  // or read, respectively.
    77  //
    78  //	i2c.Tx(addr, nil, r)
    79  //
    80  // Performs only a read transfer.
    81  //
    82  //	i2c.Tx(addr, w, nil)
    83  //
    84  // Performs only a write transfer.
    85  func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
    86  	if i2c.mode != I2CModeController {
    87  		return ErrI2CWrongMode
    88  	}
    89  
    90  	// timeout in microseconds.
    91  	const timeout = 40 * 1000 // 40ms is a reasonable time for a real-time system.
    92  	return i2c.tx(uint8(addr), w, r, timeout)
    93  }
    94  
    95  // Listen starts listening for I2C requests sent to specified address
    96  //
    97  // addr is the address to listen to
    98  func (i2c *I2C) Listen(addr uint16) error {
    99  	if i2c.mode != I2CModeTarget {
   100  		return ErrI2CWrongMode
   101  	}
   102  
   103  	return i2c.listen(uint8(addr))
   104  }
   105  
   106  // Configure initializes i2c peripheral and configures I2C config's pins passed.
   107  // Here's a list of valid SDA and SCL GPIO pins on bus I2C0 of the rp2040:
   108  //
   109  //	SDA: 0, 4, 8, 12, 16, 20
   110  //	SCL: 1, 5, 9, 13, 17, 21
   111  //
   112  // Same as above for I2C1 bus:
   113  //
   114  //	SDA: 2, 6, 10, 14, 18, 26
   115  //	SCL: 3, 7, 11, 15, 19, 27
   116  func (i2c *I2C) Configure(config I2CConfig) error {
   117  	const defaultBaud uint32 = 100_000 // 100kHz standard mode
   118  	if config.SCL == 0 && config.SDA == 0 {
   119  		// If config pins are zero valued or clock pin is invalid then we set default values.
   120  		switch i2c.Bus {
   121  		case rp.I2C0:
   122  			config.SCL = I2C0_SCL_PIN
   123  			config.SDA = I2C0_SDA_PIN
   124  		case rp.I2C1:
   125  			config.SCL = I2C1_SCL_PIN
   126  			config.SDA = I2C1_SDA_PIN
   127  		}
   128  	}
   129  	var okSCL, okSDA bool
   130  	switch i2c.Bus {
   131  	case rp.I2C0:
   132  		okSCL = (config.SCL+3)%4 == 0
   133  		okSDA = (config.SDA+4)%4 == 0
   134  	case rp.I2C1:
   135  		okSCL = (config.SCL+1)%4 == 0
   136  		okSDA = (config.SDA+2)%4 == 0
   137  	}
   138  
   139  	switch {
   140  	case !okSCL:
   141  		return errInvalidI2CSCL
   142  	case !okSDA:
   143  		return errInvalidI2CSDA
   144  	}
   145  
   146  	if config.Frequency == 0 {
   147  		config.Frequency = defaultBaud
   148  	}
   149  	config.SDA.Configure(PinConfig{PinI2C})
   150  	config.SCL.Configure(PinConfig{PinI2C})
   151  	return i2c.init(config)
   152  }
   153  
   154  // SetBaudRate sets the I2C frequency. It has the side effect of also
   155  // enabling the I2C hardware if disabled beforehand.
   156  //
   157  //go:inline
   158  func (i2c *I2C) SetBaudRate(br uint32) error {
   159  
   160  	if br == 0 {
   161  		return ErrInvalidI2CBaudrate
   162  	}
   163  
   164  	// I2C is synchronous design that runs from clk_sys
   165  	freqin := CPUFrequency()
   166  
   167  	// TODO there are some subtleties to I2C timing which we are completely ignoring here
   168  	period := (freqin + br/2) / br
   169  	lcnt := period * 3 / 5 // oof this one hurts
   170  	hcnt := period - lcnt
   171  	// Check for out-of-range divisors:
   172  	if hcnt > rp.I2C0_IC_FS_SCL_HCNT_IC_FS_SCL_HCNT_Msk || hcnt < 8 || lcnt > rp.I2C0_IC_FS_SCL_LCNT_IC_FS_SCL_LCNT_Msk || lcnt < 8 {
   173  		return ErrInvalidI2CBaudrate
   174  	}
   175  
   176  	// Per I2C-bus specification a device in standard or fast mode must
   177  	// internally provide a hold time of at least 300ns for the SDA signal to
   178  	// bridge the undefined region of the falling edge of SCL. A smaller hold
   179  	// time of 120ns is used for fast mode plus.
   180  
   181  	// sda_tx_hold_count = freq_in [cycles/s] * 300ns * (1s / 1e9ns)
   182  	// Reduce 300/1e9 to 3/1e7 to avoid numbers that don't fit in uint.
   183  	// Add 1 to avoid division truncation.
   184  	sdaTxHoldCnt := ((freqin * 3) / 10000000) + 1
   185  	if br >= 1_000_000 {
   186  		// sda_tx_hold_count = freq_in [cycles/s] * 120ns * (1s / 1e9ns)
   187  		// Reduce 120/1e9 to 3/25e6 to avoid numbers that don't fit in uint.
   188  		// Add 1 to avoid division truncation.
   189  		sdaTxHoldCnt = ((freqin * 3) / 25000000) + 1
   190  	}
   191  
   192  	if sdaTxHoldCnt > lcnt-2 {
   193  		return ErrInvalidI2CBaudrate
   194  	}
   195  	err := i2c.disable()
   196  	if err != nil {
   197  		return err
   198  	}
   199  	// Always use "fast" mode (<= 400 kHz, works fine for standard mode too)
   200  
   201  	i2c.Bus.IC_CON.ReplaceBits(rp.I2C0_IC_CON_SPEED_FAST<<rp.I2C0_IC_CON_SPEED_Pos, rp.I2C0_IC_CON_SPEED_Msk, 0)
   202  	i2c.Bus.IC_FS_SCL_HCNT.Set(hcnt)
   203  	i2c.Bus.IC_FS_SCL_LCNT.Set(lcnt)
   204  
   205  	i2c.Bus.IC_FS_SPKLEN.Set(u32max(1, lcnt/16))
   206  
   207  	i2c.Bus.IC_SDA_HOLD.ReplaceBits(sdaTxHoldCnt<<rp.I2C0_IC_SDA_HOLD_IC_SDA_TX_HOLD_Pos, rp.I2C0_IC_SDA_HOLD_IC_SDA_TX_HOLD_Msk, 0)
   208  	i2c.enable()
   209  	return nil
   210  }
   211  
   212  //go:inline
   213  func (i2c *I2C) enable() {
   214  	i2c.Bus.IC_ENABLE.ReplaceBits(rp.I2C0_IC_ENABLE_ENABLE<<rp.I2C0_IC_ENABLE_ENABLE_Pos, rp.I2C0_IC_ENABLE_ENABLE_Msk, 0)
   215  }
   216  
   217  // Implemented as per 4.3.10.3. Disabling DW_apb_i2c section.
   218  //
   219  //go:inline
   220  func (i2c *I2C) disable() error {
   221  	const MAX_T_POLL_COUNT = 64 // 64 us timeout corresponds to around 1000kb/s i2c transfer rate.
   222  	deadline := ticks() + MAX_T_POLL_COUNT
   223  	i2c.Bus.IC_ENABLE.Set(0)
   224  	for i2c.Bus.IC_ENABLE_STATUS.Get()&1 != 0 {
   225  		if ticks() > deadline {
   226  			return ErrRP2040I2CDisable
   227  		}
   228  	}
   229  	return nil
   230  }
   231  
   232  //go:inline
   233  func (i2c *I2C) init(config I2CConfig) error {
   234  	i2c.reset()
   235  	if err := i2c.disable(); err != nil {
   236  		return err
   237  	}
   238  
   239  	i2c.mode = config.Mode
   240  
   241  	// Configure as fast-mode with RepStart support, 7-bit addresses
   242  	mode := uint32(rp.I2C0_IC_CON_SPEED_FAST<<rp.I2C0_IC_CON_SPEED_Pos) |
   243  		rp.I2C0_IC_CON_IC_RESTART_EN | rp.I2C0_IC_CON_TX_EMPTY_CTRL // sets TX_EMPTY_CTRL to enable TX_EMPTY interrupt status
   244  	if config.Mode == I2CModeController {
   245  		mode |= rp.I2C0_IC_CON_MASTER_MODE | rp.I2C0_IC_CON_IC_SLAVE_DISABLE
   246  	}
   247  	i2c.Bus.IC_CON.Set(mode)
   248  
   249  	// Set FIFO watermarks to 1 to make things simpler. This is encoded by a register value of 0.
   250  	if config.Mode == I2CModeController {
   251  		i2c.Bus.IC_TX_TL.Set(0)
   252  		i2c.Bus.IC_RX_TL.Set(0)
   253  	}
   254  
   255  	// Always enable the DREQ signalling -- harmless if DMA isn't listening
   256  	i2c.Bus.IC_DMA_CR.Set(rp.I2C0_IC_DMA_CR_TDMAE | rp.I2C0_IC_DMA_CR_RDMAE)
   257  	return i2c.SetBaudRate(config.Frequency)
   258  }
   259  
   260  // reset sets I2C register RESET bits in the reset peripheral and then clears them.
   261  //
   262  //go:inline
   263  func (i2c *I2C) reset() {
   264  	resetVal := i2c.deinit()
   265  	rp.RESETS.RESET.ClearBits(resetVal)
   266  	// Wait until reset is done.
   267  	for !rp.RESETS.RESET_DONE.HasBits(resetVal) {
   268  	}
   269  }
   270  
   271  // deinit sets reset bit for I2C. Must call reset to reenable I2C after deinit.
   272  //
   273  //go:inline
   274  func (i2c *I2C) deinit() (resetVal uint32) {
   275  	switch {
   276  	case i2c.Bus == rp.I2C0:
   277  		resetVal = rp.RESETS_RESET_I2C0
   278  	case i2c.Bus == rp.I2C1:
   279  		resetVal = rp.RESETS_RESET_I2C1
   280  	}
   281  	// Perform I2C reset.
   282  	rp.RESETS.RESET.SetBits(resetVal)
   283  
   284  	return resetVal
   285  }
   286  
   287  // tx performs blocking write followed by read to I2C bus.
   288  func (i2c *I2C) tx(addr uint8, tx, rx []byte, timeout_us uint64) (err error) {
   289  	deadline := ticks() + timeout_us
   290  	if addr >= 0x80 || isReservedI2CAddr(addr) {
   291  		return ErrInvalidTgtAddr
   292  	}
   293  	txlen := len(tx)
   294  	rxlen := len(rx)
   295  	// Quick return if possible.
   296  	if txlen == 0 && rxlen == 0 {
   297  		return nil
   298  	}
   299  
   300  	err = i2c.disable()
   301  	if err != nil {
   302  		return err
   303  	}
   304  	i2c.Bus.IC_TAR.Set(uint32(addr))
   305  	i2c.enable()
   306  	abort := false
   307  	var abortReason i2cAbortError
   308  	txStop := rxlen == 0
   309  	for txCtr := 0; txCtr < txlen; txCtr++ {
   310  		if abort {
   311  			break
   312  		}
   313  		first := txCtr == 0
   314  		last := txCtr == txlen-1 && rxlen == 0
   315  		i2c.Bus.IC_DATA_CMD.Set(
   316  			(boolToBit(first) << rp.I2C0_IC_DATA_CMD_RESTART_Pos) |
   317  				(boolToBit(last && txStop) << rp.I2C0_IC_DATA_CMD_STOP_Pos) |
   318  				uint32(tx[txCtr]))
   319  
   320  		// Wait until the transmission of the address/data from the internal
   321  		// shift register has completed. For this to function correctly, the
   322  		// TX_EMPTY_CTRL flag in IC_CON must be set. The TX_EMPTY_CTRL flag
   323  		// was set in i2c_init.
   324  
   325  		// IC_RAW_INTR_STAT_TX_EMPTY: This bit is set to 1 when the transmit buffer is at or below
   326  		// the threshold value set in the IC_TX_TL register and the
   327  		// transmission of the address/data from the internal shift
   328  		// register for the most recently popped command is
   329  		// completed. It is automatically cleared by hardware when
   330  		// the buffer level goes above the threshold. When
   331  		// IC_ENABLE[0] is set to 0, the TX FIFO is flushed and held
   332  		// in reset. There the TX FIFO looks like it has no data within
   333  		// it, so this bit is set to 1, provided there is activity in the
   334  		// controller or target state machines. When there is no longer
   335  		// any activity, then with ic_en=0, this bit is set to 0.
   336  		for !i2c.interrupted(rp.I2C0_IC_RAW_INTR_STAT_TX_EMPTY) {
   337  			if ticks() > deadline {
   338  				return errI2CWriteTimeout // If there was a timeout, don't attempt to do anything else.
   339  			}
   340  
   341  			gosched()
   342  		}
   343  
   344  		abortReason = i2c.getAbortReason()
   345  		if abortReason != 0 {
   346  			i2c.clearAbortReason()
   347  			abort = true
   348  		}
   349  		if abort || last {
   350  			// If the transaction was aborted or if it completed
   351  			// successfully wait until the STOP condition has occured.
   352  
   353  			// TODO Could there be an abort while waiting for the STOP
   354  			// condition here? If so, additional code would be needed here
   355  			// to take care of the abort.
   356  			for !i2c.interrupted(rp.I2C0_IC_RAW_INTR_STAT_STOP_DET) {
   357  				if ticks() > deadline {
   358  					if abort {
   359  						return abortReason
   360  					}
   361  					return errI2CWriteTimeout
   362  				}
   363  
   364  				gosched()
   365  			}
   366  			i2c.Bus.IC_CLR_STOP_DET.Get()
   367  		}
   368  	}
   369  
   370  	// Midway check for abort. Related issue https://github.com/tinygo-org/tinygo/issues/3671.
   371  	// The root cause for an abort after writing registers was "tx data no ack" (abort code=8).
   372  	// If the abort code was not registered then the whole peripheral would remain in disabled state forever.
   373  	abortReason = i2c.getAbortReason()
   374  	if abortReason != 0 {
   375  		i2c.clearAbortReason()
   376  		abort = true
   377  	}
   378  
   379  	rxStart := txlen == 0
   380  	if rxlen > 0 && !abort {
   381  		for rxCtr := 0; rxCtr < rxlen; rxCtr++ {
   382  			first := rxCtr == 0
   383  			last := rxCtr == rxlen-1
   384  			for i2c.writeAvailable() == 0 {
   385  				gosched()
   386  			}
   387  			i2c.Bus.IC_DATA_CMD.Set(
   388  				boolToBit(first && rxStart)<<rp.I2C0_IC_DATA_CMD_RESTART_Pos |
   389  					boolToBit(last)<<rp.I2C0_IC_DATA_CMD_STOP_Pos |
   390  					rp.I2C0_IC_DATA_CMD_CMD) // -> 1 for read
   391  
   392  			for !abort && i2c.readAvailable() == 0 {
   393  				abortReason = i2c.getAbortReason()
   394  				if abortReason != 0 {
   395  					i2c.clearAbortReason()
   396  					abort = true
   397  				}
   398  				if ticks() > deadline {
   399  					return errI2CReadTimeout // If there was a timeout, don't attempt to do anything else.
   400  				}
   401  
   402  				gosched()
   403  			}
   404  			if abort {
   405  				break
   406  			}
   407  			rx[rxCtr] = uint8(i2c.Bus.IC_DATA_CMD.Get())
   408  		}
   409  	}
   410  	// From Pico SDK: A lot of things could have just happened due to the ingenious and
   411  	// creative design of I2C. Try to figure things out.
   412  	if abort {
   413  		switch {
   414  		case abortReason == 0 || abortReason&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK != 0:
   415  			// No reported errors - seems to happen if there is nothing connected to the bus.
   416  			// Address byte not acknowledged
   417  			err = ErrI2CGeneric
   418  		case abortReason&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK != 0:
   419  			// Address acknowledged, some data not acknowledged
   420  			fallthrough
   421  		default:
   422  			err = abortReason
   423  		}
   424  	}
   425  	return err
   426  }
   427  
   428  // listen sets up for async handling of requests on the I2C bus.
   429  func (i2c *I2C) listen(addr uint8) error {
   430  	if addr >= 0x80 || isReservedI2CAddr(addr) {
   431  		return ErrInvalidTgtAddr
   432  	}
   433  
   434  	err := i2c.disable()
   435  	if err != nil {
   436  		return err
   437  	}
   438  
   439  	i2c.Bus.IC_SAR.Set(uint32(addr))
   440  
   441  	i2c.enable()
   442  
   443  	return nil
   444  }
   445  
   446  func (i2c *I2C) WaitForEvent(buf []byte) (evt I2CTargetEvent, count int, err error) {
   447  	rxPtr := 0
   448  	for {
   449  		stat := i2c.Bus.IC_RAW_INTR_STAT.Get()
   450  
   451  		if stat&rp.I2C0_IC_INTR_MASK_M_RX_FULL != 0 {
   452  			b := uint8(i2c.Bus.IC_DATA_CMD.Get())
   453  			if rxPtr < len(buf) {
   454  				buf[rxPtr] = b
   455  				rxPtr++
   456  			}
   457  		}
   458  
   459  		// Stop
   460  		if stat&rp.I2C0_IC_INTR_MASK_M_STOP_DET != 0 {
   461  			if rxPtr > 0 {
   462  				return I2CReceive, rxPtr, nil
   463  			}
   464  
   465  			i2c.Bus.IC_CLR_STOP_DET.Get() // clear
   466  			return I2CFinish, 0, nil
   467  		}
   468  
   469  		// Start or restart - ignore start, return on restart
   470  		if stat&rp.I2C0_IC_INTR_MASK_M_START_DET != 0 {
   471  			i2c.Bus.IC_CLR_START_DET.Get() // clear restart
   472  
   473  			// Restart
   474  			if rxPtr > 0 {
   475  				return I2CReceive, rxPtr, nil
   476  			}
   477  		}
   478  
   479  		// Read request - leave flag set until we start to reply.
   480  		if stat&rp.I2C0_IC_INTR_MASK_M_RD_REQ != 0 {
   481  			return I2CRequest, 0, nil
   482  		}
   483  
   484  		gosched()
   485  	}
   486  }
   487  
   488  func (i2c *I2C) Reply(buf []byte) error {
   489  	txPtr := 0
   490  
   491  	stat := i2c.Bus.IC_RAW_INTR_STAT.Get()
   492  
   493  	if stat&rp.I2C0_IC_INTR_MASK_M_RD_REQ == 0 {
   494  		return ErrI2CWrongMode
   495  	}
   496  	i2c.Bus.IC_CLR_RD_REQ.Get() // clear restart
   497  
   498  	// Clear any dangling TX abort
   499  	if stat&rp.I2C0_IC_INTR_MASK_M_TX_ABRT != 0 {
   500  		i2c.Bus.IC_CLR_TX_ABRT.Get()
   501  	}
   502  
   503  	for txPtr < len(buf) {
   504  		if stat&rp.I2C0_IC_INTR_MASK_M_TX_EMPTY != 0 {
   505  			i2c.Bus.IC_DATA_CMD.Set(uint32(buf[txPtr]))
   506  			txPtr++
   507  		}
   508  
   509  		// This Tx abort is a normal case - we're sending more
   510  		// data than controller wants to receive
   511  		if stat&rp.I2C0_IC_INTR_MASK_M_TX_ABRT != 0 {
   512  			i2c.Bus.IC_CLR_TX_ABRT.Get()
   513  			return nil
   514  		}
   515  
   516  		gosched()
   517  	}
   518  
   519  	return nil
   520  }
   521  
   522  // writeAvailable determines non-blocking write space available
   523  //
   524  //go:inline
   525  func (i2c *I2C) writeAvailable() uint32 {
   526  	return rp.I2C0_IC_COMP_PARAM_1_TX_BUFFER_DEPTH_Pos - i2c.Bus.IC_TXFLR.Get()
   527  }
   528  
   529  // readAvailable determines number of bytes received
   530  //
   531  //go:inline
   532  func (i2c *I2C) readAvailable() uint32 {
   533  	return i2c.Bus.IC_RXFLR.Get()
   534  }
   535  
   536  // Equivalent to IC_CLR_TX_ABRT.Get() (side effect clears ABORT_REASON)
   537  //
   538  //go:inline
   539  func (i2c *I2C) clearAbortReason() {
   540  	// Note clearing the abort flag also clears the reason, and
   541  	// this instance of flag is clear-on-read! Note also the
   542  	// IC_CLR_TX_ABRT register always reads as 0.
   543  	i2c.Bus.IC_CLR_TX_ABRT.Get()
   544  }
   545  
   546  // getAbortReason reads IC_TX_ABRT_SOURCE register.
   547  //
   548  //go:inline
   549  func (i2c *I2C) getAbortReason() i2cAbortError {
   550  	return i2cAbortError(i2c.Bus.IC_TX_ABRT_SOURCE.Get())
   551  }
   552  
   553  // returns true if RAW_INTR_STAT bits in mask are all set. performs:
   554  //
   555  //	RAW_INTR_STAT & mask == mask
   556  //
   557  //go:inline
   558  func (i2c *I2C) interrupted(mask uint32) bool {
   559  	reg := i2c.Bus.IC_RAW_INTR_STAT.Get()
   560  	return reg&mask == mask
   561  }
   562  
   563  type i2cAbortError uint32
   564  
   565  func (b i2cAbortError) Error() string {
   566  	return "i2c abort, reason " + itoa.Uitoa(uint(b))
   567  }
   568  
   569  func (b i2cAbortError) Reasons() (reasons []string) {
   570  	if b == 0 {
   571  		return nil
   572  	}
   573  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK != 0 {
   574  		reasons = append(reasons, "7-bit address no ack")
   575  	}
   576  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK != 0 {
   577  		reasons = append(reasons, "10-bit address first byte no ack")
   578  	}
   579  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK != 0 {
   580  		reasons = append(reasons, "10-bit address second byte no ack")
   581  	}
   582  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK != 0 {
   583  		reasons = append(reasons, "tx data no ack")
   584  	}
   585  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_GCALL_NOACK != 0 {
   586  		reasons = append(reasons, "general call no ack")
   587  	}
   588  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_GCALL_READ != 0 {
   589  		reasons = append(reasons, "general call read")
   590  	}
   591  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_HS_ACKDET != 0 {
   592  		reasons = append(reasons, "high speed ack detect")
   593  	}
   594  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_SBYTE_ACKDET != 0 {
   595  		reasons = append(reasons, "start byte ack detect")
   596  	}
   597  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_HS_NORSTRT != 0 {
   598  		reasons = append(reasons, "high speed no restart")
   599  	}
   600  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_SBYTE_NORSTRT != 0 {
   601  		reasons = append(reasons, "start byte no restart")
   602  	}
   603  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_10B_RD_NORSTRT != 0 {
   604  		reasons = append(reasons, "10-bit read no restart")
   605  	}
   606  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_MASTER_DIS != 0 {
   607  		reasons = append(reasons, "master disabled")
   608  	}
   609  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ARB_LOST != 0 {
   610  		reasons = append(reasons, "arbitration lost")
   611  	}
   612  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_SLVFLUSH_TXFIFO != 0 {
   613  		reasons = append(reasons, "slave flush tx fifo")
   614  	}
   615  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_SLV_ARBLOST != 0 {
   616  		reasons = append(reasons, "slave arbitration lost")
   617  	}
   618  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_SLVRD_INTX != 0 {
   619  		reasons = append(reasons, "slave read while inactive")
   620  	}
   621  	if b&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_USER_ABRT != 0 {
   622  		reasons = append(reasons, "user abort")
   623  	}
   624  	return reasons
   625  }
   626  
   627  //go:inline
   628  func boolToBit(a bool) uint32 {
   629  	if a {
   630  		return 1
   631  	}
   632  	return 0
   633  }
   634  
   635  //go:inline
   636  func u32max(a, b uint32) uint32 {
   637  	if a > b {
   638  		return a
   639  	}
   640  	return b
   641  }
   642  
   643  //go:inline
   644  func isReservedI2CAddr(addr uint8) bool {
   645  	return (addr&0x78) == 0 || (addr&0x78) == 0x78
   646  }