Forum: Mikrocontroller und Digitale Elektronik PIC18F Can Hardwarefilter anstatt Software Filter?


von Manuel B. (desteini)


Lesenswert?

Hallo Leute,

Ich habe eine Board entworfen, dass mit Hilfe des PIC18F258 
CAN-Nachrichten per Interrupt liest und schreibt. Soweit funktioniert 
das auch. Sobald der Bus aber eine höhere Last hat (2 Nachrichten alle 
10ms und eine alle 100ms) kommt die Nachricht für das Board (die, die 
alle 100ms verschickt wird) nichtmehr an, oder extrem spät.

Laut PCAN-View werden aber alle Nachrichten richtig auf den Bus 
geschickt. Das heißt es muss ein Problem mit dem Board sein und somit 
mit dem Chip sein.

Die Idee war nun einen Filter zu benutzen um nur diese Nachricht zu 
beachten, die wir brauchen. Leider scheint es mit der benutzten library 
nicht zu funktionieren. Der Code kommt später, vllt findet jemand den 
Fehler, obwohl wir schon einiges ausprobiert haben.

Nun habe ich von einem Hardware Filter gelesen. Eventuell ist das eine 
bessere Lösung als das gesammte Programm mit einer anderen Library neu 
zu schreiben. Habt ihr vorschläge für einen Hardware Filter bzw. glaubt 
ihr dass es nützen wird? Oder glaubt ihr, dass Problem liegt an was 
anderem?

Ist es ein großer Aufwand den Hardware Filter im Nachhinein zu 
integrieren? bzw größer, als das Programm mit einer neuen Library zu 
schreiben?

Can.h
1
/*********************************************************************
2
 *
3
 *                           This is the header for CAN.C
4
 *   
5
 *********************************************************************
6
 * FileName:        CAN.H
7
 * Dependencies:    CANDef.h
8
 * Processor:       PIC18FXX8
9
 * Compiler:        MCC18 v2.20 or higher
10
 *                  HITECH PICC-18 v8.20PL4 or higher
11
 * Linker:          
12
 * Company:         Microchip Technology, Inc.
13
 *
14
 * Software License Agreement
15
 *
16
 * The software supplied herewith by Microchip Technology Incorporated
17
 * (the "Company") is intended and supplied to you, the Company’s
18
 * customer, for use solely and exclusively with products manufactured
19
 * by the Company. 
20
 *
21
 * The software is owned by the Company and/or its supplier, and is 
22
 * protected under applicable copyright laws. All rights are reserved. 
23
 * Any use in violation of the foregoing restrictions may subject the 
24
 * user to criminal sanctions under applicable laws, as well as to 
25
 * civil liability for the breach of the terms and conditions of this 
26
 * license.
27
 
28
 * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, 
29
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED 
30
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
31
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, 
32
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR 
33
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
34
 *
35
 *
36
 *
37
 *
38
 * Author               Date        Comment
39
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
40
 * Thomas Castmo        06/07/2003  Initial release
41
 * Thomas Castmo        07/07/2003  Cleared up a bit and implemented 
42
 *                                  the window function CANCON<3:1> 
43
 *                                  for interrupts
44
 * Thomas Castmo        16/07/2003  Added support for the Microchip
45
 *                                  MPLAB C18 compiler
46
 * 
47
 ********************************************************************/
48
#ifndef __CAN_H
49
#define __CAN_H
50
51
#include "candef.h"
52
53
#define CANInit() CANOpen(CAN_CONFIG_1, CAN_CONFIG_2, CAN_CONFIG_3)
54
55
#define MASK_ENABLE_ALL 0x00000000      //The mask to enable all incoming messages
56
57
#define ACCEPTANCE_MASK_0_1 RXMASK0      //Acceptance mask for filters 0 and 1
58
#define ACCEPTANCE_MASK_2_5 RXMASK1      //Acceptance mask for filters 2, 3, 4 and 5
59
60
//                          0x1FFFFFFF      Maximum extended identifier
61
//                          0x000007FF      Maximum standard identifier
62
#define ACCEPTANCE_FILTER_0 RXFILT0      //Acceptance filter 0
63
#define ACCEPTANCE_FILTER_1 RXFILT1      //Acceptance filter 1
64
65
//                          0x1FFFFFFF      Maximum extended identifier
66
//                          0x000007FF      Maximum standard identifier
67
#define ACCEPTANCE_FILTER_2 RXFILT2      //Acceptance filter 2
68
#define ACCEPTANCE_FILTER_3 RXFILT3      //Acceptance filter 3
69
#define ACCEPTANCE_FILTER_4 RXFILT4      //Acceptance filter 4
70
#define ACCEPTANCE_FILTER_5 RXFILT5      //Acceptance filter 5
71
72
//If a desired filter is to accept extended identifiers
73
//then comment the appropriate line out
74
#ifdef ST_FILTER_0
75
#define ACCEPT_STANDARD_FILTER_0
76
#endif
77
#ifdef ST_FILTER_1
78
#define ACCEPT_STANDARD_FILTER_1
79
#endif
80
#ifdef ST_FILTER_2
81
#define ACCEPT_STANDARD_FILTER_2
82
#endif
83
#ifdef ST_FILTER_3
84
#define ACCEPT_STANDARD_FILTER_3
85
#endif
86
#ifdef ST_FILTER_4
87
#define ACCEPT_STANDARD_FILTER_4
88
#endif
89
#ifdef ST_FILTER_5
90
#define ACCEPT_STANDARD_FILTER_5
91
#endif
92
93
94
95
96
//                            0x1FFFFFFF      Maximum extended identifier
97
//                            0x000007FF      Maximum standard identifier
98
#define MY_ADDRESS_IDENTIFIER MY_IDENT
99
100
//To use extended identifier for my address, comment the following line out
101
#ifdef STD_IDENT
102
#define MY_ADDRESS_IS_STANDARD
103
#endif
104
105
106
//If using normal mode, comment the following line out
107
#ifdef LPBACK
108
#define USE_LOOPBACK_MODE
109
#endif
110
111
112
//Size of RX buffer (14 bytes per buffer entry) has to be greater than or equal to 2
113
#define RXBUF RX_BUFFER
114
115
//Size of TX buffer (14 bytes per buffer entry) has to be greater than or equal to 2
116
#define TXBUF TX_BUFFER
117
118
#if TXBUF < 2 || RXBUF < 2
119
#error "The RXbuffer and TXbuffer has to greater than or equal to 2"
120
#endif
121
  
122
//CAN message structure (one message is 15 bytes wide)
123
struct CANMessage {
124
  unsigned long Address;
125
  unsigned char Data[8];
126
  unsigned char NoOfBytes;
127
  unsigned char Priority;
128
  unsigned Ext:1;
129
  unsigned Remote:1;
130
};
131
132
#define CAN_LISTEN_MODE 0x7F 
133
#define CAN_LOOPBACK_MODE 0x5F 
134
#define CAN_DISABLE_MODE 0x3F  
135
#define CAN_NORMAL_MODE 0x1F
136
137
138
139
140
/*********************************************************************
141
 * Function:        char CANOpen(unsigned char CONFIG1, unsigned char CONFIG2, unsigned char CONFIG3)
142
 *
143
 * PreCondition:    None
144
 *
145
 * Input:           Values to be written into BRGCON1 -> BRGCON3
146
 *
147
 * Output:          0 -> Initialasation succeeded
148
 *
149
 * Side Effects:    None
150
 *
151
 * Overview:        Sets up the appropriate register for the device to act
152
 *                  as a CAN node
153
 *
154
 * Note:            Input values 0x03, 0xAA, 0x05 at Fosc = 16MHz works with 
155
 *                  the default firmware at nodeB on the CAN I/O expander board.
156
 ********************************************************************/
157
char CANOpen(unsigned char, unsigned char, unsigned char);  
158
159
160
/*********************************************************************
161
 * Function:        void CANISR(void)
162
 *
163
 * PreCondition:    None
164
 *
165
 * Input:           None
166
 *
167
 * Output:          None
168
 *
169
 * Side Effects:    Will modify the RX/TX Buffer registers´ Write/Read pointers
170
 *
171
 * Overview:        Checks if a CAN reception/transmission was complete 
172
 *                  and if so write/read to the CAN RX/TX FIFO buffers
173
 *
174
 * Note:            This function is supposed to be called from the ISR
175
 ********************************************************************/
