mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-14 11:53:41 +00:00
mcp2515: add support for mcp2515 CAN device
This commit is contained in:
@@ -89,6 +89,8 @@ smoke-test:
|
|||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp3008/main.go
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp3008/main.go
|
||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp2515/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/microbitmatrix/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/microbitmatrix/main.go
|
||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mma8653/main.go
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mma8653/main.go
|
||||||
@@ -194,7 +196,7 @@ DRIVERS = $(wildcard */)
|
|||||||
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
|
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
|
||||||
hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \
|
hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \
|
||||||
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \
|
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \
|
||||||
pcf8563
|
pcf8563 mcp2515
|
||||||
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
|
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
|
||||||
|
|
||||||
unit-test:
|
unit-test:
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func main() {
|
|||||||
|
|
||||||
## Currently supported devices
|
## Currently supported devices
|
||||||
|
|
||||||
The following 63 devices are supported.
|
The following 64 devices are supported.
|
||||||
|
|
||||||
| Device Name | Interface Type |
|
| Device Name | Interface Type |
|
||||||
|----------|-------------|
|
|----------|-------------|
|
||||||
@@ -92,6 +92,7 @@ The following 63 devices are supported.
|
|||||||
| [MAX7219 & MAX7221 display driver](https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf) | SPI |
|
| [MAX7219 & MAX7221 display driver](https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf) | SPI |
|
||||||
| [MCP23017 port expander](https://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf) | I2C |
|
| [MCP23017 port expander](https://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf) | I2C |
|
||||||
| [MCP3008 analog to digital converter (ADC)](http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf) | SPI |
|
| [MCP3008 analog to digital converter (ADC)](http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf) | SPI |
|
||||||
|
| [MCP2515 Stand-Alone CAN Controller with SPI Interface](https://ww1.microchip.com/downloads/en/DeviceDoc/MCP2515-Family-Data-Sheet-DS20001801K.pdf) | SPI |
|
||||||
| [Microphone - PDM](https://cdn-learn.adafruit.com/assets/assets/000/049/977/original/MP34DT01-M.pdf) | I2S/PDM |
|
| [Microphone - PDM](https://cdn-learn.adafruit.com/assets/assets/000/049/977/original/MP34DT01-M.pdf) | I2S/PDM |
|
||||||
| [MMA8653 accelerometer](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf) | I2C |
|
| [MMA8653 accelerometer](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf) | I2C |
|
||||||
| [MPU6050 accelerometer/gyroscope](https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf) | I2C |
|
| [MPU6050 accelerometer/gyroscope](https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf) | I2C |
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/mcp2515"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
spi = machine.SPI0
|
||||||
|
csPin = machine.D5
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
spi.Configure(machine.SPIConfig{
|
||||||
|
Frequency: 115200,
|
||||||
|
SCK: machine.SPI0_SCK_PIN,
|
||||||
|
SDO: machine.SPI0_SDO_PIN,
|
||||||
|
SDI: machine.SPI0_SDI_PIN,
|
||||||
|
Mode: 0})
|
||||||
|
can := mcp2515.New(spi, csPin)
|
||||||
|
can.Configure()
|
||||||
|
err := can.Begin(mcp2515.CAN500kBps, mcp2515.Clock8MHz)
|
||||||
|
if err != nil {
|
||||||
|
failMessage(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
err := can.Tx(0x111, 8, []byte{0x00, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA})
|
||||||
|
if err != nil {
|
||||||
|
failMessage(err.Error())
|
||||||
|
}
|
||||||
|
if can.Received() {
|
||||||
|
msg, err := can.Rx()
|
||||||
|
if err != nil {
|
||||||
|
failMessage(err.Error())
|
||||||
|
}
|
||||||
|
fmt.Printf("CAN-ID: %03X dlc: %d data: ", msg.ID, msg.Dlc)
|
||||||
|
for _, b := range msg.Data {
|
||||||
|
fmt.Printf("%02X ", b)
|
||||||
|
}
|
||||||
|
fmt.Print("\r\n")
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func failMessage(msg string) {
|
||||||
|
for {
|
||||||
|
println(msg)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,786 @@
|
|||||||
|
// Package mcp2515 implements a driver for the MCP2515 CAN Controller.
|
||||||
|
//
|
||||||
|
// Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/MCP2515-Stand-Alone-CAN-Controller-with-SPI-20001801J.pdf
|
||||||
|
//
|
||||||
|
// Reference: https://github.com/coryjfowler/MCP_CAN_lib
|
||||||
|
package mcp2515 // import "tinygo.org/x/drivers/mcp2515"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Device wraps MCP2515 SPI CAN Module.
|
||||||
|
type Device struct {
|
||||||
|
spi SPI
|
||||||
|
cs machine.Pin
|
||||||
|
msg *CANMsg
|
||||||
|
mcpMode byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// CANMsg stores CAN message fields.
|
||||||
|
type CANMsg struct {
|
||||||
|
ID uint32
|
||||||
|
Dlc uint8
|
||||||
|
Data []byte
|
||||||
|
Ext bool
|
||||||
|
Rtr bool
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
bufferSize int = 64
|
||||||
|
)
|
||||||
|
|
||||||
|
// New returns a new MCP2515 driver. Pass in a fully configured SPI bus.
|
||||||
|
func New(b drivers.SPI, csPin machine.Pin) *Device {
|
||||||
|
d := &Device{
|
||||||
|
spi: SPI{
|
||||||
|
bus: b,
|
||||||
|
tx: make([]byte, 0, bufferSize),
|
||||||
|
rx: make([]byte, 0, bufferSize),
|
||||||
|
},
|
||||||
|
cs: csPin,
|
||||||
|
msg: &CANMsg{},
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure sets up the device for communication.
|
||||||
|
func (d *Device) Configure() {
|
||||||
|
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
}
|
||||||
|
|
||||||
|
const beginTimeoutValue int = 10
|
||||||
|
|
||||||
|
// Begin starts the CAN controller.
|
||||||
|
func (d *Device) Begin(speed byte, clock byte) error {
|
||||||
|
timeOutCount := 0
|
||||||
|
for {
|
||||||
|
err := d.init(speed, clock)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
timeOutCount++
|
||||||
|
if timeOutCount >= beginTimeoutValue {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Received returns true if CAN message is received.
|
||||||
|
func (d *Device) Received() bool {
|
||||||
|
res, err := d.readStatus()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// if RX STATUS INSTRUCTION result is not 0x00 (= No RX message)
|
||||||
|
// TODO: reconsider this logic
|
||||||
|
return (res & mcpStatRxifMask) != 0x00
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rx returns received CAN message.
|
||||||
|
func (d *Device) Rx() (*CANMsg, error) {
|
||||||
|
err := d.readMsg()
|
||||||
|
return d.msg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tx transmits CAN Message.
|
||||||
|
func (d *Device) Tx(canid uint32, dlc uint8, data []byte) error {
|
||||||
|
// TODO: add ext, rtrBit, waitSent
|
||||||
|
timeoutCount := 0
|
||||||
|
|
||||||
|
var bufNum, res uint8
|
||||||
|
var err error
|
||||||
|
res = mcpAlltxbusy
|
||||||
|
for res == mcpAlltxbusy && (timeoutCount < timeoutvalue) {
|
||||||
|
if timeoutCount > 0 {
|
||||||
|
time.Sleep(time.Microsecond * 10)
|
||||||
|
}
|
||||||
|
bufNum, res, err = d.getNextFreeTxBuf()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
timeoutCount++
|
||||||
|
}
|
||||||
|
if timeoutCount == timeoutvalue {
|
||||||
|
return fmt.Errorf("Tx: Tx timeout")
|
||||||
|
}
|
||||||
|
err = d.writeCANMsg(bufNum, canid, 0, 0, dlc, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) init(speed, clock byte) error {
|
||||||
|
err := d.Reset()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.setCANCTRLMode(modeConfig); err != nil {
|
||||||
|
return fmt.Errorf("setCANCTRLMode %s: ", err)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
|
||||||
|
// set baudrate
|
||||||
|
if err := d.configRate(speed, clock); err != nil {
|
||||||
|
return fmt.Errorf("configRate %s: ", err)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
|
||||||
|
if err := d.initCANBuffers(); err != nil {
|
||||||
|
return fmt.Errorf("initCANBuffers: %s ", err)
|
||||||
|
}
|
||||||
|
if err := d.setRegister(mcpCANINTE, mcpRX0IF|mcpRX1IF); err != nil {
|
||||||
|
return fmt.Errorf("setRegister: %s ", err)
|
||||||
|
}
|
||||||
|
if err := d.modifyRegister(mcpRXB0CTRL, mcpRxbRxMask|mcpRxbBuktMask, mcpRxbRxStdExt|mcpRxbBuktMask); err != nil {
|
||||||
|
return fmt.Errorf("modifyRegister: %s ", err)
|
||||||
|
}
|
||||||
|
if err := d.modifyRegister(mcpRXB1CTRL, mcpRxbRxMask, mcpRxbRxStdExt); err != nil {
|
||||||
|
return fmt.Errorf("modifyRegister: %s ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.setMode(modeNormal); err != nil {
|
||||||
|
return fmt.Errorf("setMode %s: ", err)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset resets mcp2515.
|
||||||
|
func (d *Device) Reset() error {
|
||||||
|
d.cs.Low()
|
||||||
|
_, err := d.spi.readWrite(mcpReset)
|
||||||
|
d.cs.High()
|
||||||
|
// time.Sleep(time.Microsecond * 4)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) setCANCTRLMode(newMode byte) error {
|
||||||
|
// If the chip is asleep and we want to change mode then a manual wake needs to be done
|
||||||
|
// This is done by setting the wake up interrupt flag
|
||||||
|
// This undocumented trick was found at https://github.com/mkleemann/can/blob/master/can_sleep_mcp2515.c
|
||||||
|
m, err := d.getMode()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if m == modeSleep && newMode != modeSleep {
|
||||||
|
r, err := d.readRegister(mcpCANINTE)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
wakeIntEnabled := (r & mcpWAKIF) == 0x00
|
||||||
|
if !wakeIntEnabled {
|
||||||
|
d.modifyRegister(mcpCANINTE, mcpWAKIF, mcpWAKIF)
|
||||||
|
}
|
||||||
|
// Set wake flag (this does the actual waking up)
|
||||||
|
d.modifyRegister(mcpCANINTF, mcpWAKIF, mcpWAKIF)
|
||||||
|
|
||||||
|
// Wait for the chip to exit SLEEP and enter LISTENONLY mode.
|
||||||
|
|
||||||
|
// If the chip is not connected to a CAN bus (or the bus has no other powered nodes) it will sometimes trigger the wake interrupt as soon
|
||||||
|
// as it's put to sleep, but it will stay in SLEEP mode instead of automatically switching to LISTENONLY mode.
|
||||||
|
// In this situation the mode needs to be manually set to LISTENONLY.
|
||||||
|
|
||||||
|
if err := d.requestNewMode(modeListenOnly); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn wake interrupt back off if it was originally off
|
||||||
|
if !wakeIntEnabled {
|
||||||
|
d.modifyRegister(mcpCANINTE, mcpWAKIF, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear wake flag
|
||||||
|
d.modifyRegister(mcpCANINTF, mcpWAKIF, 0)
|
||||||
|
|
||||||
|
return d.requestNewMode(newMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) setMode(opMode byte) error {
|
||||||
|
if opMode != modeSleep {
|
||||||
|
d.mcpMode = opMode
|
||||||
|
}
|
||||||
|
|
||||||
|
err := d.setCANCTRLMode(opMode)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) getMode() (byte, error) {
|
||||||
|
r, err := d.readRegister(mcpCANSTAT)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return r & modeMask, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) configRate(speed, clock byte) error {
|
||||||
|
// TODO: add another baudrate
|
||||||
|
var cfg1, cfg2, cfg3 byte
|
||||||
|
set := true
|
||||||
|
switch clock {
|
||||||
|
case Clock16MHz:
|
||||||
|
switch speed {
|
||||||
|
case CAN500kBps:
|
||||||
|
cfg1 = mcp16mHz500kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz500kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz500kBpsCfg3
|
||||||
|
case CAN1000kBps:
|
||||||
|
cfg1 = mcp16mHz1000kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz1000kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz1000kBpsCfg3
|
||||||
|
default:
|
||||||
|
set = false
|
||||||
|
}
|
||||||
|
case Clock8MHz:
|
||||||
|
switch speed {
|
||||||
|
case CAN500kBps:
|
||||||
|
cfg1 = mcp8mHz500kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz500kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz500kBpsCfg3
|
||||||
|
case CAN1000kBps:
|
||||||
|
cfg1 = mcp8mHz1000kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz1000kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz1000kBpsCfg3
|
||||||
|
default:
|
||||||
|
set = false
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
set = false
|
||||||
|
}
|
||||||
|
if !set {
|
||||||
|
return errors.New("invalid parameter")
|
||||||
|
}
|
||||||
|
if err := d.setRegister(mcpCNF1, cfg1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.setRegister(mcpCNF2, cfg2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.setRegister(mcpCNF3, cfg3); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) initCANBuffers() error {
|
||||||
|
a1 := byte(mcpTXB0CTRL)
|
||||||
|
a2 := byte(mcpTXB1CTRL)
|
||||||
|
a3 := byte(mcpTXB2CTRL)
|
||||||
|
for i := 0; i < 14; i++ {
|
||||||
|
if err := d.setRegister(a1, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.setRegister(a2, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.setRegister(a3, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a1++
|
||||||
|
a2++
|
||||||
|
a3++
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.setRegister(mcpRXB0CTRL, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.setRegister(mcpRXB1CTRL, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) readMsg() error {
|
||||||
|
status, err := d.readRxTxStatus()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if (status & mcpRX0IF) == 0x01 {
|
||||||
|
err := d.readRxBuffer(mcpReadRx0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if (status & mcpRX1IF) == 0x02 {
|
||||||
|
err := d.readRxBuffer(mcpReadRx1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("readMsg: nothing is received")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) readRxBuffer(loadAddr uint8) error {
|
||||||
|
msg := d.msg
|
||||||
|
d.cs.Low()
|
||||||
|
defer d.cs.High()
|
||||||
|
_, err := d.spi.readWrite(loadAddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = d.spi.read(4)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buf := d.spi.rx
|
||||||
|
msg.ID = uint32((uint32(buf[0]) << 3) + (uint32(buf[1]) >> 5))
|
||||||
|
msg.Ext = false
|
||||||
|
if (buf[1] & mcpTxbExideM) == mcpTxbExideM {
|
||||||
|
// extended id
|
||||||
|
msg.ID = uint32(uint32(msg.ID<<2) + uint32(buf[1]&0x03))
|
||||||
|
msg.ID = uint32(uint32(msg.ID<<8) + uint32(buf[2]))
|
||||||
|
msg.ID = uint32(uint32(msg.ID<<8) + uint32(buf[3]))
|
||||||
|
msg.Ext = true
|
||||||
|
}
|
||||||
|
err = d.spi.read(1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
msgSize := d.spi.rx[0]
|
||||||
|
msg.Dlc = uint8(msgSize & mcpDlcMask)
|
||||||
|
msg.Rtr = false
|
||||||
|
if (msgSize & mcpRtrMask) == 0x40 {
|
||||||
|
msg.Rtr = true
|
||||||
|
}
|
||||||
|
readLen := uint8(canMaxCharInMessage)
|
||||||
|
if msg.Dlc < canMaxCharInMessage {
|
||||||
|
readLen = msg.Dlc
|
||||||
|
}
|
||||||
|
err = d.spi.read(int(readLen))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
msg.Data = d.spi.rx
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) getNextFreeTxBuf() (uint8, uint8, error) {
|
||||||
|
status, err := d.readStatus()
|
||||||
|
if err != nil {
|
||||||
|
return 0, mcpAlltxbusy, err
|
||||||
|
}
|
||||||
|
status &= mcpStatTxPendingMask
|
||||||
|
|
||||||
|
bufNum := uint8(0x00)
|
||||||
|
|
||||||
|
if status == mcpStatTxPendingMask {
|
||||||
|
return 0, mcpAlltxbusy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < int(mcpNTxbuffers-nReservedTx(0)); i++ {
|
||||||
|
if (status & txStatusPendingFlag(uint8(i))) == 0 {
|
||||||
|
bufNum = txCtrlReg(uint8(i)) + 1
|
||||||
|
d.modifyRegister(mcpCANINTF, txIfFlag(uint8(i)), 0)
|
||||||
|
return bufNum, mcp2515Ok, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, mcpAlltxbusy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) writeCANMsg(bufNum uint8, canid uint32, ext, rtrBit, dlc uint8, data []byte) error {
|
||||||
|
d.cs.Low()
|
||||||
|
defer d.cs.High()
|
||||||
|
_, err := d.spi.readWrite(txSidhToLoad(bufNum))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = d.spi.clearBuffer(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = d.spi.setTxBufData(canid, ext, rtrBit, dlc, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = d.spi.write()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Since cs.Low and cs.High are executed in d.startTransmission,
|
||||||
|
// it is necessary to set cs.High once to separate the instruction of mcp2515.
|
||||||
|
d.cs.High()
|
||||||
|
|
||||||
|
err = d.startTransmission(bufNum)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SPI) setTxBufData(canid uint32, ext, rtrBit, dlc uint8, data []byte) error {
|
||||||
|
canid = canid & 0x0FFFF
|
||||||
|
if ext == 1 {
|
||||||
|
// TODO: add Extended ID
|
||||||
|
err := s.setTxData(0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = s.setTxData(0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = s.setTxData(0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = s.setTxData(0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := s.setTxData(byte(canid >> 3))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = s.setTxData(byte((canid & 0x07) << 5))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = s.setTxData(0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = s.setTxData(0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rtrBit == 1 {
|
||||||
|
dlc |= mcpRtrMask
|
||||||
|
} else {
|
||||||
|
dlc |= (0)
|
||||||
|
}
|
||||||
|
err := s.setTxData(dlc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, d := range data {
|
||||||
|
err := s.setTxData(d)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) startTransmission(bufNum uint8) error {
|
||||||
|
d.cs.Low()
|
||||||
|
_, err := d.spi.readWrite(txSidhToRTS(bufNum))
|
||||||
|
d.cs.High()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func nReservedTx(number uint8) uint8 {
|
||||||
|
if number < mcpNTxbuffers {
|
||||||
|
return number
|
||||||
|
}
|
||||||
|
return mcpNTxbuffers - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func txStatusPendingFlag(i uint8) uint8 {
|
||||||
|
ret := uint8(0)
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
ret = mcpStatTx0Pending
|
||||||
|
case 1:
|
||||||
|
ret = mcpStatTx1Pending
|
||||||
|
case 2:
|
||||||
|
ret = mcpStatTx2Pending
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func txCtrlReg(status uint8) uint8 {
|
||||||
|
ret := uint8(0)
|
||||||
|
switch status {
|
||||||
|
case 0:
|
||||||
|
ret = mcpTXB0CTRL
|
||||||
|
case 1:
|
||||||
|
ret = mcpTXB1CTRL
|
||||||
|
case 2:
|
||||||
|
ret = mcpTXB2CTRL
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func txIfFlag(i uint8) uint8 {
|
||||||
|
ret := uint8(0)
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
ret = mcpTX0IF
|
||||||
|
case 1:
|
||||||
|
ret = mcpTX1IF
|
||||||
|
case 2:
|
||||||
|
ret = mcpTX2IF
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func txSidhToSidh(i uint8) uint8 {
|
||||||
|
ret := uint8(0)
|
||||||
|
switch i {
|
||||||
|
case mcpTX0IF:
|
||||||
|
ret = mcpTXB0SIDH
|
||||||
|
case mcpTX1IF:
|
||||||
|
ret = mcpTXB1SIDH
|
||||||
|
case mcpTX2IF:
|
||||||
|
ret = mcpTXB2SIDH
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func txSidhToRTS(i uint8) uint8 {
|
||||||
|
ret := uint8(0)
|
||||||
|
switch i {
|
||||||
|
case mcpTXB0SIDH:
|
||||||
|
ret = mcpRtsTx0
|
||||||
|
case mcpTXB1SIDH:
|
||||||
|
ret = mcpRtsTx1
|
||||||
|
case mcpTXB2SIDH:
|
||||||
|
ret = mcpRtsTx2
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func txSidhToLoad(i uint8) uint8 {
|
||||||
|
ret := uint8(0)
|
||||||
|
switch i {
|
||||||
|
case mcpTXB0SIDH:
|
||||||
|
ret = mcpLoadTx0
|
||||||
|
case mcpTXB1SIDH:
|
||||||
|
ret = mcpLoadTx1
|
||||||
|
case mcpTXB2SIDH:
|
||||||
|
ret = mcpLoadTx2
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) setRegister(addr, value byte) error {
|
||||||
|
d.cs.Low()
|
||||||
|
defer d.cs.High()
|
||||||
|
_, err := d.spi.readWrite(mcpWrite)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = d.spi.readWrite(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = d.spi.readWrite(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// time.Sleep(time.Microsecond * 4)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) readRegister(addr byte) (byte, error) {
|
||||||
|
d.cs.Low()
|
||||||
|
defer d.cs.High()
|
||||||
|
_, err := d.spi.readWrite(mcpRead)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
_, err = d.spi.readWrite(addr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
err = d.spi.read(1)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
// time.Sleep(time.Microsecond * 4)
|
||||||
|
return d.spi.rx[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) modifyRegister(addr, mask, data byte) error {
|
||||||
|
d.cs.Low()
|
||||||
|
defer d.cs.High()
|
||||||
|
_, err := d.spi.readWrite(mcpBitMod)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = d.spi.readWrite(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = d.spi.readWrite(mask)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = d.spi.readWrite(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// time.Sleep(time.Microsecond * 4)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) requestNewMode(newMode byte) error {
|
||||||
|
s := time.Now()
|
||||||
|
for {
|
||||||
|
err := d.modifyRegister(mcpCANCTRL, modeMask, newMode)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r, err := d.readRegister(mcpCANSTAT)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if r&modeMask == newMode {
|
||||||
|
return nil
|
||||||
|
} else if e := time.Now(); e.Sub(s) > 200*time.Millisecond {
|
||||||
|
return errors.New("requestNewMode max time expired")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) readStatus() (byte, error) {
|
||||||
|
d.cs.Low()
|
||||||
|
defer d.cs.High()
|
||||||
|
_, err := d.spi.readWrite(mcpReadStatus)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
err = d.spi.read(1)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.spi.rx[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) readRxTxStatus() (byte, error) {
|
||||||
|
status, err := d.readStatus()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
ret := status & (mcpStatTxifMask | mcpStatRxifMask)
|
||||||
|
if (status & mcpStatTx0if) == 0x08 {
|
||||||
|
ret |= mcpTX0IF
|
||||||
|
}
|
||||||
|
if (status & mcpStatTx1if) == 0x20 {
|
||||||
|
ret |= mcpTX1IF
|
||||||
|
}
|
||||||
|
if (status & mcpStatTx2if) == 0x80 {
|
||||||
|
ret |= mcpTX2IF
|
||||||
|
}
|
||||||
|
ret |= ret & mcpStatRxifMask
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SPI struct {
|
||||||
|
bus drivers.SPI
|
||||||
|
tx []byte
|
||||||
|
rx []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
tx = iota
|
||||||
|
rx
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *SPI) readWrite(w byte) (byte, error) {
|
||||||
|
return s.bus.Transfer(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SPI) read(readLength int) error {
|
||||||
|
err := s.clearBuffer(rx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = s.setBufferLength(readLength, rx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return s.bus.Tx(nil, s.rx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SPI) write() error {
|
||||||
|
return s.bus.Tx(s.tx, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SPI) clearBuffer(dir int) error { return s.setBufferLength(0, dir) }
|
||||||
|
|
||||||
|
func (s *SPI) setBufferLength(length int, dir int) error {
|
||||||
|
if dir == tx {
|
||||||
|
if length > cap(s.tx) {
|
||||||
|
return fmt.Errorf("length is longer than capacity")
|
||||||
|
}
|
||||||
|
s.tx = s.tx[:length]
|
||||||
|
} else if dir == rx {
|
||||||
|
if length > cap(s.rx) {
|
||||||
|
return fmt.Errorf("length is longer than capacity")
|
||||||
|
}
|
||||||
|
s.rx = s.rx[:length]
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("invalid direction")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SPI) setTxData(data byte) error {
|
||||||
|
if len(s.tx) >= bufferSize {
|
||||||
|
return fmt.Errorf("cannot expand buffer (to avoid memory allocation)")
|
||||||
|
}
|
||||||
|
s.tx = append(s.tx, data)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) dumpMode() error {
|
||||||
|
m, err := d.getMode()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("Mode: %02X\r\n", m)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) dumpRegister(addr byte) error {
|
||||||
|
r, err := d.readRegister(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("Register: %02X = %02X\r\n", addr, r)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,421 @@
|
|||||||
|
// Package mcp2515 implements a driver for the MCP2515 CAN Controller.
|
||||||
|
//
|
||||||
|
// Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/MCP2515-Stand-Alone-CAN-Controller-with-SPI-20001801J.pdf
|
||||||
|
//
|
||||||
|
package mcp2515 // import "tinygo.org/x/drivers/mcp2515"
|
||||||
|
|
||||||
|
const DebugEn = 0
|
||||||
|
|
||||||
|
const (
|
||||||
|
// begin mt
|
||||||
|
|
||||||
|
timeoutvalue = 50
|
||||||
|
mcpSidh = 0
|
||||||
|
mcpSidl = 1
|
||||||
|
mcpEid8 = 2
|
||||||
|
mcpEid0 = 3
|
||||||
|
|
||||||
|
mcpTxbExideM = 0x08 // in txbnsidl
|
||||||
|
mcpDlcMask = 0x0f //= 4 lsbits
|
||||||
|
mcpRtrMask = 0x40 // =(1<=<6) bit= 6
|
||||||
|
|
||||||
|
mcpRxbRxAny = 0x60
|
||||||
|
mcpRxbRxExt = 0x40
|
||||||
|
mcpRxbRxStd = 0x20
|
||||||
|
mcpRxbRxStdExt = 0x00
|
||||||
|
mcpRxbRxMask = 0x60
|
||||||
|
mcpRxbBuktMask = 1 << 2
|
||||||
|
|
||||||
|
// bits in the txbnctrl registers.
|
||||||
|
|
||||||
|
mcpTxbTxbufeM = 0x80
|
||||||
|
mcpTxbAbtfM = 0x40
|
||||||
|
mcpTxbMloaM = 0x20
|
||||||
|
mcpTxbTxerrM = 0x10
|
||||||
|
mcpTxbTxreqM = 0x08
|
||||||
|
mcpTxbTxieM = 0x04
|
||||||
|
mcpTxbTxp10M = 0x03
|
||||||
|
|
||||||
|
mcpTxbRtrM = 0x40 // in txbndlc
|
||||||
|
mcpRxbIdeM = 0x08 // in rxbnsidl
|
||||||
|
mcpRxbRtrM = 0x40 // in rxbndlc
|
||||||
|
|
||||||
|
mcpStatTxPendingMask = 0x54
|
||||||
|
mcpStatTx0Pending = 0x04
|
||||||
|
mcpStatTx1Pending = 0x10
|
||||||
|
mcpStatTx2Pending = 0x40
|
||||||
|
mcpStatTxifMask = 0xa8
|
||||||
|
mcpStatTx0if = 0x08
|
||||||
|
mcpStatTx1if = 0x20
|
||||||
|
mcpStatTx2if = 0x80
|
||||||
|
mcpStatRxifMask = 0x03
|
||||||
|
mcpStatRx0if = 1 << 0
|
||||||
|
mcpStatRx1if = 1 << 1
|
||||||
|
|
||||||
|
mcpEflgRx1ovr = 1 << 7
|
||||||
|
mcpEflgRx0ovr = 1 << 6
|
||||||
|
mcpEflgTxbo = 1 << 5
|
||||||
|
mcpEflgTxep = 1 << 4
|
||||||
|
mcpEflgRxep = 1 << 3
|
||||||
|
mcpEflgTxwar = 1 << 2
|
||||||
|
mcpEflgRxwar = 1 << 1
|
||||||
|
mcpEflgEwarn = 1 << 0
|
||||||
|
mcpEflgErrormask = 0xf8 //= 5 ms-bits
|
||||||
|
|
||||||
|
// define mcp2515 register addresses
|
||||||
|
|
||||||
|
mcpRXF0SIDH = 0x00
|
||||||
|
mcpRXF0SIDL = 0x01
|
||||||
|
mcpRXF0EID8 = 0x02
|
||||||
|
mcpRXF0EID0 = 0x03
|
||||||
|
mcpRXF1SIDH = 0x04
|
||||||
|
mcpRXF1SIDL = 0x05
|
||||||
|
mcpRXF1EID8 = 0x06
|
||||||
|
mcpRXF1EID0 = 0x07
|
||||||
|
mcpRXF2SIDH = 0x08
|
||||||
|
mcpRXF2SIDL = 0x09
|
||||||
|
mcpRXF2EID8 = 0x0a
|
||||||
|
mcpRXF2EID0 = 0x0b
|
||||||
|
mcpBFPCTRL = 0x0c
|
||||||
|
mcpTXRTSCTRl = 0x0d
|
||||||
|
mcpCANSTAT = 0x0e
|
||||||
|
mcpCANCTRL = 0x0f
|
||||||
|
mcpRXF3SIDH = 0x10
|
||||||
|
mcpRXF3SIDL = 0x11
|
||||||
|
mcpRXF3EID8 = 0x12
|
||||||
|
mcpRXF3EID0 = 0x13
|
||||||
|
mcpRXF4SIDH = 0x14
|
||||||
|
mcpRXF4SIDL = 0x15
|
||||||
|
mcpRXF4EID8 = 0x16
|
||||||
|
mcpRXF4EID0 = 0x17
|
||||||
|
mcpRXF5SIDH = 0x18
|
||||||
|
mcpRXF5SIDL = 0x19
|
||||||
|
mcpRXF5EID8 = 0x1a
|
||||||
|
mcpRXF5EID0 = 0x1b
|
||||||
|
mcpTEC = 0x1c
|
||||||
|
mcpREC = 0x1d
|
||||||
|
mcpRXM0SIDH = 0x20
|
||||||
|
mcpRXM0SIDL = 0x21
|
||||||
|
mcpRXM0EID8 = 0x22
|
||||||
|
mcpRXM0EID0 = 0x23
|
||||||
|
mcpRXM1SIDH = 0x24
|
||||||
|
mcpRXM1SIDL = 0x25
|
||||||
|
mcpRXM1EID8 = 0x26
|
||||||
|
mcpRXM1EID0 = 0x27
|
||||||
|
mcpCNF3 = 0x28
|
||||||
|
mcpCNF2 = 0x29
|
||||||
|
mcpCNF1 = 0x2a
|
||||||
|
mcpCANINTE = 0x2b
|
||||||
|
mcpCANINTF = 0x2c
|
||||||
|
mcpEFLG = 0x2d
|
||||||
|
mcpTXB0CTRL = 0x30
|
||||||
|
mcpTXB0SIDH = 0x31
|
||||||
|
mcpTXB1CTRL = 0x40
|
||||||
|
mcpTXB1SIDH = 0x41
|
||||||
|
mcpTXB2CTRL = 0x50
|
||||||
|
mcpTXB2SIDH = 0x51
|
||||||
|
mcpRXB0CTRL = 0x60
|
||||||
|
mcpRXB0SIDH = 0x61
|
||||||
|
mcpRXB1CTRL = 0x70
|
||||||
|
mcpRXB1SIDH = 0x71
|
||||||
|
|
||||||
|
mcpTxInt = 0x1c // enable all transmit interrup ts
|
||||||
|
mcpTx01Int = 0x0c // enable txb0 and txb1 interru pts
|
||||||
|
mcpRxInt = 0x03 // enable receive interrupts
|
||||||
|
mcpNoInt = 0x00 // disable all interrupts
|
||||||
|
|
||||||
|
mcpTx01Mask = 0x14
|
||||||
|
mcpTxMask = 0x54
|
||||||
|
|
||||||
|
// define spi instruction set
|
||||||
|
mcpWrite = 0x02
|
||||||
|
mcpRead = 0x03
|
||||||
|
mcpBitMod = 0x05
|
||||||
|
mcpLoadTx0 = 0x40
|
||||||
|
mcpLoadTx1 = 0x42
|
||||||
|
mcpLoadTx2 = 0x44
|
||||||
|
|
||||||
|
mcpRtsTx0 = 0x81
|
||||||
|
mcpRtsTx1 = 0x82
|
||||||
|
mcpRtsTx2 = 0x84
|
||||||
|
mcpRtsAll = 0x87
|
||||||
|
mcpReadRx0 = 0x90
|
||||||
|
mcpReadRx1 = 0x94
|
||||||
|
mcpReadStatus = 0xa0
|
||||||
|
mcpRxStatus = 0xb0
|
||||||
|
mcpReset = 0xc0
|
||||||
|
|
||||||
|
// canctrl register values
|
||||||
|
|
||||||
|
modeNormal = 0x00
|
||||||
|
modeSleep = 0x20
|
||||||
|
modeLoopBack = 0x40
|
||||||
|
modeListenOnly = 0x60
|
||||||
|
modeConfig = 0x80
|
||||||
|
modePowerUp = 0xe0
|
||||||
|
modeMask = 0xe0
|
||||||
|
abortTx = 0x10
|
||||||
|
modeOneShot = 0x08
|
||||||
|
clkoutEnable = 0x04
|
||||||
|
clkoutDisable = 0x00
|
||||||
|
clkoutPs1 = 0x00
|
||||||
|
clkoutPs2 = 0x01
|
||||||
|
clkoutPs4 = 0x02
|
||||||
|
clkoutPs8 = 0x03
|
||||||
|
|
||||||
|
// cnf1 register values
|
||||||
|
|
||||||
|
sjw1 = 0x00
|
||||||
|
sjw2 = 0x40
|
||||||
|
sjw3 = 0x80
|
||||||
|
sjw4 = 0xc0
|
||||||
|
|
||||||
|
// cnf2 register values
|
||||||
|
|
||||||
|
btlmode = 0x80
|
||||||
|
sample1x = 0x00
|
||||||
|
sample3x = 0x40
|
||||||
|
|
||||||
|
// cnf3 register values
|
||||||
|
|
||||||
|
sofEnable = 0x80
|
||||||
|
sofDisable = 0x00
|
||||||
|
wakfilEnable = 0x40
|
||||||
|
wakfilDisable = 0x00
|
||||||
|
|
||||||
|
// canintf register bits
|
||||||
|
|
||||||
|
mcpRX0IF = 0x01
|
||||||
|
mcpRX1IF = 0x02
|
||||||
|
mcpTX0IF = 0x04
|
||||||
|
mcpTX1IF = 0x08
|
||||||
|
mcpTX2IF = 0x10
|
||||||
|
mcpERRIF = 0x20
|
||||||
|
mcpWAKIF = 0x40
|
||||||
|
mcpMERRF = 0x80
|
||||||
|
|
||||||
|
// bfpctrl register bits
|
||||||
|
|
||||||
|
b1bfs = 0x20
|
||||||
|
b0bfs = 0x10
|
||||||
|
b1bfe = 0x08
|
||||||
|
b0bfe = 0x04
|
||||||
|
b1bfm = 0x02
|
||||||
|
b0bfm = 0x01
|
||||||
|
|
||||||
|
// txrtctrl register bits
|
||||||
|
|
||||||
|
b2rts = 0x20
|
||||||
|
b1rts = 0x10
|
||||||
|
b0rts = 0x08
|
||||||
|
b2rtsm = 0x04
|
||||||
|
b1rtsm = 0x02
|
||||||
|
b0rtsm = 0x01
|
||||||
|
|
||||||
|
// clock
|
||||||
|
|
||||||
|
Clock16MHz = 1
|
||||||
|
Clock8MHz = 2
|
||||||
|
|
||||||
|
// speed= 16m
|
||||||
|
|
||||||
|
mcp16mHz1000kBpsCfg1 = 0x00
|
||||||
|
mcp16mHz1000kBpsCfg2 = 0xd0
|
||||||
|
mcp16mHz1000kBpsCfg3 = 0x82
|
||||||
|
|
||||||
|
mcp16mHz500kBpsCfg1 = 0x00
|
||||||
|
mcp16mHz500kBpsCfg2 = 0xf0
|
||||||
|
mcp16mHz500kBpsCfg3 = 0x86
|
||||||
|
|
||||||
|
mcp16mHz250kBpsCfg1 = 0x41
|
||||||
|
mcp16mHz250kBpsCfg2 = 0xf1
|
||||||
|
mcp16mHz250kBpsCfg3 = 0x85
|
||||||
|
|
||||||
|
mcp16mHz200kBpsCfg1 = 0x01
|
||||||
|
mcp16mHz200kBpsCfg2 = 0xfa
|
||||||
|
mcp16mHz200kBpsCfg3 = 0x87
|
||||||
|
|
||||||
|
mcp16mHz125kBpsCfg1 = 0x03
|
||||||
|
mcp16mHz125kBpsCfg2 = 0xf0
|
||||||
|
mcp16mHz125kBpsCfg3 = 0x86
|
||||||
|
|
||||||
|
mcp16mHz100kBpsCfg1 = 0x03
|
||||||
|
mcp16mHz100kBpsCfg2 = 0xfa
|
||||||
|
mcp16mHz100kBpsCfg3 = 0x87
|
||||||
|
|
||||||
|
mcp16mHz95kBpsCfg1 = 0x03
|
||||||
|
mcp16mHz95kBpsCfg2 = 0xad
|
||||||
|
mcp16mHz95kBpsCfg3 = 0x07
|
||||||
|
|
||||||
|
mcp16mHz83k3BpsCfg1 = 0x03
|
||||||
|
mcp16mHz83k3BpsCfg2 = 0xbe
|
||||||
|
mcp16mHz83k3BpsCfg3 = 0x07
|
||||||
|
|
||||||
|
mcp16mHz80kBpsCfg1 = 0x03
|
||||||
|
mcp16mHz80kBpsCfg2 = 0xff
|
||||||
|
mcp16mHz80kBpsCfg3 = 0x87
|
||||||
|
|
||||||
|
mcp16mHz50kBpsCfg1 = 0x07
|
||||||
|
mcp16mHz50kBpsCfg2 = 0xfa
|
||||||
|
mcp16mHz50kBpsCfg3 = 0x87
|
||||||
|
|
||||||
|
mcp16mHz40kBpsCfg1 = 0x07
|
||||||
|
mcp16mHz40kBpsCfg2 = 0xff
|
||||||
|
mcp16mHz40kBpsCfg3 = 0x87
|
||||||
|
|
||||||
|
mcp16mHz33kBpsCfg1 = 0x09
|
||||||
|
mcp16mHz33kBpsCfg2 = 0xbe
|
||||||
|
mcp16mHz33kBpsCfg3 = 0x07
|
||||||
|
|
||||||
|
mcp16mHz31k25BpsCfg1 = 0x0f
|
||||||
|
mcp16mHz31k25BpsCfg2 = 0xf1
|
||||||
|
mcp16mHz31k25BpsCfg3 = 0x85
|
||||||
|
|
||||||
|
mcp16mHz25kBpsCfg1 = 0x0f
|
||||||
|
mcp16mHz25kBpsCfg2 = 0xba
|
||||||
|
mcp16mHz25kBpsCfg3 = 0x07
|
||||||
|
|
||||||
|
mcp16mHz20kBpsCfg1 = 0x0f
|
||||||
|
mcp16mHz20kBpsCfg2 = 0xff
|
||||||
|
mcp16mHz20kBpsCfg3 = 0x87
|
||||||
|
|
||||||
|
mcp16mHz10kBpsCfg1 = 0x1f
|
||||||
|
mcp16mHz10kBpsCfg2 = 0xff
|
||||||
|
mcp16mHz10kBpsCfg3 = 0x87
|
||||||
|
|
||||||
|
mcp16mHz5kBpsCfg1 = 0x3f
|
||||||
|
mcp16mHz5kBpsCfg2 = 0xff
|
||||||
|
mcp16mHz5kBpsCfg3 = 0x87
|
||||||
|
|
||||||
|
mcp16mHz666kBpsCfg1 = 0x00
|
||||||
|
mcp16mHz666kBpsCfg2 = 0xa0
|
||||||
|
mcp16mHz666kBpsCfg3 = 0x04
|
||||||
|
|
||||||
|
// speed= 8m
|
||||||
|
|
||||||
|
mcp8mHz1000kBpsCfg1 = 0x00
|
||||||
|
mcp8mHz1000kBpsCfg2 = 0x80
|
||||||
|
mcp8mHz1000kBpsCfg3 = 0x00
|
||||||
|
|
||||||
|
mcp8mHz500kBpsCfg1 = 0x00
|
||||||
|
mcp8mHz500kBpsCfg2 = 0x90
|
||||||
|
mcp8mHz500kBpsCfg3 = 0x02
|
||||||
|
|
||||||
|
mcp8mHz250kBpsCfg1 = 0x00
|
||||||
|
mcp8mHz250kBpsCfg2 = 0xb1
|
||||||
|
mcp8mHz250kBpsCfg3 = 0x05
|
||||||
|
|
||||||
|
mcp8mHz200kBpsCfg1 = 0x00
|
||||||
|
mcp8mHz200kBpsCfg2 = 0xb4
|
||||||
|
mcp8mHz200kBpsCfg3 = 0x06
|
||||||
|
|
||||||
|
mcp8mHz125kBpsCfg1 = 0x01
|
||||||
|
mcp8mHz125kBpsCfg2 = 0xb1
|
||||||
|
mcp8mHz125kBpsCfg3 = 0x05
|
||||||
|
|
||||||
|
mcp8mHz100kBpsCfg1 = 0x01
|
||||||
|
mcp8mHz100kBpsCfg2 = 0xb4
|
||||||
|
mcp8mHz100kBpsCfg3 = 0x06
|
||||||
|
|
||||||
|
mcp8mHz80kBpsCfg1 = 0x01
|
||||||
|
mcp8mHz80kBpsCfg2 = 0xbf
|
||||||
|
mcp8mHz80kBpsCfg3 = 0x07
|
||||||
|
|
||||||
|
mcp8mHz50kBpsCfg1 = 0x03
|
||||||
|
mcp8mHz50kBpsCfg2 = 0xb4
|
||||||
|
mcp8mHz50kBpsCfg3 = 0x06
|
||||||
|
|
||||||
|
mcp8mHz40kBpsCfg1 = 0x03
|
||||||
|
mcp8mHz40kBpsCfg2 = 0xbf
|
||||||
|
mcp8mHz40kBpsCfg3 = 0x07
|
||||||
|
|
||||||
|
mcp8mHz31k25BpsCfg1 = 0x07
|
||||||
|
mcp8mHz31k25BpsCfg2 = 0xa4
|
||||||
|
mcp8mHz31k25BpsCfg3 = 0x04
|
||||||
|
|
||||||
|
mcp8mHz20kBpsCfg1 = 0x07
|
||||||
|
mcp8mHz20kBpsCfg2 = 0xbf
|
||||||
|
mcp8mHz20kBpsCfg3 = 0x07
|
||||||
|
|
||||||
|
mcp8mHz10kBpsCfg1 = 0x0f
|
||||||
|
mcp8mHz10kBpsCfg2 = 0xbf
|
||||||
|
mcp8mHz10kBpsCfg3 = 0x07
|
||||||
|
|
||||||
|
mcp8mHz5kBpsCfg1 = 0x1f
|
||||||
|
mcp8mHz5kBpsCfg2 = 0xbf
|
||||||
|
mcp8mHz5kBpsCfg3 = 0x07
|
||||||
|
|
||||||
|
mcp16mHz47kBpsCfg1 = 0x06
|
||||||
|
mcp16mHz47kBpsCfg2 = 0xbe
|
||||||
|
mcp16mHz47kBpsCfg3 = 0x07
|
||||||
|
|
||||||
|
mcpdebug = 0
|
||||||
|
mcpdebugTxbuf = 0
|
||||||
|
mcpNTxbuffers = 3
|
||||||
|
|
||||||
|
mcpRxbuf0 = 0x61
|
||||||
|
mcpRxbuf1 = 0x71
|
||||||
|
|
||||||
|
mcp2515Ok = 0
|
||||||
|
mcp2515Fail = 1
|
||||||
|
mcpAlltxbusy = 2
|
||||||
|
|
||||||
|
candebug = 1
|
||||||
|
|
||||||
|
canuseloop = 0
|
||||||
|
|
||||||
|
cansendtimeout = 200 // milliseconds
|
||||||
|
|
||||||
|
mcpPinHiz = 0
|
||||||
|
mcpPinInt = 1
|
||||||
|
mcpPinOut = 2
|
||||||
|
mcpPinIn = 3
|
||||||
|
|
||||||
|
mcpRx0bf = 0
|
||||||
|
mcpRx1bf = 1
|
||||||
|
mcpTx0rts = 2
|
||||||
|
mcpTx1rts = 3
|
||||||
|
mcpTx2rts = 4
|
||||||
|
|
||||||
|
// initial value of gcanautoprocess
|
||||||
|
|
||||||
|
canautoprocess = 1
|
||||||
|
canautoon = 1
|
||||||
|
canautooff = 0
|
||||||
|
canStdid = 0
|
||||||
|
canExtid = 1
|
||||||
|
candefaultident = 0x55cc
|
||||||
|
candefaultidentext = 1
|
||||||
|
|
||||||
|
CAN5kBps = 1
|
||||||
|
CAN10kBps = 2
|
||||||
|
CAN20kBps = 3
|
||||||
|
CAN25kBps = 4
|
||||||
|
CAN31k25Bps = 5
|
||||||
|
CAN33kBps = 6
|
||||||
|
CAN40kBps = 7
|
||||||
|
CAN50kBps = 8
|
||||||
|
CAN80kBps = 9
|
||||||
|
CAN83k3Bps = 10
|
||||||
|
CAN95kBps = 11
|
||||||
|
CAN100kBps = 12
|
||||||
|
CAN125kBps = 13
|
||||||
|
CAN200kBps = 14
|
||||||
|
CAN250kBps = 15
|
||||||
|
CAN500kBps = 16
|
||||||
|
CAN666kBps = 17
|
||||||
|
CAN1000kBps = 18
|
||||||
|
CAN47kBps = 19
|
||||||
|
|
||||||
|
canOk = 0
|
||||||
|
canFailinit = 1
|
||||||
|
canFailtx = 2
|
||||||
|
canMsgavail = 3
|
||||||
|
canNomsg = 4
|
||||||
|
canCtrlerror = 5
|
||||||
|
canGettxbftimeout = 6
|
||||||
|
canSendmsgtimeout = 7
|
||||||
|
canFail = 0xff
|
||||||
|
|
||||||
|
canMaxCharInMessage = 8
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user