Controller Area Network library for NUCLEO boards equipped with CAN peripheral.

Dependents:   Nucleo-Courtois CANBLE CANnucleo_Hello3 Nucleo_Serialprintf ... more

Controller Area Network library for the NUCLEO and DISCOVERY boards equipped with CAN peripheral


Information

Because CAN support has been finally implemented into the mbed library also for the ST boards there is no need to use the CANnucleo library anymore (however you may if you want). The CAN_Hello example is trying to demonstrate the mbed built-in CAN API with NUCLEO boards.


Provides CAN support for the following boards:

with the following features:

  • Easy to use. Delete the mbed library from your project and import the latest mbed-dev and CANnucleo libraries. In the mbed-dev library open the device.h file associated with the selected target board and add #undef DEVICE_CAN as follows:

device.h

#ifndef MBED_DEVICE_H
#define MBED_DEVICE_H

//=======================================
#define DEVICE_ID_LENGTH       24

#undef DEVICE_CAN

#include "objects.h"

#endif

See the CANnucleo_Hello demo for more details.

  • Automatic recovery from bus-off state can be enabled/disabled in the constructor (defaults to ENABLE).
  • Up to 14 filters (0 - 13) are available for the application to set up for message filtering performed by hardware.
    For more details see below or have a look at the comments in CANnucleo.cpp.
  • One CAN channel per NUCLEO board is supported. The CAN peripheral can be connected either to pins PA_11, PA_12 (Receiver, Transmitter) or to pins PB_8, PB_9 (Receiver, Transmitter). This is configured when creating a CAN instance.
  • Simplifies adding/getting data to/from a CAN message by using the << (append) and the >> (extract) operators.

Import programCANnucleo_Hello

Using CAN bus with NUCLEO boards (Demo for the CANnucleo library).



Filtering performed by the built-in CAN controller without disturbing the CPU

CANnucleo supports only mask mode and 32-bit filter scale. Identifier list mode filtering and 16-bit filter scale are not supported. There are 14 filters available (0 - 13) for the application to set up. Each filter is a 32-bit filter defined by a filter ID and a filter mask. If no filter is set up then no CAN message is accepted! That's why filter #0 is set up in the constructor to accept all CAN messages by default. On reception of a message it is compared with filter #0. If there is a match, the message is accepted and stored. If there is no match, the incoming identifier is then compared with the next filter. If the received identifier does not match any of the identifiers configured in the filters, the message is discarded by hardware without disturbing the software.

CAN filter function - designed to setup a CAN filter

int CAN::filter(unsigned int id, unsigned int mask, CANFormat format, int handle)

Parameters

id - 'Filter ID' defines the bit values to be compared with the corresponding received bits.

Mapping of 32-bits (4-bytes) :

STID[10:3]STID[2:0] EXID[17:13]EXID[12:5]EXID[4:0] IDE RTR 0
  • STID - Stardard Identifier bits
  • EXID - Extended Identifier bits
  • [x:y]- bit range
  • IDE - Identifier Extension bit (0 -> Standard Identifier, 1 -> Extended Identifier)
  • RTR - Remote Transmission Request bit (0 -> Remote Transmission Request, 1 -> Standard message)

mask - 'Filter mask' defines which bits of the 'Filter ID' are compared with the received bits and which are disregarded.
Mapping of 32-bits (4-bytes) :

STID[10:3]STID[2:0] EXID[17:13]EXID[12:5]EXID[4:0] IDE RTR 0
  • STID - Stardard Identifier bits
  • EXID - Extended Identifier bits
  • [x:y]- bit range
  • IDE - Identifier Extension bit
  • RTR - Remote Transmission Request bit
  • 1 -> bit is considered
  • 0 -> bit is disregarded

format - This parameter must be CANAny
handle - Selects the filter. This parameter must be a number between 0 and 13.
retval - 0 - successful, 1 - error, 2 - busy, 3 - time out

Example of filter set up and filtering

Let's assume we would like to accept only messages with standard identifier 0x207:

STID[15:0] = 0x207 = 00000010 00000111


We map the STID to filter ID by shifting the bits adequately:

Filter ID = STID << (16 + (15 - 10)) = STID << 21 = 01000000 11100000 00000000 00000000


To compare only the bits representing STID we set the filter mask appropriately:

Filter mask = 11111111 11100000 00000000 00000100 = 0xFFE00004
              |||||||| |||                    |
              -------- ---                    |
                  |     |                     |
           STID[10:3]  STID[2:0]             IDE


Recall that filter #0 has been set up in the constructor to accept all CAN messages by default. So we have to reconfigure it. If we were set up filter #1 here then filter #0 would accept all the messages and no message would reach filter #1!
To reconfigure (set up) filter #0 we call:

