github.com/aykevl/tinygo@v0.5.0/src/machine/machine_nrf.go (about)

     1  // +build nrf
     2  
     3  package machine
     4  
     5  import (
     6  	"device/arm"
     7  	"device/nrf"
     8  )
     9  
    10  type GPIOMode uint8
    11  
    12  const (
    13  	GPIO_INPUT          = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos)
    14  	GPIO_INPUT_PULLUP   = GPIO_INPUT | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos)
    15  	GPIO_INPUT_PULLDOWN = GPIO_INPUT | (nrf.GPIO_PIN_CNF_PULL_Pulldown << nrf.GPIO_PIN_CNF_PULL_Pos)
    16  	GPIO_OUTPUT         = (nrf.GPIO_PIN_CNF_DIR_Output << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Disconnect << nrf.GPIO_PIN_CNF_INPUT_Pos)
    17  )
    18  
    19  // Configure this pin with the given configuration.
    20  func (p GPIO) Configure(config GPIOConfig) {
    21  	cfg := config.Mode | nrf.GPIO_PIN_CNF_DRIVE_S0S1 | nrf.GPIO_PIN_CNF_SENSE_Disabled
    22  	port, pin := p.getPortPin()
    23  	port.PIN_CNF[pin] = nrf.RegValue(cfg)
    24  }
    25  
    26  // Set the pin to high or low.
    27  // Warning: only use this on an output pin!
    28  func (p GPIO) Set(high bool) {
    29  	port, pin := p.getPortPin()
    30  	if high {
    31  		port.OUTSET = 1 << pin
    32  	} else {
    33  		port.OUTCLR = 1 << pin
    34  	}
    35  }
    36  
    37  // Return the register and mask to enable a given GPIO pin. This can be used to
    38  // implement bit-banged drivers.
    39  func (p GPIO) PortMaskSet() (*uint32, uint32) {
    40  	port, pin := p.getPortPin()
    41  	return (*uint32)(&port.OUTSET), 1 << pin
    42  }
    43  
    44  // Return the register and mask to disable a given port. This can be used to
    45  // implement bit-banged drivers.
    46  func (p GPIO) PortMaskClear() (*uint32, uint32) {
    47  	port, pin := p.getPortPin()
    48  	return (*uint32)(&port.OUTCLR), 1 << pin
    49  }
    50  
    51  // Get returns the current value of a GPIO pin.
    52  func (p GPIO) Get() bool {
    53  	port, pin := p.getPortPin()
    54  	return (port.IN>>pin)&1 != 0
    55  }
    56  
    57  // UART on the NRF.
    58  type UART struct {
    59  	Buffer *RingBuffer
    60  }
    61  
    62  // UART
    63  var (
    64  	// UART0 is the hardware serial port on the NRF.
    65  	UART0 = UART{Buffer: NewRingBuffer()}
    66  )
    67  
    68  // Configure the UART.
    69  func (uart UART) Configure(config UARTConfig) {
    70  	// Default baud rate to 115200.
    71  	if config.BaudRate == 0 {
    72  		config.BaudRate = 115200
    73  	}
    74  
    75  	uart.SetBaudRate(config.BaudRate)
    76  
    77  	// Set TX and RX pins from board.
    78  	uart.setPins(UART_TX_PIN, UART_RX_PIN)
    79  
    80  	nrf.UART0.ENABLE = nrf.UART_ENABLE_ENABLE_Enabled
    81  	nrf.UART0.TASKS_STARTTX = 1
    82  	nrf.UART0.TASKS_STARTRX = 1
    83  	nrf.UART0.INTENSET = nrf.UART_INTENSET_RXDRDY_Msk
    84  
    85  	// Enable RX IRQ.
    86  	arm.SetPriority(nrf.IRQ_UART0, 0xc0) // low priority
    87  	arm.EnableIRQ(nrf.IRQ_UART0)
    88  }
    89  
    90  // SetBaudRate sets the communication speed for the UART.
    91  func (uart UART) SetBaudRate(br uint32) {
    92  	// Magic: calculate 'baudrate' register from the input number.
    93  	// Every value listed in the datasheet will be converted to the
    94  	// correct register value, except for 192600. I suspect the value
    95  	// listed in the nrf52 datasheet (0x0EBED000) is incorrectly rounded
    96  	// and should be 0x0EBEE000, as the nrf51 datasheet lists the
    97  	// nonrounded value 0x0EBEDFA4.
    98  	// Some background:
    99  	// https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values/2046#2046
   100  	rate := uint32((uint64(br/400)*uint64(400*0xffffffff/16000000) + 0x800) & 0xffffff000)
   101  
   102  	nrf.UART0.BAUDRATE = nrf.RegValue(rate)
   103  }
   104  
   105  // WriteByte writes a byte of data to the UART.
   106  func (uart UART) WriteByte(c byte) error {
   107  	nrf.UART0.EVENTS_TXDRDY = 0
   108  	nrf.UART0.TXD = nrf.RegValue(c)
   109  	for nrf.UART0.EVENTS_TXDRDY == 0 {
   110  	}
   111  	return nil
   112  }
   113  
   114  func (uart UART) handleInterrupt() {
   115  	if nrf.UART0.EVENTS_RXDRDY != 0 {
   116  		uart.Receive(byte(nrf.UART0.RXD))
   117  		nrf.UART0.EVENTS_RXDRDY = 0x0
   118  	}
   119  }
   120  
   121  // I2C on the NRF.
   122  type I2C struct {
   123  	Bus *nrf.TWI_Type
   124  }
   125  
   126  // There are 2 I2C interfaces on the NRF.
   127  var (
   128  	I2C0 = I2C{Bus: nrf.TWI0}
   129  	I2C1 = I2C{Bus: nrf.TWI1}
   130  )
   131  
   132  // I2CConfig is used to store config info for I2C.
   133  type I2CConfig struct {
   134  	Frequency uint32
   135  	SCL       uint8
   136  	SDA       uint8
   137  }
   138  
   139  // Configure is intended to setup the I2C interface.
   140  func (i2c I2C) Configure(config I2CConfig) {
   141  	// Default I2C bus speed is 100 kHz.
   142  	if config.Frequency == 0 {
   143  		config.Frequency = TWI_FREQ_100KHZ
   144  	}
   145  	// Default I2C pins if not set.
   146  	if config.SDA == 0 && config.SCL == 0 {
   147  		config.SDA = SDA_PIN
   148  		config.SCL = SCL_PIN
   149  	}
   150  
   151  	// do config
   152  	sclPort, sclPin := GPIO{config.SCL}.getPortPin()
   153  	sclPort.PIN_CNF[sclPin] = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
   154  		(nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) |
   155  		(nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) |
   156  		(nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) |
   157  		(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos)
   158  
   159  	sdaPort, sdaPin := GPIO{config.SDA}.getPortPin()
   160  	sdaPort.PIN_CNF[sdaPin] = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
   161  		(nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) |
   162  		(nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) |
   163  		(nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) |
   164  		(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos)
   165  
   166  	if config.Frequency == TWI_FREQ_400KHZ {
   167  		i2c.Bus.FREQUENCY = nrf.TWI_FREQUENCY_FREQUENCY_K400
   168  	} else {
   169  		i2c.Bus.FREQUENCY = nrf.TWI_FREQUENCY_FREQUENCY_K100
   170  	}
   171  
   172  	i2c.Bus.ENABLE = nrf.TWI_ENABLE_ENABLE_Enabled
   173  	i2c.setPins(config.SCL, config.SDA)
   174  }
   175  
   176  // Tx does a single I2C transaction at the specified address.
   177  // It clocks out the given address, writes the bytes in w, reads back len(r)
   178  // bytes and stores them in r, and generates a stop condition on the bus.
   179  func (i2c I2C) Tx(addr uint16, w, r []byte) error {
   180  	i2c.Bus.ADDRESS = nrf.RegValue(addr)
   181  	if len(w) != 0 {
   182  		i2c.Bus.TASKS_STARTTX = 1 // start transmission for writing
   183  		for _, b := range w {
   184  			i2c.writeByte(b)
   185  		}
   186  	}
   187  	if len(r) != 0 {
   188  		i2c.Bus.TASKS_STARTRX = 1 // re-start transmission for reading
   189  		for i := range r {        // read each char
   190  			if i+1 == len(r) {
   191  				// The 'stop' signal must be sent before reading back the last
   192  				// byte, so that it will be sent by the I2C peripheral right
   193  				// after the last byte has been read.
   194  				r[i] = i2c.readLastByte()
   195  			} else {
   196  				r[i] = i2c.readByte()
   197  			}
   198  		}
   199  	} else {
   200  		// Nothing to read back. Stop the transmission.
   201  		i2c.signalStop()
   202  	}
   203  	return nil
   204  }
   205  
   206  // signalStop sends a stop signal when writing or tells the I2C peripheral that
   207  // it must generate a stop condition after the next character is retrieved when
   208  // reading.
   209  func (i2c I2C) signalStop() {
   210  	i2c.Bus.TASKS_STOP = 1
   211  	for i2c.Bus.EVENTS_STOPPED == 0 {
   212  	}
   213  	i2c.Bus.EVENTS_STOPPED = 0
   214  }
   215  
   216  // writeByte writes a single byte to the I2C bus.
   217  func (i2c I2C) writeByte(data byte) {
   218  	i2c.Bus.TXD = nrf.RegValue(data)
   219  	for i2c.Bus.EVENTS_TXDSENT == 0 {
   220  	}
   221  	i2c.Bus.EVENTS_TXDSENT = 0
   222  }
   223  
   224  // readByte reads a single byte from the I2C bus.
   225  func (i2c I2C) readByte() byte {
   226  	for i2c.Bus.EVENTS_RXDREADY == 0 {
   227  	}
   228  	i2c.Bus.EVENTS_RXDREADY = 0
   229  	return byte(i2c.Bus.RXD)
   230  }
   231  
   232  // readLastByte reads a single byte from the I2C bus, sending a stop signal
   233  // after it has been read.
   234  func (i2c I2C) readLastByte() byte {
   235  	for i2c.Bus.EVENTS_RXDREADY == 0 {
   236  	}
   237  	i2c.Bus.EVENTS_RXDREADY = 0
   238  	i2c.signalStop() // signal 'stop' now, so it is sent when reading RXD
   239  	return byte(i2c.Bus.RXD)
   240  }
   241  
   242  // SPI on the NRF.
   243  type SPI struct {
   244  	Bus *nrf.SPI_Type
   245  }
   246  
   247  // There are 2 SPI interfaces on the NRF5x.
   248  var (
   249  	SPI0 = SPI{Bus: nrf.SPI0}
   250  	SPI1 = SPI{Bus: nrf.SPI1}
   251  )
   252  
   253  // SPIConfig is used to store config info for SPI.
   254  type SPIConfig struct {
   255  	Frequency uint32
   256  	SCK       uint8
   257  	MOSI      uint8
   258  	MISO      uint8
   259  	LSBFirst  bool
   260  	Mode      uint8
   261  }
   262  
   263  // Configure is intended to setup the SPI interface.
   264  func (spi SPI) Configure(config SPIConfig) {
   265  	// Disable bus to configure it
   266  	spi.Bus.ENABLE = nrf.SPI_ENABLE_ENABLE_Disabled
   267  
   268  	// set frequency
   269  	var freq uint32
   270  
   271  	switch config.Frequency {
   272  	case 125000:
   273  		freq = nrf.SPI_FREQUENCY_FREQUENCY_K125
   274  	case 250000:
   275  		freq = nrf.SPI_FREQUENCY_FREQUENCY_K250
   276  	case 500000:
   277  		freq = nrf.SPI_FREQUENCY_FREQUENCY_K500
   278  	case 1000000:
   279  		freq = nrf.SPI_FREQUENCY_FREQUENCY_M1
   280  	case 2000000:
   281  		freq = nrf.SPI_FREQUENCY_FREQUENCY_M2
   282  	case 4000000:
   283  		freq = nrf.SPI_FREQUENCY_FREQUENCY_M4
   284  	case 8000000:
   285  		freq = nrf.SPI_FREQUENCY_FREQUENCY_M8
   286  	default:
   287  		freq = nrf.SPI_FREQUENCY_FREQUENCY_K500
   288  	}
   289  	spi.Bus.FREQUENCY = nrf.RegValue(freq)
   290  
   291  	var conf uint32
   292  
   293  	// set bit transfer order
   294  	if config.LSBFirst {
   295  		conf = (nrf.SPI_CONFIG_ORDER_LsbFirst << nrf.SPI_CONFIG_ORDER_Pos)
   296  	}
   297  
   298  	// set mode
   299  	switch config.Mode {
   300  	case 0:
   301  		conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
   302  		conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
   303  	case 1:
   304  		conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
   305  		conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos)
   306  	case 2:
   307  		conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos)
   308  		conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
   309  	case 3:
   310  		conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos)
   311  		conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos)
   312  	default: // to mode
   313  		conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
   314  		conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
   315  	}
   316  	spi.Bus.CONFIG = nrf.RegValue(conf)
   317  
   318  	// set pins
   319  	spi.setPins(config.SCK, config.MOSI, config.MISO)
   320  
   321  	// Re-enable bus now that it is configured.
   322  	spi.Bus.ENABLE = nrf.SPI_ENABLE_ENABLE_Enabled
   323  }
   324  
   325  // Transfer writes/reads a single byte using the SPI interface.
   326  func (spi SPI) Transfer(w byte) (byte, error) {
   327  	spi.Bus.TXD = nrf.RegValue(w)
   328  	for spi.Bus.EVENTS_READY == 0 {
   329  	}
   330  	r := spi.Bus.RXD
   331  	spi.Bus.EVENTS_READY = 0
   332  
   333  	// TODO: handle SPI errors
   334  	return byte(r), nil
   335  }