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

     1  //go:build nrf51
     2  
     3  package machine
     4  
     5  import (
     6  	"device/nrf"
     7  )
     8  
     9  const eraseBlockSizeValue = 1024
    10  
    11  func eraseBlockSize() int64 {
    12  	return eraseBlockSizeValue
    13  }
    14  
    15  // Get peripheral and pin number for this GPIO pin.
    16  func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
    17  	return nrf.GPIO, uint32(p)
    18  }
    19  
    20  func (uart *UART) setPins(tx, rx Pin) {
    21  	nrf.UART0.PSELTXD.Set(uint32(tx))
    22  	nrf.UART0.PSELRXD.Set(uint32(rx))
    23  }
    24  
    25  func (i2c *I2C) setPins(scl, sda Pin) {
    26  	i2c.Bus.PSELSCL.Set(uint32(scl))
    27  	i2c.Bus.PSELSDA.Set(uint32(sda))
    28  }
    29  
    30  // SPI on the NRF.
    31  type SPI struct {
    32  	Bus *nrf.SPI_Type
    33  }
    34  
    35  // There are 2 SPI interfaces on the NRF51.
    36  var (
    37  	SPI0 = SPI{Bus: nrf.SPI0}
    38  	SPI1 = SPI{Bus: nrf.SPI1}
    39  )
    40  
    41  // SPIConfig is used to store config info for SPI.
    42  type SPIConfig struct {
    43  	Frequency uint32
    44  	SCK       Pin
    45  	SDO       Pin
    46  	SDI       Pin
    47  	LSBFirst  bool
    48  	Mode      uint8
    49  }
    50  
    51  // Configure is intended to setup the SPI interface.
    52  func (spi SPI) Configure(config SPIConfig) error {
    53  	// Disable bus to configure it
    54  	spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Disabled)
    55  
    56  	// set frequency
    57  	var freq uint32
    58  
    59  	if config.Frequency == 0 {
    60  		config.Frequency = 4000000 // 4MHz
    61  	}
    62  
    63  	switch {
    64  	case config.Frequency >= 8000000:
    65  		freq = nrf.SPI_FREQUENCY_FREQUENCY_M8
    66  	case config.Frequency >= 4000000:
    67  		freq = nrf.SPI_FREQUENCY_FREQUENCY_M4
    68  	case config.Frequency >= 2000000:
    69  		freq = nrf.SPI_FREQUENCY_FREQUENCY_M2
    70  	case config.Frequency >= 1000000:
    71  		freq = nrf.SPI_FREQUENCY_FREQUENCY_M1
    72  	case config.Frequency >= 500000:
    73  		freq = nrf.SPI_FREQUENCY_FREQUENCY_K500
    74  	case config.Frequency >= 250000:
    75  		freq = nrf.SPI_FREQUENCY_FREQUENCY_K250
    76  	default: // below 250kHz, default to the lowest speed available
    77  		freq = nrf.SPI_FREQUENCY_FREQUENCY_K125
    78  	}
    79  	spi.Bus.FREQUENCY.Set(freq)
    80  
    81  	var conf uint32
    82  
    83  	// set bit transfer order
    84  	if config.LSBFirst {
    85  		conf = (nrf.SPI_CONFIG_ORDER_LsbFirst << nrf.SPI_CONFIG_ORDER_Pos)
    86  	}
    87  
    88  	// set mode
    89  	switch config.Mode {
    90  	case 0:
    91  		conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
    92  		conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
    93  	case 1:
    94  		conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
    95  		conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos)
    96  	case 2:
    97  		conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos)
    98  		conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
    99  	case 3:
   100  		conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos)
   101  		conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos)
   102  	default: // to mode
   103  		conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
   104  		conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
   105  	}
   106  	spi.Bus.CONFIG.Set(conf)
   107  
   108  	// set pins
   109  	if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 {
   110  		config.SCK = SPI0_SCK_PIN
   111  		config.SDO = SPI0_SDO_PIN
   112  		config.SDI = SPI0_SDI_PIN
   113  	}
   114  	spi.Bus.PSELSCK.Set(uint32(config.SCK))
   115  	spi.Bus.PSELMOSI.Set(uint32(config.SDO))
   116  	spi.Bus.PSELMISO.Set(uint32(config.SDI))
   117  
   118  	// Re-enable bus now that it is configured.
   119  	spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Enabled)
   120  
   121  	return nil
   122  }
   123  
   124  // Transfer writes/reads a single byte using the SPI interface.
   125  func (spi SPI) Transfer(w byte) (byte, error) {
   126  	spi.Bus.TXD.Set(uint32(w))
   127  	for spi.Bus.EVENTS_READY.Get() == 0 {
   128  	}
   129  	r := spi.Bus.RXD.Get()
   130  	spi.Bus.EVENTS_READY.Set(0)
   131  
   132  	// TODO: handle SPI errors
   133  	return byte(r), nil
   134  }
   135  
   136  // Tx handles read/write operation for SPI interface. Since SPI is a syncronous write/read
   137  // interface, there must always be the same number of bytes written as bytes read.
   138  // The Tx method knows about this, and offers a few different ways of calling it.
   139  //
   140  // This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer.
   141  // Note that the tx and rx buffers must be the same size:
   142  //
   143  //	spi.Tx(tx, rx)
   144  //
   145  // This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros
   146  // until all the bytes in the command packet have been received:
   147  //
   148  //	spi.Tx(tx, nil)
   149  //
   150  // This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet":
   151  //
   152  //	spi.Tx(nil, rx)
   153  func (spi SPI) Tx(w, r []byte) error {
   154  	var err error
   155  
   156  	switch {
   157  	case len(w) == 0:
   158  		// read only, so write zero and read a result.
   159  		for i := range r {
   160  			r[i], err = spi.Transfer(0)
   161  			if err != nil {
   162  				return err
   163  			}
   164  		}
   165  	case len(r) == 0:
   166  		// write only
   167  		spi.Bus.TXD.Set(uint32(w[0]))
   168  		w = w[1:]
   169  		for _, b := range w {
   170  			spi.Bus.TXD.Set(uint32(b))
   171  			for spi.Bus.EVENTS_READY.Get() == 0 {
   172  			}
   173  			spi.Bus.EVENTS_READY.Set(0)
   174  			_ = spi.Bus.RXD.Get()
   175  		}
   176  		for spi.Bus.EVENTS_READY.Get() == 0 {
   177  		}
   178  		spi.Bus.EVENTS_READY.Set(0)
   179  		_ = spi.Bus.RXD.Get()
   180  
   181  	default:
   182  		// write/read
   183  		if len(w) != len(r) {
   184  			return ErrTxInvalidSliceSize
   185  		}
   186  
   187  		for i, b := range w {
   188  			r[i], err = spi.Transfer(b)
   189  			if err != nil {
   190  				return err
   191  			}
   192  		}
   193  	}
   194  
   195  	return nil
   196  }
   197  
   198  // InitADC initializes the registers needed for ADC.
   199  func InitADC() {
   200  	return // no specific setup on nrf51 machine.
   201  }
   202  
   203  // Configure configures an ADC pin to be able to read analog data.
   204  func (a ADC) Configure(ADCConfig) {
   205  	return // no pin specific setup on nrf51 machine.
   206  }
   207  
   208  // Get returns the current value of a ADC pin in the range 0..0xffff.
   209  func (a ADC) Get() uint16 {
   210  	var value uint32
   211  
   212  	adcPin := a.getADCPin()
   213  
   214  	// Enable ADC.
   215  	nrf.ADC.SetENABLE(nrf.ADC_ENABLE_ENABLE_Enabled)
   216  
   217  	// Set pin to read.
   218  	nrf.ADC.SetCONFIG_PSEL(adcPin)
   219  
   220  	// config ADC
   221  	nrf.ADC.SetCONFIG_RES(nrf.ADC_CONFIG_RES_10bit)
   222  	nrf.ADC.SetCONFIG_INPSEL(nrf.ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling)
   223  	nrf.ADC.SetCONFIG_REFSEL(nrf.ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling)
   224  
   225  	// Start tasks.
   226  	nrf.ADC.TASKS_START.Set(1)
   227  
   228  	// Wait until the sample task is done.
   229  	for nrf.ADC.EVENTS_END.Get() == 0 {
   230  	}
   231  	nrf.ADC.EVENTS_END.Set(0x00)
   232  
   233  	value = nrf.ADC.GetRESULT()
   234  
   235  	// Stop the ADC
   236  	nrf.ADC.TASKS_STOP.Set(1)
   237  
   238  	// Disable ADC.
   239  	nrf.ADC.SetENABLE(nrf.ADC_ENABLE_ENABLE_Disabled)
   240  
   241  	if value < 0 {
   242  		value = 0
   243  	}
   244  
   245  	// Return 16-bit result from 10-bit value.
   246  	return uint16(value << 6)
   247  }
   248  
   249  func (a ADC) getADCPin() uint32 {
   250  	switch a.Pin {
   251  	case 1:
   252  		return nrf.ADC_CONFIG_PSEL_AnalogInput2
   253  
   254  	case 2:
   255  		return nrf.ADC_CONFIG_PSEL_AnalogInput3
   256  
   257  	case 3:
   258  		return nrf.ADC_CONFIG_PSEL_AnalogInput4
   259  
   260  	case 4:
   261  		return nrf.ADC_CONFIG_PSEL_AnalogInput5
   262  
   263  	case 5:
   264  		return nrf.ADC_CONFIG_PSEL_AnalogInput6
   265  
   266  	case 6:
   267  		return nrf.ADC_CONFIG_PSEL_AnalogInput7
   268  
   269  	case 26:
   270  		return nrf.ADC_CONFIG_PSEL_AnalogInput0
   271  
   272  	case 27:
   273  		return nrf.ADC_CONFIG_PSEL_AnalogInput1
   274  
   275  	default:
   276  		return 0
   277  	}
   278  }