176
void CANISR(void);
177
178
179
/*********************************************************************
180
 * Function:        char CANPut(struct CANMessage Message)
181
 *
182
 * PreCondition:    None
183
 *
184
 * Input:           A CAN message
185
 *
186
 * Output:          1 -> Failed to put a CAN on the buffer, buffer is full
187
 *                  0 -> The CAN message is put on the buffer and will be 
188
 *                       transmitted eventually 
189
 *
190
 * Side Effects:    Will modify the TX Buffer register´s Write pointer
191
 *
192
 * Overview:        Initially checks if at least one buffer slot is available
193
 *                  and if so push the requested message in the buffer
194
 *
195
 * Note:            None
196
 ********************************************************************/
197
char CANPut(struct CANMessage);
198
199
200
/*********************************************************************
201
 * Function:        char CANRXMessageIsPending(void)
202
 *
203
 * PreCondition:    None
204
 *
205
 * Input:           None
206
 *
207
 * Output:          1 -> At least one received message is pending in the RX buffer
208
 *                  0 -> No received messages are pending
209
 *
210
 * Side Effects:    None
211
 *
212
 * Overview:        Checks if the RX Write pointer is equal to RX Read pointer and
213
 *                  if so returns 0, else returns 1
214
 *
215
 * Note:            Since no care is taken if the buffer overflow
216
 *                  this function has to be polled frequently to
217
 *                  prevent a software receive buffer overflow
218
 ********************************************************************/
219
char CANRXMessageIsPending(void);
220
221
222
/*********************************************************************
223
 * Function:        struct CANMessage CANGet(void)
224
 *
225
 * PreCondition:    An unread message has to be in the buffer
226
 *                  use RXCANMessageIsPending(void) prior to 
227
 *                  calling this function in order to determine
228
 *                  if an unread message is pending.
229
 *
230
 * Input:           None
231
 *
232
 * Output:          The received message
233
 *
234
 * Side Effects:    Will modify the RX Buffer register´s Read pointer
235
 *
236
 * Overview:        Pops the the first message of the RX buffer
237
 *
238
 * Note:            None
239
 ********************************************************************/
240
struct CANMessage CANGet(void);
241
242
243
/*********************************************************************
244
 * Function:        void CANSetMode(unsigned char Mode)
245
 *
246
 * PreCondition:    None
247
 *
248
 * Input:           Desired CAN Mode
249
 *                  (CAN_LISTEN_MODE, CAN_LOOPBACK_MODE
250
 *                   CAN_DISABLE_MODE, CAN_NORMAL_MODE)
251
 *
252
 * Output:          None
253
 *
254
 * Side Effects:    None
255
 *
256
 * Overview:        Requests to set the desired mode and waits until
257
 *          the mode has been set.
258
 *
259
 * Note:            If USE_LOOPBACK_MODE is defined the requested
260
 *                  mode will be loopback mode if the input is
261
 *                  Normal mode
262
 ********************************************************************/
263
void CANSetMode(unsigned char);
264
265
#endif

Definitions.h
1
#ifndef __DEFINITIONS_H
2
#define __DEFINITIONS_H
3
4
#include <p18f258.h> // Define PIC we are using
5
#include <stdlib.h>
6
#include <string.h>
7
#include <spi.h>
8
#include <timers.h>
9
#include <delays.h>
10
11
12
//#pragma config OSC = LP            //Oscillator Selection:LP
13
//#pragma config OSC = XT            //Oscillator Selection:XT
14
#pragma config OSC = HS            //Oscillator Selection:HS
15
//#pragma config OSC = RC            //Oscillator Selection:RC
16
//#pragma config OSC = EC            //Oscillator Selection:EC-OSC2 as Clock Out
17
//#pragma config OSC = ECIO          //Oscillator Selection:EC-OSC2 as RA6
18
//#pragma config OSC = HSPLL         //Oscillator Selection:HS-PLL Enabled
19
//#pragma config OSC = RCIO          //Oscillator Selection:RC-OSC2 as RA6
20
               
21
#pragma config OSCS = OFF           //Osc. Switch On Off
22
23
#pragma config    PWRT = OFF              //Power Up Timer
24
 
25
#pragma config BOR = OFF               //Brown Out Reset:
26
  
27
#pragma config BORV = 25               //Brown Out Voltage:4.5V
28
// #pragma config BORV = 42         //Brown Out Voltage:4.2V
29
// #pragma config BORV = 27         //Brown Out Voltage:2.7V
30
// #pragma config BORV = 25         //Brown Out Voltage:2.5V
31
32
 
33
#pragma config WDT = OFF             // Watchdog Timer
34
 
35
//#pragma config WDTPS = 1               //Watchdog Postscaler:1:1
36
//#pragma config WDTPS = 2               //Watchdog Postscaler:1:2
37
//#pragma config WDTPS = 4               //Watchdog Postscaler:1:4
38
//#pragma config WDTPS = 8               //Watchdog Postscaler:1:8
39
//#pragma config WDTPS = 16              //Watchdog Postscaler:1:16
40
//#pragma config WDTPS = 32              //Watchdog Postscaler:1:32
41
//#pragma config WDTPS = 64              //Watchdog Postscaler:1:64
42
//#pragma config WDTPS = 128             //Watchdog Postscaler:1:128
43
44
//#pragma config CCP2MUX = OFF           //CCP2 Mux:Disable (RB3)
45
46
#pragma config STVR = OFF              //Stack Overflow Reset:Disabled
47
    
48
#pragma config LVP = OFF               //Low Voltage ICSP:Disabled
49
       
50
#pragma config DEBUG = OFF             //Background Debugger Enable:Disabled
51
   
52
#pragma config CP0 = OFF               //Code Protection Block 0:Disabled
53
#pragma config CP1 = OFF               //Code Protection Block 1:Disabled
54
#pragma config CP2 = OFF               //Code Protection Block 2:Disabled
55
#pragma config CP3 = OFF               //Code Protection Block 3:Disabled
56
#pragma config CPB = OFF               //Boot Block Code Protection:Disabled
57
#pragma config CPD = OFF               //Data EEPROM Code Protection:Disabled
58
#pragma config WRT0 = OFF              //Write Protection Block 0:Disabled
59
#pragma config WRT1 = OFF              //Write Protection Block 1:Disabled
60
#pragma config WRT2 = OFF              //Write Protection Block 2:Disabled
61
#pragma config WRT3 = OFF              //Write Protection Block 3:Disabled
62
#pragma config WRTB = OFF              //Boot Block Write Protection:Disabled  
63
#pragma config WRTC = OFF              //Configuration Register Write Protection:Disabled
64
#pragma config WRTD = OFF              //Data EEPROM Write Protection:Disabled
65
#pragma config EBTR0 = OFF             //Table Read Protection Block 0:Disabled
66
#pragma config EBTR1 = OFF             //Table Read Protection Block 1:Disabled
67
#pragma config EBTR2 = OFF             //Table Read Protection Block 2:Disabled
68
#pragma config EBTR3 = OFF             //Table Read Protection Block 3:Disabled
69
#pragma config EBTRB = OFF             //Boot Block Table Read Protection:Disabled
70
71
72
/*-----------------------------------
73
----------- DEFINITIONS -------------
74
-----------------------------------*/
75
76
//Ecan 
77
#define CAN_RX      PORTBbits.RB3
78
#define CAN_TX      PORTBbits.RB2
79
80
//Canflag
81
#define CF0                      PIR3bits.RXB0IF
82
#define CF1                      PIR3bits.RXB1IF
83
#define CRF0                     PIR3bits.TXB0IF
84
#define CRF1                     PIR3bits.TXB1IF
85
86
//Timerflag
87
#define T0F                     INTCONbits.TMR0IF
88
#define T1F                     PIR1bits.TMR1IF
89
#define T2F                     PIR1bits.TMR2IF
90
#define T3F                     PIR2bits.TMR3IF
91
92
// Timerstatus
93
#define T0Status                T0CONbits.TMR0ON
94
#define T1Status                T1CONbits.TMR1ON
95
#define T2Status                T2CONbits.TMR2ON
96
//LED
97
#define LED        PORTAbits.RA0
98
//relay control PORTA
99
#define LAC        PORTAbits.RA1
100
#define RAC        PORTAbits.RA2
101
#define SLC        PORTAbits.RA3
102
//#define HBC        PORTAbits.RA4
103
#define HBMOC        PORTAbits.RA5
104
105
//relay control PORTC
106
#define HBC      PORTCbits.RC6
107
#define WWC      PORTCbits.RC5
108
#define HC      PORTCbits.RC4
109
110
//Inputs PORTC
111
#define SA                      PORTCbits.RC7
112
#define SLS      PORTCbits.RC3
113
#define SPT      PORTCbits.RC2
114
#define SFS      PORTCbits.RC1
115
#define SFD      PORTCbits.RC0
116
117
#define OFF       1
118
#define ON         !OFF
119
120
#define FALSE       0
121
#define TRUE       !FALSE
122
123
#define OK         1
124
#define ERROR       !OK
125
126
#define DEBUG_DEFAULT   0
127
#define DEBUG_SMALL   1
128
#define DEBUG_MEDIUM   2
129
#define DEBUG_FULL     3
130
131
//#define MY_IDENT
132
//#define THROTTLE_ID    0x110
133
//#define  GEAR_ID      0x120
134
#define HEBELID                 0x104
135
136
137
/*-----------------------------------
138
--------ERRORS CODE -----------------
139
-----------------------------------*/
140
#define UKNOWN_CMD     99
141
#define BAD_CMD     7
142
#define BAD_DEVC     1
143
#define BAD_DATA     2
144
145
146
//valore in percentuale di quanto sia premuto l'accelleratore. 0 sollevato - 255 premuto completamente
147
unsigned char LeftArrow, RightArrow, StopLight,HighBeam,HighBeamManual, Wipewasher, Horn;
148
unsigned int Buffer;
149
150
int len;
151
long timer;
152
153
char msg_ready;  //flag per inviare un messaggio tramite can
154
unsigned char Msg[8];
155
156
#endif

