1 /*
2 * CANopen main program file for PIC32 microcontroller.
3 *
4 * @file main_PIC32.c
5 * @author Janez Paternoster
6 * @copyright 2010 - 2020 Janez Paternoster
7 *
8 * This file is part of CANopenNode, an opensource CANopen Stack.
9 * Project home page is <https://github.com/CANopenNode/CANopenNode>.
10 * For more information on CANopen see <http://www.can-cia.org/>.
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 #define CO_FSYS 64000 /* (8MHz Quartz used) */
27 #define CO_PBCLK 32000 /* peripheral bus clock */
28
29
30 #include "CANopen.h"
31 #include "application.h"
32 #ifdef USE_EEPROM
33 #include "eeprom.h" /* 25LC128 eeprom chip connected to SPI2A port. */
34 #endif
35 #include <xc.h> /* for interrupts */
36 #include <sys/attribs.h> /* for interrupts */
37
38
39 /* Configuration bits */
40 #pragma config FVBUSONIO = OFF /* USB VBUS_ON Selection (OFF = pin is controlled by the port function) */
41 #pragma config FUSBIDIO = OFF /* USB USBID Selection (OFF = pin is controlled by the port function) */
42 #pragma config UPLLEN = OFF /* USB PLL Enable */
43 #pragma config UPLLIDIV = DIV_12 /* USB PLL Input Divider */
44 #pragma config FCANIO = ON /* CAN IO Pin Selection (ON = default CAN IO Pins) */
45 #pragma config FETHIO = ON /* Ethernet IO Pin Selection (ON = default Ethernet IO Pins) */
46 #pragma config FMIIEN = ON /* Ethernet MII Enable (ON = MII enabled) */
47 #pragma config FSRSSEL = PRIORITY_7 /* SRS (Shadow registers set) Select */
48 #pragma config POSCMOD = XT /* Primary Oscillator */
49 #pragma config FSOSCEN = OFF /* Secondary oscillator Enable */
50 #pragma config FNOSC = PRIPLL /* Oscillator Selection */
51 #pragma config FPLLIDIV = DIV_2 /* PLL Input Divider */
52 #pragma config FPLLMUL = MUL_16 /* PLL Multiplier */
53 #pragma config FPLLODIV = DIV_1 /* PLL Output Divider Value */
54 #pragma config FPBDIV = DIV_2 /* Bootup PBCLK divider */
55 #pragma config FCKSM = CSDCMD /* Clock Switching and Monitor Selection */
56 #pragma config OSCIOFNC = OFF /* CLKO Enable */
57 #pragma config IESO = OFF /* Internal External Switch Over */
58 #pragma config FWDTEN = OFF /* Watchdog Timer Enable */
59 #pragma config WDTPS = PS1024 /* Watchdog Timer Postscale Select (in milliseconds) */
60 #pragma config CP = OFF /* Code Protect Enable */
61 #pragma config BWP = ON /* Boot Flash Write Protect */
62 #pragma config PWP = PWP256K /* Program Flash Write Protect */
63 #ifdef CO_ICS_PGx1
64 #pragma config ICESEL = ICS_PGx1 /* ICE/ICD Comm Channel Select */
65 #else
66 #pragma config ICESEL = ICS_PGx2 /* ICE/ICD Comm Channel Select (2 for Explorer16 board) */
67 #endif
68 #pragma config DEBUG = ON /* Background Debugger Enable */
69
70
71 /* macros */
72 #define CO_TMR_TMR TMR2 /* TMR register */
73 #define CO_TMR_PR PR2 /* Period register */
74 #define CO_TMR_CON T2CON /* Control register */
75 #define CO_TMR_ISR_FLAG IFS0bits.T2IF /* Interrupt Flag bit */
76 #define CO_TMR_ISR_PRIORITY IPC2bits.T2IP /* Interrupt Priority */
77 #define CO_TMR_ISR_ENABLE IEC0bits.T2IE /* Interrupt Enable bit */
78
79 #define CO_CAN_ISR() void __ISR(_CAN_1_VECTOR, IPL5SOFT) CO_CAN1InterruptHandler(void)
80 #define CO_CAN_ISR_FLAG IFS1bits.CAN1IF /* Interrupt Flag bit */
81 #define CO_CAN_ISR_PRIORITY IPC11bits.CAN1IP /* Interrupt Priority */
82 #define CO_CAN_ISR_ENABLE IEC1bits.CAN1IE /* Interrupt Enable bit */
83
84 #define CO_CAN_ISR2() void __ISR(_CAN_2_VECTOR, IPL5SOFT) CO_CAN2InterruptHandler(void)
85 #define CO_CAN_ISR2_FLAG IFS1bits.CAN2IF /* Interrupt Flag bit */
86 #define CO_CAN_ISR2_PRIORITY IPC11bits.CAN2IP /* Interrupt Priority */
87 #define CO_CAN_ISR2_ENABLE IEC1bits.CAN2IE /* Interrupt Enable bit */
88
89 #define CO_clearWDT() (WDTCONSET = _WDTCON_WDTCLR_MASK)
90
91 /* Global variables and objects */
92 volatile uint16_t CO_timer1ms = 0U; /* variable increments each millisecond */
93 const CO_CANbitRateData_t CO_CANbitRateData[8] = {CO_CANbitRateDataInitializers};
94 static uint32_t tmpU32;
95 #ifdef USE_EEPROM
96 CO_EE_t CO_EEO; /* Eeprom object */
97 #endif
98
99
100 /* main ***********************************************************************/
main(void)101 int main (void){
102 CO_NMT_reset_cmd_t reset = CO_RESET_NOT;
103
104 /* Configure system for maximum performance. plib is necessary for that.*/
105 /* SYSTEMConfig(CO_FSYS*1000, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE); */
106
107 /* Enable system multi vectored interrupts */
108 INTCONbits.MVEC = 1;
109 __builtin_enable_interrupts();
110
111 /* Disable JTAG and trace port */
112 DDPCONbits.JTAGEN = 0;
113 DDPCONbits.TROEN = 0;
114
115
116 /* Verify, if OD structures have proper alignment of initial values */
117 if(CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord) while(1) CO_clearWDT();
118 if(CO_OD_EEPROM.FirstWord != CO_OD_EEPROM.LastWord) while(1) CO_clearWDT();
119 if(CO_OD_ROM.FirstWord != CO_OD_ROM.LastWord) while(1) CO_clearWDT();
120
121
122 /* initialize EEPROM - part 1 */
123 #ifdef USE_EEPROM
124 CO_ReturnError_t eeStatus = CO_EE_init_1(&CO_EEO, (uint8_t*) &CO_OD_EEPROM, sizeof(CO_OD_EEPROM),
125 (uint8_t*) &CO_OD_ROM, sizeof(CO_OD_ROM));
126 #endif
127
128
129 programStart();
130
131
132 /* increase variable each startup. Variable is stored in eeprom. */
133 OD_powerOnCounter++;
134
135
136 while(reset != CO_RESET_APP){
137 /* CANopen communication reset - initialize CANopen objects *******************/
138 CO_ReturnError_t err;
139 uint16_t timer1msPrevious;
140 uint16_t TMR_TMR_PREV = 0;
141 uint8_t nodeId;
142 uint16_t CANBitRate;
143
144 /* disable CAN and CAN interrupts */
145 CO_CAN_ISR_ENABLE = 0;
146 CO_CAN_ISR2_ENABLE = 0;
147
148 /* Read CANopen Node-ID and CAN bit-rate from object dictionary */
149 nodeId = OD_CANNodeID;
150 if(nodeId<1 || nodeId>127) nodeId = 0x10;
151 CANBitRate = OD_CANBitRate;/* in kbps */
152
153 /* initialize CANopen */
154 err = CO_init(ADDR_CAN1, nodeId, CANBitRate);
155 if(err != CO_ERROR_NO){
156 while(1) CO_clearWDT();
157 /* CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); */
158 }
159
160
161 /* initialize eeprom - part 2 */
162 #ifdef USE_EEPROM
163 CO_EE_init_2(&CO_EEO, eeStatus, CO->SDO[0], CO->em);
164 #endif
165
166
167 /* initialize variables */
168 timer1msPrevious = CO_timer1ms;
169 OD_performance[ODA_performance_mainCycleMaxTime] = 0;
170 OD_performance[ODA_performance_timerCycleMaxTime] = 0;
171 reset = CO_RESET_NOT;
172
173
174
175 /* Configure Timer interrupt function for execution every 1 millisecond */
176 CO_TMR_CON = 0;
177 CO_TMR_TMR = 0;
178 #if CO_PBCLK > 65000
179 #error wrong timer configuration
180 #endif
181 CO_TMR_PR = CO_PBCLK - 1; /* Period register */
182 CO_TMR_CON = 0x8000; /* start timer (TON=1) */
183 CO_TMR_ISR_FLAG = 0; /* clear interrupt flag */
184 CO_TMR_ISR_PRIORITY = 3; /* interrupt - set lower priority than CAN (set the same value in interrupt) */
185
186 /* Configure CAN1 Interrupt (Combined) */
187 CO_CAN_ISR_FLAG = 0; /* CAN1 Interrupt - Clear flag */
188 CO_CAN_ISR_PRIORITY = 5; /* CAN1 Interrupt - Set higher priority than timer (set the same value in '#define CO_CAN_ISR_PRIORITY') */
189 CO_CAN_ISR2_FLAG = 0; /* CAN2 Interrupt - Clear flag */
190 CO_CAN_ISR2_PRIORITY = 5; /* CAN Interrupt - Set higher priority than timer (set the same value in '#define CO_CAN_ISR_PRIORITY') */
191
192
193 communicationReset();
194
195
196 /* start CAN and enable interrupts */
197 CO_CANsetNormalMode(CO->CANmodule[0]);
198 CO_TMR_ISR_ENABLE = 1;
199 CO_CAN_ISR_ENABLE = 1;
200
201 #if CO_NO_CAN_MODULES >= 2
202 CO_CANsetNormalMode(CO->CANmodule[1]);
203 CO_CAN_ISR2_ENABLE = 1;
204 #endif
205
206
207 while(reset == CO_RESET_NOT){
208 /* loop for normal program execution ******************************************/
209 uint16_t timer1msCopy, timer1msDiff;
210
211 CO_clearWDT();
212
213
214 /* calculate cycle time for performance measurement */
215 timer1msCopy = CO_timer1ms;
216 timer1msDiff = timer1msCopy - timer1msPrevious;
217 timer1msPrevious = timer1msCopy;
218 uint16_t t0 = CO_TMR_TMR;
219 uint16_t t = t0;
220 if(t >= TMR_TMR_PREV){
221 t = t - TMR_TMR_PREV;
222 t = (timer1msDiff * 100) + (t / (CO_PBCLK / 100));
223 }
224 else if(timer1msDiff){
225 t = TMR_TMR_PREV - t;
226 t = (timer1msDiff * 100) - (t / (CO_PBCLK / 100));
227 }
228 else t = 0;
229 OD_performance[ODA_performance_mainCycleTime] = t;
230 if(t > OD_performance[ODA_performance_mainCycleMaxTime])
231 OD_performance[ODA_performance_mainCycleMaxTime] = t;
232 TMR_TMR_PREV = t0;
233
234
235 /* Application asynchronous program */
236 programAsync(timer1msDiff);
237
238 CO_clearWDT();
239
240
241 /* CANopen process */
242 reset = CO_process(CO, timer1msDiff, NULL);
243
244 CO_clearWDT();
245
246
247 #ifdef USE_EEPROM
248 CO_EE_process(&CO_EEO);
249 #endif
250 }
251 }
252
253
254 /* program exit ***************************************************************/
255 // CO_DISABLE_INTERRUPTS();
256
257 /* delete objects from memory */
258 programEnd();
259 CO_delete(ADDR_CAN1);
260
261 /* reset */
262 SYSKEY = 0x00000000;
263 SYSKEY = 0xAA996655;
264 SYSKEY = 0x556699AA;
265 RSWRSTSET = 1;
266 tmpU32 = RSWRST;
267 while(1);
268 }
269
270
271 /* timer interrupt function executes every millisecond ************************/
272 #ifndef USE_EXTERNAL_TIMER_1MS_INTERRUPT
__ISR(_TIMER_2_VECTOR,IPL3SOFT)273 void __ISR(_TIMER_2_VECTOR, IPL3SOFT) CO_TimerInterruptHandler(void){
274
275 CO_TMR_ISR_FLAG = 0;
276
277 CO_timer1ms++;
278
279 if(CO->CANmodule[0]->CANnormal) {
280 bool_t syncWas;
281 int i;
282
283 /* Process Sync */
284 syncWas = CO_process_SYNC(CO, 1000);
285
286 /* Read inputs */
287 CO_process_RPDO(CO, syncWas);
288
289 /* Further I/O or nonblocking application code may go here. */
290 #if CO_NO_TRACE > 0
291 OD_time.epochTimeOffsetMs++;
292 for(i=0; i<OD_traceEnable && i<CO_NO_TRACE; i++) {
293 CO_trace_process(CO->trace[i], OD_time.epochTimeOffsetMs);
294 }
295 #endif
296 program1ms();
297
298 /* Write outputs */
299 CO_process_TPDO(CO, syncWas, 1000);
300
301 /* verify timer overflow */
302 if(CO_TMR_ISR_FLAG == 1){
303 CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0);
304 CO_TMR_ISR_FLAG = 0;
305 }
306 }
307
308 /* calculate cycle time for performance measurement */
309 uint16_t t = CO_TMR_TMR / (CO_PBCLK / 100);
310 OD_performance[ODA_performance_timerCycleTime] = t;
311 if(t > OD_performance[ODA_performance_timerCycleMaxTime])
312 OD_performance[ODA_performance_timerCycleMaxTime] = t;
313 }
314 #endif
315
316
317 /* CAN interrupt function *****************************************************/
CO_CAN_ISR()318 CO_CAN_ISR(){
319 CO_CANinterrupt(CO->CANmodule[0]);
320 /* Clear combined Interrupt flag */
321 CO_CAN_ISR_FLAG = 0;
322 }
323
324 #if CO_NO_CAN_MODULES >= 2
CO_CAN_ISR2()325 CO_CAN_ISR2(){
326 CO_CANinterrupt(CO->CANmodule[1]);
327 /* Clear combined Interrupt flag */
328 CO_CAN_ISR2_FLAG = 0;
329 }
330 #endif
331