Professional Documents
Culture Documents
Controller Area Network
Controller Area Network
Application Layer
Supervisor
CAN LAYERS
Data or
Control field CRC field ACK
Superposition of
error flags
Superposition of
overload flags
Figure 13.9 Overload frame
Interframe Space (1 of 2)
• Data frames and remote frames are separated from preceding
frames by the interframe space.
• Overload frames and error frames are not preceded by an
interframe space.
• The formats for interframe space is shown in Figure 13.10 and
13.11.
Suspend
Intermission Bus Idle
Transmission
Sample point
Figure 13.12 Nominal bit time
Sync seg Segment
• It is used to synchronize the various nodes on
the bus.
• An edge is expected to lie in this segment.
Prop-seg Segment
• Used to compensate for the physical delay times
within the network
• Equals twice the sum of the signal’s propagation
time on the CAN bus line, the comparator delay,
and the output driver delay
Phase_seg1 and phase_seg2
• Used to compensate for edge phase errors
• Both can be lengthened or shortened by
synchronization
Sample Point
• At the end of phase_seg1 segment.
• Users can choose to take three samples instead of one.
• A majority function determines the bit value when three
samples are taken.
• Each sample is separated by half time quantum from the
next sample.
• The time spent on determining the bit value is the
information processing time.
Time Quantum
• A fixed unit of time derived by dividing the oscillator
period by a prescaler
• Length of time segments
– sync_seg is 1 time quantum long
– prop_seg is programmable to be 1,2,…,8 time quanta long
– phase_seg1 is programmable to be 1,2,…,8 time quanta long
– phase_seg2 is programmable to be 2,3,…,8 time quanta long
• Information processing time is fixed at 2 time quanta for
the HCS12.
• The total number of time quanta in a bit time must be
programmable between 8 and 25.
Synchronization Issue
• All CAN nodes must be synchronized while receiving a
transmission.
• The beginning of each received bit must occur during each node’s
sync_seg segment.
• Synchronization is needed to compensate for the difference in
oscillator frequencies of each node, the change in propagation delay
and other factors.
• Two types of synchronizations are defined: hard synchronization
and resynchronization.
– Hard synchronization is performed at the beginning of a message frame,
when each CAN node aligns the sync_seg of its current bit time to the
recessive-to-dominant transition.
– Resynchronization is performed during the remainder of the message
frame whenever a change of bit value from recessive to dominant
occurs outside the expected sync_seg segment.
Overview of the HCS12 CAN Module (1 of 2)
• An HCS12 device may have from one to five on-chip CAN modules.
• Each CAN module has five receive buffers with FIFO storage
scheme and three transmit buffers.
• Each of the three transmit buffers may be assigned with a local
priority.
• Maskable identifier filter supports two full size extended identifier
filters (32-bit), four 16-bit filters, or eight 8-bit filters.
• The CAN module has a programmable loopback mode that supports
self-test operation.
• The CAN module has a listen-only mode for monitoring of the CAN
bus.
Overview of the HCS12 CAN Module (2 of 2)
• The CAN module has separate signaling and interrupts for all CAN
receiver and transmitter error states (warning, error passive, and
bus off).
• Clock signal for CAN bus can come from either the bus clock or
oscillator clock.
• The CAN module supports time-stamping for received and
transmitted messages
• The block diagram of a CAN module is shown in Figure 13.13.
• The CAN module requires a transceiver (e.g., MCP2551,
PCA82C250) to interface with the CAN bus.
• A typical CAN bus system is shown in Figure 13.14.
• The CAN module has a 16-bit free-running timer.
Oscillator clock CANCLK Tq clk
MUX Prescaler RxCAN
Bus clock Receive/
Transmit
Engine TxCAN
Control
and
Status
Message
Tx int. req. filtering
Configuration and
Rx int. req. registers buffering
Err. int. req.
Wake-up int. req.
wake- Low pass
up filter
HCS12
TxCAN RxCAN
Transceiver
• This register selects the synchronization jump width and the baud
rate prescale factor.
7 6 5 4 3 2 1 0
SJW1 SJW0 BRP5 BRP4 BRP3 BRP2 BRP1 BRP0
reset: 0 0 0 0 0 0 0 0
SJW1, SJW0: Synchronization jump width
00 = 1 Tq clock cycle
01 = 2 Tq clock cycle
10 = 3 Tq clock cycle
11 = 4 Tq clock cycle
BRP5~BRP0: Baud rate prescaler
000000 = 1
000001 = 2
000010 = 3
....
111110 = 63
111111 = 64
Figure 13.19 MSCAN bus timeing register 0 (CANxBTR0, x = 0, 1, 2, 3, or 4)
MSCAN Bus Timing Register 1 (CANxBTR1)
• This register provides control on phase_seg1 and phase_seg2.
• Time Segment1 consists of prop_seg and phase_seg1.
prescaler value
Bit time = --------------------- (1 + TimeSegment1 + TimeSegment2)
fCANCLK
7 6 5 4 3 2 1 0
SAMP TSEG22 TSEG21 TSEG20 TSEG13 TSEG12 TSEG11 TSEG10
reset: 0 0 0 0 0 0 0 0
SAMP: Sampling
0 = One sample per bit
1 = Three samples per bit
TSEG22~TSEG20: Time segment 2
000 = 1 Tq clock cycle
001 = 2 Tq clock cycles
....
110 = 7 Tq clock cycles
111 = 8 Tq clock cycles
TSEG13~TSEG10: Time segment 1
0000 = 1 Tq clock cycle
0001 = 2 Tq clock cycles
....
1110 = 15 Tq clock cycles
1111 = 16 Tq clock cycles
7 6 5 4 3 2 1 0
0 0 0 0 0 TXE2 TXE1 TXE0
reset: 0 0 0 0 0 1 1 1
TXE2~TXE0: Transmitter buffer empty
0 = The associated message buffer is full (loaded with a message due for
transmission).
1 = The associated message buffer is empty.
7 6 5 4 3 2 1 0
0 0 0 0 0 TXEIE2 TXEIE1 TXEIE0
reset: 0 0 0 0 0 0 0 0
TXEIE2~TXEIE0: Transmitter empty interrupt enable
0 = Disable interrupt from this buffer.
1 = A transmitter empty event causes a transmitter empty interrupt request.
• When the application has high-priority message but cannot find any
empty transmit buffer to use, it can request to abort the previous
messages that have been scheduled for transmission.
7 6 5 4 3 2 1 0
0 0 0 0 0 ABTRQ2 ABTRQ1 ABTRQ0
reset: 0 0 0 0 0 0 0 0
ABTRQ2~ABTRQ0: Abort request
0 = No abort request
1 = Abort request pending
7 6 5 4 3 2 1 0
0 0 0 0 0 ABTAK2 ABTAK1 ABTAK0
reset: 0 0 0 0 0 0 0 0
ABTAK2~ABTAK0: Abort acknowledge
0 = The message was not aborted.
1 = The message was aborted.
7 6 5 4 3 2 1 0
TSR15 TSR14 TSR13 TSR12 TSR11 TSR10 TSR9 TSR8 TSRH
reset: x x x x x x x x
7 6 5 4 3 2 1 0
TSR7 TSR6 TSR5 TSR4 TSR3 TSR2 TSR1 TSR0 TSRL
reset: x x x x x x x x
Figure 13.36 MSCAN Time stamp registers
Can Foreground Receive
Buffer Register Names
Table 13.2a CAN foreground receive buffer x variable names
Name Address Description
CANxRIDR0 $_0 CAN foreground receive buffer x identifier register 0
CANxRIDR1 $_1 CAN foreground receive buffer x identifier register 1
CANxRIDR2 $_2 CAN foreground receive buffer x identifier register 2
CANxRIDR3 $_3 CAN foreground receive buffer x identifier register 3
CANxRDSR0 $_4 CAN foreground receive buffer x data segment register 0
CANxRDSR1 $_5 CAN foreground receive buffer x data segment register 1
CANxRDSR2 $_6 CAN foreground receive buffer x data segment register 2
CANxRDSR3 $_7 CAN foreground receive buffer x data segment register 3
CANxRDSR4 $_8 CAN foreground receive buffer x data segment register 4
CANxRDSR5 $_9 CAN foreground receive buffer x data segment register 5
CANxRDSR6 $_A CAN foreground receive buffer x data segment register 6
CANxRDSR7 $_B CAN foreground receive buffer x data segment register 7
CANxRDLR $_C CAN foreground receive buffer x data length register
Note 1. x can be 0, 1, 2, or 3
2. The absolute address of each register is equal to the sum of the base address
of the CAN foreground receive buffer base x address and the address
field of the corresponding register.
CAN Foreground Transmit
Buffer Register Names
Table 13.2b CAN foreground transmit buffer x variable names
Name Address Description
CANxTIDR0 $_0 CAN foreground transmit buffer x identifier register 0
CANxTIDR1 $_1 CAN foreground transmit buffer x identifier register 1
CANxTIDR2 $_2 CAN foreground transmit buffer x identifier register 2
CANxTIDR3 $_3 CAN foreground transmit buffer x identifier register 3
CANxTDSR0 $_4 CAN foreground transmit buffer x data segment register 0
CANxTDSR1 $_5 CAN foreground transmit buffer x data segment register 1
CANxTDSR2 $_6 CAN foreground transmit buffer x data segment register 2
CANxTDSR3 $_7 CAN foreground transmit buffer x data segment register 3
CANxTDSR4 $_8 CAN foreground transmit buffer x data segment register 4
CANxTDSR5 $_9 CAN foreground transmit buffer x data segment register 5
CANxTDSR6 $_A CAN foreground transmit buffer x data segment register 6
CANxTDSR7 $_B CAN foreground transmit buffer x data segment register 7
CANxTDLR $_C CAN foreground transmit buffer x data length register
CANxTBPR $_D CAN foreground transmit buffer x priority register
CANxTSRH $_E CAN foreground transmit buffer x time stamp register high
CANxTSRL $_F CAN foreground transmit buffer x time stamp register low
Note 1. x can be 0, 1, 2, or 3
2. The absolute address of each register is equal to the sum of the base
address of the CAN foreground transmit buffer x and the address field of the
corresponding register.
Transmit Storage Structure
Tx0
• Multiple messages TXE0
can be set up in
TxBG
advance and achieve PRIO
real-time
performance.
• A transmit buffer is Tx1
TXE1
made accessible to MSCAN
CPU bus
TxFG
the user by writing
appropriate value into PRIO
the CANxTBSEL
register. Tx2
TXE2
• The transmit buffer
organization is shown
in Figure 13.37. TxBG PRIO
structure. RX1
RxBG
MSCAN RX2
• The message buffers RX3
are alternately mapped RX4
RXF
into a single memory
area referred to as the CPU bus
RxFG
foreground receive
buffer.
• The application reads Figure 13.38 User model for receive buffer organization
CLKSRC
Oscillator clock
1 2 3 n
CAN_H
RT
RT = 120
(120
CAN_L
voltage
5V
CAN_H
3.5V
2.5V
CAN_L
1.5V
0V
Recessive Dominant Recessive
TXD
VDD Thermal
Dominant
Detect shutdown
TxD 1
Driver
control
Slope power- 7 CANH
Rs control on reset VDD
8
RxD Receiver
4
GND
6
CANL
Reference
VREF
5 Voltage
20
Slew rate V/uS
15
10
0
10 20 30 40 49 60 70 80 90 100 110
Resistance (K)
CAN_H
• In summary,
Prescaler =2
Nominal bit time = 16
Prop_seg =7
Sync_seg =1
Phase_seg1 =4
Phase_seg2 =4
RJW =4
Oscillator tolerance = 0.98%
MSCAN Configuration
• Timing parameters for the CAN module need only be set once after reset.
• Other parameters such as acceptance filters may be changed after reset
configuration.
• Example 13.3 Write a program to configure the MSCAN module 1 after
reset with the timing parameters in Example 13.1 and the following setting:
– Enable wakeup
– Disable time stamp
– Select oscillator as the clock source to the MSCAN
– Disable loopback mode, disable listen only mode
– Take one sample per bit
– Acceptance messages with extended identifiers that start with T1 and P1 (use
two 32-bit filters)
• Solution:
openCan1 bset CAN1CTL1,CANE ; required after reset
bset CAN1CTL0,INITRQ ; request to enter initialization mode
w1 brclr CAN1CTL1,INITAK,w1 ; make sure initialization mode is entered
movb #$84,CAN1CTL1 ; enable CAN1,select oscillator as clock
; source, enable wake up filter
movb #$41,CAN1BTR0 ; set jump width to 2 Tq, prescaler set to 2
movb #$18,CAN1BTR1 ; set phase_seg2 to 2 Tq, phase_seg1 to 2 Tq,
; set prop_seg to 7 Tq
movb #$54,CAN1IDAR0 ; acceptance identifier 'T'
movb #$3C,CAN1IDAR1 ; acceptance identifier '1‘ (IDE bit = 1)
movb #$40,CAN1IDAR2 ; "
movb #$00,CAN1IDAR3 ; "
movb #$00,CAN1IDMR0 ; acceptance mask for extended identifier "T1"
movb #$00,CAN1IDMR1 ; "
movb #$3F,CAN1IDMR2 ; "
movb #$FF,CAN1IDMR3 ; "
movb #$50,CAN1IDAR4 ; acceptance identifier 'P'
movb #$3C,CAN1IDAR5 ; acceptance identifier '1‘ (IDE bit = 1)
movb #$40,CAN1IDAR6 ; "
movb #$00,CAN1IDAR7 ; "
movb #$00,CAN1IDMR4 ; acceptance mask for extended identifier "P1"
movb #$00,CAN1IDMR5 ; "
movb #$3F,CAN1IDMR6 ; "
movb #$FF,CAN1IDMR7 ; "
clr CAN1IDAC ; set two 32-bit filter mode
bclr CAN1CTL0,INITRQ ; leave initialization mode
movb #$24,CAN1CTL0 ; stop clock on wait mode, enable wakeup
rts
C Function to Initialize the CAN1 Module
void openCan1(void)
{
CAN1CTL1 |= CANE; /* enable CAN, required after reset */
CAN1CTL0 |= INITRQ; /* request to enter initialization mode */
while(!(CAN1CTL1&INITAK)); /* wait until initialization mode is entered */
CAN1CTL1 = 0x84; /* enable CAN1, select oscillator as MSCAN clock
source, enable wakeup filter */
CAN1BTR0 = 0x41; /* set SJW to 2, set prescaler to 2 */
CAN1BTR1 = 0x18; /* set phase_seg2 to 2Tq, phase_seg1 to 2Tq,
prop_seg to 7 Tq */
CAN1IDAR0 = 0x54; /* set acceptance identifier "T1" */
CAN1IDAR1 = 0x3C; /* " */
CAN1IDAR2 = 0x40; /* " */
CAN1IDAR3 = 0x00; /* " */
CAN1IDMR0 = 0x00; /* acceptance mask for "T1" */
CAN1IDMR1 = 0x00; /* " */
CAN1IDMR2 = 0x3F; /* " */
CAN1IDMR3 = 0xFF; /* " */
CAN1IDAR4 = 0x50; /* set acceptance identifier "P1" */
CAN1IDAR5 = 0x3C; /* " */
CAN1IDAR6 = 0x40; /* " */
CAN1IDAR7 = 0x00; /* " */
CAN1IDMR4 = 0x00; /* acceptance mask for "P1" */
CAN1IDMR5 = 0x00; /* " */
CAN1IDMR6 = 0x3F; /* " */
CAN1IDMR7 = 0xFF; /* " */
CAN1IDAC = 0x00; /* select two 32-bit filter mode */
CAN1CTL0 &= ~INITRQ; /* exit initialization mode *
CAN1CTL0 = 0x24; /* stop clock on wait mode, enable wake up */
}
• Example 13.4 Write an instruction sequence to change the configuration of the CAN1
module so that it would accept messages with standard identifier starting with letter ‘T’
or ‘P’.
• Solution:
- This reconfiguration is done in normal mode.
- Need to wait until the transmit buffer is empty
- Need to place CAN1 in sleep mode
Instruction Sequence to change the CAN1
Configuration
ct1 brset CAN1TFLG,$07,tb_empty ; wait until all transmit buffers are empty
bra ct1
tb_empty bset CAN1CTL0,SLPRQ ; request to enter sleep mode
ct2 brclr CAN1CTL1,SLPAK,ct2 ; wait until sleep more is entered
bset CAN1CTL0,INITRQ ; request to enter initialization mode
ct3 brclr CAN1CTL1,INITAK,ct3 ; wait until initialization mode is entered
movb #$10,CAN1IDAC ; select 4 16-bit acceptance mode
movb #$54,CAN1IDAR0 ; set up filter for letter 'T' for standard
movb #0,CAN1IDAR1 ; identifier (IDE bit = 0)
movb #$50,CAN1IDAR2 ; set up filter for letter 'P' for standard
clr CAN1IDAR3 ; identifier (IDE bit = 0)
clr CAN1IDMR0 ; acceptance mask for 'T'
movb #$F7,CAN1IDMR1 ; check IDE bit only (must be 0)
clr CAN1IDMR2 ; acceptance mask for 'P'
movb #$F7,CAN1IDMR3 ; check IDE bit only (must be 0)
movb #$54,CAN1IDAR4 ; set up filter for letter 'T' for standard
movb #0,CAN1IDAR5 ; identifier
movb #$50,CAN1IDAR6 ; set up filter for letter 'P' for standard
clr CAN1IDAR7 ; identifier
clr CAN1IDMR4 ; acceptance mask for 'T'
movb #$F7,CAN1IDMR5 ; check IDE bit only (must be 0)
clr CAN1IDMR6 ; acceptance mask for 'P'
movb #$F7,CAN1IDMR7 ; check IDE bit only (must be 0)
bclr CAN1CTL0,INITRQ ; exit initialization mode
bclr CAN1CTL0,SLPRQ ; exit sleep mode
Data Transmission and Reception in MSCAN
• Data transmission in CAN bus can be driven by polling method or interrupts.
• When data to be transmitted is small and infrequent, polling method is quite
good.
• Data arrival is usually less predictable. It is more convenient to use
interrupt-driven method for data reception.
– Example 13.5 Write a function to send out the message stored at a buffer pointed
to by index register X from the CAN1 module. The function should find an
available buffer to hold the message to be sent out.
– Solution:
tbuf equ 0 ; tbuf offset from top of stack
snd2can1 pshy
pshb
leas -1,sp ; allocate one byte for local variable
sloop1 brset CAN1TFLG,$01,tb0 ; is transmit buffer 0 empty?
brset CAN1TFLG,$02,tb1 ; is transmit buffer 1 empty?
brset CAN1TFLG,$04,tb2 ; is transmit buffer 2 empty?
bra sloop1 ; if necessary wait until one buffer is empty
tb0 movb #0,tbuf,sp ; mark transmit buffer 0 empty
bra tcopy
tb1 movb #1,tbuf,sp ; mark transmit buffer 1 empty
bra tcopy
tb2 movb #2,tbuf,sp ; mark transmit buffer 2 empty
tcopy movb CAN1TFLG,CAN1TBSEL ; make the empty transmit buffer accessible
ldy #CAN1TIDR0 ; set y to point to the start of the transmit buffer
ldab #7 ; always copy 7 words (place word count in B)
cploop movw 2,x+,2,y+
dbne b,cploop
ldab tbuf,sp
cmpb #0
beq istb0
cmpb #1
beq istb1
movb #$04,CAN1TFLG ; mark buffer 2 ready for transmission
bra dcopy
istb0 movb #$01,CAN1TFLG ; mark buffer 0 ready for transmission
bra dcopy
istb1 movb #$02,CAN1TFLG ; mark buffer 1 ready for transmission
dcopy leas 1,sp ; deallocate local variables
pulb
puly
rts
C Function for CAN1 Data Transmission
void snd2can1(char *ptr)
{
int tb,i,*pt1,*pt2;
pt1 = (int *)ptr; /* convert to integer pointer */
while(1) { /* find an empty transmit buffer */
if(CAN1TFLG & 0x01){
tb = 0;
break;
}
if(CAN1TFLG & 0x02){
tb = 1;
break;
}
if(CAN1TFLG & 0x04){
tb = 2;
break;
}
}
CAN1TBSEL = CAN1TFLG; /* make empty transmit buffer accessible */
pt2 = (int *)&CAN1TIDR0; /* pt2 points to the IDR0 of TXFG */
for (i = 0; i < 7; i++) /* copy the whole transmit buffer */
*pt2++ = *pt1++;
if (tb == 0)
CAN1TFLG = 0x01; /* mark buffer 0 ready for transmission */
else if (tb == 1)
CAN1TFLG = 0x02; /* mark buffer 1 ready for transmission */
else
CAN1TFLG = 0x04; /* mark buffer 2 ready for transmission */
}
• Example 13.6 Write a program to send out the string “3.5 V” from CAN1
and use “V1” as its identifier. Set transmit buffer priority to the highest.
• Solution:
org $1000
tbuf0 ds 16
org $1500
movb #$56,tbuf0 ; identifier V1
movb #$3C,tbuf0+1 ; "
movb #$40,tbuf0+2 ; "
movb #0,tbuf0+3 ; “
movb #$34,tbuf0+4 ; data "3"
movb #$2E,tbuf0+5 ; data "."
movb #$35,tbuf0+6 ; data "5"
movb #$20,tbuf0+7 ; data " "
movb #$56,tbuf0+8 ; data "V"
movb #5,tbuf0+12 ; data length (=5)
movb #0,tbuf0+13 ; set transmit buffer priority to highest
ldx #tbuf0
jsr snd2can1 ; call subroutine to perform the actual transmission
rts
swi
end
C Program that Sends Out “3.5 V” from CAN1
#include “c:\egnu091\include\hcs12.h”
void snd2can1(char *ptr);
int main(void)
{
char tbuf0[16];
tbuf0[0] = 'V'; /* identifier V1 */
tbuf0[1] = 0x3C; /* " */
tbuf0[2] = 0x40; /* " */
tbuf0[3] = 0; /* " */
tbuf0[4] = '3'; /* letter 3 */
tbuf0[5] = '.'; /* character . */
tbuf0[6] = '5'; /* letter 5 */
tbuf0[7] = 0x20; /* space */
tbuf0[8] = 'V'; /* letter V */
tbuf0[12] = 5; /* data length */
tbuf0[13] = 0; /* tbuf0 priority */
snd2can1(tbuf0);
return 0;
}
• Example 13.7 Assuming that the CAN1 receiver has been set up to
accept messages with extended identifiers “T1” and “V1”. The filter 0 is set
up to accept the identifier started with “T1,” whereas the filter 1 is set up to
accept the identifier started with “V1”. Write the interrupt handling routine for
the RXF interrupt. If the acceptance is caused by filter 0, the RXF service
routine would display the following message on a 20 2 LCD:
Temperature is
xxx.yoF
If the acceptance of the message is caused by filter 1, the RXF interrupt service
routine would display the following message:
Voltage is
x.y V
• Solution:
- The interrupt service routine checks the RXF flag of the CAN1RFLG register to
make sure that the interrupt is caused by the RXF flag.
- CAN data reception is performed by the interrupt service routine.
can1Rx_ISR brset CAN1RFLG,RXF,RxfSet ; is the RXF flag set to 1?
rti ; if not, do nothing
RxfSet ldab CAN1IDAC ; check into IDHIT bits
andb #$07 ; mask out higher 5 bits
beq hit0 ; filter 0 hit?
cmpb #1 ; filter 1 hit?
beq hit1
rti ; not hit 0 nor hit 1, do thing
hit0 ldab CAN1RDLR ; get the byte count of incoming data
beq rxfDone ; byte count 0, return
ldx #t1_line1 ; output "Temperature is"
jsr puts2lcd ; "
ldx #CAN1RDSR0
outLoop1 ldaa 1,x+ ; output one byte at a time
jsr putc2lcd ; "
dbne b,outLoop1 ; "
rti
hit1 ldab CAN1RDLR ; get the byte count of incoming data
beq rxfDone ; byte count 0, return
ldx #v1_line1 ; output "Voltage is"
jsr puts2lcd ; "
ldx #CAN1RDSR0 ; x points to data segment register 0
outLoop2 ldaa 1,x+
jsr putc2lcd
dbne b,outLoop2
rxfDone rti
t1_line1 fcc "Temperature is"
dc.b 0
v1_line1 fcc "Voltage is"
dc.b 0
C Program for the Interrupt-driven Data Reception in
CAN Bus
#include “c:\egnu091\include\hcs12.h”
#include “c:\egnu091\include\vectors12.h”
#include “c:\egnu091\include\delay.c”
#include “c:\egnu091\include\lcd_util_SSE256.c”
#define INTERRUPT __attribute__((interrupt))
void INTERRUPT RxISR(void);
void openCan1(void);
char *t1Msg = "Temperature is";
char *v1Msg = "Voltage is";
int main (void)
{
UserMSCAN1Rx = (unsigned short) &RxISR;
openCan1();
openlcd();
CAN1RIER = 0x01; /* enable CAN1 RXF interrupt only */
asm("cli");
while(1); /* wait for RXF interrupt */
return 0;
}
void INTERRUPT RxISR (void)
{
char tmp,i,*ptr;
if (!(CAN1RFLG & RXF)) /* interrupt not caused by RXF, return */
return;
tmp = CAN1IDAC & 0x07; /* extract filter hit info */
if (tmp == 0) { /* filter 0 hit */
if (CAN1RDLR==0) /* data length 0, do nothing */
return;
cmd2lcd(0x80); /* set LCD cursor to first row */
puts2lcd(t1Msg); /* output "Temperature is" on LCD */
cmd2lcd(0xC0); /* set LCD cursor to second row */
ptr = (char *)&CAN1RDSR0; /* ptr points to the first data byte */
for (i = 0; i < CAN1RDLR; i++)
putc2lcd(*ptr++); /* output temperature value on the LCD 2nd row */
}
else if (tmp == 1) { /* filter 1 hit */
if(CAN1RDLR == 0) /* data length 0, do nothing */
return;
cmd2lcd(0x80); /* set LCD cursor to first row */
puts2lcd(v1Msg); /* output "Voltage is" on the 1st row of LCD */
cmd2lcd(0xC0); /* set LCD cursor to second row */
ptr = (char *)&CAN1RDSR0; /* PTR points to the first data byte */
for(i = 0; i < CAN1RDLR; i++)
putc2lcd(*ptr++); /* output voltage value on the 2nd row of LCD */
}
else asm(“nop”); /* other hit, do nothing */
}
• Example 13.8 Write a C program to be run in a CAN environment using
the same timing parameters as computed in Example 13.1. Each CAN
node measures the voltage (in the range from 0 to 5 V) and sends it out
from the CAN bus and also receives the voltage message sent over the
CAN bus by other nodes. Configure the CAN1 module to receive messages
having an extended identifier started with “V1”. The transmission and
reception are to be proceeded as follows:
- The program measures the voltage of the AN7 pin every 200 milliseconds and
sends out the value with identifier “V1”. The voltage is represented in the format of
“x.y V”. After sending out a message, the program outputs the following message on
the first row of the LCD:
Sent: x.y V
- Message reception is interrupt driven. Whenever a new message is accepted, the
program outputs the following message on the second row of the LCD:
Received x.y V
• Solution:
#include “c:\egnu091\include\hcs12.h”
#include “c:\egnu091\include\delay.c”
#include “c:\egnu091\include\vectors12.h”
#include “c:\egnu091\include\lcd_util_SSE256.c”
#define INTERRUPT __attribute__((interrupt))
char *msg1 = "Sent: ";
char *msg2 = "Received: ";
void INTERRUPT RxISR(void);
void openAD0(void);
void wait20us (void);
void OpenCan1(void);
void MakeBuf(char *pt1, char *pt2);
void snd2can1(char *ptr);
int main(void)
{
char buffer[6]; /* to hold measured voltage */
char buf[16]; /* transmit data buffer */
int temp;
UserMSCAN1Rx = (unsigned short)&RxISR; /* set up interrupt vector */
openlcd(); /* configure LCD kit */
OpenCan1(); /* configure CAN1 module */
buffer[1] = '.'; /* decimal point */
buffer[3] = 0x20; /* space character */
buffer[4] = 'V'; /* volt character */
buffer[5] = 0; /* null character */
openAD0(); /* configure AD0 module */
CAN1RIER = 0x01; /* enable RXF interrupt only */
asm("cli"); /* enable interrupt globally */
while(1) {
ATD0CTL5 = 0x87; /* convert AN7, result right justified */
while(!(ATD0STAT0 & SCF)); /* wait for conversion to complete */
buffer[0] = 0x30 + (ATD0DR0*10)/2046; /* integral digit of voltage */
temp = (ATD0DR0 * 10)%2046; /* find the remainder */
buffer[2] = 0x30 + (temp * 10)/2046; /* compute the fractional digit */
MakeBuf(&buf[0],&buffer[0]); /* format data for transmission */
snd2can1(&buf[0]); /* send out voltage on CAN bus */
cmd2lcd(0x80); /* set LCD cursor to first row */
puts2lcd(msg1); /* output the message "sent: x.y V" */
puts2lcd(&buffer[0]); /* " */
delayby100ms(2); /* wait for messages to arrive for .2 seconds */
}
return 0;
}
/*******************************************************************************************/
/* The following function formats a buffer into the structure of a CAN transmit */
/* buffer so that it can be copied into any empty transmit buffer for transmission. */
/*******************************************************************************************/
void MakeBuf(char *pt1, char *pt2)
{
char i;
*pt1 = 'V'; /* set "V1" as the transmit identifier */
*(pt1+1) = 0x3C; /* " */
*(pt1+2) = 0x40; /* " */
*(pt1+3) = 0; /* " */
for(i = 4; i < 9; i++) /* copy voltage data */
*(pt1 + i) = *(pt2 + i - 4);
*(pt1+12) = 5; /* set data length to 5 */
}
/************************************************************************************/
/* The following function handles the RXF interrupt. It checks if the RXF */
/* is set. If not, return. It also ignores the RTR request. */
/************************************************************************************/
void INTERRUPT RxISR (void)
{
char tmp,i,*ptr;
if (!(CAN1RFLG & RXF)) /* interrupt not caused by RXF, return */
return;
tmp = CAN1IDAC & 0x07; /* extract filter hit info */
if (tmp == 0){ /* filter 0 hit */
if (CAN1RDLR==0) /* if data length is 0, do nothing */
return;
cmd2lcd(0xC0); /* set LCD cursor to second row */
puts2lcd(msg2); /* output "received: " */
ptr = (char *)&CAN1RDSR0; /* ptr points to the first data byte */
for (i = 0; i < CAN1RDLR; i++)
putc2lcd(*ptr++); /* output "x.y V" */
return;
}
else return; /* other hit, do nothing */
}
void openAD0 (void)
{
int i;
ATD0CTL2 = 0xE0;
delayby10us(2);
ATD0CTL3 = 0x0A; /* perform one conversion */
ATD0CTL4 = 0x25; /* 4 cycles sample time, prescaler set to 12 */
}
void OpenCan1(void)
{
CAN1CTL1 |= CANE; /* enable CAN, required after reset */
CAN1CTL0 |= INITRQ; /* request to enter initialization mode */
while(!(CAN1CTL1&INITAK)); /* wait until initialization mode is entered */
CAN1CTL1 = 0x84; /* enable CAN1, select oscillator as MSCAN clock
source, enable wakeup filter */
CAN1BTR0 = 0x41; /* set SJW to 2, set prescaler to 2 */
CAN1BTR1 = 0x18; /* set phase_seg2 to 2Tq, phase_seg1 to 2Tq,
prop_seg to 7 Tq */
CAN1IDAR0 = 0x56; /* set acceptance identifier "V1" */
CAN1IDAR1 = 0x3C; /* " */
CAN1IDAR2 = 0x40; /* " */
CAN1IDAR3 = 0x00; /* " */
CAN1IDMR0 = 0x00; /* acceptance mask for "V1" */
CAN1IDMR1 = 0x00; /* " */
CAN1IDMR2 = 0x3F; /* " */
CAN1IDMR3 = 0xFF; /* " */
CAN1IDAR4 = 0x00; /* set acceptance identifier NULL */
CAN1IDAR5 = 0x00; /* " */
CAN1IDAR6 = 0x00; /* " */
CAN1IDAR7 = 0x00; /* " */
CAN1IDMR4 = 0x00; /* acceptance mask for NULL */
CAN1IDMR5 = 0x00; /* " */
CAN1IDMR6 = 0x00; /* " */
CAN1IDMR7 = 0x00; /* " */
CAN1IDAC = 0x00; /* select two 32-bit filter mode */
CAN1CTL0 &= ~INITRQ; /* exit initialization mode */
CAN1CTL0 = 0x24; /* stop clock on wait mode, enable wake up */
}
void snd2can1(char *ptr)
{
int tb,i,*pt1,*pt2;
pt1 = (int *)ptr; /* convert to integer pointer */
while(1) {
if(CAN1TFLG & 0x01){
tb = 0;
break;
}
if(CAN1TFLG & 0x02){
tb = 1;
break;
}
if(CAN1TFLG & 0x04){
tb = 2;
break;
}
}
CAN1TBSEL = CAN1TFLG; /* make empty transmit buffer accessible */
pt2 = (int *)&CAN1TIDR0; /* pt2 points to the IDR0 of TXFG */
for (i = 0; i < 7; i++) /* copy the whole transmit buffer */
*pt2++ = *pt1++;
if (tb == 0)
CAN1TFLG = 0x01; /* mark buffer 0 ready for transmission */
else if (tb == 1)
CAN1TFLG = 0x02; /* mark buffer 1 ready for transmission */
else
CAN1TFLG = 0x04; /* mark buffer 2 ready for transmission */
}