CANdef.h
1
/****************************************************
2
*       This file was created by                    *
3
*       Microchip Application Maestro               *
4
*       and holds the set-up parameters             *
5
*       specified when the code was generated.      *
6
*       The user is advised not to make any         *
7
*       changes to this file                        *
8
****************************************************/
9
#define BAUD_RATE_PRESC 1
10
#define SJW_TIME 4
11
#define SAMPLES 3
12
#define PROP_TIME 1
13
#define PH_SEG_1 4
14
#define PH_SEG_2 4
15
#define CAN_CONFIG_1 BAUD_RATE_PRESC-1|(SJW_TIME-1<<6)
16
#if SAMPLES == 1
17
#define CAN_CONFIG0_2 0x80|(PH_SEG_1-1<<3)|(PROP_TIME-1)
18
#elif SAMPLES == 3
19
#define CAN_CONFIG_2 0xC0|(PH_SEG_1-1<<3)|(PROP_TIME-1)
20
#else
21
#error "Number of samples is out of range"
22
#endif
23
#define CAN_CONFIG_3 PH_SEG_2-1
24
#define RXMASK0 -1
25
#define RXMASK1 -1
26
#define RXFILT0 0x104
27
#define ST_FILTER_0 
28
#define RXFILT1 0x104
29
#define ST_FILTER_1 
30
#define RXFILT2 0x104
31
#define ST_FILTER_2
32
#define RXFILT3 0x104
33
#define ST_FILTER_3
34
#define RXFILT4 0x104
35
#define ST_FILTER_4
36
#define RXFILT5 0x104
37
#define ST_FILTER_5
38
//#define LPBACK
39
//#define MY_IDENT 0x150
40
#define STD_IDENT
41
#define RX_BUFFER 4
42
#define TX_BUFFER 4
43
//#define CAN_INT_LOW
44
//#define CAN_ERROR_HANDLER_ENABLE

Can.c
1
/*********************************************************************
2
 *
3
 *   This file contains CAN drivers for PIC18Fxx8 devices
4
 *   
5
 *********************************************************************
6
 * FileName:        CAN.C
7
 * Dependencies:    CAN.H, PIC18.H or P18CXXX.H
8
 * Processor:       PIC18FXX8
9
 * Compiler:        MCC18 v2.20 or higher
10
 *                  HITECH PICC-18 v8.20PL4 or higher
11
 * Linker:          
12
 * Company:         Microchip Technology, Inc.
13
 *
14
 * Software License Agreement
15
 *
16
 * The software supplied herewith by Microchip Technology Incorporated
17
 * (the "Company") is intended and supplied to you, the Company’s
18
 * customer, for use solely and exclusively with products manufactured
19
 * by the Company. 
20
 *
21
 * The software is owned by the Company and/or its supplier, and is 
22
 * protected under applicable copyright laws. All rights are reserved. 
23
 * Any use in violation of the foregoing restrictions may subject the 
24
 * user to criminal sanctions under applicable laws, as well as to 
25
 * civil liability for the breach of the terms and conditions of this 
26
 * license.
27
 
28
 * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, 
29
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED 
30
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
31
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, 
32
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR 
33
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
34
 *
35
 *
36
 *
37
 *
38
 * Author               Date        Comment
39
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
40
 * Thomas Castmo        06/07/2003  Initial release
41
 * Thomas Castmo        07/07/2003  Cleared up a bit and implemented 
42
 *                                  the window function CANCON<3:1> 
43
 *                                  for interrupts
44
 * Thomas Castmo        16/07/2003  Added support for the Microchip
45
 *                                  MPLAB C18 compiler
46
 * 
47
 ********************************************************************/
48
#include "can.h"
49
50
#if defined(HI_TECH_C)
51
    #if defined(_MPC_)
52
        #define HITECH_C18
53
    #else
54
        #error "Unknown part is selected."
55
    #endif
56
#else
57
    #define MCHP_C18