can.filter(0x207 << 21, 0xFFE00004, CANAny, 0);


            Only these bits of 'Filter id' (set to 1 here in 'Filter mask') are compared 
            with the corresponding bits of received message (the others are disregarded)
                                |
                 ---------------------------------
                 |||||||| |||                    |
   Filter mask = 11111111 11100000 00000000 00000100 (= 0xFFE00004)
   Filter id   = 01000000 11100000 00000000 00000000 (= 0x40E00000)
                 |||||||| |||                    |
                 ---------------------------------
                                |
            To accept the message the values of these bits must match.
            Otherwise the message is passed to the next filter or
            discarded if this was the last active filter.
                                |
                 ---------------------------------
                 |||||||| |||                    |
   Received id = 01000000 11100000 00000000 00000010 (= 0x40E00002)
                             ||||| |||||||| ||||| ||
                             -----------------------
                                         |
                          These bits (set to 0 in 'Filter mask') are disregarded (masked).
                          They can have arbitrary values.


NOTE: For the meaning of individual bits see the mapping of 32-bits explained above.

We can use the filter function to setup more (up to 14) CAN filters for example as follows:

can.filter(0x207 << 21, 0xFFE00004, CANAny, 0);    // filter #0
can.filter(0x251 << 21, 0xFFE00004, CANAny, 1);    // filter #1
can.filter(0x304 << 21, 0xFFE00004, CANAny, 2);    // filter #2
...
Committer:
hudakz
Date:
Sun Dec 25 14:03:41 2016 +0000
Revision:
25:173eea49222f
Parent:
23:c5d348e65e24
Child:
26:321a5b290148
CAN speed corrected for NUCLEO-F303K8.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:e29bc8e0dddd 1 /*
hudakz 5:b53e5ee15315 2 ******************************************************************************
hudakz 5:b53e5ee15315 3 * @file can_api.c
hudakz 5:b53e5ee15315 4 * @author Zoltan Hudak
hudakz 5:b53e5ee15315 5 * @version
hudakz 5:b53e5ee15315 6 * @date 04-August-2015
hudakz 5:b53e5ee15315 7 * @brief CAN api for NUCLEO-F103RB platform
hudakz 5:b53e5ee15315 8 ******************************************************************************
hudakz 5:b53e5ee15315 9 * @attention
hudakz 5:b53e5ee15315 10 *
hudakz 5:b53e5ee15315 11 * <h2><center>&copy; COPYRIGHT(c) 2015 Zoltan Hudak <hudakz@inbox.com>
hudakz 5:b53e5ee15315 12 *
hudakz 5:b53e5ee15315 13 * All rights reserved.
hudakz 0:e29bc8e0dddd 14
hudakz 0:e29bc8e0dddd 15 This program is free software: you can redistribute it and/or modify
hudakz 0:e29bc8e0dddd 16 it under the terms of the GNU General Public License as published by
hudakz 0:e29bc8e0dddd 17 the Free Software Foundation, either version 3 of the License, or
hudakz 0:e29bc8e0dddd 18 (at your option) any later version.
hudakz 0:e29bc8e0dddd 19
hudakz 0:e29bc8e0dddd 20 This program is distributed in the hope that it will be useful,
hudakz 0:e29bc8e0dddd 21 but WITHOUT ANY WARRANTY; without even the implied warranty of
hudakz 0:e29bc8e0dddd 22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
hudakz 0:e29bc8e0dddd 23 GNU General Public License for more details.
hudakz 0:e29bc8e0dddd 24
hudakz 0:e29bc8e0dddd 25 You should have received a copy of the GNU General Public License
hudakz 0:e29bc8e0dddd 26 along with this program. If not, see <http://www.gnu.org/licenses/>.
hudakz 0:e29bc8e0dddd 27 */
hudakz 23:c5d348e65e24 28 #include "cannucleo_api.h"
hudakz 0:e29bc8e0dddd 29 #include "can_helper.h"
hudakz 0:e29bc8e0dddd 30 #include "pinmap.h"
hudakz 0:e29bc8e0dddd 31
hudakz 20:bcd8161f8f6c 32 extern void (*rxCompleteCallback)(void);
hudakz 20:bcd8161f8f6c 33 extern CAN_HandleTypeDef _canHandle;
hudakz 20:bcd8161f8f6c 34
hudakz 20:bcd8161f8f6c 35 static uint32_t irq_id = 0;
hudakz 20:bcd8161f8f6c 36 static can_irq_handler irq_handler = 0;
hudakz 0:e29bc8e0dddd 37
hudakz 0:e29bc8e0dddd 38 /**
hudakz 0:e29bc8e0dddd 39 * @brief
hudakz 0:e29bc8e0dddd 40 * @note
hudakz 0:e29bc8e0dddd 41 * @param
hudakz 0:e29bc8e0dddd 42 * @retval
hudakz 0:e29bc8e0dddd 43 */
hudakz 20:bcd8161f8f6c 44 void can_init(PinName rd, PinName td, FunctionalState abom) {
hudakz 20:bcd8161f8f6c 45 initCAN(rd, td, abom);
hudakz 20:bcd8161f8f6c 46 can_filter(0, 0, CANAny, 0);
hudakz 0:e29bc8e0dddd 47 }
hudakz 0:e29bc8e0dddd 48
hudakz 0:e29bc8e0dddd 49 /**
hudakz 0:e29bc8e0dddd 50 * @brief
hudakz 0:e29bc8e0dddd 51 * @note
hudakz 0:e29bc8e0dddd 52 * @param
hudakz 0:e29bc8e0dddd 53 * @retval
hudakz 0:e29bc8e0dddd 54 */
hudakz 20:bcd8161f8f6c 55 void can_free(void) {
hudakz 15:5123ead7b002 56 HAL_CAN_MspDeInit(&_canHandle);
hudakz 0:e29bc8e0dddd 57 }
hudakz 0:e29bc8e0dddd 58
hudakz 0:e29bc8e0dddd 59 /**
hudakz 0:e29bc8e0dddd 60 * @brief
hudakz 0:e29bc8e0dddd 61 * @note
hudakz 0:e29bc8e0dddd 62 * @param
hudakz 0:e29bc8e0dddd 63 * @retval
hudakz 0:e29bc8e0dddd 64 */
hudakz 20:bcd8161f8f6c 65 int can_frequency(int hz) {
hudakz 15:5123ead7b002 66 HAL_NVIC_DisableIRQ(CAN_IRQ);
hudakz 16:f4c8f45bded9 67
hudakz 16:f4c8f45bded9 68 #if defined(TARGET_NUCLEO_F072RB) || \
hudakz 16:f4c8f45bded9 69 defined(TARGET_NUCLEO_F091RC)
hudakz 16:f4c8f45bded9 70
hudakz 16:f4c8f45bded9 71 // APB1 peripheral clock = 48000000Hz
hudakz 16:f4c8f45bded9 72
hudakz 16:f4c8f45bded9 73 switch(hz) {
hudakz 16:f4c8f45bded9 74 case 1000000:
hudakz 16:f4c8f45bded9 75 // 1000kbps bit rate
hudakz 16:f4c8f45bded9 76 _canHandle.Init.Prescaler = 4; // number of time quanta = 48000000/4/1000000 = 12
hudakz 16:f4c8f45bded9 77 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 16:f4c8f45bded9 78 _canHandle.Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75%
hudakz 16:f4c8f45bded9 79 _canHandle.Init.BS2 = CAN_BS2_3TQ;
hudakz 16:f4c8f45bded9 80 break;
hudakz 16:f4c8f45bded9 81
hudakz 16:f4c8f45bded9 82 case 500000:
hudakz 16:f4c8f45bded9 83 // 500kbps bit rate
hudakz 16:f4c8f45bded9 84 _canHandle.Init.Prescaler = 8; // number of time quanta = 48000000/8/500000 = 12
hudakz 16:f4c8f45bded9 85 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 16:f4c8f45bded9 86 _canHandle.Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75%
hudakz 16:f4c8f45bded9 87 _canHandle.Init.BS2 = CAN_BS2_3TQ;
hudakz 16:f4c8f45bded9 88 break;
hudakz 16:f4c8f45bded9 89
hudakz 16:f4c8f45bded9 90 case 250000:
hudakz 16:f4c8f45bded9 91 // 250kbps
hudakz 16:f4c8f45bded9 92 _canHandle.Init.Prescaler = 12; // number of time quanta = 48000000/12/250000 = 16
hudakz 16:f4c8f45bded9 93 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 16:f4c8f45bded9 94 _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75%
hudakz 16:f4c8f45bded9 95 _canHandle.Init.BS2 = CAN_BS2_4TQ;
hudakz 16:f4c8f45bded9 96 break;
hudakz 16:f4c8f45bded9 97
hudakz 16:f4c8f45bded9 98 case 125000:
hudakz 16:f4c8f45bded9 99 // 125kbps
hudakz 16:f4c8f45bded9 100 _canHandle.Init.Prescaler = 24; // number of time quanta = 48000000/24/125000 = 16
hudakz 16:f4c8f45bded9 101 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 16:f4c8f45bded9 102 _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75%
hudakz 16:f4c8f45bded9 103 _canHandle.Init.BS2 = CAN_BS2_4TQ;
hudakz 16:f4c8f45bded9 104 break;
hudakz 16:f4c8f45bded9 105
hudakz 16:f4c8f45bded9 106 default:
hudakz 16:f4c8f45bded9 107 // 125kbps (default)
hudakz 16:f4c8f45bded9 108 _canHandle.Init.Prescaler = 24; // number of time quanta = 48000000/24/125000 = 16
hudakz 16:f4c8f45bded9 109 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 16:f4c8f45bded9 110 _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75%
hudakz 16:f4c8f45bded9 111 _canHandle.Init.BS2 = CAN_BS2_4TQ;
hudakz 16:f4c8f45bded9 112 }
hudakz 0:e29bc8e0dddd 113
hudakz 16:f4c8f45bded9 114 #elif defined(TARGET_NUCLEO_F103RB) || \
hudakz 16:f4c8f45bded9 115 defined(TARGET_NUCLEO_F303RE) || \
hudakz 16:f4c8f45bded9 116 defined(TARGET_NUCLEO_F303K8) || \
hudakz 16:f4c8f45bded9 117 defined(TARGET_NUCLEO_F334R8) || \
hudakz 16:f4c8f45bded9 118 defined(TARGET_DISCO_F334C8)
hudakz 16:f4c8f45bded9 119
hudakz 5:b53e5ee15315 120 // APB1 peripheral clock = 36000000Hz
hudakz 0:e29bc8e0dddd 121
hudakz 0:e29bc8e0dddd 122 switch(hz) {
hudakz 0:e29bc8e0dddd 123 case 1000000:
hudakz 0:e29bc8e0dddd 124 // 1000kbps bit rate
hudakz 0:e29bc8e0dddd 125 _canHandle.Init.Prescaler = 3; // number of time quanta = 36000000/3/1000000 = 12
hudakz 0:e29bc8e0dddd 126 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 0:e29bc8e0dddd 127 _canHandle.Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75%
hudakz 0:e29bc8e0dddd 128 _canHandle.Init.BS2 = CAN_BS2_3TQ;
hudakz 0:e29bc8e0dddd 129 break;
hudakz 0:e29bc8e0dddd 130
hudakz 0:e29bc8e0dddd 131 case 500000:
hudakz 0:e29bc8e0dddd 132 // 500kbps bit rate
hudakz 0:e29bc8e0dddd 133 _canHandle.Init.Prescaler = 6; // number of time quanta = 36000000/6/500000 = 12
hudakz 0:e29bc8e0dddd 134 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 0:e29bc8e0dddd 135 _canHandle.Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75%
hudakz 0:e29bc8e0dddd 136 _canHandle.Init.BS2 = CAN_BS2_3TQ;
hudakz 0:e29bc8e0dddd 137 break;
hudakz 0:e29bc8e0dddd 138
hudakz 0:e29bc8e0dddd 139 case 250000:
hudakz 0:e29bc8e0dddd 140 // 250kbps
hudakz 0:e29bc8e0dddd 141 _canHandle.Init.Prescaler = 9; // number of time quanta = 36000000/9/250000 = 16
hudakz 0:e29bc8e0dddd 142 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 0:e29bc8e0dddd 143 _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75%
hudakz 0:e29bc8e0dddd 144 _canHandle.Init.BS2 = CAN_BS2_4TQ;
hudakz 0:e29bc8e0dddd 145 break;
hudakz 0:e29bc8e0dddd 146
hudakz 0:e29bc8e0dddd 147 case 125000:
hudakz 0:e29bc8e0dddd 148 // 125kbps
hudakz 0:e29bc8e0dddd 149 _canHandle.Init.Prescaler = 18; // number of time quanta = 36000000/18/125000 = 16
hudakz 0:e29bc8e0dddd 150 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 0:e29bc8e0dddd 151 _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75%
hudakz 0:e29bc8e0dddd 152 _canHandle.Init.BS2 = CAN_BS2_4TQ;
hudakz 0:e29bc8e0dddd 153 break;
hudakz 0:e29bc8e0dddd 154
hudakz 0:e29bc8e0dddd 155 default:
hudakz 0:e29bc8e0dddd 156 // 125kbps (default)
hudakz 5:b53e5ee15315 157 #if DEBUG
hudakz 0:e29bc8e0dddd 158 printf("Unknown frequency specified!\r\n");
hudakz 0:e29bc8e0dddd 159 printf("Using default 125kbps\r\n");
hudakz 5:b53e5ee15315 160 #endif
hudakz 17:1fd35431ee8e 161 _canHandle.Init.Prescaler = 18; // number of time quanta = 36000000/18/125000 = 16
hudakz 16:f4c8f45bded9 162 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 17:1fd35431ee8e 163 _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75%
hudakz 16:f4c8f45bded9 164 _canHandle.Init.BS2 = CAN_BS2_4TQ;
hudakz 16:f4c8f45bded9 165 }
hudakz 16:f4c8f45bded9 166
hudakz 25:173eea49222f 167 #elif defined(TARGET_NUCLEO_F303K8)
hudakz 25:173eea49222f 168
hudakz 25:173eea49222f 169 // APB1 peripheral clock = 32000000Hz
hudakz 25:173eea49222f 170
hudakz 25:173eea49222f 171 switch(hz) {
hudakz 25:173eea49222f 172 case 1000000:
hudakz 25:173eea49222f 173 // 1000kbps bit rate
hudakz 25:173eea49222f 174 _canHandle.Init.Prescaler = 2; // number of time quanta = 32000000/2/1000000 = 16
hudakz 25:173eea49222f 175 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 25:173eea49222f 176 _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75%
hudakz 25:173eea49222f 177 _canHandle.Init.BS2 = CAN_BS2_4TQ;
hudakz 25:173eea49222f 178 break;
hudakz 25:173eea49222f 179
hudakz 25:173eea49222f 180 case 500000:
hudakz 25:173eea49222f 181 // 500kbps bit rate
hudakz 25:173eea49222f 182 _canHandle.Init.Prescaler = 4; // number of time quanta = 32000000/4/500000 = 16
hudakz 25:173eea49222f 183 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 25:173eea49222f 184 _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75%
hudakz 25:173eea49222f 185 _canHandle.Init.BS2 = CAN_BS2_4TQ;
hudakz 25:173eea49222f 186 break;
hudakz 25:173eea49222f 187
hudakz 25:173eea49222f 188 case 250000:
hudakz 25:173eea49222f 189 // 250kbps
hudakz 25:173eea49222f 190 _canHandle.Init.Prescaler = 8; // number of time quanta = 32000000/8/250000 = 16
hudakz 25:173eea49222f 191 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 25:173eea49222f 192 _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75%
hudakz 25:173eea49222f 193 _canHandle.Init.BS2 = CAN_BS2_4TQ;
hudakz 25:173eea49222f 194 break;
hudakz 25:173eea49222f 195
hudakz 25:173eea49222f 196 case 125000:
hudakz 25:173eea49222f 197 // 125kbps
hudakz 25:173eea49222f 198 _canHandle.Init.Prescaler = 16; // number of time quanta = 32000000/16/125000 = 16
hudakz 25:173eea49222f 199 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 25:173eea49222f 200 _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75%
hudakz 25:173eea49222f 201 _canHandle.Init.BS2 = CAN_BS2_4TQ;
hudakz 25:173eea49222f 202 break;
hudakz 25:173eea49222f 203
hudakz 25:173eea49222f 204 default:
hudakz 25:173eea49222f 205 // 125kbps (default)
hudakz 25:173eea49222f 206 #if DEBUG
hudakz 25:173eea49222f 207 printf("Unknown frequency specified!\r\n");
hudakz 25:173eea49222f 208 printf("Using default 125kbps\r\n");
hudakz 25:173eea49222f 209 #endif
hudakz 25:173eea49222f 210 _canHandle.Init.Prescaler = 16; // number of time quanta = 32000000/16/125000 = 16
hudakz 25:173eea49222f 211 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 25:173eea49222f 212 _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75%
hudakz 25:173eea49222f 213 _canHandle.Init.BS2 = CAN_BS2_4TQ;
hudakz 25:173eea49222f 214 }
hudakz 25:173eea49222f 215
hudakz 16:f4c8f45bded9 216 #elif defined(TARGET_NUCLEO_F446RE)
hudakz 16:f4c8f45bded9 217
hudakz 16:f4c8f45bded9 218 // APB1 peripheral clock = 45000000Hz
hudakz 16:f4c8f45bded9 219
hudakz 16:f4c8f45bded9 220 switch(hz) {
hudakz 16:f4c8f45bded9 221 case 1000000:
hudakz 16:f4c8f45bded9 222 // 1000kbps bit rate
hudakz 16:f4c8f45bded9 223 _canHandle.Init.Prescaler = 5; // number of time quanta = 45000000/5/1000000 = 9
hudakz 16:f4c8f45bded9 224 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 16:f4c8f45bded9 225 _canHandle.Init.BS1 = CAN_BS1_6TQ; // sample point at: (1 + 6) / 9 * 100 = 77.78%
hudakz 16:f4c8f45bded9 226 _canHandle.Init.BS2 = CAN_BS2_2TQ;
hudakz 16:f4c8f45bded9 227 break;
hudakz 16:f4c8f45bded9 228
hudakz 16:f4c8f45bded9 229 case 500000:
hudakz 16:f4c8f45bded9 230 // 500kbps bit rate
hudakz 16:f4c8f45bded9 231 _canHandle.Init.Prescaler = 10; // number of time quanta = 45000000/10/500000 = 9
hudakz 16:f4c8f45bded9 232 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 16:f4c8f45bded9 233 _canHandle.Init.BS1 = CAN_BS1_6TQ; // sample point at: (1 + 6) / 9 * 100 = 77.78%
hudakz 16:f4c8f45bded9 234 _canHandle.Init.BS2 = CAN_BS2_2TQ;
hudakz 16:f4c8f45bded9 235 break;
hudakz 16:f4c8f45bded9 236
hudakz 16:f4c8f45bded9 237 case 250000:
hudakz 16:f4c8f45bded9 238 // 250kbps
hudakz 16:f4c8f45bded9 239 _canHandle.Init.Prescaler = 15; // number of time quanta = 45000000/15/250000 = 12
hudakz 16:f4c8f45bded9 240 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 16:f4c8f45bded9 241 _canHandle.Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75%
hudakz 16:f4c8f45bded9 242 _canHandle.Init.BS2 = CAN_BS2_3TQ;
hudakz 16:f4c8f45bded9 243 break;
hudakz 16:f4c8f45bded9 244
hudakz 16:f4c8f45bded9 245 case 125000:
hudakz 16:f4c8f45bded9 246 // 125kbps
hudakz 16:f4c8f45bded9 247 _canHandle.Init.Prescaler = 30; // number of time quanta = 45000000/30/125000 = 12
hudakz 16:f4c8f45bded9 248 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 16:f4c8f45bded9 249 _canHandle.Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75%
hudakz 16:f4c8f45bded9 250 _canHandle.Init.BS2 = CAN_BS2_3TQ;
hudakz 16:f4c8f45bded9 251 break;
hudakz 16:f4c8f45bded9 252
hudakz 16:f4c8f45bded9 253 default:
hudakz 16:f4c8f45bded9 254 // 125kbps (default)
hudakz 16:f4c8f45bded9 255 #if DEBUG
hudakz 16:f4c8f45bded9 256 printf("Unknown frequency specified!\r\n");
hudakz 16:f4c8f45bded9 257 printf("Using default 125kbps\r\n");
hudakz 16:f4c8f45bded9 258 #endif
hudakz 17:1fd35431ee8e 259 _canHandle.Init.Prescaler = 30; // number of time quanta = 45000000/30/125000 = 12
hudakz 0:e29bc8e0dddd 260 _canHandle.Init.SJW = CAN_SJW_1TQ;
hudakz 17:1fd35431ee8e 261 _canHandle.Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75%
hudakz 17:1fd35431ee8e 262 _canHandle.Init.BS2 = CAN_BS2_3TQ;
hudakz 0:e29bc8e0dddd 263 }
hudakz 16:f4c8f45bded9 264
hudakz 16:f4c8f45bded9 265 #endif
hudakz 0:e29bc8e0dddd 266
hudakz 0:e29bc8e0dddd 267 HAL_CAN_Init(&_canHandle);
hudakz 15:5123ead7b002 268 HAL_NVIC_EnableIRQ(CAN_IRQ);
hudakz 11:439f3a34c42e 269
hudakz 5:b53e5ee15315 270 return 1;
hudakz 0:e29bc8e0dddd 271 }
hudakz 0:e29bc8e0dddd 272
hudakz 0:e29bc8e0dddd 273 /**
hudakz 0:e29bc8e0dddd 274 * @brief
hudakz 0:e29bc8e0dddd 275 * @note
hudakz 0:e29bc8e0dddd 276 * @param
hudakz 0:e29bc8e0dddd 277 * @retval
hudakz 0:e29bc8e0dddd 278 */
hudakz 20:bcd8161f8f6c 279 void can_callback(void) {
hudakz 20:bcd8161f8f6c 280 irq_handler(irq_id, IRQ_RX);
hudakz 20:bcd8161f8f6c 281 }
hudakz 20:bcd8161f8f6c 282
hudakz 20:bcd8161f8f6c 283 /**
hudakz 20:bcd8161f8f6c 284 * @brief
hudakz 20:bcd8161f8f6c 285 * @note
hudakz 20:bcd8161f8f6c 286 * @param
hudakz 20:bcd8161f8f6c 287 * @retval
hudakz 20:bcd8161f8f6c 288 */
hudakz 20:bcd8161f8f6c 289 void can_irq_init(uint32_t id, can_irq_handler handler) {
hudakz 20:bcd8161f8f6c 290 irq_id = id;
hudakz 20:bcd8161f8f6c 291 irq_handler = handler;
hudakz 20:bcd8161f8f6c 292 rxCompleteCallback = can_callback;
hudakz 20:bcd8161f8f6c 293
hudakz 0:e29bc8e0dddd 294 if(HAL_CAN_Receive_IT(&_canHandle, CAN_FIFO0) != HAL_OK) {
hudakz 5:b53e5ee15315 295 #ifdef DEBUG
hudakz 0:e29bc8e0dddd 296 printf("CAN reception initialization error\r\n");
hudakz 5:b53e5ee15315 297 #endif
hudakz 0:e29bc8e0dddd 298 }
hudakz 0:e29bc8e0dddd 299 }
hudakz 0:e29bc8e0dddd 300
hudakz 0:e29bc8e0dddd 301 /**
hudakz 0:e29bc8e0dddd 302 * @brief
hudakz 0:e29bc8e0dddd 303 * @note
hudakz 0:e29bc8e0dddd 304 * @param
hudakz 0:e29bc8e0dddd 305 * @retval
hudakz 0:e29bc8e0dddd 306 */
hudakz 20:bcd8161f8f6c 307 void can_irq_free(void) {
hudakz 11:439f3a34c42e 308 rxCompleteCallback = 0;
hudakz 20:bcd8161f8f6c 309 }
hudakz 0:e29bc8e0dddd 310
hudakz 0:e29bc8e0dddd 311 /**
hudakz 0:e29bc8e0dddd 312 * @brief
hudakz 0:e29bc8e0dddd 313 * @note
hudakz 0:e29bc8e0dddd 314 * @param
hudakz 0:e29bc8e0dddd 315 * @retval
hudakz 0:e29bc8e0dddd 316 */
hudakz 20:bcd8161f8f6c 317 int can_write(CAN_Message msg, int cc) {
hudakz 0:e29bc8e0dddd 318 int i = 0;
hudakz 0:e29bc8e0dddd 319
hudakz 0:e29bc8e0dddd 320 if(msg.format == CANStandard) {
hudakz 0:e29bc8e0dddd 321 _canHandle.pTxMsg->StdId = msg.id;
hudakz 0:e29bc8e0dddd 322 _canHandle.pTxMsg->ExtId = 0x00;
hudakz 0:e29bc8e0dddd 323 }
hudakz 0:e29bc8e0dddd 324 else {
hudakz 0:e29bc8e0dddd 325 _canHandle.pTxMsg->StdId = 0x00;
hudakz 0:e29bc8e0dddd 326 _canHandle.pTxMsg->ExtId = msg.id;
hudakz 0:e29bc8e0dddd 327 }
hudakz 0:e29bc8e0dddd 328
hudakz 0:e29bc8e0dddd 329 _canHandle.pTxMsg->RTR = msg.type == CANData ? CAN_RTR_DATA : CAN_RTR_REMOTE;
hudakz 0:e29bc8e0dddd 330 _canHandle.pTxMsg->IDE = msg.format == CANStandard ? CAN_ID_STD : CAN_ID_EXT;
hudakz 0:e29bc8e0dddd 331 _canHandle.pTxMsg->DLC = msg.len;
hudakz 0:e29bc8e0dddd 332
hudakz 0:e29bc8e0dddd 333 for(i = 0; i < msg.len; i++)
hudakz 0:e29bc8e0dddd 334 _canHandle.pTxMsg->Data[i] = msg.data[i];
hudakz 0:e29bc8e0dddd 335
hudakz 0:e29bc8e0dddd 336 if(HAL_CAN_Transmit(&_canHandle, 10) != HAL_OK) {
hudakz 5:b53e5ee15315 337 #ifdef DEBUG
hudakz 0:e29bc8e0dddd 338 printf("Transmission error\r\n");
hudakz 5:b53e5ee15315 339 #endif
hudakz 5:b53e5ee15315 340 return 0;
hudakz 0:e29bc8e0dddd 341 }
hudakz 5:b53e5ee15315 342 else
hudakz 5:b53e5ee15315 343 return 1;
hudakz 0:e29bc8e0dddd 344 }
hudakz 0:e29bc8e0dddd 345
hudakz 0:e29bc8e0dddd 346 /**
hudakz 0:e29bc8e0dddd 347 * @brief
hudakz 0:e29bc8e0dddd 348 * @note
hudakz 0:e29bc8e0dddd 349 * @param
hudakz 0:e29bc8e0dddd 350 * @retval
hudakz 0:e29bc8e0dddd 351 */
hudakz 20:bcd8161f8f6c 352 int can_read(CAN_Message* msg, int handle) {
hudakz 10:227a455d0f9f 353 int i;
hudakz 0:e29bc8e0dddd 354 msg->id = _canHandle.pRxMsg->IDE == CAN_ID_STD ? _canHandle.pRxMsg->StdId : _canHandle.pRxMsg->ExtId;
hudakz 0:e29bc8e0dddd 355 msg->type = _canHandle.pRxMsg->RTR == CAN_RTR_DATA ? CANData : CANRemote;
hudakz 0:e29bc8e0dddd 356 msg->format = _canHandle.pRxMsg->IDE == CAN_ID_STD ? CANStandard : CANExtended;
hudakz 0:e29bc8e0dddd 357 msg->len = _canHandle.pRxMsg->DLC;
hudakz 10:227a455d0f9f 358 for(i = 0; i < msg->len; i++)
hudakz 0:e29bc8e0dddd 359 msg->data[i] = _canHandle.pRxMsg->Data[i];
hudakz 5:b53e5ee15315 360
hudakz 5:b53e5ee15315 361 return msg->len;
hudakz 0:e29bc8e0dddd 362 }
hudakz 0:e29bc8e0dddd 363
hudakz 0:e29bc8e0dddd 364 /**
hudakz 0:e29bc8e0dddd 365 * @brief
hudakz 0:e29bc8e0dddd 366 * @note
hudakz 0:e29bc8e0dddd 367 * @param
hudakz 0:e29bc8e0dddd 368 * @retval
hudakz 0:e29bc8e0dddd 369 */
hudakz 20:bcd8161f8f6c 370 int can_mode(CanMode mode) {
hudakz 0:e29bc8e0dddd 371 switch(mode) {
hudakz 0:e29bc8e0dddd 372 case MODE_RESET:
hudakz 0:e29bc8e0dddd 373 return HAL_ERROR;
hudakz 0:e29bc8e0dddd 374
hudakz 0:e29bc8e0dddd 375 case MODE_NORMAL:
hudakz 0:e29bc8e0dddd 376 _canHandle.Init.Mode = CAN_MODE_NORMAL;
hudakz 0:e29bc8e0dddd 377 break;
hudakz 0:e29bc8e0dddd 378
hudakz 0:e29bc8e0dddd 379 case MODE_SILENT:
hudakz 0:e29bc8e0dddd 380 _canHandle.Init.Mode = CAN_MODE_SILENT;
hudakz 0:e29bc8e0dddd 381 break;
hudakz 0:e29bc8e0dddd 382
hudakz 0:e29bc8e0dddd 383 case MODE_TEST_GLOBAL:
hudakz 0:e29bc8e0dddd 384 _canHandle.Init.Mode = CAN_MODE_LOOPBACK;
hudakz 0:e29bc8e0dddd 385 break;
hudakz 0:e29bc8e0dddd 386
hudakz 0:e29bc8e0dddd 387 case MODE_TEST_LOCAL:
hudakz 0:e29bc8e0dddd 388 _canHandle.Init.Mode = CAN_MODE_LOOPBACK;
hudakz 0:e29bc8e0dddd 389 break;
hudakz 0:e29bc8e0dddd 390
hudakz 0:e29bc8e0dddd 391 case MODE_TEST_SILENT:
hudakz 0:e29bc8e0dddd 392 _canHandle.Init.Mode = CAN_MODE_SILENT_LOOPBACK;
hudakz 0:e29bc8e0dddd 393 break;
hudakz 0:e29bc8e0dddd 394 }
hudakz 0:e29bc8e0dddd 395
hudakz 3:0fae6b54a2ee 396 return HAL_CAN_Init(&_canHandle);
hudakz 0:e29bc8e0dddd 397 }
hudakz 0:e29bc8e0dddd 398
hudakz 0:e29bc8e0dddd 399 /**
hudakz 0:e29bc8e0dddd 400 * @brief
hudakz 0:e29bc8e0dddd 401 * @note
hudakz 0:e29bc8e0dddd 402 * @param
hudakz 0:e29bc8e0dddd 403 * @retval
hudakz 0:e29bc8e0dddd 404 */
hudakz 20:bcd8161f8f6c 405 int can_filter(uint32_t id, uint32_t mask, CANFormat format /*=CANAny*/, int32_t handle /*=0*/ ) {
hudakz 0:e29bc8e0dddd 406 CAN_FilterConfTypeDef sFilterConfig;
hudakz 0:e29bc8e0dddd 407
hudakz 8:5c90d6b9a382 408 sFilterConfig.FilterNumber = handle; // Specifies the filter number (must be a number between 0 and 13 at 32-bit filter scale)
hudakz 0:e29bc8e0dddd 409 sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
hudakz 0:e29bc8e0dddd 410 sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
hudakz 0:e29bc8e0dddd 411 sFilterConfig.FilterIdHigh = (((id) >> 16) & 0xFFFF);
hudakz 0:e29bc8e0dddd 412 sFilterConfig.FilterIdLow = ((id) & 0xFFFF);
hudakz 0:e29bc8e0dddd 413 sFilterConfig.FilterMaskIdHigh = (((mask) >> 16) & 0xFFFF);
hudakz 0:e29bc8e0dddd 414 sFilterConfig.FilterMaskIdLow = ((mask) & 0xFFFF);
hudakz 0:e29bc8e0dddd 415 sFilterConfig.FilterFIFOAssignment = 0;
hudakz 0:e29bc8e0dddd 416 sFilterConfig.FilterActivation = ENABLE;
hudakz 8:5c90d6b9a382 417 sFilterConfig.BankNumber = 0; // Selects the start bank filter
hudakz 8:5c90d6b9a382 418 return HAL_CAN_ConfigFilter(&_canHandle, &sFilterConfig);
hudakz 0:e29bc8e0dddd 419 }
hudakz 0:e29bc8e0dddd 420
hudakz 0:e29bc8e0dddd 421 /**
hudakz 0:e29bc8e0dddd 422 * @brief
hudakz 0:e29bc8e0dddd 423 * @note
hudakz 0:e29bc8e0dddd 424 * @param
hudakz 0:e29bc8e0dddd 425 * @retval
hudakz 0:e29bc8e0dddd 426 */
hudakz 20:bcd8161f8f6c 427 void can_reset(void) {
hudakz 0:e29bc8e0dddd 428 __HAL_CAN_RESET_HANDLE_STATE(&_canHandle);
hudakz 0:e29bc8e0dddd 429 }
hudakz 0:e29bc8e0dddd 430
hudakz 0:e29bc8e0dddd 431 /**
hudakz 0:e29bc8e0dddd 432 * @brief
hudakz 0:e29bc8e0dddd 433 * @note
hudakz 0:e29bc8e0dddd 434 * @param
hudakz 0:e29bc8e0dddd 435 * @retval
hudakz 0:e29bc8e0dddd 436 */
hudakz 20:bcd8161f8f6c 437 unsigned char can_rderror(void) {
hudakz 0:e29bc8e0dddd 438 return HAL_CAN_GetError(&_canHandle);
hudakz 0:e29bc8e0dddd 439 }
hudakz 0:e29bc8e0dddd 440
hudakz 0:e29bc8e0dddd 441 /**
hudakz 0:e29bc8e0dddd 442 * @brief
hudakz 0:e29bc8e0dddd 443 * @note
hudakz 0:e29bc8e0dddd 444 * @param
hudakz 0:e29bc8e0dddd 445 * @retval
hudakz 0:e29bc8e0dddd 446 */
hudakz 20:bcd8161f8f6c 447 unsigned char can_tderror(void) {
hudakz 0:e29bc8e0dddd 448 return HAL_CAN_GetError(&_canHandle);
hudakz 0:e29bc8e0dddd 449 }
hudakz 0:e29bc8e0dddd 450
hudakz 0:e29bc8e0dddd 451 /**
hudakz 0:e29bc8e0dddd 452 * @brief
hudakz 0:e29bc8e0dddd 453 * @note
hudakz 0:e29bc8e0dddd 454 * @param
hudakz 0:e29bc8e0dddd 455 * @retval
hudakz 0:e29bc8e0dddd 456 */
hudakz 20:bcd8161f8f6c 457 void can_monitor(int silent) {
hudakz 0:e29bc8e0dddd 458
hudakz 0:e29bc8e0dddd 459 // not implemented
hudakz 0:e29bc8e0dddd 460 }
hudakz 1:eb04f7f0478d 461
hudakz 5:b53e5ee15315 462
hudakz 6:c5a40d5fd9f1 463
hudakz 11:439f3a34c42e 464
hudakz 12:c45310ff2233 465
hudakz 20:bcd8161f8f6c 466
hudakz 23:c5d348e65e24 467