CAN

Controller-Area Network (CAN) is a bus standard that allows microcontrollers and devices to communicate with each other without going through a host computer.

API

API summary

 
 /* mbed Microcontroller Library
  * Copyright (c) 2006-2013 ARM Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 #ifndef MBED_CAN_H
 #define MBED_CAN_H
 
 #include "platform/platform.h"
 
 #if defined (DEVICE_CAN) || defined(DOXYGEN_ONLY)
 
 #include "hal/can_api.h"
 #include "platform/Callback.h"
 #include "platform/PlatformMutex.h"
 #include "platform/NonCopyable.h"
 
 namespace mbed {
 /** \addtogroup drivers */
 
 /** CANMessage class
  *
  * @note Synchronization level: Thread safe
  * @ingroup drivers
  */
 class CANMessage : public CAN_Message {
 
 public:
  /** Creates empty CAN message.
  */
  CANMessage() : CAN_Message() {
  len = 8;
  type = CANData;
  format = CANStandard;
  id = 0;
  memset(data, 0, 8);
  }
 
  /** Creates CAN message with specific content.
  *
  * @param _id Message ID
  * @param _data Mesaage Data
  * @param _len Message Data length
  * @param _type Type of Data: Use enum CANType for valid parameter values
  * @param _format Data Format: Use enum CANFormat for valid parameter values
  */
  CANMessage(int _id, const char *_data, char _len = 8, CANType _type = CANData, CANFormat _format = CANStandard) {
  len = _len & 0xF;
  type = _type;
  format = _format;
  id = _id;
  memcpy(data, _data, _len);
  }
 
  /** Creates CAN remote message.
  *
  * @param _id Message ID
  * @param _format Data Format: Use enum CANType for valid parameter values
  */
  CANMessage(int _id, CANFormat _format = CANStandard) {
  len = 0;
  type = CANRemote;
  format = _format;
  id = _id;
  memset(data, 0, 8);
  }
 };
 
 /** A can bus client, used for communicating with can devices
  * @ingroup drivers
  */
 class CAN : private NonCopyable<CAN> {
 
 public:
  /** Creates an CAN interface connected to specific pins.
  *
  * @param rd read from transmitter
  * @param td transmit to transmitter
  *
  * Example:
  * @code
  * #include "mbed.h"
  *
  * Ticker ticker;
  * DigitalOut led1(LED1);
  * DigitalOut led2(LED2);
  * CAN can1(p9, p10);
  * CAN can2(p30, p29);
  *
  * char counter = 0;
  *
  * void send() {
  * if(can1.write(CANMessage(1337, &counter, 1))) {
  * printf("Message sent: %d\n", counter);
  * counter++;
  * }
  * led1 = !led1;
  * }
  *
  * int main() {
  * ticker.attach(&send, 1);
  * CANMessage msg;
  * while(1) {
  * if(can2.read(msg)) {
  * printf("Message received: %d\n\n", msg.data[0]);
  * led2 = !led2;
  * }
  * wait(0.2);
  * }
  * }
  * @endcode
  */
  CAN(PinName rd, PinName td);
 
  /** Initialize CAN interface and set the frequency
  *
  * @param rd the rd pin
  * @param td the td pin
  * @param hz the bus frequency in hertz
  */
  CAN(PinName rd, PinName td, int hz);
 
  virtual ~CAN();
 
  /** Set the frequency of the CAN interface
  *
  * @param hz The bus frequency in hertz
  *
  * @returns
  * 1 if successful,
  * 0 otherwise
  */
  int frequency(int hz);
 
  /** Write a CANMessage to the bus.
  *
  * @param msg The CANMessage to write.
  *
  * @returns
  * 0 if write failed,
  * 1 if write was successful
  */
  int write(CANMessage msg);
 
  /** Read a CANMessage from the bus.
  *
  * @param msg A CANMessage to read to.
  * @param handle message filter handle (0 for any message)
  *
  * @returns
  * 0 if no message arrived,
  * 1 if message arrived
  */
  int read(CANMessage &msg, int handle = 0);
 
  /** Reset CAN interface.
  *
  * To use after error overflow.
  */
  void reset();
 
  /** Puts or removes the CAN interface into silent monitoring mode
  *
  * @param silent boolean indicating whether to go into silent mode or not
  */
  void monitor(bool silent);
 
  enum Mode {
  Reset = 0,
  Normal,
  Silent,
  LocalTest,
  GlobalTest,
  SilentTest
  };
 
  /** Change CAN operation to the specified mode
  *
  * @param mode The new operation mode (CAN::Normal, CAN::Silent, CAN::LocalTest, CAN::GlobalTest, CAN::SilentTest)
  *
  * @returns
  * 0 if mode change failed or unsupported,
  * 1 if mode change was successful
  */
  int mode(Mode mode);
 
  /** Filter out incomming messages
  *
  * @param id the id to filter on
  * @param mask the mask applied to the id
  * @param format format to filter on (Default CANAny)
  * @param handle message filter handle (Optional)
  *
  * @returns
  * 0 if filter change failed or unsupported,
  * new filter handle if successful
  */
  int filter(unsigned int id, unsigned int mask, CANFormat format = CANAny, int handle = 0);
 
  /** Detects read errors - Used to detect read overflow errors.
  *
  * @returns number of read errors
  */
  unsigned char rderror();
 
  /** Detects write errors - Used to detect write overflow errors.
  *
  * @returns number of write errors
  */
  unsigned char tderror();
 
  enum IrqType {
  RxIrq = 0,
  TxIrq,
  EwIrq,
  DoIrq,
  WuIrq,
  EpIrq,
  AlIrq,
  BeIrq,
  IdIrq,
 
  IrqCnt
  };
 
  /** Attach a function to call whenever a CAN frame received interrupt is
  * generated.
  *
  * @param func A pointer to a void function, or 0 to set as none
  * @param type Which CAN interrupt to attach the member function to (CAN::RxIrq for message received, CAN::TxIrq for transmitted or aborted, CAN::EwIrq for error warning, CAN::DoIrq for data overrun, CAN::WuIrq for wake-up, CAN::EpIrq for error passive, CAN::AlIrq for arbitration lost, CAN::BeIrq for bus error)
  */
  void attach(Callback<void()> func, IrqType type=RxIrq);
 
  /** Attach a member function to call whenever a CAN frame received interrupt
  * is generated.
  *
  * @param obj pointer to the object to call the member function on
  * @param method pointer to the member function to be called
  * @param type Which CAN interrupt to attach the member function to (CAN::RxIrq for message received, TxIrq for transmitted or aborted, EwIrq for error warning, DoIrq for data overrun, WuIrq for wake-up, EpIrq for error passive, AlIrq for arbitration lost, BeIrq for bus error)
  * @deprecated
  * The attach function does not support cv-qualifiers. Replaced by
  * attach(callback(obj, method), type).
  */
  template<typename T>
  MBED_DEPRECATED_SINCE("mbed-os-5.1",
  "The attach function does not support cv-qualifiers. Replaced by "
  "attach(callback(obj, method), type).")
  void attach(T* obj, void (T::*method)(), IrqType type=RxIrq) {
  // Underlying call thread safe
  attach(callback(obj, method), type);
  }
 
  /** Attach a member function to call whenever a CAN frame received interrupt
  * is generated.
  *
  * @param obj pointer to the object to call the member function on
  * @param method pointer to the member function to be called
  * @param type Which CAN interrupt to attach the member function to (CAN::RxIrq for message received, TxIrq for transmitted or aborted, EwIrq for error warning, DoIrq for data overrun, WuIrq for wake-up, EpIrq for error passive, AlIrq for arbitration lost, BeIrq for bus error)
  * @deprecated
  * The attach function does not support cv-qualifiers. Replaced by
  * attach(callback(obj, method), type).
  */
  template<typename T>
  MBED_DEPRECATED_SINCE("mbed-os-5.1",
  "The attach function does not support cv-qualifiers. Replaced by "
  "attach(callback(obj, method), type).")
  void attach(T* obj, void (*method)(T*), IrqType type=RxIrq) {
  // Underlying call thread safe
  attach(callback(obj, method), type);
  }
 
  static void _irq_handler(uint32_t id, CanIrqType type);
 
 protected:
  virtual void lock();
  virtual void unlock();
  can_t _can;
  Callback<void()> _irq[IrqCnt];
  PlatformMutex _mutex;
 };
 
 } // namespace mbed
 
 #endif
 
 #endif // MBED_CAN_H
 