58
#endif
59
60
#if defined(MCHP_C18) && defined(HITECH_C18)
61
#error "Invalid Compiler selection."
62
#endif
63
64
#if !defined(MCHP_C18) && !defined(HITECH_C18)
65
#error "Compiler not supported."
66
#endif
67
68
69
#if defined(HITECH_C18)
70
#include <pic18.h>
71
72
#elif defined(MCHP_C18)
73
#include <p18cxxx.h>
74
75
#define TRISB2 TRISBbits.TRISB2
76
#define TRISB3 TRISBbits.TRISB3
77
#define TXB0REQ TXB0CONbits.TXREQ
78
#define RXB0FUL RXB0CONbits.RXFUL
79
#define RXB0RTRRO RXB0CONbits.RXRTRRO
80
81
#define RXB0IF PIR3bits.RXB0IF
82
#define RXB1IF PIR3bits.RXB1IF
83
#define TXB0IF PIR3bits.TXB0IF
84
#define TXB1IF PIR3bits.TXB1IF
85
#define TXB2IF PIR3bits.TXB2IF
86
#define ERRIF PIR3bits.ERRIF
87
#define WAKIF PIR3bits.WAKIF
88
89
#define RXB0IE PIE3bits.RXB0IE
90
#define RXB1IE PIE3bits.RXB1IE
91
#define TXB0IE PIE3bits.TXB0IE
92
#define TXB1IE PIE3bits.TXB1IE
93
#define TXB2IE PIE3bits.TXB2IE
94
#define ERRIE PIE3bits.ERRIE
95
#define WAKIE PIE3bits.WAKIE
96
97
98
#endif
99
100
101
102
#define CONFIG_MODE 0x9F
103
#define LISTEN_MODE 0x7F 
104
#define LOOPBACK_MODE 0x5F 
105
#define DISABLE_MODE 0x3F  
106
#define NORMAL_MODE 0x1F
107
#define MODE_MASK 0xE0
108
109
#define NoInterrupt 0x00
110
#define ErrorInterrupt 0x02
111
#define TXB2Interrupt 0x04
112
#define TXB1Interrupt 0x06
113
#define TXB0Interrupt 0x08
114
#define RXB1Interrupt 0x0A
115
#define RXB0Interrupt 0x0C
116
#define WakeUpInterrupt 0x0E
117
118
119
#ifdef CAN_ERROR_HANDLER_ENABLE
120
extern void CANErrorHandler(void);
121
#define CAN_INT_BITS 0x3F  //CAN interrupts which should be enabled, simply what PIE3 is to be loaded with (Note all TXB IE will be set regardless of this value)
122
#else
123
#define CAN_INT_BITS 0x1F  //CAN interrupts which should be enabled, simply what PIE3 is to be loaded with (Note all TXB IE will be set regardless of this value)
124
#endif
125
126
union RXBuffer {        //Receive buffer structure
127
  unsigned char Data[14];    //It has to be a bit messy/strict for
128
  struct {          //it to go trough the PICC18 compiler
129
    union {
130
      unsigned char Byte;
131
      struct {
132
        unsigned FILHIT0:1;
133
        unsigned JTOFF:1;
134
        unsigned RXB0DBEN:1;
135
        unsigned RXRTRRO:1;
136
        unsigned :1;
137
        unsigned RXM0:1;
138
        unsigned RXM1:1;
139
        unsigned RXFUL:1;
140
      } Bits;
141
    } RXBCON;
142
    union {
143
      unsigned char Byte;
144
    } RXBSIDH;
145
    union {
146
      unsigned char Byte;
147
      struct {
148
        unsigned EID16:1;
149
        unsigned EID17:1;
150
        unsigned :1;
151
        unsigned EXID:1;
152
        unsigned SRR:1;
153
        unsigned SID0:1;
154
        unsigned SID1:1;
155
        unsigned SID2:1;
156
      } Bits;
157
    } RXBSIDL;
158
    union {
159
      unsigned char Byte;
160
    } RXBEIDH;
161
    union {
162
      unsigned char Byte;
163
    } RXBEIDL;
164
    union {
165
      unsigned char Byte;
166
      struct {
167
        unsigned DLC0:1;
168
        unsigned DLC1:1;
169
        unsigned DLC2:1;
170
        unsigned DLC3:1;
171
        unsigned RB0:1;
172
        unsigned RB1:1;
173
        unsigned RXRTR:1;
174
        unsigned :1;
175
      } Bits;
176
    } RXBDLC;
177
    union {
178
      unsigned char Array[8];
179
      struct {
180
        unsigned char RXBD0;
181
        unsigned char RXBD1;
182
        unsigned char RXBD2;
183
        unsigned char RXBD3;
184
        unsigned char RXBD4;
185
        unsigned char RXBD5;
186
        unsigned char RXBD6;
187
        unsigned char RXBD7;
188
      } Bytes;
189
    } RXBD;
190
  } Specific;
191
};
192
193
union TXBuffer {          //Transmit buffer structure
194
  unsigned char Data[14];
195
  struct {
196
    union {
197
      unsigned char Byte;
198
      struct {
199
        unsigned TXPRI0:1;
200
        unsigned TXPRI1:1;
201
        unsigned :1;
202
        unsigned TXREQ:1;
203
        unsigned TXERR:1;
204
        unsigned TXLARB:1;
205
        unsigned TXABT:1;
206
      } Bits;
207
    } TXBCON;
208
    union {
209
      unsigned char Byte;
210
    } TXBSIDH;
211
    union {
212
      unsigned char Byte;
213
      struct {
214
        unsigned EID16:1;
215
        unsigned EID17:1;
216
        unsigned :1;
217
        unsigned EXIDE:1;
218
        unsigned :1;
219
        unsigned SID0:1;
220
        unsigned SID1:1;
221
        unsigned SID2:1;
222
      } Bits;
223
    } TXBSIDL;
224
    union {
225
      unsigned char Byte;
226
    } TXBEIDH;
227
    union {
228
      unsigned char Byte;
229
    } TXBEIDL;
230
    union {
231
      unsigned char Byte;
232
      struct {
233
        unsigned DLC0:1;
234
        unsigned DLC1:1;
235
        unsigned DLC2:1;
236
        unsigned DLC3:1;
237
        unsigned :1;
238
        unsigned :1;
239
        unsigned TXRTR:1;
240
        unsigned :1;
241
      } Bits;
242
    } TXBDLC;
243
    union {
244
      unsigned char Array[8];
245
      struct {
246
        unsigned char TXBD0;
247
        unsigned char TXBD1;
248
        unsigned char TXBD2;
249
        unsigned char TXBD3;
250
        unsigned char TXBD4;
251
        unsigned char TXBD5;
252
        unsigned char TXBD6;
253
        unsigned char TXBD7;
254
      } Bytes;
255
    } TXBD;
256
  } Specific;
257
};
258
union RXBuffer RXMessage[RXBUF];    //Received messages FIFO buffer
259
union TXBuffer TXMessage[TXBUF];    //Pending messages to transmit FIFO buffer
260
char RXRPtr = 0;            //Read pointer for RXMessage buffer
261
char RXWPtr = 0;            //Write pointer for RXMessage buffer
262
char TXRPtr = 0;            //Read pointer for TXMessage buffer
263
char TXWPtr = 0;            //Write pointer for TXMessage buffer
264
265
266
/*********************************************************************
267
 * Function:        void CANGetMessage(void)
268
 *
269
 * PreCondition:    <WIN2:WIN0> in the CANCON register has to set
270
 *                  to reflect the desired RXB registers
271
 *
272
 * Input:           None
273
 *
274
 * Output:          None
275
 *
276
 * Side Effects:    Will modify the RX FIFO Write pointer (RXWPtr)
277
 *
278
 * Overview:        Gets the registers for a RXB and puts them in the
279
 *                  CAN Receive buffer
280
 *
281
 * Note:            Care is not taken if buffer is full
282
 ********************************************************************/
283
void CANGetMessage(void);
284
285
/*********************************************************************
286
 * Function:        char CANPutMessage(void)
287
 *
288
 * PreCondition:    <WIN2:WIN0> in the CANCON register has to set
289
 *                  to reflect the desired TXB registers
290
 *
291
 * Input:           None
292
 *
293
 * Output:          0 -> A new message has been put in the transmit queue
294
 *                  1 -> There was no messages in the TX buffer to send
295
 *
296
 * Side Effects:    Will modify the TX buffer´s Read pointer (TXRPtr)
297
 *
298
 * Overview:        Checks if there is any messages to transmit and if so
299
 *                  place it in the registers reflected by <WIN2:WIN0> 
300
 *
301
 * Note:            None
302
 ********************************************************************/
303
 char CANPutMessage(void);
304
305
/*********************************************************************
306
 * Function:        char CANOpen(void)
307
 *
308
 * PreCondition:    None
309
 *
310
 * Input:           Values to be written into BRGCON1 -> BRGCON3
311
 *
312
 * Output:          0 -> Initialasation succeeded
313
 *
314
 * Side Effects:    None
315
 *
316
 * Overview:        Sets up the appropriate register for the device to act
317
 *                  as a CAN node
318
 *
319
 * Note:            Input values 0x03, 0xAA, 0x05 at Fosc = 16MHz works with 
320
 *                  the default firmware at nodeB on the CAN I/O expander board.
321
 ********************************************************************/
