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 }