├── .github └── FUNDING.yml ├── .gitignore ├── .gitmodules ├── Doxyfile ├── LICENSE ├── PIC24_dsPIC33 ├── CO_driver.c └── CO_driver_target.h ├── PIC32 ├── CO_application.h ├── CO_driver.c ├── CO_driver_target.h ├── CO_eepromPIC32.c └── CO_main_PIC32.c ├── README.md ├── dsPIC30F ├── CO_driver.c └── CO_driver_target.h ├── dsPIC33C ├── CO_driver.c └── CO_driver_target.h ├── example_PIC32.X ├── CO_driver_custom.h ├── Makefile ├── appl_max32_demo.c └── nbproject │ ├── configurations.xml │ └── project.xml ├── example_dsPIC30F.X ├── Makefile ├── main_dsPIC30F.c └── nbproject │ ├── configurations.xml │ └── project.xml └── example_dsPIC33_ex16_IO.X ├── Makefile ├── main_dsPIC33F.c └── nbproject ├── configurations.xml └── project.xml /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # CANopenNode 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['paypal.me/jnz022'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /html 2 | 3 | # MPLAB X IDE, keep only base project files: 4 | # - *.X/Makefile 5 | # - *.X/nbproject/configurations.xml 6 | # - *.X/nbproject/project.xml 7 | 8 | *.X/build/ 9 | *.X/debug/ 10 | *.X/dist/ 11 | *.X/nbproject/private/ 12 | *.X/nbproject/*.mk 13 | *.X/nbproject/Makefile-genesis.properties 14 | *.X/nbproject/Package-default.bash 15 | *.X/.generated_files/ 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "CANopenNode"] 2 | path = CANopenNode 3 | url = https://github.com/CANopenNode/CANopenNode.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /PIC24_dsPIC33/CO_driver_target.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Microchip dsPIC33 or PIC24 specific definitions for CANopenNode. 3 | * 4 | * @file CO_driver_target.h 5 | * @author Janez Paternoster 6 | * @author Peter Rozsahegyi (EDS) 7 | * @author Jens Nielsen (CAN receive) 8 | * @copyright 2004 - 2020 Janez Paternoster 9 | * 10 | * This file is part of CANopenNode, an opensource CANopen Stack. 11 | * Project home page is . 12 | * For more information on CANopen see . 13 | * 14 | * Licensed under the Apache License, Version 2.0 (the "License"); 15 | * you may not use this file except in compliance with the License. 16 | * You may obtain a copy of the License at 17 | * 18 | * http://www.apache.org/licenses/LICENSE-2.0 19 | * 20 | * Unless required by applicable law or agreed to in writing, software 21 | * distributed under the License is distributed on an "AS IS" BASIS, 22 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23 | * See the License for the specific language governing permissions and 24 | * limitations under the License. 25 | */ 26 | 27 | 28 | #ifndef CO_DRIVER_TARGET 29 | #define CO_DRIVER_TARGET 30 | 31 | /* This file contains device and application specific definitions. 32 | * It is included from CO_driver.h, which contains documentation 33 | * for definitions below. */ 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #ifdef CO_DRIVER_CUSTOM 41 | #include "CO_driver_custom.h" 42 | #endif 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | /* Stack configuration override from CO_driver.h. 49 | * For more information see file CO_config.h. */ 50 | /* Use default options here, it is possible to reduce memory usage. */ 51 | 52 | 53 | /* Basic definitions */ 54 | #define CO_LITTLE_ENDIAN 55 | #define CO_SWAP_16(x) x 56 | #define CO_SWAP_32(x) x 57 | #define CO_SWAP_64(x) x 58 | #define CO_OWN_INTTYPES 59 | #define PRIu32 "lu" 60 | #define PRId32 "ld" 61 | /* NULL is defined in stddef.h */ 62 | /* true and false are defined in stdbool.h */ 63 | /* int8_t to uint64_t are defined in stdint.h */ 64 | typedef unsigned char bool_t; 65 | typedef float float32_t; 66 | typedef long double float64_t; 67 | 68 | 69 | /* CAN message buffer sizes for CAN module 1 and 2. Valid values 70 | * are 0, 4, 6, 8, 12, 16. Default is one TX and seven RX messages (FIFO). */ 71 | #ifndef CO_CAN1msgBuffSize 72 | #define CO_CAN1msgBuffSize 8 73 | #endif 74 | #ifndef CO_CAN2msgBuffSize 75 | #define CO_CAN2msgBuffSize 0 //CAN module 2 not used by default 76 | #endif 77 | 78 | /* Default DMA addresses for CAN modules. */ 79 | #ifndef CO_CAN1_DMA0 80 | #define CO_CAN1_DMA0 ADDR_DMA0 81 | #endif 82 | #ifndef CO_CAN1_DMA1 83 | #define CO_CAN1_DMA1 ADDR_DMA1 84 | #endif 85 | #ifndef CO_CAN2_DMA0 86 | #define CO_CAN2_DMA0 ADDR_DMA2 87 | #endif 88 | #ifndef CO_CAN2_DMA1 89 | #define CO_CAN2_DMA1 ADDR_DMA3 90 | #endif 91 | 92 | /* Define DMA attribute on supported platforms */ 93 | #if defined(__dsPIC33F__) || defined(__PIC24H__) || defined(__DMA_BASE) 94 | #define __dma __attribute__((space(dma))) 95 | #else 96 | #define __dma 97 | #if defined(__C30_VERSION__) && !defined(__XC16_VERSION__) 98 | #define __builtin_dmaoffset(V) (uint16_t)V 99 | #endif 100 | #endif 101 | 102 | /* Define EDS attribute on supported platforms */ 103 | #if defined(__HAS_EDS__) 104 | #define __eds __attribute__((eds)) 105 | #if defined(__C30_VERSION__) && !defined(__XC16_VERSION__) 106 | #define __builtin_dmapage(V) (uint16_t)0 107 | #endif 108 | #else 109 | #define __eds 110 | #define __eds__ 111 | #endif 112 | 113 | /* CAN module base addresses */ 114 | #define ADDR_CAN1 ((void *)&C1CTRL1) 115 | #define ADDR_CAN2 ((void *)&C2CTRL1) 116 | 117 | /* DMA addresses */ 118 | #define ADDR_DMA0 ((uint16_t)&DMA0CON) 119 | #define ADDR_DMA1 ((uint16_t)&DMA1CON) 120 | #define ADDR_DMA2 ((uint16_t)&DMA2CON) 121 | #define ADDR_DMA3 ((uint16_t)&DMA3CON) 122 | #define ADDR_DMA4 ((uint16_t)&DMA4CON) 123 | #define ADDR_DMA5 ((uint16_t)&DMA5CON) 124 | #define ADDR_DMA6 ((uint16_t)&DMA6CON) 125 | #define ADDR_DMA7 ((uint16_t)&DMA7CON) 126 | 127 | 128 | /* CAN receive message structure as aligned in CAN module. */ 129 | /* In dsPIC33F and PIC24H this structure is used for both: transmitting and 130 | * receiving to and from CAN module. (Object is ownded by CAN module). 131 | */ 132 | typedef struct { 133 | uint16_t ident; /* Standard Identifier as aligned in CAN module. 16 bits: 134 | 'UUUSSSSS SSSSSSRE' (U: unused; S: SID; R=SRR; E=IDE). */ 135 | uint16_t extIdent; /* Extended identifier, not used here */ 136 | uint16_t DLC :4; /* Data length code (bits 0...3) */ 137 | uint16_t DLCrest :12; /* Not used here (bits 4..15) */ 138 | uint8_t data[8]; /* 8 data bytes */ 139 | uint8_t dummy; /* Not used */ 140 | uint8_t FILHIT; /* Filter hit */ 141 | } CO_CANrxMsg_t; 142 | 143 | /* Access to received CAN message */ 144 | #define CO_CANrxMsg_readIdent(msg) ((((uint16_t)(((CO_CANrxMsg_t *)(msg))->ident))>>2)&0x7FF) 145 | #define CO_CANrxMsg_readDLC(msg) ((uint8_t)(((CO_CANrxMsg_t *)(msg))->DLC)) 146 | #define CO_CANrxMsg_readData(msg) ((uint8_t *)(((CO_CANrxMsg_t *)(msg))->data)) 147 | 148 | /* Received message object */ 149 | typedef struct { 150 | uint16_t ident; 151 | uint16_t mask; 152 | void *object; 153 | void (*CANrx_callback)(void *object, void *message); 154 | } CO_CANrx_t; 155 | 156 | /* Transmit message object */ 157 | typedef struct { 158 | uint16_t ident; /* Standard Identifier as aligned in CAN module. 16 bits: 159 | 'SSSSSUUU SSSSSSRE' (U: unused; S: SID; R=SRR; E=IDE). */ 160 | uint8_t DLC; 161 | uint8_t data[8]; 162 | volatile bool_t bufferFull; 163 | volatile bool_t syncFlag; 164 | } CO_CANtx_t; 165 | 166 | /* CAN module object */ 167 | typedef struct { 168 | void *CANptr; 169 | __eds__ CO_CANrxMsg_t *CANmsgBuff; /* dsPIC33F specific: CAN message buffer for CAN module */ 170 | uint8_t CANmsgBuffSize; /* dsPIC33F specific: Size of the above buffer */ 171 | CO_CANrx_t *rxArray; 172 | uint16_t rxSize; 173 | CO_CANtx_t *txArray; 174 | uint16_t txSize; 175 | uint16_t CANerrorStatus; 176 | volatile bool_t CANnormal; 177 | volatile bool_t useCANrxFilters; 178 | volatile bool_t bufferInhibitFlag; 179 | volatile bool_t firstCANtxMessage; 180 | volatile uint16_t CANtxCount; 181 | uint16_t errOld; 182 | } CO_CANmodule_t; 183 | 184 | 185 | /* (un)lock critical section in CO_CANsend() */ 186 | #define CO_LOCK_CAN_SEND(CAN_MODULE) asm volatile ("disi #0x3FFF") 187 | #define CO_UNLOCK_CAN_SEND(CAN_MODULE) asm volatile ("disi #0x0000") 188 | 189 | /* (un)lock critical section in CO_errorReport() or CO_errorReset() */ 190 | #define CO_LOCK_EMCY(CAN_MODULE) asm volatile ("disi #0x3FFF") 191 | #define CO_UNLOCK_EMCY(CAN_MODULE) asm volatile ("disi #0x0000") 192 | 193 | /* (un)lock critical section when accessing Object Dictionary */ 194 | #define CO_LOCK_OD(CAN_MODULE) asm volatile ("disi #0x3FFF") 195 | #define CO_UNLOCK_OD(CAN_MODULE) asm volatile ("disi #0x0000") 196 | 197 | /* dsPIC33F specific */ 198 | #define CO_DISABLE_INTERRUPTS() asm volatile ("disi #0x3FFF") 199 | #define CO_ENABLE_INTERRUPTS() asm volatile ("disi #0x0000") 200 | 201 | /* Synchronization between CAN receive and message processing threads. */ 202 | #define CO_MemoryBarrier() 203 | #define CO_FLAG_READ(rxNew) ((rxNew) != NULL) 204 | #define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} 205 | #define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} 206 | 207 | 208 | /* CAN bit rates 209 | * 210 | * CAN bit rates are initializers for array of eight CO_CANbitRateData_t 211 | * objects. 212 | * 213 | * Macros are not used by driver itself, they may be used by application with 214 | * combination with object CO_CANbitRateData_t. 215 | * Application must declare following global variable depending on CO_FCY used: 216 | * const CO_CANbitRateData_t CO_CANbitRateData[8] = {CO_CANbitRateDataInitializers}; 217 | * 218 | * There are initializers for eight objects, which corresponds to following 219 | * CAN bit rates (in kbps): 10, 20, 50, 125, 250, 500, 800, 1000. 220 | * 221 | * CO_FCY is internal instruction cycle clock frequency in kHz units. See 222 | * dsPIC33F documentation for more information on FCY. 223 | * 224 | * Possible values for FCY are (in three groups): 225 | * - Optimal CAN bit timing on all Baud Rates: 8000, 12000, 16000, 24000. 226 | * - Not so optimal CAN bit timing on all Baud Rates: 4000, 32000. 227 | * - not all CANopen Baud Rates possible: 2000, 3000, 5000, 6000, 10000, 228 | * 20000, 40000, 48000, 56000, 64000, 70000. 229 | * 230 | * IMPORTANT: For FCY<=12000 there is unresolved bug; CANCKS configuration 231 | * bit on ECAN does not work, so some baudrates are not possible. 232 | */ 233 | #ifdef CO_FCY 234 | /* Macros, which divides K into (SJW + PROP + PhSeg1 + PhSeg2) */ 235 | #define TQ_x_4 1, 1, 1, 1 236 | #define TQ_x_5 1, 1, 2, 1 237 | #define TQ_x_6 1, 1, 3, 1 238 | #define TQ_x_8 1, 2, 3, 2 239 | #define TQ_x_9 1, 2, 4, 2 240 | #define TQ_x_10 1, 3, 4, 2 241 | #define TQ_x_12 1, 3, 6, 2 242 | #define TQ_x_14 1, 4, 7, 2 243 | #define TQ_x_15 1, 4, 8, 2 /* good timing */ 244 | #define TQ_x_16 1, 5, 8, 2 /* good timing */ 245 | #define TQ_x_17 1, 6, 8, 2 /* good timing */ 246 | #define TQ_x_18 1, 7, 8, 2 /* good timing */ 247 | #define TQ_x_19 1, 8, 8, 2 /* good timing */ 248 | #define TQ_x_20 1, 8, 8, 3 /* good timing */ 249 | #define TQ_x_21 1, 8, 8, 4 250 | #define TQ_x_25 1, 8, 8, 8 251 | 252 | #if CO_FCY == 2000 253 | #define CO_CANbitRateDataInitializers \ 254 | {1, 5, TQ_x_20, 10}, \ 255 | {2, 5, TQ_x_20, 20}, \ 256 | {1, 1, TQ_x_20, 50}, \ 257 | {2, 1, TQ_x_16, 125}, \ 258 | {2, 1, TQ_x_8 , 250}, \ 259 | {2, 1, TQ_x_4 , 500}, \ 260 | {2, 1, TQ_x_4 , 0}, \ 261 | {2, 1, TQ_x_4 , 0} 262 | #elif CO_FCY == 3000 263 | #define CO_CANbitRateDataInitializers \ 264 | {2, 15, TQ_x_20, 10}, \ 265 | {1, 5, TQ_x_15, 20}, \ 266 | {1, 2, TQ_x_15, 50}, \ 267 | {1, 1, TQ_x_12, 125}, \ 268 | {2, 1, TQ_x_12, 250}, \ 269 | {2, 1, TQ_x_6 , 500}, \ 270 | {2, 1, TQ_x_6 , 0}, \ 271 | {2, 1, TQ_x_6 , 0} 272 | #elif CO_FCY == 4000 273 | #define CO_CANbitRateDataInitializers \ 274 | {2, 25, TQ_x_16, 10}, \ 275 | {1, 5, TQ_x_20, 20}, \ 276 | {2, 5, TQ_x_16, 50}, \ 277 | {1, 1, TQ_x_16, 125}, \ 278 | {2, 1, TQ_x_16, 250}, \ 279 | {2, 1, TQ_x_8 , 500}, \ 280 | {2, 1, TQ_x_5 , 800}, \ 281 | {2, 1, TQ_x_4 , 1000} 282 | #elif CO_FCY == 5000 283 | #define CO_CANbitRateDataInitializers \ 284 | {2, 25, TQ_x_20, 10}, \ 285 | {1, 5, TQ_x_25, 20}, \ 286 | {2, 5, TQ_x_20, 50}, \ 287 | {1, 1, TQ_x_20, 125}, \ 288 | {2, 1, TQ_x_20, 250}, \ 289 | {2, 1, TQ_x_10, 500}, \ 290 | {2, 1, TQ_x_10, 0}, \ 291 | {2, 1, TQ_x_5 , 1000} 292 | #elif CO_FCY == 6000 293 | #define CO_CANbitRateDataInitializers \ 294 | {1, 20, TQ_x_15, 10}, \ 295 | {1, 10, TQ_x_15, 20}, \ 296 | {1, 4, TQ_x_15, 50}, \ 297 | {2, 3, TQ_x_16, 125}, \ 298 | {1, 1, TQ_x_12, 250}, \ 299 | {2, 1, TQ_x_12, 500}, \ 300 | {2, 1, TQ_x_12, 0}, \ 301 | {2, 1, TQ_x_6 , 1000} 302 | #elif CO_FCY == 8000 303 | #define CO_CANbitRateDataInitializers \ 304 | {1, 25, TQ_x_16, 10}, \ 305 | {2, 25, TQ_x_16, 20}, \ 306 | {1, 5, TQ_x_16, 50}, \ 307 | {1, 2, TQ_x_16, 125}, \ 308 | {1, 1, TQ_x_16, 250}, \ 309 | {2, 1, TQ_x_16, 500}, \ 310 | {2, 1, TQ_x_10, 800}, \ 311 | {2, 1, TQ_x_8 , 1000} 312 | #elif CO_FCY == 10000 313 | #define CO_CANbitRateDataInitializers \ 314 | {1, 25, TQ_x_20, 10}, \ 315 | {2, 25, TQ_x_20, 20}, \ 316 | {1, 5, TQ_x_20, 50}, \ 317 | {2, 5, TQ_x_16, 125}, \ 318 | {1, 1, TQ_x_20, 250}, \ 319 | {2, 1, TQ_x_20, 500}, \ 320 | {2, 1, TQ_x_20, 0}, \ 321 | {2, 1, TQ_x_10, 1000} 322 | #elif CO_FCY == 12000 323 | #define CO_CANbitRateDataInitializers \ 324 | {2, 63, TQ_x_19, 10}, \ 325 | {1, 20, TQ_x_15, 20}, \ 326 | {2, 15, TQ_x_16, 50}, \ 327 | {1, 3, TQ_x_16, 125}, \ 328 | {2, 3, TQ_x_16, 250}, \ 329 | {1, 1, TQ_x_12, 500}, \ 330 | {2, 1, TQ_x_15, 800}, \ 331 | {2, 1, TQ_x_12, 1000} 332 | #elif CO_FCY == 16000 333 | #define CO_CANbitRateDataInitializers \ 334 | {1, 50, TQ_x_16, 10}, \ 335 | {1, 25, TQ_x_16, 20}, \ 336 | {1, 10, TQ_x_16, 50}, \ 337 | {1, 4, TQ_x_16, 125}, \ 338 | {1, 2, TQ_x_16, 250}, \ 339 | {1, 1, TQ_x_16, 500}, \ 340 | {1, 1, TQ_x_10, 800}, \ 341 | {1, 1, TQ_x_8 , 1000} 342 | #elif CO_FCY == 20000 343 | #define CO_CANbitRateDataInitializers \ 344 | {1, 50, TQ_x_20, 10}, \ 345 | {1, 25, TQ_x_20, 20}, \ 346 | {1, 10, TQ_x_20, 50}, \ 347 | {1, 5, TQ_x_16, 125}, \ 348 | {1, 2, TQ_x_20, 250}, \ 349 | {1, 1, TQ_x_20, 500}, \ 350 | {1, 1, TQ_x_20, 0}, \ 351 | {1, 1, TQ_x_10, 1000} 352 | #elif CO_FCY == 24000 353 | #define CO_CANbitRateDataInitializers \ 354 | {1, 63, TQ_x_19, 10}, \ 355 | {1, 40, TQ_x_15, 20}, \ 356 | {1, 15, TQ_x_16, 50}, \ 357 | {1, 6, TQ_x_16, 125}, \ 358 | {1, 3, TQ_x_16, 250}, \ 359 | {1, 2, TQ_x_12, 500}, \ 360 | {1, 1, TQ_x_15, 800}, \ 361 | {1, 1, TQ_x_12, 1000} 362 | #elif CO_FCY == 32000 363 | #define CO_CANbitRateDataInitializers \ 364 | {1, 64, TQ_x_25, 10}, \ 365 | {1, 50, TQ_x_16, 20}, \ 366 | {1, 20, TQ_x_16, 50}, \ 367 | {1, 8, TQ_x_16, 125}, \ 368 | {1, 4, TQ_x_16, 250}, \ 369 | {1, 2, TQ_x_16, 500}, \ 370 | {1, 2, TQ_x_10, 800}, \ 371 | {1, 1, TQ_x_16, 1000} 372 | #elif CO_FCY == 40000 373 | #define CO_CANbitRateDataInitializers \ 374 | {1, 50, TQ_x_20, 0}, \ 375 | {1, 50, TQ_x_20, 20}, \ 376 | {1, 25, TQ_x_16, 50}, \ 377 | {1, 10, TQ_x_16, 125}, \ 378 | {1, 5, TQ_x_16, 250}, \ 379 | {1, 2, TQ_x_20, 500}, \ 380 | {1, 1, TQ_x_25, 800}, \ 381 | {1, 1, TQ_x_20, 1000} 382 | #elif CO_FCY == 48000 383 | #define CO_CANbitRateDataInitializers \ 384 | {1, 63, TQ_x_19, 0}, \ 385 | {1, 63, TQ_x_19, 20}, \ 386 | {1, 30, TQ_x_16, 50}, \ 387 | {1, 12, TQ_x_16, 125}, \ 388 | {1, 6, TQ_x_16, 250}, \ 389 | {1, 3, TQ_x_16, 500}, \ 390 | {1, 2, TQ_x_15, 800}, \ 391 | {1, 2, TQ_x_12, 1000} 392 | #elif CO_FCY == 56000 393 | #define CO_CANbitRateDataInitializers \ 394 | {1, 61, TQ_x_23, 0}, \ 395 | {1, 61, TQ_x_23, 20}, \ 396 | {1, 35, TQ_x_16, 50}, \ 397 | {1, 14, TQ_x_16, 125}, \ 398 | {1, 7, TQ_x_16, 250}, \ 399 | {1, 4, TQ_x_14, 500}, \ 400 | {1, 5, TQ_x_7 , 800}, \ 401 | {1, 2, TQ_x_14, 1000} 402 | #elif CO_FCY == 64000 403 | #define CO_CANbitRateDataInitializers \ 404 | {1, 64, TQ_x_25, 0}, \ 405 | {1, 64, TQ_x_25, 20}, \ 406 | {1, 40, TQ_x_16, 50}, \ 407 | {1, 16, TQ_x_16, 125}, \ 408 | {1, 8, TQ_x_16, 250}, \ 409 | {1, 4, TQ_x_16, 500}, \ 410 | {1, 2, TQ_x_20, 800}, \ 411 | {1, 2, TQ_x_16, 1000} 412 | #elif CO_FCY == 70000 413 | #define CO_CANbitRateDataInitializers \ 414 | {1, 64, TQ_x_25, 0}, \ 415 | {1, 64, TQ_x_25, 20}, \ 416 | {1, 35, TQ_x_20, 50}, \ 417 | {1, 14, TQ_x_20, 125}, \ 418 | {1, 7, TQ_x_20, 250}, \ 419 | {1, 5, TQ_x_14, 500}, \ 420 | {1, 3, TQ_x_15, 0}, \ 421 | {1, 2, TQ_x_17, 0} 422 | #else 423 | #error define_CO_FCY CO_FCY not supported 424 | #endif 425 | #endif 426 | 427 | /* Structure contains timing coefficients for CAN module. 428 | * 429 | * CAN baud rate is calculated from following equations: 430 | * FCAN = FCY * Scale - Input frequency to CAN module (MAX 40MHz for dsPIC33F/PIC24H and 70MHz for dsPIC33E/PIC24E) 431 | * TQ = 2 * BRP / FCAN - Time Quanta 432 | * BaudRate = 1 / (TQ * K) - Can bus Baud Rate 433 | * K = SJW + PROP + PhSeg1 + PhSeg2 - Number of Time Quantas 434 | */ 435 | typedef struct { 436 | uint8_t scale; /* (1 or 2) Scales FCY clock - dsPIC33F and PIC24H specific */ 437 | uint8_t BRP; /* (1...64) Baud Rate Prescaler */ 438 | uint8_t SJW; /* (1...4) SJW time */ 439 | uint8_t PROP; /* (1...8) PROP time */ 440 | uint8_t phSeg1; /* (1...8) Phase Segment 1 time */ 441 | uint8_t phSeg2; /* (1...8) Phase Segment 2 time */ 442 | uint16_t bitrate; /* bitrate in kbps */ 443 | } CO_CANbitRateData_t; 444 | 445 | #ifdef __cplusplus 446 | } 447 | #endif /* __cplusplus */ 448 | 449 | #endif /* CO_DRIVER_TARGET */ 450 | -------------------------------------------------------------------------------- /PIC32/CO_application.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Application interface for CANopenNode. 3 | * 4 | * @file CO_application.h 5 | * @author Janez Paternoster 6 | * @copyright 2021 Janez Paternoster 7 | * 8 | * This file is part of CANopenNode, an opensource CANopen Stack. 9 | * Project home page is . 10 | * For more information on CANopen see . 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | #ifndef CO_APPLICATION_H 26 | #define CO_APPLICATION_H 27 | 28 | #include "CANopen.h" 29 | 30 | 31 | /** 32 | * Application interface, similar to Arduino, extended to CANopen and 33 | * additional, realtime thread. 34 | */ 35 | 36 | 37 | /** 38 | * Function is called once on the program startup, after Object dictionary 39 | * initialization and before CANopen initialization. 40 | * 41 | * @param [in,out] bitRate Stored CAN bit rate, can be overridden. 42 | * @param [in,out] nodeId Stored CANopen NodeId, can be overridden. 43 | * @param [out] errInfo Variable may indicate error information - index of 44 | * erroneous OD entry. 45 | * 46 | * @return @ref CO_ReturnError_t CO_ERROR_NO in case of success. 47 | */ 48 | CO_ReturnError_t app_programStart(uint16_t *bitRate, 49 | uint8_t *nodeId, 50 | uint32_t *errInfo); 51 | 52 | 53 | /** 54 | * Function is called after CANopen communication reset. 55 | * 56 | * @param co CANopen object. 57 | */ 58 | void app_communicationReset(CO_t *co); 59 | 60 | 61 | /** 62 | * Function is called just before program ends. 63 | */ 64 | void app_programEnd(); 65 | 66 | 67 | /** 68 | * Function is called cyclically from main(). 69 | * 70 | * Place for the slower code (all must be non-blocking). 71 | * 72 | * @warning 73 | * Mind race conditions between this functions and following three functions 74 | * (app_programRt() app_peripheralRead() and app_peripheralWrite()), which all 75 | * run from the realtime thread. If accessing Object dictionary variable which 76 | * is also mappable to PDO, it is necessary to use CO_LOCK_OD() and 77 | * CO_UNLOCK_OD() macros from @ref CO_critical_sections. 78 | * 79 | * @param co CANopen object. 80 | * @param timer1usDiff Time difference since last call in microseconds 81 | */ 82 | void app_programAsync(CO_t *co, uint32_t timer1usDiff); 83 | 84 | 85 | /** 86 | * Function is called cyclically from realtime thread at constant intervals. 87 | * 88 | * Code inside this function must be executed fast. Take care on race conditions 89 | * with app_programAsync. 90 | * 91 | * @param co CANopen object. 92 | * @param timer1usDiff Time difference since last call in microseconds 93 | */ 94 | void app_programRt(CO_t *co, uint32_t timer1usDiff); 95 | 96 | 97 | /** 98 | * Function is called in the beginning of the realtime thread. 99 | * 100 | * @param co CANopen object. 101 | * @param timer1usDiff Time difference since last call in microseconds 102 | */ 103 | void app_peripheralRead(CO_t *co, uint32_t timer1usDiff); 104 | 105 | 106 | /** 107 | * Function is called in the end of the realtime thread. 108 | * 109 | * @param co CANopen object. 110 | * @param timer1usDiff Time difference since last call in microseconds 111 | */ 112 | void app_peripheralWrite(CO_t *co, uint32_t timer1usDiff); 113 | 114 | 115 | #endif /* CO_APPLICATION_H */ 116 | -------------------------------------------------------------------------------- /PIC32/CO_driver_target.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Microchip PIC32MX specific definitions for CANopenNode. 3 | * 4 | * @file CO_driver_target.h 5 | * @author Janez Paternoster 6 | * @copyright 2021 Janez Paternoster 7 | * 8 | * This file is part of CANopenNode, an opensource CANopen Stack. 9 | * Project home page is . 10 | * For more information on CANopen see . 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | #ifndef CO_DRIVER_TARGET_H 27 | #define CO_DRIVER_TARGET_H 28 | 29 | /* This file contains device and application specific definitions. 30 | * It is included from CO_driver.h, which contains documentation 31 | * for common definitions below. */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "CO_driver_custom.h" 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | 45 | /* Stack configuration override from CO_driver.h. 46 | * For more information see file CO_config.h. */ 47 | #ifndef CO_CONFIG_NMT 48 | #define CO_CONFIG_NMT CO_CONFIG_NMT_MASTER 49 | #endif 50 | 51 | /* Add full SDO_SRV_BLOCK transfer with CRC16 */ 52 | #ifndef CO_CONFIG_SDO_SRV 53 | #define CO_CONFIG_SDO_SRV (CO_CONFIG_SDO_SRV_SEGMENTED | \ 54 | CO_CONFIG_SDO_SRV_BLOCK) 55 | #endif 56 | #ifndef CO_CONFIG_SDO_SRV_BUFFER_SIZE 57 | #define CO_CONFIG_SDO_SRV_BUFFER_SIZE 900 58 | #endif 59 | #ifndef CO_CONFIG_CRC16 60 | #define CO_CONFIG_CRC16 (CO_CONFIG_CRC16_ENABLE) 61 | #endif 62 | 63 | 64 | /* default system clock configuration */ 65 | #ifndef CO_FSYS 66 | #define CO_FSYS 64000 /* (8MHz Quartz used) */ 67 | #endif 68 | 69 | /* default peripheral bus clock configuration */ 70 | #ifndef CO_PBCLK 71 | #define CO_PBCLK 32000 72 | #endif 73 | 74 | 75 | /* Basic definitions */ 76 | #define CO_LITTLE_ENDIAN 77 | #define CO_SWAP_16(x) x 78 | #define CO_SWAP_32(x) x 79 | #define CO_SWAP_64(x) x 80 | /* NULL is defined in stddef.h */ 81 | /* true and false are defined in stdbool.h */ 82 | /* int8_t to uint64_t are defined in stdint.h */ 83 | typedef unsigned char bool_t; 84 | typedef float float32_t; 85 | typedef long double float64_t; 86 | 87 | 88 | /* CAN receive message structure as aligned in CAN module. */ 89 | typedef struct { 90 | unsigned ident :11; /* Standard Identifier */ 91 | unsigned FILHIT :5; /* Filter hit, see PIC32MX documentation */ 92 | unsigned CMSGTS :16; /* CAN message timestamp, see PIC32MX documentation */ 93 | unsigned DLC :4; /* Data length code (bits 0...3) */ 94 | unsigned :5; 95 | unsigned RTR :1; /* Remote Transmission Request bit */ 96 | unsigned :22; 97 | uint8_t data[8]; /* 8 data bytes */ 98 | } CO_CANrxMsg_t; 99 | 100 | /* Access to received CAN message */ 101 | #define CO_CANrxMsg_readIdent(msg) ((uint16_t)(((CO_CANrxMsg_t *)(msg))->ident)) 102 | #define CO_CANrxMsg_readDLC(msg) ((uint8_t)(((CO_CANrxMsg_t *)(msg))->DLC)) 103 | #define CO_CANrxMsg_readData(msg) ((uint8_t *)(((CO_CANrxMsg_t *)(msg))->data)) 104 | 105 | /* Received message object */ 106 | typedef struct { 107 | uint16_t ident; 108 | uint16_t mask; 109 | void *object; 110 | void (*CANrx_callback)(void *object, void *message); 111 | } CO_CANrx_t; 112 | 113 | /* Transmit message object */ 114 | typedef struct { 115 | uint32_t CMSGSID; /* Equal to register in transmit message buffer. Includes standard Identifier */ 116 | uint32_t CMSGEID; /* Equal to register in transmit message buffer. Includes data length code and RTR */ 117 | uint8_t data[8]; 118 | volatile bool_t bufferFull; 119 | volatile bool_t syncFlag; 120 | } CO_CANtx_t; 121 | 122 | /* CAN module object */ 123 | typedef struct { 124 | void *CANptr; 125 | CO_CANrxMsg_t CANmsgBuff[33]; /* PIC32 specific: CAN message buffer for CAN module. 32 buffers for receive, 1 buffer for transmit */ 126 | uint8_t CANmsgBuffSize; /* PIC32 specific: Size of the above buffer == 33. Take care initial value! */ 127 | CO_CANrx_t *rxArray; 128 | uint16_t rxSize; 129 | CO_CANtx_t *txArray; 130 | uint16_t txSize; 131 | uint16_t CANerrorStatus; 132 | volatile bool_t CANnormal; 133 | volatile bool_t useCANrxFilters; 134 | volatile bool_t bufferInhibitFlag; 135 | volatile bool_t firstCANtxMessage; 136 | volatile uint16_t CANtxCount; 137 | uint32_t errOld; 138 | unsigned int interruptStatus; /* for enabling/disabling interrupts */ 139 | unsigned int interruptDisabler; /* for enabling/disabling interrupts */ 140 | } CO_CANmodule_t; 141 | 142 | 143 | /* Data storage object for one entry */ 144 | typedef struct { 145 | void *addr; 146 | size_t len; 147 | uint8_t subIndexOD; 148 | uint8_t attr; 149 | void *storageModule; 150 | uint16_t crc; 151 | size_t eepromAddrSignature; 152 | size_t eepromAddr; 153 | size_t offset; 154 | } CO_storage_entry_t; 155 | 156 | 157 | /* (un)lock critical section in CO_CANsend() */ 158 | #define CO_LOCK_CAN_SEND(CAN_MODULE) { \ 159 | if ((CAN_MODULE)->interruptDisabler == 0) { \ 160 | (CAN_MODULE)->interruptStatus = __builtin_disable_interrupts(); \ 161 | (CAN_MODULE)->interruptDisabler = 1; \ 162 | } \ 163 | } 164 | #define CO_UNLOCK_CAN_SEND(CAN_MODULE) { \ 165 | if ((CAN_MODULE)->interruptDisabler == 1) { \ 166 | if(((CAN_MODULE)->interruptStatus & _CP0_STATUS_IE_MASK) != 0) { \ 167 | __builtin_enable_interrupts(); \ 168 | } \ 169 | (CAN_MODULE)->interruptDisabler = 0; \ 170 | } \ 171 | } 172 | 173 | /* (un)lock critical section in CO_errorReport() or CO_errorReset() */ 174 | #define CO_LOCK_EMCY(CAN_MODULE) { \ 175 | if ((CAN_MODULE)->interruptDisabler == 0) { \ 176 | (CAN_MODULE)->interruptStatus = __builtin_disable_interrupts(); \ 177 | (CAN_MODULE)->interruptDisabler = 2; \ 178 | } \ 179 | } 180 | #define CO_UNLOCK_EMCY(CAN_MODULE) { \ 181 | if ((CAN_MODULE)->interruptDisabler == 2) { \ 182 | if(((CAN_MODULE)->interruptStatus & _CP0_STATUS_IE_MASK) != 0) { \ 183 | __builtin_enable_interrupts(); \ 184 | } \ 185 | (CAN_MODULE)->interruptDisabler = 0; \ 186 | } \ 187 | } 188 | 189 | /* (un)lock critical section when accessing Object Dictionary */ 190 | #define CO_LOCK_OD(CAN_MODULE) { \ 191 | if ((CAN_MODULE)->interruptDisabler == 0) { \ 192 | (CAN_MODULE)->interruptStatus = __builtin_disable_interrupts(); \ 193 | (CAN_MODULE)->interruptDisabler = 3; \ 194 | } \ 195 | } 196 | #define CO_UNLOCK_OD(CAN_MODULE) { \ 197 | if ((CAN_MODULE)->interruptDisabler == 3) { \ 198 | if(((CAN_MODULE)->interruptStatus & _CP0_STATUS_IE_MASK) != 0) { \ 199 | __builtin_enable_interrupts(); \ 200 | } \ 201 | (CAN_MODULE)->interruptDisabler = 0; \ 202 | } \ 203 | } 204 | 205 | 206 | /* Synchronization between CAN receive and message processing threads. */ 207 | #define CO_MemoryBarrier() 208 | #define CO_FLAG_READ(rxNew) ((rxNew) != NULL) 209 | #define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} 210 | #define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} 211 | 212 | 213 | /* Translate a kernel virtual address in KSEG0 or KSEG1 to a real 214 | * physical address and back. */ 215 | typedef unsigned long CO_paddr_t; /* a physical address */ 216 | typedef unsigned long CO_vaddr_t; /* a virtual address */ 217 | #define CO_KVA_TO_PA(v) ((CO_paddr_t)(v) & 0x1fffffff) 218 | #define CO_PA_TO_KVA0(pa) ((void *) ((pa) | 0x80000000)) 219 | #define CO_PA_TO_KVA1(pa) ((void *) ((pa) | 0xa0000000)) 220 | 221 | 222 | /* Callback for checking bitrate, needed by LSS slave */ 223 | bool_t CO_LSSchkBitrateCallback(void *object, uint16_t bitRate); 224 | 225 | 226 | /* Function called from CAN receive interrupt handler */ 227 | void CO_CANinterrupt(CO_CANmodule_t *CANmodule); 228 | 229 | #ifdef __cplusplus 230 | } 231 | #endif /* __cplusplus */ 232 | 233 | #endif /* CO_DRIVER_TARGET_H */ 234 | -------------------------------------------------------------------------------- /PIC32/CO_eepromPIC32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Eeprom interface for use with CO_storageEeprom, PIC32 specific 3 | * 4 | * @file CO_eepromPIC32.c 5 | * @author Janez Paternoster 6 | * @copyright 2021 Janez Paternoster 7 | * 8 | * This file is part of CANopenNode, an opensource CANopen Stack. 9 | * Project home page is . 10 | * For more information on CANopen see . 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | #include "storage/CO_eeprom.h" 26 | #include "301/crc16-ccitt.h" 27 | 28 | /* 29 | * Hardware definition 30 | * 31 | * Here registers are used directly. As alternative 'void *storageModule' colud 32 | * be used as more object oriented way. 33 | * 34 | * By default 25LC128 eeprom is connected to SPI2 port of PIC32MX (RG6..RG9). 35 | */ 36 | #ifndef CO_STOR_EE_SIZE 37 | #define CO_STOR_EE_SIZE 0x4000 // 0x4000 for 128kbits or 0x8000 for 25LC256 38 | #endif 39 | #ifndef CO_STOR_EE_PAGE_SIZE 40 | #define CO_STOR_EE_PAGE_SIZE 64 41 | #endif 42 | #ifndef CO_STOR_SS 43 | #define CO_STOR_SS 44 | #define CO_STOR_SS_INIT() {TRISGCLR = 0x0200;} 45 | #define CO_STOR_SS_LOW() {PORTGCLR = 0x0200;} 46 | #define CO_STOR_SS_HIGH() {PORTGSET = 0x0200;} 47 | #endif 48 | #ifndef CO_STOR_SPI 49 | #define CO_STOR_SPI 50 | #define CO_STOR_SPIBUF SPI2BUF 51 | #define CO_STOR_SPICON SPI2CON 52 | #define CO_STOR_SPISTAT SPI2STAT 53 | #define CO_STOR_SPISTATbits SPI2STATbits 54 | #define CO_STOR_SPIBRG SPI2BRG 55 | #endif 56 | 57 | #define EE_CMD_READ (unsigned)0b00000011 58 | #define EE_CMD_WRITE (unsigned)0b00000010 59 | #define EE_CMD_WRDI (unsigned)0b00000100 60 | #define EE_CMD_WREN (unsigned)0b00000110 61 | #define EE_CMD_RDSR (unsigned)0b00000101 62 | #define EE_CMD_WRSR (unsigned)0b00000001 63 | #define SPI_FIFO_SIZE 16 // PIC32 uses 16 bytes long FIFO buffer with SPI. 64 | 65 | 66 | /* 67 | * Eeprom is configured so, that first half of memory locations is not write 68 | * protected, so it is suitable for auto storage variables. Second half of 69 | * memory locations is write protected. It is used for storage on command, which 70 | * disables the protection for the short time when writing. Below are two 71 | * internal variables, used for indicating next free address in eeprom, one for 72 | * autonomous storage and one for protected storage 73 | */ 74 | static size_t eepromAddrNextAuto = 0; 75 | static size_t eepromAddrNextProt = CO_STOR_EE_SIZE / 2; 76 | static volatile uint32_t dummy; 77 | 78 | 79 | /** 80 | * Enable write operation in EEPROM. It is called before every writing to it. 81 | */ 82 | static inline void EE_writeEnable() { 83 | CO_STOR_SS_LOW(); 84 | 85 | /* write byte */ 86 | CO_STOR_SPIBUF = EE_CMD_WREN; 87 | 88 | /* read one byte after it is ready */ 89 | while (CO_STOR_SPISTATbits.SPIRBE); 90 | dummy = CO_STOR_SPIBUF; 91 | 92 | CO_STOR_SS_HIGH(); 93 | } 94 | 95 | 96 | /** 97 | * Read eeprom status register. 98 | * 99 | * @return Data read from the status register. 100 | */ 101 | static inline uint8_t EE_readStatus() { 102 | CO_STOR_SS_LOW(); 103 | 104 | /* write two bytes */ 105 | CO_STOR_SPIBUF = EE_CMD_RDSR; 106 | CO_STOR_SPIBUF = 0; 107 | 108 | /* read two bytes after they are ready */ 109 | while(CO_STOR_SPISTATbits.SPIRBE); 110 | dummy = CO_STOR_SPIBUF; 111 | while(CO_STOR_SPISTATbits.SPIRBE); 112 | CO_STOR_SS_HIGH(); 113 | 114 | return CO_STOR_SPIBUF; 115 | } 116 | 117 | /** 118 | * Return true if write is in process. 119 | */ 120 | #define EE_isWriteInProcess() ((EE_readStatus() & 0x01) != 0) 121 | /** 122 | * Return true if upper half of the eeprom is protected 123 | */ 124 | #define EE_isWriteProtected() ((EE_readStatus() & 0x8C) == 0x88) 125 | 126 | 127 | /** 128 | * Write eeprom status register. 129 | * 130 | * Make sure EE_isWriteInProcess() is false before and after function call 131 | * 132 | * @param data Data byte to be written to status register. 133 | */ 134 | static inline void EE_writeStatus(uint8_t data) { 135 | EE_writeEnable(); 136 | 137 | CO_STOR_SS_LOW(); 138 | 139 | /* write two bytes */ 140 | CO_STOR_SPIBUF = EE_CMD_WRSR; 141 | CO_STOR_SPIBUF = data; 142 | 143 | /* read two bytes after they are ready */ 144 | while(CO_STOR_SPISTATbits.SPIRBE); 145 | dummy = CO_STOR_SPIBUF; 146 | while(CO_STOR_SPISTATbits.SPIRBE); 147 | dummy = CO_STOR_SPIBUF; 148 | 149 | CO_STOR_SS_HIGH(); 150 | } 151 | 152 | /** 153 | * Enable write protection for upper half of the eeprom 154 | */ 155 | #define EE_writeProtect() EE_writeStatus(0x88) 156 | /* 157 | * Disable write protection for upper half of the eeprom 158 | */ 159 | #define EE_writeUnprotect() EE_writeStatus(0) 160 | 161 | 162 | /** 163 | * Write to SPI and at the same time read from SPI. 164 | * 165 | * @param tx Ponter to transmitting data. If NULL, zeroes will be transmitted. 166 | * @param rx Ponter to data buffer, where received data wile be stored. 167 | * If null, Received data will be disregarded. 168 | * @param len Length of data buffers. Max SPI_FIFO_SIZE. 169 | */ 170 | static void EE_SPIwrite(uint8_t *tx, uint8_t *rx, uint8_t len) { 171 | /* write bytes into SPI_TXB fifo buffer */ 172 | if (tx != NULL) { 173 | for (uint8_t i = 0; i < len; i++) CO_STOR_SPIBUF = tx[i]; 174 | } 175 | else { 176 | for (uint8_t i = 0; i < len; i++) CO_STOR_SPIBUF = 0; 177 | } 178 | 179 | /* read bytes from SPI_RXB fifo buffer */ 180 | for (uint8_t i = 0; i < len; i++) { 181 | /* wait untill buffer is filled, then read it */ 182 | while(CO_STOR_SPISTATbits.SPIRBE); 183 | if (rx != NULL) { 184 | rx[i] = (uint8_t) CO_STOR_SPIBUF; 185 | } 186 | else { 187 | dummy = CO_STOR_SPIBUF; 188 | } 189 | } 190 | } 191 | 192 | 193 | /******************************************************************************/ 194 | bool_t CO_eeprom_init(void *storageModule) { 195 | /* Configure SPI port for use with eeprom */ 196 | CO_STOR_SS_HIGH(); 197 | CO_STOR_SS_INIT(); 198 | 199 | /* Stop and reset the SPI, clear the receive buffer */ 200 | CO_STOR_SPICON = 0; 201 | CO_STOR_SPISTAT = 0; 202 | dummy = CO_STOR_SPIBUF; 203 | 204 | /* Clock = FPB / ((4+1) * 2) */ 205 | CO_STOR_SPIBRG = 4; 206 | 207 | /* MSSEN = 0 - Master mode slave select enable bit 208 | * ENHBUF(bit16) = 1 - Enhanced buffer enable bit 209 | * Enable SPI, 8-bit mode 210 | * SMP = 0, CKE = 1, CKP = 0 211 | * MSTEN = 1 - master mode enable bit */ 212 | CO_STOR_SPICON = 0x00018120; 213 | 214 | eepromAddrNextAuto = 0; 215 | eepromAddrNextProt = CO_STOR_EE_SIZE / 2; 216 | 217 | EE_writeProtect(); 218 | 219 | /* If eeprom chip is OK, this will pass, otherwise timeout */ 220 | for (uint16_t i = 0; i < 0xFFFF; i++) { 221 | if (!EE_isWriteInProcess()) { 222 | if (EE_isWriteProtected()) { 223 | return true; 224 | } 225 | } 226 | dummy ++; //small delay 227 | } 228 | 229 | return false; 230 | } 231 | 232 | 233 | /******************************************************************************/ 234 | size_t CO_eeprom_getAddr(void *storageModule, bool_t isAuto, 235 | size_t len, bool_t *overflow) 236 | { 237 | size_t addr; 238 | 239 | if (isAuto) { 240 | /* auto storage is processed byte by byte, no alignment necessary */ 241 | addr = eepromAddrNextAuto; 242 | eepromAddrNextAuto += len; 243 | if (eepromAddrNextAuto > (CO_STOR_EE_SIZE / 2)) { 244 | *overflow = true; 245 | } 246 | } 247 | else { 248 | /* addresses for storage on command must be page aligned */ 249 | addr = eepromAddrNextProt; 250 | size_t lenAligned = len & (~(CO_STOR_EE_PAGE_SIZE - 1)); 251 | if (lenAligned < len) { 252 | lenAligned += CO_STOR_EE_PAGE_SIZE; 253 | } 254 | eepromAddrNextProt += lenAligned; 255 | if (eepromAddrNextProt > CO_STOR_EE_SIZE) { 256 | *overflow = true; 257 | } 258 | } 259 | 260 | return addr; 261 | } 262 | 263 | 264 | /******************************************************************************/ 265 | void CO_eeprom_readBlock(void *storageModule, uint8_t *data, 266 | size_t eepromAddr, size_t len) 267 | { 268 | uint8_t buf[3] = { 269 | EE_CMD_READ, 270 | (uint8_t) (eepromAddr >> 8), 271 | (uint8_t) eepromAddr 272 | }; 273 | 274 | CO_STOR_SS_LOW(); 275 | EE_SPIwrite(buf, NULL, 3); 276 | 277 | while (len > 0) { 278 | uint8_t subLen = len <= SPI_FIFO_SIZE ? (uint8_t)len : SPI_FIFO_SIZE; 279 | 280 | EE_SPIwrite(NULL, data, subLen); 281 | len -= subLen; 282 | data += subLen; 283 | } 284 | 285 | CO_STOR_SS_HIGH(); 286 | } 287 | 288 | 289 | /******************************************************************************/ 290 | bool_t CO_eeprom_writeBlock(void *storageModule, uint8_t *data, 291 | size_t eepromAddr, size_t len) 292 | { 293 | while(EE_isWriteInProcess()); 294 | EE_writeUnprotect(); 295 | while(EE_isWriteInProcess()); 296 | 297 | while (len > 0) { 298 | uint8_t buf[3] = { 299 | EE_CMD_WRITE, 300 | (uint8_t) (eepromAddr >> 8), 301 | (uint8_t) eepromAddr, 302 | }; 303 | 304 | EE_writeEnable(); 305 | 306 | CO_STOR_SS_LOW(); 307 | EE_SPIwrite(buf, NULL, 3); 308 | 309 | for (uint8_t i = 0; i < (CO_STOR_EE_PAGE_SIZE / SPI_FIFO_SIZE); i++) { 310 | if (len > SPI_FIFO_SIZE) { 311 | EE_SPIwrite(data, NULL, SPI_FIFO_SIZE); 312 | len -= SPI_FIFO_SIZE; 313 | data += SPI_FIFO_SIZE; 314 | } 315 | else { 316 | EE_SPIwrite(data, NULL, (uint8_t)len); 317 | len = 0; 318 | break; 319 | } 320 | } 321 | CO_STOR_SS_HIGH(); 322 | 323 | eepromAddr += CO_STOR_EE_PAGE_SIZE; 324 | 325 | /* wait for completion of the write operation */ 326 | while(EE_isWriteInProcess()); 327 | } 328 | 329 | EE_writeProtect(); 330 | while(EE_isWriteInProcess()); 331 | 332 | return EE_isWriteProtected(); 333 | } 334 | 335 | 336 | /******************************************************************************/ 337 | uint16_t CO_eeprom_getCrcBlock(void *storageModule, 338 | size_t eepromAddr, size_t len) 339 | { 340 | uint16_t crc = 0; 341 | uint8_t buf[SPI_FIFO_SIZE] = { 342 | EE_CMD_READ, 343 | (uint8_t) (eepromAddr >> 8), 344 | (uint8_t) eepromAddr 345 | }; 346 | 347 | CO_STOR_SS_LOW(); 348 | EE_SPIwrite(buf, NULL, 3); 349 | 350 | while (len > 0) { 351 | uint8_t subLen = len <= SPI_FIFO_SIZE ? (uint8_t)len : SPI_FIFO_SIZE; 352 | 353 | /* update crc from data part */ 354 | EE_SPIwrite(NULL, buf, subLen); 355 | crc = crc16_ccitt(buf, subLen, crc); 356 | len -= subLen; 357 | } 358 | 359 | CO_STOR_SS_HIGH(); 360 | 361 | return crc; 362 | } 363 | 364 | 365 | /******************************************************************************/ 366 | bool_t CO_eeprom_updateByte(void *storageModule, uint8_t data, 367 | size_t eepromAddr) 368 | { 369 | if (EE_isWriteInProcess()) { 370 | return false; 371 | } 372 | 373 | /* read data byte from eeprom */ 374 | uint8_t bufTx[4] = { 375 | EE_CMD_READ, 376 | (uint8_t) (eepromAddr >> 8), 377 | (uint8_t) eepromAddr, 378 | 0 379 | }; 380 | uint8_t bufRx[4]; 381 | CO_STOR_SS_LOW(); 382 | EE_SPIwrite(bufTx, bufRx, 4); 383 | CO_STOR_SS_HIGH(); 384 | 385 | /* If data in EEPROM differs, then write it to EEPROM. 386 | * Don't wait write to complete */ 387 | if(bufRx[3] != data) { 388 | uint8_t buf[4] = { 389 | EE_CMD_WRITE, 390 | (uint8_t) (eepromAddr >> 8), 391 | (uint8_t) eepromAddr, 392 | data 393 | }; 394 | 395 | EE_writeEnable(); 396 | CO_STOR_SS_LOW(); 397 | EE_SPIwrite(buf, NULL, 4); 398 | CO_STOR_SS_HIGH(); 399 | } 400 | 401 | return true; 402 | } 403 | -------------------------------------------------------------------------------- /PIC32/CO_main_PIC32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CANopen main program file for PIC32 microcontroller. 3 | * 4 | * @file main_PIC32.c 5 | * @author Janez Paternoster 6 | * @copyright 2021 Janez Paternoster 7 | * 8 | * This file is part of CANopenNode, an opensource CANopen Stack. 9 | * Project home page is . 10 | * For more information on CANopen see . 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #include "CANopen.h" 29 | #include "storage/CO_storageEeprom.h" 30 | #include "OD.h" 31 | #include "CO_application.h" 32 | 33 | 34 | /* Default configuration bit settings */ 35 | #ifndef CO_CONFIGURATION_BITS_CONFIGURED 36 | #define CO_CONFIGURATION_BITS_CONFIGURED 37 | #pragma config FVBUSONIO = OFF /* USB VBUS_ON Selection */ 38 | #pragma config FUSBIDIO = OFF /* USB USBID Selection */ 39 | #pragma config UPLLEN = OFF /* USB PLL Enable */ 40 | #pragma config UPLLIDIV = DIV_12 /* USB PLL Input Divider */ 41 | #pragma config FCANIO = ON /* CAN IO Pin Selection */ 42 | #pragma config FETHIO = ON /* Ethernet IO Pin Selection */ 43 | #pragma config FMIIEN = ON /* Ethernet MII Enable (ON = MII enabled) */ 44 | #pragma config FSRSSEL = PRIORITY_7 /* SRS (Shadow registers set) Select */ 45 | #pragma config POSCMOD = XT /* Primary Oscillator */ 46 | #pragma config FSOSCEN = OFF /* Secondary oscillator Enable */ 47 | #pragma config FNOSC = PRIPLL /* Oscillator Selection */ 48 | #pragma config FPLLIDIV = DIV_2 /* PLL Input Divider */ 49 | #pragma config FPLLMUL = MUL_16 /* PLL Multiplier */ 50 | #pragma config FPLLODIV = DIV_1 /* PLL Output Divider Value */ 51 | #pragma config FPBDIV = DIV_2 /* Bootup PBCLK divider */ 52 | #pragma config FCKSM = CSDCMD /* Clock Switching and Monitor Selection */ 53 | #pragma config OSCIOFNC = OFF /* CLKO Enable */ 54 | #pragma config IESO = OFF /* Internal External Switch Over */ 55 | #pragma config FWDTEN = OFF /* Watchdog Timer Enable */ 56 | #pragma config WDTPS = PS1024 /* Watchdog Timer Postscale Select */ 57 | #pragma config CP = OFF /* Code Protect Enable */ 58 | #pragma config BWP = ON /* Boot Flash Write Protect */ 59 | #pragma config PWP = PWP256K /* Program Flash Write Protect */ 60 | #pragma config DEBUG = ON /* Background Debugger Enable */ 61 | #ifdef CO_ICS_PGx1 62 | #pragma config ICESEL = ICS_PGx1 /* ICE/ICD Comm Channel Select */ 63 | #else 64 | #pragma config ICESEL = ICS_PGx2 /* ICE/ICD Comm Channel Select (2 for 65 | * Explorer16 and Max32 board) */ 66 | #endif 67 | #endif 68 | 69 | 70 | /* 71 | * Configure peripherals 72 | * - Configure Analog Inputs AI0..AI15: 73 | * - AD1CON1: 74 | * - FORM = 000b: Data output is unsigned integer, 10bit, right justified 75 | * - SSRC = 111b: Internal counter ends sampling and starts conversion 76 | * - CLRASAM = 1: Stop conversions after ADC interrupt is generated 77 | * - AD1CON2: 78 | * - VCFG = 001b: ADC voltage reference is Vref+ and AVss 79 | * - CSCNA = 1: Enable scan mode 80 | * - SMPI = 1111b: Interrupts after each 16th sample/convert sequence 81 | * - AD1CON3: 82 | * - ADRC = 0: Clock derived from Peripheral Bus Clock (PBCLK) 83 | * - SAMC = 31: Auto sample time = 31*TAD 84 | * - ADCS = 0..2: (If PBCLK=32MHz -> TAD=125ns) 85 | * - AD1PCFG, AD1CSSL: Use all ports AI0..AI15 86 | * - Enable ADC interrupt with priority 3, turn ADC On. ADC conversion is 87 | * triggered by high priority timer interval interrupt. After conversion is 88 | * completed, Real Time Thread is executed, see its definitions below. 89 | * Analog values AN0..AN15 are available in ADC1BUF0..ADC1BUF15 90 | */ 91 | #ifndef CO_PERIPHERAL_CONFIG 92 | /* ADC conversion clock select */ 93 | #if CO_PBCLK <= 24000 94 | #define HW_ADCS 0 95 | #elif CO_PBCLK <= 48000 96 | #define HW_ADCS 1 97 | #elif CO_PBCLK <= 96000 98 | #define HW_ADCS 2 99 | #endif 100 | #define CO_PERIPHERAL_CONFIG() { \ 101 | AD1CON1 = 0x00F0; \ 102 | AD1CON2 = 0x243C; \ 103 | AD1CON3 = 0x1F00 | HW_ADCS; \ 104 | AD1CHS = 0; \ 105 | AD1PCFG = 0; \ 106 | AD1CSSL = 0xFFFF; \ 107 | AD1CON1SET = 0x8000; \ 108 | } 109 | #endif /* CO_PERIPHERAL_CONFIG */ 110 | 111 | 112 | /* 113 | * Real Time Thread definitions 114 | * 115 | * Configure timer interrupt, 1ms interval, highest priority. Timer will trigger 116 | * ADC conversion. After conversion of all analog inputs completed, ADC 117 | * interrupt will be used as Real Time Thread. 118 | */ 119 | #ifndef CO_RT_THREAD_CONFIG 120 | #if CO_PBCLK < 2 || CO_PBCLK > 65000 121 | #error wrong timer configuration for real time thread 122 | #endif 123 | #define CO_RT_THREAD_CONFIG() { \ 124 | T2CON = 0; \ 125 | TMR2 = 0; \ 126 | PR2 = CO_PBCLK - 1; \ 127 | T2CON = 0x8000; \ 128 | IFS0bits.T2IF = 0; \ 129 | IPC2bits.T2IP = 7; \ 130 | IFS1bits.AD1IF = 0; \ 131 | IEC1bits.AD1IE = 1; \ 132 | IPC6bits.AD1IP = 3; \ 133 | } 134 | #endif 135 | /* Interval of the realtime thread */ 136 | #ifndef CO_RT_THREAD_INTERVAL_US 137 | #define CO_RT_THREAD_INTERVAL_US 1000 138 | #endif 139 | /* Additional external triggers, which can be used inside the first interrupt */ 140 | #ifndef CO_RT_THREAD_CUSTOM_TRIGGERS 141 | #define CO_RT_THREAD_CUSTOM_TRIGGERS() 142 | #endif 143 | /* Default interrupt handler, twin, timer starts ADC conversion, then adc isr */ 144 | #ifndef CO_RT_THREAD_ISR 145 | #define CO_RT_THREAD_ISR_DEFAULT 146 | #define CO_RT_THREAD_ISR() void __ISR(_TIMER_2_VECTOR, IPL7SRS) _adIsr(void) { \ 147 | static bool_t skipFirstPass = true; \ 148 | if(skipFirstPass) { skipFirstPass = false; } \ 149 | else { \ 150 | AD1CON1bits.ASAM = 1; \ 151 | CO_RT_THREAD_CUSTOM_TRIGGERS(); \ 152 | } \ 153 | IFS0bits.T2IF = 0; \ 154 | } \ 155 | void __ISR(_ADC_VECTOR, IPL3SOFT) _rtThread(void) 156 | #endif 157 | /* Enable interrupt, 0 or 1 */ 158 | #ifndef CO_RT_THREAD_ENABLE 159 | #define CO_RT_THREAD_ENABLE(ENABLE) IEC0bits.T2IE = ENABLE 160 | #endif 161 | /* Interrupt flag bit, used inside _rtThread */ 162 | #ifndef CO_RT_THREAD_ISR_FLAG 163 | #define CO_RT_THREAD_ISR_FLAG IFS1bits.AD1IF 164 | #endif 165 | 166 | 167 | /* CAN receive interrupt definitions */ 168 | /* Configure CAN rx interrupt, priority is 5, higher than timer */ 169 | #ifndef CO_CANRX_CONFIG 170 | #define CO_CANRX_CONFIG() { \ 171 | IFS1bits.CAN1IF = 0; \ 172 | IPC11bits.CAN1IP = 5; \ 173 | } 174 | #endif 175 | /* Default interrupt handler, use same priority as in CO_CANRX_CONFIG() */ 176 | #ifndef CO_CANRX_ISR 177 | #define CO_CANRX_ISR_DEFAULT 178 | #define CO_CANRX_ISR() void __ISR(_CAN_1_VECTOR, IPL5SOFT) _canRxIsr(void) 179 | #endif 180 | /* Enable interrupt, 0 or 1 */ 181 | #ifndef CO_CANRX_ENABLE 182 | #define CO_CANRX_ENABLE(ENABLE) IEC1bits.CAN1IE = ENABLE 183 | #endif 184 | /* Interrupt flag bit, used inside CO_CANRX_ISR */ 185 | #ifndef CO_CANRX_ISR_FLAG 186 | #define CO_CANRX_ISR_FLAG IFS1bits.CAN1IF 187 | #endif 188 | 189 | 190 | /* Watchdog timer */ 191 | #ifndef CO_clearWDT 192 | #define CO_clearWDT() (WDTCONSET = _WDTCON_WDTCLR_MASK) 193 | #endif 194 | 195 | 196 | /* default values for CO_CANopenInit() */ 197 | #ifndef NMT_CONTROL 198 | #define NMT_CONTROL \ 199 | CO_NMT_STARTUP_TO_OPERATIONAL \ 200 | | CO_NMT_ERR_ON_ERR_REG \ 201 | | CO_ERR_REG_GENERIC_ERR \ 202 | | CO_ERR_REG_COMMUNICATION 203 | #endif 204 | #ifndef FIRST_HB_TIME 205 | #define FIRST_HB_TIME 500 206 | #endif 207 | #ifndef SDO_SRV_TIMEOUT_TIME 208 | #define SDO_SRV_TIMEOUT_TIME 1000 209 | #endif 210 | #ifndef SDO_CLI_TIMEOUT_TIME 211 | #define SDO_CLI_TIMEOUT_TIME 500 212 | #endif 213 | #ifndef SDO_CLI_BLOCK 214 | #define SDO_CLI_BLOCK false 215 | #endif 216 | #ifndef OD_STATUS_BITS 217 | #define OD_STATUS_BITS NULL 218 | #endif 219 | 220 | /* Definitions for application specific data storage objects */ 221 | #ifndef CO_STORAGE_APPLICATION 222 | #define CO_STORAGE_APPLICATION 223 | #endif 224 | /* Interval for automatic data storage in microseconds */ 225 | #ifndef CO_STORAGE_AUTO_INTERVAL 226 | #define CO_STORAGE_AUTO_INTERVAL 60000000 227 | #endif 228 | 229 | 230 | /* CANopen object */ 231 | CO_t *CO = NULL; 232 | 233 | /* Active node-id, copied from pendingNodeId in the communication reset */ 234 | static uint8_t CO_activeNodeId = CO_LSS_NODE_ID_ASSIGNMENT; 235 | 236 | /* Timer for time measurement */ 237 | volatile uint32_t CO_timer_us = 0; 238 | 239 | /* Data block for mainline data, which can be stored to non-volatile memory */ 240 | typedef struct { 241 | /* Pending CAN bit rate, can be set by switch or LSS slave. */ 242 | uint16_t pendingBitRate; 243 | /* Pending CANopen NodeId, can be set by switch or LSS slave. */ 244 | uint8_t pendingNodeId; 245 | } mainlineStorage_t; 246 | 247 | static mainlineStorage_t mlStorage = {0}; 248 | 249 | /* callback for storing node id and bitrate */ 250 | static bool_t LSScfgStoreCallback(void *object, uint8_t id, uint16_t bitRate) { 251 | mainlineStorage_t *mainlineStorage = object; 252 | mainlineStorage->pendingBitRate = bitRate; 253 | mainlineStorage->pendingNodeId = id; 254 | return true; 255 | } 256 | 257 | /* main ***********************************************************************/ 258 | int main (void) { 259 | CO_ReturnError_t err; 260 | CO_NMT_reset_cmd_t reset = CO_RESET_NOT; 261 | bool_t firstRun = true; 262 | 263 | #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE 264 | CO_storage_t storage; 265 | CO_storage_entry_t storageEntries[] = { 266 | { 267 | .addr = &OD_PERSIST_COMM, 268 | .len = sizeof(OD_PERSIST_COMM), 269 | .subIndexOD = 2, 270 | .attr = CO_storage_cmd | CO_storage_restore 271 | }, 272 | { 273 | .addr = &mlStorage, 274 | .len = sizeof(mlStorage), 275 | .subIndexOD = 4, 276 | .attr = CO_storage_cmd | CO_storage_auto | CO_storage_restore 277 | }, 278 | CO_STORAGE_APPLICATION 279 | }; 280 | uint8_t storageEntriesCount = sizeof(storageEntries) 281 | / sizeof(storageEntries[0]); 282 | uint32_t storageInitError = 0; 283 | #endif 284 | 285 | /* Configure system for maximum performance. plib is necessary for that.*/ 286 | /* SYSTEMConfig(CO_FSYS*1000, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE); */ 287 | 288 | /* Enable system multi vectored interrupts */ 289 | INTCONbits.MVEC = 1; 290 | __builtin_enable_interrupts(); 291 | 292 | /* Disable JTAG and trace port */ 293 | DDPCONbits.JTAGEN = 0; 294 | DDPCONbits.TROEN = 0; 295 | 296 | 297 | /* Allocate memory for CANopen objects */ 298 | uint32_t heapMemoryUsed = 0; 299 | CO = CO_new(NULL, &heapMemoryUsed); 300 | if (CO == NULL) { 301 | while (1); 302 | } 303 | 304 | 305 | #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE 306 | err = CO_storageEeprom_init(&storage, 307 | CO->CANmodule, 308 | NULL, 309 | OD_ENTRY_H1010_storeParameters, 310 | OD_ENTRY_H1011_restoreDefaultParameters, 311 | storageEntries, 312 | storageEntriesCount, 313 | &storageInitError); 314 | 315 | if (err != CO_ERROR_NO && err != CO_ERROR_DATA_CORRUPT) { 316 | while (1); 317 | } 318 | #endif 319 | 320 | /* Configure peripherals */ 321 | CO_PERIPHERAL_CONFIG(); 322 | 323 | /* Execute external application code */ 324 | uint32_t errInfo_app_programStart = 0; 325 | err = app_programStart(&mlStorage.pendingBitRate, 326 | &mlStorage.pendingNodeId, 327 | &errInfo_app_programStart); 328 | if (err != CO_ERROR_NO) { 329 | while (1); 330 | } 331 | 332 | /* verify stored values */ 333 | if (!CO_LSSchkBitrateCallback(NULL, mlStorage.pendingBitRate)) { 334 | mlStorage.pendingBitRate = 125; 335 | } 336 | if (mlStorage.pendingNodeId < 1 || mlStorage.pendingNodeId > 127) { 337 | mlStorage.pendingNodeId = CO_LSS_NODE_ID_ASSIGNMENT; 338 | } 339 | 340 | 341 | while (reset != CO_RESET_APP) { 342 | /* CANopen communication reset - initialize CANopen objects *******************/ 343 | uint32_t errInfo; 344 | static uint32_t CO_timer_us_previous = 0; 345 | 346 | /* disable CAN receive interrupts */ 347 | CO_CANRX_ENABLE(0); 348 | 349 | /* initialize CANopen */ 350 | err = CO_CANinit(CO, (void *)_CAN1_BASE_ADDRESS, 351 | mlStorage.pendingBitRate); 352 | if (err != CO_ERROR_NO) { 353 | while (1) CO_clearWDT(); 354 | } 355 | 356 | CO_LSS_address_t lssAddress = {.identity = { 357 | .vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, 358 | .productCode = OD_PERSIST_COMM.x1018_identity.productCode, 359 | .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, 360 | .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber 361 | }}; 362 | err = CO_LSSinit(CO, &lssAddress, 363 | &mlStorage.pendingNodeId, &mlStorage.pendingBitRate); 364 | if (err != CO_ERROR_NO) { 365 | while (1) CO_clearWDT(); 366 | } 367 | 368 | CO_activeNodeId = mlStorage.pendingNodeId; 369 | errInfo = 0; 370 | 371 | err = CO_CANopenInit(CO, /* CANopen object */ 372 | NULL, /* alternate NMT */ 373 | NULL, /* alternate em */ 374 | OD, /* Object dictionary */ 375 | OD_STATUS_BITS, /* Optional OD_statusBits */ 376 | NMT_CONTROL, /* CO_NMT_control_t */ 377 | FIRST_HB_TIME, /* firstHBTime_ms */ 378 | SDO_SRV_TIMEOUT_TIME, /* SDOserverTimeoutTime_ms */ 379 | SDO_CLI_TIMEOUT_TIME, /* SDOclientTimeoutTime_ms */ 380 | SDO_CLI_BLOCK, /* SDOclientBlockTransfer */ 381 | CO_activeNodeId, 382 | &errInfo); 383 | if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { 384 | while (1) CO_clearWDT(); 385 | } 386 | 387 | /* Emergency messages in case of errors */ 388 | if (!CO->nodeIdUnconfigured) { 389 | if (errInfo == 0) errInfo = errInfo_app_programStart; 390 | if (errInfo != 0) { 391 | CO_errorReport(CO->em, CO_EM_INCONSISTENT_OBJECT_DICT, 392 | CO_EMC_DATA_SET, errInfo); 393 | } 394 | #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE 395 | if (storageInitError != 0) { 396 | CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, 397 | CO_EMC_HARDWARE, storageInitError); 398 | } 399 | #endif 400 | } 401 | 402 | /* initialize callbacks */ 403 | CO_LSSslave_initCkBitRateCall(CO->LSSslave, NULL, 404 | CO_LSSchkBitrateCallback); 405 | CO_LSSslave_initCfgStoreCall(CO->LSSslave, &mlStorage, 406 | LSScfgStoreCallback); 407 | 408 | 409 | /* First time only initialization. */ 410 | if (firstRun) { 411 | firstRun = false; 412 | 413 | /* Configure real time thread and CAN receive interrupt */ 414 | CO_RT_THREAD_CONFIG(); 415 | CO_CANRX_CONFIG(); 416 | 417 | CO_timer_us_previous = CO_timer_us; 418 | } /* if(firstRun) */ 419 | 420 | /* Execute external application code */ 421 | app_communicationReset(CO); 422 | 423 | errInfo = 0; 424 | err = CO_CANopenInitPDO(CO, /* CANopen object */ 425 | CO->em, /* emergency object */ 426 | OD, /* Object dictionary */ 427 | CO_activeNodeId, 428 | &errInfo); 429 | if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { 430 | while (1) CO_clearWDT(); 431 | } 432 | 433 | 434 | /* start CAN and enable interrupts */ 435 | CO_CANsetNormalMode(CO->CANmodule); 436 | CO_RT_THREAD_ENABLE(1); 437 | CO_CANRX_ENABLE(1); 438 | reset = CO_RESET_NOT; 439 | 440 | 441 | while (reset == CO_RESET_NOT) { 442 | /* loop for normal program execution ******************************************/ 443 | 444 | /* calculate time difference since last cycle */ 445 | uint32_t timer_us_copy = CO_timer_us; 446 | uint32_t timeDifference_us = timer_us_copy - CO_timer_us_previous; 447 | CO_timer_us_previous = timer_us_copy; 448 | 449 | CO_clearWDT(); 450 | 451 | /* process CANopen objects */ 452 | reset = CO_process(CO, false, timeDifference_us, NULL); 453 | 454 | CO_clearWDT(); 455 | 456 | /* Execute external application code */ 457 | app_programAsync(CO, timeDifference_us); 458 | 459 | CO_clearWDT(); 460 | 461 | #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE 462 | CO_storageEeprom_auto_process(&storage, false); 463 | #endif 464 | } 465 | } /* while(reset != CO_RESET_APP */ 466 | 467 | 468 | /* program exit ***************************************************************/ 469 | CO_RT_THREAD_ENABLE(0); 470 | CO_CANRX_ENABLE(0); 471 | 472 | /* Execute external application code */ 473 | app_programEnd(); 474 | 475 | #if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE 476 | CO_storageEeprom_auto_process(&storage, true); 477 | #endif 478 | 479 | /* delete objects from memory */ 480 | CO_CANsetConfigurationMode(CO->CANmodule->CANptr); 481 | CO_delete(CO); 482 | 483 | /* reset microcontroller */ 484 | SYSKEY = 0x00000000; 485 | SYSKEY = 0xAA996655; 486 | SYSKEY = 0x556699AA; 487 | RSWRSTSET = 1; 488 | (void) RSWRST; 489 | while (1); 490 | } 491 | 492 | 493 | /* timer interrupt function executes every millisecond ************************/ 494 | #ifdef CO_RT_THREAD_ISR_DEFAULT 495 | CO_RT_THREAD_ISR() { 496 | CO_timer_us += CO_RT_THREAD_INTERVAL_US; 497 | 498 | /* Execute external application code */ 499 | app_peripheralRead(CO, CO_RT_THREAD_INTERVAL_US); 500 | 501 | CO_RT_THREAD_ISR_FLAG = 0; 502 | 503 | /* No need to CO_LOCK_OD(co->CANmodule); this is interrupt */ 504 | if (!CO->nodeIdUnconfigured && CO->CANmodule->CANnormal) { 505 | bool_t syncWas = false; 506 | 507 | #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE 508 | syncWas = CO_process_SYNC(CO, CO_RT_THREAD_INTERVAL_US, NULL); 509 | #endif 510 | #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE 511 | CO_process_RPDO(CO, syncWas, CO_RT_THREAD_INTERVAL_US, NULL); 512 | #endif 513 | 514 | /* Execute external application code */ 515 | app_programRt(CO, CO_RT_THREAD_INTERVAL_US); 516 | 517 | #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE 518 | CO_process_TPDO(CO, syncWas, CO_RT_THREAD_INTERVAL_US, NULL); 519 | #endif 520 | 521 | /* verify timer overflow */ 522 | if (CO_RT_THREAD_ISR_FLAG == 1) { 523 | CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, 524 | CO_EMC_SOFTWARE_INTERNAL, 0); 525 | CO_RT_THREAD_ISR_FLAG = 0; 526 | } 527 | 528 | (void) syncWas; 529 | } 530 | 531 | /* Execute external application code */ 532 | app_peripheralWrite(CO, CO_RT_THREAD_INTERVAL_US); 533 | } 534 | #endif /* CO_RT_THREAD_ISR_DEFAULT */ 535 | 536 | 537 | /* CAN interrupt function *****************************************************/ 538 | #ifdef CO_CANRX_ISR_DEFAULT 539 | CO_CANRX_ISR() { 540 | CO_CANinterrupt(CO->CANmodule); 541 | /* Clear combined Interrupt flag */ 542 | CO_CANRX_ISR_FLAG = 0; 543 | } 544 | #endif 545 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CANopenPIC {#readmeCANopenPIC} 2 | ========== 3 | 4 | CANopenPIC is a CANopen stack running on PIC microcontrollers. 5 | 6 | It is based on [CANopenNode](https://github.com/CANopenNode/CANopenNode), which is free and open source CANopen Stack and is included as a git submodule. 7 | 8 | CANopen is the internationally standardized (EN 50325-4) ([CiA301](http://can-cia.org/standardization/technical-documents)) CAN-based higher-layer protocol for embedded control system. For more information on CANopen see http://www.can-cia.org/. 9 | 10 | CANopenPIC homepage is https://github.com/CANopenNode/CANopenPIC 11 | 12 | 13 | Getting or updating the project 14 | ------------------------------- 15 | Clone the project from git repository and get submodules: 16 | 17 | git clone https://github.com/CANopenNode/CANopenPIC.git 18 | cd CANopenPIC 19 | git submodule init 20 | git submodule update 21 | 22 | Update the project: 23 | 24 | cd CANopenPIC 25 | git pull # or: git fetch; inspect the changes (gitk); git merge 26 | git submodule update 27 | 28 | 29 | Using on PIC32, dsPIC33, PIC24 and dsPIC30 30 | ------------------------------------------ 31 | Visit [Microchip](http://www.microchip.com/) and Install MplabX IDE, XC32 C compiler for PIC32 or XC16 C compiler for others. Works on Linux, Mac or Windows. 32 | 33 | PIC programmer is required, for example [PICkit 4](https://microchipdeveloper.com/pickit4:start). 34 | 35 | Open one of the example projects, build and program your microcontroller. 36 | 37 | Program is tested on Explorer16 board from Microchip with devices PIC32MX795F512L and dsPIC33FJ256GP710, and on Max32 board. CAN transciever chip must be soldered to the Explorer16 board. 38 | 39 | Program also works on dsPIC30F4011 with basic CANopen functionality (see dsPIC30F/CO_driver_target.h). Device has only 2 Kbytes of RAM. 40 | 41 | After connecting the CANopen PIC device into the CAN(open) network, bootup message is visible. By default device uses Object Dictionary from `CANopenNode/example`, which contains only communication parameters. With the external CANopen tool all parameters can be accessed and CANopen PIC device can be configured (For example write heartbeat producer time in object 0x1017,0). 42 | 43 | For more information and examples see https://github.com/CANopenNode/CANopenDemo 44 | 45 | 46 | ### PIC32 on Arduino style Max32 board 47 | - [Max32 board](https://reference.digilentinc.com/reference/microprocessor/max32/start) with [PIC32MX795F512L](https://www.microchip.com/wwwproducts/en/PIC32MX795F512L) Microcontroller. 48 | - Board must be programmed directly from MPLAB X, with PIC programmer, [PICkit 4](https://microchipdeveloper.com/pickit4:start) for example. It is necessary to solder the connector for programmer to the Max32 board. 49 | - Add CAN transciever (MCP2551 or similar) and EEEPROM (25LC128 or similar) chips to the board. See example schema below. CAN connector is DB9, according to CiA303,1, values in brackets are pins for flat cable, if used with DB9 connector. 50 | 51 | +-------+ +-------------+ +----------------+ 52 | | | 5-| VREF RXD |-4-----------45-| C1RX/ETXD1/RF0 | 53 | | CAN_L |-2(3)------6-| CAN_L VCC |-3-------+--5V0-| VCC5V0 | 54 | | CAN_H |-7(4)------7-| CAN_H GND |-2--+ | | | 55 | | | +--8-| RS TXD |-1--|----|---46-| C1TX/ETXD0/RF1 | 56 | | | | +-------------+ | | | | 57 | | | 47kΩ MCP2551 | 100nF | | 58 | | | | | | | | 59 | | GND |-3(5)---+------------GND--------+----+--GND-| GND | 60 | +-------+ | | 61 | DB9 | | 62 | | | 63 | +-----------------------------+------3V3-| VCC3V3 | 64 | | +--------------------------|-------29-| SDI2/RG7 | 65 | | | +-----------------------|-------53-| SS2/RG9 | 66 | | | | | | | 67 | | | | +-------------+ | | | 68 | | | +-1-| !CS VCC |-8---+ | | 69 | | +----2-| SO !HOLD |-7---+ | | 70 | +-------3-| !WP SCK |-6---|-------52-| SCK2/RG6 | 71 | +-4-| GND SI |-5---|-------43-| SDO2/RG8 | 72 | | +-------------+ | | | 73 | | 25LC128 100nF | | 74 | | | | | 75 | +-----------------------+------GND-| GND | 76 | +----------------+ 77 | Max32 78 | 79 | - If EEprom chip is not used or connected differently, disable or configure it in CO_driver_custom.h file. 80 | - File appl_max32_demo.c contains entry functions for custom application in Arduino style with additional CANopen communicationReset function and real-time thread. See file CO_application.h for more information. 81 | - Default CAN bitrate is 250kbps and CANopen NodeId is 0x30. See appl_max32_demo.c file. Can also be configured by CANopen LSS commands. 82 | - After Max32 is first connected to the CANopen network it shows bootup message and emergency message, because it has empty eeprom. It is necessary to trigger saveAll command and reset: `cocomm "0x30 w 0x1010 1 vs save" "0x30 reset node"`. To see heartbeat messages use: `cocomm "0x30 w 0x1017 0 u16 1000"`, etc. See also tutorial in https://github.com/CANopenNode/CANopenDemo 83 | 84 | 85 | Starting new project with MplabX 86 | -------------------------------- 87 | #### Create new project 88 | - Microchip Embedded, Application Project 89 | - Choose device, compiler 90 | - Specify project name and location, set UTF-8 91 | - Add header and source files, may be organized in logical folders, see example 92 | 93 | 94 | #### MplabX project configuration: 95 | - encoding: UTF-8 96 | - (gcc -> optimization-level = 1) 97 | - Global Options -> Use legacy libc: NO 98 | - Global Options -> Additional options : Add `-std=gnu99` 99 | - gcc -> Include directories (example_PIC32): `.;../PIC32;../CANopenNode` 100 | - Add `DO.h` and `OD.c` files to the project or include `../CANopenNode/example` above. 101 | - ld -> Heap size (bytes): 10000 (see heapMemoryUsed in main() for actual usage). 102 | If macro `CO_USE_GLOBALS` is definded, then heap is not needed. 103 | 104 | 105 | Change Log 106 | ---------- 107 | - **[v4.0](https://github.com/CANopenNode/CANopenPIC/tree/HEAD) - current**: Update CANopenNode to branch v4.0. [Full Changelog](https://github.com/CANopenNode/CANopenPIC/compare/v2.0...master) 108 | - Update CANopenNode to branch v4.0 (new object dictionary interface). 109 | - Minor updates in the drivers. 110 | - PIC32: renewed storage, main_PIC32.c and application interface. 111 | - Added Max32 board example. 112 | - Put some project files into gitignore. 113 | - Cleanup readme.md, wider example is in https://github.com/CANopenNode/CANopenDemo 114 | - **[v2.0](https://github.com/CANopenNode/CANopenPIC/tree/v2.0) - 2021-04-08**: Update CANopenNode to branch v2.0. [Full Changelog](https://github.com/CANopenNode/CANopenPIC/compare/v1.0...v2.0) 115 | - Update CANopenNode to branch v2.0. 116 | - License changed to Apache 2.0. 117 | - Drivers moved from CANopenNode into this project. Changed directory structure. Changed CANopen.h interface. 118 | - Trace added to PIC32. Time base changed to microseconds in all functions. 119 | - LSS slave running in all microcontrollers. 120 | - **[v1.0](https://github.com/CANopenNode/CANopenPIC/tree/v1.0) - 2016-03-21**: Stable. [Full Changelog](https://github.com/CANopenNode/CANopenPIC/compare/v0.5...v1.0) 121 | - **[v0.5](https://github.com/CANopenNode/CANopenPIC/tree/v0.5) - 2015-10-20**: Git repository started on GitHub. 122 | - **[v0.4](https://sourceforge.net/p/canopennode/code_complete/ci/master/tree/) - 2012-02-26**: Git repository started on Sourceforge. 123 | - **[v0.3](https://sourceforge.net/projects/canopennode/files/canopennode/CANopenNode-3.00/) - 2011-08-26**: First edition for 16 and 32 bit PIC on SourceForge. 124 | 125 | 126 | License 127 | ------- 128 | This file is part of CANopenNode, an opensource CANopen Stack. 129 | Project home page is . 130 | For more information on CANopen see . 131 | 132 | Licensed under the Apache License, Version 2.0 (the "License"); 133 | you may not use this file except in compliance with the License. 134 | You may obtain a copy of the License at 135 | 136 | http://www.apache.org/licenses/LICENSE-2.0 137 | 138 | Unless required by applicable law or agreed to in writing, software 139 | distributed under the License is distributed on an "AS IS" BASIS, 140 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 141 | See the License for the specific language governing permissions and 142 | limitations under the License. 143 | -------------------------------------------------------------------------------- /dsPIC30F/CO_driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CAN module object for Microchip dsPIC30F microcontroller. 3 | * 4 | * @file CO_driver.c 5 | * @author Janez Paternoster 6 | * @copyright 2004 - 2020 Janez Paternoster 7 | * 8 | * This file is part of CANopenNode, an opensource CANopen Stack. 9 | * Project home page is . 10 | * For more information on CANopen see . 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | #include "301/CO_driver.h" 27 | 28 | 29 | extern const CO_CANbitRateData_t CO_CANbitRateData[8]; 30 | 31 | /** 32 | * Macro and Constants - CAN module registers - offset. 33 | */ 34 | #define CAN_REG(base, offset) (*((volatile uint16_t *) ((char *)(base) + (offset)))) 35 | 36 | #define C_RXF0SID 0x00 37 | #define C_RXF0EIDH 0x02 38 | #define C_RXF0EIDL 0x04 39 | #define C_RXF1SID 0x08 40 | #define C_RXF1EIDH 0x0A 41 | #define C_RXF1EIDL 0x0C 42 | #define C_RXF2SID 0x10 43 | #define C_RXF2EIDH 0x12 44 | #define C_RXF2EIDL 0x14 45 | #define C_RXF3SID 0x18 46 | #define C_RXF3EIDH 0x1A 47 | #define C_RXF3EIDL 0x1C 48 | #define C_RXF4SID 0x20 49 | #define C_RXF4EIDH 0x22 50 | #define C_RXF4EIDL 0x24 51 | #define C_RXF5SID 0x28 52 | #define C_RXF5EIDH 0x2A 53 | #define C_RXF5EIDL 0x2C 54 | #define C_RXM0SID 0x30 55 | #define C_RXM0EIDH 0x32 56 | #define C_RXM0EIDL 0x34 57 | #define C_RXM1SID 0x38 58 | #define C_RXM1EIDH 0x3A 59 | #define C_RXM1EIDL 0x3C 60 | 61 | #define C_TXBUF2 0x40 62 | #define C_TXBUF1 0x50 63 | #define C_TXBUF0 0x60 64 | #define C_TXSID 0x0 65 | #define C_TXEID 0x2 66 | #define C_TXDLC 0x4 67 | #define C_TXB 0x6 68 | #define C_TXCON 0xE 69 | 70 | #define C_RXBUF1 0x70 71 | #define C_RXBUF0 0x80 72 | #define C_RXCON 0xE 73 | /* register alignment as in CO_CANrxMsg_t */ 74 | 75 | #define C_CTRL 0x90 76 | #define C_CFG1 0x92 77 | #define C_CFG2 0x94 78 | #define C_INTF 0x96 79 | #define C_INTE 0x98 80 | #define C_EC 0x9A 81 | 82 | 83 | /******************************************************************************/ 84 | void CO_CANsetConfigurationMode(void *CANptr){ 85 | uint16_t C_CTRLcopy = CAN_REG(CANptr, C_CTRL); 86 | 87 | /* set REQOP = 0x4 */ 88 | C_CTRLcopy &= 0xFCFF; 89 | C_CTRLcopy |= 0x0400; 90 | CAN_REG(CANptr, C_CTRL) = C_CTRLcopy; 91 | 92 | /* while OPMODE != 4 */ 93 | while((CAN_REG(CANptr, C_CTRL) & 0x00E0) != 0x0080); 94 | } 95 | 96 | 97 | /******************************************************************************/ 98 | void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ 99 | uint16_t C_CTRLcopy = CAN_REG(CANmodule->CANptr, C_CTRL); 100 | 101 | /* set REQOP = 0x0 */ 102 | C_CTRLcopy &= 0xF8FF; 103 | CAN_REG(CANmodule->CANptr, C_CTRL) = C_CTRLcopy; 104 | 105 | /* while OPMODE != 0 */ 106 | while((CAN_REG(CANmodule->CANptr, C_CTRL) & 0x00E0) != 0x0000); 107 | 108 | CANmodule->CANnormal = true; 109 | } 110 | 111 | 112 | /******************************************************************************/ 113 | CO_ReturnError_t CO_CANmodule_init( 114 | CO_CANmodule_t *CANmodule, 115 | void *CANptr, 116 | CO_CANrx_t rxArray[], 117 | uint16_t rxSize, 118 | CO_CANtx_t txArray[], 119 | uint16_t txSize, 120 | uint16_t CANbitRate) 121 | { 122 | uint16_t i; 123 | const CO_CANbitRateData_t *CANbitRateData = NULL; 124 | 125 | /* verify arguments */ 126 | if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ 127 | return CO_ERROR_ILLEGAL_ARGUMENT; 128 | } 129 | 130 | /* Configure object variables */ 131 | CANmodule->CANptr = CANptr; 132 | CANmodule->rxArray = rxArray; 133 | CANmodule->rxSize = rxSize; 134 | CANmodule->txArray = txArray; 135 | CANmodule->txSize = txSize; 136 | CANmodule->CANerrorStatus = 0; 137 | CANmodule->CANnormal = false; 138 | CANmodule->useCANrxFilters = false; 139 | CANmodule->bufferInhibitFlag = false; 140 | CANmodule->firstCANtxMessage = true; 141 | CANmodule->CANtxCount = 0U; 142 | CANmodule->errOld = 0U; 143 | 144 | for(i=0U; iscale == 1) 171 | CAN_REG(CANptr, C_CTRL) |= 0x0800; 172 | 173 | CAN_REG(CANptr, C_CFG1) = (CANbitRateData->SJW - 1) << 6 | 174 | (CANbitRateData->BRP - 1); 175 | 176 | CAN_REG(CANptr, C_CFG2) = ((uint16_t)(CANbitRateData->phSeg2 - 1)) << 8 | 177 | 0x0080 | 178 | (CANbitRateData->phSeg1 - 1) << 3 | 179 | (CANbitRateData->PROP - 1); 180 | 181 | 182 | /* setup RX and TX control registers */ 183 | CAN_REG(CANptr, C_RXBUF0 + C_RXCON) = 0x0040; 184 | CAN_REG(CANptr, C_RXBUF1 + C_RXCON) = 0x0000; 185 | CAN_REG(CANptr, C_TXBUF0 + C_TXCON) = 0x0000; 186 | CAN_REG(CANptr, C_TXBUF1 + C_TXCON) = 0x0000; 187 | CAN_REG(CANptr, C_TXBUF2 + C_TXCON) = 0x0000; 188 | 189 | 190 | /* CAN module hardware filters */ 191 | CAN_REG(CANptr, C_RXF0SID) = 0x0000; 192 | CAN_REG(CANptr, C_RXF1SID) = 0x0000; 193 | CAN_REG(CANptr, C_RXF2SID) = 0x0000; 194 | CAN_REG(CANptr, C_RXF3SID) = 0x0000; 195 | CAN_REG(CANptr, C_RXF4SID) = 0x0000; 196 | CAN_REG(CANptr, C_RXF5SID) = 0x0000; 197 | /* CAN module filters are not used, all messages with standard 11-bit */ 198 | /* identifier will be received */ 199 | /* Set masks so, that all messages with standard identifier are accepted */ 200 | CAN_REG(CANptr, C_RXM0SID) = 0x0001; 201 | CAN_REG(CANptr, C_RXM1SID) = 0x0001; 202 | 203 | 204 | /* CAN interrupt registers */ 205 | /* clear interrupt flags */ 206 | CAN_REG(CANptr, C_INTF) = 0x0000; 207 | /* enable both two receive interrupts and one transmit interrupt for TX0 */ 208 | CAN_REG(CANptr, C_INTE) = 0x0007; 209 | /* CAN interrupt (combined) must be configured by application */ 210 | 211 | return CO_ERROR_NO; 212 | } 213 | 214 | 215 | /******************************************************************************/ 216 | void CO_CANmodule_disable(CO_CANmodule_t *CANmodule) { 217 | if (CANmodule != NULL) { 218 | CO_CANsetConfigurationMode(CANmodule->CANptr); 219 | } 220 | } 221 | 222 | 223 | /******************************************************************************/ 224 | CO_ReturnError_t CO_CANrxBufferInit( 225 | CO_CANmodule_t *CANmodule, 226 | uint16_t index, 227 | uint16_t ident, 228 | uint16_t mask, 229 | bool_t rtr, 230 | void *object, 231 | void (*CANrx_callback)(void *object, void *message)) 232 | { 233 | CO_ReturnError_t ret = CO_ERROR_NO; 234 | 235 | if((CANmodule!=NULL) && (object!=NULL) && (CANrx_callback!=NULL) && (index < CANmodule->rxSize)){ 236 | /* buffer, which will be configured */ 237 | CO_CANrx_t *buffer = &CANmodule->rxArray[index]; 238 | uint16_t RXF, RXM; 239 | 240 | /* Configure object variables */ 241 | buffer->object = object; 242 | buffer->CANrx_callback = CANrx_callback; 243 | 244 | 245 | /* CAN identifier and CAN mask, bit aligned with CAN module registers */ 246 | RXF = (ident & 0x07FF) << 2; 247 | if(rtr){ 248 | RXF |= 0x02; 249 | } 250 | RXM = (mask & 0x07FF) << 2; 251 | RXM |= 0x02; 252 | 253 | /* configure filter and mask */ 254 | if(RXF != buffer->ident || RXM != buffer->mask){ 255 | buffer->ident = RXF; 256 | buffer->mask = RXM; 257 | } 258 | } 259 | else{ 260 | ret = CO_ERROR_ILLEGAL_ARGUMENT; 261 | } 262 | 263 | return ret; 264 | } 265 | 266 | 267 | /******************************************************************************/ 268 | CO_CANtx_t *CO_CANtxBufferInit( 269 | CO_CANmodule_t *CANmodule, 270 | uint16_t index, 271 | uint16_t ident, 272 | bool_t rtr, 273 | uint8_t noOfBytes, 274 | bool_t syncFlag) 275 | { 276 | CO_CANtx_t *buffer = NULL; 277 | 278 | if((CANmodule != NULL) && (index < CANmodule->txSize)){ 279 | /* get specific buffer */ 280 | buffer = &CANmodule->txArray[index]; 281 | 282 | /* CAN identifier, bit aligned with CAN module registers */ 283 | uint16_t TXF; 284 | TXF = ident << 5; 285 | TXF &= 0xF800; 286 | TXF |= (ident & 0x003F) << 2; 287 | if(rtr){ 288 | TXF |= 0x02; 289 | } 290 | 291 | /* write to buffer */ 292 | buffer->ident = TXF; 293 | buffer->DLC = noOfBytes; 294 | buffer->bufferFull = false; 295 | buffer->syncFlag = syncFlag; 296 | } 297 | 298 | return buffer; 299 | } 300 | 301 | 302 | /* Copy message to CAN module - internal usage only. 303 | * 304 | * @param dest Destination address of CAN module transmit buffer. 305 | * @param src Pointer to source message . 306 | */ 307 | static void CO_CANsendToModule(void *dest, CO_CANtx_t *src){ 308 | uint8_t DLC; 309 | volatile uint8_t *CANdataBuffer; 310 | uint8_t *pData; 311 | 312 | /* CAN-ID + RTR */ 313 | CAN_REG(dest, C_TXSID) = src->ident; 314 | 315 | /* Data lenght */ 316 | DLC = src->DLC; 317 | if(DLC > 8) DLC = 8; 318 | CAN_REG(dest, C_TXDLC) = DLC << 3; 319 | 320 | /* copy data */ 321 | CANdataBuffer = (volatile uint8_t*)((char *)dest + C_TXB); 322 | pData = src->data; 323 | for(; DLC>0; DLC--) *(CANdataBuffer++) = *(pData++); 324 | 325 | /* control register, transmit request */ 326 | CAN_REG(dest, C_TXCON) |= 0x08; 327 | } 328 | 329 | 330 | /******************************************************************************/ 331 | CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){ 332 | CO_ReturnError_t err = CO_ERROR_NO; 333 | void *CANptr = CANmodule->CANptr; 334 | 335 | /* Verify overflow */ 336 | if(buffer->bufferFull){ 337 | if(!CANmodule->firstCANtxMessage){ 338 | /* don't set error, if bootup message is still on buffers */ 339 | CANmodule->CANerrorStatus |= CO_CAN_ERRTX_OVERFLOW; 340 | } 341 | err = CO_ERROR_TX_OVERFLOW; 342 | } 343 | 344 | CO_LOCK_CAN_SEND(); 345 | /* if CAN TB buffer is free, copy message to it */ 346 | if((CAN_REG(CANptr, C_TXBUF0 + C_TXCON) & 0x8) == 0 && CANmodule->CANtxCount == 0){ 347 | CANmodule->bufferInhibitFlag = buffer->syncFlag; 348 | CO_CANsendToModule((void *)((char *)CANptr + C_TXBUF0), buffer); 349 | } 350 | /* if no buffer is free, message will be sent by interrupt */ 351 | else{ 352 | buffer->bufferFull = true; 353 | CANmodule->CANtxCount++; 354 | } 355 | CO_UNLOCK_CAN_SEND(); 356 | 357 | return err; 358 | } 359 | 360 | 361 | /******************************************************************************/ 362 | void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){ 363 | 364 | /* See generic driver for implemetation. */ 365 | } 366 | 367 | 368 | /******************************************************************************/ 369 | void CO_CANmodule_process(CO_CANmodule_t *CANmodule){ 370 | uint8_t err; 371 | 372 | err = CAN_REG(CANmodule->CANptr, C_INTF)>>8; 373 | 374 | if (CANmodule->errOld != err) { 375 | uint16_t status = CANmodule->CANerrorStatus; 376 | 377 | CANmodule->errOld = err; 378 | 379 | /* CAN RX bus overflow */ 380 | if(err & 0xC0){ 381 | status |= CO_CAN_ERRRX_OVERFLOW; 382 | CAN_REG(CANmodule->CANptr, C_INTF) &= 0x3FFF;/* clear bits */ 383 | } 384 | 385 | /* CAN TX bus off */ 386 | if(err & 0x20){ 387 | status |= CO_CAN_ERRTX_BUS_OFF; 388 | } 389 | else{ 390 | status &= 0xFFFF ^ CO_CAN_ERRTX_BUS_OFF; 391 | } 392 | 393 | /* CAN TX bus passive */ 394 | if(err & 0x10){ 395 | if(!CANmodule->firstCANtxMessage) status |= CO_CAN_ERRTX_PASSIVE; 396 | } 397 | else{ 398 | status &= 0xFFFF ^ (CO_CAN_ERRTX_PASSIVE | CO_CAN_ERRTX_OVERFLOW); 399 | } 400 | 401 | /* CAN RX bus passive */ 402 | if(err & 0x08){ 403 | status |= CO_CAN_ERRRX_PASSIVE; 404 | } 405 | else{ 406 | status &= 0xFFFF ^ CO_CAN_ERRRX_PASSIVE; 407 | } 408 | 409 | /* CAN TX or RX bus warning */ 410 | if(err & 0x19){ 411 | status |= CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING; 412 | } 413 | else{ 414 | status &= 0xFFFF ^ (CO_CAN_ERRTX_WARNING | CO_CAN_ERRRX_WARNING); 415 | } 416 | 417 | CANmodule->CANerrorStatus = status; 418 | } 419 | } 420 | 421 | 422 | /******************************************************************************/ 423 | void CO_CANinterrupt(CO_CANmodule_t *CANmodule){ 424 | uint16_t ICODE; 425 | ICODE = CAN_REG(CANmodule->CANptr, C_CTRL) & 0xE; 426 | 427 | /* receive interrupt 0 (New CAN messagge is available in RX buffer 0) */ 428 | if(ICODE == 0xC){ 429 | CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ 430 | uint16_t index; /* index of received message */ 431 | uint16_t rcvMsgIdent; /* identifier of the received message */ 432 | CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ 433 | bool_t msgMatched = false; 434 | 435 | rcvMsg = (CO_CANrxMsg_t*) ((char *)CANmodule->CANptr + C_RXBUF0); 436 | rcvMsgIdent = rcvMsg->ident; 437 | /* CAN module filters are not used, message with any standard 11-bit identifier */ 438 | /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ 439 | buffer = &CANmodule->rxArray[0]; 440 | for(index = CANmodule->rxSize; index > 0U; index--){ 441 | if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ 442 | msgMatched = true; 443 | break; 444 | } 445 | buffer++; 446 | } 447 | 448 | /* Call specific function, which will process the message */ 449 | if(msgMatched && (buffer != NULL) && (buffer->CANrx_callback != NULL)){ 450 | buffer->CANrx_callback(buffer->object, (void *)rcvMsg); 451 | } 452 | 453 | /* Clear RXFUL flag */ 454 | rcvMsg->CON &= 0xFF7F; 455 | 456 | /* Clear interrupt flag */ 457 | CAN_REG(CANmodule->CANptr, C_INTF) &= 0xFFFE; 458 | } 459 | 460 | 461 | /* receive interrupt 1 (New CAN messagge is available in RX buffer 1) */ 462 | else if(ICODE == 0xA){ 463 | CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */ 464 | uint16_t index; /* index of received message */ 465 | uint16_t rcvMsgIdent; /* identifier of the received message */ 466 | CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */ 467 | bool_t msgMatched = false; 468 | 469 | rcvMsg = (CO_CANrxMsg_t*) ((char *)CANmodule->CANptr + C_RXBUF1); 470 | rcvMsgIdent = rcvMsg->ident; 471 | /* CAN module filters are not used, message with any standard 11-bit identifier */ 472 | /* has been received. Search rxArray form CANmodule for the same CAN-ID. */ 473 | buffer = &CANmodule->rxArray[0]; 474 | for(index = CANmodule->rxSize; index > 0U; index--){ 475 | if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){ 476 | msgMatched = true; 477 | break; 478 | } 479 | buffer++; 480 | } 481 | 482 | /* Call specific function, which will process the message */ 483 | if(msgMatched && (buffer != NULL) && (buffer->CANrx_callback != NULL)){ 484 | buffer->CANrx_callback(buffer->object, (void *)rcvMsg); 485 | } 486 | 487 | /* Clear RXFUL flag */ 488 | rcvMsg->CON &= 0xFF7F; 489 | 490 | /* Clear interrupt flag */ 491 | CAN_REG(CANmodule->CANptr, C_INTF) &= 0xFFFD; 492 | } 493 | 494 | 495 | /* transmit interrupt (TX buffer is free) */ 496 | else if(ICODE == 0x8){ 497 | /* Clear interrupt flag */ 498 | CAN_REG(CANmodule->CANptr, C_INTF) &= 0xFFFB; 499 | /* First CAN message (bootup) was sent successfully */ 500 | CANmodule->firstCANtxMessage = false; 501 | /* clear flag from previous message */ 502 | CANmodule->bufferInhibitFlag = false; 503 | /* Are there any new messages waiting to be send and buffer is free */ 504 | if(CANmodule->CANtxCount > 0U && (CAN_REG(CANmodule->CANptr, C_TXBUF0 + C_TXCON) & 0x8) == 0){ 505 | uint16_t i; /* index of transmitting message */ 506 | 507 | /* first buffer */ 508 | CO_CANtx_t *buffer = &CANmodule->txArray[0]; 509 | /* search through whole array of pointers to transmit message buffers. */ 510 | for(i = CANmodule->txSize; i > 0U; i--){ 511 | /* if message buffer is full, send it. */ 512 | if(buffer->bufferFull){ 513 | buffer->bufferFull = false; 514 | CANmodule->CANtxCount--; 515 | 516 | /* Copy message to CAN buffer */ 517 | CANmodule->bufferInhibitFlag = buffer->syncFlag; 518 | CO_CANsendToModule((void *)((char *)CANmodule->CANptr + C_TXBUF0), buffer); 519 | break; /* exit for loop */ 520 | } 521 | buffer++; 522 | }/* end of for loop */ 523 | 524 | /* Clear counter if no more messages */ 525 | if(i == 0U){ 526 | CANmodule->CANtxCount = 0U; 527 | } 528 | } 529 | } 530 | } 531 | -------------------------------------------------------------------------------- /dsPIC30F/CO_driver_target.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Microchip dsPIC30F specific definitions for CANopenNode. 3 | * 4 | * @file CO_driver_target.h 5 | * @author Janez Paternoster 6 | * @copyright 2004 - 2020 Janez Paternoster 7 | * 8 | * This file is part of CANopenNode, an opensource CANopen Stack. 9 | * Project home page is . 10 | * For more information on CANopen see . 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | 26 | #ifndef CO_DRIVER_TARGET 27 | #define CO_DRIVER_TARGET 28 | 29 | /* This file contains device and application specific definitions. 30 | * It is included from CO_driver.h, which contains documentation 31 | * for definitions below. */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #ifdef CO_DRIVER_CUSTOM 39 | #include "CO_driver_custom.h" 40 | #endif 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | /* Stack configuration override from CO_driver.h. 47 | * For more information see file CO_config.h. */ 48 | /* Make small memory configuration, it is possible to reduce further by lowering number of PDOs */ 49 | #define CO_CONFIG_GLOBAL_FLAG_OD_DYNAMIC (0) 50 | #define CO_CONFIG_HB_CONS (0) 51 | #define CO_CONFIG_EM (CO_CONFIG_EM_PRODUCER) 52 | #define CO_CONFIG_SDO_SRV (0) /* only expedited transfer */ 53 | #define CO_CONFIG_SYNC (0) 54 | #define CO_CONFIG_PDO (CO_CONFIG_RPDO_ENABLE | CO_CONFIG_TPDO_ENABLE | CO_CONFIG_TPDO_TIMERS_ENABLE) 55 | #define CO_CONFIG_TIME (0) 56 | #define CO_CONFIG_LSS (0) 57 | #define CO_CONFIG_STORAGE (0) 58 | 59 | 60 | /* use global variables in CANopen.c instead of heap */ 61 | #define CO_USE_GLOBALS 62 | 63 | /* Basic definitions */ 64 | #define CO_LITTLE_ENDIAN 65 | #define CO_SWAP_16(x) x 66 | #define CO_SWAP_32(x) x 67 | #define CO_SWAP_64(x) x 68 | #define CO_OWN_INTTYPES 69 | #define PRIu32 "lu" 70 | #define PRId32 "ld" 71 | /* NULL is defined in stddef.h */ 72 | /* true and false are defined in stdbool.h */ 73 | /* int8_t to uint64_t are defined in stdint.h */ 74 | typedef unsigned char bool_t; 75 | typedef float float32_t; 76 | typedef long double float64_t; 77 | 78 | 79 | /* CAN module base addresses */ 80 | #define ADDR_CAN1 ((void *)0x300) 81 | #define ADDR_CAN2 ((void *)0x3C0) 82 | 83 | 84 | /* CAN receive message structure as aligned in CAN module. */ 85 | typedef struct { 86 | uint16_t ident; /* Standard Identifier as aligned in CAN module. 16 bits: 87 | 'UUUSSSSS SSSSSSRE' (U: unused; S: SID; R=SRR; E=IDE). */ 88 | uint16_t extIdent; /* Extended identifier, not used here */ 89 | uint16_t DLC :4; /* Data length code (bits 0...3) */ 90 | uint16_t DLCrest :12; /* Not used here (bits 4..15) */ 91 | uint8_t data[8]; /* 8 data bytes */ 92 | uint16_t CON; /* Control word */ 93 | } CO_CANrxMsg_t; 94 | 95 | /* Access to received CAN message */ 96 | #define CO_CANrxMsg_readIdent(msg) ((((uint16_t)(((CO_CANrxMsg_t *)(msg))->ident))>>2)&0x7FF) 97 | #define CO_CANrxMsg_readDLC(msg) ((uint8_t)(((CO_CANrxMsg_t *)(msg))->DLC)) 98 | #define CO_CANrxMsg_readData(msg) ((uint8_t *)(((CO_CANrxMsg_t *)(msg))->data)) 99 | 100 | /* Received message object */ 101 | typedef struct { 102 | uint16_t ident; 103 | uint16_t mask; 104 | void *object; 105 | void (*CANrx_callback)(void *object, void *message); 106 | } CO_CANrx_t; 107 | 108 | /* Transmit message object */ 109 | typedef struct { 110 | uint16_t ident; /* Standard Identifier as aligned in CAN module. 16 bits: 111 | 'SSSSSUUU SSSSSSRE' (U: unused; S: SID; R=SRR; E=IDE). */ 112 | uint8_t DLC; 113 | uint8_t data[8]; 114 | volatile bool_t bufferFull; 115 | volatile bool_t syncFlag; 116 | } CO_CANtx_t; 117 | 118 | /* CAN module object */ 119 | typedef struct { 120 | void *CANptr; 121 | CO_CANrx_t *rxArray; 122 | uint16_t rxSize; 123 | CO_CANtx_t *txArray; 124 | uint16_t txSize; 125 | uint16_t CANerrorStatus; 126 | volatile bool_t CANnormal; 127 | volatile bool_t useCANrxFilters; 128 | volatile bool_t bufferInhibitFlag; 129 | volatile bool_t firstCANtxMessage; 130 | volatile uint16_t CANtxCount; 131 | uint8_t errOld; 132 | } CO_CANmodule_t; 133 | 134 | 135 | /* (un)lock critical section in CO_CANsend() */ 136 | #define CO_LOCK_CAN_SEND(CAN_MODULE) asm volatile ("disi #0x3FFF") 137 | #define CO_UNLOCK_CAN_SEND(CAN_MODULE) asm volatile ("disi #0x0000") 138 | 139 | /* (un)lock critical section in CO_errorReport() or CO_errorReset() */ 140 | #define CO_LOCK_EMCY(CAN_MODULE) asm volatile ("disi #0x3FFF") 141 | #define CO_UNLOCK_EMCY(CAN_MODULE) asm volatile ("disi #0x0000") 142 | 143 | /* (un)lock critical section when accessing Object Dictionary */ 144 | #define CO_LOCK_OD(CAN_MODULE) asm volatile ("disi #0x3FFF") 145 | #define CO_UNLOCK_OD(CAN_MODULE) asm volatile ("disi #0x0000") 146 | 147 | /* Synchronization between CAN receive and message processing threads. */ 148 | #define CO_MemoryBarrier() 149 | #define CO_FLAG_READ(rxNew) ((rxNew) != NULL) 150 | #define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} 151 | #define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} 152 | 153 | 154 | /* CAN bit rates 155 | * 156 | * CAN bit rates are initializers for array of eight CO_CANbitRateData_t 157 | * objects. 158 | * 159 | * Macros are not used by driver itself, they may be used by application with 160 | * combination with object CO_CANbitRateData_t. 161 | * Application must declare following global variable depending on CO_FCY used: 162 | * const CO_CANbitRateData_t CO_CANbitRateData[8] = {CO_CANbitRateDataInitializers}; 163 | * 164 | * There are initializers for eight objects, which corresponds to following 165 | * CAN bit rates (in kbps): 10, 20, 50, 125, 250, 500, 800, 1000. 166 | * 167 | * CO_FCY is internal instruction cycle clock frequency in kHz units. It is 168 | * calculated from oscillator frequency (FOSC [in kHz]) and PLL mode: 169 | * - If PLL is not used -> FCY = FOSC / 4, 170 | * - If PLL x 4 is used -> FCY = FOSC, 171 | * - If PLL x 16 is used -> FCY = FOSC * 4 172 | * 173 | * Possible values for FCY are (in three groups): 174 | * - Optimal CAN bit timing on all Baud Rates: 4000, 6000, 16000, 24000. 175 | * - Not so optimal CAN bit timing on all Baud Rates: 2000, 8000. 176 | * - not all CANopen Baud Rates possible: 1000, 1500, 2500, 3000, 5000, 177 | * 10000, 12000, 20000, 28000, 30000, 1843 (internal FRC, no PLL), 178 | * 7372 (internal FRC + 4*PLL). 179 | */ 180 | #ifdef CO_FCY 181 | /* Macros, which divides K into (SJW + PROP + PhSeg1 + PhSeg2) */ 182 | #define TQ_x_4 1, 1, 1, 1 183 | #define TQ_x_5 1, 1, 2, 1 184 | #define TQ_x_6 1, 1, 3, 1 185 | #define TQ_x_8 1, 2, 3, 2 186 | #define TQ_x_9 1, 2, 4, 2 187 | #define TQ_x_10 1, 3, 4, 2 188 | #define TQ_x_12 1, 3, 6, 2 189 | #define TQ_x_14 1, 4, 7, 2 190 | #define TQ_x_15 1, 4, 8, 2 /* good timing */ 191 | #define TQ_x_16 1, 5, 8, 2 /* good timing */ 192 | #define TQ_x_17 1, 6, 8, 2 /* good timing */ 193 | #define TQ_x_18 1, 7, 8, 2 /* good timing */ 194 | #define TQ_x_19 1, 8, 8, 2 /* good timing */ 195 | #define TQ_x_20 1, 8, 8, 3 /* good timing */ 196 | #define TQ_x_21 1, 8, 8, 4 197 | #define TQ_x_25 1, 8, 8, 8 198 | 199 | #if CO_FCY == 1000 200 | #define CO_CANbitRateDataInitializers \ 201 | {4, 10, TQ_x_20, 10}, \ 202 | {4, 5, TQ_x_20, 20}, \ 203 | {4, 2, TQ_x_20, 50}, \ 204 | {4, 1, TQ_x_16, 125}, \ 205 | {4, 1, TQ_x_8 , 250}, \ 206 | {4, 1, TQ_x_4 , 500}, \ 207 | {4, 1, TQ_x_4 , 0}, \ 208 | {4, 1, TQ_x_4 , 0} 209 | #elif CO_FCY == 1500 210 | #define CO_CANbitRateDataInitializers \ 211 | {4, 15, TQ_x_20, 10}, \ 212 | {4, 10, TQ_x_15, 20}, \ 213 | {4, 4, TQ_x_15, 50}, \ 214 | {4, 2, TQ_x_12, 125}, \ 215 | {4, 1, TQ_x_12, 250}, \ 216 | {4, 1, TQ_x_6 , 500}, \ 217 | {4, 1, TQ_x_6 , 0}, \ 218 | {4, 1, TQ_x_6 , 0} 219 | #elif CO_FCY == 1843 /* internal FRC, no PLL */ 220 | #define CO_CANbitRateDataInitializers \ 221 | {4, 23, TQ_x_16, 10}, \ 222 | {4, 23, TQ_x_8 , 20}, \ 223 | {4, 23, TQ_x_8 , 0}, \ 224 | {4, 23, TQ_x_8 , 0}, \ 225 | {4, 23, TQ_x_8 , 0}, \ 226 | {4, 23, TQ_x_8 , 0}, \ 227 | {4, 23, TQ_x_8 , 0}, \ 228 | {4, 23, TQ_x_8 , 0} 229 | #elif CO_FCY == 2000 230 | #define CO_CANbitRateDataInitializers \ 231 | {4, 25, TQ_x_16, 10}, \ 232 | {4, 10, TQ_x_20, 20}, \ 233 | {4, 5, TQ_x_16, 50}, \ 234 | {4, 2, TQ_x_16, 125}, \ 235 | {4, 1, TQ_x_16, 250}, \ 236 | {4, 1, TQ_x_8 , 500}, \ 237 | {4, 1, TQ_x_5 , 800}, \ 238 | {4, 1, TQ_x_4 , 1000} 239 | #elif CO_FCY == 2500 240 | #define CO_CANbitRateDataInitializers \ 241 | {4, 25, TQ_x_20, 10}, \ 242 | {4, 10, TQ_x_25, 20}, \ 243 | {4, 5, TQ_x_20, 50}, \ 244 | {4, 2, TQ_x_20, 125}, \ 245 | {4, 1, TQ_x_20, 250}, \ 246 | {4, 1, TQ_x_10, 500}, \ 247 | {4, 1, TQ_x_10, 0}, \ 248 | {4, 1, TQ_x_5 , 1000} 249 | #elif CO_FCY == 3000 250 | #define CO_CANbitRateDataInitializers \ 251 | {4, 40, TQ_x_15, 10}, \ 252 | {4, 20, TQ_x_15, 20}, \ 253 | {4, 8, TQ_x_15, 50}, \ 254 | {4, 3, TQ_x_16, 125}, \ 255 | {4, 2, TQ_x_12, 250}, \ 256 | {4, 1, TQ_x_12, 500}, \ 257 | {4, 1, TQ_x_12, 0}, \ 258 | {4, 1, TQ_x_6 , 1000} 259 | #elif CO_FCY == 4000 260 | #define CO_CANbitRateDataInitializers \ 261 | {4, 50, TQ_x_16, 10}, \ 262 | {4, 25, TQ_x_16, 20}, \ 263 | {4, 10, TQ_x_16, 50}, \ 264 | {4, 4, TQ_x_16, 125}, \ 265 | {4, 2, TQ_x_16, 250}, \ 266 | {4, 1, TQ_x_16, 500}, \ 267 | {4, 1, TQ_x_10, 800}, \ 268 | {4, 1, TQ_x_8 , 1000} 269 | #elif CO_FCY == 5000 270 | #define CO_CANbitRateDataInitializers \ 271 | {4, 50, TQ_x_20, 10}, \ 272 | {4, 25, TQ_x_20, 20}, \ 273 | {4, 10, TQ_x_20, 50}, \ 274 | {4, 5, TQ_x_16, 125}, \ 275 | {4, 2, TQ_x_20, 250}, \ 276 | {4, 1, TQ_x_20, 500}, \ 277 | {4, 1, TQ_x_20, 0}, \ 278 | {4, 1, TQ_x_10, 1000} 279 | #elif CO_FCY == 6000 280 | #define CO_CANbitRateDataInitializers \ 281 | {4, 63, TQ_x_19, 10}, \ 282 | {4, 40, TQ_x_15, 20}, \ 283 | {4, 15, TQ_x_16, 50}, \ 284 | {4, 6, TQ_x_16, 125}, \ 285 | {4, 3, TQ_x_16, 250}, \ 286 | {4, 2, TQ_x_12, 500}, \ 287 | {4, 1, TQ_x_15, 800}, \ 288 | {4, 1, TQ_x_12, 1000} 289 | #elif CO_FCY == 7372 /* internal FRC + 4*PLL */ 290 | #define CO_CANbitRateDataInitializers \ 291 | {1, 23, TQ_x_16, 10}, \ 292 | {4, 46, TQ_x_16, 20}, \ 293 | {4, 14, TQ_x_21, 50}, \ 294 | {4, 13, TQ_x_9 , 125}, \ 295 | {4, 13, TQ_x_9 , 0}, \ 296 | {4, 13, TQ_x_9 , 0}, \ 297 | {4, 13, TQ_x_9 , 0}, \ 298 | {4, 13, TQ_x_9 , 0} 299 | #elif CO_FCY == 8000 300 | #define CO_CANbitRateDataInitializers \ 301 | {1, 25, TQ_x_16, 10}, \ 302 | {1, 10, TQ_x_20, 20}, \ 303 | {1, 5, TQ_x_16, 50}, \ 304 | {1, 2, TQ_x_16, 125}, \ 305 | {1, 1, TQ_x_16, 250}, \ 306 | {1, 1, TQ_x_8 , 500}, \ 307 | {1, 1, TQ_x_5 , 800}, \ 308 | {1, 1, TQ_x_4 , 1000} 309 | #elif CO_FCY == 10000 310 | #define CO_CANbitRateDataInitializers \ 311 | {1, 25, TQ_x_20, 10}, \ 312 | {1, 10, TQ_x_25, 20}, \ 313 | {1, 5, TQ_x_20, 50}, \ 314 | {1, 2, TQ_x_20, 125}, \ 315 | {1, 1, TQ_x_20, 250}, \ 316 | {1, 1, TQ_x_10, 500}, \ 317 | {1, 1, TQ_x_10, 0}, \ 318 | {1, 1, TQ_x_5 , 1000} 319 | #elif CO_FCY == 12000 320 | #define CO_CANbitRateDataInitializers \ 321 | {1, 40, TQ_x_15, 10}, \ 322 | {1, 20, TQ_x_15, 20}, \ 323 | {1, 8, TQ_x_15, 50}, \ 324 | {1, 3, TQ_x_16, 125}, \ 325 | {1, 2, TQ_x_12, 250}, \ 326 | {1, 1, TQ_x_12, 500}, \ 327 | {1, 1, TQ_x_12, 0}, \ 328 | {1, 1, TQ_x_6 , 1000} 329 | #elif CO_FCY == 16000 330 | #define CO_CANbitRateDataInitializers \ 331 | {1, 50, TQ_x_16, 10}, \ 332 | {1, 25, TQ_x_16, 20}, \ 333 | {1, 10, TQ_x_16, 50}, \ 334 | {1, 4, TQ_x_16, 125}, \ 335 | {1, 2, TQ_x_16, 250}, \ 336 | {1, 1, TQ_x_16, 500}, \ 337 | {1, 1, TQ_x_10, 800}, \ 338 | {1, 1, TQ_x_8 , 1000} 339 | #elif CO_FCY == 20000 340 | #define CO_CANbitRateDataInitializers \ 341 | {1, 50, TQ_x_20, 10}, \ 342 | {1, 25, TQ_x_20, 20}, \ 343 | {1, 10, TQ_x_20, 50}, \ 344 | {1, 5, TQ_x_16, 125}, \ 345 | {1, 2, TQ_x_20, 250}, \ 346 | {1, 1, TQ_x_20, 500}, \ 347 | {1, 1, TQ_x_20, 0}, \ 348 | {1, 1, TQ_x_10, 1000} 349 | #elif CO_FCY == 24000 350 | #define CO_CANbitRateDataInitializers \ 351 | {1, 63, TQ_x_19, 10}, \ 352 | {1, 40, TQ_x_15, 20}, \ 353 | {1, 15, TQ_x_16, 50}, \ 354 | {1, 6, TQ_x_16, 125}, \ 355 | {1, 3, TQ_x_16, 250}, \ 356 | {1, 2, TQ_x_12, 500}, \ 357 | {1, 1, TQ_x_15, 800}, \ 358 | {1, 1, TQ_x_12, 1000} 359 | #elif CO_FCY == 28000 360 | #define CO_CANbitRateDataInitializers \ 361 | {1, 56, TQ_x_25, 10}, \ 362 | {1, 35, TQ_x_20, 20}, \ 363 | {1, 14, TQ_x_20, 50}, \ 364 | {1, 7, TQ_x_16, 125}, \ 365 | {1, 4, TQ_x_14, 250}, \ 366 | {1, 2, TQ_x_14, 500}, \ 367 | {1, 2, TQ_x_14, 0}, \ 368 | {1, 1, TQ_x_14, 1000} 369 | #elif CO_FCY == 30000 370 | #define CO_CANbitRateDataInitializers \ 371 | {1, 60, TQ_x_25, 10}, \ 372 | {1, 50, TQ_x_15, 20}, \ 373 | {1, 20, TQ_x_15, 50}, \ 374 | {1, 8, TQ_x_15, 125}, \ 375 | {1, 4, TQ_x_15, 250}, \ 376 | {1, 2, TQ_x_15, 500}, \ 377 | {1, 2, TQ_x_15, 0}, \ 378 | {1, 1, TQ_x_15, 1000} 379 | #else 380 | #error define_CO_FCY CO_FCY not supported 381 | #endif 382 | #endif 383 | 384 | /* Structure contains timing coefficients for CAN module. 385 | * 386 | * CAN baud rate is calculated from following equations: 387 | * FCAN = FCY * Scale - Input frequency to CAN module (MAX 30MHz for dsPIC30F) 388 | * TQ = 2 * BRP / FCAN - Time Quanta 389 | * BaudRate = 1 / (TQ * K) - Can bus Baud Rate 390 | * K = SJW + PROP + PhSeg1 + PhSeg2 - Number of Time Quantas 391 | */ 392 | typedef struct { 393 | uint8_t scale; /* (1 or 4) Scales FCY clock - dsPIC30F specific */ 394 | uint8_t BRP; /* (1...64) Baud Rate Prescaler */ 395 | uint8_t SJW; /* (1...4) SJW time */ 396 | uint8_t PROP; /* (1...8) PROP time */ 397 | uint8_t phSeg1; /* (1...8) Phase Segment 1 time */ 398 | uint8_t phSeg2; /* (1...8) Phase Segment 2 time */ 399 | uint16_t bitrate; /* bitrate in kbps */ 400 | } CO_CANbitRateData_t; 401 | 402 | #ifdef __cplusplus 403 | } 404 | #endif /* __cplusplus */ 405 | 406 | #endif /* CO_DRIVER_TARGET */ 407 | -------------------------------------------------------------------------------- /dsPIC33C/CO_driver_target.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Microchip dsPIC33C specific definitions for CANopenNode. 3 | * 4 | * @file CO_driver_target.h 5 | * @author Janez Paternoster 6 | * @author Peter Rozsahegyi (EDS) 7 | * @author Jens Nielsen (CAN receive) 8 | * @author Julien Peyregne (dsPIC33C) 9 | * @copyright 2004 - 2024 Janez Paternoster 10 | * 11 | * This file is part of CANopenNode, an opensource CANopen Stack. 12 | * Project home page is . 13 | * For more information on CANopen see . 14 | * 15 | * Licensed under the Apache License, Version 2.0 (the "License"); 16 | * you may not use this file except in compliance with the License. 17 | * You may obtain a copy of the License at 18 | * 19 | * http://www.apache.org/licenses/LICENSE-2.0 20 | * 21 | * Unless required by applicable law or agreed to in writing, software 22 | * distributed under the License is distributed on an "AS IS" BASIS, 23 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | * See the License for the specific language governing permissions and 25 | * limitations under the License. 26 | */ 27 | 28 | 29 | #ifndef CO_DRIVER_TARGET 30 | #define CO_DRIVER_TARGET 31 | 32 | /* This file contains device and application specific definitions. 33 | * It is included from CO_driver.h, which contains documentation 34 | * for definitions below. */ 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #ifdef CO_DRIVER_CUSTOM 42 | #include "CO_driver_custom.h" 43 | #endif 44 | 45 | #ifdef __cplusplus 46 | extern "C" { 47 | #endif 48 | 49 | /* Stack configuration override from CO_driver.h. 50 | * For more information see file CO_config.h. */ 51 | /* Use default options here, it is possible to reduce memory usage. */ 52 | 53 | 54 | /* Basic definitions */ 55 | #define CO_LITTLE_ENDIAN 56 | #define CO_SWAP_16(x) x 57 | #define CO_SWAP_32(x) x 58 | #define CO_SWAP_64(x) x 59 | #define CO_OWN_INTTYPES 60 | #define PRIu32 "lu" 61 | #define PRId32 "ld" 62 | /* NULL is defined in stddef.h */ 63 | /* true and false are defined in stdbool.h */ 64 | /* int8_t to uint64_t are defined in stdint.h */ 65 | typedef unsigned char bool_t; 66 | typedef float float32_t; 67 | typedef long double float64_t; 68 | 69 | 70 | /* CAN message buffer sizes for CAN module 1 and 2. Valid values 71 | * are 0, 4, 6, 8, 12, 16. Default is one TX and seven RX messages (FIFO). */ 72 | #ifndef CAN_FIFO_ALLOCATE_RAM_SIZE 73 | #define CAN_FIFO_ALLOCATE_RAM_SIZE 5000 // TODO 74 | #endif 75 | 76 | 77 | /* Default DMA addresses for CAN modules. */ 78 | #ifndef CO_CAN1_DMA0 79 | #define CO_CAN1_DMA0 ADDR_DMA0 80 | #endif 81 | #ifndef CO_CAN1_DMA1 82 | #define CO_CAN1_DMA1 ADDR_DMA1 83 | #endif 84 | #ifndef CO_CAN2_DMA0 85 | #define CO_CAN2_DMA0 ADDR_DMA2 86 | #endif 87 | #ifndef CO_CAN2_DMA1 88 | #define CO_CAN2_DMA1 ADDR_DMA3 89 | #endif 90 | 91 | /* Define DMA attribute on supported platforms */ 92 | #if defined(__dsPIC33F__) || defined(__PIC24H__) || defined(__DMA_BASE) 93 | #define __dma __attribute__((space(dma))) 94 | #else 95 | #define __dma 96 | #if defined(__C30_VERSION__) && !defined(__XC16_VERSION__) 97 | #define __builtin_dmaoffset(V) (uint16_t)V 98 | #endif 99 | #endif 100 | 101 | /* Define EDS attribute on supported platforms */ 102 | #if defined(__HAS_EDS__) 103 | #define __eds __attribute__((eds)) 104 | #if defined(__C30_VERSION__) && !defined(__XC16_VERSION__) 105 | #define __builtin_dmapage(V) (uint16_t)0 106 | #endif 107 | #else 108 | #define __eds 109 | #define __eds__ 110 | #endif 111 | 112 | /* CAN module base addresses */ 113 | #define ADDR_CAN1 ((void *)&C1CONL) 114 | #define ADDR_CAN2 ((void *)&C2CONL) 115 | 116 | 117 | /*data structure to implement a CANFD message buffer. */ 118 | /* CANFD Message Time Stamp */ 119 | typedef unsigned long CANFD_MSG_TIMESTAMP; 120 | 121 | /* CANFD RX Message Object Control*/ 122 | typedef struct _CANFD_RX_MSGOBJ_CTRL { 123 | uint16_t DLC:4; 124 | uint16_t IDE:1; 125 | uint16_t RTR:1; 126 | uint16_t BRS:1; 127 | uint16_t FDF:1; 128 | uint16_t ESI:1; 129 | uint16_t unimplemented1:2; 130 | uint16_t FilterHit:5; 131 | uint16_t unimplemented2:16; 132 | } CANFD_RX_MSGOBJ_CTRL; 133 | 134 | /* CANFD RX Message ID*/ 135 | typedef struct _CANFD_MSGOBJ_ID { 136 | uint16_t SID:11; 137 | uint32_t EID:18; 138 | uint16_t SID11:1; 139 | uint16_t unimplemented1:2; 140 | } CANFD_MSGOBJ_ID; 141 | 142 | 143 | /* CAN receive message structure as aligned in CAN module. */ 144 | /* In dsPIC33F and PIC24H this structure is used for both: transmitting and 145 | * receiving to and from CAN module. (Object is ownded by CAN module). 146 | */ 147 | typedef struct { 148 | struct { 149 | CANFD_MSGOBJ_ID id; 150 | CANFD_RX_MSGOBJ_CTRL ctrl; 151 | // CANFD_MSG_TIMESTAMP timeStamp; // Only exist if RXTSEN is set (CxFIFOCONxL) 152 | uint8_t dataByte[8]; 153 | } bF; 154 | uint16_t word[8];//10 155 | uint8_t byte [16];//20 156 | } CO_CANrxMsg_t; 157 | 158 | 159 | /* Access to received CAN message */ 160 | #define CO_CANrxMsg_readIdent(msg) ((((uint16_t)(((CO_CANrxMsg_t *)(msg))->bF.id.SID))>>2)&0x7FF) 161 | #define CO_CANrxMsg_readDLC(msg) ((uint8_t)(((CO_CANrxMsg_t *)(msg))->bF.ctrl.DLC)) 162 | #define CO_CANrxMsg_readData(msg) ((uint8_t *)(((CO_CANrxMsg_t *)(msg))->bF.dataByte)) 163 | 164 | /* Received message object */ 165 | typedef struct { 166 | uint16_t ident; 167 | uint16_t mask; 168 | void *object; 169 | void (*CANrx_callback)(void *object, void *message); 170 | } CO_CANrx_t; 171 | 172 | /* Transmit message object */ 173 | typedef struct { 174 | uint16_t ident; /* Standard Identifier as aligned in CAN module. 16 bits: 175 | 'SSSSSUUU SSSSSSRE' (U: unused; S: SID; R=SRR; E=IDE). */ 176 | uint8_t DLC; 177 | uint8_t data[8]; 178 | volatile bool_t bufferFull; 179 | volatile bool_t syncFlag; 180 | } CO_CANtx_t; 181 | 182 | /* CAN module object */ 183 | typedef struct { 184 | void *CANptr; 185 | CO_CANrx_t *rxArray; 186 | uint16_t rxSize; 187 | CO_CANtx_t *txArray; 188 | uint16_t txSize; 189 | uint16_t CANerrorStatus; 190 | volatile bool_t CANnormal; 191 | volatile bool_t useCANrxFilters; 192 | volatile bool_t bufferInhibitFlag; 193 | volatile bool_t firstCANtxMessage; 194 | volatile uint16_t CANtxCount; 195 | uint16_t errOld; 196 | unsigned int mapFlthitIndex[16]; 197 | } CO_CANmodule_t; 198 | 199 | 200 | /* (un)lock critical section in CO_CANsend() */ 201 | #define CO_LOCK_CAN_SEND(CAN_MODULE) asm volatile ("disi #0x3FFF") 202 | #define CO_UNLOCK_CAN_SEND(CAN_MODULE) asm volatile ("disi #0x0000") 203 | 204 | /* (un)lock critical section in CO_errorReport() or CO_errorReset() */ 205 | #define CO_LOCK_EMCY(CAN_MODULE) asm volatile ("disi #0x3FFF") 206 | #define CO_UNLOCK_EMCY(CAN_MODULE) asm volatile ("disi #0x0000") 207 | 208 | /* (un)lock critical section when accessing Object Dictionary */ 209 | #define CO_LOCK_OD(CAN_MODULE) asm volatile ("disi #0x3FFF") 210 | #define CO_UNLOCK_OD(CAN_MODULE) asm volatile ("disi #0x0000") 211 | 212 | /* dsPIC33F specific */ 213 | #define CO_DISABLE_INTERRUPTS() asm volatile ("disi #0x3FFF") 214 | #define CO_ENABLE_INTERRUPTS() asm volatile ("disi #0x0000") 215 | 216 | /* Synchronization between CAN receive and message processing threads. */ 217 | #define CO_MemoryBarrier() 218 | #define CO_FLAG_READ(rxNew) ((rxNew) != NULL) 219 | #define CO_FLAG_SET(rxNew) {CO_MemoryBarrier(); rxNew = (void*)1L;} 220 | #define CO_FLAG_CLEAR(rxNew) {CO_MemoryBarrier(); rxNew = NULL;} 221 | 222 | void CO_CANinterrupt(CO_CANmodule_t *CANmodule); 223 | void CO_CANinterruptRX(CO_CANmodule_t *CANmodule); 224 | void CO_CANinterruptTX(CO_CANmodule_t *CANmodule); 225 | 226 | /* CAN bit rates 227 | * 228 | * CAN bit rates are initializers for array of eight CO_CANbitRateData_t 229 | * objects. 230 | * 231 | * Macros are not used by driver itself, they may be used by application with 232 | * combination with object CO_CANbitRateData_t. 233 | * Application must declare following global variable depending on CO_FCY used: 234 | * const CO_CANbitRateData_t CO_CANbitRateData[8] = {CO_CANbitRateDataInitializers}; 235 | * 236 | * There are initializers for eight objects, which corresponds to following 237 | * CAN bit rates (in kbps): 10, 20, 50, 125, 250, 500, 800, 1000. 238 | * 239 | * CO_FCY is internal instruction cycle clock frequency in kHz units. See 240 | * dsPIC33F documentation for more information on FCY. 241 | * 242 | * Possible values for FCY are (in three groups): 243 | * - Optimal CAN bit timing on all Baud Rates: 8000, 12000, 16000, 24000. 244 | * - Not so optimal CAN bit timing on all Baud Rates: 4000, 32000. 245 | * - not all CANopen Baud Rates possible: 2000, 3000, 5000, 6000, 10000, 246 | * 20000, 40000, 48000, 56000, 64000, 70000. 247 | * 248 | * IMPORTANT: For FCY<=12000 there is unresolved bug; CANCKS configuration 249 | * bit on ECAN does not work, so some baudrates are not possible. 250 | */ 251 | #ifdef CO_FCY 252 | /* Macros, which divides K into (SJW + PROP + PhSeg1 + PhSeg2) */ 253 | #define TQ_x_4 1, 1, 1, 1 254 | #define TQ_x_5 1, 1, 2, 1 255 | #define TQ_x_6 1, 1, 3, 1 256 | #define TQ_x_8 1, 2, 3, 2 257 | #define TQ_x_9 1, 2, 4, 2 258 | #define TQ_x_10 1, 3, 4, 2 259 | #define TQ_x_12 1, 3, 6, 2 260 | #define TQ_x_14 1, 4, 7, 2 261 | #define TQ_x_15 1, 4, 8, 2 /* good timing */ 262 | #define TQ_x_16 1, 5, 8, 2 /* good timing */ 263 | #define TQ_x_17 1, 6, 8, 2 /* good timing */ 264 | #define TQ_x_18 1, 7, 8, 2 /* good timing */ 265 | #define TQ_x_19 1, 8, 8, 2 /* good timing */ 266 | #define TQ_x_20 1, 8, 8, 3 /* good timing */ 267 | #define TQ_x_21 1, 8, 8, 4 268 | #define TQ_x_25 1, 8, 8, 8 269 | 270 | #define DTQ_x_40 5, 31, 8 271 | 272 | #define NTQ_x_80 16, 63, 16 // MCC (generated values +1) 273 | #define NTQ_x_100 40, 159, 40 // MCC (generated values +1) 274 | #define NTQ_x_160 32, 127, 32 // MCC (generated values +1) 275 | #define NTQ_x_200 20, 79, 20 // MCC (generated values +1) 276 | #define NTQ_x_320 64, 255, 64 // MCC (generated values +1) 277 | 278 | // Recommended FCAN : 20MHz, 40MHz, 80MHz 279 | #if CO_FCY == 80000 280 | #define CO_CANbitRateDataInitializers \ 281 | {1, 100, NTQ_x_80, 200, DTQ_x_40, 10}, /* TODO CAN=10kbps*/ \ 282 | {1, 50, NTQ_x_80, 100, DTQ_x_40, 20}, /* TODO CAN=20kbps*/ \ 283 | {1, 20, NTQ_x_80, 40, DTQ_x_40, 50}, /* TODO CAN=50kbps*/ \ 284 | {1, 10, NTQ_x_80, 20, DTQ_x_40, 100}, /* TODO CAN=100kbps*/ \ 285 | {1, 2, NTQ_x_320, 16, DTQ_x_40, 125}, /*CAN=125kbps*/ \ 286 | {1, 1, NTQ_x_320, 8, DTQ_x_40, 250}, /*CAN=250kbps*/ \ 287 | {1, 1, NTQ_x_160, 4, DTQ_x_40, 500}, /*CAN=500kbps*/ \ 288 | {1, 1, NTQ_x_80, 2, DTQ_x_40, 1000} /*CAN=1000kbps*/ 289 | #else 290 | #error define_CO_FCY CO_FCY not supported 291 | #endif 292 | #endif 293 | 294 | /* Structure contains timing coefficients for CAN module. 295 | * 296 | * CAN baud rate is calculated from following equations: 297 | * FCAN = FCY * Scale - Input frequency to CAN module (MAX 40MHz for dsPIC33F/PIC24H and 70MHz for dsPIC33E/PIC24E) 298 | * TQ = 2 * BRP / FCAN - Time Quanta 299 | * BaudRate = 1 / (TQ * K) - Can bus Baud Rate 300 | * K = SJW + PROP + PhSeg1 + PhSeg2 - Number of Time Quantas 301 | */ 302 | typedef struct { 303 | uint8_t scale; /* (1 or 2) Scales FCY clock - dsPIC33F and PIC24H specific */ // TODO CAN 304 | // Nominal bit rate (arbitration) 305 | uint8_t NBRP; /* (1...256) Baud Rate Prescaler */ 306 | uint8_t NSJW; /* (1...128) SJW time */ 307 | uint8_t NtSeg1; /* (1...256) Prop + Phase Segment 1 time */ 308 | uint8_t NtSeg2; /* (1...128) Phase Segment 2 time */ 309 | // Data bit rate (data and CRC) 310 | uint8_t DBRP; /* (1...256) Baud Rate Prescaler */ 311 | uint8_t DSJW; /* (1...16) SJW time */ 312 | uint8_t DtSeg1; /* (1...32) Prop + Phase Segment 1 time */ 313 | uint8_t DtSeg2; /* (1...16) Phase Segment 2 time */ 314 | uint16_t bitrate; /* bitrate in kbps */ 315 | } CO_CANbitRateData_t; 316 | 317 | #ifdef __cplusplus 318 | } 319 | #endif /* __cplusplus */ 320 | 321 | #endif /* CO_DRIVER_TARGET */ 322 | -------------------------------------------------------------------------------- /example_PIC32.X/CO_driver_custom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Custom definitions for CANopenNode. 3 | * 4 | * @file CO_driver_custom.h 5 | * @author -- 6 | * @copyright 2021 -- 7 | * 8 | * This file is part of CANopenNode, an opensource CANopen Stack. 9 | * Project home page is . 10 | * For more information on CANopen see . 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | #ifndef CO_DRIVER_CUSTOM_H 26 | #define CO_DRIVER_CUSTOM_H 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /* This file contains application specific custom definitions for CANopenNode. 33 | * It is included from CO_driver_target.h, so it may override any default 34 | * setting. See also file CO_config.h. */ 35 | 36 | 37 | /* Configure storage - override default setting, so eeprom on explorer16 board 38 | * works too. For CS signal use RG9 and RD12 ports. See CO_eepromPIC32.c. */ 39 | #define CO_STOR_SS 40 | #define CO_STOR_SS_INIT() {TRISGCLR = 0x0200; TRISDCLR = 0x1000;} 41 | #define CO_STOR_SS_LOW() {PORTGCLR = 0x0200; PORTDCLR = 0x1000;} 42 | #define CO_STOR_SS_HIGH() {PORTGSET = 0x0200; PORTDSET = 0x1000;} 43 | 44 | /* Override eeprom size in bytes, 0x8000 for 25LC256 */ 45 | //#define CO_STOR_EE_SIZE 0x8000 46 | 47 | /* If eeprom is not present, disable storage */ 48 | //#define CO_CONFIG_STORAGE (0) 49 | 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif /* __cplusplus */ 54 | 55 | #endif /* CO_DRIVER_CUSTOM_H */ 56 | -------------------------------------------------------------------------------- /example_PIC32.X/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # There exist several targets which are by default empty and which can be 3 | # used for execution of your targets. These targets are usually executed 4 | # before and after some main targets. They are: 5 | # 6 | # .build-pre: called before 'build' target 7 | # .build-post: called after 'build' target 8 | # .clean-pre: called before 'clean' target 9 | # .clean-post: called after 'clean' target 10 | # .clobber-pre: called before 'clobber' target 11 | # .clobber-post: called after 'clobber' target 12 | # .all-pre: called before 'all' target 13 | # .all-post: called after 'all' target 14 | # .help-pre: called before 'help' target 15 | # .help-post: called after 'help' target 16 | # 17 | # Targets beginning with '.' are not intended to be called on their own. 18 | # 19 | # Main targets can be executed directly, and they are: 20 | # 21 | # build build a specific configuration 22 | # clean remove built files from a configuration 23 | # clobber remove all built files 24 | # all build all configurations 25 | # help print help mesage 26 | # 27 | # Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and 28 | # .help-impl are implemented in nbproject/makefile-impl.mk. 29 | # 30 | # Available make variables: 31 | # 32 | # CND_BASEDIR base directory for relative paths 33 | # CND_DISTDIR default top distribution directory (build artifacts) 34 | # CND_BUILDDIR default top build directory (object files, ...) 35 | # CONF name of current configuration 36 | # CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration) 37 | # CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration) 38 | # CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration) 39 | # CND_PACKAGE_DIR_${CONF} directory of package (current configuration) 40 | # CND_PACKAGE_NAME_${CONF} name of package (current configuration) 41 | # CND_PACKAGE_PATH_${CONF} path to package (current configuration) 42 | # 43 | # NOCDDL 44 | 45 | 46 | # Environment 47 | MKDIR=mkdir 48 | CP=cp 49 | CCADMIN=CCadmin 50 | RANLIB=ranlib 51 | 52 | 53 | # build 54 | build: .build-post 55 | 56 | .build-pre: 57 | # Add your pre 'build' code here... 58 | 59 | .build-post: .build-impl 60 | # Add your post 'build' code here... 61 | 62 | 63 | # clean 64 | clean: .clean-post 65 | 66 | .clean-pre: 67 | # Add your pre 'clean' code here... 68 | # WARNING: the IDE does not call this target since it takes a long time to 69 | # simply run make. Instead, the IDE removes the configuration directories 70 | # under build and dist directly without calling make. 71 | # This target is left here so people can do a clean when running a clean 72 | # outside the IDE. 73 | 74 | .clean-post: .clean-impl 75 | # Add your post 'clean' code here... 76 | 77 | 78 | # clobber 79 | clobber: .clobber-post 80 | 81 | .clobber-pre: 82 | # Add your pre 'clobber' code here... 83 | 84 | .clobber-post: .clobber-impl 85 | # Add your post 'clobber' code here... 86 | 87 | 88 | # all 89 | all: .all-post 90 | 91 | .all-pre: 92 | # Add your pre 'all' code here... 93 | 94 | .all-post: .all-impl 95 | # Add your post 'all' code here... 96 | 97 | 98 | # help 99 | help: .help-post 100 | 101 | .help-pre: 102 | # Add your pre 'help' code here... 103 | 104 | .help-post: .help-impl 105 | # Add your post 'help' code here... 106 | 107 | 108 | 109 | # include project implementation makefile 110 | include nbproject/Makefile-impl.mk 111 | 112 | # include project make variables 113 | include nbproject/Makefile-variables.mk 114 | -------------------------------------------------------------------------------- /example_PIC32.X/appl_max32_demo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Application program for CANopen IO device on Max32 board with PIC32 3 | * 4 | * @file appl_max32_demo.c 5 | * @author -- 6 | * @copyright 2021 -- 7 | * 8 | * This file is part of CANopenNode, an opensource CANopen Stack. 9 | * Project home page is . 10 | * For more information on CANopen see . 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the "License"); 13 | * you may not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * http://www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an "AS IS" BASIS, 20 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | #include "CO_application.h" 26 | #include "OD.h" 27 | 28 | 29 | /* CANopen LED diodes, as present on Explorer 16 and Max32 boards. */ 30 | #define CAN_INIT_LEDS() TRISAbits.TRISA2 = TRISCbits.TRISC1 = TRISAbits.TRISA3=0 31 | #define CAN_RUN_LED LATAbits.LATA2 = LATCbits.LATC1 32 | #define CAN_ERROR_LED LATAbits.LATA3 33 | 34 | 35 | /******************************************************************************/ 36 | CO_ReturnError_t app_programStart(uint16_t *bitRate, 37 | uint8_t *nodeId, 38 | uint32_t *errInfo) 39 | { 40 | /* CANopen led diodes */ 41 | CAN_INIT_LEDS(); 42 | CAN_RUN_LED = 0; 43 | CAN_ERROR_LED = 1; 44 | 45 | /* Place for peripheral or any other startup configuration. See main_PIC32.c 46 | * for defaults. */ 47 | 48 | /* Set initial CAN bitRate and CANopen nodeId. May be configured by LSS. */ 49 | if (*bitRate == 0) *bitRate = 250; 50 | if (*nodeId == 0) *nodeId = 0x30; 51 | 52 | return CO_ERROR_NO; 53 | } 54 | 55 | 56 | /******************************************************************************/ 57 | void app_communicationReset(CO_t *co) { 58 | if (!co->nodeIdUnconfigured) { 59 | 60 | } 61 | } 62 | 63 | 64 | /******************************************************************************/ 65 | void app_programEnd() { 66 | CAN_RUN_LED = 0; CAN_ERROR_LED = 0; 67 | } 68 | 69 | 70 | /******************************************************************************/ 71 | void app_programAsync(CO_t *co, uint32_t timer1usDiff) { 72 | /* Here can be slower code, all must be non-blocking. Mind race conditions 73 | * between this functions and following three functions, which all run from 74 | * realtime timer interrupt */ 75 | } 76 | 77 | 78 | /******************************************************************************/ 79 | void app_programRt(CO_t *co, uint32_t timer1usDiff) { 80 | 81 | } 82 | 83 | 84 | /******************************************************************************/ 85 | void app_peripheralRead(CO_t *co, uint32_t timer1usDiff) { 86 | 87 | /* All analog inputs must be read or interrupt source for RT thread won't be 88 | * cleared. See analog input configuration in main_PIC32.c */ 89 | volatile uint32_t dummyRead; 90 | dummyRead = ADC1BUF0; 91 | dummyRead = ADC1BUF1; 92 | dummyRead = ADC1BUF2; 93 | dummyRead = ADC1BUF3; 94 | dummyRead = ADC1BUF4; 95 | dummyRead = ADC1BUF5; 96 | dummyRead = ADC1BUF6; 97 | dummyRead = ADC1BUF7; 98 | dummyRead = ADC1BUF8; 99 | dummyRead = ADC1BUF9; 100 | dummyRead = ADC1BUFA; 101 | dummyRead = ADC1BUFB; 102 | dummyRead = ADC1BUFC; 103 | dummyRead = ADC1BUFD; 104 | dummyRead = ADC1BUFE; 105 | dummyRead = ADC1BUFF; 106 | //OD_RAM.x6401_readAnalogInput_16_bit[0xF] = ADC1BUFF; 107 | 108 | /* Read digital inputs */ 109 | //uint8_t digIn = 0; 110 | //if(PORTDbits.RD6 != 0) digIn |= 0x08; 111 | //if(PORTDbits.RD7 != 0) digIn |= 0x04; 112 | //if(PORTDbits.RD13 != 0) digIn |= 0x01; 113 | //OD_RAM.x6000_readDigitalInput_8_bit[0] = digIn; 114 | } 115 | 116 | 117 | /******************************************************************************/ 118 | void app_peripheralWrite(CO_t *co, uint32_t timer1usDiff) { 119 | CAN_RUN_LED = CO_LED_GREEN(co->LEDs, CO_LED_CANopen); 120 | CAN_ERROR_LED = CO_LED_RED(co->LEDs, CO_LED_CANopen); 121 | 122 | /* Write to digital outputs */ 123 | //uint8_t digOut = OD_RAM.x6200_writeDigitalOutput_8_bit[0]; 124 | //LATAbits.LATA0 = (digOut & 0x01) ? 1 : 0; 125 | //LATAbits.LATA1 = (digOut & 0x02) ? 1 : 0; 126 | //LATAbits.LATA4 = (digOut & 0x10) ? 1 : 0; 127 | //LATAbits.LATA5 = (digOut & 0x20) ? 1 : 0; 128 | //LATAbits.LATA6 = (digOut & 0x40) ? 1 : 0; 129 | //LATAbits.LATA7 = (digOut & 0x80) ? 1 : 0; 130 | } 131 | -------------------------------------------------------------------------------- /example_PIC32.X/nbproject/configurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | ../CANopenNode/301/CO_config.h 10 | ../CANopenNode/301/CO_driver.h 11 | ../CANopenNode/301/CO_ODinterface.h 12 | ../CANopenNode/301/CO_NMT_Heartbeat.h 13 | ../CANopenNode/301/CO_HBconsumer.h 14 | ../CANopenNode/301/CO_Emergency.h 15 | ../CANopenNode/301/CO_SDOserver.h 16 | ../CANopenNode/301/CO_TIME.h 17 | ../CANopenNode/301/CO_SYNC.h 18 | ../CANopenNode/301/CO_PDO.h 19 | ../CANopenNode/301/crc16-ccitt.h 20 | 21 | 22 | ../CANopenNode/303/CO_LEDs.h 23 | 24 | 25 | ../CANopenNode/305/CO_LSS.h 26 | ../CANopenNode/305/CO_LSSslave.h 27 | 28 | 29 | ../CANopenNode/storage/CO_storage.h 30 | ../CANopenNode/storage/CO_eeprom.h 31 | ../CANopenNode/storage/CO_storageEeprom.h 32 | 33 | ../CANopenNode/CANopen.h 34 | 35 | 36 | ../PIC32/CO_driver_target.h 37 | ../PIC32/CO_application.h 38 | 39 | CO_driver_custom.h 40 | ../CANopenNode/example/OD.h 41 | 42 | 45 | Makefile 46 | 47 | 50 | 51 | 54 | 55 | 56 | ../CANopenNode/301/CO_ODinterface.c 57 | ../CANopenNode/301/CO_NMT_Heartbeat.c 58 | ../CANopenNode/301/CO_HBconsumer.c 59 | ../CANopenNode/301/CO_Emergency.c 60 | ../CANopenNode/301/CO_SDOserver.c 61 | ../CANopenNode/301/CO_TIME.c 62 | ../CANopenNode/301/CO_SYNC.c 63 | ../CANopenNode/301/CO_PDO.c 64 | ../CANopenNode/301/crc16-ccitt.c 65 | 66 | 67 | ../CANopenNode/303/CO_LEDs.c 68 | 69 | 70 | ../CANopenNode/305/CO_LSSslave.c 71 | 72 | 73 | ../CANopenNode/storage/CO_storage.c 74 | ../CANopenNode/storage/CO_storageEeprom.c 75 | 76 | ../CANopenNode/CANopen.c 77 | 78 | 79 | ../PIC32/CO_driver.c 80 | ../PIC32/CO_eepromPIC32.c 81 | ../PIC32/CO_main_PIC32.c 82 | 83 | appl_max32_demo.c 84 | ../CANopenNode/example/OD.c 85 | 86 | 87 | 88 | ../PIC32 89 | ../CANopenNode 90 | 91 | Makefile 92 | 93 | 94 | 95 | localhost 96 | PIC32MX795F512L 97 | 98 | 99 | pk4hybrid 100 | XC32 101 | 4.45 102 | 2 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | false 118 | false 119 | 120 | 121 | 122 | 123 | 124 | 125 | false 126 | false 127 | 128 | false 129 | 130 | false 131 | false 132 | false 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | -------------------------------------------------------------------------------- /example_PIC32.X/nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.microchip.mplab.nbide.embedded.makeproject 4 | 5 | 6 | example_PIC32 7 | 89118679-14f3-4046-8e56-c665e8a023dd 8 | 0 9 | c 10 | 11 | h 12 | 13 | UTF-8 14 | 15 | 16 | ../PIC32 17 | ../CANopenNode 18 | 19 | 20 | 21 | default 22 | 2 23 | 24 | 25 | 26 | false 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /example_dsPIC30F.X/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # There exist several targets which are by default empty and which can be 3 | # used for execution of your targets. These targets are usually executed 4 | # before and after some main targets. They are: 5 | # 6 | # .build-pre: called before 'build' target 7 | # .build-post: called after 'build' target 8 | # .clean-pre: called before 'clean' target 9 | # .clean-post: called after 'clean' target 10 | # .clobber-pre: called before 'clobber' target 11 | # .clobber-post: called after 'clobber' target 12 | # .all-pre: called before 'all' target 13 | # .all-post: called after 'all' target 14 | # .help-pre: called before 'help' target 15 | # .help-post: called after 'help' target 16 | # 17 | # Targets beginning with '.' are not intended to be called on their own. 18 | # 19 | # Main targets can be executed directly, and they are: 20 | # 21 | # build build a specific configuration 22 | # clean remove built files from a configuration 23 | # clobber remove all built files 24 | # all build all configurations 25 | # help print help mesage 26 | # 27 | # Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and 28 | # .help-impl are implemented in nbproject/makefile-impl.mk. 29 | # 30 | # Available make variables: 31 | # 32 | # CND_BASEDIR base directory for relative paths 33 | # CND_DISTDIR default top distribution directory (build artifacts) 34 | # CND_BUILDDIR default top build directory (object files, ...) 35 | # CONF name of current configuration 36 | # CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration) 37 | # CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration) 38 | # CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration) 39 | # CND_PACKAGE_DIR_${CONF} directory of package (current configuration) 40 | # CND_PACKAGE_NAME_${CONF} name of package (current configuration) 41 | # CND_PACKAGE_PATH_${CONF} path to package (current configuration) 42 | # 43 | # NOCDDL 44 | 45 | 46 | # Environment 47 | MKDIR=mkdir 48 | CP=cp 49 | CCADMIN=CCadmin 50 | RANLIB=ranlib 51 | 52 | 53 | # build 54 | build: .build-post 55 | 56 | .build-pre: 57 | # Add your pre 'build' code here... 58 | 59 | .build-post: .build-impl 60 | # Add your post 'build' code here... 61 | 62 | 63 | # clean 64 | clean: .clean-post 65 | 66 | .clean-pre: 67 | # Add your pre 'clean' code here... 68 | # WARNING: the IDE does not call this target since it takes a long time to 69 | # simply run make. Instead, the IDE removes the configuration directories 70 | # under build and dist directly without calling make. 71 | # This target is left here so people can do a clean when running a clean 72 | # outside the IDE. 73 | 74 | .clean-post: .clean-impl 75 | # Add your post 'clean' code here... 76 | 77 | 78 | # clobber 79 | clobber: .clobber-post 80 | 81 | .clobber-pre: 82 | # Add your pre 'clobber' code here... 83 | 84 | .clobber-post: .clobber-impl 85 | # Add your post 'clobber' code here... 86 | 87 | 88 | # all 89 | all: .all-post 90 | 91 | .all-pre: 92 | # Add your pre 'all' code here... 93 | 94 | .all-post: .all-impl 95 | # Add your post 'all' code here... 96 | 97 | 98 | # help 99 | help: .help-post 100 | 101 | .help-pre: 102 | # Add your pre 'help' code here... 103 | 104 | .help-post: .help-impl 105 | # Add your post 'help' code here... 106 | 107 | 108 | 109 | # include project implementation makefile 110 | include nbproject/Makefile-impl.mk 111 | 112 | # include project make variables 113 | include nbproject/Makefile-variables.mk 114 | -------------------------------------------------------------------------------- /example_dsPIC30F.X/main_dsPIC30F.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CANopen main program file for dsPIC30F microcontroller. 3 | * 4 | * Example code for using CANopenNode library on dsPIC30F4011 microcontroller. 5 | * 6 | * @file main_dsPIC30F.c 7 | * @author Janez Paternoster 8 | * @copyright 2010 - 2020 Janez Paternoster 9 | * 10 | * This file is part of CANopenNode, an opensource CANopen Stack. 11 | * Project home page is . 12 | * For more information on CANopen see . 13 | * 14 | * This file is part of CANopenNode, an opensource CANopen Stack. 15 | * Project home page is . 16 | * For more information on CANopen see . 17 | * 18 | * Licensed under the Apache License, Version 2.0 (the "License"); 19 | * you may not use this file except in compliance with the License. 20 | * You may obtain a copy of the License at 21 | * 22 | * http://www.apache.org/licenses/LICENSE-2.0 23 | * 24 | * Unless required by applicable law or agreed to in writing, software 25 | * distributed under the License is distributed on an "AS IS" BASIS, 26 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27 | * See the License for the specific language governing permissions and 28 | * limitations under the License. 29 | */ 30 | 31 | 32 | /** 33 | * This file is tested on dsPIC30F4011 microcontroller with two led diodes and 34 | * 8 MHz quartz. Device sends bootup message. NodeID is 0x30. 35 | */ 36 | 37 | #define CO_FCY 16000 /* (8MHz Quartz used) */ 38 | 39 | 40 | #include "CANopen.h" 41 | #include "OD.h" 42 | /* (not implemented) #include "eeprom.h" */ 43 | 44 | /* Configuration bits */ 45 | #pragma config FPR = XT_PLL8 // Primary Oscillator Mode (XT w/PLL 8x) 46 | #pragma config FOS = PRI // Oscillator Source (Primary Oscillator) 47 | #pragma config FCKSMEN = CSW_FSCM_ON // Clock Switching and Monitor (Sw Enabled, Mon Enabled) 48 | 49 | 50 | /* macros */ 51 | #define CO_TIMER_ISR() void __attribute__((interrupt, auto_psv)) _T2Interrupt (void) 52 | #define CO_TMR_TMR TMR2 /* TMR register */ 53 | #define CO_TMR_PR PR2 /* Period register */ 54 | #define CO_TMR_CON T2CON /* Control register */ 55 | #define CO_TMR_ISR_FLAG IFS0bits.T2IF /* Interrupt Flag bit */ 56 | #define CO_TMR_ISR_PRIORITY IPC1bits.T2IP /* Interrupt Priority */ 57 | #define CO_TMR_ISR_ENABLE IEC0bits.T2IE /* Interrupt Enable bit */ 58 | 59 | #define CO_RT_THREAD_INTERVAL_US 1000 /* Interval of the realtime thread */ 60 | 61 | #define CO_CAN_ISR() void __attribute__((interrupt, auto_psv)) _C1Interrupt (void) 62 | #define CO_CAN_ISR_FLAG IFS1bits.C1IF /* Interrupt Flag bit */ 63 | #define CO_CAN_ISR_PRIORITY IPC6bits.C1IP /* Interrupt Priority */ 64 | #define CO_CAN_ISR_ENABLE IEC1bits.C1IE /* Interrupt Enable bit */ 65 | 66 | 67 | /* default values for CO_CANopenInit() */ 68 | #define NMT_CONTROL (CO_NMT_STARTUP_TO_OPERATIONAL | CO_NMT_ERR_ON_ERR_REG | CO_ERR_REG_GENERIC_ERR | CO_ERR_REG_COMMUNICATION) 69 | #define FIRST_HB_TIME 500 70 | #define SDO_SRV_TIMEOUT_TIME 1000 71 | #define SDO_CLI_TIMEOUT_TIME 500 72 | #define SDO_CLI_BLOCK false 73 | #define OD_STATUS_BITS NULL 74 | 75 | /* Global variables and objects */ 76 | CO_t* CO = NULL; /* CANopen object */ 77 | volatile uint32_t CO_timer_us = 0U; /* Timer for time measurement in microseconds */ 78 | const CO_CANbitRateData_t CO_CANbitRateData[8] = {CO_CANbitRateDataInitializers}; 79 | /* (not implemented) eeprom_t eeprom; */ 80 | 81 | 82 | #if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 83 | /* callback for checking bitrate */ 84 | static bool_t LSSchkBitrateCallback(void *object, uint16_t bitRate) { 85 | (void)object; 86 | int i; 87 | 88 | for (i=0; i<(sizeof(CO_CANbitRateData)/sizeof(CO_CANbitRateData[0])); i++) { 89 | if (CO_CANbitRateData[i].bitrate == bitRate) { 90 | return true; 91 | } 92 | } 93 | return false; 94 | } 95 | #endif 96 | 97 | /* main ***********************************************************************/ 98 | int main (void){ 99 | CO_ReturnError_t err; 100 | CO_NMT_reset_cmd_t reset = CO_RESET_NOT; 101 | bool_t firstRun = true; 102 | uint8_t pendingNodeId = 10; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ 103 | uint8_t activeNodeId = 10; /* Copied from CO_pendingNodeId in the communication reset section */ 104 | uint16_t pendingBitRate = 250; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ 105 | uint32_t heapMemoryUsed; 106 | 107 | /* Initialize two CAN led diodes */ 108 | TRISFbits.TRISF4 = 0; LATFbits.LATF4 = 0; 109 | TRISFbits.TRISF5 = 0; LATFbits.LATF5 = 1; 110 | #define CAN_RUN_LED LATFbits.LATF4 111 | #define CAN_ERROR_LED LATFbits.LATF5 112 | 113 | 114 | /* Allocate memory */ 115 | CO = CO_new(NULL, &heapMemoryUsed); 116 | if (CO == NULL) { 117 | while (1) ClrWdt(); 118 | } 119 | 120 | 121 | /* initialize EEPROM */ 122 | /* (not implemented) */ 123 | 124 | 125 | while(reset != CO_RESET_APP){ 126 | /* CANopen communication reset - initialize CANopen objects *******************/ 127 | uint32_t errInfo; 128 | static uint32_t CO_timer_us_previous = 0; 129 | 130 | /* disable CAN and CAN interrupts, turn on red LED */ 131 | CO_CAN_ISR_ENABLE = 0; 132 | CAN_RUN_LED = 0; 133 | CAN_ERROR_LED = 1; 134 | 135 | /* initialize CANopen */ 136 | err = CO_CANinit(CO, (void *)ADDR_CAN1, pendingBitRate); 137 | if (err != CO_ERROR_NO) { 138 | while (1) ClrWdt(); 139 | } 140 | 141 | #if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 142 | CO_LSS_address_t lssAddress = {.identity = { 143 | .vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, 144 | .productCode = OD_PERSIST_COMM.x1018_identity.productCode, 145 | .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, 146 | .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber 147 | }}; 148 | err = CO_LSSinit(CO, &lssAddress, &pendingNodeId, &pendingBitRate); 149 | if (err != CO_ERROR_NO) { 150 | while (1) ClrWdt(); 151 | } 152 | #endif 153 | 154 | activeNodeId = pendingNodeId; 155 | 156 | errInfo = 0; 157 | err = CO_CANopenInit(CO, /* CANopen object */ 158 | NULL, /* alternate NMT */ 159 | NULL, /* alternate em */ 160 | OD, /* Object dictionary */ 161 | OD_STATUS_BITS, /* Optional OD_statusBits */ 162 | NMT_CONTROL, /* CO_NMT_control_t */ 163 | FIRST_HB_TIME, /* firstHBTime_ms */ 164 | SDO_SRV_TIMEOUT_TIME, /* SDOserverTimeoutTime_ms */ 165 | SDO_CLI_TIMEOUT_TIME, /* SDOclientTimeoutTime_ms */ 166 | SDO_CLI_BLOCK, /* SDOclientBlockTransfer */ 167 | activeNodeId, 168 | &errInfo); 169 | if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { 170 | while (1) ClrWdt(); 171 | } 172 | 173 | /* Emergency messages in case of errors */ 174 | if (!CO->nodeIdUnconfigured && errInfo != 0) { 175 | CO_errorReport(CO->em, CO_EM_INCONSISTENT_OBJECT_DICT, CO_EMC_DATA_SET, errInfo); 176 | } 177 | 178 | /* First time only initialization. */ 179 | if (firstRun) { 180 | firstRun = false; 181 | CO_timer_us_previous = CO_timer_us; 182 | } /* if(firstRun) */ 183 | 184 | /* initialize callbacks */ 185 | #if ((CO_CONFIG_LSS)&CO_CONFIG_LSS_SLAVE) != 0 186 | CO_LSSslave_initCkBitRateCall(CO->LSSslave, NULL, LSSchkBitrateCallback); 187 | #endif 188 | 189 | /* init PDO */ 190 | errInfo = 0; 191 | err = CO_CANopenInitPDO(CO, /* CANopen object */ 192 | CO->em, /* emergency object */ 193 | OD, /* Object dictionary */ 194 | activeNodeId, 195 | &errInfo); 196 | if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { 197 | while (1) ClrWdt(); 198 | } 199 | 200 | /* start CAN */ 201 | CO_CANsetNormalMode(CO->CANmodule); 202 | 203 | 204 | /* Configure Timer interrupt function for execution every 1 millisecond */ 205 | CO_TMR_CON = 0; 206 | CO_TMR_TMR = 0; 207 | CO_TMR_PR = CO_FCY - 1; /* Period register */ 208 | CO_TMR_CON = 0x8000; /* start timer (TON=1) */ 209 | CO_TMR_ISR_FLAG = 0; /* clear interrupt flag */ 210 | CO_TMR_ISR_PRIORITY = 3; /* interrupt - set lower priority than CAN */ 211 | CO_TMR_ISR_ENABLE = 1; /* enable interrupt */ 212 | /* Configure CAN1 Interrupt (Combined) */ 213 | CO_CAN_ISR_FLAG = 0; /* CAN1 Interrupt - Clear flag */ 214 | CO_CAN_ISR_PRIORITY = 5; /* CAN1 Interrupt - Set higher priority than timer */ 215 | CO_CAN_ISR_ENABLE = 1; /* CAN1 Interrupt - Enable interrupt */ 216 | 217 | reset = CO_RESET_NOT; 218 | 219 | while(reset == CO_RESET_NOT){ 220 | /* loop for normal program execution ******************************************/ 221 | 222 | /* calculate time difference since last cycle */ 223 | uint32_t timer_us_copy = CO_timer_us; 224 | uint32_t timeDifference_us = timer_us_copy - CO_timer_us_previous; 225 | CO_timer_us_previous = timer_us_copy; 226 | 227 | ClrWdt(); 228 | 229 | /* CANopen process */ 230 | reset = CO_process(CO, false, timeDifference_us, NULL); 231 | 232 | CAN_RUN_LED = CO_LED_GREEN(CO->LEDs, CO_LED_CANopen); 233 | CAN_ERROR_LED = CO_LED_RED(CO->LEDs, CO_LED_CANopen); 234 | 235 | ClrWdt(); 236 | 237 | /* (not implemented) eeprom_process(&eeprom); */ 238 | } 239 | } 240 | /* program exit ***************************************************************/ 241 | /* save variables to eeprom */ 242 | RESTORE_CPU_IPL(7); /* disable interrupts */ 243 | CAN_RUN_LED = 0; 244 | /* CAN_ERROR_LED = 0; */ 245 | /* (not implemented) eeprom_saveAll(&eeprom); */ 246 | CAN_ERROR_LED = 1; 247 | 248 | /* delete CANopen object from memory */ 249 | CO_delete(ADDR_CAN1); 250 | 251 | /* reset */ 252 | return 0; 253 | } 254 | 255 | 256 | /* timer interrupt function executes every millisecond ************************/ 257 | CO_TIMER_ISR(){ 258 | 259 | /* clear interrupt flag bit */ 260 | CO_TMR_ISR_FLAG = 0; 261 | 262 | CO_timer_us += CO_RT_THREAD_INTERVAL_US; 263 | 264 | if (!CO->nodeIdUnconfigured && CO->CANmodule->CANnormal) { 265 | bool_t syncWas; 266 | 267 | #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE 268 | syncWas = CO_process_SYNC(CO, CO_RT_THREAD_INTERVAL_US, NULL); 269 | #endif 270 | #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE 271 | CO_process_RPDO(CO, syncWas, CO_RT_THREAD_INTERVAL_US, NULL); 272 | #endif 273 | 274 | /* Further I/O or nonblocking application code may go here. */ 275 | 276 | #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE 277 | CO_process_TPDO(CO, syncWas, CO_RT_THREAD_INTERVAL_US, NULL); 278 | #endif 279 | 280 | /* verify timer overflow */ 281 | if(CO_TMR_ISR_FLAG == 1){ 282 | CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0); 283 | CO_TMR_ISR_FLAG = 0; 284 | } 285 | } 286 | } 287 | 288 | 289 | /* CAN interrupt function *****************************************************/ 290 | void CO_CANinterrupt(CO_CANmodule_t *CANmodule); 291 | CO_CAN_ISR(){ 292 | CO_CANinterrupt(CO->CANmodule); 293 | 294 | /* Clear combined Interrupt flag */ 295 | CO_CAN_ISR_FLAG = 0; 296 | } 297 | -------------------------------------------------------------------------------- /example_dsPIC30F.X/nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.microchip.mplab.nbide.embedded.makeproject 4 | 5 | 6 | example_dsPIC30F 7 | 3ebdea85-22c3-45c8-adf7-9055cc70614d 8 | 0 9 | c 10 | 11 | h 12 | 13 | UTF-8 14 | 15 | 16 | ../dsPIC30F 17 | ../CANopenNode 18 | 19 | 20 | 21 | default 22 | 2 23 | 24 | 25 | 26 | false 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /example_dsPIC33_ex16_IO.X/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # There exist several targets which are by default empty and which can be 3 | # used for execution of your targets. These targets are usually executed 4 | # before and after some main targets. They are: 5 | # 6 | # .build-pre: called before 'build' target 7 | # .build-post: called after 'build' target 8 | # .clean-pre: called before 'clean' target 9 | # .clean-post: called after 'clean' target 10 | # .clobber-pre: called before 'clobber' target 11 | # .clobber-post: called after 'clobber' target 12 | # .all-pre: called before 'all' target 13 | # .all-post: called after 'all' target 14 | # .help-pre: called before 'help' target 15 | # .help-post: called after 'help' target 16 | # 17 | # Targets beginning with '.' are not intended to be called on their own. 18 | # 19 | # Main targets can be executed directly, and they are: 20 | # 21 | # build build a specific configuration 22 | # clean remove built files from a configuration 23 | # clobber remove all built files 24 | # all build all configurations 25 | # help print help mesage 26 | # 27 | # Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and 28 | # .help-impl are implemented in nbproject/makefile-impl.mk. 29 | # 30 | # Available make variables: 31 | # 32 | # CND_BASEDIR base directory for relative paths 33 | # CND_DISTDIR default top distribution directory (build artifacts) 34 | # CND_BUILDDIR default top build directory (object files, ...) 35 | # CONF name of current configuration 36 | # CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration) 37 | # CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration) 38 | # CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration) 39 | # CND_PACKAGE_DIR_${CONF} directory of package (current configuration) 40 | # CND_PACKAGE_NAME_${CONF} name of package (current configuration) 41 | # CND_PACKAGE_PATH_${CONF} path to package (current configuration) 42 | # 43 | # NOCDDL 44 | 45 | 46 | # Environment 47 | MKDIR=mkdir 48 | CP=cp 49 | CCADMIN=CCadmin 50 | RANLIB=ranlib 51 | 52 | 53 | # build 54 | build: .build-post 55 | 56 | .build-pre: 57 | # Add your pre 'build' code here... 58 | 59 | .build-post: .build-impl 60 | # Add your post 'build' code here... 61 | 62 | 63 | # clean 64 | clean: .clean-post 65 | 66 | .clean-pre: 67 | # Add your pre 'clean' code here... 68 | # WARNING: the IDE does not call this target since it takes a long time to 69 | # simply run make. Instead, the IDE removes the configuration directories 70 | # under build and dist directly without calling make. 71 | # This target is left here so people can do a clean when running a clean 72 | # outside the IDE. 73 | 74 | .clean-post: .clean-impl 75 | # Add your post 'clean' code here... 76 | 77 | 78 | # clobber 79 | clobber: .clobber-post 80 | 81 | .clobber-pre: 82 | # Add your pre 'clobber' code here... 83 | 84 | .clobber-post: .clobber-impl 85 | # Add your post 'clobber' code here... 86 | 87 | 88 | # all 89 | all: .all-post 90 | 91 | .all-pre: 92 | # Add your pre 'all' code here... 93 | 94 | .all-post: .all-impl 95 | # Add your post 'all' code here... 96 | 97 | 98 | # help 99 | help: .help-post 100 | 101 | .help-pre: 102 | # Add your pre 'help' code here... 103 | 104 | .help-post: .help-impl 105 | # Add your post 'help' code here... 106 | 107 | 108 | 109 | # include project implementation makefile 110 | include nbproject/Makefile-impl.mk 111 | 112 | # include project make variables 113 | include nbproject/Makefile-variables.mk 114 | -------------------------------------------------------------------------------- /example_dsPIC33_ex16_IO.X/main_dsPIC33F.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CANopen main program file for dsPIC33F microcontroller. 3 | * 4 | * Example code for using CANopenNode library Explorer16 board and 5 | * dsPIC33FJ256GP710 microcontroller. 6 | * 7 | * @file main_dsPIC33F.c 8 | * @author Janez Paternoster 9 | * @copyright 2010 - 2020 Janez Paternoster 10 | * 11 | * This file is part of CANopenNode, an opensource CANopen Stack. 12 | * Project home page is . 13 | * For more information on CANopen see . 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 | * Licensed under the Apache License, Version 2.0 (the "License"); 20 | * you may not use this file except in compliance with the License. 21 | * You may obtain a copy of the License at 22 | * 23 | * http://www.apache.org/licenses/LICENSE-2.0 24 | * 25 | * Unless required by applicable law or agreed to in writing, software 26 | * distributed under the License is distributed on an "AS IS" BASIS, 27 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | * See the License for the specific language governing permissions and 29 | * limitations under the License. 30 | */ 31 | 32 | 33 | /** 34 | * This file is tested on explorer16 board from Microchip. Microcontroller is 35 | * dsPIC33FJ256GP710. D3 and D4 LEDs are used as CANopen status LEDs (D4 should 36 | * be red). Device sends bootup and Heartbeat message. Default NodeID is 0x30. 37 | * Implemented is simple CANopen I/O device profile (DS401): 38 | * - TPDO with address 0x1B0 is send, if any button (S3, S6, S4) is pressed. 39 | * - LED diodes (D5...D10) are controlled by two bytes long RPDO on 40 | * CAN address 0x230 (upper six bits from first byte is used to control LEDs). 41 | */ 42 | 43 | #define CO_FCY 24000 /* (8MHz Quartz used) */ 44 | 45 | 46 | #include "CANopen.h" 47 | #include "OD.h" 48 | /* (not implemented) #include "eeprom.h" */ 49 | 50 | /* Configuration bits */ 51 | #pragma config FNOSC = PRIPLL /* Primary Oscillator (XT, HS, EC) w/ PLL */ 52 | #pragma config FCKSM = CSDCMD /* Both Clock Switching and Fail-Safe Clock Monitor are disabled */ 53 | #pragma config OSCIOFNC = OFF /* OSC2 pin has clock out function */ 54 | #pragma config POSCMD = XT /* XT Oscillator Mode */ 55 | 56 | 57 | /* macros */ 58 | #define CO_TIMER_ISR() void __attribute__((interrupt, auto_psv)) _T2Interrupt (void) 59 | #define CO_TMR_TMR TMR2 /* TMR register */ 60 | #define CO_TMR_PR PR2 /* Period register */ 61 | #define CO_TMR_CON T2CON /* Control register */ 62 | #define CO_TMR_ISR_FLAG IFS0bits.T2IF /* Interrupt Flag bit */ 63 | #define CO_TMR_ISR_PRIORITY IPC1bits.T2IP /* Interrupt Priority */ 64 | #define CO_TMR_ISR_ENABLE IEC0bits.T2IE /* Interrupt Enable bit */ 65 | 66 | #define CO_RT_THREAD_INTERVAL_US 1000 /* Interval of the realtime thread */ 67 | 68 | #define CO_CAN_ISR() void __attribute__((interrupt, auto_psv)) _C1Interrupt (void) 69 | #define CO_CAN_ISR_FLAG IFS2bits.C1IF /* Interrupt Flag bit */ 70 | #define CO_CAN_ISR_PRIORITY IPC8bits.C1IP /* Interrupt Priority */ 71 | #define CO_CAN_ISR_ENABLE IEC2bits.C1IE /* Interrupt Enable bit */ 72 | 73 | 74 | /* default values for CO_CANopenInit() */ 75 | #define NMT_CONTROL (CO_NMT_STARTUP_TO_OPERATIONAL | CO_NMT_ERR_ON_ERR_REG | CO_ERR_REG_GENERIC_ERR | CO_ERR_REG_COMMUNICATION) 76 | #define FIRST_HB_TIME 500 77 | #define SDO_SRV_TIMEOUT_TIME 1000 78 | #define SDO_CLI_TIMEOUT_TIME 500 79 | #define SDO_CLI_BLOCK false 80 | #define OD_STATUS_BITS NULL 81 | 82 | /* Global variables and objects */ 83 | CO_t* CO = NULL; /* CANopen object */ 84 | volatile uint32_t CO_timer_us = 0U; /* Timer for time measurement in microseconds */ 85 | const CO_CANbitRateData_t CO_CANbitRateData[8] = {CO_CANbitRateDataInitializers}; 86 | /* (not implemented) eeprom_t eeprom; */ 87 | 88 | 89 | /* callback for checking bitrate */ 90 | static bool_t LSSchkBitrateCallback(void *object, uint16_t bitRate) { 91 | (void)object; 92 | int i; 93 | 94 | for (i=0; i<(sizeof(CO_CANbitRateData)/sizeof(CO_CANbitRateData[0])); i++) { 95 | if (CO_CANbitRateData[i].bitrate == bitRate) { 96 | return true; 97 | } 98 | } 99 | return false; 100 | } 101 | 102 | /* main ***********************************************************************/ 103 | int main (void){ 104 | CO_ReturnError_t err; 105 | CO_NMT_reset_cmd_t reset = CO_RESET_NOT; 106 | bool_t firstRun = true; 107 | uint8_t pendingNodeId = 10; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ 108 | uint8_t activeNodeId = 10; /* Copied from CO_pendingNodeId in the communication reset section */ 109 | uint16_t pendingBitRate = 250; /* read from dip switches or nonvolatile memory, configurable by LSS slave */ 110 | uint32_t heapMemoryUsed; 111 | 112 | /* Initialize two CAN led diodes */ 113 | TRISAbits.TRISA0 = 0; LATAbits.LATA0 = 0; 114 | TRISAbits.TRISA1 = 0; LATAbits.LATA1 = 1; 115 | #define CAN_RUN_LED LATAbits.LATA0 116 | #define CAN_ERROR_LED LATAbits.LATA1 117 | 118 | 119 | /* Configure Oscillator */ 120 | /* Fosc = Fin*M/(N1*N2), Fcy=Fosc/2 */ 121 | /* Fosc = 8M*24/(2*2) = 48MHz -> Fcy = 24MHz */ 122 | PLLFBD=22; /* M=24 */ 123 | CLKDIVbits.PLLPOST=0; /* N1=2 */ 124 | CLKDIVbits.PLLPRE=0; /* N2=2 */ 125 | OSCTUN=0; /* Tune FRC oscillator, if FRC is used */ 126 | while(OSCCONbits.LOCK!=1) ClrWdt(); /* wait for PLL to lock */ 127 | 128 | 129 | /* Allocate memory */ 130 | CO = CO_new(NULL, &heapMemoryUsed); 131 | if (CO == NULL) { 132 | while (1) ClrWdt(); 133 | } 134 | 135 | 136 | /* initialize EEPROM */ 137 | /* (not implemented) */ 138 | 139 | 140 | while(reset != CO_RESET_APP){ 141 | /* CANopen communication reset - initialize CANopen objects *******************/ 142 | uint32_t errInfo; 143 | static uint32_t CO_timer_us_previous = 0; 144 | 145 | /* disable CAN and CAN interrupts, turn on red LED */ 146 | CO_CAN_ISR_ENABLE = 0; 147 | CAN_RUN_LED = 0; 148 | CAN_ERROR_LED = 1; 149 | 150 | /* initialize CANopen */ 151 | err = CO_CANinit(CO, (void *)ADDR_CAN1, pendingBitRate); 152 | if (err != CO_ERROR_NO) { 153 | while (1) ClrWdt(); 154 | } 155 | 156 | CO_LSS_address_t lssAddress = {.identity = { 157 | .vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID, 158 | .productCode = OD_PERSIST_COMM.x1018_identity.productCode, 159 | .revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber, 160 | .serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber 161 | }}; 162 | err = CO_LSSinit(CO, &lssAddress, &pendingNodeId, &pendingBitRate); 163 | if (err != CO_ERROR_NO) { 164 | while (1) ClrWdt(); 165 | } 166 | 167 | activeNodeId = pendingNodeId; 168 | 169 | errInfo = 0; 170 | err = CO_CANopenInit(CO, /* CANopen object */ 171 | NULL, /* alternate NMT */ 172 | NULL, /* alternate em */ 173 | OD, /* Object dictionary */ 174 | OD_STATUS_BITS, /* Optional OD_statusBits */ 175 | NMT_CONTROL, /* CO_NMT_control_t */ 176 | FIRST_HB_TIME, /* firstHBTime_ms */ 177 | SDO_SRV_TIMEOUT_TIME, /* SDOserverTimeoutTime_ms */ 178 | SDO_CLI_TIMEOUT_TIME, /* SDOclientTimeoutTime_ms */ 179 | SDO_CLI_BLOCK, /* SDOclientBlockTransfer */ 180 | activeNodeId, 181 | &errInfo); 182 | if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { 183 | while (1) ClrWdt(); 184 | } 185 | 186 | /* Emergency messages in case of errors */ 187 | if (!CO->nodeIdUnconfigured && errInfo != 0) { 188 | CO_errorReport(CO->em, CO_EM_INCONSISTENT_OBJECT_DICT, CO_EMC_DATA_SET, errInfo); 189 | } 190 | 191 | /* First time only initialization. */ 192 | if (firstRun) { 193 | firstRun = false; 194 | CO_timer_us_previous = CO_timer_us; 195 | } /* if(firstRun) */ 196 | 197 | /* initialize callbacks */ 198 | CO_LSSslave_initCkBitRateCall(CO->LSSslave, NULL, LSSchkBitrateCallback); 199 | 200 | /* init PDO */ 201 | errInfo = 0; 202 | err = CO_CANopenInitPDO(CO, /* CANopen object */ 203 | CO->em, /* emergency object */ 204 | OD, /* Object dictionary */ 205 | activeNodeId, 206 | &errInfo); 207 | if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) { 208 | while (1) ClrWdt(); 209 | } 210 | 211 | /* start CAN */ 212 | CO_CANsetNormalMode(CO->CANmodule); 213 | 214 | 215 | /* Configure Timer interrupt function for execution every 1 millisecond */ 216 | CO_TMR_CON = 0; 217 | CO_TMR_TMR = 0; 218 | CO_TMR_PR = CO_FCY - 1; /* Period register */ 219 | CO_TMR_CON = 0x8000; /* start timer (TON=1) */ 220 | CO_TMR_ISR_FLAG = 0; /* clear interrupt flag */ 221 | CO_TMR_ISR_PRIORITY = 3; /* interrupt - set lower priority than CAN */ 222 | CO_TMR_ISR_ENABLE = 1; /* enable interrupt */ 223 | /* Configure CAN1 Interrupt (Combined) */ 224 | CO_CAN_ISR_FLAG = 0; /* CAN1 Interrupt - Clear flag */ 225 | CO_CAN_ISR_PRIORITY = 5; /* CAN1 Interrupt - Set higher priority than timer */ 226 | CO_CAN_ISR_ENABLE = 1; /* CAN1 Interrupt - Enable interrupt */ 227 | 228 | reset = CO_RESET_NOT; 229 | 230 | while(reset == CO_RESET_NOT){ 231 | /* loop for normal program execution ******************************************/ 232 | 233 | /* calculate time difference since last cycle */ 234 | uint32_t timer_us_copy = CO_timer_us; 235 | uint32_t timeDifference_us = timer_us_copy - CO_timer_us_previous; 236 | CO_timer_us_previous = timer_us_copy; 237 | 238 | ClrWdt(); 239 | 240 | /* CANopen process */ 241 | reset = CO_process(CO, false, timeDifference_us, NULL); 242 | 243 | CAN_RUN_LED = CO_LED_GREEN(CO->LEDs, CO_LED_CANopen); 244 | CAN_ERROR_LED = CO_LED_RED(CO->LEDs, CO_LED_CANopen); 245 | 246 | ClrWdt(); 247 | 248 | /* (not implemented) eeprom_process(&eeprom); */ 249 | } 250 | } 251 | /* program exit ***************************************************************/ 252 | /* save variables to eeprom */ 253 | RESTORE_CPU_IPL(7); /* disable interrupts */ 254 | CAN_RUN_LED = 0; 255 | /* CAN_ERROR_LED = 0; */ 256 | /* (not implemented) eeprom_saveAll(&eeprom); */ 257 | CAN_ERROR_LED = 1; 258 | 259 | /* delete CANopen object from memory */ 260 | CO_delete(ADDR_CAN1); 261 | 262 | /* reset */ 263 | return 0; 264 | } 265 | 266 | 267 | /* timer interrupt function executes every millisecond ************************/ 268 | CO_TIMER_ISR(){ 269 | 270 | /* clear interrupt flag bit */ 271 | CO_TMR_ISR_FLAG = 0; 272 | 273 | CO_timer_us += CO_RT_THREAD_INTERVAL_US; 274 | 275 | if (!CO->nodeIdUnconfigured && CO->CANmodule->CANnormal) { 276 | bool_t syncWas; 277 | 278 | #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE 279 | syncWas = CO_process_SYNC(CO, CO_RT_THREAD_INTERVAL_US, NULL); 280 | #endif 281 | #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE 282 | CO_process_RPDO(CO, syncWas, CO_RT_THREAD_INTERVAL_US, NULL); 283 | #endif 284 | 285 | /* Further I/O or nonblocking application code may go here. */ 286 | 287 | #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE 288 | CO_process_TPDO(CO, syncWas, CO_RT_THREAD_INTERVAL_US, NULL); 289 | #endif 290 | 291 | /* verify timer overflow */ 292 | if(CO_TMR_ISR_FLAG == 1){ 293 | CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0); 294 | CO_TMR_ISR_FLAG = 0; 295 | } 296 | } 297 | } 298 | 299 | 300 | /* CAN interrupt function *****************************************************/ 301 | void CO_CANinterrupt(CO_CANmodule_t *CANmodule); 302 | CO_CAN_ISR(){ 303 | CO_CANinterrupt(CO->CANmodule); 304 | 305 | /* Clear combined Interrupt flag */ 306 | CO_CAN_ISR_FLAG = 0; 307 | } 308 | -------------------------------------------------------------------------------- /example_dsPIC33_ex16_IO.X/nbproject/configurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | ../CANopenNode/301/CO_Emergency.h 9 | ../CANopenNode/301/CO_HBconsumer.h 10 | ../CANopenNode/301/CO_NMT_Heartbeat.h 11 | ../CANopenNode/301/CO_PDO.h 12 | ../CANopenNode/301/CO_SDOserver.h 13 | ../CANopenNode/301/CO_SYNC.h 14 | ../CANopenNode/301/CO_TIME.h 15 | ../CANopenNode/301/CO_driver.h 16 | ../CANopenNode/301/crc16-ccitt.h 17 | ../CANopenNode/301/CO_config.h 18 | ../CANopenNode/301/CO_ODinterface.h 19 | 20 | 21 | ../CANopenNode/303/CO_LEDs.h 22 | 23 | 24 | ../CANopenNode/305/CO_LSS.h 25 | ../CANopenNode/305/CO_LSSslave.h 26 | 27 | 28 | ../PIC24_dsPIC33/CO_driver_target.h 29 | 30 | ../CANopenNode/CANopen.h 31 | ../CANopenNode/example/OD.h 32 | 33 | 36 | Makefile 37 | 38 | 41 | 42 | 45 | 46 | ../CANopenNode/301/CO_Emergency.c 47 | ../CANopenNode/301/CO_HBconsumer.c 48 | ../CANopenNode/301/CO_NMT_Heartbeat.c 49 | ../CANopenNode/301/CO_PDO.c 50 | ../CANopenNode/301/CO_SDOserver.c 51 | ../CANopenNode/301/CO_SYNC.c 52 | ../CANopenNode/301/CO_TIME.c 53 | ../CANopenNode/301/CO_ODinterface.c 54 | 55 | 56 | ../CANopenNode/303/CO_LEDs.c 57 | 58 | 59 | ../CANopenNode/305/CO_LSSslave.c 60 | 61 | 62 | ../PIC24_dsPIC33/CO_driver.c 63 | 64 | ../CANopenNode/CANopen.c 65 | main_dsPIC33F.c 66 | ../CANopenNode/example/OD.c 67 | 68 | 69 | 70 | ../PIC24_dsPIC33 71 | ../CANopenNode 72 | 73 | Makefile 74 | 75 | 76 | 77 | localhost 78 | dsPIC33FJ256GP710 79 | 80 | 81 | noID 82 | XC16 83 | 2.10 84 | 2 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | false 100 | false 101 | 102 | 103 | 104 | 105 | 106 | 107 | false 108 | false 109 | 110 | false 111 | 112 | false 113 | false 114 | false 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | -------------------------------------------------------------------------------- /example_dsPIC33_ex16_IO.X/nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.microchip.mplab.nbide.embedded.makeproject 4 | 5 | 6 | example_dsPIC33_ex16_IO 7 | 07c035b6-7533-4cf6-b35d-40dd0d5f4290 8 | 0 9 | c 10 | 11 | h 12 | 13 | UTF-8 14 | 15 | 16 | ../PIC24_dsPIC33 17 | ../CANopenNode 18 | 19 | 20 | 21 | default 22 | 2 23 | 24 | 25 | 26 | false 27 | 28 | 29 | 30 | 31 | --------------------------------------------------------------------------------