diff --git a/libraries/Arduino_CAN/examples/CANRead/CANRead.ino b/libraries/Arduino_CAN/examples/CANRead/CANRead.ino new file mode 100644 index 000000000..9b2e34a77 --- /dev/null +++ b/libraries/Arduino_CAN/examples/CANRead/CANRead.ino @@ -0,0 +1,30 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + +void setup() +{ + Serial.begin(115200); + while (!Serial) { } + + if (!CAN.begin(CanBitRate::BR_250k)) + { + Serial.println("CAN.begin(...) failed."); + for (;;) {} + } +} + +void loop() +{ + if (CAN.available()) + { + CanMsg const msg = CAN.read(); + Serial.println(msg); + } +} diff --git a/libraries/Arduino_CAN/examples/CANWrite/CANWrite.ino b/libraries/Arduino_CAN/examples/CANWrite/CANWrite.ino new file mode 100644 index 000000000..522f6c345 --- /dev/null +++ b/libraries/Arduino_CAN/examples/CANWrite/CANWrite.ino @@ -0,0 +1,55 @@ +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include + +/************************************************************************************** + * CONSTANTS + **************************************************************************************/ + +static uint32_t const CAN_ID = 0x20; + +/************************************************************************************** + * SETUP/LOOP + **************************************************************************************/ + +void setup() +{ + Serial.begin(115200); + while (!Serial) { } + + if (!CAN.begin(CanBitRate::BR_250k)) + { + Serial.println("CAN.begin(...) failed."); + for (;;) {} + } +} + +static uint32_t msg_cnt = 0; + +void loop() +{ + /* Assemble a CAN message with the format of + * 0xCA 0xFE 0x00 0x00 [4 byte message counter] + */ + uint8_t const msg_data[] = {0xCA,0xFE,0,0,0,0,0,0}; + memcpy((void *)(msg_data + 4), &msg_cnt, sizeof(msg_cnt)); + CanMsg msg(CAN_ID, sizeof(msg_data), msg_data); + + /* Transmit the CAN message, capture and display an + * error core in case of failure. + */ + if (int const rc = CAN.write(msg); rc <= 0) + { + Serial.print ("CAN.write(...) failed with error code "); + Serial.println(rc); + for (;;) { } + } + + /* Increase the message counter. */ + msg_cnt++; + + /* Only send one message per second. */ + delay(1000); +} diff --git a/libraries/Arduino_CAN/extras/scripts/README.md b/libraries/Arduino_CAN/extras/scripts/README.md new file mode 100644 index 000000000..6493734b1 --- /dev/null +++ b/libraries/Arduino_CAN/extras/scripts/README.md @@ -0,0 +1,16 @@ +`extras/scripts` +================ +This directory contains helpful shell scripts when working with CAN. + +### How-to-`SocketCAN` +```bash +sudo ./setup_scan.sh +``` +Display received CAN frames via [`candump`](https://manpages.ubuntu.com/manpages/jammy/man1/candump.1.html): +```bash +candump can0 +``` +Transmit CAN frames via [`cansend`](https://manpages.ubuntu.com/manpages/jammy/man1/cansend.1.html): +```bash +cansend can0 00001234#DEADBEEF +``` diff --git a/libraries/Arduino_CAN/extras/scripts/setup_scan.sh b/libraries/Arduino_CAN/extras/scripts/setup_scan.sh new file mode 100755 index 000000000..2ad84a704 --- /dev/null +++ b/libraries/Arduino_CAN/extras/scripts/setup_scan.sh @@ -0,0 +1,4 @@ +#!/bin/bash +sudo ip link set can0 type can bitrate 250000 +sudo ip link set can0 up + diff --git a/libraries/Arduino_CAN/keywords.txt b/libraries/Arduino_CAN/keywords.txt new file mode 100644 index 000000000..81d46a86d --- /dev/null +++ b/libraries/Arduino_CAN/keywords.txt @@ -0,0 +1,32 @@ +####################################### +# Syntax Coloring Map for CAN +####################################### + +####################################### +# Class (KEYWORD1) +####################################### + +CAN KEYWORD1 +CAN1 KEYWORD1 +CanMsg KEYWORD1 +CanBitRate KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +write KEYWORD2 +available KEYWORD2 +read KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +BR_100k LITERAL1 +BR_125k LITERAL1 +BR_250k LITERAL1 +BR_500k LITERAL1 +BR_1000k LITERAL1 diff --git a/libraries/Arduino_CAN/library.properties b/libraries/Arduino_CAN/library.properties new file mode 100644 index 000000000..4b4eb945e --- /dev/null +++ b/libraries/Arduino_CAN/library.properties @@ -0,0 +1,10 @@ +name=Arduino_CAN +version=1.0.0 +author=Arduino +maintainer=Arduino +sentence=CAN communication library for ArduinoCore-mbed enabled boards. +paragraph=This library provides CAN for ArduinoCore-mbed enabled boards which expose CAN on their connectors. +category=Other +url= +architectures=mbed,mbed_portenta +include=Arduino_CAN.h diff --git a/libraries/Arduino_CAN/src/Arduino_CAN.cpp b/libraries/Arduino_CAN/src/Arduino_CAN.cpp new file mode 100644 index 000000000..fce0ce3a2 --- /dev/null +++ b/libraries/Arduino_CAN/src/Arduino_CAN.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2022 by Alexander Entinger + * Arduino_CAN library for Arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "Arduino_CAN.h" + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +namespace arduino +{ + +/************************************************************************************** + * CTOR/DTOR + **************************************************************************************/ + +Arduino_CAN::Arduino_CAN(PinName const can_tx_pin, PinName const can_rx_pin) +: _can(can_rx_pin, can_tx_pin) +{ + +} + +/************************************************************************************** + * PUBLIC MEMBER FUNCTIONS + **************************************************************************************/ + +bool Arduino_CAN::begin(CanBitRate const can_bitrate) +{ + int const rc = _can.frequency(static_cast(can_bitrate)); + return (rc == 1); +} + +void Arduino_CAN::end() +{ + /* Nothing to do. */ +} + +int Arduino_CAN::write(CanMsg const & msg) +{ + mbed::CANMessage const can_msg( + msg.id, + msg.data, + msg.data_length, + CANData, + CANStandard); + + return _can.write(can_msg); +} + +size_t Arduino_CAN::available() +{ + mbed::CANMessage can_msg; + bool const msg_read = _can.read(can_msg) > 0; + + if (msg_read) + { + CanMsg const msg( + can_msg.id, + can_msg.len, + can_msg.data); + + _rx_msg_buf.enqueue(msg); + } + + return _rx_msg_buf.available(); +} + +CanMsg Arduino_CAN::read() +{ + return _rx_msg_buf.dequeue(); +} + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +} /* arduino */ + +/************************************************************************************** + * OBJECT INSTANTIATION + **************************************************************************************/ + +#if CAN_HOWMANY > 0 +arduino::Arduino_CAN CAN(PIN_CAN0_TX, PIN_CAN0_RX); +#endif + +#if CAN_HOWMANY > 1 +arduino::Arduino_CAN CAN1(PIN_CAN1_TX, PIN_CAN1_RX); +#endif diff --git a/libraries/Arduino_CAN/src/Arduino_CAN.h b/libraries/Arduino_CAN/src/Arduino_CAN.h new file mode 100644 index 000000000..095fc89db --- /dev/null +++ b/libraries/Arduino_CAN/src/Arduino_CAN.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022 by Alexander Entinger + * CAN library for Arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef ARDUINO_CORE_MBED_CAN_H_ +#define ARDUINO_CORE_MBED_CAN_H_ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include +#include + +#include "api/HardwareCAN.h" + +/************************************************************************************** + * COMPILE TIME CHECKS + **************************************************************************************/ + +#if !(defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) || defined(ARDUINO_GIGA)) +# error "CAN only available on Arduino Portenta H7 and Arduino Giga (of all ArduinoCore-mbed enabled boards)." +#endif + +/************************************************************************************** + * TYPEDEF + **************************************************************************************/ + +typedef arduino::CanMsg CanMsg; + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +namespace arduino +{ + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class Arduino_CAN final : public HardwareCAN +{ +public: + Arduino_CAN(PinName const can_tx_pin, PinName const can_rx_pin); + virtual ~Arduino_CAN() { } + + + bool begin(CanBitRate const can_bitrate) override; + void end() override; + + + int write(CanMsg const & msg) override; + size_t available() override; + CanMsg read() override; + +private: + mbed::CAN _can; + CanMsgRingbuffer _rx_msg_buf; +}; + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +} /* arduino */ + +/************************************************************************************** + * EXTERN DECLARATION + **************************************************************************************/ + +#if CAN_HOWMANY > 0 +extern arduino::Arduino_CAN CAN; +#endif + +#if CAN_HOWMANY > 1 +extern arduino::Arduino_CAN CAN1; +#endif + +#endif /* ARDUINO_CORE_MBED_CAN_H_ */ diff --git a/variants/GIGA/pins_arduino.h b/variants/GIGA/pins_arduino.h index e17d1190a..231eb2c14 100644 --- a/variants/GIGA/pins_arduino.h +++ b/variants/GIGA/pins_arduino.h @@ -263,4 +263,12 @@ void _ontouch1200bps_(); #define USB_MAX_POWER (500) +#define CAN_HOWMANY 2 + +#define PIN_CAN0_TX (PB_13) +#define PIN_CAN0_RX (PB_12) + +#define PIN_CAN1_TX (PH_13) +#define PIN_CAN1_RX (PB_8) + #endif //__PINS_ARDUINO__ diff --git a/variants/PORTENTA_H7_M4/pins_arduino.h b/variants/PORTENTA_H7_M4/pins_arduino.h index e54178535..98b9d7f8f 100644 --- a/variants/PORTENTA_H7_M4/pins_arduino.h +++ b/variants/PORTENTA_H7_M4/pins_arduino.h @@ -8,4 +8,4 @@ #include "../GIGA/pins_arduino.h" #endif -#undef SERIAL_CDC \ No newline at end of file +#undef SERIAL_CDC diff --git a/variants/PORTENTA_H7_M4/variant.cpp b/variants/PORTENTA_H7_M4/variant.cpp index c949632aa..edb8add1b 100644 --- a/variants/PORTENTA_H7_M4/variant.cpp +++ b/variants/PORTENTA_H7_M4/variant.cpp @@ -12,4 +12,4 @@ #undef initVariant -void initVariant() {} \ No newline at end of file +void initVariant() {} diff --git a/variants/PORTENTA_H7_M7/pins_arduino.h b/variants/PORTENTA_H7_M7/pins_arduino.h index 45fde5367..aa525e31a 100644 --- a/variants/PORTENTA_H7_M7/pins_arduino.h +++ b/variants/PORTENTA_H7_M7/pins_arduino.h @@ -164,4 +164,9 @@ void _ontouch1200bps_(); #define USB_MAX_POWER (500) +#define CAN_HOWMANY 1 + +#define PIN_CAN0_TX (PH_13) /* Labeled CAN1_TX on high-density connector. */ +#define PIN_CAN0_RX (PB_8) /* Labeled CAN1_RX on high-density connector. */ + #endif //__PINS_ARDUINO__ diff --git a/variants/PORTENTA_H7_M7/variant.cpp b/variants/PORTENTA_H7_M7/variant.cpp index 4e85cf618..83e800c49 100644 --- a/variants/PORTENTA_H7_M7/variant.cpp +++ b/variants/PORTENTA_H7_M7/variant.cpp @@ -78,7 +78,7 @@ PinDescription g_APinDescription[] = { { PB_5, NULL, NULL, NULL }, { PB_6, NULL, NULL, NULL }, { PB_7, NULL, NULL, NULL }, - { PB_8, NULL, NULL, NULL }, + { PB_8, NULL, NULL, NULL }, // HD-connector: CAN1_RX -> software object: CAN { PB_9, NULL, NULL, NULL }, { PB_10, NULL, NULL, NULL }, { PB_11, NULL, NULL, NULL }, @@ -179,7 +179,7 @@ PinDescription g_APinDescription[] = { { PH_10, NULL, NULL, NULL }, { PH_11, NULL, NULL, NULL }, { PH_12, NULL, NULL, NULL }, - { PH_13, NULL, NULL, NULL }, + { PH_13, NULL, NULL, NULL }, // HD-connector: CAN1_TX -> software object: CAN { PH_14, NULL, NULL, NULL }, { PH_15, NULL, NULL, NULL }, { PI_0, NULL, NULL, NULL },