#define MBED_DEPRECATED_SINCE(D, M)
Definition: mbed_toolchain.h:272
Definition: CAN.h:36
Definition: PlatformMutex.h:30
CANMessage()
Definition: CAN.h:41
Callback< R()> callback(R(*func)()=0)
Definition: Callback.h:3536
CANMessage(int _id, const char *_data, char _len=8, CANType _type=CANData, CANFormat _format=CANStandard)
Definition: CAN.h:57
Definition: NonCopyable.h:141
Definition: Callback.h:35
Definition: CAN.h:82
Definition: AnalogIn.h:27
CANMessage(int _id, CANFormat _format=CANStandard)
Definition: CAN.h:70

Hello World!

This example sends a counter from one CAN bus (can1) and listens for a packet on the other CAN bus (can2). Each bus controller should be connected to a CAN bus transceiver. These should be connected together at a CAN bus.

 


#include "mbed.h"

Ticker ticker;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
CAN can1(MBED_CONF_APP_CAN1_RD, MBED_CONF_APP_CAN1_TD);
CAN can2(MBED_CONF_APP_CAN2_RD, MBED_CONF_APP_CAN2_TD);
char counter = 0;

void send() {
    printf("send()\n");
    if(can1.write(CANMessage(1337, &counter, 1))) {
        printf("wloop()\n");
        counter++;
        printf("Message sent: %d\n", counter);
    } 
    led1 = !led1;
}

int main() {
    printf("main()\n");
    ticker.attach(&send, 1);
    CANMessage msg;
    while(1) {
        printf("loop()\n");
        if(can2.read(msg)) {
            printf("Message received: %d\n", msg.data[0]);
            led2 = !led2;
        } 
        wait(0.2);
    }
}

Details

You can use the CAN interface to write data words out of a CAN port. It will return the data received from another CAN device. You can configure the CAN clock frequency.

Additional resources