322
char CANOpen(unsigned char CONFIG1, unsigned char CONFIG2, unsigned char CONFIG3)
323
{
324
  TRISB2 = 0;
325
  TRISB3 = 1;
326
  PIE3 = 0;                    //Disable all CAN interrupts
327
  PIR3 = 0;                    //and clear all CAN interrupt flags
328
  CANCON = (CONFIG_MODE & MODE_MASK) | (CANCON & 0x3F);  //Set configuration mode
329
  while((CANSTAT & MODE_MASK) != (CONFIG_MODE & MODE_MASK));  //Wait until config mode is set
330
331
  BRGCON1 = CONFIG1;
332
  BRGCON2 = CONFIG2;
333
  BRGCON3 = CONFIG3;
334
  
335
  RXB0CON = 0x04;          //Receive all valid messages receive buffer overflow 
336
  RXB1CON = 0x00;          //writes to RXB1
337
  
338
  //Set the acceptance filters for all the filters
339
#ifdef ACCEPT_STANDARD_FILTER_0
340
  RXF0SIDL = (unsigned char)(ACCEPTANCE_FILTER_0 << 5);
341
  RXF0SIDH = (unsigned char)(ACCEPTANCE_FILTER_0 >> 3);
342
#else
343
  RXF0EIDL = (unsigned char)(ACCEPTANCE_FILTER_0 & 0xFF);  
344
  RXF0EIDH = (unsigned char)((ACCEPTANCE_FILTER_0 >> 8) & 0xFF);
345
  RXF0SIDL = (unsigned char)((ACCEPTANCE_FILTER_0 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_0 >> 13) & 0xE0) | 0x08;
346
  RXF0SIDH = (unsigned char)((ACCEPTANCE_FILTER_0 >> 21) & 0xFF);
347
#endif
348
#ifdef ACCEPT_STANDARD_FILTER_1
349
  RXF1SIDL = (unsigned char)(ACCEPTANCE_FILTER_1 << 5);
350
  RXF1SIDH = (unsigned char)(ACCEPTANCE_FILTER_1 >> 3);
351
#else
352
  RXF1EIDL = (unsigned char)(ACCEPTANCE_FILTER_1 & 0xFF);  
353
  RXF1EIDH = (unsigned char)((ACCEPTANCE_FILTER_1 >> 8) & 0xFF);
354
  RXF1SIDL = (unsigned char)((ACCEPTANCE_FILTER_1 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_1 >> 13) & 0xE0) | 0x08;
355
  RXF1SIDH = (unsigned char)((ACCEPTANCE_FILTER_1 >> 21) & 0xFF);
356
#endif
357
358
#ifdef ACCEPT_STANDARD_FILTER_2
359
  RXF2SIDL = (unsigned char)(ACCEPTANCE_FILTER_2 << 5);
360
  RXF2SIDH = (unsigned char)(ACCEPTANCE_FILTER_2 >> 3);
361
#else
362
  RXF2EIDL = (unsigned char)(ACCEPTANCE_FILTER_2 & 0xFF);  
363
  RXF2EIDH = (unsigned char)((ACCEPTANCE_FILTER_2 >> 8) & 0xFF);
364
  RXF2SIDL = (unsigned char)((ACCEPTANCE_FILTER_2 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_2 >> 13) & 0xE0) | 0x08;
365
  RXF2SIDH = (unsigned char)((ACCEPTANCE_FILTER_2 >> 21) & 0xFF);
366
#endif
367
368
#ifdef ACCEPT_STANDARD_FILTER_3
369
  RXF3SIDL = (unsigned char)(ACCEPTANCE_FILTER_3 << 5);
370
  RXF3SIDH = (unsigned char)(ACCEPTANCE_FILTER_3 >> 3);
371
#else
372
  RXF3EIDL = (unsigned char)(ACCEPTANCE_FILTER_3 & 0xFF);  
373
  RXF3EIDH = (unsigned char)((ACCEPTANCE_FILTER_3 >> 8) & 0xFF);
374
  RXF3SIDL = (unsigned char)((ACCEPTANCE_FILTER_3 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_3 >> 13) & 0xE0) | 0x08;
375
  RXF3SIDH = (unsigned char)((ACCEPTANCE_FILTER_3 >> 21) & 0xFF);
376
#endif
377
378
#ifdef ACCEPT_STANDARD_FILTER_4
379
  RXF4SIDL = (unsigned char)(ACCEPTANCE_FILTER_4 << 5);
380
  RXF4SIDH = (unsigned char)(ACCEPTANCE_FILTER_4 >> 3);
381
#else
382
  RXF4EIDL = (unsigned char)(ACCEPTANCE_FILTER_4 & 0xFF);  
383
  RXF4EIDH = (unsigned char)((ACCEPTANCE_FILTER_4 >> 8) & 0xFF);
384
  RXF4SIDL = (unsigned char)((ACCEPTANCE_FILTER_4 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_4 >> 13) & 0xE0) | 0x08;
385
  RXF4SIDH = (unsigned char)((ACCEPTANCE_FILTER_4 >> 21) & 0xFF);
386
#endif
387
388
#ifdef ACCEPT_STANDARD_FILTER_5
389
  RXF5SIDL = (unsigned char)(ACCEPTANCE_FILTER_5 << 5);
390
  RXF5SIDH = (unsigned char)(ACCEPTANCE_FILTER_5 >> 3);
391
#else
392
  RXF5EIDL = (unsigned char)(ACCEPTANCE_FILTER_5 & 0xFF);  
393
  RXF5EIDH = (unsigned char)((ACCEPTANCE_FILTER_5 >> 8) & 0xFF);
394
  RXF5SIDL = (unsigned char)((ACCEPTANCE_FILTER_5 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_4 >> 13) & 0xE0) | 0x08;
395
  RXF5SIDH = (unsigned char)((ACCEPTANCE_FILTER_5 >> 21) & 0xFF);
396
#endif
397
398
//Set the acceptance masks
399
  RXM0EIDL = (unsigned char)(ACCEPTANCE_MASK_0_1 & 0xFF);  
400
  RXM0EIDH = (unsigned char)((ACCEPTANCE_MASK_0_1 >> 8) & 0xFF);
401
  RXM0SIDL = (unsigned char)((ACCEPTANCE_MASK_0_1 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_MASK_0_1 >> 13) & 0xE0) | 0x08;
402
  RXM0SIDH = (unsigned char)((ACCEPTANCE_MASK_0_1 >> 21) & 0xFF);
403
  RXM1EIDL = (unsigned char)(ACCEPTANCE_MASK_2_5 & 0xFF);  
404
  RXM1EIDH = (unsigned char)((ACCEPTANCE_MASK_2_5 >> 8) & 0xFF);
405
  RXM1SIDL = (unsigned char)((ACCEPTANCE_MASK_2_5 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_MASK_2_5 >> 13) & 0xE0) | 0x08;
406
  RXM1SIDH = (unsigned char)((ACCEPTANCE_MASK_2_5 >> 21) & 0xFF);
407
408
  CIOCON = 0x20;            //Drive TX pin Vdd when recessive, disable capture
409
410
#ifdef CAN_LOW_INT
411
  IPR3 = 0x00;
412
#else
413
  IPR3 = 0xFF;
414
#endif
415
416
#ifdef USE_LOOPBACK_MODE
417
  CANCON = (LOOPBACK_MODE & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF));          //Set loopback mode for debug purposes only
418
  while((CANSTAT & MODE_MASK) != (LOOPBACK_MODE & MODE_MASK));  //Wait until loopback mode is set
419
#else
420
  CANCON = (NORMAL_MODE & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF));          //Set normal mode
421
  while((CANSTAT & MODE_MASK) != (NORMAL_MODE & MODE_MASK));    //Wait until normal mode is set
422
#endif
423
  PIE3 = CAN_INT_BITS & 0xE3;      //Enable CAN interrupts except TX interrupts
424
//  PIR3 = 0x18;            //Set TXB1 & TXB2 int flags
425
PIR3 = 0x0;            //Set TXB1 & TXB2 int flags
426
427
//Send my address to notify our presence
428
#ifdef MY_ADDRESS_IS_STANDARD
429
  TXB0SIDL = (unsigned char)(MY_ADDRESS_IDENTIFIER << 5);
430
  TXB0SIDH = (unsigned char)(MY_ADDRESS_IDENTIFIER >> 3);    //Load address with MY_ADDRESS_IDENTIFIER standard identifier
431
  TXB0DLC = 0x00;                        //0 data bytes to send
432
  TXB0CON = 0x00;                        //Initiate transmission
433
  TXB0REQ = 1;
434
#else
435
  TXB0EIDL = (unsigned char)(MY_ADDRESS_IDENTIFIER & 0xFF);  //Load address with MY_ADDRESS_IDENTIFIER extended identifier
436
  TXB0EIDH = (unsigned char)((MY_ADDRESS_IDENTIFIER >> 8) & 0xFF);
437
  TXB0SIDL = (unsigned char)((MY_ADDRESS_IDENTIFIER >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_2 >> 13) & 0xE0) | 0x08;
438
  TXB0SIDH = (unsigned char)((MY_ADDRESS_IDENTIFIER >> 21) & 0xFF);
439
  TXB0DLC = 0x00;                        //0 data bytes to send
440
  TXB0CON = 0x00;                        //Initiate transmission
441
  TXB0REQ = 1;
442
#endif
443
  
444
  return 0;
445
}
446
447
448
/*********************************************************************
449
 * Function:        void CANISR(void)
450
 *
451
 * PreCondition:    None
452
 *
453
 * Input:           None
454
 *
455
 * Output:          None
456
 *
457
 * Side Effects:    Will modify the RX/TX interrupt flags 
458
 *                  and interrupt enable bits
459
 *
460
 * Overview:        Checks if a CAN reception/transmission was complete 
461
 *                  and if so write/read to the CAN RX/TX FIFO buffers
462
 *
463
 * Note:            This function is supposed to be called from the ISR
464
 ********************************************************************/
