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

     1  //go:build stm32l5 || stm32f7 || stm32l4 || stm32l0 || stm32wlx
     2  
     3  package machine
     4  
     5  import (
     6  	"device/stm32"
     7  	"unsafe"
     8  )
     9  
    10  //go:linkname ticks runtime.ticks
    11  func ticks() int64
    12  
    13  // I2C implementation for 'newer' STM32 MCUs, including the F7, L5 and L4
    14  // series of MCUs.
    15  //
    16  // Currently, only 100KHz mode is supported
    17  
    18  const (
    19  	flagBUSY  = stm32.I2C_ISR_BUSY
    20  	flagTCR   = stm32.I2C_ISR_TCR
    21  	flagRXNE  = stm32.I2C_ISR_RXNE
    22  	flagSTOPF = stm32.I2C_ISR_STOPF
    23  	flagAF    = stm32.I2C_ISR_NACKF
    24  	flagTXIS  = stm32.I2C_ISR_TXIS
    25  	flagTXE   = stm32.I2C_ISR_TXE
    26  )
    27  
    28  const (
    29  	MAX_NBYTE_SIZE = 255
    30  
    31  	// 100ms delay = 100e6ns / 16ns
    32  	// In runtime_stm32_timers.go, tick is fixed at 16ns per tick
    33  	TIMEOUT_TICKS = 100e6 / 16
    34  
    35  	I2C_NO_STARTSTOP         = 0x0
    36  	I2C_GENERATE_START_WRITE = 0x80000000 | stm32.I2C_CR2_START
    37  	I2C_GENERATE_START_READ  = 0x80000000 | stm32.I2C_CR2_START | stm32.I2C_CR2_RD_WRN
    38  	I2C_GENERATE_STOP        = 0x80000000 | stm32.I2C_CR2_STOP
    39  )
    40  
    41  type I2C struct {
    42  	Bus             *stm32.I2C_Type
    43  	AltFuncSelector uint8
    44  }
    45  
    46  // I2CConfig is used to store config info for I2C.
    47  type I2CConfig struct {
    48  	SCL Pin
    49  	SDA Pin
    50  }
    51  
    52  func (i2c *I2C) Configure(config I2CConfig) error {
    53  	// disable I2C interface before any configuration changes
    54  	i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE)
    55  
    56  	// enable clock for I2C
    57  	enableAltFuncClock(unsafe.Pointer(i2c.Bus))
    58  
    59  	// init pins
    60  	if config.SCL == 0 && config.SDA == 0 {
    61  		config.SCL = I2C0_SCL_PIN
    62  		config.SDA = I2C0_SDA_PIN
    63  	}
    64  	i2c.configurePins(config)
    65  
    66  	// Frequency range
    67  	i2c.Bus.TIMINGR.Set(i2c.getFreqRange())
    68  
    69  	// Disable Own Address1 before set the Own Address1 configuration
    70  	i2c.Bus.OAR1.ClearBits(stm32.I2C_OAR1_OA1EN)
    71  
    72  	// 7 bit addressing, no self address
    73  	i2c.Bus.OAR1.Set(stm32.I2C_OAR1_OA1EN)
    74  
    75  	// Enable the AUTOEND by default, and enable NACK (should be disable only during Slave process
    76  	i2c.Bus.CR2.Set(stm32.I2C_CR2_AUTOEND | stm32.I2C_CR2_NACK)
    77  
    78  	// Disable Own Address2 / Dual Addressing
    79  	i2c.Bus.OAR2.Set(0)
    80  
    81  	// Disable Generalcall and NoStretch, Enable peripheral
    82  	i2c.Bus.CR1.Set(stm32.I2C_CR1_PE)
    83  
    84  	return nil
    85  }
    86  
    87  // SetBaudRate sets the communication speed for I2C.
    88  func (i2c *I2C) SetBaudRate(br uint32) error {
    89  	// TODO: implement
    90  	return errI2CNotImplemented
    91  }
    92  
    93  func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
    94  	if len(w) > 0 {
    95  		if err := i2c.controllerTransmit(addr, w); nil != err {
    96  			return err
    97  		}
    98  	}
    99  
   100  	if len(r) > 0 {
   101  		if err := i2c.controllerReceive(addr, r); nil != err {
   102  			return err
   103  		}
   104  	}
   105  
   106  	return nil
   107  }
   108  
   109  func (i2c *I2C) configurePins(config I2CConfig) {
   110  	config.SCL.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSCL}, i2c.AltFuncSelector)
   111  	config.SDA.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSDA}, i2c.AltFuncSelector)
   112  }
   113  
   114  func (i2c *I2C) controllerTransmit(addr uint16, w []byte) error {
   115  	start := ticks()
   116  
   117  	if !i2c.waitOnFlagUntilTimeout(flagBUSY, false, start) {
   118  		return errI2CBusReadyTimeout
   119  	}
   120  
   121  	pos := 0
   122  	xferCount := len(w)
   123  	xferSize := uint8(xferCount)
   124  	if xferCount > MAX_NBYTE_SIZE {
   125  		// Large write, indicate reload
   126  		xferSize = MAX_NBYTE_SIZE
   127  		i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_GENERATE_START_WRITE)
   128  	} else {
   129  		// Small write, auto-end
   130  		i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_GENERATE_START_WRITE)
   131  	}
   132  
   133  	for xferCount > 0 {
   134  		if !i2c.waitOnTXISFlagUntilTimeout(start) {
   135  			return errI2CWriteTimeout
   136  		}
   137  
   138  		i2c.Bus.TXDR.Set(uint32(w[pos]))
   139  		pos++
   140  		xferCount--
   141  		xferSize--
   142  
   143  		// If we've written the last byte of this chunk
   144  		if xferCount != 0 && xferSize == 0 {
   145  			// Wait for Transfer Complete Reload to be flagged
   146  			if !i2c.waitOnFlagUntilTimeout(flagTCR, true, start) {
   147  				return errI2CWriteTimeout
   148  			}
   149  
   150  			if xferCount > MAX_NBYTE_SIZE {
   151  				// Large write remaining, indicate reload
   152  				xferSize = MAX_NBYTE_SIZE
   153  				i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_NO_STARTSTOP)
   154  			} else {
   155  				// Small write, auto-end
   156  				xferSize = uint8(xferCount)
   157  				i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_NO_STARTSTOP)
   158  			}
   159  		}
   160  	}
   161  
   162  	if !i2c.waitOnStopFlagUntilTimeout(start) {
   163  		return errI2CWriteTimeout
   164  	}
   165  
   166  	i2c.clearFlag(stm32.I2C_ISR_STOPF)
   167  
   168  	i2c.resetCR2()
   169  
   170  	return nil
   171  }
   172  
   173  func (i2c *I2C) controllerReceive(addr uint16, r []byte) error {
   174  	start := ticks()
   175  
   176  	if !i2c.waitOnFlagUntilTimeout(flagBUSY, false, start) {
   177  		return errI2CBusReadyTimeout
   178  	}
   179  
   180  	pos := 0
   181  	xferCount := len(r)
   182  	xferSize := uint8(xferCount)
   183  	if xferCount > MAX_NBYTE_SIZE {
   184  		// Large read, indicate reload
   185  		xferSize = MAX_NBYTE_SIZE
   186  		i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_GENERATE_START_READ)
   187  	} else {
   188  		// Small read, auto-end
   189  		i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_GENERATE_START_READ)
   190  	}
   191  
   192  	for xferCount > 0 {
   193  		if !i2c.waitOnRXNEFlagUntilTimeout(start) {
   194  			return errI2CWriteTimeout
   195  		}
   196  
   197  		r[pos] = uint8(i2c.Bus.RXDR.Get())
   198  		pos++
   199  		xferCount--
   200  		xferSize--
   201  
   202  		// If we've read the last byte of this chunk
   203  		if xferCount != 0 && xferSize == 0 {
   204  			// Wait for Transfer Complete Reload to be flagged
   205  			if !i2c.waitOnFlagUntilTimeout(flagTCR, true, start) {
   206  				return errI2CWriteTimeout
   207  			}
   208  
   209  			if xferCount > MAX_NBYTE_SIZE {
   210  				// Large read remaining, indicate reload
   211  				xferSize = MAX_NBYTE_SIZE
   212  				i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_NO_STARTSTOP)
   213  			} else {
   214  				// Small read, auto-end
   215  				xferSize = uint8(xferCount)
   216  				i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_NO_STARTSTOP)
   217  			}
   218  		}
   219  	}
   220  
   221  	if !i2c.waitOnStopFlagUntilTimeout(start) {
   222  		return errI2CWriteTimeout
   223  	}
   224  
   225  	i2c.clearFlag(stm32.I2C_ISR_STOPF)
   226  
   227  	i2c.resetCR2()
   228  
   229  	return nil
   230  }
   231  
   232  func (i2c *I2C) waitOnFlagUntilTimeout(flag uint32, set bool, startTicks int64) bool {
   233  	for i2c.hasFlag(flag) != set {
   234  		if (ticks() - startTicks) > TIMEOUT_TICKS {
   235  			return false
   236  		}
   237  	}
   238  	return true
   239  }
   240  
   241  func (i2c *I2C) waitOnRXNEFlagUntilTimeout(startTicks int64) bool {
   242  	for !i2c.hasFlag(flagRXNE) {
   243  		if i2c.isAcknowledgeFailed(startTicks) {
   244  			return false
   245  		}
   246  
   247  		if i2c.hasFlag(flagSTOPF) {
   248  			i2c.clearFlag(flagSTOPF)
   249  			i2c.resetCR2()
   250  			return false
   251  		}
   252  
   253  		if (ticks() - startTicks) > TIMEOUT_TICKS {
   254  			return false
   255  		}
   256  	}
   257  
   258  	return true
   259  }
   260  
   261  func (i2c *I2C) waitOnTXISFlagUntilTimeout(startTicks int64) bool {
   262  	for !i2c.hasFlag(flagTXIS) {
   263  		if i2c.isAcknowledgeFailed(startTicks) {
   264  			return false
   265  		}
   266  
   267  		if (ticks() - startTicks) > TIMEOUT_TICKS {
   268  			return false
   269  		}
   270  	}
   271  
   272  	return true
   273  }
   274  
   275  func (i2c *I2C) waitOnStopFlagUntilTimeout(startTicks int64) bool {
   276  	for !i2c.hasFlag(flagSTOPF) {
   277  		if i2c.isAcknowledgeFailed(startTicks) {
   278  			return false
   279  		}
   280  
   281  		if (ticks() - startTicks) > TIMEOUT_TICKS {
   282  			return false
   283  		}
   284  	}
   285  
   286  	return true
   287  }
   288  
   289  func (i2c *I2C) isAcknowledgeFailed(startTicks int64) bool {
   290  	if i2c.hasFlag(flagAF) {
   291  		// Wait until STOP Flag is reset
   292  		// AutoEnd should be initiate after AF
   293  		for !i2c.hasFlag(flagSTOPF) {
   294  			if (ticks() - startTicks) > TIMEOUT_TICKS {
   295  				return true
   296  			}
   297  		}
   298  
   299  		i2c.clearFlag(flagAF)
   300  		i2c.clearFlag(flagSTOPF)
   301  		i2c.flushTXDR()
   302  		i2c.resetCR2()
   303  
   304  		return true
   305  	}
   306  
   307  	return false
   308  }
   309  
   310  func (i2c *I2C) flushTXDR() {
   311  	// If a pending TXIS flag is set, write a dummy data in TXDR to clear it
   312  	if i2c.hasFlag(flagTXIS) {
   313  		i2c.Bus.TXDR.Set(0)
   314  	}
   315  
   316  	// Flush TX register if not empty
   317  	if !i2c.hasFlag(flagTXE) {
   318  		i2c.clearFlag(flagTXE)
   319  	}
   320  }
   321  
   322  func (i2c *I2C) resetCR2() {
   323  	i2c.Bus.CR2.ClearBits(stm32.I2C_CR2_SADD_Msk |
   324  		stm32.I2C_CR2_HEAD10R_Msk |
   325  		stm32.I2C_CR2_NBYTES_Msk |
   326  		stm32.I2C_CR2_RELOAD_Msk |
   327  		stm32.I2C_CR2_RD_WRN_Msk)
   328  }
   329  
   330  func (i2c *I2C) transferConfig(addr uint16, size uint8, mode uint32, request uint32) {
   331  	mask := uint32(stm32.I2C_CR2_SADD_Msk |
   332  		stm32.I2C_CR2_NBYTES_Msk |
   333  		stm32.I2C_CR2_RELOAD_Msk |
   334  		stm32.I2C_CR2_AUTOEND_Msk |
   335  		(stm32.I2C_CR2_RD_WRN & uint32(request>>(31-stm32.I2C_CR2_RD_WRN_Pos))) |
   336  		stm32.I2C_CR2_START_Msk |
   337  		stm32.I2C_CR2_STOP_Msk)
   338  
   339  	value := (uint32(addr<<1) & stm32.I2C_CR2_SADD_Msk) |
   340  		((uint32(size) << stm32.I2C_CR2_NBYTES_Pos) & stm32.I2C_CR2_NBYTES_Msk) |
   341  		mode | request
   342  
   343  	i2c.Bus.CR2.ReplaceBits(value, mask, 0)
   344  }
   345  
   346  func (i2c *I2C) hasFlag(flag uint32) bool {
   347  	return i2c.Bus.ISR.HasBits(flag)
   348  }
   349  
   350  func (i2c *I2C) clearFlag(flag uint32) {
   351  	if flag == stm32.I2C_ISR_TXE {
   352  		i2c.Bus.ISR.SetBits(flag)
   353  	} else {
   354  		i2c.Bus.ICR.SetBits(flag)
   355  	}
   356  }