├── .github └── workflows │ └── master.yml ├── .gitignore ├── .mbedignore ├── CANopenNode.lib ├── CONTRIBUTING.md ├── CO_OD.c ├── CO_OD.h ├── README.md ├── config.h ├── doc └── wiring.jpg ├── main.cpp ├── mbed-os.lib └── mbed_app.json /.github/workflows/master.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI master 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the master branch 8 | push: 9 | branches: [ master ] 10 | 11 | pull_request: 12 | branches: [ master ] 13 | 14 | # Allows you to run this workflow manually from the Actions tab 15 | workflow_dispatch: 16 | 17 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 18 | jobs: 19 | # This workflow contains a single job called "build" 20 | build: 21 | # The type of runner that the job will run on 22 | runs-on: ubuntu-20.04 23 | env: 24 | TARGET_MACHINE: NUCLEO_F091RC 25 | 26 | # Steps represent a sequence of tasks that will be executed as part of the job 27 | steps: 28 | 29 | - name: Show TARGET 30 | run: | 31 | echo "Target is ${{ env.TARGET_MACHINE }}" 32 | 33 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 34 | - name: Checkout 35 | uses: actions/checkout@v2 36 | 37 | # Runs a single command using the runners shell 38 | - name: Run a one-line script 39 | run: echo Hello, world! 40 | 41 | - name: Install Python 42 | uses: actions/setup-python@v2.2.2 43 | with: 44 | # Version range or exact version of a Python version to use, using SemVer's version range syntax. 45 | python-version: 2.x 46 | 47 | - name: Install arm-none-eabi-gcc 48 | # You may pin to the exact commit or the version. 49 | # uses: fiam/arm-none-eabi-gcc@77f4527db18a17bf6def2cfeeea231f7bfa50902 50 | uses: fiam/arm-none-eabi-gcc@v1.0.2 51 | with: 52 | # GNU Embedded Toolchain for Arm release name, in the V-YYYY-qZ format (e.g. "9-2019-q4") 53 | release: "7-2018-q2" 54 | env: 55 | ACTIONS_ALLOW_UNSECURE_COMMANDS: "true" 56 | 57 | - name: Show Python/pip/git/gcc versions 58 | run: | 59 | echo "---------------------------------------------------" 60 | python --version 61 | echo "---------------------------------------------------" 62 | pip --version 63 | echo "---------------------------------------------------" 64 | git --version 65 | echo "---------------------------------------------------" 66 | arm-none-eabi-gcc --version 67 | echo "---------------------------------------------------" 68 | wget --version 69 | 70 | - name: Install python/mbed/gcc requirements 71 | run: | 72 | echo "Installing mbed cli" 73 | pip install mbed-cli==1.10.0 74 | echo "---------------------------------------------------" 75 | echo "Downloading mbed-os 5.15 requirements.txt" 76 | wget "https://raw.githubusercontent.com/ARMmbed/mbed-os/mbed-os-5.15/requirements.txt" 77 | echo "---------------------------------------------------" 78 | echo "Installing requirements using pip" 79 | pip install -r requirements.txt 80 | echo "---------------------------------------------------" 81 | mbed --version 82 | echo "---------------------------------------------------" 83 | GCC_BIN=$(which arm-none-eabi-gcc | awk -F'arm' '{print $1}') 84 | echo "GCC PATH = $GCC_BIN" 85 | mbed config -G GCC_ARM_PATH "$GCC_BIN" 86 | 87 | - name: Mbed deploy 88 | run: mbed deploy -v 89 | 90 | - name: Mbed compile 91 | run: mbed compile -t GCC_ARM -m ${{ env.TARGET_MACHINE }} 92 | 93 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .build 2 | .mbed 3 | projectfiles 4 | *.py* 5 | .vscode 6 | GettingStarted.html -------------------------------------------------------------------------------- /.mbedignore: -------------------------------------------------------------------------------- 1 | CANopenNode/example/* 2 | CANopenNode/stack/drvTemplate/* 3 | CANopenNode/stack/dsPIC30F/* 4 | CANopenNode/stack/eCos/* 5 | CANopenNode/stack/LPC177x_8x/* 6 | CANopenNode/stack/LPC1768/* 7 | CANopenNode/stack/MCF5282/* 8 | CANopenNode/stack/neuberger-socketCAN/* 9 | CANopenNode/stack/PIC24_dsPIC33/* 10 | CANopenNode/stack/PIC32/* 11 | CANopenNode/stack/SAM3X/* 12 | CANopenNode/stack/socketCAN/* 13 | CANopenNode/stack/STM32/* 14 | CANopenNode/stack/STM32F3/* 15 | mbed-os/features/nanostack/sal-stack-nanostack/source/Service_Libs/utils/ns_crc* -------------------------------------------------------------------------------- /CANopenNode.lib: -------------------------------------------------------------------------------- 1 | https://github.com/Alphatronics/CANopenNode/#14678019528726b8de2742249dafd2964421595b 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Mbed OS 2 | 3 | Mbed OS is an open-source, device software platform for the Internet of Things. Contributions are an important part of the platform, and our goal is to make it as simple as possible to become a contributor. 4 | 5 | To encourage productive collaboration, as well as robust, consistent and maintainable code, we have a set of guidelines for [contributing to Mbed OS](https://os.mbed.com/docs/latest/reference/contributing.html). 6 | -------------------------------------------------------------------------------- /CO_OD.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CANopen Object Dictionary. 3 | * 4 | * This file was automatically generated with CANopenNode Object 5 | * Dictionary Editor. DON'T EDIT THIS FILE MANUALLY !!!! 6 | * Object Dictionary Editor is currently an older, but functional web 7 | * application. For more info see See 'Object_Dictionary_Editor/about.html' in 8 | * 9 | * For more information on CANopen Object Dictionary see . 10 | * 11 | * @file CO_OD.c 12 | * @author Janez Paternoster 13 | * @copyright 2010 - 2016 Janez Paternoster 14 | * 15 | * This file is part of CANopenNode, an opensource CANopen Stack. 16 | * Project home page is . 17 | * For more information on CANopen see . 18 | * 19 | * CANopenNode is free and open source software: you can redistribute 20 | * it and/or modify it under the terms of the GNU General Public License 21 | * as published by the Free Software Foundation, either version 2 of the 22 | * License, or (at your option) any later version. 23 | * 24 | * This program is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | * GNU General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU General Public License 30 | * along with this program. If not, see . 31 | * 32 | * Following clarification and special exception to the GNU General Public 33 | * License is included to the distribution terms of CANopenNode: 34 | * 35 | * Linking this library statically or dynamically with other modules is 36 | * making a combined work based on this library. Thus, the terms and 37 | * conditions of the GNU General Public License cover the whole combination. 38 | * 39 | * As a special exception, the copyright holders of this library give 40 | * you permission to link this library with independent modules to 41 | * produce an executable, regardless of the license terms of these 42 | * independent modules, and to copy and distribute the resulting 43 | * executable under terms of your choice, provided that you also meet, 44 | * for each linked independent module, the terms and conditions of the 45 | * license of that module. An independent module is a module which is 46 | * not derived from or based on this library. If you modify this 47 | * library, you may extend this exception to your version of the 48 | * library, but you are not obliged to do so. If you do not wish 49 | * to do so, delete this exception statement from your version. 50 | */ 51 | 52 | 53 | #include "CO_driver.h" 54 | #include "CO_OD.h" 55 | #include "CO_SDO.h" 56 | 57 | 58 | /******************************************************************************* 59 | DEFINITION AND INITIALIZATION OF OBJECT DICTIONARY VARIABLES 60 | *******************************************************************************/ 61 | 62 | /***** Definition for RAM variables *******************************************/ 63 | struct sCO_OD_RAM CO_OD_RAM = { 64 | CO_OD_FIRST_LAST_WORD, 65 | 66 | /*1001*/ 0x0, 67 | /*1002*/ 0x0L, 68 | /*1003*/ {0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, 69 | /*1010*/ {0x3L}, 70 | /*1011*/ {0x1L}, 71 | /*2100*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 72 | /*2103*/ 0x0, 73 | /*2104*/ 0x0, 74 | /*2107*/ {0x3E8, 0x0, 0x0, 0x0, 0x0}, 75 | /*2108*/ {0}, 76 | /*2109*/ {0}, 77 | /*2110*/ {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}, 78 | /*2120*/ {0x5, 0x1234567890ABCDEFLL, 0x234567890ABCDEF1LL, 12.345, 456.789, 0}, 79 | /*2130*/ {0x3, {'-', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, 0, 0x0L}, 80 | /*6000*/ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 81 | /*6200*/ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 82 | /*6401*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 83 | /*6411*/ {0, 0, 0, 0, 0, 0, 0, 0}, 84 | 85 | CO_OD_FIRST_LAST_WORD, 86 | }; 87 | 88 | 89 | /***** Definition for EEPROM variables ****************************************/ 90 | struct sCO_OD_EEPROM CO_OD_EEPROM = { 91 | CO_OD_FIRST_LAST_WORD, 92 | 93 | /*2106*/ 0x0L, 94 | /*2112*/ {1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}, 95 | 96 | CO_OD_FIRST_LAST_WORD, 97 | }; 98 | 99 | 100 | /***** Definition for ROM variables *******************************************/ 101 | struct sCO_OD_ROM CO_OD_ROM = { //constant variables, stored in flash 102 | CO_OD_FIRST_LAST_WORD, 103 | 104 | /*1000*/ 0x0L, 105 | /*1005*/ 0x80L, 106 | /*1006*/ 0x0L, 107 | /*1007*/ 0x0L, 108 | /*1008*/ {'A', 'l', 'p', 'h', 't', 'r', 'o', 'n', 'i', 'c', 's'}, 109 | /*1009*/ {'1', '.', '0', 'A'}, 110 | /*100A*/ {'1', '9', '1', '0'}, 111 | /*1014*/ 0x80L, 112 | /*1015*/ 0x64, 113 | /*1016*/ {0x0L, 0x0L, 0x0L, 0x0L}, 114 | /*1017*/ 0x1F4, // 500 ms 115 | /*1018*/ {0x4, 0x0L, 0x0L, 0x0L, 0x0L}, 116 | /*1019*/ 0x0, 117 | /*1029*/ {0x0, 0x0, 0x1, 0x0, 0x0, 0x0}, 118 | /*1200*/{{0x2, 0x600L, 0x580L}}, 119 | /*1400*/{{0x2, 0x200L, 0xFF}, 120 | /*1401*/ {0x2, 0x300L, 0xFE}, 121 | /*1402*/ {0x2, 0x400L, 0xFE}, 122 | /*1403*/ {0x2, 0x500L, 0xFE}}, 123 | /*1600*/{{0x2, 0x62000108L, 0x62000208L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, 124 | /*1601*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, 125 | /*1602*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, 126 | /*1603*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}}, 127 | /*1800*/{{0x6, 0x180L, 0xFF, 0x64, 0x0, 0x0, 0x0}, 128 | /*1801*/ {0x6, 0x280L, 0xFE, 0x0, 0x0, 0x0, 0x0}, 129 | /*1802*/ {0x6, 0x380L, 0xFE, 0x0, 0x0, 0x0, 0x0}, 130 | /*1803*/ {0x6, 0x480L, 0xFE, 0x0, 0x0, 0x0, 0x0}}, 131 | /*1A00*/{{0x2, 0x60000108L, 0x60000208L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, 132 | /*1A01*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, 133 | /*1A02*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}, 134 | /*1A03*/ {0x0, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L}}, 135 | /*1F80*/ 0x0L, 136 | /*2101*/ CANOPEN_DEFAULT_NODE_ID, 137 | /*2102*/ 0xFA, 138 | /*2111*/ {1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}, 139 | 140 | CO_OD_FIRST_LAST_WORD 141 | }; 142 | 143 | 144 | /******************************************************************************* 145 | STRUCTURES FOR RECORD TYPE OBJECTS 146 | *******************************************************************************/ 147 | /*0x1018*/ const CO_OD_entryRecord_t OD_record1018[5] = { 148 | {(void*)&CO_OD_ROM.identity.maxSubIndex, 0x05, 1}, 149 | {(void*)&CO_OD_ROM.identity.vendorID, 0x85, 4}, 150 | {(void*)&CO_OD_ROM.identity.productCode, 0x85, 4}, 151 | {(void*)&CO_OD_ROM.identity.revisionNumber, 0x85, 4}, 152 | {(void*)&CO_OD_ROM.identity.serialNumber, 0x85, 4}}; 153 | /*0x1200*/ const CO_OD_entryRecord_t OD_record1200[3] = { 154 | {(void*)&CO_OD_ROM.SDOServerParameter[0].maxSubIndex, 0x05, 1}, 155 | {(void*)&CO_OD_ROM.SDOServerParameter[0].COB_IDClientToServer, 0x85, 4}, 156 | {(void*)&CO_OD_ROM.SDOServerParameter[0].COB_IDServerToClient, 0x85, 4}}; 157 | /*0x1400*/ const CO_OD_entryRecord_t OD_record1400[3] = { 158 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[0].maxSubIndex, 0x05, 1}, 159 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[0].COB_IDUsedByRPDO, 0x8D, 4}, 160 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[0].transmissionType, 0x0D, 1}}; 161 | /*0x1401*/ const CO_OD_entryRecord_t OD_record1401[3] = { 162 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[1].maxSubIndex, 0x05, 1}, 163 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[1].COB_IDUsedByRPDO, 0x8D, 4}, 164 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[1].transmissionType, 0x0D, 1}}; 165 | /*0x1402*/ const CO_OD_entryRecord_t OD_record1402[3] = { 166 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[2].maxSubIndex, 0x05, 1}, 167 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[2].COB_IDUsedByRPDO, 0x8D, 4}, 168 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[2].transmissionType, 0x0D, 1}}; 169 | /*0x1403*/ const CO_OD_entryRecord_t OD_record1403[3] = { 170 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[3].maxSubIndex, 0x05, 1}, 171 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[3].COB_IDUsedByRPDO, 0x8D, 4}, 172 | {(void*)&CO_OD_ROM.RPDOCommunicationParameter[3].transmissionType, 0x0D, 1}}; 173 | /*0x1600*/ const CO_OD_entryRecord_t OD_record1600[9] = { 174 | {(void*)&CO_OD_ROM.RPDOMappingParameter[0].numberOfMappedObjects, 0x0D, 1}, 175 | {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject1, 0x8D, 4}, 176 | {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject2, 0x8D, 4}, 177 | {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject3, 0x8D, 4}, 178 | {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject4, 0x8D, 4}, 179 | {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject5, 0x8D, 4}, 180 | {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject6, 0x8D, 4}, 181 | {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject7, 0x8D, 4}, 182 | {(void*)&CO_OD_ROM.RPDOMappingParameter[0].mappedObject8, 0x8D, 4}}; 183 | /*0x1601*/ const CO_OD_entryRecord_t OD_record1601[9] = { 184 | {(void*)&CO_OD_ROM.RPDOMappingParameter[1].numberOfMappedObjects, 0x0D, 1}, 185 | {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject1, 0x8D, 4}, 186 | {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject2, 0x8D, 4}, 187 | {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject3, 0x8D, 4}, 188 | {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject4, 0x8D, 4}, 189 | {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject5, 0x8D, 4}, 190 | {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject6, 0x8D, 4}, 191 | {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject7, 0x8D, 4}, 192 | {(void*)&CO_OD_ROM.RPDOMappingParameter[1].mappedObject8, 0x8D, 4}}; 193 | /*0x1602*/ const CO_OD_entryRecord_t OD_record1602[9] = { 194 | {(void*)&CO_OD_ROM.RPDOMappingParameter[2].numberOfMappedObjects, 0x0D, 1}, 195 | {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject1, 0x8D, 4}, 196 | {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject2, 0x8D, 4}, 197 | {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject3, 0x8D, 4}, 198 | {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject4, 0x8D, 4}, 199 | {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject5, 0x8D, 4}, 200 | {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject6, 0x8D, 4}, 201 | {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject7, 0x8D, 4}, 202 | {(void*)&CO_OD_ROM.RPDOMappingParameter[2].mappedObject8, 0x8D, 4}}; 203 | /*0x1603*/ const CO_OD_entryRecord_t OD_record1603[9] = { 204 | {(void*)&CO_OD_ROM.RPDOMappingParameter[3].numberOfMappedObjects, 0x0D, 1}, 205 | {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject1, 0x8D, 4}, 206 | {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject2, 0x8D, 4}, 207 | {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject3, 0x8D, 4}, 208 | {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject4, 0x8D, 4}, 209 | {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject5, 0x8D, 4}, 210 | {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject6, 0x8D, 4}, 211 | {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject7, 0x8D, 4}, 212 | {(void*)&CO_OD_ROM.RPDOMappingParameter[3].mappedObject8, 0x8D, 4}}; 213 | /*0x1800*/ const CO_OD_entryRecord_t OD_record1800[7] = { 214 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].maxSubIndex, 0x05, 1}, 215 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].COB_IDUsedByTPDO, 0x8D, 4}, 216 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].transmissionType, 0x0D, 1}, 217 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].inhibitTime, 0x8D, 2}, 218 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].compatibilityEntry, 0x0D, 1}, 219 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].eventTimer, 0x8D, 2}, 220 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[0].SYNCStartValue, 0x0D, 1}}; 221 | /*0x1801*/ const CO_OD_entryRecord_t OD_record1801[7] = { 222 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].maxSubIndex, 0x05, 1}, 223 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].COB_IDUsedByTPDO, 0x8D, 4}, 224 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].transmissionType, 0x0D, 1}, 225 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].inhibitTime, 0x8D, 2}, 226 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].compatibilityEntry, 0x0D, 1}, 227 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].eventTimer, 0x8D, 2}, 228 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[1].SYNCStartValue, 0x0D, 1}}; 229 | /*0x1802*/ const CO_OD_entryRecord_t OD_record1802[7] = { 230 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].maxSubIndex, 0x05, 1}, 231 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].COB_IDUsedByTPDO, 0x8D, 4}, 232 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].transmissionType, 0x0D, 1}, 233 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].inhibitTime, 0x8D, 2}, 234 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].compatibilityEntry, 0x0D, 1}, 235 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].eventTimer, 0x8D, 2}, 236 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[2].SYNCStartValue, 0x0D, 1}}; 237 | /*0x1803*/ const CO_OD_entryRecord_t OD_record1803[7] = { 238 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].maxSubIndex, 0x05, 1}, 239 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].COB_IDUsedByTPDO, 0x8D, 4}, 240 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].transmissionType, 0x0D, 1}, 241 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].inhibitTime, 0x8D, 2}, 242 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].compatibilityEntry, 0x0D, 1}, 243 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].eventTimer, 0x8D, 2}, 244 | {(void*)&CO_OD_ROM.TPDOCommunicationParameter[3].SYNCStartValue, 0x0D, 1}}; 245 | /*0x1A00*/ const CO_OD_entryRecord_t OD_record1A00[9] = { 246 | {(void*)&CO_OD_ROM.TPDOMappingParameter[0].numberOfMappedObjects, 0x0D, 1}, 247 | {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject1, 0x8D, 4}, 248 | {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject2, 0x8D, 4}, 249 | {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject3, 0x8D, 4}, 250 | {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject4, 0x8D, 4}, 251 | {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject5, 0x8D, 4}, 252 | {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject6, 0x8D, 4}, 253 | {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject7, 0x8D, 4}, 254 | {(void*)&CO_OD_ROM.TPDOMappingParameter[0].mappedObject8, 0x8D, 4}}; 255 | /*0x1A01*/ const CO_OD_entryRecord_t OD_record1A01[9] = { 256 | {(void*)&CO_OD_ROM.TPDOMappingParameter[1].numberOfMappedObjects, 0x0D, 1}, 257 | {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject1, 0x8D, 4}, 258 | {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject2, 0x8D, 4}, 259 | {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject3, 0x8D, 4}, 260 | {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject4, 0x8D, 4}, 261 | {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject5, 0x8D, 4}, 262 | {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject6, 0x8D, 4}, 263 | {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject7, 0x8D, 4}, 264 | {(void*)&CO_OD_ROM.TPDOMappingParameter[1].mappedObject8, 0x8D, 4}}; 265 | /*0x1A02*/ const CO_OD_entryRecord_t OD_record1A02[9] = { 266 | {(void*)&CO_OD_ROM.TPDOMappingParameter[2].numberOfMappedObjects, 0x0D, 1}, 267 | {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject1, 0x8D, 4}, 268 | {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject2, 0x8D, 4}, 269 | {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject3, 0x8D, 4}, 270 | {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject4, 0x8D, 4}, 271 | {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject5, 0x8D, 4}, 272 | {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject6, 0x8D, 4}, 273 | {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject7, 0x8D, 4}, 274 | {(void*)&CO_OD_ROM.TPDOMappingParameter[2].mappedObject8, 0x8D, 4}}; 275 | /*0x1A03*/ const CO_OD_entryRecord_t OD_record1A03[9] = { 276 | {(void*)&CO_OD_ROM.TPDOMappingParameter[3].numberOfMappedObjects, 0x0D, 1}, 277 | {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject1, 0x8D, 4}, 278 | {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject2, 0x8D, 4}, 279 | {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject3, 0x8D, 4}, 280 | {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject4, 0x8D, 4}, 281 | {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject5, 0x8D, 4}, 282 | {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject6, 0x8D, 4}, 283 | {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject7, 0x8D, 4}, 284 | {(void*)&CO_OD_ROM.TPDOMappingParameter[3].mappedObject8, 0x8D, 4}}; 285 | /*0x2120*/ const CO_OD_entryRecord_t OD_record2120[6] = { 286 | {(void*)&CO_OD_RAM.testVar.maxSubIndex, 0x06, 1}, 287 | {(void*)&CO_OD_RAM.testVar.I64, 0xBE, 8}, 288 | {(void*)&CO_OD_RAM.testVar.U64, 0xBE, 8}, 289 | {(void*)&CO_OD_RAM.testVar.R32, 0xBE, 4}, 290 | {(void*)&CO_OD_RAM.testVar.R64, 0xBE, 8}, 291 | {0, 0x0E, 0}}; 292 | /*0x2130*/ const CO_OD_entryRecord_t OD_record2130[4] = { 293 | {(void*)&CO_OD_RAM.time.maxSubIndex, 0x06, 1}, 294 | {(void*)&CO_OD_RAM.time.string[0], 0x06, 30}, 295 | {(void*)&CO_OD_RAM.time.epochTimeBaseMs, 0x8E, 8}, 296 | {(void*)&CO_OD_RAM.time.epochTimeOffsetMs, 0xBE, 4}}; 297 | 298 | 299 | /******************************************************************************* 300 | OBJECT DICTIONARY 301 | *******************************************************************************/ 302 | const CO_OD_entry_t CO_OD[CO_OD_NoOfElements] = { 303 | {0x1000, 0x00, 0x85, 4, (void*)&CO_OD_ROM.deviceType}, 304 | {0x1001, 0x00, 0x36, 1, (void*)&CO_OD_RAM.errorRegister}, 305 | {0x1002, 0x00, 0xB6, 4, (void*)&CO_OD_RAM.manufacturerStatusRegister}, 306 | {0x1003, 0x08, 0x8E, 4, (void*)&CO_OD_RAM.preDefinedErrorField[0]}, 307 | {0x1005, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.COB_ID_SYNCMessage}, 308 | {0x1006, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.communicationCyclePeriod}, 309 | {0x1007, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.synchronousWindowLength}, 310 | {0x1008, 0x00, 0x05, 11, (void*)&CO_OD_ROM.manufacturerDeviceName[0]}, 311 | {0x1009, 0x00, 0x05, 4, (void*)&CO_OD_ROM.manufacturerHardwareVersion[0]}, 312 | {0x100A, 0x00, 0x05, 4, (void*)&CO_OD_ROM.manufacturerSoftwareVersion[0]}, 313 | {0x1010, 0x01, 0x8E, 4, (void*)&CO_OD_RAM.storeParameters[0]}, 314 | {0x1011, 0x01, 0x8E, 4, (void*)&CO_OD_RAM.restoreDefaultParameters[0]}, 315 | {0x1014, 0x00, 0x85, 4, (void*)&CO_OD_ROM.COB_ID_EMCY}, 316 | {0x1015, 0x00, 0x8D, 2, (void*)&CO_OD_ROM.inhibitTimeEMCY}, 317 | {0x1016, 0x04, 0x8D, 4, (void*)&CO_OD_ROM.consumerHeartbeatTime[0]}, 318 | {0x1017, 0x00, 0x8D, 2, (void*)&CO_OD_ROM.producerHeartbeatTime}, 319 | {0x1018, 0x04, 0x00, 0, (void*)&OD_record1018}, 320 | {0x1019, 0x00, 0x0D, 1, (void*)&CO_OD_ROM.synchronousCounterOverflowValue}, 321 | {0x1029, 0x06, 0x0D, 1, (void*)&CO_OD_ROM.errorBehavior[0]}, 322 | {0x1200, 0x02, 0x00, 0, (void*)&OD_record1200}, 323 | {0x1400, 0x02, 0x00, 0, (void*)&OD_record1400}, 324 | {0x1401, 0x02, 0x00, 0, (void*)&OD_record1401}, 325 | {0x1402, 0x02, 0x00, 0, (void*)&OD_record1402}, 326 | {0x1403, 0x02, 0x00, 0, (void*)&OD_record1403}, 327 | {0x1600, 0x08, 0x00, 0, (void*)&OD_record1600}, 328 | {0x1601, 0x08, 0x00, 0, (void*)&OD_record1601}, 329 | {0x1602, 0x08, 0x00, 0, (void*)&OD_record1602}, 330 | {0x1603, 0x08, 0x00, 0, (void*)&OD_record1603}, 331 | {0x1800, 0x06, 0x00, 0, (void*)&OD_record1800}, 332 | {0x1801, 0x06, 0x00, 0, (void*)&OD_record1801}, 333 | {0x1802, 0x06, 0x00, 0, (void*)&OD_record1802}, 334 | {0x1803, 0x06, 0x00, 0, (void*)&OD_record1803}, 335 | {0x1A00, 0x08, 0x00, 0, (void*)&OD_record1A00}, 336 | {0x1A01, 0x08, 0x00, 0, (void*)&OD_record1A01}, 337 | {0x1A02, 0x08, 0x00, 0, (void*)&OD_record1A02}, 338 | {0x1A03, 0x08, 0x00, 0, (void*)&OD_record1A03}, 339 | {0x1F80, 0x00, 0x8D, 4, (void*)&CO_OD_ROM.NMTStartup}, 340 | {0x2100, 0x00, 0x36, 10, (void*)&CO_OD_RAM.errorStatusBits[0]}, 341 | {0x2101, 0x00, 0x0D, 1, (void*)&CO_OD_ROM.CANNodeID}, 342 | {0x2102, 0x00, 0x8D, 2, (void*)&CO_OD_ROM.CANBitRate}, 343 | {0x2103, 0x00, 0x8E, 2, (void*)&CO_OD_RAM.SYNCCounter}, 344 | {0x2104, 0x00, 0x86, 2, (void*)&CO_OD_RAM.SYNCTime}, 345 | {0x2106, 0x00, 0x87, 4, (void*)&CO_OD_EEPROM.powerOnCounter}, 346 | {0x2107, 0x05, 0xBE, 2, (void*)&CO_OD_RAM.performance[0]}, 347 | {0x2108, 0x01, 0xB6, 2, (void*)&CO_OD_RAM.temperature[0]}, 348 | {0x2109, 0x01, 0xB6, 2, (void*)&CO_OD_RAM.voltage[0]}, 349 | {0x2110, 0x10, 0xFE, 4, (void*)&CO_OD_RAM.variableInt32[0]}, 350 | {0x2111, 0x10, 0xFD, 4, (void*)&CO_OD_ROM.variableROMInt32[0]}, 351 | {0x2112, 0x10, 0xFF, 4, (void*)&CO_OD_EEPROM.variableNVInt32[0]}, 352 | {0x2120, 0x05, 0x00, 0, (void*)&OD_record2120}, 353 | {0x2130, 0x03, 0x00, 0, (void*)&OD_record2130}, 354 | {0x6000, 0x08, 0x76, 1, (void*)&CO_OD_RAM.readInput8Bit[0]}, 355 | {0x6200, 0x08, 0x3E, 1, (void*)&CO_OD_RAM.writeOutput8Bit[0]}, 356 | {0x6401, 0x0C, 0xB6, 2, (void*)&CO_OD_RAM.readAnalogueInput16Bit[0]}, 357 | {0x6411, 0x08, 0xBE, 2, (void*)&CO_OD_RAM.writeAnalogueOutput16Bit[0]}, 358 | }; 359 | 360 | -------------------------------------------------------------------------------- /CO_OD.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CANopen Object Dictionary. 3 | * 4 | * This file was automatically generated with CANopenNode Object 5 | * Dictionary Editor. DON'T EDIT THIS FILE MANUALLY !!!! 6 | * Object Dictionary Editor is currently an older, but functional web 7 | * application. For more info see See 'Object_Dictionary_Editor/about.html' in 8 | * 9 | * For more information on CANopen Object Dictionary see . 10 | * 11 | * @file CO_OD.h 12 | * @author Janez Paternoster 13 | * @copyright 2010 - 2016 Janez Paternoster 14 | * 15 | * This file is part of CANopenNode, an opensource CANopen Stack. 16 | * Project home page is . 17 | * For more information on CANopen see . 18 | * 19 | * CANopenNode is free and open source software: you can redistribute 20 | * it and/or modify it under the terms of the GNU General Public License 21 | * as published by the Free Software Foundation, either version 2 of the 22 | * License, or (at your option) any later version. 23 | * 24 | * This program is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | * GNU General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU General Public License 30 | * along with this program. If not, see . 31 | * 32 | * Following clarification and special exception to the GNU General Public 33 | * License is included to the distribution terms of CANopenNode: 34 | * 35 | * Linking this library statically or dynamically with other modules is 36 | * making a combined work based on this library. Thus, the terms and 37 | * conditions of the GNU General Public License cover the whole combination. 38 | * 39 | * As a special exception, the copyright holders of this library give 40 | * you permission to link this library with independent modules to 41 | * produce an executable, regardless of the license terms of these 42 | * independent modules, and to copy and distribute the resulting 43 | * executable under terms of your choice, provided that you also meet, 44 | * for each linked independent module, the terms and conditions of the 45 | * license of that module. An independent module is a module which is 46 | * not derived from or based on this library. If you modify this 47 | * library, you may extend this exception to your version of the 48 | * library, but you are not obliged to do so. If you do not wish 49 | * to do so, delete this exception statement from your version. 50 | */ 51 | 52 | 53 | #ifndef CO_OD_H 54 | #define CO_OD_H 55 | 56 | #include "config.h" 57 | 58 | 59 | /******************************************************************************* 60 | FILE INFO: 61 | FileName: IO Example 62 | FileVersion: - 63 | CreationTime: 18:04:29 64 | CreationDate: 2016-03-25 65 | CreatedBy: JP 66 | *******************************************************************************/ 67 | 68 | 69 | /******************************************************************************* 70 | DEVICE INFO: 71 | VendorName: CANopenNode 72 | VendorNumber: 0 73 | ProductName: CANopenNode 74 | ProductNumber: 0 75 | *******************************************************************************/ 76 | 77 | 78 | /******************************************************************************* 79 | FEATURES 80 | *******************************************************************************/ 81 | #define CO_NO_SYNC 1 //Associated objects: 1005, 1006, 1007, 2103, 2104 82 | #define CO_NO_TIME 0 //Associated objects: 1012-1013 83 | #define CO_NO_EMERGENCY 1 //Associated objects: 1014, 1015 84 | #define CO_NO_SDO_SERVER 1 //Associated objects: 1200 85 | #define CO_NO_SDO_CLIENT 0 86 | #define CO_NO_RPDO 4 //Associated objects: 1400, 1401, 1402, 1403, 1600, 1601, 1602, 1603 87 | #define CO_NO_TPDO 4 //Associated objects: 1800, 1801, 1802, 1803, 1A00, 1A01, 1A02, 1A03 88 | #define CO_NO_NMT_MASTER 0 89 | #define CO_NO_TRACE 0 90 | #define CO_NO_LSS_SERVER 0 91 | #define CO_NO_LSS_CLIENT 0 92 | 93 | /******************************************************************************* 94 | OBJECT DICTIONARY 95 | *******************************************************************************/ 96 | #define CO_OD_NoOfElements 55 97 | 98 | 99 | /******************************************************************************* 100 | TYPE DEFINITIONS FOR RECORDS 101 | *******************************************************************************/ 102 | /*1018 */ typedef struct{ 103 | uint8_t maxSubIndex; 104 | uint32_t vendorID; 105 | uint32_t productCode; 106 | uint32_t revisionNumber; 107 | uint32_t serialNumber; 108 | } OD_identity_t; 109 | 110 | /*1200[1] */ typedef struct{ 111 | uint8_t maxSubIndex; 112 | uint32_t COB_IDClientToServer; 113 | uint32_t COB_IDServerToClient; 114 | } OD_SDOServerParameter_t; 115 | 116 | /*1400[4] */ typedef struct{ 117 | uint8_t maxSubIndex; 118 | uint32_t COB_IDUsedByRPDO; 119 | uint8_t transmissionType; 120 | } OD_RPDOCommunicationParameter_t; 121 | 122 | /*1600[4] */ typedef struct{ 123 | uint8_t numberOfMappedObjects; 124 | uint32_t mappedObject1; 125 | uint32_t mappedObject2; 126 | uint32_t mappedObject3; 127 | uint32_t mappedObject4; 128 | uint32_t mappedObject5; 129 | uint32_t mappedObject6; 130 | uint32_t mappedObject7; 131 | uint32_t mappedObject8; 132 | } OD_RPDOMappingParameter_t; 133 | 134 | /*1800[4] */ typedef struct{ 135 | uint8_t maxSubIndex; 136 | uint32_t COB_IDUsedByTPDO; 137 | uint8_t transmissionType; 138 | uint16_t inhibitTime; 139 | uint8_t compatibilityEntry; 140 | uint16_t eventTimer; 141 | uint8_t SYNCStartValue; 142 | } OD_TPDOCommunicationParameter_t; 143 | 144 | /*1A00[4] */ typedef struct{ 145 | uint8_t numberOfMappedObjects; 146 | uint32_t mappedObject1; 147 | uint32_t mappedObject2; 148 | uint32_t mappedObject3; 149 | uint32_t mappedObject4; 150 | uint32_t mappedObject5; 151 | uint32_t mappedObject6; 152 | uint32_t mappedObject7; 153 | uint32_t mappedObject8; 154 | } OD_TPDOMappingParameter_t; 155 | 156 | /*2120 */ typedef struct{ 157 | uint8_t maxSubIndex; 158 | int64_t I64; 159 | uint64_t U64; 160 | float32_t R32; 161 | float64_t R64; 162 | domain_t domain_t; 163 | } OD_testVar_t; 164 | 165 | /*2130 */ typedef struct{ 166 | uint8_t maxSubIndex; 167 | char_t string[30]; 168 | uint64_t epochTimeBaseMs; 169 | uint32_t epochTimeOffsetMs; 170 | } OD_time_t; 171 | 172 | 173 | /******************************************************************************* 174 | STRUCTURES FOR VARIABLES IN DIFFERENT MEMORY LOCATIONS 175 | *******************************************************************************/ 176 | #define CO_OD_FIRST_LAST_WORD 0x55 //Any value from 0x01 to 0xFE. If changed, EEPROM will be reinitialized. 177 | 178 | /***** Structure for RAM variables ********************************************/ 179 | struct sCO_OD_RAM{ 180 | uint32_t FirstWord; 181 | 182 | /*1001 */ uint8_t errorRegister; 183 | /*1002 */ uint32_t manufacturerStatusRegister; 184 | /*1003 */ uint32_t preDefinedErrorField[8]; 185 | /*1010 */ uint32_t storeParameters[1]; 186 | /*1011 */ uint32_t restoreDefaultParameters[1]; 187 | /*2100 */ oChar_t errorStatusBits[10]; 188 | /*2103 */ uint16_t SYNCCounter; 189 | /*2104 */ uint16_t SYNCTime; 190 | /*2107 */ uint16_t performance[5]; 191 | /*2108 */ int16_t temperature[1]; 192 | /*2109 */ int16_t voltage[1]; 193 | /*2110 */ int32_t variableInt32[16]; 194 | /*2120 */ OD_testVar_t testVar; 195 | /*2130 */ OD_time_t time; 196 | /*6000 */ uint8_t readInput8Bit[8]; 197 | /*6200 */ uint8_t writeOutput8Bit[8]; 198 | /*6401 */ int16_t readAnalogueInput16Bit[12]; 199 | /*6411 */ int16_t writeAnalogueOutput16Bit[8]; 200 | 201 | uint32_t LastWord; 202 | }; 203 | 204 | /***** Structure for EEPROM variables *****************************************/ 205 | struct sCO_OD_EEPROM{ 206 | uint32_t FirstWord; 207 | 208 | /*2106 */ uint32_t powerOnCounter; 209 | /*2112 */ int32_t variableNVInt32[16]; 210 | 211 | uint32_t LastWord; 212 | }; 213 | 214 | 215 | /***** Structure for ROM variables ********************************************/ 216 | struct sCO_OD_ROM{ 217 | uint32_t FirstWord; 218 | 219 | /*1000 */ uint32_t deviceType; 220 | /*1005 */ uint32_t COB_ID_SYNCMessage; 221 | /*1006 */ uint32_t communicationCyclePeriod; 222 | /*1007 */ uint32_t synchronousWindowLength; 223 | /*1008 */ char_t manufacturerDeviceName[11]; 224 | /*1009 */ char_t manufacturerHardwareVersion[4]; 225 | /*100A */ char_t manufacturerSoftwareVersion[4]; 226 | /*1014 */ uint32_t COB_ID_EMCY; 227 | /*1015 */ uint16_t inhibitTimeEMCY; 228 | /*1016 */ uint32_t consumerHeartbeatTime[4]; 229 | /*1017 */ uint16_t producerHeartbeatTime; 230 | /*1018 */ OD_identity_t identity; 231 | /*1019 */ uint8_t synchronousCounterOverflowValue; 232 | /*1029 */ uint8_t errorBehavior[6]; 233 | /*1200[1] */ OD_SDOServerParameter_t SDOServerParameter[1]; 234 | /*1400[4] */ OD_RPDOCommunicationParameter_t RPDOCommunicationParameter[4]; 235 | /*1600[4] */ OD_RPDOMappingParameter_t RPDOMappingParameter[4]; 236 | /*1800[4] */ OD_TPDOCommunicationParameter_t TPDOCommunicationParameter[4]; 237 | /*1A00[4] */ OD_TPDOMappingParameter_t TPDOMappingParameter[4]; 238 | /*1F80 */ uint32_t NMTStartup; 239 | /*2101 */ uint8_t CANNodeID; 240 | /*2102 */ uint16_t CANBitRate; 241 | /*2111 */ int32_t variableROMInt32[16]; 242 | 243 | uint32_t LastWord; 244 | }; 245 | 246 | 247 | /***** Declaration of Object Dictionary variables *****************************/ 248 | extern struct sCO_OD_RAM CO_OD_RAM; 249 | 250 | extern struct sCO_OD_EEPROM CO_OD_EEPROM; 251 | 252 | extern struct sCO_OD_ROM CO_OD_ROM; 253 | 254 | 255 | /******************************************************************************* 256 | ALIASES FOR OBJECT DICTIONARY VARIABLES 257 | *******************************************************************************/ 258 | /*1000, Data Type: uint32_t */ 259 | #define OD_deviceType CO_OD_ROM.deviceType 260 | 261 | /*1001, Data Type: uint8_t */ 262 | #define OD_errorRegister CO_OD_RAM.errorRegister 263 | 264 | /*1002, Data Type: uint32_t */ 265 | #define OD_manufacturerStatusRegister CO_OD_RAM.manufacturerStatusRegister 266 | 267 | /*1003, Data Type: uint32_t, Array[8] */ 268 | #define OD_preDefinedErrorField CO_OD_RAM.preDefinedErrorField 269 | #define ODL_preDefinedErrorField_arrayLength 8 270 | 271 | /*1005, Data Type: uint32_t */ 272 | #define OD_COB_ID_SYNCMessage CO_OD_ROM.COB_ID_SYNCMessage 273 | 274 | /*1006, Data Type: uint32_t */ 275 | #define OD_communicationCyclePeriod CO_OD_ROM.communicationCyclePeriod 276 | 277 | /*1007, Data Type: uint32_t */ 278 | #define OD_synchronousWindowLength CO_OD_ROM.synchronousWindowLength 279 | 280 | /*1008, Data Type: char_t, Array[11] */ 281 | #define OD_manufacturerDeviceName CO_OD_ROM.manufacturerDeviceName 282 | #define ODL_manufacturerDeviceName_stringLength 11 283 | 284 | /*1009, Data Type: char_t, Array[4] */ 285 | #define OD_manufacturerHardwareVersion CO_OD_ROM.manufacturerHardwareVersion 286 | #define ODL_manufacturerHardwareVersion_stringLength 4 287 | 288 | /*100A, Data Type: char_t, Array[4] */ 289 | #define OD_manufacturerSoftwareVersion CO_OD_ROM.manufacturerSoftwareVersion 290 | #define ODL_manufacturerSoftwareVersion_stringLength 4 291 | 292 | /*1010, Data Type: uint32_t, Array[1] */ 293 | #define OD_storeParameters CO_OD_RAM.storeParameters 294 | #define ODL_storeParameters_arrayLength 1 295 | #define ODA_storeParameters_saveAllParameters 0 296 | 297 | /*1011, Data Type: uint32_t, Array[1] */ 298 | #define OD_restoreDefaultParameters CO_OD_RAM.restoreDefaultParameters 299 | #define ODL_restoreDefaultParameters_arrayLength 1 300 | #define ODA_restoreDefaultParameters_restoreAllDefaultParameters 0 301 | 302 | /*1014, Data Type: uint32_t */ 303 | #define OD_COB_ID_EMCY CO_OD_ROM.COB_ID_EMCY 304 | 305 | /*1015, Data Type: uint16_t */ 306 | #define OD_inhibitTimeEMCY CO_OD_ROM.inhibitTimeEMCY 307 | 308 | /*1016, Data Type: uint32_t, Array[4] */ 309 | #define OD_consumerHeartbeatTime CO_OD_ROM.consumerHeartbeatTime 310 | #define ODL_consumerHeartbeatTime_arrayLength 4 311 | 312 | /*1017, Data Type: uint16_t */ 313 | #define OD_producerHeartbeatTime CO_OD_ROM.producerHeartbeatTime 314 | 315 | /*1018, Data Type: OD_identity_t */ 316 | #define OD_identity CO_OD_ROM.identity 317 | 318 | /*1019, Data Type: uint8_t */ 319 | #define OD_synchronousCounterOverflowValue CO_OD_ROM.synchronousCounterOverflowValue 320 | 321 | /*1029, Data Type: uint8_t, Array[6] */ 322 | #define OD_errorBehavior CO_OD_ROM.errorBehavior 323 | #define ODL_errorBehavior_arrayLength 6 324 | #define ODA_errorBehavior_communication 0 325 | #define ODA_errorBehavior_communicationOther 1 326 | #define ODA_errorBehavior_communicationPassive 2 327 | #define ODA_errorBehavior_generic 3 328 | #define ODA_errorBehavior_deviceProfile 4 329 | #define ODA_errorBehavior_manufacturerSpecific 5 330 | 331 | /*1200[1], Data Type: OD_SDOServerParameter_t, Array[1] */ 332 | #define OD_SDOServerParameter CO_OD_ROM.SDOServerParameter 333 | 334 | /*1400[4], Data Type: OD_RPDOCommunicationParameter_t, Array[4] */ 335 | #define OD_RPDOCommunicationParameter CO_OD_ROM.RPDOCommunicationParameter 336 | 337 | /*1600[4], Data Type: OD_RPDOMappingParameter_t, Array[4] */ 338 | #define OD_RPDOMappingParameter CO_OD_ROM.RPDOMappingParameter 339 | 340 | /*1800[4], Data Type: OD_TPDOCommunicationParameter_t, Array[4] */ 341 | #define OD_TPDOCommunicationParameter CO_OD_ROM.TPDOCommunicationParameter 342 | 343 | /*1A00[4], Data Type: OD_TPDOMappingParameter_t, Array[4] */ 344 | #define OD_TPDOMappingParameter CO_OD_ROM.TPDOMappingParameter 345 | 346 | /*1F80, Data Type: uint32_t */ 347 | #define OD_NMTStartup CO_OD_ROM.NMTStartup 348 | 349 | /*2100, Data Type: oChar_t, Array[10] */ 350 | #define OD_errorStatusBits CO_OD_RAM.errorStatusBits 351 | #define ODL_errorStatusBits_stringLength 10 352 | 353 | /*2101, Data Type: uint8_t */ 354 | #define OD_CANNodeID CO_OD_ROM.CANNodeID 355 | 356 | /*2102, Data Type: uint16_t */ 357 | #define OD_CANBitRate CO_OD_ROM.CANBitRate 358 | 359 | /*2103, Data Type: uint16_t */ 360 | #define OD_SYNCCounter CO_OD_RAM.SYNCCounter 361 | 362 | /*2104, Data Type: uint16_t */ 363 | #define OD_SYNCTime CO_OD_RAM.SYNCTime 364 | 365 | /*2106, Data Type: uint32_t */ 366 | #define OD_powerOnCounter CO_OD_EEPROM.powerOnCounter 367 | 368 | /*2107, Data Type: uint16_t, Array[5] */ 369 | #define OD_performance CO_OD_RAM.performance 370 | #define ODL_performance_arrayLength 5 371 | #define ODA_performance_cyclesPerSecond 0 372 | #define ODA_performance_timerCycleTime 1 373 | #define ODA_performance_timerCycleMaxTime 2 374 | #define ODA_performance_mainCycleTime 3 375 | #define ODA_performance_mainCycleMaxTime 4 376 | 377 | /*2108, Data Type: int16_t, Array[1] */ 378 | #define OD_temperature CO_OD_RAM.temperature 379 | #define ODL_temperature_arrayLength 1 380 | #define ODA_temperature_mainPCB 0 381 | 382 | /*2109, Data Type: int16_t, Array[1] */ 383 | #define OD_voltage CO_OD_RAM.voltage 384 | #define ODL_voltage_arrayLength 1 385 | #define ODA_voltage_mainPCBSupply 0 386 | 387 | /*2110, Data Type: int32_t, Array[16] */ 388 | #define OD_variableInt32 CO_OD_RAM.variableInt32 389 | #define ODL_variableInt32_arrayLength 16 390 | 391 | /*2111, Data Type: int32_t, Array[16] */ 392 | #define OD_variableROMInt32 CO_OD_ROM.variableROMInt32 393 | #define ODL_variableROMInt32_arrayLength 16 394 | 395 | /*2112, Data Type: int32_t, Array[16] */ 396 | #define OD_variableNVInt32 CO_OD_EEPROM.variableNVInt32 397 | #define ODL_variableNVInt32_arrayLength 16 398 | 399 | /*2120, Data Type: OD_testVar_t */ 400 | #define OD_testVar CO_OD_RAM.testVar 401 | 402 | /*2130, Data Type: OD_time_t */ 403 | #define OD_time CO_OD_RAM.time 404 | 405 | /*6000, Data Type: uint8_t, Array[8] */ 406 | #define OD_readInput8Bit CO_OD_RAM.readInput8Bit 407 | #define ODL_readInput8Bit_arrayLength 8 408 | 409 | /*6200, Data Type: uint8_t, Array[8] */ 410 | #define OD_writeOutput8Bit CO_OD_RAM.writeOutput8Bit 411 | #define ODL_writeOutput8Bit_arrayLength 8 412 | 413 | /*6401, Data Type: int16_t, Array[12] */ 414 | #define OD_readAnalogueInput16Bit CO_OD_RAM.readAnalogueInput16Bit 415 | #define ODL_readAnalogueInput16Bit_arrayLength 12 416 | 417 | /*6411, Data Type: int16_t, Array[8] */ 418 | #define OD_writeAnalogueOutput16Bit CO_OD_RAM.writeAnalogueOutput16Bit 419 | #define ODL_writeAnalogueOutput16Bit_arrayLength 8 420 | 421 | 422 | #endif 423 | 424 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CANopenNode example for Mbed OS 2 | 3 | [![CI master](https://github.com/Alphatronics/mbed-os-example-canopen/actions/workflows/master.yml/badge.svg)](https://github.com/Alphatronics/mbed-os-example-canopen/actions/workflows/master.yml) 4 | 5 | This guide reviews the steps required to get CANopenNode working on an Mbed OS platform. 6 | 7 | **CANopenNode** is free and open source CANopen Stack. 8 | 9 | CANopen is the internationally standardized (EN 50325-4) 10 | ([CiA301](http://can-cia.org/standardization/technical-documents)) 11 | CAN-based higher-layer protocol for embedded control system. For more 12 | information on CANopen see http://www.can-cia.org/ 13 | 14 | CANopenNode is written in ANSI C in object-oriented way. It runs on 15 | different microcontrollers, as standalone application or with RTOS. 16 | Stack includes master functionalities. For Linux implementation with 17 | CANopen master functionalities see 18 | https://github.com/CANopenNode/CANopenSocket. 19 | 20 | Variables (communication, device, custom) are ordered in CANopen Object 21 | Dictionary and are accessible from both: C code and from CAN network. 22 | 23 | CANopenNode homepage is https://github.com/CANopenNode/CANopenNode 24 | 25 | ## CANopen Features 26 | 27 | - NMT slave to start, stop, reset device. Simple NMT master. 28 | - Heartbeat producer/consumer error control. 29 | - PDO linking and dynamic mapping for fast exchange of process variables. 30 | - SDO expedited, segmented and block transfer for service access to all parameters. 31 | - SDO master. 32 | - Emergency message. 33 | - Sync producer/consumer. 34 | - Non-volatile storage. 35 | 36 | ## Usage of CANopenNode 37 | 38 | CANopenNode itself doesn't have complete working code for any microcontroller. 39 | It is only the library with the stack and drivers for different 40 | microcontrollers. It has example, which should compile on any system with 41 | template driver (drvTemplate), which actually doesn't access CAN hardware. 42 | CANopenNode should be used as a git submodule included in a project with 43 | 44 | ## Supported boards 45 | 46 | * STM32 Nucleo F091RC 47 | * STM32 Nucleo L496ZG 48 | 49 | ## Deploying the firmware 50 | 51 | ### Import the example application 52 | 53 | Please install [mbed CLI](https://github.com/ARMmbed/mbed-cli#installing-mbed-cli). 54 | 55 | From the command-line, import the example: 56 | 57 | ``` 58 | mbed import mbed-os-example-canopen 59 | cd mbed-os-example-canopen 60 | ``` 61 | 62 | ### Now compile 63 | 64 | Invoke `mbed compile`, and specify the name of your platform and your favorite toolchain (`GCC_ARM`, `ARM`, `IAR`). For example, for the ARM Compiler 5: 65 | 66 | ``` 67 | mbed compile -m NUCLEO_F091RC -t GCC_ARM 68 | ``` 69 | 70 | Your PC may take a few minutes to compile your code. At the end, you see the following result: 71 | 72 | ``` 73 | [snip] 74 | +-----------------------+--------------+----------+-----------+ 75 | | Module | .text | .data | .bss | 76 | |-----------------------|--------------|----------|-----------| 77 | | CANopenNode\CANopen.o | 3626(+0) | 0(+0) | 86(+0) | 78 | | CANopenNode\stack | 23056(-146) | 0(+0) | 276(+0) | 79 | | CO_OD.o | 0(+0) | 980(+0) | 0(+0) | 80 | | [fill] | 98(+2) | 12(+0) | 20(+0) | 81 | | [lib]\c.a | 25188(+0) | 2472(+0) | 89(+0) | 82 | | [lib]\gcc.a | 8464(+0) | 0(+0) | 0(+0) | 83 | | [lib]\misc | 192(+0) | 4(+0) | 28(+0) | 84 | | main.o | 1338(+0) | 0(+0) | 222(+0) | 85 | | mbed-os\components | 244(+0) | 0(+0) | 0(+0) | 86 | | mbed-os\drivers | 1804(+0) | 0(+0) | 0(+0) | 87 | | mbed-os\events | 3184(+0) | 0(+0) | 3108(+0) | 88 | | mbed-os\hal | 2970(+0) | 4(+0) | 66(+0) | 89 | | mbed-os\platform | 6008(+0) | 260(+0) | 364(+0) | 90 | | mbed-os\rtos | 18026(+0) | 168(+0) | 5973(+0) | 91 | | mbed-os\targets | 15318(+0) | 4(+0) | 1064(+0) | 92 | | Subtotals | 109516(-144) | 3904(+0) | 11296(+0) | 93 | Total Static RAM memory (data + bss): 15200(+0) bytes 94 | Total Flash memory (text + data): 113420(-144) bytes 95 | 96 | Image: .\BUILD\NUCLEO_F091RC\GCC_ARM-DEBUG\mbed-os-example-canopen.bin 97 | ``` 98 | 99 | ### Program your board 100 | 101 | 1. Connect your mbed device to the computer over USB. 102 | 2. Copy the binary file to the mbed device. 103 | 3. Press the reset button to start the program. 104 | 105 | ## Wiring 106 | 107 | ![Wiring](doc/wiring.jpg) 108 | 109 | ## Output 110 | 111 | To view the serial output you can use any terminal client of your choosing such as [PuTTY](http://www.putty.org/) or [CoolTerm](http://freeware.the-meiers.org/). 112 | 113 | The default baud rate for this application is set to `115200` and may be modified in the `mbed_app.json` file. 114 | 115 | You can find more information on the Mbed OS configuration tools and serial communication in Mbed OS in the related [related links section](#related-links). 116 | 117 | 118 | ## Troubleshooting 119 | 120 | If you have problems, you can review the [documentation](https://os.mbed.com/docs/latest/tutorials/debugging.html) for suggestions on what could be wrong and how to fix it. 121 | 122 | ## Related Links 123 | 124 | * [Mbed OS Configuration](https://os.mbed.com/docs/latest/reference/configuration.html) 125 | * [Mbed OS Serial Communication](https://os.mbed.com/docs/latest/tutorials/serial-communication.html) 126 | 127 | ### License and contributions 128 | 129 | The software is provided under Apache-2.0 license. Contributions to this project are accepted under the same license. Please see contributing.md for more info. 130 | 131 | This project contains code from other projects. The original license text is included in those source files. They must comply with our license guide. 132 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #define CAN_MODULE_ADDRESS CAN_1 // the hardware address of the can bus, since our STM32F091 has only one CAN bus this param is of no use so any value is OK 5 | #define CANOPEN_DEFAULT_NODE_ID 0x0A // CANopen NODE ID 6 | #define CAN_BITRATE 250 // in kbps 7 | 8 | #endif //CONFIG_H -------------------------------------------------------------------------------- /doc/wiring.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alphatronics/mbed-os-example-canopen/81941bf101cf413ddba24c25c8db61e313b8dc86/doc/wiring.jpg -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* mbed Microcontroller Library 2 | * Copyright (c) 2018 ARM Limited 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "mbed.h" 7 | 8 | #include "CANopen.h" 9 | #include "config.h" 10 | 11 | extern "C" { 12 | #include "CO_driver.h" 13 | } 14 | #include "CO_Indicators.h" 15 | 16 | 17 | // flag used to stop threads 18 | #define STOP_THREADS_FLAG 1 19 | // Interval of tmrTask thread in micros: should always be 1ms! 20 | static const int RTTHREAD_INTERVAL_1000US = 1000; 21 | // variable increments each millisecond 22 | volatile uint16_t CO_timer1ms = 0U; 23 | // thread object that holds the RT thread 24 | Thread* rtThread; 25 | // function executed by RT thread 26 | static void rtTask(void); 27 | // Timer used to measure performance of RT thread 28 | Timer rtPerfTimer; 29 | 30 | 31 | 32 | DigitalOut userLed(LED2, 1); 33 | DigitalIn userButton(USER_BUTTON); 34 | 35 | 36 | 37 | 38 | // main() runs in its own thread in the OS 39 | int main() 40 | { 41 | printf("######## CANOPEN DEMO (" __DATE__ ", " __TIME__ ") ##########\n"); 42 | OD_powerOnCounter++; // increment boot counter 43 | 44 | CO_NMT_reset_cmd_t resetCmd = CO_RESET_NOT; 45 | while(resetCmd != CO_RESET_APP && resetCmd != CO_RESET_QUIT) 46 | { 47 | printf("####### start comms-loop #######\n"); 48 | 49 | // initialize CANopen 50 | CO_ReturnError_t err = CO_init((void*)CAN_MODULE_ADDRESS, CANOPEN_DEFAULT_NODE_ID, CAN_BITRATE); 51 | if(err != CO_ERROR_NO){ 52 | printf("ERROR: CO_init, code: %d\n", err); 53 | ThisThread::sleep_for(3000); // in ms 54 | break; 55 | } 56 | 57 | // allow rtThread to process SYNC, RPDO and TPDO 58 | printf("Enabling rtThread processing\n"); 59 | rtThread = new Thread(osPriorityAboveNormal, 8 * 1024, NULL, "rtThread"); 60 | osStatus threadstate = rtThread->start(callback(rtTask)); 61 | if(threadstate != osOK) { 62 | printf("Failed starting rtThread\n"); 63 | } 64 | 65 | CO_CANsetNormalMode(CO->CANmodule[0]); 66 | 67 | resetCmd = CO_RESET_NOT; 68 | uint16_t previousTicksMs = CO_timer1ms; 69 | 70 | printf("CANopen ready\n"); 71 | while(resetCmd == CO_RESET_NOT) 72 | { 73 | // calc the amount of millis have passed since we last ran this loop 74 | uint16_t currentTicksMs = CO_timer1ms; 75 | uint16_t millisDiff = currentTicksMs - previousTicksMs; 76 | previousTicksMs = currentTicksMs; 77 | 78 | // CANopen process (note: millisDiff will typically be 0ms or 1ms since this code loops faster than the rtThread) 79 | resetCmd = CO_process(CO, millisDiff, NULL); 80 | 81 | // Nonblocking application code may go here. 82 | // ex: killing the watchdog may be a good idea 83 | // ex: process EEPROM 84 | } 85 | 86 | printf("CANopen communication reset\n"); 87 | rtThread->flags_set(STOP_THREADS_FLAG); 88 | rtThread->join(); 89 | delete(rtThread); 90 | rtThread = NULL; 91 | 92 | // delete objects from memory 93 | CO_delete((void*)CAN_MODULE_ADDRESS); // => may crash application if CO_init failed 94 | 95 | // STATE MACHINE: CANopen communication reset - cleanup and reinitialize CANopen objects 96 | CO_CANreset(); 97 | } 98 | 99 | // program exit: stop threads 100 | printf("Program exit!!\n"); 101 | 102 | // reset 103 | if(resetCmd != CO_RESET_QUIT) 104 | system_reset(); 105 | return 0; 106 | } 107 | 108 | 109 | static void rtLoop(void) 110 | { 111 | // Process Sync and read RPDO 112 | bool_t syncWas = CO_process_SYNC(CO, RTTHREAD_INTERVAL_1000US); 113 | CO_process_RPDO(CO, syncWas); 114 | 115 | //apply RPDO value to DigitalOut(s) 116 | // note: userLed is first bit of RPDO-0 117 | uint8_t outputmap = OD_writeOutput8Bit[0]; 118 | userLed.write(outputmap & 0x01); 119 | 120 | //apply DigitalIn(s) value to TPDO 121 | // note: userButton is first bit of TPDO-0 and is also inverted 122 | uint8_t inputmap = (userButton.read() == 0 ? 1 : 0) & 0x01; 123 | OD_readInput8Bit[0] = inputmap; 124 | 125 | // Process TPDO 126 | CO_process_TPDO(CO, syncWas, RTTHREAD_INTERVAL_1000US); 127 | 128 | //Update LED indicators 129 | CO_Indicators_process(CO->NMT); 130 | } 131 | 132 | 133 | // timer thread executes in constant intervals 134 | static void rtTask(void) 135 | { 136 | rtPerfTimer.start(); 137 | 138 | // Sleep for exact 1ms. 139 | // It schedules this this thread inactive which allows the main thread 140 | // to continue execution. It would be better if we could sleep more precisely 141 | // using nanos instead, however mbed doesn't allow that. The benefit would 142 | // be that we could sleep only the time needed to fit exactly 143 | // 1 ms taking into account the time to execute the RT code below. 144 | while(!ThisThread::flags_wait_any_for(STOP_THREADS_FLAG, RTTHREAD_INTERVAL_1000US/1000)) { 145 | 146 | CO_timer1ms++; 147 | 148 | if(CO->CANmodule[0]->CANnormal) { 149 | // We use a Timer to measure the RT thread execution time. 150 | // In case of bad performance, an EMCY msg will be created later on. 151 | rtPerfTimer.reset(); 152 | int begin = rtPerfTimer.read_us(); 153 | 154 | // perform RT tasks 155 | // NOTE: DO NOT PERFORM ANY PRINTF ACTIONS IN THE RT_LOOP, 156 | // it's too slow and will trigger the bad performance timer 157 | // and hence put the device in pre-op mode until reset. 158 | rtLoop(); 159 | 160 | //calculate time spend executing RT code, send EMCY in case of bad performance (>1ms) 161 | int timespan = rtPerfTimer.read_us() - begin; 162 | if(timespan > RTTHREAD_INTERVAL_1000US) { 163 | float tsMillis = static_cast(timespan) / 1000; 164 | printf("RT slow: %.3fms\n", tsMillis); 165 | CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0U); 166 | // => device will enter pre-op and must be reset 167 | } 168 | } 169 | } 170 | } -------------------------------------------------------------------------------- /mbed-os.lib: -------------------------------------------------------------------------------- 1 | https://github.com/ARMmbed/mbed-os/#0b7d9af4dd104e57907f526ff963aa09e7018ffa 2 | -------------------------------------------------------------------------------- /mbed_app.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_overrides": { 3 | "*": { 4 | "platform.stdio-baud-rate": 115200, 5 | "platform.default-serial-baud-rate": 115200, 6 | "platform.stdio-convert-newlines": true 7 | }, 8 | "LPC1768": { 9 | "target.features_remove": ["NANOSTACK", "BLE", "LWIP"] 10 | }, 11 | "NUCLEO_F091RC": { 12 | "target.features_remove": ["NANOSTACK", "BLE", "LWIP"] 13 | } 14 | } 15 | } 16 | --------------------------------------------------------------------------------