465
void CANISR(void)
466
{
467
  unsigned char TempCANCON;
468
469
  if(PIR3 & PIE3)
470
  {
471
    TempCANCON = CANCON;
472
    
473
    if(RXB0IF && RXB0IE)
474
    {
475
      RXB0IF = 0;    //Clear interrupt flag
476
      CANCON = CANCON & 0xF0 | RXB0Interrupt;
477
      CANGetMessage();
478
    }
479
    else if(RXB1IF && RXB1IE)
480
    {
481
      RXB1IF = 0;    //Clear interrupt flag
482
      CANCON = CANCON & 0xF0 | RXB1Interrupt;
483
      CANGetMessage();
484
    }
485
    else if(TXB0IF && TXB0IE)
486
    {
487
      CANCON = CANCON & 0xF0 | TXB0Interrupt;
488
      if(CANPutMessage())
489
        TXB0IE = 0;
490
      else
491
        TXB0IF = 0;
492
    }
493
    else if(TXB1IF && TXB1IE)
494
    {
495
      CANCON = CANCON & 0xF0 | TXB1Interrupt;
496
      if(CANPutMessage())
497
        TXB1IE = 0;
498
      else
499
        TXB1IF = 0;
500
    }
501
    else if(TXB2IF && TXB2IE)
502
    {
503
      CANCON = CANCON & 0xF0 | TXB2Interrupt;
504
      if(CANPutMessage())      //if there wasn't any more messages to send
505
        TXB2IE = 0;        //disable interrupts for TXB2 and leave TXB2IF 
506
      else            //still on so PutCAN() can reenable the interrupt and instantly vector to ISR
507
        TXB2IF = 0;        //message was sent, just clear the interrupt flag.
508
    }
509
    else if(ERRIF && ERRIE)
510
    {
511
      ERRIF = 0;      //Clear interrupt flag
512
#ifdef CAN_ERROR_HANDLER_ENABLE
513
      CANErrorHandler();
514
#endif      
515
                //No error handler implemented!!!
516
    }
517
    else if(WAKIF && WAKIE)
518
    {
519
      WAKIF = 0;      //Clear interrupt flag
520
    }
521
522
    CANCON = TempCANCON;
523
  }
524
}
525
526
527
/*********************************************************************
528
 * Function:        void CANGetMessage(void)
529
 *
530
 * PreCondition:    <WIN2:WIN0> in the CANCON register has to set
531
 *                  to reflect the desired RXB registers
532
 *
533
 * Input:           None
534
 *
535
 * Output:          None
536
 *
537
 * Side Effects:    Will modify the RX FIFO Write pointer (RXWPtr)
538
 *
539
 * Overview:        Gets the registers for a RXB and puts them in the
540
 *                  CAN Receive buffer
541
 *
542
 * Note:            Care is not taken if buffer is full
543
 ********************************************************************/
544
void CANGetMessage(void)
545
{
546
  unsigned char i;
547
  if(++RXWPtr >= RXBUF)    //If pointer overflowed
548
    RXWPtr = 0;        //Clear it
549
  
550
  for(i=0;i<14;i++)
551
  {
552
    RXMessage[RXWPtr].Data[i] = *(unsigned char *)(0xF60+i);
553
  }
554
  RXB0FUL = 0;
555
}
556
557
558
/*********************************************************************
559
 * Function:        char CANPutMessage(void)
560
 *
561
 * PreCondition:    <WIN2:WIN0> in the CANCON register has to set
562
 *                  to reflect the desired TXB registers
563
 *
564
 * Input:           None
565
 *
566
 * Output:          0 -> A new message has been put in the transmit queue
567
 *                  1 -> There was no messages in the TX buffer to send
568
 *
569
 * Side Effects:    Will modify the TX buffer´s Read pointer (TXRPtr)
570
 *
571
 * Overview:        Checks if there is any messages to transmit and if so
572
 *                  place it in the registers reflected by <WIN2:WIN0> 
573
 *
574
 * Note:            None
575
 ********************************************************************/
576
char CANPutMessage(void)
577
{
578
  unsigned char i;
579
  if(TXWPtr != TXRPtr)            //If there are any more data to send
580
  {
581
    if(++TXRPtr >= TXBUF)          //then increment the TX read pointer
582
      TXRPtr = 0;
583
    for(i=0;i<14;i++)
584
      *(unsigned char *)(0xF60+i) = TXMessage[TXRPtr].Data[i];
585
    RXB0RTRRO = 1;              //TXREQ = 1;
586
    return 0;
587
  }
588
  else
589
    return 1;
590
}
591
592
593
/*********************************************************************
594
 * Function:        char CANPut(struct CANMessage Message)
595
 *
596
 * PreCondition:    None
597
 *
598
 * Input:           A CAN message
599
 *
600
 * Output:          1 -> Failed to put a CAN on the buffer, buffer is full
601
 *                  0 -> The CAN message is put on the buffer and will be 
602
 *                       transmitted eventually 
603
 *
604
 * Side Effects:    Will modify the TX Buffer register´s Write pointer
605
 *
606
 * Overview:        Initially checks if at least one buffer slot is available
607
 *                  and if so push the requested message in the buffer.
608
 *                  Checks if the TX modules are idle and if they are, reactivate one.
609
 *
610
 * Note:            None
611
 ********************************************************************/
612
char CANPut(struct CANMessage Message)
613
{
614
  unsigned char TempPtr, i;
615
  if(TXWPtr == TXRPtr-1 || (TXWPtr == TXBUF-1 && TXRPtr == 0))  //if all transmit buffers are full return 1
616
    return 1;
617
    
618
  //Do not modify the TX pointer until the message has been successfully copied so the CANISR don't
619
  //send a message that isn't ready
620
  if(TXWPtr >= TXBUF-1)          //check if transmit write pointer will overflow
621
  {
622
    TempPtr = 0;              //and post clear write pointer
623
  }
624
  else
625
  {
626
    TempPtr = TXWPtr+1;              //and postincrement write pointer
627
  }
628
  
629
  if(Message.NoOfBytes > 8)          //Ensure we don't handle more than 8 bytes
630
    Message.NoOfBytes = 8;  
631
    
632
  TXMessage[TempPtr].Specific.TXBDLC.Byte = Message.NoOfBytes;        //Set the data count
633
634
  if(!Message.Remote)      //If dataframe
635
  {
636
    TXMessage[TempPtr].Specific.TXBDLC.Bits.TXRTR = 0;                //Clear the Remote Transfer Request bit
637
    
638
    for(i = 0; i < Message.NoOfBytes; i++)  //Load data registers
639
    {
640
      TXMessage[TempPtr].Specific.TXBD.Array[i] = Message.Data[i];
641
    }
642
  }
643
  else                      //Remote frame
644
  {
645
    TXMessage[TempPtr].Specific.TXBDLC.Bits.TXRTR = 1;                //Set TXRTR bit
646
  }
647
  if(Message.Ext)            //Extended identifier
648
  {
649
    TXMessage[TempPtr].Specific.TXBEIDL.Byte = (unsigned char)(Message.Address & 0xFF);      // Put address <7:0> in EIDL
650
    TXMessage[TempPtr].Specific.TXBEIDH.Byte = (unsigned char)((Message.Address >> 8) & 0xFF);  // Put address <15:8> in EIDH
651
    TXMessage[TempPtr].Specific.TXBSIDL.Byte = (unsigned char)((Message.Address >> 16) & 0x03) | (unsigned char)((Message.Address >> 13) & 0xE0);
652
    TXMessage[TempPtr].Specific.TXBSIDH.Byte = (unsigned char)((Message.Address >> 21) & 0xFF);
653
    TXMessage[TempPtr].Specific.TXBSIDL.Bits.EXIDE = 1;
654
  }
655
  else                      //Standard identifier
656
  {
657
    TXMessage[TempPtr].Specific.TXBSIDL.Byte = (unsigned char)((Message.Address << 5) & 0xFF);  //Put address <2:0> in SIDL
658
    TXMessage[TempPtr].Specific.TXBSIDH.Byte = (unsigned char)((Message.Address >> 3) & 0xFF);  //Put address <10:3> in SIDH
659
    TXMessage[TempPtr].Specific.TXBSIDL.Bits.EXIDE = 0;
660
  }
661
  TXMessage[TempPtr].Specific.TXBCON.Byte = Message.Priority & 0x03;  //Set the internal priority of the data frame
662
  
663
  TXWPtr = TempPtr;
664
665
  //Reenable an interrupt if it is idle, it doesn't matter if another TX source caught the pending message
666
  //before the source that is enabled here does since the interrupt CHECKS if there are any messages pending
667
  //and if the buffer is empty, it will disable itself again.
668
  if(!TXB0IE)      //TXB0 is idle
669
    TXB0IE = 1;    //enable TXB0 to fire an interrupt to send the pending message
670
  else if(!TXB1IE)    //else if TXB1 is idle
671
    TXB1IE = 1;    //same procedure
672
  else if(!TXB2IE)    //finally try TXB2
673
    TXB2IE = 1;  
674
675
  return 0;
676
}
677
678
679
/*********************************************************************
680
 * Function:        char CANRXMessageIsPending(void)
681
 *
682
 * PreCondition:    None
683
 *
684
 * Input:           None
685
 *
686
 * Output:          1 -> At least one received message is pending in the RX buffer
687
 *                  0 -> No received messages are pending
688
 *
689
 * Side Effects:    None
690
 *
691
 * Overview:        Checks if the RX Write pointer is equal to RX Read pointer and
692
 *                  if so returns 0, else returns 1
693
 *
694
 * Note:            Since no care is taken if the buffer overflow
695
 *                  this function has to be polled frequently to
696
 *                  prevent a software receive buffer overflow
697
 ********************************************************************/
