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

     1  //go:build nrf52840 || nrf52833
     2  
     3  package machine
     4  
     5  import (
     6  	"device/nrf"
     7  	"unsafe"
     8  )
     9  
    10  // I2C on the NRF528xx.
    11  type I2C struct {
    12  	Bus  *nrf.TWIM_Type // Called Bus to align with Bus field in nrf51
    13  	BusT *nrf.TWIS_Type
    14  	mode I2CMode
    15  }
    16  
    17  // There are 2 I2C interfaces on the NRF.
    18  var (
    19  	I2C0 = &I2C{Bus: nrf.TWIM0, BusT: nrf.TWIS0}
    20  	I2C1 = &I2C{Bus: nrf.TWIM1, BusT: nrf.TWIS1}
    21  )
    22  
    23  func (i2c *I2C) enableAsController() {
    24  	i2c.Bus.ENABLE.Set(nrf.TWIM_ENABLE_ENABLE_Enabled)
    25  }
    26  
    27  func (i2c *I2C) enableAsTarget() {
    28  	i2c.BusT.ENABLE.Set(nrf.TWIS_ENABLE_ENABLE_Enabled)
    29  }
    30  
    31  func (i2c *I2C) disable() {
    32  	i2c.Bus.ENABLE.Set(0)
    33  }
    34  
    35  // Tx does a single I2C transaction at the specified address (when in controller mode).
    36  //
    37  // It clocks out the given address, writes the bytes in w, reads back len(r)
    38  // bytes and stores them in r, and generates a stop condition on the bus.
    39  func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) {
    40  	i2c.Bus.ADDRESS.Set(uint32(addr))
    41  
    42  	i2c.Bus.EVENTS_STOPPED.Set(0)
    43  	i2c.Bus.EVENTS_ERROR.Set(0)
    44  	i2c.Bus.EVENTS_RXSTARTED.Set(0)
    45  	i2c.Bus.EVENTS_TXSTARTED.Set(0)
    46  	i2c.Bus.EVENTS_LASTRX.Set(0)
    47  	i2c.Bus.EVENTS_LASTTX.Set(0)
    48  	i2c.Bus.EVENTS_SUSPENDED.Set(0)
    49  
    50  	// Configure for a single shot to perform both write and read (as applicable)
    51  	if len(w) != 0 {
    52  		i2c.Bus.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&w[0]))))
    53  		i2c.Bus.TXD.MAXCNT.Set(uint32(len(w)))
    54  
    55  		// If no read, immediately signal stop after TX
    56  		if len(r) == 0 {
    57  			i2c.Bus.SHORTS.Set(nrf.TWIM_SHORTS_LASTTX_STOP)
    58  		}
    59  	}
    60  	if len(r) != 0 {
    61  		i2c.Bus.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&r[0]))))
    62  		i2c.Bus.RXD.MAXCNT.Set(uint32(len(r)))
    63  
    64  		// Auto-start Rx after Tx and Stop after Rx
    65  		i2c.Bus.SHORTS.Set(nrf.TWIM_SHORTS_LASTTX_STARTRX | nrf.TWIM_SHORTS_LASTRX_STOP)
    66  	}
    67  
    68  	// Fire the transaction
    69  	i2c.Bus.TASKS_RESUME.Set(1)
    70  	if len(w) != 0 {
    71  		i2c.Bus.TASKS_STARTTX.Set(1)
    72  	} else if len(r) != 0 {
    73  		i2c.Bus.TASKS_STARTRX.Set(1)
    74  	}
    75  
    76  	// Wait until transaction stopped to ensure buffers fully processed
    77  	for i2c.Bus.EVENTS_STOPPED.Get() == 0 {
    78  		// Allow scheduler to run
    79  		gosched()
    80  
    81  		// Handle errors by ensuring STOP sent on bus
    82  		if i2c.Bus.EVENTS_ERROR.Get() != 0 {
    83  			if i2c.Bus.EVENTS_STOPPED.Get() == 0 {
    84  				// STOP cannot be sent during SUSPEND
    85  				i2c.Bus.TASKS_RESUME.Set(1)
    86  				i2c.Bus.TASKS_STOP.Set(1)
    87  			}
    88  			err = twiCError(i2c.Bus.ERRORSRC.Get())
    89  		}
    90  	}
    91  
    92  	return
    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 uint8) error {
    99  	i2c.BusT.ADDRESS[0].Set(uint32(addr))
   100  	i2c.BusT.CONFIG.Set(nrf.TWIS_CONFIG_ADDRESS0_Enabled)
   101  
   102  	i2c.BusT.EVENTS_STOPPED.Set(0)
   103  	i2c.BusT.EVENTS_ERROR.Set(0)
   104  	i2c.BusT.EVENTS_RXSTARTED.Set(0)
   105  	i2c.BusT.EVENTS_TXSTARTED.Set(0)
   106  	i2c.BusT.EVENTS_WRITE.Set(0)
   107  	i2c.BusT.EVENTS_READ.Set(0)
   108  
   109  	return nil
   110  }
   111  
   112  // WaitForEvent blocks the current go-routine until an I2C event is received (when in Target mode).
   113  //
   114  // The passed buffer will be populated for receive events, with the number of bytes
   115  // received returned in count.  For other event types, buf is not modified and a count
   116  // of zero is returned.
   117  //
   118  // For request events, the caller MUST call `Reply` to avoid hanging the i2c bus indefinitely.
   119  func (i2c *I2C) WaitForEvent(buf []byte) (evt I2CTargetEvent, count int, err error) {
   120  	i2c.BusT.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&buf[0]))))
   121  	i2c.BusT.RXD.MAXCNT.Set(uint32(len(buf)))
   122  
   123  	i2c.BusT.TASKS_PREPARERX.Set(nrf.TWIS_TASKS_PREPARERX_TASKS_PREPARERX_Trigger)
   124  
   125  	i2c.Bus.TASKS_RESUME.Set(1)
   126  
   127  	for i2c.BusT.EVENTS_STOPPED.Get() == 0 &&
   128  		i2c.BusT.EVENTS_READ.Get() == 0 {
   129  		gosched()
   130  
   131  		if i2c.BusT.EVENTS_ERROR.Get() != 0 {
   132  			i2c.BusT.EVENTS_ERROR.Set(0)
   133  			return I2CReceive, 0, twisError(i2c.BusT.ERRORSRC.Get())
   134  		}
   135  	}
   136  
   137  	count = 0
   138  	evt = I2CFinish
   139  	err = nil
   140  
   141  	if i2c.BusT.EVENTS_WRITE.Get() != 0 {
   142  		i2c.BusT.EVENTS_WRITE.Set(0)
   143  
   144  		// Data was sent to this target.  We've waited for
   145  		// READ or STOPPED event, so transmission should be
   146  		// complete.
   147  		count = int(i2c.BusT.RXD.AMOUNT.Get())
   148  		evt = I2CReceive
   149  	} else if i2c.BusT.EVENTS_READ.Get() != 0 {
   150  		i2c.BusT.EVENTS_READ.Set(0)
   151  
   152  		// Data is requested from this target, hw will stretch
   153  		// the controller's clock until there is a reply to
   154  		// send
   155  		evt = I2CRequest
   156  	} else if i2c.BusT.EVENTS_STOPPED.Get() != 0 {
   157  		i2c.BusT.EVENTS_STOPPED.Set(0)
   158  		evt = I2CFinish
   159  	}
   160  
   161  	return
   162  }
   163  
   164  // Reply supplies the response data the controller.
   165  func (i2c *I2C) Reply(buf []byte) error {
   166  	i2c.BusT.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&buf[0]))))
   167  	i2c.BusT.TXD.MAXCNT.Set(uint32(len(buf)))
   168  
   169  	i2c.BusT.EVENTS_STOPPED.Set(0)
   170  
   171  	// Trigger Tx
   172  	i2c.BusT.TASKS_PREPARETX.Set(nrf.TWIS_TASKS_PREPARETX_TASKS_PREPARETX_Trigger)
   173  
   174  	// Block, waiting for Tx to complete
   175  	for i2c.BusT.EVENTS_STOPPED.Get() == 0 {
   176  		gosched()
   177  
   178  		if i2c.BusT.EVENTS_ERROR.Get() != 0 {
   179  			return twisError(i2c.BusT.ERRORSRC.Get())
   180  		}
   181  	}
   182  
   183  	i2c.BusT.EVENTS_STOPPED.Set(0)
   184  
   185  	return nil
   186  }
   187  
   188  // twiCError converts an I2C controller error to Go
   189  func twiCError(val uint32) error {
   190  	if val == 0 {
   191  		return nil
   192  	} else if val&nrf.TWIM_ERRORSRC_OVERRUN_Msk == nrf.TWIM_ERRORSRC_OVERRUN {
   193  		return errI2CBusError
   194  	} else if val&nrf.TWIM_ERRORSRC_ANACK_Msk == nrf.TWIM_ERRORSRC_ANACK {
   195  		return errI2CAckExpected
   196  	} else if val&nrf.TWIM_ERRORSRC_DNACK_Msk == nrf.TWIM_ERRORSRC_DNACK {
   197  		return errI2CAckExpected
   198  	}
   199  
   200  	return errI2CBusError
   201  }
   202  
   203  // twisError converts an I2C target error to Go
   204  func twisError(val uint32) error {
   205  	if val == 0 {
   206  		return nil
   207  	} else if val&nrf.TWIS_ERRORSRC_OVERFLOW_Msk == nrf.TWIS_ERRORSRC_OVERFLOW {
   208  		return errI2COverflow
   209  	} else if val&nrf.TWIS_ERRORSRC_DNACK_Msk == nrf.TWIS_ERRORSRC_DNACK {
   210  		return errI2CAckExpected
   211  	} else if val&nrf.TWIS_ERRORSRC_OVERREAD_Msk == nrf.TWIS_ERRORSRC_OVERREAD {
   212  		return errI2COverread
   213  	}
   214  
   215  	return errI2CBusError
   216  }
   217  
   218  var (
   219  	Watchdog = &watchdogImpl{}
   220  )
   221  
   222  const (
   223  	// WatchdogMaxTimeout in milliseconds (approx 36h)
   224  	WatchdogMaxTimeout = (0xffffffff * 1000) / 32768
   225  )
   226  
   227  type watchdogImpl struct {
   228  }
   229  
   230  // Configure the watchdog.
   231  //
   232  // This method should not be called after the watchdog is started and on
   233  // some platforms attempting to reconfigure after starting the watchdog
   234  // is explicitly forbidden / will not work.
   235  func (wd *watchdogImpl) Configure(config WatchdogConfig) error {
   236  	// 32.768kHz counter
   237  	crv := int32((int64(config.TimeoutMillis) * 32768) / 1000)
   238  	nrf.WDT.CRV.Set(uint32(crv))
   239  
   240  	// One source
   241  	nrf.WDT.RREN.Set(0x1)
   242  
   243  	// Run during sleep
   244  	nrf.WDT.CONFIG.Set(nrf.WDT_CONFIG_SLEEP_Run)
   245  
   246  	return nil
   247  }
   248  
   249  // Starts the watchdog.
   250  func (wd *watchdogImpl) Start() error {
   251  	nrf.WDT.TASKS_START.Set(nrf.WDT_TASKS_START_TASKS_START)
   252  	return nil
   253  }
   254  
   255  // Update the watchdog, indicating that `source` is healthy.
   256  func (wd *watchdogImpl) Update() {
   257  	// 0x6E524635 = magic value from datasheet
   258  	nrf.WDT.RR[0].Set(0x6E524635)
   259  }