├── .gitmodules
├── .gitignore
├── .github
└── FUNDING.yml
├── example_PIC32.X
├── nbproject
│ ├── project.xml
│ └── configurations.xml
├── CO_driver_custom.h
├── Makefile
└── appl_max32_demo.c
├── example_dsPIC30F.X
├── nbproject
│ └── project.xml
├── Makefile
└── main_dsPIC30F.c
├── example_dsPIC33_ex16_IO.X
├── nbproject
│ ├── project.xml
│ └── configurations.xml
├── Makefile
└── main_dsPIC33F.c
├── PIC32
├── CO_application.h
├── CO_driver_target.h
├── CO_eepromPIC32.c
└── CO_main_PIC32.c
├── README.md
├── LICENSE
├── dsPIC33C
└── CO_driver_target.h
├── dsPIC30F
├── CO_driver_target.h
└── CO_driver.c
└── PIC24_dsPIC33
└── CO_driver_target.h
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "CANopenNode"]
2 | path = CANopenNode
3 | url = https://github.com/CANopenNode/CANopenNode.git
4 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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_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_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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------