698
char CANRXMessageIsPending(void)
699
{
700
  if(RXWPtr != RXRPtr)
701
    return 1;
702
  else
703
    return 0;
704
}
705
706
707
708
/*********************************************************************
709
 * Function:        struct CANMessage CANGet(void)
710
 *
711
 * PreCondition:    An unread message has to be in the buffer
712
 *                  use RXCANMessageIsPending(void) prior to 
713
 *                  calling this function in order to determine
714
 *                  if an unread message is pending.
715
 *
716
 * Input:           None
717
 *
718
 * Output:          The received message
719
 *
720
 * Side Effects:    Will modify the RX Buffer register´s Read pointer
721
 *
722
 * Overview:        Pops the the first message of the RX buffer
723
 *
724
 * Note:            None
725
 ********************************************************************/
726
struct CANMessage CANGet(void)
727
{
728
  struct CANMessage ReturnMessage;
729
  unsigned char TempPtr, i;
730
731
  /*Do not modify the RX pointer until the message has been successfully
732
    copied to prevent ISR to overwrite it (Note. this is not implemented in the ISR yet)*/
733
  if(RXRPtr >= RXBUF-1)          //Check if pointer will overflow
734
  {
735
    TempPtr = 0;
736
  }
737
  else
738
  {
739
    TempPtr = RXRPtr+1;
740
  }
741
  
742
  ReturnMessage.NoOfBytes = RXMessage[TempPtr].Specific.RXBDLC.Byte & 0x0F;          //copy data count
743
  if(RXMessage[TempPtr].Specific.RXBCON.Bits.RXRTRRO)  //Remote frame request
744
  {
745
    ReturnMessage.Remote = 1;
746
  }
747
  else        //Data frame 
748
  {
749
    ReturnMessage.Remote = 0;                  //Clear remote flag
750
    for(i = 0; i < ReturnMessage.NoOfBytes; i++)        //copy data content
751
      ReturnMessage.Data[i] = RXMessage[TempPtr].Specific.RXBD.Array[i];
752
  }
753
  CANCON = CANCON & 0xF0;
754
  
755
  ReturnMessage.Address = (unsigned int)(RXMessage[TempPtr].Specific.RXBSIDH.Byte) << 3;      //Load the standard identifier into the address
756
  ReturnMessage.Address |= (RXMessage[TempPtr].Specific.RXBSIDL.Byte >> 5);
757
758
  if(RXMessage[TempPtr].Specific.RXBSIDL.Bits.EXID)        //Extended identifier
759
  {
760
    ReturnMessage.Ext = 1;                    //Set the extended identifier flag
761
    ReturnMessage.Address = (ReturnMessage.Address << 2) | (RXMessage[TempPtr].Specific.RXBSIDL.Byte & 0x03);
762
    ReturnMessage.Address = ReturnMessage.Address << 16;    //and copy the extended address 
763
    ReturnMessage.Address |= (unsigned int)(RXMessage[TempPtr].Specific.RXBEIDH.Byte) << 8;
764
    ReturnMessage.Address |= RXMessage[TempPtr].Specific.RXBEIDL.Byte;    
765
  }
766
  else                //Standard identifier
767
  {
768
    ReturnMessage.Ext = 0;    //clear the extended identifier flag
769
  }
770
  
771
  RXRPtr = TempPtr;
772
  return ReturnMessage;    
773
}
774
775
776
/*********************************************************************
777
 * Function:        void CANSetMode(unsigned char Mode)
778
 *
779
 * PreCondition:    None
780
 *
781
 * Input:           Desired CAN Mode
782
 *                  (CAN_LISTEN_MODE, CAN_LOOPBACK_MODE
783
 *                   CAN_DISABLE_MODE, CAN_NORMAL_MODE)
784
 *
785
 * Output:          None
786
 *
787
 * Side Effects:    None
788
 *
789
 * Overview:        Requests to set the desired mode and waits until
790
 *                  the mode has been set.
791
 *
792
 * Note:            If USE_LOOPBACK_MODE is defined the requested
793
 *                  mode will be loopback mode if the input is
794
 *                  Normal mode
795
 ********************************************************************/
796
void CANSetMode(unsigned char Mode)
797
{
798
#ifdef USE_LOOPBACK_MODE
799
  if(Mode == NORMAL_MODE)
800
  {
801
    CANCON = (LOOPBACK_MODE & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF));
802
    while((CANSTAT & MODE_MASK) != (LOOPBACK_MODE & MODE_MASK));  
803
  }
804
  else
805
#endif
806
  {
807
    CANCON = (Mode & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF));
808
    while((CANSTAT & MODE_MASK) != (Mode & MODE_MASK));
809
  }
810
811
}

Vielen Dank für eure Hilfe ;)

PS: wie kann man den Code so einfügen, dass man in ihm hoch und runter 
scrollen kann, ohne dass gleich der ganze Code dargestellt wird?

von mknoelke (Gast)


Lesenswert?

Oh schön, lese ich mal alles wenn ich einen langen harten Winter nix 
vorhab.
Bitte poste doch noch den Quellcode Deines Betriebssystems des 
Entwicklungsrechners plus aller Treiber.

CAN macht doch schon fast alles in Hardware.
Deine Lösung nennt sich - de BUG en.

Wird von erfahrenen Programmierern in dem unwahrscheinlichen Fall 
angewendet das Programme nicht nach dem ersten compilerdurchlauf 
vollständig fehlerfrei laufen.

Manuel Bali schrieb:
> Oder glaubt ihr, dass Problem liegt an was
> anderem?

Ja, zwischen Deinen Ohren.
Z.B. wahrscheinlich daran das Du zu lange Zeit alles blockierst während 
Du eine Nachricht auswertest.
Höchstwahrscheinlich durch zu langer Verweildauer in der IRQ.

von Manuel B. (desteini)


Lesenswert?

Ok sehr nette Antwort.

Wobei ich das mit dem Hardware-Filter tatsächlich falsch verstanden 
habe. Mein Fehler!

Im Receive Interrupt wird zuerst der ID gecheckt, falls es der Falsche 
ist, wird garnichts gemacht. Nur bei richtigem ID macht er überhaupt 
etwas. Aber dann hätte er die Nachricht ja schon empfangen -> Sprich 
daran kann es wohl nicht liegen.

Und in wie fern hilft mir der Debug Mode, wenn es nur auftritt, wenn ich 
ne Hohe Buslast hab, und verspätet. Wenn ich da von Hand durch debugge, 
ist es klar, dass er zu langsam ist.

Trotzdem Danke für die Antwort, eventuell könntest du das nächstemal auf 
deine Beleididungen verzichten ;)

von mknoelke (Gast)


Lesenswert?

Sei nicht so empfindlich, ich habe Dich nicht beleidigt.
Das der Fehler meist zwischen den Ohren zu finden ist, ist keine 
Beleidigung sondern eine anerkannte Tatsache und eine geflügelter Spruch 
unter Entwicklern.

