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

     1  //go:build (sam && atsame51) || (sam && atsame54)
     2  
     3  package machine
     4  
     5  import (
     6  	"device/sam"
     7  	"errors"
     8  	"runtime/interrupt"
     9  	"unsafe"
    10  )
    11  
    12  const (
    13  	CANRxFifoSize = 16
    14  	CANTxFifoSize = 16
    15  	CANEvFifoSize = 16
    16  )
    17  
    18  // Message RAM can only be located in the first 64 KB area of the system RAM.
    19  // TODO: when the go:section pragma is merged, add the section configuration
    20  
    21  //go:align 4
    22  var CANRxFifo [2][(8 + 64) * CANRxFifoSize]byte
    23  
    24  //go:align 4
    25  var CANTxFifo [2][(8 + 64) * CANTxFifoSize]byte
    26  
    27  //go:align 4
    28  var CANEvFifo [2][(8) * CANEvFifoSize]byte
    29  
    30  type CAN struct {
    31  	Bus *sam.CAN_Type
    32  }
    33  
    34  type CANTransferRate uint32
    35  
    36  // CAN transfer rates for CANConfig
    37  const (
    38  	CANTransferRate125kbps  CANTransferRate = 125000
    39  	CANTransferRate250kbps  CANTransferRate = 250000
    40  	CANTransferRate500kbps  CANTransferRate = 500000
    41  	CANTransferRate1000kbps CANTransferRate = 1000000
    42  	CANTransferRate2000kbps CANTransferRate = 2000000
    43  	CANTransferRate4000kbps CANTransferRate = 4000000
    44  )
    45  
    46  // CANConfig holds CAN configuration parameters. Tx and Rx need to be
    47  // specified with some pins. When the Standby Pin is specified, configure it
    48  // as an output pin and output Low in Configure(). If this operation is not
    49  // necessary, specify NoPin.
    50  type CANConfig struct {
    51  	TransferRate   CANTransferRate
    52  	TransferRateFD CANTransferRate
    53  	Tx             Pin
    54  	Rx             Pin
    55  	Standby        Pin
    56  }
    57  
    58  var (
    59  	errCANInvalidTransferRate   = errors.New("CAN: invalid TransferRate")
    60  	errCANInvalidTransferRateFD = errors.New("CAN: invalid TransferRateFD")
    61  )
    62  
    63  // Configure this CAN peripheral with the given configuration.
    64  func (can *CAN) Configure(config CANConfig) error {
    65  	if config.Standby != NoPin {
    66  		config.Standby.Configure(PinConfig{Mode: PinOutput})
    67  		config.Standby.Low()
    68  	}
    69  
    70  	mode := PinCAN0
    71  	if can.instance() == 1 {
    72  		mode = PinCAN1
    73  	}
    74  
    75  	config.Rx.Configure(PinConfig{Mode: mode})
    76  	config.Tx.Configure(PinConfig{Mode: mode})
    77  
    78  	can.Bus.CCCR.SetBits(sam.CAN_CCCR_INIT)
    79  	for !can.Bus.CCCR.HasBits(sam.CAN_CCCR_INIT) {
    80  	}
    81  
    82  	can.Bus.CCCR.SetBits(sam.CAN_CCCR_CCE)
    83  
    84  	can.Bus.CCCR.SetBits(sam.CAN_CCCR_BRSE | sam.CAN_CCCR_FDOE)
    85  	can.Bus.MRCFG.Set(sam.CAN_MRCFG_QOS_MEDIUM)
    86  	// base clock == 48 MHz
    87  	if config.TransferRate == 0 {
    88  		config.TransferRate = CANTransferRate500kbps
    89  	}
    90  	brp := uint32(6)
    91  	switch config.TransferRate {
    92  	case CANTransferRate125kbps:
    93  		brp = 32
    94  	case CANTransferRate250kbps:
    95  		brp = 16
    96  	case CANTransferRate500kbps:
    97  		brp = 8
    98  	case CANTransferRate1000kbps:
    99  		brp = 4
   100  	default:
   101  		return errCANInvalidTransferRate
   102  	}
   103  	can.Bus.NBTP.Set(8<<sam.CAN_NBTP_NTSEG1_Pos | (brp-1)<<sam.CAN_NBTP_NBRP_Pos |
   104  		1<<sam.CAN_NBTP_NTSEG2_Pos | 3<<sam.CAN_NBTP_NSJW_Pos)
   105  
   106  	if config.TransferRateFD == 0 {
   107  		config.TransferRateFD = CANTransferRate1000kbps
   108  	}
   109  	if config.TransferRateFD < config.TransferRate {
   110  		return errCANInvalidTransferRateFD
   111  	}
   112  	brp = uint32(2)
   113  	switch config.TransferRateFD {
   114  	case CANTransferRate125kbps:
   115  		brp = 32
   116  	case CANTransferRate250kbps:
   117  		brp = 16
   118  	case CANTransferRate500kbps:
   119  		brp = 8
   120  	case CANTransferRate1000kbps:
   121  		brp = 4
   122  	case CANTransferRate2000kbps:
   123  		brp = 2
   124  	case CANTransferRate4000kbps:
   125  		brp = 1
   126  	default:
   127  		return errCANInvalidTransferRateFD
   128  	}
   129  	can.Bus.DBTP.Set((brp-1)<<sam.CAN_DBTP_DBRP_Pos | 8<<sam.CAN_DBTP_DTSEG1_Pos |
   130  		1<<sam.CAN_DBTP_DTSEG2_Pos | 3<<sam.CAN_DBTP_DSJW_Pos)
   131  
   132  	can.Bus.RXF0C.Set(sam.CAN_RXF0C_F0OM | CANRxFifoSize<<sam.CAN_RXF0C_F0S_Pos | uint32(uintptr(unsafe.Pointer(&CANRxFifo[can.instance()][0])))&0xFFFF)
   133  	can.Bus.RXESC.Set(sam.CAN_RXESC_F0DS_DATA64)
   134  	can.Bus.TXESC.Set(sam.CAN_TXESC_TBDS_DATA64)
   135  	can.Bus.TXBC.Set(CANTxFifoSize<<sam.CAN_TXBC_TFQS_Pos | 0<<sam.CAN_TXBC_NDTB_Pos | uint32(uintptr(unsafe.Pointer(&CANTxFifo[can.instance()][0])))&0xFFFF)
   136  	can.Bus.TXEFC.Set(CANEvFifoSize<<sam.CAN_TXEFC_EFS_Pos | uint32(uintptr(unsafe.Pointer(&CANEvFifo[can.instance()][0])))&0xFFFF)
   137  
   138  	can.Bus.TSCC.Set(sam.CAN_TSCC_TSS_INC)
   139  
   140  	can.Bus.GFC.Set(0<<sam.CAN_GFC_ANFS_Pos | 0<<sam.CAN_GFC_ANFE_Pos)
   141  
   142  	can.Bus.SIDFC.Set(0 << sam.CAN_SIDFC_LSS_Pos)
   143  	can.Bus.XIDFC.Set(0 << sam.CAN_SIDFC_LSS_Pos)
   144  
   145  	can.Bus.XIDAM.Set(0x1FFFFFFF << sam.CAN_XIDAM_EIDM_Pos)
   146  
   147  	can.Bus.ILE.SetBits(sam.CAN_ILE_EINT0)
   148  
   149  	can.Bus.CCCR.ClearBits(sam.CAN_CCCR_CCE)
   150  	can.Bus.CCCR.ClearBits(sam.CAN_CCCR_INIT)
   151  	for can.Bus.CCCR.HasBits(sam.CAN_CCCR_INIT) {
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  // Callbacks to be called for CAN.SetInterrupt(). Wre're using the magic
   158  // constant 2 and 32 here beacuse th SAM E51/E54 has 2 CAN and 32 interrupt
   159  // sources.
   160  var (
   161  	canInstances [2]*CAN
   162  	canCallbacks [2][32]func(*CAN)
   163  )
   164  
   165  // SetInterrupt sets an interrupt to be executed when a particular CAN state.
   166  //
   167  // This call will replace a previously set callback. You can pass a nil func
   168  // to unset the CAN interrupt. If you do so, the change parameter is ignored
   169  // and can be set to any value (such as 0).
   170  func (can *CAN) SetInterrupt(ie uint32, callback func(*CAN)) error {
   171  	if callback == nil {
   172  		// Disable this CAN interrupt
   173  		can.Bus.IE.ClearBits(ie)
   174  		return nil
   175  	}
   176  	can.Bus.IE.SetBits(ie)
   177  
   178  	idx := 0
   179  	switch can.Bus {
   180  	case sam.CAN0:
   181  		canInstances[0] = can
   182  	case sam.CAN1:
   183  		canInstances[1] = can
   184  		idx = 1
   185  	}
   186  
   187  	for i := uint(0); i < 32; i++ {
   188  		if ie&(1<<i) != 0 {
   189  			canCallbacks[idx][i] = callback
   190  		}
   191  	}
   192  
   193  	switch can.Bus {
   194  	case sam.CAN0:
   195  		interrupt.New(sam.IRQ_CAN0, func(interrupt.Interrupt) {
   196  			ir := sam.CAN0.IR.Get()
   197  			sam.CAN0.IR.Set(ir) // clear interrupt
   198  			for i := uint(0); i < 32; i++ {
   199  				if ir&(1<<i) != 0 && canCallbacks[0][i] != nil {
   200  					canCallbacks[0][i](canInstances[0])
   201  				}
   202  			}
   203  		}).Enable()
   204  	case sam.CAN1:
   205  		interrupt.New(sam.IRQ_CAN1, func(interrupt.Interrupt) {
   206  			ir := sam.CAN1.IR.Get()
   207  			sam.CAN1.IR.Set(ir) // clear interrupt
   208  			for i := uint(0); i < 32; i++ {
   209  				if ir&(1<<i) != 0 && canCallbacks[1][i] != nil {
   210  					canCallbacks[1][i](canInstances[1])
   211  				}
   212  			}
   213  		}).Enable()
   214  	}
   215  
   216  	return nil
   217  }
   218  
   219  // TxFifoIsFull returns whether TxFifo is full or not.
   220  func (can *CAN) TxFifoIsFull() bool {
   221  	return (can.Bus.TXFQS.Get() & sam.CAN_TXFQS_TFQF_Msk) == sam.CAN_TXFQS_TFQF_Msk
   222  }
   223  
   224  // TxRaw sends a CAN Frame according to CANTxBufferElement.
   225  func (can *CAN) TxRaw(e *CANTxBufferElement) {
   226  	putIndex := (can.Bus.TXFQS.Get() & sam.CAN_TXFQS_TFQPI_Msk) >> sam.CAN_TXFQS_TFQPI_Pos
   227  
   228  	f := CANTxFifo[can.instance()][putIndex*(8+64) : (putIndex+1)*(8+64)]
   229  	id := e.ID
   230  	if !e.XTD {
   231  		// standard identifier is stored into ID[28:18]
   232  		id <<= 18
   233  	}
   234  
   235  	f[3] = byte(id>>24) & 0x1F
   236  	if e.ESI {
   237  		f[3] |= 0x80
   238  	}
   239  	if e.XTD {
   240  		f[3] |= 0x40
   241  	}
   242  	if e.RTR {
   243  		f[3] |= 0x20
   244  	}
   245  	f[2] = byte(id >> 16)
   246  	f[1] = byte(id >> 8)
   247  	f[0] = byte(id)
   248  	f[7] = e.MM
   249  	f[6] = e.DLC
   250  	if e.EFC {
   251  		f[6] |= 0x80
   252  	}
   253  	if e.FDF {
   254  		f[6] |= 0x20
   255  	}
   256  	if e.BRS {
   257  		f[6] |= 0x10
   258  	}
   259  	f[5] = 0x00 // reserved
   260  	f[4] = 0x00 // reserved
   261  
   262  	length := CANDlcToLength(e.DLC, e.FDF)
   263  	for i := byte(0); i < length; i++ {
   264  		f[8+i] = e.DB[i]
   265  	}
   266  
   267  	can.Bus.TXBAR.SetBits(1 << putIndex)
   268  }
   269  
   270  // The Tx transmits CAN frames. It is easier to use than TxRaw, but not as
   271  // flexible.
   272  func (can *CAN) Tx(id uint32, data []byte, isFD, isExtendedID bool) {
   273  	length := byte(len(data))
   274  	dlc := CANLengthToDlc(length, true)
   275  
   276  	e := CANTxBufferElement{
   277  		ESI: false,
   278  		XTD: isExtendedID,
   279  		RTR: false,
   280  		ID:  id,
   281  		MM:  0x00,
   282  		EFC: true,
   283  		FDF: isFD,
   284  		BRS: isFD,
   285  		DLC: dlc,
   286  	}
   287  
   288  	if !isFD {
   289  		if length > 8 {
   290  			length = 8
   291  		}
   292  	}
   293  	for i := byte(0); i < length; i++ {
   294  		e.DB[i] = data[i]
   295  	}
   296  
   297  	can.TxRaw(&e)
   298  }
   299  
   300  // RxFifoSize returns the number of CAN Frames currently stored in the RXFifo.
   301  func (can *CAN) RxFifoSize() int {
   302  	sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos
   303  	return int(sz)
   304  }
   305  
   306  // RxFifoIsFull returns whether RxFifo is full or not.
   307  func (can *CAN) RxFifoIsFull() bool {
   308  	sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos
   309  	return sz == CANRxFifoSize
   310  }
   311  
   312  // RxFifoIsEmpty returns whether RxFifo is empty or not.
   313  func (can *CAN) RxFifoIsEmpty() bool {
   314  	sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos
   315  	return sz == 0
   316  }
   317  
   318  // RxRaw copies the received CAN frame to CANRxBufferElement.
   319  func (can *CAN) RxRaw(e *CANRxBufferElement) {
   320  	idx := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0GI_Msk) >> sam.CAN_RXF0S_F0GI_Pos
   321  	f := CANRxFifo[can.instance()][idx*(8+64):]
   322  
   323  	e.ESI = false
   324  	if (f[3] & 0x80) != 0x00 {
   325  		e.ESI = true
   326  	}
   327  
   328  	e.XTD = false
   329  	if (f[3] & 0x40) != 0x00 {
   330  		e.XTD = true
   331  	}
   332  
   333  	e.RTR = false
   334  	if (f[3] & 0x20) != 0x00 {
   335  		e.RTR = true
   336  	}
   337  
   338  	id := ((uint32(f[3]) << 24) + (uint32(f[2]) << 16) + (uint32(f[1]) << 8) + uint32(f[0])) & 0x1FFFFFFF
   339  	if !e.XTD {
   340  		id >>= 18
   341  		id &= 0x000007FF
   342  	}
   343  	e.ID = id
   344  
   345  	e.ANMF = false
   346  	if (f[7] & 0x80) != 0x00 {
   347  		e.ANMF = true
   348  	}
   349  
   350  	e.FIDX = f[7] & 0x7F
   351  
   352  	e.FDF = false
   353  	if (f[6] & 0x20) != 0x00 {
   354  		e.FDF = true
   355  	}
   356  
   357  	e.BRS = false
   358  	if (f[6] & 0x10) != 0x00 {
   359  		e.BRS = true
   360  	}
   361  
   362  	e.DLC = f[6] & 0x0F
   363  
   364  	e.RXTS = (uint16(f[5]) << 8) + uint16(f[4])
   365  
   366  	for i := byte(0); i < CANDlcToLength(e.DLC, e.FDF); i++ {
   367  		e.DB[i] = f[i+8]
   368  	}
   369  
   370  	can.Bus.RXF0A.ReplaceBits(idx, sam.CAN_RXF0A_F0AI_Msk, sam.CAN_RXF0A_F0AI_Pos)
   371  }
   372  
   373  // Rx receives a CAN frame. It is easier to use than RxRaw, but not as
   374  // flexible.
   375  func (can *CAN) Rx() (id uint32, dlc byte, data []byte, isFd, isExtendedID bool) {
   376  	e := CANRxBufferElement{}
   377  	can.RxRaw(&e)
   378  	length := CANDlcToLength(e.DLC, e.FDF)
   379  	return e.ID, length, e.DB[:length], e.FDF, e.XTD
   380  }
   381  
   382  func (can *CAN) instance() byte {
   383  	if can.Bus == sam.CAN0 {
   384  		return 0
   385  	} else {
   386  		return 1
   387  	}
   388  }
   389  
   390  // CANTxBufferElement is a struct that corresponds to the same5x' Tx Buffer
   391  // Element.
   392  type CANTxBufferElement struct {
   393  	ESI bool
   394  	XTD bool
   395  	RTR bool
   396  	ID  uint32
   397  	MM  uint8
   398  	EFC bool
   399  	FDF bool
   400  	BRS bool
   401  	DLC uint8
   402  	DB  [64]uint8
   403  }
   404  
   405  // CANRxBufferElement is a struct that corresponds to the same5x Rx Buffer and
   406  // FIFO Element.
   407  type CANRxBufferElement struct {
   408  	ESI  bool
   409  	XTD  bool
   410  	RTR  bool
   411  	ID   uint32
   412  	ANMF bool
   413  	FIDX uint8
   414  	FDF  bool
   415  	BRS  bool
   416  	DLC  uint8
   417  	RXTS uint16
   418  	DB   [64]uint8
   419  }
   420  
   421  // Data returns the received data as a slice of the size according to dlc.
   422  func (e CANRxBufferElement) Data() []byte {
   423  	return e.DB[:CANDlcToLength(e.DLC, e.FDF)]
   424  }
   425  
   426  // Length returns its actual length.
   427  func (e CANRxBufferElement) Length() byte {
   428  	return CANDlcToLength(e.DLC, e.FDF)
   429  }
   430  
   431  // CANDlcToLength() converts a DLC value to its actual length.
   432  func CANDlcToLength(dlc byte, isFD bool) byte {
   433  	length := dlc
   434  	if dlc == 0x09 {
   435  		length = 12
   436  	} else if dlc == 0x0A {
   437  		length = 16
   438  	} else if dlc == 0x0B {
   439  		length = 20
   440  	} else if dlc == 0x0C {
   441  		length = 24
   442  	} else if dlc == 0x0D {
   443  		length = 32
   444  	} else if dlc == 0x0E {
   445  		length = 48
   446  	} else if dlc == 0x0F {
   447  		length = 64
   448  	}
   449  	return length
   450  
   451  }
   452  
   453  // CANLengthToDlc() converts its actual length to a DLC value.
   454  func CANLengthToDlc(length byte, isFD bool) byte {
   455  	dlc := length
   456  	if length <= 0x08 {
   457  	} else if length <= 12 {
   458  		dlc = 0x09
   459  	} else if length <= 16 {
   460  		dlc = 0x0A
   461  	} else if length <= 20 {
   462  		dlc = 0x0B
   463  	} else if length <= 24 {
   464  		dlc = 0x0C
   465  	} else if length <= 32 {
   466  		dlc = 0x0D
   467  	} else if length <= 48 {
   468  		dlc = 0x0E
   469  	} else if length <= 64 {
   470  		dlc = 0x0F
   471  	}
   472  	return dlc
   473  }