diff options
author | sago35 <[email protected]> | 2021-04-18 18:18:59 +0900 |
---|---|---|
committer | Ron Evans <[email protected]> | 2021-05-10 12:27:10 +0200 |
commit | e7c6bd373094aa148a93170fcf73b2f3cff2d918 (patch) | |
tree | 7cc2cbd9159b9370ff936946e0e85b3886935d5b | |
parent | 9f5066aa6f1d67f161bc0d7520dc2f1bfa1f2b0d (diff) | |
download | tinygo-e7c6bd373094aa148a93170fcf73b2f3cff2d918.tar.gz tinygo-e7c6bd373094aa148a93170fcf73b2f3cff2d918.zip |
atsame5x: add support for CAN
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | src/examples/can/feather-m4-can.go | 15 | ||||
-rw-r--r-- | src/examples/can/main.go | 53 | ||||
-rw-r--r-- | src/examples/caninterrupt/feather-m4-can.go | 15 | ||||
-rw-r--r-- | src/examples/caninterrupt/main.go | 75 | ||||
-rw-r--r-- | src/machine/board_atsame54-xpro.go | 11 | ||||
-rw-r--r-- | src/machine/board_feather-m4-can.go | 15 | ||||
-rw-r--r-- | src/machine/machine_atsame5x_can.go | 468 | ||||
-rw-r--r-- | src/runtime/runtime_atsame5x_can.go | 23 | ||||
-rw-r--r-- | targets/atsame54-xpro.json | 3 | ||||
-rw-r--r-- | targets/atsame54p20a.json | 2 | ||||
-rw-r--r-- | targets/feather-m4-can.json | 3 |
12 files changed, 682 insertions, 5 deletions
@@ -343,8 +343,12 @@ smoketest: @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=atsame54-xpro examples/blinky1 @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=atsame54-xpro examples/can + @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=feather-m4-can examples/blinky1 @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=feather-m4-can examples/caninterrupt + @$(MD5SUM) test.hex # test pwm $(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm @$(MD5SUM) test.hex diff --git a/src/examples/can/feather-m4-can.go b/src/examples/can/feather-m4-can.go new file mode 100644 index 000000000..e60552a44 --- /dev/null +++ b/src/examples/can/feather-m4-can.go @@ -0,0 +1,15 @@ +// +build feather_m4_can + +package main + +import ( + "machine" +) + +func init() { + // power on the CAN Transceiver + // https://learn.adafruit.com/adafruit-feather-m4-can-express/pinouts#can-bus-3078990-8 + boost_en := machine.BOOST_EN + boost_en.Configure(machine.PinConfig{Mode: machine.PinOutput}) + boost_en.High() +} diff --git a/src/examples/can/main.go b/src/examples/can/main.go new file mode 100644 index 000000000..7d5de82ba --- /dev/null +++ b/src/examples/can/main.go @@ -0,0 +1,53 @@ +package main + +import ( + "fmt" + "machine" + "time" +) + +func main() { + can1 := machine.CAN1 + can1.Configure(machine.CANConfig{ + TransferRate: machine.CANTransferRate500kbps, + TransferRateFD: machine.CANTransferRate1000kbps, + Rx: machine.CAN1_RX, + Tx: machine.CAN1_TX, + Standby: machine.CAN1_STANDBY, + }) + + can0 := machine.CAN0 + can0.Configure(machine.CANConfig{ + TransferRate: machine.CANTransferRate500kbps, + TransferRateFD: machine.CANTransferRate1000kbps, + Rx: machine.CAN0_RX, + Tx: machine.CAN0_TX, + Standby: machine.NoPin, + }) + + rxMsg := machine.CANRxBufferElement{} + + for { + can1.Tx(0x123, []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, false, false) + can1.Tx(0x789, []byte{0x02, 0x24, 0x46, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, true, false) + time.Sleep(time.Millisecond * 1000) + + sz0 := can0.RxFifoSize() + if sz0 > 0 { + fmt.Printf("CAN0 %d\r\n", sz0) + for i := 0; i < sz0; i++ { + can0.RxRaw(&rxMsg) + fmt.Printf("-> %08X %X %#v\r\n", rxMsg.ID, rxMsg.DLC, rxMsg.Data()) + } + } + + sz1 := can1.RxFifoSize() + if sz1 > 0 { + fmt.Printf("CAN1 %d\r\n", sz1) + for i := 0; i < sz1; i++ { + can1.RxRaw(&rxMsg) + fmt.Printf("-> %08X %X %#v\r\n", rxMsg.ID, rxMsg.DLC, rxMsg.Data()) + } + } + } +} diff --git a/src/examples/caninterrupt/feather-m4-can.go b/src/examples/caninterrupt/feather-m4-can.go new file mode 100644 index 000000000..e60552a44 --- /dev/null +++ b/src/examples/caninterrupt/feather-m4-can.go @@ -0,0 +1,15 @@ +// +build feather_m4_can + +package main + +import ( + "machine" +) + +func init() { + // power on the CAN Transceiver + // https://learn.adafruit.com/adafruit-feather-m4-can-express/pinouts#can-bus-3078990-8 + boost_en := machine.BOOST_EN + boost_en.Configure(machine.PinConfig{Mode: machine.PinOutput}) + boost_en.High() +} diff --git a/src/examples/caninterrupt/main.go b/src/examples/caninterrupt/main.go new file mode 100644 index 000000000..69b0b4d31 --- /dev/null +++ b/src/examples/caninterrupt/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "device/sam" + "fmt" + "machine" + "time" +) + +type canMsg struct { + ch byte + id uint32 + dlc byte + data []byte +} + +func main() { + ch := make(chan canMsg, 10) + go func() { + for { + select { + case m := <-ch: + fmt.Printf("%d %03X %X ", m.ch, m.id, m.dlc) + for _, d := range m.data { + fmt.Printf("%02X ", d) + } + fmt.Printf("\r\n") + } + + } + }() + + can1 := machine.CAN1 + can1.Configure(machine.CANConfig{ + TransferRate: machine.CANTransferRate500kbps, + TransferRateFD: machine.CANTransferRate1000kbps, + Rx: machine.CAN1_RX, + Tx: machine.CAN1_TX, + Standby: machine.CAN1_STANDBY, + }) + // RF0NE : Rx FIFO 0 New Message Interrupt Enable + can1.SetInterrupt(sam.CAN_IE_RF0NE, func(*machine.CAN) { + rxMsg := machine.CANRxBufferElement{} + can1.RxRaw(&rxMsg) + m := canMsg{ch: 1, id: rxMsg.ID, dlc: rxMsg.DLC, data: rxMsg.Data()} + select { + case ch <- m: + } + }) + + can0 := machine.CAN0 + can0.Configure(machine.CANConfig{ + TransferRate: machine.CANTransferRate500kbps, + TransferRateFD: machine.CANTransferRate1000kbps, + Rx: machine.CAN0_RX, + Tx: machine.CAN0_TX, + Standby: machine.NoPin, + }) + // RF0NE : Rx FIFO 0 New Message Interrupt Enable + can0.SetInterrupt(sam.CAN_IE_RF0NE, func(*machine.CAN) { + rxMsg := machine.CANRxBufferElement{} + can0.RxRaw(&rxMsg) + m := canMsg{ch: 2, id: rxMsg.ID, dlc: rxMsg.DLC, data: rxMsg.Data()} + select { + case ch <- m: + } + }) + + for { + can0.Tx(0x123, []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, false, false) + time.Sleep(time.Millisecond * 500) + can1.Tx(0x456, []byte{0xAA, 0xBB, 0xCC}, false, false) + time.Sleep(time.Millisecond * 1000) + } +} diff --git a/src/machine/board_atsame54-xpro.go b/src/machine/board_atsame54-xpro.go index 52c15b57e..d5d1f6819 100644 --- a/src/machine/board_atsame54-xpro.go +++ b/src/machine/board_atsame54-xpro.go @@ -328,3 +328,14 @@ var ( SERCOM: 6, } ) + +// CAN on the SAM E54 Xplained Pro +var ( + CAN0 = CAN{ + Bus: sam.CAN0, + } + + CAN1 = CAN{ + Bus: sam.CAN1, + } +) diff --git a/src/machine/board_feather-m4-can.go b/src/machine/board_feather-m4-can.go index 536e4b62e..795a6a3e2 100644 --- a/src/machine/board_feather-m4-can.go +++ b/src/machine/board_feather-m4-can.go @@ -125,7 +125,7 @@ func init() { D7.High() } -// I2C on the Feather M4. +// I2C on the Feather M4 CAN. var ( I2C0 = &I2C{ Bus: sam.SERCOM2_I2CM, @@ -133,10 +133,21 @@ var ( } ) -// SPI on the Feather M4. +// SPI on the Feather M4 CAN. var ( SPI0 = SPI{ Bus: sam.SERCOM1_SPIM, SERCOM: 1, } ) + +// CAN on the Feather M4 CAN. +var ( + CAN0 = CAN{ + Bus: sam.CAN0, + } + + CAN1 = CAN{ + Bus: sam.CAN1, + } +) diff --git a/src/machine/machine_atsame5x_can.go b/src/machine/machine_atsame5x_can.go new file mode 100644 index 000000000..9cad660ec --- /dev/null +++ b/src/machine/machine_atsame5x_can.go @@ -0,0 +1,468 @@ +// +build sam,atsame51 sam,atsame54 + +package machine + +import ( + "device/sam" + "errors" + "runtime/interrupt" + "unsafe" +) + +const ( + CANRxFifoSize = 16 + CANTxFifoSize = 16 + CANEvFifoSize = 16 +) + +// Message RAM can only be located in the first 64 KB area of the system RAM. +// TODO: when the go:section pragma is merged, add the section configuration + +//go:align 4 +var CANRxFifo [2][(8 + 64) * CANRxFifoSize]byte + +//go:align 4 +var CANTxFifo [2][(8 + 64) * CANTxFifoSize]byte + +//go:align 4 +var CANEvFifo [2][(8) * CANEvFifoSize]byte + +type CAN struct { + Bus *sam.CAN_Type +} + +type CANTransferRate uint32 + +// CAN transfer rates for CANConfig +const ( + CANTransferRate125kbps CANTransferRate = 125000 + CANTransferRate250kbps CANTransferRate = 250000 + CANTransferRate500kbps CANTransferRate = 500000 + CANTransferRate1000kbps CANTransferRate = 1000000 + CANTransferRate2000kbps CANTransferRate = 2000000 + CANTransferRate4000kbps CANTransferRate = 4000000 +) + +// CANConfig holds CAN configuration parameters. Tx and Rx need to be +// specified with some pins. When the Standby Pin is specified, configure it +// as an output pin and output Low in Configure(). If this operation is not +// necessary, specify NoPin. +type CANConfig struct { + TransferRate CANTransferRate + TransferRateFD CANTransferRate + Tx Pin + Rx Pin + Standby Pin +} + +var ( + errCANInvalidTransferRate = errors.New("CAN: invalid TransferRate") + errCANInvalidTransferRateFD = errors.New("CAN: invalid TransferRateFD") +) + +// Configure this CAN peripheral with the given configuration. +func (can *CAN) Configure(config CANConfig) error { + if config.Standby != NoPin { + config.Standby.Configure(PinConfig{Mode: PinOutput}) + config.Standby.Low() + } + + mode := PinCAN0 + if can.instance() == 1 { + mode = PinCAN1 + } + + config.Rx.Configure(PinConfig{Mode: mode}) + config.Tx.Configure(PinConfig{Mode: mode}) + + can.Bus.CCCR.SetBits(sam.CAN_CCCR_INIT) + for !can.Bus.CCCR.HasBits(sam.CAN_CCCR_INIT) { + } + + can.Bus.CCCR.SetBits(sam.CAN_CCCR_CCE) + + can.Bus.CCCR.SetBits(sam.CAN_CCCR_BRSE | sam.CAN_CCCR_FDOE) + can.Bus.MRCFG.Set(sam.CAN_MRCFG_QOS_MEDIUM) + // base clock == 48 MHz + if config.TransferRate == 0 { + config.TransferRate = CANTransferRate500kbps + } + brp := uint32(6) + switch config.TransferRate { + case CANTransferRate125kbps: + brp = 32 + case CANTransferRate250kbps: + brp = 16 + case CANTransferRate500kbps: + brp = 8 + case CANTransferRate1000kbps: + brp = 4 + default: + return errCANInvalidTransferRate + } + can.Bus.NBTP.Set(8<<sam.CAN_NBTP_NTSEG1_Pos | (brp-1)<<sam.CAN_NBTP_NBRP_Pos | + 1<<sam.CAN_NBTP_NTSEG2_Pos | 3<<sam.CAN_NBTP_NSJW_Pos) + + if config.TransferRateFD == 0 { + config.TransferRateFD = CANTransferRate1000kbps + } + if config.TransferRateFD < config.TransferRate { + return errCANInvalidTransferRateFD + } + brp = uint32(2) + switch config.TransferRateFD { + case CANTransferRate125kbps: + brp = 32 + case CANTransferRate250kbps: + brp = 16 + case CANTransferRate500kbps: + brp = 8 + case CANTransferRate1000kbps: + brp = 4 + case CANTransferRate2000kbps: + brp = 2 + case CANTransferRate4000kbps: + brp = 1 + default: + return errCANInvalidTransferRateFD + } + can.Bus.DBTP.Set((brp-1)<<sam.CAN_DBTP_DBRP_Pos | 8<<sam.CAN_DBTP_DTSEG1_Pos | + 1<<sam.CAN_DBTP_DTSEG2_Pos | 3<<sam.CAN_DBTP_DSJW_Pos) + + can.Bus.RXF0C.Set(sam.CAN_RXF0C_F0OM | CANRxFifoSize<<sam.CAN_RXF0C_F0S_Pos | uint32(uintptr(unsafe.Pointer(&CANRxFifo[can.instance()][0])))&0xFFFF) + can.Bus.RXESC.Set(sam.CAN_RXESC_F0DS_DATA64) + can.Bus.TXESC.Set(sam.CAN_TXESC_TBDS_DATA64) + 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) + can.Bus.TXEFC.Set(CANEvFifoSize<<sam.CAN_TXEFC_EFS_Pos | uint32(uintptr(unsafe.Pointer(&CANEvFifo[can.instance()][0])))&0xFFFF) + + can.Bus.TSCC.Set(sam.CAN_TSCC_TSS_INC) + + can.Bus.GFC.Set(0<<sam.CAN_GFC_ANFS_Pos | 0<<sam.CAN_GFC_ANFE_Pos) + + can.Bus.SIDFC.Set(0 << sam.CAN_SIDFC_LSS_Pos) + can.Bus.XIDFC.Set(0 << sam.CAN_SIDFC_LSS_Pos) + + can.Bus.XIDAM.Set(0x1FFFFFFF << sam.CAN_XIDAM_EIDM_Pos) + + can.Bus.ILE.SetBits(sam.CAN_ILE_EINT0) + + can.Bus.CCCR.ClearBits(sam.CAN_CCCR_CCE) + can.Bus.CCCR.ClearBits(sam.CAN_CCCR_INIT) + for can.Bus.CCCR.HasBits(sam.CAN_CCCR_INIT) { + } + + return nil +} + +// Callbacks to be called for CAN.SetInterrupt(). Wre're using the magic +// constant 2 and 32 here beacuse th SAM E51/E54 has 2 CAN and 32 interrupt +// sources. +var ( + canInstances [2]*CAN + canCallbacks [2][32]func(*CAN) +) + +// SetInterrupt sets an interrupt to be executed when a particular CAN state. +// +// This call will replace a previously set callback. You can pass a nil func +// to unset the CAN interrupt. If you do so, the change parameter is ignored +// and can be set to any value (such as 0). +func (can *CAN) SetInterrupt(ie uint32, callback func(*CAN)) error { + if callback == nil { + // Disable this CAN interrupt + can.Bus.IE.ClearBits(ie) + return nil + } + can.Bus.IE.SetBits(ie) + + idx := 0 + switch can.Bus { + case sam.CAN0: + canInstances[0] = can + case sam.CAN1: + canInstances[1] = can + idx = 1 + } + + for i := uint(0); i < 32; i++ { + if ie&(1<<i) != 0 { + canCallbacks[idx][i] = callback + } + } + + switch can.Bus { + case sam.CAN0: + interrupt.New(sam.IRQ_CAN0, func(interrupt.Interrupt) { + ir := sam.CAN0.IR.Get() + sam.CAN0.IR.Set(ir) // clear interrupt + for i := uint(0); i < 32; i++ { + if ir&(1<<i) != 0 && canCallbacks[0][i] != nil { + canCallbacks[0][i](canInstances[0]) + } + } + }).Enable() + case sam.CAN1: + interrupt.New(sam.IRQ_CAN1, func(interrupt.Interrupt) { + ir := sam.CAN1.IR.Get() + sam.CAN1.IR.Set(ir) // clear interrupt + for i := uint(0); i < 32; i++ { + if ir&(1<<i) != 0 && canCallbacks[1][i] != nil { + canCallbacks[1][i](canInstances[1]) + } + } + }).Enable() + } + + return nil +} + +// TxFifoIsFull returns whether TxFifo is full or not. +func (can *CAN) TxFifoIsFull() bool { + return (can.Bus.TXFQS.Get() & sam.CAN_TXFQS_TFQF_Msk) == sam.CAN_TXFQS_TFQF_Msk +} + +// TxRaw sends a CAN Frame according to CANTxBufferElement. +func (can *CAN) TxRaw(e *CANTxBufferElement) { + putIndex := (can.Bus.TXFQS.Get() & sam.CAN_TXFQS_TFQPI_Msk) >> sam.CAN_TXFQS_TFQPI_Pos + + f := CANTxFifo[can.instance()][putIndex*(8+64) : (putIndex+1)*(8+64)] + id := e.ID + if !e.XTD { + // standard identifier is stored into ID[28:18] + id <<= 18 + } + + f[3] = byte(id >> 24) + if e.ESI { + f[3] |= 0x80 + } + if e.XTD { + f[3] |= 0x40 + } + if e.RTR { + f[3] |= 0x20 + } + f[2] = byte(id >> 16) + f[1] = byte(id >> 8) + f[0] = byte(0) + f[7] = e.MM + f[6] = e.DLC + if e.EFC { + f[6] |= 0x80 + } + if e.FDF { + f[6] |= 0x20 + } + if e.BRS { + f[6] |= 0x10 + } + f[5] = 0x00 // reserved + f[4] = 0x00 // reserved + + length := CANDlcToLength(e.DLC, e.FDF) + for i := byte(0); i < length; i++ { + f[8+i] = e.DB[i] + } + + can.Bus.TXBAR.SetBits(1 << putIndex) +} + +// The Tx transmits CAN frames. It is easier to use than TxRaw, but not as +// flexible. +func (can *CAN) Tx(id uint32, data []byte, isFD, isExtendedID bool) { + length := byte(len(data)) + dlc := CANLengthToDlc(length, true) + + e := CANTxBufferElement{ + ESI: false, + XTD: isExtendedID, + RTR: false, + ID: id, + MM: 0x00, + EFC: true, + FDF: isFD, + BRS: isFD, + DLC: dlc, + } + + if !isFD { + if length > 8 { + length = 8 + } + } + for i := byte(0); i < length; i++ { + e.DB[i] = data[i] + } + + can.TxRaw(&e) +} + +// RxFifoSize returns the number of CAN Frames currently stored in the RXFifo. +func (can *CAN) RxFifoSize() int { + sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos + return int(sz) +} + +// RxFifoIsFull returns whether RxFifo is full or not. +func (can *CAN) RxFifoIsFull() bool { + sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos + return sz == CANRxFifoSize +} + +// RxFifoIsEmpty returns whether RxFifo is empty or not. +func (can *CAN) RxFifoIsEmpty() bool { + sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos + return sz == 0 +} + +// RxRaw copies the received CAN frame to CANRxBufferElement. +func (can *CAN) RxRaw(e *CANRxBufferElement) { + idx := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0GI_Msk) >> sam.CAN_RXF0S_F0GI_Pos + f := CANRxFifo[can.instance()][idx*(8+64):] + + e.ESI = false + if (f[3] & 0x80) != 0x00 { + e.ESI = true + } + + e.XTD = false + if (f[3] & 0x40) != 0x00 { + e.XTD = true + } + + e.RTR = false + if (f[3] & 0x20) != 0x00 { + e.RTR = true + } + + id := ((uint32(f[3]) << 24) + (uint32(f[2]) << 16) + (uint32(f[1]) << 8) + uint32(f[0])) & 0x1FFFFFFF + if (f[3] & 0x20) == 0 { + id >>= 18 + id &= 0x000007FF + } + e.ID = id + + e.ANMF = false + if (f[7] & 0x80) != 0x00 { + e.ANMF = true + } + + e.FIDX = f[7] & 0x7F + + e.FDF = false + if (f[6] & 0x20) != 0x00 { + e.FDF = true + } + + e.BRS = false + if (f[6] & 0x10) != 0x00 { + e.BRS = true + } + + e.DLC = f[6] & 0x0F + + e.RXTS = (uint16(f[5]) << 8) + uint16(f[4]) + + for i := byte(0); i < CANDlcToLength(e.DLC, e.FDF); i++ { + e.DB[i] = f[i+8] + } + + can.Bus.RXF0A.ReplaceBits(idx, sam.CAN_RXF0A_F0AI_Msk, sam.CAN_RXF0A_F0AI_Pos) +} + +// Rx receives a CAN frame. It is easier to use than RxRaw, but not as +// flexible. +func (can *CAN) Rx() (id uint32, dlc byte, data []byte, isFd, isExtendedID bool) { + e := CANRxBufferElement{} + can.RxRaw(&e) + length := CANDlcToLength(e.DLC, e.FDF) + return e.ID, length, e.DB[:length], e.FDF, e.XTD +} + +func (can *CAN) instance() byte { + if can.Bus == sam.CAN0 { + return 0 + } else { + return 1 + } +} + +// CANTxBufferElement is a struct that corresponds to the same5x' Tx Buffer +// Element. +type CANTxBufferElement struct { + ESI bool + XTD bool + RTR bool + ID uint32 + MM uint8 + EFC bool + FDF bool + BRS bool + DLC uint8 + DB [64]uint8 +} + +// CANRxBufferElement is a struct that corresponds to the same5x Rx Buffer and +// FIFO Element. +type CANRxBufferElement struct { + ESI bool + XTD bool + RTR bool + ID uint32 + ANMF bool + FIDX uint8 + FDF bool + BRS bool + DLC uint8 + RXTS uint16 + DB [64]uint8 +} + +// Data returns the received data as a slice of the size according to dlc. +func (e CANRxBufferElement) Data() []byte { + return e.DB[:CANDlcToLength(e.DLC, e.FDF)] +} + +// CANDlcToLength() converts a DLC value to its actual length. +func CANDlcToLength(dlc byte, isFD bool) byte { + length := dlc + if dlc == 0x09 { + length = 12 + } else if dlc == 0x0A { + length = 16 + } else if dlc == 0x0B { + length = 20 + } else if dlc == 0x0C { + length = 24 + } else if dlc == 0x0D { + length = 32 + } else if dlc == 0x0E { + length = 48 + } else if dlc == 0x0F { + length = 64 + } + return length + +} + +// CANLengthToDlc() converts its actual length to a DLC value. +func CANLengthToDlc(length byte, isFD bool) byte { + dlc := length + if length <= 0x08 { + } else if length <= 12 { + dlc = 0x09 + } else if length <= 16 { + dlc = 0x0A + } else if length <= 20 { + dlc = 0x0B + } else if length <= 24 { + dlc = 0x0C + } else if length <= 32 { + dlc = 0x0D + } else if length <= 48 { + dlc = 0x0E + } else if length <= 64 { + dlc = 0x0F + } + return dlc +} diff --git a/src/runtime/runtime_atsame5x_can.go b/src/runtime/runtime_atsame5x_can.go new file mode 100644 index 000000000..db778b0a1 --- /dev/null +++ b/src/runtime/runtime_atsame5x_can.go @@ -0,0 +1,23 @@ +// +build sam,atsame51 sam,atsame54 + +package runtime + +import ( + "device/sam" +) + +func init() { + initCANClock() +} + +func initCANClock() { + // Turn on clocks for CAN0/CAN1. + sam.MCLK.AHBMASK.SetBits(sam.MCLK_AHBMASK_CAN0_) + sam.MCLK.AHBMASK.SetBits(sam.MCLK_AHBMASK_CAN1_) + + // Put Generic Clock Generator 1 as source for USB + sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_CAN0].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) | + sam.GCLK_PCHCTRL_CHEN) + sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_CAN1].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) | + sam.GCLK_PCHCTRL_CHEN) +} diff --git a/targets/atsame54-xpro.json b/targets/atsame54-xpro.json index d46f8c499..631df8cfb 100644 --- a/targets/atsame54-xpro.json +++ b/targets/atsame54-xpro.json @@ -2,5 +2,6 @@ "inherits": ["atsame54p20a"], "build-tags": ["atsame54_xpro"], "flash-method": "openocd", - "openocd-interface": "cmsis-dap" + "openocd-interface": "cmsis-dap", + "default-stack-size": 4096 } diff --git a/targets/atsame54p20a.json b/targets/atsame54p20a.json index ed7831f3d..f2450fb42 100644 --- a/targets/atsame54p20a.json +++ b/targets/atsame54p20a.json @@ -1,6 +1,6 @@ { "inherits": ["cortex-m4"], - "build-tags": ["sam", "atsame5x", "atsame54p20", "atsame54p20a"], + "build-tags": ["sam", "atsame5x", "atsame54", "atsame54p20", "atsame54p20a"], "linkerscript": "targets/atsame5xx20-no-bootloader.ld", "extra-files": [ "src/device/sam/atsame54p20a.s" diff --git a/targets/feather-m4-can.json b/targets/feather-m4-can.json index 0480eb8f0..190d4d8f9 100644 --- a/targets/feather-m4-can.json +++ b/targets/feather-m4-can.json @@ -4,5 +4,6 @@ "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "FTHRCANBOOT", - "msd-firmware-name": "firmware.uf2" + "msd-firmware-name": "firmware.uf2", + "default-stack-size": 4096 } |