Rework program and try another lib
This commit is contained in:
parent
a54a5ca2d5
commit
36274df86b
17 changed files with 2336 additions and 6 deletions
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 @ Longan Labs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2018 Longan Labs Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
143
Easylink_CAN_Waker/lib/Arduino_CAN_BUS_MCP2515-master/README.md
Normal file
143
Easylink_CAN_Waker/lib/Arduino_CAN_BUS_MCP2515-master/README.md
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
# CAN Bus Library
|
||||||
|
[![GitHub](https://img.shields.io/github/license/Longan-Labs/Arduino_CAN_BUS_MCP2515)](https://github.com/Longan-Labs/Arduino_CAN_BUS_MCP2515/blob/master/LICENSE)
|
||||||
|
[![Installation instructions](https://www.ardu-badge.com/badge/mcp_canbus.svg?)](https://www.ardu-badge.com/mcp_canbus)
|
||||||
|
[![GitHub version](https://img.shields.io/github/release/Longan-Labs/Arduino_CAN_BUS_MCP2515.svg?logo=github&logoColor=ffffff)](https://github.com/Longan-Labs/Arduino_CAN_BUS_MCP2515/releases/latest)
|
||||||
|
[![GitHub Release Date](https://img.shields.io/github/release-date/Longan-Labs/Arduino_CAN_BUS_MCP2515.svg?logo=github&logoColor=ffffff)](https://github.com/Longan-Labs/Arduino_CAN_BUS_MCP2515/releases/latest)
|
||||||
|
[![GitHub Repo stars](https://img.shields.io/github/stars/Longan-Labs/Arduino_CAN_BUS_MCP2515?logo=github&logoColor=ffffff)](https://github.com/Longan-Labs/Arduino_CAN_BUS_MCP2515/stargazers)
|
||||||
|
[![GitHub issues](https://img.shields.io/github/issues/Longan-Labs/Arduino_CAN_BUS_MCP2515.svg?logo=github&logoColor=ffffff)](https://github.com/Longan-Labs/Arduino_CAN_BUS_MCP2515/issues)
|
||||||
|
|
||||||
|
Arduino library for MCP2515, it's available for most of theArduino boards, we test it with Arduino UNO, Leonardo, Mega as well as Zero.
|
||||||
|
|
||||||
|
With this library, you can,
|
||||||
|
|
||||||
|
1. Send a CAN2.0 frame
|
||||||
|
2. Receive a CAN2.0 frame
|
||||||
|
3. Get data from OBD-II
|
||||||
|
4. Set the masks and filters, there're 32 masks and filters.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
You can install it similiar to any other Arduino libraries, using the Library Manager or from a Zip file in the Arduino IDE.
|
||||||
|
|
||||||
|
- Install using the Library Manager
|
||||||
|
1. In the Arduino IDE, navigate to Sketch > Include Library > Manage Libraries...
|
||||||
|
2. Search for "mcp_canbus" to find this library
|
||||||
|
3. Click "INSTALL"
|
||||||
|
|
||||||
|
- Install from a Zip file
|
||||||
|
1. [Download this library](https://github.com/Longan-Labs/Aruino_CAN_BUS_MCP2515/archive/refs/heads/master.zip)
|
||||||
|
2. Extract the zip file
|
||||||
|
3. In the Arduino IDE, navigate to Sketch > Include Library > Add .ZIP Library
|
||||||
|
|
||||||
|
You can also read [how to install mcp_canbus library](https://www.ardu-badge.com/mcp_canbus) for a reference.
|
||||||
|
|
||||||
|
## Respository Contents
|
||||||
|
|
||||||
|
* [**/examples**](./examples) - Example sketches for the library (.ino). Run these from the Arduino IDE.
|
||||||
|
* [**/src**](./src) - Source files for the library (.cpp, .h).
|
||||||
|
* [**keywords.txt**](./keywords.txt) - Keywords from this library that will be highlighted in the Arduino IDE.
|
||||||
|
* [**library.properties**](./library.properties) - General library properties for the Arduino package manager.
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
### Header
|
||||||
|
```
|
||||||
|
#include <mcp_canbus.h>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Functions
|
||||||
|
|
||||||
|
- begin()
|
||||||
|
- init_Mask()
|
||||||
|
- init_filt()
|
||||||
|
- checkReceive()
|
||||||
|
- readMsgBufID()
|
||||||
|
- readMsgBuf()
|
||||||
|
- getCanId()
|
||||||
|
- sendMsgBuf()
|
||||||
|
- isRemoteRequest()
|
||||||
|
- isExtendedFrame()
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
here are many examples implemented in this library. One of the examples is below. You can find other examples [here](./examples)
|
||||||
|
|
||||||
|
```Cpp
|
||||||
|
/* send a frame from can bus
|
||||||
|
support@longan-labs.cc
|
||||||
|
|
||||||
|
CAN Baudrate,
|
||||||
|
|
||||||
|
#define CAN_5KBPS 1
|
||||||
|
#define CAN_10KBPS 2
|
||||||
|
#define CAN_20KBPS 3
|
||||||
|
#define CAN_25KBPS 4
|
||||||
|
#define CAN_31K25BPS 5
|
||||||
|
#define CAN_33KBPS 6
|
||||||
|
#define CAN_40KBPS 7
|
||||||
|
#define CAN_50KBPS 8
|
||||||
|
#define CAN_80KBPS 9
|
||||||
|
#define CAN_83K3BPS 10
|
||||||
|
#define CAN_95KBPS 11
|
||||||
|
#define CAN_100KBPS 12
|
||||||
|
#define CAN_125KBPS 13
|
||||||
|
#define CAN_200KBPS 14
|
||||||
|
#define CAN_250KBPS 15
|
||||||
|
#define CAN_500KBPS 16
|
||||||
|
#define CAN_666KBPS 17
|
||||||
|
#define CAN_1000KBPS 18
|
||||||
|
|
||||||
|
CANBed V1: https://www.longan-labs.cc/1030008.html
|
||||||
|
CANBed M0: https://www.longan-labs.cc/1030014.html
|
||||||
|
CAN Bus Shield: https://www.longan-labs.cc/1030016.html
|
||||||
|
OBD-II CAN Bus GPS Dev Kit: https://www.longan-labs.cc/1030003.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <mcp_canbus.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
const int SPI_CS_PIN = 17; // CANBed V1
|
||||||
|
// const int SPI_CS_PIN = 3; // CANBed M0
|
||||||
|
// const int SPI_CS_PIN = 9; // CAN Bus Shield
|
||||||
|
|
||||||
|
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
while(!Serial);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit
|
||||||
|
// pinMode(A3, OUTPUT);
|
||||||
|
// digitalWrite(A3, HIGH);
|
||||||
|
|
||||||
|
while (CAN_OK != CAN.begin(CAN_500KBPS)) // init can bus : baudrate = 500k
|
||||||
|
{
|
||||||
|
Serial.println("CAN BUS FAIL!");
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
Serial.println("CAN BUS OK!");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char stmp[8] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
CAN.sendMsgBuf(0x00, 0, 8, stmp);
|
||||||
|
delay(100); // send data per 100ms
|
||||||
|
}
|
||||||
|
|
||||||
|
// END FILE
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get a Dev Board
|
||||||
|
|
||||||
|
If you need a Dev board, plese try,
|
||||||
|
|
||||||
|
- [CAN Bus Shield for Arduino](https://www.longan-labs.cc/1030016.html)
|
||||||
|
- [CANBed V1](https://www.longan-labs.cc/1030008.html)
|
||||||
|
- [CANBed M0](https://www.longan-labs.cc/1030014.html)
|
||||||
|
- [OBD-II CAN Bus GPS Dev Kit](https://www.longan-labs.cc/1030003.html)
|
||||||
|
|
||||||
|
## Contact us
|
||||||
|
|
||||||
|
If you have any question, please feel free to contact [support@longan-labs.cc](support@longan-labs.cc)
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*************************************************************************************************
|
||||||
|
OBD-II_PIDs TEST CODE
|
||||||
|
|
||||||
|
Query
|
||||||
|
send id: 0x7df
|
||||||
|
dta: 0x02, 0x01, PID_CODE, 0, 0, 0, 0, 0
|
||||||
|
|
||||||
|
Response
|
||||||
|
From id: 0x7E9 or 0x7EA or 0x7EB
|
||||||
|
dta: len, 0x41, PID_CODE, byte0, byte1(option), byte2(option), byte3(option), byte4(option)
|
||||||
|
|
||||||
|
https://en.wikipedia.org/wiki/OBD-II_PIDs
|
||||||
|
***************************************************************************************************/
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <mcp_canbus.h>
|
||||||
|
|
||||||
|
/* Please modify SPI_CS_PIN to adapt to your board.
|
||||||
|
|
||||||
|
CANBed V1 - 17
|
||||||
|
CANBed M0 - 3
|
||||||
|
CAN Bus Shield - 9
|
||||||
|
CANBed 2040 - 9
|
||||||
|
CANBed Dual - 9
|
||||||
|
OBD-2G Dev Kit - 9
|
||||||
|
OBD-II GPS Kit - 9
|
||||||
|
Hud Dev Kit - 9
|
||||||
|
|
||||||
|
Seeed Studio CAN-Bus Breakout Board for XIAO and QT Py - D7
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SPI_CS_PIN 9
|
||||||
|
|
||||||
|
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
|
||||||
|
|
||||||
|
#define PID_ENGIN_PRM 0x0C
|
||||||
|
#define PID_VEHICLE_SPEED 0x0D
|
||||||
|
#define PID_COOLANT_TEMP 0x05
|
||||||
|
|
||||||
|
#define CAN_ID_PID 0x7DF
|
||||||
|
|
||||||
|
void set_mask_filt()
|
||||||
|
{
|
||||||
|
// set mask, set both the mask to 0x3ff
|
||||||
|
|
||||||
|
CAN.init_Mask(0, 0, 0x7FC);
|
||||||
|
CAN.init_Mask(1, 0, 0x7FC);
|
||||||
|
|
||||||
|
// set filter, we can receive id from 0x04 ~ 0x09
|
||||||
|
|
||||||
|
CAN.init_Filt(0, 0, 0x7E8);
|
||||||
|
CAN.init_Filt(1, 0, 0x7E8);
|
||||||
|
|
||||||
|
CAN.init_Filt(2, 0, 0x7E8);
|
||||||
|
CAN.init_Filt(3, 0, 0x7E8);
|
||||||
|
CAN.init_Filt(4, 0, 0x7E8);
|
||||||
|
CAN.init_Filt(5, 0, 0x7E8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendPid(unsigned char __pid) {
|
||||||
|
unsigned char tmp[8] = {0x02, 0x01, __pid, 0, 0, 0, 0, 0};
|
||||||
|
CAN.sendMsgBuf(CAN_ID_PID, 0, 8, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getRPM(int *r)
|
||||||
|
{
|
||||||
|
sendPid(PID_ENGIN_PRM);
|
||||||
|
unsigned long __timeout = millis();
|
||||||
|
|
||||||
|
while(millis()-__timeout < 1000) // 1s time out
|
||||||
|
{
|
||||||
|
unsigned char len = 0;
|
||||||
|
unsigned char buf[8];
|
||||||
|
|
||||||
|
if (CAN_MSGAVAIL == CAN.checkReceive()) { // check if get data
|
||||||
|
CAN.readMsgBuf(&len, buf); // read data, len: data length, buf: data buf
|
||||||
|
|
||||||
|
if(buf[1] == 0x41)
|
||||||
|
{
|
||||||
|
*r = (256*buf[3]+buf[4])/4;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
while(!Serial);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit Atemga32U4 version
|
||||||
|
// pinMode(A3, OUTPUT);
|
||||||
|
// digitalWrite(A3, HIGH);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit RP2040 version
|
||||||
|
// pinMode(12, OUTPUT);
|
||||||
|
// digitalWrite(12, HIGH);
|
||||||
|
|
||||||
|
while (CAN_OK != CAN.begin(CAN_500KBPS)) { // init can bus : baudrate = 500k
|
||||||
|
Serial.println("CAN init fail, retry...");
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
Serial.println("CAN init ok!");
|
||||||
|
set_mask_filt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
int __rpm = 0;
|
||||||
|
|
||||||
|
int ret = getRPM(&__rpm);
|
||||||
|
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
Serial.print("Engin Speed: ");
|
||||||
|
Serial.print(__rpm);
|
||||||
|
Serial.println(" rpm");
|
||||||
|
}else Serial.println("get Engin Speed Fail...");
|
||||||
|
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// END FILE
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*************************************************************************************************
|
||||||
|
OBD-II_PIDs TEST CODE
|
||||||
|
|
||||||
|
Query
|
||||||
|
send id: 0x7df
|
||||||
|
dta: 0x02, 0x01, PID_CODE, 0, 0, 0, 0, 0
|
||||||
|
|
||||||
|
Response
|
||||||
|
From id: 0x7E9 or 0x7EA or 0x7EB
|
||||||
|
dta: len, 0x41, PID_CODE, byte0, byte1(option), byte2(option), byte3(option), byte4(option)
|
||||||
|
|
||||||
|
https://en.wikipedia.org/wiki/OBD-II_PIDs
|
||||||
|
***************************************************************************************************/
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <mcp_canbus.h>
|
||||||
|
|
||||||
|
/* Please modify SPI_CS_PIN to adapt to your board.
|
||||||
|
|
||||||
|
CANBed V1 - 17
|
||||||
|
CANBed M0 - 3
|
||||||
|
CAN Bus Shield - 9
|
||||||
|
CANBed 2040 - 9
|
||||||
|
CANBed Dual - 9
|
||||||
|
OBD-2G Dev Kit - 9
|
||||||
|
OBD-II GPS Kit - 9
|
||||||
|
Hud Dev Kit - 9
|
||||||
|
|
||||||
|
Seeed Studio CAN-Bus Breakout Board for XIAO and QT Py - D7
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SPI_CS_PIN 9
|
||||||
|
|
||||||
|
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
|
||||||
|
|
||||||
|
#define PID_ENGIN_PRM 0x0C
|
||||||
|
#define PID_VEHICLE_SPEED 0x0D
|
||||||
|
#define PID_COOLANT_TEMP 0x05
|
||||||
|
|
||||||
|
#define CAN_ID_PID 0x7DF
|
||||||
|
|
||||||
|
void set_mask_filt()
|
||||||
|
{
|
||||||
|
// set mask, set both the mask to 0x3ff
|
||||||
|
|
||||||
|
CAN.init_Mask(0, 0, 0x7FC);
|
||||||
|
CAN.init_Mask(1, 0, 0x7FC);
|
||||||
|
|
||||||
|
// set filter, we can receive id from 0x04 ~ 0x09
|
||||||
|
|
||||||
|
CAN.init_Filt(0, 0, 0x7E8);
|
||||||
|
CAN.init_Filt(1, 0, 0x7E8);
|
||||||
|
|
||||||
|
CAN.init_Filt(2, 0, 0x7E8);
|
||||||
|
CAN.init_Filt(3, 0, 0x7E8);
|
||||||
|
CAN.init_Filt(4, 0, 0x7E8);
|
||||||
|
CAN.init_Filt(5, 0, 0x7E8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendPid(unsigned char __pid) {
|
||||||
|
unsigned char tmp[8] = {0x02, 0x01, __pid, 0, 0, 0, 0, 0};
|
||||||
|
CAN.sendMsgBuf(CAN_ID_PID, 0, 8, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getSpeed(int *s)
|
||||||
|
{
|
||||||
|
sendPid(PID_VEHICLE_SPEED);
|
||||||
|
unsigned long __timeout = millis();
|
||||||
|
|
||||||
|
while(millis()-__timeout < 1000) // 1s time out
|
||||||
|
{
|
||||||
|
unsigned char len = 0;
|
||||||
|
unsigned char buf[8];
|
||||||
|
|
||||||
|
if (CAN_MSGAVAIL == CAN.checkReceive()) { // check if get data
|
||||||
|
CAN.readMsgBuf(&len, buf); // read data, len: data length, buf: data buf
|
||||||
|
|
||||||
|
if(buf[1] == 0x41)
|
||||||
|
{
|
||||||
|
*s = buf[3];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while(!Serial);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit Atemga32U4 version
|
||||||
|
// pinMode(A3, OUTPUT);
|
||||||
|
// digitalWrite(A3, HIGH);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit RP2040 version
|
||||||
|
// pinMode(12, OUTPUT);
|
||||||
|
// digitalWrite(12, HIGH);
|
||||||
|
|
||||||
|
while (CAN_OK != CAN.begin(CAN_500KBPS)) { // init can bus : baudrate = 500k
|
||||||
|
Serial.println("CAN init fail, retry...");
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
Serial.println("CAN init ok!");
|
||||||
|
set_mask_filt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
int __speed = 0;
|
||||||
|
int ret = getSpeed(&__speed);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
Serial.print("Vehicle Speed: ");
|
||||||
|
Serial.print(__speed);
|
||||||
|
Serial.println(" kmh");
|
||||||
|
}
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// END FILE
|
|
@ -0,0 +1,99 @@
|
||||||
|
/* receive a frame from can bus
|
||||||
|
|
||||||
|
CAN Baudrate,
|
||||||
|
|
||||||
|
#define CAN_5KBPS 1
|
||||||
|
#define CAN_10KBPS 2
|
||||||
|
#define CAN_20KBPS 3
|
||||||
|
#define CAN_25KBPS 4
|
||||||
|
#define CAN_31K25BPS 5
|
||||||
|
#define CAN_33KBPS 6
|
||||||
|
#define CAN_40KBPS 7
|
||||||
|
#define CAN_50KBPS 8
|
||||||
|
#define CAN_80KBPS 9
|
||||||
|
#define CAN_83K3BPS 10
|
||||||
|
#define CAN_95KBPS 11
|
||||||
|
#define CAN_100KBPS 12
|
||||||
|
#define CAN_125KBPS 13
|
||||||
|
#define CAN_200KBPS 14
|
||||||
|
#define CAN_250KBPS 15
|
||||||
|
#define CAN_500KBPS 16
|
||||||
|
#define CAN_666KBPS 17
|
||||||
|
#define CAN_1000KBPS 18
|
||||||
|
|
||||||
|
CANBed V1: https://www.longan-labs.cc/1030008.html
|
||||||
|
CANBed M0: https://www.longan-labs.cc/1030014.html
|
||||||
|
CAN Bus Shield: https://www.longan-labs.cc/1030016.html
|
||||||
|
OBD-II CAN Bus GPS Dev Kit: https://www.longan-labs.cc/1030003.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <mcp_canbus.h>
|
||||||
|
|
||||||
|
/* Please modify SPI_CS_PIN to adapt to your board.
|
||||||
|
|
||||||
|
CANBed V1 - 17
|
||||||
|
CANBed M0 - 3
|
||||||
|
CAN Bus Shield - 9
|
||||||
|
CANBed 2040 - 9
|
||||||
|
CANBed Dual - 9
|
||||||
|
OBD-2G Dev Kit - 9
|
||||||
|
OBD-II GPS Kit - 9
|
||||||
|
Hud Dev Kit - 9
|
||||||
|
|
||||||
|
Seeed Studio CAN-Bus Breakout Board for XIAO and QT Py - D7
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define SPI_CS_PIN 9
|
||||||
|
|
||||||
|
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
|
||||||
|
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
while(!Serial);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit Atemga32U4 version
|
||||||
|
// pinMode(A3, OUTPUT);
|
||||||
|
// digitalWrite(A3, HIGH);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit RP2040 version
|
||||||
|
// pinMode(12, OUTPUT);
|
||||||
|
// digitalWrite(12, HIGH);
|
||||||
|
|
||||||
|
while (CAN_OK != CAN.begin(CAN_500KBPS)) // init can bus : baudrate = 500k
|
||||||
|
{
|
||||||
|
Serial.println("CAN BUS FAIL!");
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
Serial.println("CAN BUS OK!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
unsigned char len = 0;
|
||||||
|
unsigned char buf[8];
|
||||||
|
|
||||||
|
if(CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming
|
||||||
|
{
|
||||||
|
CAN.readMsgBuf(&len, buf); // read data, len: data length, buf: data buf
|
||||||
|
|
||||||
|
unsigned long canId = CAN.getCanId();
|
||||||
|
|
||||||
|
Serial.println("-----------------------------");
|
||||||
|
Serial.print("Get data from ID: ");
|
||||||
|
Serial.println(canId, HEX);
|
||||||
|
|
||||||
|
for(int i = 0; i<len; i++) // print the data
|
||||||
|
{
|
||||||
|
Serial.print(buf[i], HEX);
|
||||||
|
Serial.print("\t");
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// END FILE
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* send a frame from can bus
|
||||||
|
|
||||||
|
CAN Baudrate,
|
||||||
|
|
||||||
|
#define CAN_5KBPS 1
|
||||||
|
#define CAN_10KBPS 2
|
||||||
|
#define CAN_20KBPS 3
|
||||||
|
#define CAN_25KBPS 4
|
||||||
|
#define CAN_31K25BPS 5
|
||||||
|
#define CAN_33KBPS 6
|
||||||
|
#define CAN_40KBPS 7
|
||||||
|
#define CAN_50KBPS 8
|
||||||
|
#define CAN_80KBPS 9
|
||||||
|
#define CAN_83K3BPS 10
|
||||||
|
#define CAN_95KBPS 11
|
||||||
|
#define CAN_100KBPS 12
|
||||||
|
#define CAN_125KBPS 13
|
||||||
|
#define CAN_200KBPS 14
|
||||||
|
#define CAN_250KBPS 15
|
||||||
|
#define CAN_500KBPS 16
|
||||||
|
#define CAN_666KBPS 17
|
||||||
|
#define CAN_1000KBPS 18
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <mcp_canbus.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
/* Please modify SPI_CS_PIN to adapt to your board.
|
||||||
|
|
||||||
|
CANBed V1 - 17
|
||||||
|
CANBed M0 - 3
|
||||||
|
CAN Bus Shield - 9
|
||||||
|
CANBed 2040 - 9
|
||||||
|
CANBed Dual - 9
|
||||||
|
OBD-2G Dev Kit - 9
|
||||||
|
OBD-II GPS Kit - 9
|
||||||
|
Hud Dev Kit - 9
|
||||||
|
|
||||||
|
Seeed Studio CAN-Bus Breakout Board for XIAO and QT Py - D7
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SPI_CS_PIN 9
|
||||||
|
|
||||||
|
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
while(!Serial);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit Atemga32U4 version
|
||||||
|
// pinMode(A3, OUTPUT);
|
||||||
|
// digitalWrite(A3, HIGH);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit RP2040 version
|
||||||
|
// pinMode(12, OUTPUT);
|
||||||
|
// digitalWrite(12, HIGH);
|
||||||
|
|
||||||
|
while (CAN_OK != CAN.begin(CAN_500KBPS)) // init can bus : baudrate = 500k
|
||||||
|
{
|
||||||
|
Serial.println("CAN BUS FAIL!");
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
Serial.println("CAN BUS OK!");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char stmp[8] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
CAN.sendMsgBuf(0x00, 0, 8, stmp);
|
||||||
|
delay(100); // send data per 100ms
|
||||||
|
}
|
||||||
|
|
||||||
|
// END FILE
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
/* receive a frame from can bus with mask and filter setting
|
||||||
|
|
||||||
|
CAN Baudrate,
|
||||||
|
|
||||||
|
#define CAN_5KBPS 1
|
||||||
|
#define CAN_10KBPS 2
|
||||||
|
#define CAN_20KBPS 3
|
||||||
|
#define CAN_25KBPS 4
|
||||||
|
#define CAN_31K25BPS 5
|
||||||
|
#define CAN_33KBPS 6
|
||||||
|
#define CAN_40KBPS 7
|
||||||
|
#define CAN_50KBPS 8
|
||||||
|
#define CAN_80KBPS 9
|
||||||
|
#define CAN_83K3BPS 10
|
||||||
|
#define CAN_95KBPS 11
|
||||||
|
#define CAN_100KBPS 12
|
||||||
|
#define CAN_125KBPS 13
|
||||||
|
#define CAN_200KBPS 14
|
||||||
|
#define CAN_250KBPS 15
|
||||||
|
#define CAN_500KBPS 16
|
||||||
|
#define CAN_666KBPS 17
|
||||||
|
#define CAN_1000KBPS 18
|
||||||
|
|
||||||
|
CANBed V1: https://www.longan-labs.cc/1030008.html
|
||||||
|
CANBed M0: https://www.longan-labs.cc/1030014.html
|
||||||
|
CAN Bus Shield: https://www.longan-labs.cc/1030016.html
|
||||||
|
OBD-II CAN Bus GPS Dev Kit: https://www.longan-labs.cc/1030003.html
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <mcp_canbus.h>
|
||||||
|
|
||||||
|
/* Please modify SPI_CS_PIN to adapt to your board.
|
||||||
|
|
||||||
|
CANBed V1 - 17
|
||||||
|
CANBed M0 - 3
|
||||||
|
CAN Bus Shield - 9
|
||||||
|
CANBed 2040 - 9
|
||||||
|
CANBed Dual - 9
|
||||||
|
OBD-2G Dev Kit - 9
|
||||||
|
OBD-II GPS Kit - 9
|
||||||
|
Hud Dev Kit - 9
|
||||||
|
|
||||||
|
Seeed Studio CAN-Bus Breakout Board for XIAO and QT Py - D7
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SPI_CS_PIN 9
|
||||||
|
|
||||||
|
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
|
||||||
|
|
||||||
|
unsigned char flagRecv = 0;
|
||||||
|
unsigned char len = 0;
|
||||||
|
unsigned char buf[8];
|
||||||
|
char str[20];
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
while(!Serial);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit Atemga32U4 version
|
||||||
|
// pinMode(A3, OUTPUT);
|
||||||
|
// digitalWrite(A3, HIGH);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit RP2040 version
|
||||||
|
// pinMode(12, OUTPUT);
|
||||||
|
// digitalWrite(12, HIGH);
|
||||||
|
|
||||||
|
while (CAN_OK != CAN.begin(CAN_500KBPS)) // init can bus : baudrate = 500k
|
||||||
|
{
|
||||||
|
Serial.println("CAN BUS FAIL!");
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
Serial.println("CAN BUS OK!");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set mask, set both the mask to 0x3ff
|
||||||
|
*/
|
||||||
|
CAN.init_Mask(0, 0, 0x3ff); // there are 2 mask in mcp2515, you need to set both of them
|
||||||
|
CAN.init_Mask(1, 0, 0x3ff);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set filter, we can receive id from 0x04 ~ 0x09
|
||||||
|
*/
|
||||||
|
CAN.init_Filt(0, 0, 0x04); // there are 6 filter in mcp2515
|
||||||
|
CAN.init_Filt(1, 0, 0x05); // there are 6 filter in mcp2515
|
||||||
|
|
||||||
|
CAN.init_Filt(2, 0, 0x06); // there are 6 filter in mcp2515
|
||||||
|
CAN.init_Filt(3, 0, 0x07); // there are 6 filter in mcp2515
|
||||||
|
CAN.init_Filt(4, 0, 0x08); // there are 6 filter in mcp2515
|
||||||
|
CAN.init_Filt(5, 0, 0x09); // there are 6 filter in mcp2515
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
if(CAN_MSGAVAIL == CAN.checkReceive()) // check if get data
|
||||||
|
{
|
||||||
|
CAN.readMsgBuf(&len, buf); // read data, len: data length, buf: data buf
|
||||||
|
|
||||||
|
Serial.println("\r\n------------------------------------------------------------------");
|
||||||
|
Serial.print("Get Data From id: ");
|
||||||
|
Serial.println(CAN.getCanId());
|
||||||
|
for(int i = 0; i<len; i++) // print the data
|
||||||
|
{
|
||||||
|
Serial.print("0x");
|
||||||
|
Serial.print(buf[i], HEX);
|
||||||
|
Serial.print("\t");
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// END FILE
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* demo: set_mask_filter_send
|
||||||
|
this demo will show you how to use mask and filter
|
||||||
|
|
||||||
|
CAN Baudrate,
|
||||||
|
|
||||||
|
#define CAN_5KBPS 1
|
||||||
|
#define CAN_10KBPS 2
|
||||||
|
#define CAN_20KBPS 3
|
||||||
|
#define CAN_25KBPS 4
|
||||||
|
#define CAN_31K25BPS 5
|
||||||
|
#define CAN_33KBPS 6
|
||||||
|
#define CAN_40KBPS 7
|
||||||
|
#define CAN_50KBPS 8
|
||||||
|
#define CAN_80KBPS 9
|
||||||
|
#define CAN_83K3BPS 10
|
||||||
|
#define CAN_95KBPS 11
|
||||||
|
#define CAN_100KBPS 12
|
||||||
|
#define CAN_125KBPS 13
|
||||||
|
#define CAN_200KBPS 14
|
||||||
|
#define CAN_250KBPS 15
|
||||||
|
#define CAN_500KBPS 16
|
||||||
|
#define CAN_666KBPS 17
|
||||||
|
#define CAN_1000KBPS 18
|
||||||
|
|
||||||
|
CANBed V1: https://www.longan-labs.cc/1030008.html
|
||||||
|
CANBed M0: https://www.longan-labs.cc/1030014.html
|
||||||
|
CAN Bus Shield: https://www.longan-labs.cc/1030016.html
|
||||||
|
OBD-II CAN Bus GPS Dev Kit: https://www.longan-labs.cc/1030003.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <mcp_canbus.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
/* Please modify SPI_CS_PIN to adapt to your board.
|
||||||
|
|
||||||
|
CANBed V1 - 17
|
||||||
|
CANBed M0 - 3
|
||||||
|
CAN Bus Shield - 9
|
||||||
|
CANBed 2040 - 9
|
||||||
|
CANBed Dual - 9
|
||||||
|
OBD-2G Dev Kit - 9
|
||||||
|
OBD-II GPS Kit - 9
|
||||||
|
Hud Dev Kit - 9
|
||||||
|
|
||||||
|
Seeed Studio CAN-Bus Breakout Board for XIAO and QT Py - D7
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SPI_CS_PIN 9
|
||||||
|
|
||||||
|
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
while(!Serial);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit Atemga32U4 version
|
||||||
|
// pinMode(A3, OUTPUT);
|
||||||
|
// digitalWrite(A3, HIGH);
|
||||||
|
|
||||||
|
// below code need for OBD-II GPS Dev Kit RP2040 version
|
||||||
|
// pinMode(12, OUTPUT);
|
||||||
|
// digitalWrite(12, HIGH);
|
||||||
|
|
||||||
|
while (CAN_OK != CAN.begin(CAN_500KBPS)) // init can bus : baudrate = 500k
|
||||||
|
{
|
||||||
|
Serial.println("CAN BUS FAIL!");
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
Serial.println("CAN BUS OK!");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char stmp[8] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
for(int id=0; id<10; id++)
|
||||||
|
{
|
||||||
|
memset(stmp, id, sizeof(stmp)); // set id to send data buff
|
||||||
|
CAN.sendMsgBuf(id, 0, sizeof(stmp), stmp);
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// END FILE
|
|
@ -0,0 +1,55 @@
|
||||||
|
#######################################
|
||||||
|
# Syntax Coloring Map For debug_lvc
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Datatypes (KEYWORD1)
|
||||||
|
#######################################
|
||||||
|
MCP_CAN KEYWORD1
|
||||||
|
mcp_can_dfs KEYWORD1
|
||||||
|
mcp_can KEYWORD1
|
||||||
|
CAN KEYWORD1
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Methods and Functions (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
begin KEYWORD2
|
||||||
|
init_Mask KEYWORD2
|
||||||
|
init_Filt KEYWORD2
|
||||||
|
sendMsgBuf KEYWORD2
|
||||||
|
readMsgBuf KEYWORD2
|
||||||
|
checkReceive KEYWORD2
|
||||||
|
checkError KEYWORD2
|
||||||
|
getCanId KEYWORD2
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Constants (LITERAL1)
|
||||||
|
#######################################
|
||||||
|
CAN_5KBPS LITERAL1
|
||||||
|
CAN_10KBPS LITERAL1
|
||||||
|
CAN_20KBPS LITERAL1
|
||||||
|
CAN_25KBPS LITERAL1
|
||||||
|
CAN_31KBPS LITERAL1
|
||||||
|
CAN_33KBPS LITERAL1
|
||||||
|
CAN_40KBPS LITERAL1
|
||||||
|
CAN_50KBPS LITERAL1
|
||||||
|
CAN_80KBPS LITERAL1
|
||||||
|
CAN_83KBPS LITERAL1
|
||||||
|
CAN_95KBPS LITERAL1
|
||||||
|
CAN_100KBPS LITERAL1
|
||||||
|
CAN_125KBPS LITERAL1
|
||||||
|
CAN_200KBPS LITERAL1
|
||||||
|
CAN_250KBPS LITERAL1
|
||||||
|
CAN_500KBPS LITERAL1
|
||||||
|
CAN_666KBPS LITERAL1
|
||||||
|
CAN_1000KBPS LITERAL1
|
||||||
|
CAN_OK LITERAL1
|
||||||
|
CAN_FAILINIT LITERAL1
|
||||||
|
CAN_FAILTX LITERAL1
|
||||||
|
CAN_MSGAVAIL LITERAL1
|
||||||
|
CAN_NOMSG LITERAL1
|
||||||
|
CAN_CTRLERROR LITERAL1
|
||||||
|
CAN_GETTXBFTIMEOUT LITERAL1
|
||||||
|
CAN_SENDMSGTIMEOUT LITERAL1
|
||||||
|
CAN_FAIL LITERAL1
|
||||||
|
SPI_CS_PIN LITERAL1
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"name": "CAN_BUS_Shield",
|
||||||
|
"keywords": "can, bus, mcp2515, MCP-2515",
|
||||||
|
"description": "Arduino Library for MCP2515",
|
||||||
|
"repository":
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Longan-Labs/Aruino_CAN_BUS_MCP2515.git"
|
||||||
|
},
|
||||||
|
"version": "1.0.0",
|
||||||
|
"frameworks": "arduino",
|
||||||
|
"platforms": "atmelavr"
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
name=mcp_canbus
|
||||||
|
version=1.0.0
|
||||||
|
author=Longan Labs
|
||||||
|
maintainer=Longan Labs
|
||||||
|
sentence=A library for MCP2515
|
||||||
|
paragraph=Arduino CAN Bus Library for MCP2515
|
||||||
|
category=Communication
|
||||||
|
url=https://github.com/Longan-Labs/Aruino_CAN_BUS_MCP2515
|
||||||
|
architectures=*
|
|
@ -0,0 +1,356 @@
|
||||||
|
/*
|
||||||
|
mcp_can_dfs.h
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef _MCP2515DFS_H_
|
||||||
|
#define _MCP2515DFS_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
//#include <inttypes.h>
|
||||||
|
|
||||||
|
|
||||||
|
// if print debug information
|
||||||
|
#define DEBUG_EN 0
|
||||||
|
|
||||||
|
// Begin mt
|
||||||
|
|
||||||
|
#define TIMEOUTVALUE 50
|
||||||
|
#define MCP_SIDH 0
|
||||||
|
#define MCP_SIDL 1
|
||||||
|
#define MCP_EID8 2
|
||||||
|
#define MCP_EID0 3
|
||||||
|
|
||||||
|
#define MCP_TXB_EXIDE_M 0x08 // In TXBnSIDL
|
||||||
|
#define MCP_DLC_MASK 0x0F // 4 LSBits
|
||||||
|
#define MCP_RTR_MASK 0x40 // (1<<6) Bit 6
|
||||||
|
|
||||||
|
#define MCP_RXB_RX_ANY 0x60
|
||||||
|
#define MCP_RXB_RX_EXT 0x40
|
||||||
|
#define MCP_RXB_RX_STD 0x20
|
||||||
|
#define MCP_RXB_RX_STDEXT 0x00
|
||||||
|
#define MCP_RXB_RX_MASK 0x60
|
||||||
|
#define MCP_RXB_BUKT_MASK (1<<2)
|
||||||
|
|
||||||
|
|
||||||
|
// Bits in the TXBnCTRL registers.
|
||||||
|
|
||||||
|
#define MCP_TXB_TXBUFE_M 0x80
|
||||||
|
#define MCP_TXB_ABTF_M 0x40
|
||||||
|
#define MCP_TXB_MLOA_M 0x20
|
||||||
|
#define MCP_TXB_TXERR_M 0x10
|
||||||
|
#define MCP_TXB_TXREQ_M 0x08
|
||||||
|
#define MCP_TXB_TXIE_M 0x04
|
||||||
|
#define MCP_TXB_TXP10_M 0x03
|
||||||
|
|
||||||
|
#define MCP_TXB_RTR_M 0x40 // In TXBnDLC
|
||||||
|
#define MCP_RXB_IDE_M 0x08 // In RXBnSIDL
|
||||||
|
#define MCP_RXB_RTR_M 0x40 // In RXBnDLC
|
||||||
|
|
||||||
|
#define MCP_STAT_RXIF_MASK (0x03)
|
||||||
|
#define MCP_STAT_RX0IF (1<<0)
|
||||||
|
#define MCP_STAT_RX1IF (1<<1)
|
||||||
|
|
||||||
|
#define MCP_EFLG_RX1OVR (1<<7)
|
||||||
|
#define MCP_EFLG_RX0OVR (1<<6)
|
||||||
|
#define MCP_EFLG_TXBO (1<<5)
|
||||||
|
#define MCP_EFLG_TXEP (1<<4)
|
||||||
|
#define MCP_EFLG_RXEP (1<<3)
|
||||||
|
#define MCP_EFLG_TXWAR (1<<2)
|
||||||
|
#define MCP_EFLG_RXWAR (1<<1)
|
||||||
|
#define MCP_EFLG_EWARN (1<<0)
|
||||||
|
#define MCP_EFLG_ERRORMASK (0xF8) // 5 MS-Bits
|
||||||
|
|
||||||
|
// Define MCP2515 register addresses
|
||||||
|
|
||||||
|
#define MCP_RXF0SIDH 0x00
|
||||||
|
#define MCP_RXF0SIDL 0x01
|
||||||
|
#define MCP_RXF0EID8 0x02
|
||||||
|
#define MCP_RXF0EID0 0x03
|
||||||
|
#define MCP_RXF1SIDH 0x04
|
||||||
|
#define MCP_RXF1SIDL 0x05
|
||||||
|
#define MCP_RXF1EID8 0x06
|
||||||
|
#define MCP_RXF1EID0 0x07
|
||||||
|
#define MCP_RXF2SIDH 0x08
|
||||||
|
#define MCP_RXF2SIDL 0x09
|
||||||
|
#define MCP_RXF2EID8 0x0A
|
||||||
|
#define MCP_RXF2EID0 0x0B
|
||||||
|
#define MCP_CANSTAT 0x0E
|
||||||
|
#define MCP_CANCTRL 0x0F
|
||||||
|
#define MCP_RXF3SIDH 0x10
|
||||||
|
#define MCP_RXF3SIDL 0x11
|
||||||
|
#define MCP_RXF3EID8 0x12
|
||||||
|
#define MCP_RXF3EID0 0x13
|
||||||
|
#define MCP_RXF4SIDH 0x14
|
||||||
|
#define MCP_RXF4SIDL 0x15
|
||||||
|
#define MCP_RXF4EID8 0x16
|
||||||
|
#define MCP_RXF4EID0 0x17
|
||||||
|
#define MCP_RXF5SIDH 0x18
|
||||||
|
#define MCP_RXF5SIDL 0x19
|
||||||
|
#define MCP_RXF5EID8 0x1A
|
||||||
|
#define MCP_RXF5EID0 0x1B
|
||||||
|
#define MCP_TEC 0x1C
|
||||||
|
#define MCP_REC 0x1D
|
||||||
|
#define MCP_RXM0SIDH 0x20
|
||||||
|
#define MCP_RXM0SIDL 0x21
|
||||||
|
#define MCP_RXM0EID8 0x22
|
||||||
|
#define MCP_RXM0EID0 0x23
|
||||||
|
#define MCP_RXM1SIDH 0x24
|
||||||
|
#define MCP_RXM1SIDL 0x25
|
||||||
|
#define MCP_RXM1EID8 0x26
|
||||||
|
#define MCP_RXM1EID0 0x27
|
||||||
|
#define MCP_CNF3 0x28
|
||||||
|
#define MCP_CNF2 0x29
|
||||||
|
#define MCP_CNF1 0x2A
|
||||||
|
#define MCP_CANINTE 0x2B
|
||||||
|
#define MCP_CANINTF 0x2C
|
||||||
|
#define MCP_EFLG 0x2D
|
||||||
|
#define MCP_TXB0CTRL 0x30
|
||||||
|
#define MCP_TXB1CTRL 0x40
|
||||||
|
#define MCP_TXB2CTRL 0x50
|
||||||
|
#define MCP_RXB0CTRL 0x60
|
||||||
|
#define MCP_RXB0SIDH 0x61
|
||||||
|
#define MCP_RXB1CTRL 0x70
|
||||||
|
#define MCP_RXB1SIDH 0x71
|
||||||
|
#define MCP_TX_INT 0x1C // Enable all transmit interrup ts
|
||||||
|
#define MCP_TX01_INT 0x0C // Enable TXB0 and TXB1 interru pts
|
||||||
|
#define MCP_RX_INT 0x03 // Enable receive interrupts
|
||||||
|
#define MCP_NO_INT 0x00 // Disable all interrupts
|
||||||
|
|
||||||
|
#define MCP_TX01_MASK 0x14
|
||||||
|
#define MCP_TX_MASK 0x54
|
||||||
|
|
||||||
|
|
||||||
|
// Define SPI Instruction Set
|
||||||
|
|
||||||
|
#define MCP_WRITE 0x02
|
||||||
|
#define MCP_READ 0x03
|
||||||
|
#define MCP_BITMOD 0x05
|
||||||
|
#define MCP_LOAD_TX0 0x40
|
||||||
|
#define MCP_LOAD_TX1 0x42
|
||||||
|
#define MCP_LOAD_TX2 0x44
|
||||||
|
|
||||||
|
#define MCP_RTS_TX0 0x81
|
||||||
|
#define MCP_RTS_TX1 0x82
|
||||||
|
#define MCP_RTS_TX2 0x84
|
||||||
|
#define MCP_RTS_ALL 0x87
|
||||||
|
#define MCP_READ_RX0 0x90
|
||||||
|
#define MCP_READ_RX1 0x94
|
||||||
|
#define MCP_READ_STATUS 0xA0
|
||||||
|
#define MCP_RX_STATUS 0xB0
|
||||||
|
#define MCP_RESET 0xC0
|
||||||
|
|
||||||
|
|
||||||
|
// CANCTRL Register Values
|
||||||
|
|
||||||
|
#define MODE_NORMAL 0x00
|
||||||
|
#define MODE_SLEEP 0x20
|
||||||
|
#define MODE_LOOPBACK 0x40
|
||||||
|
#define MODE_LISTENONLY 0x60
|
||||||
|
#define MODE_CONFIG 0x80
|
||||||
|
#define MODE_POWERUP 0xE0
|
||||||
|
#define MODE_MASK 0xE0
|
||||||
|
#define ABORT_TX 0x10
|
||||||
|
#define MODE_ONESHOT 0x08
|
||||||
|
#define CLKOUT_ENABLE 0x04
|
||||||
|
#define CLKOUT_DISABLE 0x00
|
||||||
|
#define CLKOUT_PS1 0x00
|
||||||
|
#define CLKOUT_PS2 0x01
|
||||||
|
#define CLKOUT_PS4 0x02
|
||||||
|
#define CLKOUT_PS8 0x03
|
||||||
|
|
||||||
|
|
||||||
|
// CNF1 Register Values
|
||||||
|
|
||||||
|
#define SJW1 0x00
|
||||||
|
#define SJW2 0x40
|
||||||
|
#define SJW3 0x80
|
||||||
|
#define SJW4 0xC0
|
||||||
|
|
||||||
|
|
||||||
|
// CNF2 Register Values
|
||||||
|
|
||||||
|
#define BTLMODE 0x80
|
||||||
|
#define SAMPLE_1X 0x00
|
||||||
|
#define SAMPLE_3X 0x40
|
||||||
|
|
||||||
|
|
||||||
|
// CNF3 Register Values
|
||||||
|
|
||||||
|
#define SOF_ENABLE 0x80
|
||||||
|
#define SOF_DISABLE 0x00
|
||||||
|
#define WAKFIL_ENABLE 0x40
|
||||||
|
#define WAKFIL_DISABLE 0x00
|
||||||
|
|
||||||
|
|
||||||
|
// CANINTF Register Bits
|
||||||
|
|
||||||
|
#define MCP_RX0IF 0x01
|
||||||
|
#define MCP_RX1IF 0x02
|
||||||
|
#define MCP_TX0IF 0x04
|
||||||
|
#define MCP_TX1IF 0x08
|
||||||
|
#define MCP_TX2IF 0x10
|
||||||
|
#define MCP_ERRIF 0x20
|
||||||
|
#define MCP_WAKIF 0x40
|
||||||
|
#define MCP_MERRF 0x80
|
||||||
|
|
||||||
|
// speed 16M
|
||||||
|
|
||||||
|
#define MCP_16MHz_1000kBPS_CFG1 (0x00)
|
||||||
|
#define MCP_16MHz_1000kBPS_CFG2 (0xD0)
|
||||||
|
#define MCP_16MHz_1000kBPS_CFG3 (0x82)
|
||||||
|
|
||||||
|
#define MCP_16MHz_500kBPS_CFG1 (0x00)
|
||||||
|
#define MCP_16MHz_500kBPS_CFG2 (0xF0)
|
||||||
|
#define MCP_16MHz_500kBPS_CFG3 (0x86)
|
||||||
|
|
||||||
|
#define MCP_16MHz_250kBPS_CFG1 (0x41)
|
||||||
|
#define MCP_16MHz_250kBPS_CFG2 (0xF1)
|
||||||
|
#define MCP_16MHz_250kBPS_CFG3 (0x85)
|
||||||
|
|
||||||
|
#define MCP_16MHz_200kBPS_CFG1 (0x01)
|
||||||
|
#define MCP_16MHz_200kBPS_CFG2 (0xFA)
|
||||||
|
#define MCP_16MHz_200kBPS_CFG3 (0x87)
|
||||||
|
|
||||||
|
#define MCP_16MHz_125kBPS_CFG1 (0x03)
|
||||||
|
#define MCP_16MHz_125kBPS_CFG2 (0xF0)
|
||||||
|
#define MCP_16MHz_125kBPS_CFG3 (0x86)
|
||||||
|
|
||||||
|
#define MCP_16MHz_100kBPS_CFG1 (0x03)
|
||||||
|
#define MCP_16MHz_100kBPS_CFG2 (0xFA)
|
||||||
|
#define MCP_16MHz_100kBPS_CFG3 (0x87)
|
||||||
|
|
||||||
|
#define MCP_16MHz_95kBPS_CFG1 (0x03)
|
||||||
|
#define MCP_16MHz_95kBPS_CFG2 (0xAD)
|
||||||
|
#define MCP_16MHz_95kBPS_CFG3 (0x07)
|
||||||
|
|
||||||
|
#define MCP_16MHz_83k3BPS_CFG1 (0x03)
|
||||||
|
#define MCP_16MHz_83k3BPS_CFG2 (0xBE)
|
||||||
|
#define MCP_16MHz_83k3BPS_CFG3 (0x07)
|
||||||
|
|
||||||
|
#define MCP_16MHz_80kBPS_CFG1 (0x03)
|
||||||
|
#define MCP_16MHz_80kBPS_CFG2 (0xFF)
|
||||||
|
#define MCP_16MHz_80kBPS_CFG3 (0x87)
|
||||||
|
|
||||||
|
#define MCP_16MHz_50kBPS_CFG1 (0x07)
|
||||||
|
#define MCP_16MHz_50kBPS_CFG2 (0xFA)
|
||||||
|
#define MCP_16MHz_50kBPS_CFG3 (0x87)
|
||||||
|
|
||||||
|
#define MCP_16MHz_40kBPS_CFG1 (0x07)
|
||||||
|
#define MCP_16MHz_40kBPS_CFG2 (0xFF)
|
||||||
|
#define MCP_16MHz_40kBPS_CFG3 (0x87)
|
||||||
|
|
||||||
|
#define MCP_16MHz_33kBPS_CFG1 (0x09)
|
||||||
|
#define MCP_16MHz_33kBPS_CFG2 (0xBE)
|
||||||
|
#define MCP_16MHz_33kBPS_CFG3 (0x07)
|
||||||
|
|
||||||
|
#define MCP_16MHz_31k25BPS_CFG1 (0x0F)
|
||||||
|
#define MCP_16MHz_31k25BPS_CFG2 (0xF1)
|
||||||
|
#define MCP_16MHz_31k25BPS_CFG3 (0x85)
|
||||||
|
|
||||||
|
#define MCP_16MHz_25kBPS_CFG1 (0X0F)
|
||||||
|
#define MCP_16MHz_25kBPS_CFG2 (0XBA)
|
||||||
|
#define MCP_16MHz_25kBPS_CFG3 (0X07)
|
||||||
|
|
||||||
|
#define MCP_16MHz_20kBPS_CFG1 (0x0F)
|
||||||
|
#define MCP_16MHz_20kBPS_CFG2 (0xFF)
|
||||||
|
#define MCP_16MHz_20kBPS_CFG3 (0x87)
|
||||||
|
|
||||||
|
#define MCP_16MHz_10kBPS_CFG1 (0x1F)
|
||||||
|
#define MCP_16MHz_10kBPS_CFG2 (0xFF)
|
||||||
|
#define MCP_16MHz_10kBPS_CFG3 (0x87)
|
||||||
|
|
||||||
|
#define MCP_16MHz_5kBPS_CFG1 (0x3F)
|
||||||
|
#define MCP_16MHz_5kBPS_CFG2 (0xFF)
|
||||||
|
#define MCP_16MHz_5kBPS_CFG3 (0x87)
|
||||||
|
|
||||||
|
#define MCP_16MHz_666kBPS_CFG1 (0x00)
|
||||||
|
#define MCP_16MHz_666kBPS_CFG2 (0xA0)
|
||||||
|
#define MCP_16MHz_666kBPS_CFG3 (0x04)
|
||||||
|
|
||||||
|
|
||||||
|
#define MCPDEBUG (0)
|
||||||
|
#define MCPDEBUG_TXBUF (0)
|
||||||
|
#define MCP_N_TXBUFFERS (3)
|
||||||
|
|
||||||
|
#define MCP_RXBUF_0 (MCP_RXB0SIDH)
|
||||||
|
#define MCP_RXBUF_1 (MCP_RXB1SIDH)
|
||||||
|
|
||||||
|
#define MCP2515_SELECT() digitalWrite(SPICS, LOW)
|
||||||
|
#define MCP2515_UNSELECT() digitalWrite(SPICS, HIGH)
|
||||||
|
|
||||||
|
#define MCP2515_OK (0)
|
||||||
|
#define MCP2515_FAIL (1)
|
||||||
|
#define MCP_ALLTXBUSY (2)
|
||||||
|
|
||||||
|
#define CANDEBUG 1
|
||||||
|
|
||||||
|
#define CANUSELOOP 0
|
||||||
|
|
||||||
|
#define CANSENDTIMEOUT (200) // milliseconds
|
||||||
|
|
||||||
|
|
||||||
|
// initial value of gCANAutoProcess
|
||||||
|
|
||||||
|
#define CANAUTOPROCESS (1)
|
||||||
|
#define CANAUTOON (1)
|
||||||
|
#define CANAUTOOFF (0)
|
||||||
|
#define CAN_STDID (0)
|
||||||
|
#define CAN_EXTID (1)
|
||||||
|
#define CANDEFAULTIDENT (0x55CC)
|
||||||
|
#define CANDEFAULTIDENTEXT (CAN_EXTID)
|
||||||
|
|
||||||
|
#define CAN_5KBPS 1
|
||||||
|
#define CAN_10KBPS 2
|
||||||
|
#define CAN_20KBPS 3
|
||||||
|
#define CAN_25KBPS 4
|
||||||
|
#define CAN_31K25BPS 5
|
||||||
|
#define CAN_33KBPS 6
|
||||||
|
#define CAN_40KBPS 7
|
||||||
|
#define CAN_50KBPS 8
|
||||||
|
#define CAN_80KBPS 9
|
||||||
|
#define CAN_83K3BPS 10
|
||||||
|
#define CAN_95KBPS 11
|
||||||
|
#define CAN_100KBPS 12
|
||||||
|
#define CAN_125KBPS 13
|
||||||
|
#define CAN_200KBPS 14
|
||||||
|
#define CAN_250KBPS 15
|
||||||
|
#define CAN_500KBPS 16
|
||||||
|
#define CAN_666KBPS 17
|
||||||
|
#define CAN_1000KBPS 18
|
||||||
|
|
||||||
|
#define CAN_OK (0)
|
||||||
|
#define CAN_FAILINIT (1)
|
||||||
|
#define CAN_FAILTX (2)
|
||||||
|
#define CAN_MSGAVAIL (3)
|
||||||
|
#define CAN_NOMSG (4)
|
||||||
|
#define CAN_CTRLERROR (5)
|
||||||
|
#define CAN_GETTXBFTIMEOUT (6)
|
||||||
|
#define CAN_SENDMSGTIMEOUT (7)
|
||||||
|
#define CAN_FAIL (0xff)
|
||||||
|
|
||||||
|
#define CAN_MAX_CHAR_IN_MESSAGE (8)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/*********************************************************************************************************
|
||||||
|
END FILE
|
||||||
|
*********************************************************************************************************/
|
|
@ -0,0 +1,971 @@
|
||||||
|
/*
|
||||||
|
mcp_can.cpp
|
||||||
|
|
||||||
|
Author:Stephen Lo
|
||||||
|
2014-1-16
|
||||||
|
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
Cory J. Fowler
|
||||||
|
Latonita
|
||||||
|
Woodward1
|
||||||
|
Mehtajaghvi
|
||||||
|
BykeBlast
|
||||||
|
TheRo0T
|
||||||
|
Tsipizic
|
||||||
|
ralfEdmund
|
||||||
|
Nathancheek
|
||||||
|
BlueAndi
|
||||||
|
Adlerweb
|
||||||
|
Btetz
|
||||||
|
Hurvajs
|
||||||
|
xboxpro1
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "mcp_canbus.h"
|
||||||
|
|
||||||
|
#define spi_readwrite SPI.transfer
|
||||||
|
#define spi_read() spi_readwrite(0x00)
|
||||||
|
#define SPI_BEGIN() SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0))
|
||||||
|
#define SPI_END() SPI.endTransaction()
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_reset
|
||||||
|
** Descriptions: reset the device
|
||||||
|
*********************************************************************************************************/
|
||||||
|
void MCP_CAN::mcp2515_reset(void)
|
||||||
|
{
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_BEGIN();
|
||||||
|
#endif
|
||||||
|
MCP2515_SELECT();
|
||||||
|
spi_readwrite(MCP_RESET);
|
||||||
|
MCP2515_UNSELECT();
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_END();
|
||||||
|
#endif
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_readRegister
|
||||||
|
** Descriptions: read register
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::mcp2515_readRegister(const byte address)
|
||||||
|
{
|
||||||
|
byte ret;
|
||||||
|
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_BEGIN();
|
||||||
|
#endif
|
||||||
|
MCP2515_SELECT();
|
||||||
|
spi_readwrite(MCP_READ);
|
||||||
|
spi_readwrite(address);
|
||||||
|
ret = spi_read();
|
||||||
|
MCP2515_UNSELECT();
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_END();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_readRegisterS
|
||||||
|
** Descriptions: read registerS
|
||||||
|
*********************************************************************************************************/
|
||||||
|
void MCP_CAN::mcp2515_readRegisterS(const byte address, byte values[], const byte n)
|
||||||
|
{
|
||||||
|
byte i;
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_BEGIN();
|
||||||
|
#endif
|
||||||
|
MCP2515_SELECT();
|
||||||
|
spi_readwrite(MCP_READ);
|
||||||
|
spi_readwrite(address);
|
||||||
|
// mcp2515 has auto-increment of address-pointer
|
||||||
|
for(i=0; i<n && i<CAN_MAX_CHAR_IN_MESSAGE; i++)
|
||||||
|
{
|
||||||
|
values[i] = spi_read();
|
||||||
|
}
|
||||||
|
MCP2515_UNSELECT();
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_END();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_setRegister
|
||||||
|
** Descriptions: set register
|
||||||
|
*********************************************************************************************************/
|
||||||
|
void MCP_CAN::mcp2515_setRegister(const byte address, const byte value)
|
||||||
|
{
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_BEGIN();
|
||||||
|
#endif
|
||||||
|
MCP2515_SELECT();
|
||||||
|
spi_readwrite(MCP_WRITE);
|
||||||
|
spi_readwrite(address);
|
||||||
|
spi_readwrite(value);
|
||||||
|
MCP2515_UNSELECT();
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_END();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_setRegisterS
|
||||||
|
** Descriptions: set registerS
|
||||||
|
*********************************************************************************************************/
|
||||||
|
void MCP_CAN::mcp2515_setRegisterS(const byte address, const byte values[], const byte n)
|
||||||
|
{
|
||||||
|
byte i;
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_BEGIN();
|
||||||
|
#endif
|
||||||
|
MCP2515_SELECT();
|
||||||
|
spi_readwrite(MCP_WRITE);
|
||||||
|
spi_readwrite(address);
|
||||||
|
|
||||||
|
for(i=0; i<n; i++)
|
||||||
|
{
|
||||||
|
spi_readwrite(values[i]);
|
||||||
|
}
|
||||||
|
MCP2515_UNSELECT();
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_END();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_modifyRegister
|
||||||
|
** Descriptions: set bit of one register
|
||||||
|
*********************************************************************************************************/
|
||||||
|
void MCP_CAN::mcp2515_modifyRegister(const byte address, const byte mask, const byte data)
|
||||||
|
{
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_BEGIN();
|
||||||
|
#endif
|
||||||
|
MCP2515_SELECT();
|
||||||
|
spi_readwrite(MCP_BITMOD);
|
||||||
|
spi_readwrite(address);
|
||||||
|
spi_readwrite(mask);
|
||||||
|
spi_readwrite(data);
|
||||||
|
MCP2515_UNSELECT();
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_END();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_readStatus
|
||||||
|
** Descriptions: read mcp2515's Status
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::mcp2515_readStatus(void)
|
||||||
|
{
|
||||||
|
byte i;
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_BEGIN();
|
||||||
|
#endif
|
||||||
|
MCP2515_SELECT();
|
||||||
|
spi_readwrite(MCP_READ_STATUS);
|
||||||
|
i = spi_read();
|
||||||
|
MCP2515_UNSELECT();
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPI_END();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_setCANCTRL_Mode
|
||||||
|
** Descriptions: set control mode
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::mcp2515_setCANCTRL_Mode(const byte newmode)
|
||||||
|
{
|
||||||
|
byte i;
|
||||||
|
|
||||||
|
mcp2515_modifyRegister(MCP_CANCTRL, MODE_MASK, newmode);
|
||||||
|
|
||||||
|
i = mcp2515_readRegister(MCP_CANCTRL);
|
||||||
|
i &= MODE_MASK;
|
||||||
|
|
||||||
|
if(i == newmode)
|
||||||
|
{
|
||||||
|
return MCP2515_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MCP2515_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_configRate
|
||||||
|
** Descriptions: set boadrate
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::mcp2515_configRate(const byte canSpeed)
|
||||||
|
{
|
||||||
|
byte set, cfg1, cfg2, cfg3;
|
||||||
|
set = 1;
|
||||||
|
switch (canSpeed)
|
||||||
|
{
|
||||||
|
case (CAN_5KBPS):
|
||||||
|
cfg1 = MCP_16MHz_5kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_5kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_5kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_10KBPS):
|
||||||
|
cfg1 = MCP_16MHz_10kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_10kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_10kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_20KBPS):
|
||||||
|
cfg1 = MCP_16MHz_20kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_20kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_20kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_25KBPS):
|
||||||
|
cfg1 = MCP_16MHz_25kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_25kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_25kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_31K25BPS):
|
||||||
|
cfg1 = MCP_16MHz_31k25BPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_31k25BPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_31k25BPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_33KBPS):
|
||||||
|
cfg1 = MCP_16MHz_33kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_33kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_33kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_40KBPS):
|
||||||
|
cfg1 = MCP_16MHz_40kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_40kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_40kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_50KBPS):
|
||||||
|
cfg1 = MCP_16MHz_50kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_50kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_50kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_80KBPS):
|
||||||
|
cfg1 = MCP_16MHz_80kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_80kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_80kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_83K3BPS):
|
||||||
|
cfg1 = MCP_16MHz_83k3BPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_83k3BPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_83k3BPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_95KBPS):
|
||||||
|
cfg1 = MCP_16MHz_95kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_95kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_95kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_100KBPS):
|
||||||
|
cfg1 = MCP_16MHz_100kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_100kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_100kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_125KBPS):
|
||||||
|
cfg1 = MCP_16MHz_125kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_125kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_125kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_200KBPS):
|
||||||
|
cfg1 = MCP_16MHz_200kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_200kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_200kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_250KBPS):
|
||||||
|
cfg1 = MCP_16MHz_250kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_250kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_250kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_500KBPS):
|
||||||
|
cfg1 = MCP_16MHz_500kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_500kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_500kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_666KBPS):
|
||||||
|
cfg1 = MCP_16MHz_666kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_666kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_666kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (CAN_1000KBPS):
|
||||||
|
cfg1 = MCP_16MHz_1000kBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHz_1000kBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHz_1000kBPS_CFG3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
set = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(set) {
|
||||||
|
mcp2515_setRegister(MCP_CNF1, cfg1);
|
||||||
|
mcp2515_setRegister(MCP_CNF2, cfg2);
|
||||||
|
mcp2515_setRegister(MCP_CNF3, cfg3);
|
||||||
|
return MCP2515_OK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return MCP2515_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_initCANBuffers
|
||||||
|
** Descriptions: init canbuffers
|
||||||
|
*********************************************************************************************************/
|
||||||
|
void MCP_CAN::mcp2515_initCANBuffers(void)
|
||||||
|
{
|
||||||
|
byte i, a1, a2, a3;
|
||||||
|
|
||||||
|
a1 = MCP_TXB0CTRL;
|
||||||
|
a2 = MCP_TXB1CTRL;
|
||||||
|
a3 = MCP_TXB2CTRL;
|
||||||
|
for(i = 0; i < 14; i++) // in-buffer loop
|
||||||
|
{
|
||||||
|
mcp2515_setRegister(a1, 0);
|
||||||
|
mcp2515_setRegister(a2, 0);
|
||||||
|
mcp2515_setRegister(a3, 0);
|
||||||
|
a1++;
|
||||||
|
a2++;
|
||||||
|
a3++;
|
||||||
|
}
|
||||||
|
mcp2515_setRegister(MCP_RXB0CTRL, 0);
|
||||||
|
mcp2515_setRegister(MCP_RXB1CTRL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_init
|
||||||
|
** Descriptions: init the device
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::mcp2515_init(const byte canSpeed)
|
||||||
|
{
|
||||||
|
|
||||||
|
byte res;
|
||||||
|
|
||||||
|
mcp2515_reset();
|
||||||
|
|
||||||
|
res = mcp2515_setCANCTRL_Mode(MODE_CONFIG);
|
||||||
|
if(res > 0)
|
||||||
|
{
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("Enter setting mode fall\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("Enter setting mode success \r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// set boadrate
|
||||||
|
if(mcp2515_configRate(canSpeed))
|
||||||
|
{
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("set rate fall!!\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("set rate success!!\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(res == MCP2515_OK) {
|
||||||
|
|
||||||
|
// init canbuffers
|
||||||
|
mcp2515_initCANBuffers();
|
||||||
|
|
||||||
|
// interrupt mode
|
||||||
|
mcp2515_setRegister(MCP_CANINTE, MCP_RX0IF | MCP_RX1IF);
|
||||||
|
|
||||||
|
#if (DEBUG_RXANY==1)
|
||||||
|
// enable both receive-buffers to receive any message and enable rollover
|
||||||
|
mcp2515_modifyRegister(MCP_RXB0CTRL,
|
||||||
|
MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK,
|
||||||
|
MCP_RXB_RX_ANY | MCP_RXB_BUKT_MASK);
|
||||||
|
mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK,
|
||||||
|
MCP_RXB_RX_ANY);
|
||||||
|
#else
|
||||||
|
// enable both receive-buffers to receive messages with std. and ext. identifiers and enable rollover
|
||||||
|
mcp2515_modifyRegister(MCP_RXB0CTRL,
|
||||||
|
MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK,
|
||||||
|
MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK);
|
||||||
|
mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK,
|
||||||
|
MCP_RXB_RX_STDEXT);
|
||||||
|
#endif
|
||||||
|
// enter normal mode
|
||||||
|
res = mcp2515_setCANCTRL_Mode(MODE_NORMAL);
|
||||||
|
if(res)
|
||||||
|
{
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("Enter Normal Mode Fall!!\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("Enter Normal Mode Success!!\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_write_id
|
||||||
|
** Descriptions: write can id
|
||||||
|
*********************************************************************************************************/
|
||||||
|
void MCP_CAN::mcp2515_write_id(const byte mcp_addr, const byte ext, const unsigned long id)
|
||||||
|
{
|
||||||
|
uint16_t canid;
|
||||||
|
byte tbufdata[4];
|
||||||
|
|
||||||
|
canid = (uint16_t)(id & 0x0FFFF);
|
||||||
|
|
||||||
|
if(ext == 1)
|
||||||
|
{
|
||||||
|
tbufdata[MCP_EID0] = (byte) (canid & 0xFF);
|
||||||
|
tbufdata[MCP_EID8] = (byte) (canid >> 8);
|
||||||
|
canid = (uint16_t)(id >> 16);
|
||||||
|
tbufdata[MCP_SIDL] = (byte) (canid & 0x03);
|
||||||
|
tbufdata[MCP_SIDL] += (byte) ((canid & 0x1C) << 3);
|
||||||
|
tbufdata[MCP_SIDL] |= MCP_TXB_EXIDE_M;
|
||||||
|
tbufdata[MCP_SIDH] = (byte) (canid >> 5);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tbufdata[MCP_SIDH] = (byte) (canid >> 3);
|
||||||
|
tbufdata[MCP_SIDL] = (byte) ((canid & 0x07) << 5);
|
||||||
|
tbufdata[MCP_EID0] = 0;
|
||||||
|
tbufdata[MCP_EID8] = 0;
|
||||||
|
}
|
||||||
|
mcp2515_setRegisterS(mcp_addr, tbufdata, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_read_id
|
||||||
|
** Descriptions: read can id
|
||||||
|
*********************************************************************************************************/
|
||||||
|
void MCP_CAN::mcp2515_read_id(const byte mcp_addr, byte* ext, unsigned long* id)
|
||||||
|
{
|
||||||
|
byte tbufdata[4];
|
||||||
|
|
||||||
|
*ext = 0;
|
||||||
|
*id = 0;
|
||||||
|
|
||||||
|
mcp2515_readRegisterS(mcp_addr, tbufdata, 4);
|
||||||
|
|
||||||
|
*id = (tbufdata[MCP_SIDH]<<3) + (tbufdata[MCP_SIDL]>>5);
|
||||||
|
|
||||||
|
if((tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M)
|
||||||
|
{
|
||||||
|
// extended id
|
||||||
|
*id = (*id<<2) + (tbufdata[MCP_SIDL] & 0x03);
|
||||||
|
*id = (*id<<8) + tbufdata[MCP_EID8];
|
||||||
|
*id = (*id<<8) + tbufdata[MCP_EID0];
|
||||||
|
*ext = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_write_canMsg
|
||||||
|
** Descriptions: write msg
|
||||||
|
*********************************************************************************************************/
|
||||||
|
void MCP_CAN::mcp2515_write_canMsg(const byte buffer_sidh_addr, int rtrBit)
|
||||||
|
{
|
||||||
|
byte mcp_addr;
|
||||||
|
mcp_addr = buffer_sidh_addr;
|
||||||
|
mcp2515_setRegisterS(mcp_addr+5, dta, dta_len); // write data bytes
|
||||||
|
// Serial.print("RTR: ");
|
||||||
|
// Serial.println(rtrBit);
|
||||||
|
if(rtrBit == 1) // if RTR set bit in byte
|
||||||
|
{
|
||||||
|
dta_len |= MCP_RTR_MASK;
|
||||||
|
}
|
||||||
|
mcp2515_setRegister((mcp_addr+4), dta_len); // write the RTR and DLC
|
||||||
|
mcp2515_write_id(mcp_addr, ext_flg, can_id); // write CAN id
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_read_canMsg
|
||||||
|
** Descriptions: read message
|
||||||
|
*********************************************************************************************************/
|
||||||
|
void MCP_CAN::mcp2515_read_canMsg(const byte buffer_sidh_addr) // read can msg
|
||||||
|
{
|
||||||
|
byte mcp_addr, ctrl;
|
||||||
|
|
||||||
|
mcp_addr = buffer_sidh_addr;
|
||||||
|
mcp2515_read_id(mcp_addr, &ext_flg,&can_id);
|
||||||
|
ctrl = mcp2515_readRegister(mcp_addr-1);
|
||||||
|
dta_len = mcp2515_readRegister(mcp_addr+4);
|
||||||
|
|
||||||
|
rtr = (ctrl & 0x08) ? 1 : 0;
|
||||||
|
|
||||||
|
dta_len &= MCP_DLC_MASK;
|
||||||
|
mcp2515_readRegisterS(mcp_addr+5, &(dta[0]), dta_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_start_transmit
|
||||||
|
** Descriptions: start transmit
|
||||||
|
*********************************************************************************************************/
|
||||||
|
void MCP_CAN::mcp2515_start_transmit(const byte mcp_addr) // start transmit
|
||||||
|
{
|
||||||
|
mcp2515_modifyRegister(mcp_addr-1 , MCP_TXB_TXREQ_M, MCP_TXB_TXREQ_M);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: mcp2515_getNextFreeTXBuf
|
||||||
|
** Descriptions: get Next free txbuf
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::mcp2515_getNextFreeTXBuf(byte *txbuf_n) // get Next free txbuf
|
||||||
|
{
|
||||||
|
byte res, i, ctrlval;
|
||||||
|
byte ctrlregs[MCP_N_TXBUFFERS] = { MCP_TXB0CTRL, MCP_TXB1CTRL, MCP_TXB2CTRL };
|
||||||
|
|
||||||
|
res = MCP_ALLTXBUSY;
|
||||||
|
*txbuf_n = 0x00;
|
||||||
|
|
||||||
|
// check all 3 TX-Buffers
|
||||||
|
for(i=0; i<MCP_N_TXBUFFERS; i++)
|
||||||
|
{
|
||||||
|
ctrlval = mcp2515_readRegister(ctrlregs[i]);
|
||||||
|
if((ctrlval & MCP_TXB_TXREQ_M) == 0) {
|
||||||
|
*txbuf_n = ctrlregs[i]+1; // return SIDH-address of Buffer
|
||||||
|
res = MCP2515_OK;
|
||||||
|
return res; // ! function exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: set CS
|
||||||
|
** Descriptions: init CS pin and set UNSELECTED
|
||||||
|
*********************************************************************************************************/
|
||||||
|
MCP_CAN::MCP_CAN(byte _CS)
|
||||||
|
{
|
||||||
|
SPICS = _CS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: init
|
||||||
|
** Descriptions: init can and set speed
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::begin(byte speedset)
|
||||||
|
{
|
||||||
|
pinMode(SPICS, OUTPUT);
|
||||||
|
MCP2515_UNSELECT();
|
||||||
|
SPI.begin();
|
||||||
|
byte res = mcp2515_init(speedset);
|
||||||
|
return ((res == MCP2515_OK) ? CAN_OK : CAN_FAILINIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: init_Mask
|
||||||
|
** Descriptions: init canid Masks
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::init_Mask(byte num, byte ext, unsigned long ulData)
|
||||||
|
{
|
||||||
|
byte res = MCP2515_OK;
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("Begin to set Mask!!\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
res = mcp2515_setCANCTRL_Mode(MODE_CONFIG);
|
||||||
|
if(res > 0){
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("Enter setting mode fall\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(num == 0){
|
||||||
|
mcp2515_write_id(MCP_RXM0SIDH, ext, ulData);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(num == 1){
|
||||||
|
mcp2515_write_id(MCP_RXM1SIDH, ext, ulData);
|
||||||
|
}
|
||||||
|
else res = MCP2515_FAIL;
|
||||||
|
|
||||||
|
res = mcp2515_setCANCTRL_Mode(MODE_NORMAL);
|
||||||
|
if(res > 0){
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("Enter normal mode fall\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("set Mask success!!\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: init_Filt
|
||||||
|
** Descriptions: init canid filters
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::init_Filt(byte num, byte ext, unsigned long ulData)
|
||||||
|
{
|
||||||
|
byte res = MCP2515_OK;
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("Begin to set Filter!!\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
res = mcp2515_setCANCTRL_Mode(MODE_CONFIG);
|
||||||
|
if(res > 0)
|
||||||
|
{
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("Enter setting mode fall\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(num)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
mcp2515_write_id(MCP_RXF0SIDH, ext, ulData);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
mcp2515_write_id(MCP_RXF1SIDH, ext, ulData);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
mcp2515_write_id(MCP_RXF2SIDH, ext, ulData);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
mcp2515_write_id(MCP_RXF3SIDH, ext, ulData);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
mcp2515_write_id(MCP_RXF4SIDH, ext, ulData);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
mcp2515_write_id(MCP_RXF5SIDH, ext, ulData);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
res = MCP2515_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = mcp2515_setCANCTRL_Mode(MODE_NORMAL);
|
||||||
|
if(res > 0)
|
||||||
|
{
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("Enter normal mode fall\r\nSet filter fail!!\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#if DEBUG_EN
|
||||||
|
Serial.print("set Filter success!!\r\n");
|
||||||
|
#else
|
||||||
|
delay(10);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: setMsg
|
||||||
|
** Descriptions: set can message, such as dlc, id, dta[] and so on
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::setMsg(unsigned long id, byte ext, byte len, byte rtr, byte *pData)
|
||||||
|
{
|
||||||
|
ext_flg = ext;
|
||||||
|
can_id = id;
|
||||||
|
//dta_len = min(len, MAX_CHAR_IN_MESSAGE);
|
||||||
|
dta_len = len > MAX_CHAR_IN_MESSAGE ? MAX_CHAR_IN_MESSAGE: len;
|
||||||
|
rtr = rtr;
|
||||||
|
for(int i = 0; i<dta_len; i++)
|
||||||
|
{
|
||||||
|
dta[i] = *(pData+i);
|
||||||
|
}
|
||||||
|
return MCP2515_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: setMsg
|
||||||
|
** Descriptions: set can message, such as dlc, id, dta[] and so on
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::setMsg(unsigned long id, byte ext, byte len, byte *pData)
|
||||||
|
{
|
||||||
|
return setMsg(id, ext, len, 0, pData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: clearMsg
|
||||||
|
** Descriptions: set all message to zero
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::clearMsg()
|
||||||
|
{
|
||||||
|
can_id = 0;
|
||||||
|
dta_len = 0;
|
||||||
|
ext_flg = 0;
|
||||||
|
rtr = 0;
|
||||||
|
filhit = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i<dta_len; i++)
|
||||||
|
{
|
||||||
|
dta[i] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MCP2515_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: sendMsg
|
||||||
|
** Descriptions: send message
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::sendMsg(int rtrBit)
|
||||||
|
{
|
||||||
|
byte res, res1, txbuf_n;
|
||||||
|
uint16_t uiTimeOut = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
res = mcp2515_getNextFreeTXBuf(&txbuf_n); // info = addr.
|
||||||
|
uiTimeOut++;
|
||||||
|
} while (res == MCP_ALLTXBUSY && (uiTimeOut < TIMEOUTVALUE));
|
||||||
|
|
||||||
|
if(uiTimeOut == TIMEOUTVALUE)
|
||||||
|
{
|
||||||
|
return CAN_GETTXBFTIMEOUT; // get tx buff time out
|
||||||
|
}
|
||||||
|
|
||||||
|
uiTimeOut = 0;
|
||||||
|
mcp2515_write_canMsg(txbuf_n, rtrBit);
|
||||||
|
mcp2515_start_transmit(txbuf_n);
|
||||||
|
|
||||||
|
do {
|
||||||
|
uiTimeOut++;
|
||||||
|
res1= mcp2515_readRegister(txbuf_n-1 /* the ctrl reg is located at txbuf_n-1 */); // read send buff ctrl reg
|
||||||
|
res1 = res1 & 0x08;
|
||||||
|
}while(res1 && (uiTimeOut < TIMEOUTVALUE));
|
||||||
|
|
||||||
|
if(uiTimeOut == TIMEOUTVALUE) // send msg timeout
|
||||||
|
{
|
||||||
|
return CAN_SENDMSGTIMEOUT;
|
||||||
|
}
|
||||||
|
return CAN_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: sendMsgBuf
|
||||||
|
** Descriptions: send buf
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::sendMsgBuf(unsigned long id, byte ext, byte rtr, byte len, byte *buf)
|
||||||
|
{
|
||||||
|
setMsg(id, ext, len, rtr, buf);
|
||||||
|
// Serial.print("RTR00: ");
|
||||||
|
// Serial.println(rtr, HEX);
|
||||||
|
return sendMsg(rtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: sendMsgBuf
|
||||||
|
** Descriptions: send buf
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::sendMsgBuf(unsigned long id, byte ext, byte len, byte *buf)
|
||||||
|
{
|
||||||
|
setMsg(id, ext, len, buf);
|
||||||
|
return sendMsg(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: readMsg
|
||||||
|
** Descriptions: read message
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::readMsg()
|
||||||
|
{
|
||||||
|
byte stat, res;
|
||||||
|
|
||||||
|
stat = mcp2515_readStatus();
|
||||||
|
|
||||||
|
if(stat & MCP_STAT_RX0IF) // Msg in Buffer 0
|
||||||
|
{
|
||||||
|
mcp2515_read_canMsg(MCP_RXBUF_0);
|
||||||
|
mcp2515_modifyRegister(MCP_CANINTF, MCP_RX0IF, 0);
|
||||||
|
res = CAN_OK;
|
||||||
|
}
|
||||||
|
else if(stat & MCP_STAT_RX1IF) // Msg in Buffer 1
|
||||||
|
{
|
||||||
|
mcp2515_read_canMsg(MCP_RXBUF_1);
|
||||||
|
mcp2515_modifyRegister(MCP_CANINTF, MCP_RX1IF, 0);
|
||||||
|
res = CAN_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = CAN_NOMSG;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: readMsgBuf
|
||||||
|
** Descriptions: read message buf
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::readMsgBuf(byte *len, byte buf[])
|
||||||
|
{
|
||||||
|
byte rc;
|
||||||
|
|
||||||
|
rc = readMsg();
|
||||||
|
|
||||||
|
if(rc == CAN_OK) {
|
||||||
|
*len = dta_len;
|
||||||
|
for(int i = 0; i<dta_len; i++)
|
||||||
|
{
|
||||||
|
buf[i] = dta[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*len = 0;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: readMsgBufID
|
||||||
|
** Descriptions: read message buf and can bus source ID
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::readMsgBufID(unsigned long *ID, byte *len, byte buf[])
|
||||||
|
{
|
||||||
|
byte rc;
|
||||||
|
rc = readMsg();
|
||||||
|
|
||||||
|
if(rc == CAN_OK) {
|
||||||
|
*len = dta_len;
|
||||||
|
*ID = can_id;
|
||||||
|
for(int i = 0; i<dta_len && i < MAX_CHAR_IN_MESSAGE; i++)
|
||||||
|
{
|
||||||
|
buf[i] = dta[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*len = 0;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: checkReceive
|
||||||
|
** Descriptions: check if got something
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::checkReceive(void)
|
||||||
|
{
|
||||||
|
byte res;
|
||||||
|
res = mcp2515_readStatus(); // RXnIF in Bit 1 and 0
|
||||||
|
return ((res & MCP_STAT_RXIF_MASK)?CAN_MSGAVAIL:CAN_NOMSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: checkError
|
||||||
|
** Descriptions: if something error
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::checkError(void)
|
||||||
|
{
|
||||||
|
byte eflg = mcp2515_readRegister(MCP_EFLG);
|
||||||
|
return ((eflg & MCP_EFLG_ERRORMASK) ? CAN_CTRLERROR : CAN_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: getCanId
|
||||||
|
** Descriptions: when receive something you can get the can id!!
|
||||||
|
*********************************************************************************************************/
|
||||||
|
unsigned long MCP_CAN::getCanId(void)
|
||||||
|
{
|
||||||
|
return can_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: isRemoteRequest
|
||||||
|
** Descriptions: when receive something you can check if it was a request
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::isRemoteRequest(void)
|
||||||
|
{
|
||||||
|
return rtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
** Function name: isExtendedFrame
|
||||||
|
** Descriptions: did we just receive standard 11bit frame or extended 29bit? 0 = std, 1 = ext
|
||||||
|
*********************************************************************************************************/
|
||||||
|
byte MCP_CAN::isExtendedFrame(void)
|
||||||
|
{
|
||||||
|
return ext_flg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************************
|
||||||
|
END FILE
|
||||||
|
*********************************************************************************************************/
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
mcp_can.h
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef _MCP2515_H_
|
||||||
|
#define _MCP2515_H_
|
||||||
|
|
||||||
|
#include "mcp_can_dfs.h"
|
||||||
|
|
||||||
|
#define MAX_CHAR_IN_MESSAGE 8
|
||||||
|
|
||||||
|
class MCP_CAN
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
byte ext_flg; // identifier xxxID
|
||||||
|
// either extended (the 29 LSB) or standard (the 11 LSB)
|
||||||
|
unsigned long can_id; // can id
|
||||||
|
byte dta_len; // data length
|
||||||
|
byte dta[MAX_CHAR_IN_MESSAGE]; // data
|
||||||
|
byte rtr; // rtr
|
||||||
|
byte filhit;
|
||||||
|
byte SPICS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mcp2515 driver function
|
||||||
|
*/
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void mcp2515_reset(void); // reset mcp2515
|
||||||
|
|
||||||
|
byte mcp2515_readRegister(const byte address); // read mcp2515's register
|
||||||
|
|
||||||
|
void mcp2515_readRegisterS(const byte address,
|
||||||
|
byte values[],
|
||||||
|
const byte n);
|
||||||
|
void mcp2515_setRegister(const byte address, // set mcp2515's register
|
||||||
|
const byte value);
|
||||||
|
|
||||||
|
void mcp2515_setRegisterS(const byte address, // set mcp2515's registers
|
||||||
|
const byte values[],
|
||||||
|
const byte n);
|
||||||
|
|
||||||
|
void mcp2515_initCANBuffers(void);
|
||||||
|
|
||||||
|
void mcp2515_modifyRegister(const byte address, // set bit of one register
|
||||||
|
const byte mask,
|
||||||
|
const byte data);
|
||||||
|
|
||||||
|
byte mcp2515_readStatus(void); // read mcp2515's Status
|
||||||
|
byte mcp2515_setCANCTRL_Mode(const byte newmode); // set mode
|
||||||
|
byte mcp2515_configRate(const byte canSpeed); // set boadrate
|
||||||
|
byte mcp2515_init(const byte canSpeed); // mcp2515init
|
||||||
|
|
||||||
|
void mcp2515_write_id( const byte mcp_addr, // write can id
|
||||||
|
const byte ext,
|
||||||
|
const unsigned long id );
|
||||||
|
|
||||||
|
void mcp2515_read_id( const byte mcp_addr, // read can id
|
||||||
|
byte* ext,
|
||||||
|
unsigned long* id );
|
||||||
|
|
||||||
|
void mcp2515_write_canMsg( const byte buffer_sidh_addr, int rtrBit ); // write can msg
|
||||||
|
void mcp2515_read_canMsg( const byte buffer_sidh_addr); // read can msg
|
||||||
|
void mcp2515_start_transmit(const byte mcp_addr); // start transmit
|
||||||
|
byte mcp2515_getNextFreeTXBuf(byte *txbuf_n); // get Next free txbuf
|
||||||
|
|
||||||
|
/*
|
||||||
|
* can operator function
|
||||||
|
*/
|
||||||
|
|
||||||
|
byte setMsg(unsigned long id, byte ext, byte len, byte rtr, byte *pData); // set message
|
||||||
|
byte setMsg(unsigned long id, byte ext, byte len, byte *pData); // set message
|
||||||
|
byte clearMsg(); // clear all message to zero
|
||||||
|
byte readMsg(); // read message
|
||||||
|
byte sendMsg(int rtrBit); // send message
|
||||||
|
|
||||||
|
public:
|
||||||
|
MCP_CAN(byte _CS);
|
||||||
|
byte begin(byte speedset); // init can
|
||||||
|
byte init_Mask(byte num, byte ext, unsigned long ulData); // init Masks
|
||||||
|
byte init_Filt(byte num, byte ext, unsigned long ulData); // init filters
|
||||||
|
byte sendMsgBuf(unsigned long id, byte ext, byte rtr, byte len, byte *buf); // send buf
|
||||||
|
byte sendMsgBuf(unsigned long id, byte ext, byte len, byte *buf); // send buf
|
||||||
|
byte readMsgBuf(byte *len, byte *buf); // read buf
|
||||||
|
byte readMsgBufID(unsigned long *ID, byte *len, byte *buf); // read buf with object ID
|
||||||
|
byte checkReceive(void); // if something received
|
||||||
|
byte checkError(void); // if something error
|
||||||
|
unsigned long getCanId(void); // get can id when receive
|
||||||
|
byte isRemoteRequest(void); // get RR flag when receive
|
||||||
|
byte isExtendedFrame(void); // did we recieve 29bit frame?
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/*********************************************************************************************************
|
||||||
|
END FILE
|
||||||
|
*********************************************************************************************************/
|
|
@ -12,5 +12,4 @@
|
||||||
platform = atmelavr
|
platform = atmelavr
|
||||||
board = megaatmega2560
|
board = megaatmega2560
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps = coryjfowler/mcp_can@^1.5.1
|
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <mcp_can.h>
|
#include <mcp_canbus.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
|
|
||||||
MCP_CAN CAN0(53); // Set CS pin for MCP2515
|
MCP_CAN CAN0(53); // Set CS pin for MCP2515
|
||||||
#define TX_DELAY 50 // Delay between messages
|
#define TX_DELAY 3 // Delay between messages
|
||||||
|
|
||||||
byte sndStat; // Status of the sent message (global variable)
|
byte sndStat; // Status of the sent message (global variable)
|
||||||
|
|
||||||
|
@ -1441,15 +1441,17 @@ void sendCanMessage(unsigned long canId, const char* hexString) {
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
Serial.println("CAN_Waker starting up...");
|
||||||
// Initialize MCP2515
|
// Initialize MCP2515
|
||||||
if (CAN0.begin(MCP_STD, CAN_500KBPS, MCP_8MHZ) == CAN_OK) {
|
if (CAN0.begin(CAN_500KBPS) == CAN_OK) {
|
||||||
Serial.println("MCP2515 Initialized Successfully!");
|
Serial.println("MCP2515 Initialized Successfully!");
|
||||||
} else {
|
} else {
|
||||||
Serial.println("Error Initializing MCP2515...");
|
Serial.println("Error Initializing MCP2515...");
|
||||||
}
|
}
|
||||||
|
|
||||||
CAN0.setMode(MCP_NORMAL); // Change to normal mode
|
//CAN0.setMode(MCP_NORMAL); // Change to normal mode
|
||||||
|
//CAN0.setMode(MODE_ONESHOT); // Change to normal mode
|
||||||
|
delay(2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
Loading…
Reference in a new issue