Du kommst schon ziemlich schräg rüber wenn Du damit anfängst 
(Kurzfassung) das Du alles richtig gemacht hast, der Chip oder die LIB 
es aber einfach nicht bringen und jetzt wohl alles neu geschrieben 
werden muß.

Debuggen heißt im ursprünglichen Wortsinn den Bug, den Fehler, das 
Fehlverhalten zu identifizieren und zu entfernen.
Das hat überhaupt nix mit von Hand im Einzelschritt durchpimpern zu tun.

Meine Empfehlung wäre mal im Detail zu schauen (per pin debuging + oszi) 
welchen zeitlichen Verlauf dein Code hat und warum der Nachrichten 
verpasst.
Irgendwas in Deinem Code oder der LIB braucht zu viel Zeit und blockiert 
da was.
Herauszufinden was das ist Deine Aufgabe.
Dazu wirst Du wohl tiefer in die LIB und/oder die CAN Hardware 
einsteigen müssen.

Der PIC18F258 hat im CAN Teil umfangreiche Möglichkeiten HW RX Message 
Filter und Priorities einzurichten und Fehlerzustände abzufragen.
Wenn eine Nachricht verloren geht dann bekommt der das mit und sagt Dir 
auch was wenn Du ihm zuhörst. Geht z.B. perfekt indem Du die Chip 
Register über den Debugger anschaust.
Fehlerbit in IRQ auswerten und Breakpoint auf die Bedingung legen 
behindert nicht die normale Ausführung.

Beherrschung der Werkzeuge + Datenblatt lesen statt nur LIB einbinden 
würde ein unhöflicher Mensch jetzt sagen.
Ich natürlich nicht.

von Manuel B. (desteini)


Lesenswert?

Alles klar, dann haben wir uns wohl auf dem falschen Fuß erwischt.

Ich bin Neuling in Mikrokontroller und vorallem CAN. Ich hatte es ein 
Semester an der Uni und das mit einem anderen Mikrochip. Deshalb sorry 
wenn es falsch rüber kam, ich meinte nich, dass es nicht meine Schuld 
war.

Meine Ansicht war nur: Wenn alles mit einer geringen Buslast 
funktioniert, und alle Daten auf dem Mikrochip ankommen, ist es ein 
Problem des Controllers. (stimmt wohl auch soweit). Eine mögliche Lösung 
wäre dann wohl ein Filter, jedoch funktioniert dieser nicht wie er 
sollte.

Allerdings hab ich wirklich nicht in Betracht bezogen, dass es ein 
Problem des Codes und nicht der Settings ist. Danke dafür! Ich hab auch 
schon einen Verdacht woran es liegen kann, falls ich es morgen Testen 
kann, werde ich berichten.

Also danke mknoelke ;)

von Peter D. (peda)


Lesenswert?

Dein Codemonster wird so keiner lesen.

Wozu meinst Du, ist der Salm über dem Eingabefenster gedacht?
Natürlich zum Ignorieren.


Antwort schreiben
Wichtige Regeln - erst lesen, dann posten!

    Groß- und Kleinschreibung verwenden
    Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

von mknoelke (Gast)


Lesenswert?

Manuel Bali schrieb:
> Alles klar, dann haben wir uns wohl auf dem falschen Fuß erwischt.

Hart aber herzlich.

Glück auf...

von Manuel B. (desteini)


Lesenswert?

@Peter Danegger: Hab ich gelesen, hab aber in einem anderen Thread 
gesehen, dass der Code quasi eingefügt wurde, aber als "Scroll-Window". 
Ich dachte, dass ich das so auch machen könnte. Und dachte, dass wenn 
ich sie hinzufüge als Datei, dass man sie nur downloaden könnte und Sie 
deshalb keiner lesen würde.

Deshalb auch die Frage: Wie man den Code in das "Scroll-Window" 
verfrachten könnte...

von Manuel B. (desteini)


Lesenswert?

So gerade ausprobiert und jetzt scheint es tatsächlich zu funktionieren. 
Das Problem war, dass beim Empfang der Nachricht zwar der Interrupt 
ausgelöst wurde und die Nachricht in den Buffer gespeichert wurde, ich 
den Buffer aber nur in der Main() ausgelesen habe. Zudem war in der Main 
noch ne 100ms Schleife(Weil ich keinen Timer mehr frei hatte), die damit 
quasi das auslesen des Buffers blockierte.

Die Lösung: Einfach das auslesen des Buffers mit in den Interrupt hauen, 
und alles scheint zu funktionieren.

Also vielen Dank nochmal mknoelke!

von Peter D. (peda)


Lesenswert?

Manuel Bali schrieb:
> Zudem war in der Main
> noch ne 100ms Schleife(Weil ich keinen Timer mehr frei hatte), die damit
> quasi das auslesen des Buffers blockierte.

Das ist natürlich ein dicker Hund, dafür wirst Du ewig in der 
Programmiererhölle schmoren.

Manuel Bali schrieb:
> Die Lösung: Einfach das auslesen des Buffers mit in den Interrupt hauen,
> und alles scheint zu funktionieren.

Das ist nur ein Würg-Around.
Die saubere Lösung wäre es, den Zeitverschwender aus der Main zu nehmen.

von Manuel B. (desteini)


Lesenswert?

Haste Recht! Grad nochmal umgeschrieben, läuft jetzt auch über einen 
Interrupt Timer... Hätt ich echt auch früher machen können. Naja Ende 
jut alles jut ;)

von mknoelke (Gast)


Lesenswert?

Na siehst Du, geht doch ;-)

Diese Art von Delay Schleifen werden zwar häufig verwendet sind aber 
wirklich dreckig. 10% der Rechenpower einfach so im Gulli.

Bau Dir einen 1ms system timer und mach z.B sowas in der IRQ
--t_100ms;
if (!t_100ms) {t_100ms = 100; flag_100ms = 1;}

Das Flag wertest Du in der main aus und setzt das nach Bearbeitung 
zurück.
So brauchst Du nur einen Hardwaretimer für beliebig viele Zeiten.

von Manuel B. (desteini)


Lesenswert?

Genau so hab ichs jetzt auch umgesetzt. Zwar mit nem 100ms Timer, aber 
das passt für meine Zwecke.

Aber echt guter Tipp mit dem 1ms Timer. Werd ich ab jetzt wohl immer 
verwenden. Dann spart man sich auch noch nen 2. Timer zu setzen und die 
Sache bliebt übersichtlicher =)

learning by doing...

Danke!

von Manuel B. (desteini)


Lesenswert?

So hier nochmal die Ergänzung zum Filter Problem, dass ich nun endlich 
gelöst habe. Scheinbar mag der PIC18F258 es nicht, wenn man die Filter 
direkt mit dem initialisieren des CAN-Moduls setzt. Also muss man nach 
dem Initialisieren nochmal in den Configurationsmodus und die Filter 
setzen. Dann zurück in den OP Modus und alles sollte funktionieren.

Zudem musste ich beide Masken benutzen, damit der Filter0 wirklich 
funktionierte. Hier mein Codeausschnitt
1
CANCON = (0x9F & 0xE0) | (CANCON & 0x3F);  //Set configuration mode
2
  while((CANSTAT & 0xE0) != (0x9F & 0xE0));  //Wait until config mode is set
3
4
        RXB0CON =  0b00100000; // Buffer Overload Off, use Filter 0, only std messages
5
        RXF0SIDH = 0b00100000; // SetHighbyte for Filter0   ID=0x104
6
        RXF0SIDL = 0b10000000; //SetLowbyte and activate STD Message
7
8
        RXM0SIDH = 0b11111111; // SetHighbyte Mask0
9
        RXM0SIDL = 0b11100000; //Set Lowbyte Mask0     0xFFF
10
11
        RXM1SIDH = 0b11111111; // SetHighbyte Mask1    0xFFF
12
        RXM1SIDL = 0b11100000; //Set Lowbyte Mask1
13
        
14
        CANCON = (0x1F & 0xE0) | (CANCON & (0xE0 ^ 0xFF)); //Set Normal mode
15
    while((CANSTAT & 0xE0) != (0x1F & 0xE0));  // Wait until Normal mode is set

Eventuell hilfts ja jemandem ;)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.