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

     1  //go:build k210
     2  
     3  package machine
     4  
     5  import (
     6  	"device/kendryte"
     7  	"device/riscv"
     8  	"errors"
     9  	"runtime/interrupt"
    10  	"unsafe"
    11  )
    12  
    13  const deviceName = kendryte.Device
    14  
    15  func CPUFrequency() uint32 {
    16  	return 390000000
    17  }
    18  
    19  type fpioaPullMode uint8
    20  type PinChange uint8
    21  
    22  // Pin modes.
    23  const (
    24  	PinInput PinMode = iota
    25  	PinInputPullup
    26  	PinInputPulldown
    27  	PinOutput
    28  )
    29  
    30  // Deprecated: use PinInputPullup and PinInputPulldown instead.
    31  const (
    32  	PinInputPullUp   = PinInputPullup
    33  	PinInputPullDown = PinInputPulldown
    34  )
    35  
    36  // FPIOA internal pull resistors.
    37  const (
    38  	fpioaPullNone fpioaPullMode = iota
    39  	fpioaPullDown
    40  	fpioaPullUp
    41  )
    42  
    43  // GPIOHS pin interrupt events.
    44  const (
    45  	PinRising PinChange = 1 << iota
    46  	PinFalling
    47  	PinToggle = PinRising | PinFalling
    48  )
    49  
    50  var (
    51  	errUnsupportedSPIController = errors.New("SPI controller not supported. Use SPI0 or SPI1.")
    52  	errI2CTxAbort               = errors.New("I2C transmition has been aborted.")
    53  )
    54  
    55  func (p Pin) setFPIOAIOPull(pull fpioaPullMode) {
    56  	switch pull {
    57  	case fpioaPullNone:
    58  		kendryte.FPIOA.IO[uint8(p)].ClearBits(kendryte.FPIOA_IO_PU & kendryte.FPIOA_IO_PD)
    59  	case fpioaPullUp:
    60  		kendryte.FPIOA.IO[uint8(p)].SetBits(kendryte.FPIOA_IO_PU)
    61  		kendryte.FPIOA.IO[uint8(p)].ClearBits(kendryte.FPIOA_IO_PD)
    62  	case fpioaPullDown:
    63  		kendryte.FPIOA.IO[uint8(p)].ClearBits(kendryte.FPIOA_IO_PU)
    64  		kendryte.FPIOA.IO[uint8(p)].SetBits(kendryte.FPIOA_IO_PD)
    65  	}
    66  }
    67  
    68  // SetFPIOAFunction is used to configure the pin for one of the FPIOA functions.
    69  // Each pin on the Kendryte K210 can be configured with any of the available FPIOA functions.
    70  func (p Pin) SetFPIOAFunction(f FPIOAFunction) {
    71  	kendryte.FPIOA.IO[uint8(p)].Set(fpioaFuncDefaults[uint8(f)])
    72  }
    73  
    74  // FPIOAFunction returns the current FPIOA function of the pin.
    75  func (p Pin) FPIOAFunction() FPIOAFunction {
    76  	return FPIOAFunction((kendryte.FPIOA.IO[uint8(p)].Get() & kendryte.FPIOA_IO_CH_SEL_Msk))
    77  }
    78  
    79  // Configure this pin with the given configuration.
    80  // The pin must already be set as GPIO or GPIOHS pin.
    81  func (p Pin) Configure(config PinConfig) {
    82  	var input bool
    83  
    84  	// Check if the current pin's FPIOA function is either GPIO or GPIOHS.
    85  	f := p.FPIOAFunction()
    86  	if f < FUNC_GPIOHS0 || f > FUNC_GPIO7 {
    87  		return // The pin is not configured as GPIO or GPIOHS.
    88  	}
    89  
    90  	// Configure pin.
    91  	kendryte.FPIOA.IO[uint8(p)].SetBits(kendryte.FPIOA_IO_OE_EN | kendryte.FPIOA_IO_IE_EN | kendryte.FPIOA_IO_ST | kendryte.FPIOA_IO_DS_Msk)
    92  
    93  	switch config.Mode {
    94  	case PinInput:
    95  		p.setFPIOAIOPull(fpioaPullNone)
    96  		input = true
    97  	case PinInputPullup:
    98  		p.setFPIOAIOPull(fpioaPullUp)
    99  		input = true
   100  	case PinInputPulldown:
   101  		p.setFPIOAIOPull(fpioaPullDown)
   102  		input = true
   103  	case PinOutput:
   104  		p.setFPIOAIOPull(fpioaPullNone)
   105  		input = false
   106  	}
   107  
   108  	if f >= FUNC_GPIO0 && f <= FUNC_GPIO7 {
   109  		// Converts the IO pin number in the effective GPIO number (based on the FPIOA function).
   110  		gpioPin := uint8(f - FUNC_GPIO0)
   111  
   112  		if input {
   113  			kendryte.GPIO.DIRECTION.ClearBits(1 << gpioPin)
   114  		} else {
   115  			kendryte.GPIO.DIRECTION.SetBits(1 << gpioPin)
   116  		}
   117  	} else if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 {
   118  		// Converts the IO pin number in the effective GPIOHS number (based on the FPIOA function).
   119  		gpioPin := uint8(f - FUNC_GPIOHS0)
   120  
   121  		if input {
   122  			kendryte.GPIOHS.INPUT_EN.SetBits(1 << gpioPin)
   123  			kendryte.GPIOHS.OUTPUT_EN.ClearBits(1 << gpioPin)
   124  		} else {
   125  			kendryte.GPIOHS.OUTPUT_EN.SetBits(1 << gpioPin)
   126  			kendryte.GPIOHS.INPUT_EN.ClearBits(1 << gpioPin)
   127  		}
   128  	}
   129  }
   130  
   131  // Set the pin to high or low.
   132  func (p Pin) Set(high bool) {
   133  
   134  	// Check if the current pin's FPIOA function is either GPIO or GPIOHS.
   135  	f := p.FPIOAFunction()
   136  	if f < FUNC_GPIOHS0 || f > FUNC_GPIO7 {
   137  		return // The pin is not configured as GPIO or GPIOHS.
   138  	}
   139  
   140  	if f >= FUNC_GPIO0 && f <= FUNC_GPIO7 {
   141  		gpioPin := uint8(f - FUNC_GPIO0)
   142  
   143  		if high {
   144  			kendryte.GPIO.DATA_OUTPUT.SetBits(1 << gpioPin)
   145  		} else {
   146  			kendryte.GPIO.DATA_OUTPUT.ClearBits(1 << gpioPin)
   147  		}
   148  	} else if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 {
   149  		gpioPin := uint8(f - FUNC_GPIOHS0)
   150  
   151  		if high {
   152  			kendryte.GPIOHS.OUTPUT_VAL.SetBits(1 << gpioPin)
   153  		} else {
   154  			kendryte.GPIOHS.OUTPUT_VAL.ClearBits(1 << gpioPin)
   155  		}
   156  	}
   157  }
   158  
   159  // Get returns the current value of a GPIO pin.
   160  func (p Pin) Get() bool {
   161  
   162  	// Check if the current pin's FPIOA function is either GPIO or GPIOHS.
   163  	f := p.FPIOAFunction()
   164  	if f < FUNC_GPIOHS0 || f > FUNC_GPIO7 {
   165  		return false // The pin is not configured as GPIO or GPIOHS.
   166  	}
   167  
   168  	var val uint32
   169  	if f >= FUNC_GPIO0 && f <= FUNC_GPIO7 {
   170  		gpioPin := uint8(f - FUNC_GPIO0)
   171  		val = kendryte.GPIO.DATA_INPUT.Get() & (1 << gpioPin)
   172  	} else if f >= FUNC_GPIOHS0 && f <= FUNC_GPIOHS31 {
   173  		gpioPin := uint8(f - FUNC_GPIOHS0)
   174  		val = kendryte.GPIOHS.INPUT_VAL.Get() & (1 << gpioPin)
   175  	}
   176  	return (val > 0)
   177  }
   178  
   179  // Callbacks to be called for GPIOHS pins configured with SetInterrupt.
   180  var pinCallbacks [32]func(Pin)
   181  
   182  // SetInterrupt sets an interrupt to be executed when a particular pin changes
   183  // state. The pin should already be configured as an input, including a pull up
   184  // or down if no external pull is provided.
   185  //
   186  // You can pass a nil func to unset the pin change interrupt. If you do so,
   187  // the change parameter is ignored and can be set to any value (such as 0).
   188  // If the pin is already configured with a callback, you must first unset
   189  // this pins interrupt before you can set a new callback.
   190  func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
   191  
   192  	// Check if the pin is a GPIOHS pin.
   193  	f := p.FPIOAFunction()
   194  	if f < FUNC_GPIOHS0 || f > FUNC_GPIOHS31 {
   195  		return ErrInvalidDataPin
   196  	}
   197  
   198  	gpioPin := uint8(f - FUNC_GPIOHS0)
   199  
   200  	// Clear all interrupts.
   201  	kendryte.GPIOHS.RISE_IE.ClearBits(1 << gpioPin)
   202  	kendryte.GPIOHS.FALL_IE.ClearBits(1 << gpioPin)
   203  	kendryte.GPIOHS.HIGH_IE.ClearBits(1 << gpioPin)
   204  	kendryte.GPIOHS.LOW_IE.ClearBits(1 << gpioPin)
   205  
   206  	// Clear all the pending bits for this pin.
   207  	kendryte.GPIOHS.RISE_IP.SetBits(1 << gpioPin)
   208  	kendryte.GPIOHS.FALL_IP.SetBits(1 << gpioPin)
   209  	kendryte.GPIOHS.HIGH_IP.SetBits(1 << gpioPin)
   210  	kendryte.GPIOHS.LOW_IP.SetBits(1 << gpioPin)
   211  
   212  	if callback == nil {
   213  		if pinCallbacks[gpioPin] != nil {
   214  			pinCallbacks[gpioPin] = nil
   215  		}
   216  		return nil
   217  	}
   218  
   219  	if pinCallbacks[gpioPin] != nil {
   220  		// The pin was already configured.
   221  		// To properly re-configure a pin, unset it first and set a new
   222  		// configuration.
   223  		return ErrNoPinChangeChannel
   224  	}
   225  
   226  	pinCallbacks[gpioPin] = callback
   227  
   228  	// Enable interrupts.
   229  	if change&PinRising != 0 {
   230  		kendryte.GPIOHS.RISE_IE.SetBits(1 << gpioPin)
   231  	}
   232  	if change&PinFalling != 0 {
   233  		kendryte.GPIOHS.FALL_IE.SetBits(1 << gpioPin)
   234  	}
   235  
   236  	handleInterrupt := func(inter interrupt.Interrupt) {
   237  
   238  		pin := uint8(inter.GetNumber() - kendryte.IRQ_GPIOHS0)
   239  
   240  		if kendryte.GPIOHS.RISE_IE.HasBits(1 << pin) {
   241  			kendryte.GPIOHS.RISE_IE.ClearBits(1 << pin)
   242  			// Acknowledge interrupt atomically.
   243  			riscv.AsmFull(
   244  				"amoor.w {}, {mask}, ({reg})",
   245  				map[string]interface{}{
   246  					"mask": uint32(1 << pin),
   247  					"reg":  uintptr(unsafe.Pointer(&kendryte.GPIOHS.RISE_IP.Reg)),
   248  				})
   249  			kendryte.GPIOHS.RISE_IE.SetBits(1 << pin)
   250  		}
   251  
   252  		if kendryte.GPIOHS.FALL_IE.HasBits(1 << pin) {
   253  			kendryte.GPIOHS.FALL_IE.ClearBits(1 << pin)
   254  			// Acknowledge interrupt atomically.
   255  			riscv.AsmFull(
   256  				"amoor.w {}, {mask}, ({reg})",
   257  				map[string]interface{}{
   258  					"mask": uint32(1 << pin),
   259  					"reg":  uintptr(unsafe.Pointer(&kendryte.GPIOHS.FALL_IP.Reg)),
   260  				})
   261  			kendryte.GPIOHS.FALL_IE.SetBits(1 << pin)
   262  		}
   263  
   264  		pinCallbacks[pin](Pin(pin))
   265  	}
   266  
   267  	var ir interrupt.Interrupt
   268  
   269  	switch f {
   270  	case FUNC_GPIOHS0:
   271  		ir = interrupt.New(kendryte.IRQ_GPIOHS0, handleInterrupt)
   272  	case FUNC_GPIOHS1:
   273  		ir = interrupt.New(kendryte.IRQ_GPIOHS1, handleInterrupt)
   274  	case FUNC_GPIOHS2:
   275  		ir = interrupt.New(kendryte.IRQ_GPIOHS2, handleInterrupt)
   276  	case FUNC_GPIOHS3:
   277  		ir = interrupt.New(kendryte.IRQ_GPIOHS3, handleInterrupt)
   278  	case FUNC_GPIOHS4:
   279  		ir = interrupt.New(kendryte.IRQ_GPIOHS4, handleInterrupt)
   280  	case FUNC_GPIOHS5:
   281  		ir = interrupt.New(kendryte.IRQ_GPIOHS5, handleInterrupt)
   282  	case FUNC_GPIOHS6:
   283  		ir = interrupt.New(kendryte.IRQ_GPIOHS6, handleInterrupt)
   284  	case FUNC_GPIOHS7:
   285  		ir = interrupt.New(kendryte.IRQ_GPIOHS7, handleInterrupt)
   286  	case FUNC_GPIOHS8:
   287  		ir = interrupt.New(kendryte.IRQ_GPIOHS8, handleInterrupt)
   288  	case FUNC_GPIOHS9:
   289  		ir = interrupt.New(kendryte.IRQ_GPIOHS9, handleInterrupt)
   290  	case FUNC_GPIOHS10:
   291  		ir = interrupt.New(kendryte.IRQ_GPIOHS10, handleInterrupt)
   292  	case FUNC_GPIOHS11:
   293  		ir = interrupt.New(kendryte.IRQ_GPIOHS11, handleInterrupt)
   294  	case FUNC_GPIOHS12:
   295  		ir = interrupt.New(kendryte.IRQ_GPIOHS12, handleInterrupt)
   296  	case FUNC_GPIOHS13:
   297  		ir = interrupt.New(kendryte.IRQ_GPIOHS13, handleInterrupt)
   298  	case FUNC_GPIOHS14:
   299  		ir = interrupt.New(kendryte.IRQ_GPIOHS14, handleInterrupt)
   300  	case FUNC_GPIOHS15:
   301  		ir = interrupt.New(kendryte.IRQ_GPIOHS15, handleInterrupt)
   302  	case FUNC_GPIOHS16:
   303  		ir = interrupt.New(kendryte.IRQ_GPIOHS16, handleInterrupt)
   304  	case FUNC_GPIOHS17:
   305  		ir = interrupt.New(kendryte.IRQ_GPIOHS17, handleInterrupt)
   306  	case FUNC_GPIOHS18:
   307  		ir = interrupt.New(kendryte.IRQ_GPIOHS18, handleInterrupt)
   308  	case FUNC_GPIOHS19:
   309  		ir = interrupt.New(kendryte.IRQ_GPIOHS19, handleInterrupt)
   310  	case FUNC_GPIOHS20:
   311  		ir = interrupt.New(kendryte.IRQ_GPIOHS20, handleInterrupt)
   312  	case FUNC_GPIOHS21:
   313  		ir = interrupt.New(kendryte.IRQ_GPIOHS21, handleInterrupt)
   314  	case FUNC_GPIOHS22:
   315  		ir = interrupt.New(kendryte.IRQ_GPIOHS22, handleInterrupt)
   316  	case FUNC_GPIOHS23:
   317  		ir = interrupt.New(kendryte.IRQ_GPIOHS23, handleInterrupt)
   318  	case FUNC_GPIOHS24:
   319  		ir = interrupt.New(kendryte.IRQ_GPIOHS24, handleInterrupt)
   320  	case FUNC_GPIOHS25:
   321  		ir = interrupt.New(kendryte.IRQ_GPIOHS25, handleInterrupt)
   322  	case FUNC_GPIOHS26:
   323  		ir = interrupt.New(kendryte.IRQ_GPIOHS26, handleInterrupt)
   324  	case FUNC_GPIOHS27:
   325  		ir = interrupt.New(kendryte.IRQ_GPIOHS27, handleInterrupt)
   326  	case FUNC_GPIOHS28:
   327  		ir = interrupt.New(kendryte.IRQ_GPIOHS28, handleInterrupt)
   328  	case FUNC_GPIOHS29:
   329  		ir = interrupt.New(kendryte.IRQ_GPIOHS29, handleInterrupt)
   330  	case FUNC_GPIOHS30:
   331  		ir = interrupt.New(kendryte.IRQ_GPIOHS30, handleInterrupt)
   332  	case FUNC_GPIOHS31:
   333  		ir = interrupt.New(kendryte.IRQ_GPIOHS31, handleInterrupt)
   334  	}
   335  
   336  	ir.SetPriority(5)
   337  	ir.Enable()
   338  
   339  	return nil
   340  
   341  }
   342  
   343  type UART struct {
   344  	Bus    *kendryte.UARTHS_Type
   345  	Buffer *RingBuffer
   346  }
   347  
   348  var (
   349  	UART0  = &_UART0
   350  	_UART0 = UART{Bus: kendryte.UARTHS, Buffer: NewRingBuffer()}
   351  )
   352  
   353  func (uart *UART) Configure(config UARTConfig) {
   354  
   355  	// Use default baudrate  if not set.
   356  	if config.BaudRate == 0 {
   357  		config.BaudRate = 115200
   358  	}
   359  
   360  	// Use default pins if not set.
   361  	if config.TX == 0 && config.RX == 0 {
   362  		config.TX = UART_TX_PIN
   363  		config.RX = UART_RX_PIN
   364  	}
   365  
   366  	config.TX.SetFPIOAFunction(FUNC_UARTHS_TX)
   367  	config.RX.SetFPIOAFunction(FUNC_UARTHS_RX)
   368  
   369  	div := CPUFrequency()/config.BaudRate - 1
   370  
   371  	uart.Bus.DIV.Set(div)
   372  	uart.Bus.TXCTRL.Set(kendryte.UARTHS_TXCTRL_TXEN)
   373  	uart.Bus.RXCTRL.Set(kendryte.UARTHS_RXCTRL_RXEN)
   374  
   375  	// Enable interrupts on receive.
   376  	uart.Bus.IE.Set(kendryte.UARTHS_IE_RXWM)
   377  
   378  	intr := interrupt.New(kendryte.IRQ_UARTHS, _UART0.handleInterrupt)
   379  	intr.SetPriority(5)
   380  	intr.Enable()
   381  }
   382  
   383  func (uart *UART) handleInterrupt(interrupt.Interrupt) {
   384  	rxdata := uart.Bus.RXDATA.Get()
   385  	c := byte(rxdata)
   386  	if uint32(c) != rxdata {
   387  		// The rxdata has other bits set than just the low 8 bits. This probably
   388  		// means that the 'empty' flag is set, which indicates there is no data
   389  		// to be read and the byte is garbage. Ignore this byte.
   390  		return
   391  	}
   392  	uart.Receive(c)
   393  }
   394  
   395  func (uart *UART) writeByte(c byte) error {
   396  	for uart.Bus.TXDATA.Get()&kendryte.UARTHS_TXDATA_FULL != 0 {
   397  	}
   398  
   399  	uart.Bus.TXDATA.Set(uint32(c))
   400  	return nil
   401  }
   402  
   403  func (uart *UART) flush() {}
   404  
   405  type SPI struct {
   406  	Bus *kendryte.SPI_Type
   407  }
   408  
   409  // SPIConfig is used to store config info for SPI.
   410  type SPIConfig struct {
   411  	Frequency uint32
   412  	SCK       Pin
   413  	SDO       Pin
   414  	SDI       Pin
   415  	LSBFirst  bool
   416  	Mode      uint8
   417  }
   418  
   419  // Configure is intended to setup the SPI interface.
   420  // Only SPI controller 0 and 1 can be used because SPI2 is a special
   421  // peripheral-mode controller and SPI3 is used for flashing.
   422  func (spi SPI) Configure(config SPIConfig) error {
   423  	// Use default pins if not set.
   424  	if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 {
   425  		config.SCK = SPI0_SCK_PIN
   426  		config.SDO = SPI0_SDO_PIN
   427  		config.SDI = SPI0_SDI_PIN
   428  	}
   429  
   430  	// Enable APB2 clock.
   431  	kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB2_CLK_EN)
   432  
   433  	switch spi.Bus {
   434  	case kendryte.SPI0:
   435  		// Initialize SPI clock.
   436  		kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_SPI0_CLK_EN)
   437  		kendryte.SYSCTL.CLK_TH1.ClearBits(kendryte.SYSCTL_CLK_TH1_SPI0_CLK_Msk)
   438  
   439  		// Initialize pins.
   440  		config.SCK.SetFPIOAFunction(FUNC_SPI0_SCLK)
   441  		config.SDO.SetFPIOAFunction(FUNC_SPI0_D0)
   442  		config.SDI.SetFPIOAFunction(FUNC_SPI0_D1)
   443  	case kendryte.SPI1:
   444  		// Initialize SPI clock.
   445  		kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_SPI1_CLK_EN)
   446  		kendryte.SYSCTL.CLK_TH1.ClearBits(kendryte.SYSCTL_CLK_TH1_SPI1_CLK_Msk)
   447  
   448  		// Initialize pins.
   449  		config.SCK.SetFPIOAFunction(FUNC_SPI1_SCLK)
   450  		config.SDO.SetFPIOAFunction(FUNC_SPI1_D0)
   451  		config.SDI.SetFPIOAFunction(FUNC_SPI1_D1)
   452  	default:
   453  		return errUnsupportedSPIController
   454  	}
   455  
   456  	// Set default frequency.
   457  	if config.Frequency == 0 {
   458  		config.Frequency = 4000000 // 4MHz
   459  	}
   460  
   461  	baudr := CPUFrequency() / config.Frequency
   462  	spi.Bus.BAUDR.Set(baudr)
   463  
   464  	// Configure SPI mode 0, standard frame format, 8-bit data, little-endian.
   465  	spi.Bus.IMR.Set(0)
   466  	spi.Bus.DMACR.Set(0)
   467  	spi.Bus.DMATDLR.Set(0x10)
   468  	spi.Bus.DMARDLR.Set(0)
   469  	spi.Bus.SER.Set(0)
   470  	spi.Bus.SSIENR.Set(0)
   471  	spi.Bus.CTRLR0.Set((7 << 16))
   472  	spi.Bus.SPI_CTRLR0.Set(0)
   473  	spi.Bus.ENDIAN.Set(0)
   474  
   475  	return nil
   476  }
   477  
   478  // Transfer writes/reads a single byte using the SPI interface.
   479  func (spi SPI) Transfer(w byte) (byte, error) {
   480  	spi.Bus.SSIENR.Set(0)
   481  
   482  	// Set transfer-receive mode.
   483  	spi.Bus.CTRLR0.ClearBits(0x3 << 8)
   484  
   485  	// Enable/disable SPI.
   486  	spi.Bus.SSIENR.Set(1)
   487  	defer spi.Bus.SSIENR.Set(0)
   488  
   489  	// Enable/disable device.
   490  	spi.Bus.SER.Set(0x1)
   491  	defer spi.Bus.SER.Set(0)
   492  
   493  	spi.Bus.DR0.Set(uint32(w))
   494  
   495  	// Wait for transfer.
   496  	for spi.Bus.SR.Get()&0x05 != 0x04 {
   497  	}
   498  
   499  	// Wait for data.
   500  	for spi.Bus.RXFLR.Get() == 0 {
   501  	}
   502  
   503  	return byte(spi.Bus.DR0.Get()), nil
   504  }
   505  
   506  // I2C on the K210.
   507  type I2C struct {
   508  	Bus kendryte.I2C_Type
   509  }
   510  
   511  var (
   512  	I2C0 = (*I2C)(unsafe.Pointer(kendryte.I2C0))
   513  	I2C1 = (*I2C)(unsafe.Pointer(kendryte.I2C1))
   514  	I2C2 = (*I2C)(unsafe.Pointer(kendryte.I2C2))
   515  )
   516  
   517  // I2CConfig is used to store config info for I2C.
   518  type I2CConfig struct {
   519  	Frequency uint32
   520  	SCL       Pin
   521  	SDA       Pin
   522  }
   523  
   524  // Configure is intended to setup the I2C interface.
   525  func (i2c *I2C) Configure(config I2CConfig) error {
   526  
   527  	if config.Frequency == 0 {
   528  		config.Frequency = 100 * KHz
   529  	}
   530  
   531  	if config.SDA == 0 && config.SCL == 0 {
   532  		config.SDA = I2C0_SDA_PIN
   533  		config.SCL = I2C0_SCL_PIN
   534  	}
   535  
   536  	// Enable APB0 clock.
   537  	kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB0_CLK_EN)
   538  
   539  	switch &i2c.Bus {
   540  	case kendryte.I2C0:
   541  		// Initialize I2C0 clock.
   542  		kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_I2C0_CLK_EN)
   543  		kendryte.SYSCTL.CLK_TH5.ReplaceBits(0x03, kendryte.SYSCTL_CLK_TH5_I2C0_CLK_Msk, kendryte.SYSCTL_CLK_TH5_I2C0_CLK_Pos)
   544  
   545  		// Initialize pins.
   546  		config.SDA.SetFPIOAFunction(FUNC_I2C0_SDA)
   547  		config.SCL.SetFPIOAFunction(FUNC_I2C0_SCLK)
   548  	case kendryte.I2C1:
   549  		// Initialize I2C1 clock.
   550  		kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_I2C1_CLK_EN)
   551  		kendryte.SYSCTL.CLK_TH5.ReplaceBits(0x03, kendryte.SYSCTL_CLK_TH5_I2C1_CLK_Msk, kendryte.SYSCTL_CLK_TH5_I2C1_CLK_Pos)
   552  
   553  		// Initialize pins.
   554  		config.SDA.SetFPIOAFunction(FUNC_I2C1_SDA)
   555  		config.SCL.SetFPIOAFunction(FUNC_I2C1_SCLK)
   556  	case kendryte.I2C2:
   557  		// Initialize I2C2 clock.
   558  		kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_I2C2_CLK_EN)
   559  		kendryte.SYSCTL.CLK_TH5.ReplaceBits(0x03, kendryte.SYSCTL_CLK_TH5_I2C2_CLK_Msk, kendryte.SYSCTL_CLK_TH5_I2C2_CLK_Pos)
   560  
   561  		// Initialize pins.
   562  		config.SDA.SetFPIOAFunction(FUNC_I2C2_SDA)
   563  		config.SCL.SetFPIOAFunction(FUNC_I2C2_SCLK)
   564  	}
   565  
   566  	i2c.SetBaudRate(config.Frequency)
   567  
   568  	i2c.Bus.INTR_MASK.Set(0)
   569  	i2c.Bus.DMA_CR.Set(0x03)
   570  	i2c.Bus.DMA_RDLR.Set(0)
   571  	i2c.Bus.DMA_TDLR.Set(0x4)
   572  
   573  	return nil
   574  }
   575  
   576  // SetBaudRate sets the communication speed for I2C.
   577  func (i2c *I2C) SetBaudRate(br uint32) error {
   578  	div := CPUFrequency() / br / 16
   579  
   580  	// Disable controller before setting the prescale register.
   581  	i2c.Bus.ENABLE.Set(0)
   582  
   583  	i2c.Bus.CON.Set(0x63)
   584  
   585  	// Set prescaler registers.
   586  	i2c.Bus.SS_SCL_HCNT.Set(uint32(div))
   587  	i2c.Bus.SS_SCL_LCNT.Set(uint32(div))
   588  
   589  	return nil
   590  }
   591  
   592  // Tx does a single I2C transaction at the specified address.
   593  // It clocks out the given address, writes the bytes in w, reads back len(r)
   594  // bytes and stores them in r, and generates a stop condition on the bus.
   595  func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
   596  	// Set peripheral address.
   597  	i2c.Bus.TAR.Set(uint32(addr))
   598  	// Enable controller.
   599  	i2c.Bus.ENABLE.Set(1)
   600  
   601  	if len(w) != 0 {
   602  		i2c.Bus.CLR_TX_ABRT.Set(i2c.Bus.CLR_TX_ABRT.Get())
   603  		dataLen := uint32(len(w))
   604  		di := 0
   605  
   606  		for dataLen != 0 {
   607  			fifoLen := 8 - i2c.Bus.TXFLR.Get()
   608  			if dataLen < fifoLen {
   609  				fifoLen = dataLen
   610  			}
   611  
   612  			for i := uint32(0); i < fifoLen; i++ {
   613  				i2c.Bus.DATA_CMD.Set(uint32(w[di]))
   614  				di += 1
   615  			}
   616  			if i2c.Bus.TX_ABRT_SOURCE.Get() != 0 {
   617  				return errI2CTxAbort
   618  			}
   619  			dataLen -= fifoLen
   620  		}
   621  
   622  		// Wait for transmition to complete.
   623  		for i2c.Bus.STATUS.HasBits(kendryte.I2C_STATUS_ACTIVITY) || !i2c.Bus.STATUS.HasBits(kendryte.I2C_STATUS_TFE) {
   624  		}
   625  
   626  		if i2c.Bus.TX_ABRT_SOURCE.Get() != 0 {
   627  			return errI2CTxAbort
   628  		}
   629  	}
   630  	if len(r) != 0 {
   631  		dataLen := uint32(len(r))
   632  		cmdLen := uint32(len(r))
   633  		di := 0
   634  
   635  		for dataLen != 0 || cmdLen != 0 {
   636  			fifoLen := i2c.Bus.RXFLR.Get()
   637  			if dataLen < fifoLen {
   638  				fifoLen = dataLen
   639  			}
   640  			for i := uint32(0); i < fifoLen; i++ {
   641  				r[di] = byte(i2c.Bus.DATA_CMD.Get())
   642  				di += 1
   643  			}
   644  			dataLen -= fifoLen
   645  
   646  			fifoLen = 8 - i2c.Bus.TXFLR.Get()
   647  			if cmdLen < fifoLen {
   648  				fifoLen = cmdLen
   649  			}
   650  			for i := uint32(0); i < fifoLen; i++ {
   651  				i2c.Bus.DATA_CMD.Set(0x100)
   652  			}
   653  			if i2c.Bus.TX_ABRT_SOURCE.Get() != 0 {
   654  				return errI2CTxAbort
   655  			}
   656  			cmdLen -= fifoLen
   657  		}
   658  	}
   659  
   660  	return nil
   661  }