Académique Documents
Professionnel Documents
Culture Documents
************************************************************************
******
C167CR CAN Ap. Note project
Main - a_canx1
This is an example program showing how to use the CAN interface on the
Keil
MCB167 evaluation board.
/
************************************************************************
******
Setup CAN controller
Returns: nothing
------------------------------------------------------------------------
-----*/
void
setup_can(void)
{
begin_can_init();
/* These mask values tell the CAN controller that all bits in a
message id. are significant when comparing the id of a received
message
to the id's in the arbitration registers of the message objects.
*/
CAN_MASK_SHORT = 0xffff;
CAN_UMASK_LONG = 0xffff;
CAN_LMASK_LONG = 0xf8ff;
CAN_MSGOBJ[TIME_MO].msg_ctl = MSGVAL_CLR;
CAN_MSGOBJ[TIME_MO].arbitr = ARBITR(CAN_TIME_MSG);
CAN_MSGOBJ[TIME_MO].msg_cfg = MSG_CFG(LEN_CAN_TIME_MSG,
CANDIR_TRANSMIT, 0);
/* We're not initializing the data field right now, so we set
CPUUPD to prevent the message from being transmitted in
response to a remote frame.
*/
CAN_MSGOBJ[TIME_MO].msg_ctl =
/* clear bits set bits */
INTPND_CLR &
RXIE_CLR &
TXIE_CLR &
MSGVAL_SET &
NEWDAT_CLR &
CPUUPD_SET &
TXRQ_CLR &
RMTPND_CLR;
/
************************************************************************
******
main
The CAN controller will transmit the time stamp message when it receives
a
remote frame for it, without any intervention from the CPU.
Returns: never
------------------------------------------------------------------------
-----*/
void
main(void)
{
printf("Program A start\n");
/* Set up */
setup_can(); /* set up CAN interface */
init_timer(); /* initialize timing */
/* Run */
while (1) { /* infinite loop */
unsigned long t;
t = timer();
update_can_transmit_message(TIME_MO, &t, LEN_CAN_TIME_MSG);
/* Put the processor in idle mode to conserve power.
The next interrupt (from the timer) will wake it up again.
*/
_idle_();
}
}
This is an example program showing how to use the CAN interface on the
Keil
MCB167 evaluation board.
/
************************************************************************
******
Setup CAN controller
Returns: nothing
------------------------------------------------------------------------
-----*/
void
setup_can(void)
{
begin_can_init();
/* These mask values tell the CAN controller that all bits in a
message id. are significant when comparing the id of a received
message
to the id's in the arbitration registers of the message objects.
*/
CAN_MASK_SHORT = 0xffff;
CAN_UMASK_LONG = 0xffff;
CAN_LMASK_LONG = 0xf8ff;
/
************************************************************************
******
main
Returns: never
------------------------------------------------------------------------
-----*/
void
main(void)
{
unsigned long time_value;
unsigned long last_printed_time_value = 0ul - 1000ul;
/* Main loop */
while (1) {
/* Request time message.
We're going to detect receipt of the message by examining
NEWDAT
(there are other ways), so also clear NEWDAT to make sure we
process
a new time message, not an old one that has been waiting around
unprocessed.
*/
CAN_MSGOBJ[TIME_MO].msg_ctl = TXRQ_SET & NEWDAT_CLR;
copy_received_can_message(TIME_MO, &time_value);
/* If this time message is at least one second later than the last
one
that was output then output it.
*/
if (time_value - last_printed_time_value >= 1000) {
printf("%lu\n", time_value);
last_printed_time_value = time_value;
}
}
}
/
************************************************************************
******
C167CR CAN Ap. Note project
Header file for timing
void
init_timer(void);
unsigned long
timer(void);
This is an example program showing how to use the CAN interface on the
Keil
MCB167 evaluation board.
If you change the values of any of these macros, you need to also
change
TIMER_UNITS_PER_SECOND in timer.h to match the new timer interrupt
frequency. A compile-time check that TIMER_UNITS_PER_SECOND is the
correct value follows these macros.
*/
#define RELOAD_VALUE 624 /* value for CAPREL register */
#define PRESCALE_SELECTION 3 /* value for T6I field of T6CON
register */
#define CPU_FREQUENCY_HZ 20000000 /* CPU frequency in Hertz */
Return: nothing.
------------------------------------------------------------------------
-----*/
void
init_timer(void)
{
CAPREL = RELOAD_VALUE;
T6 = RELOAD_VALUE;
T6CON = 0x80c0 | PRESCALE_SELECTION;
/* interrupt set up */
T6IC = CALC_IC(0, 1, 10, 0); /* enable interrupt at priority level
10, group level 0 */
}
/
************************************************************************
******
Gets the timer value.
_atomic_(0);
temp = timer_val;
_endatomic_();
return temp;
}
/
************************************************************************
******
Interrupt service routine for the timer interrupt.
------------------------------------------------------------------------
-----*/
void
timer_interrupt(void) interrupt 0x26
{
/* See comment in timer() function above discussing interruptability
of
operations on timer_val.
This operation (incrementing timer_val in the interrupt service
routine) also needs to be uninterruptable, if any higher-priority
interrupt handlers make use of the time. Otherwise, such an
interrupt
could catch timer_val half-updated and get an erroneous time.
*/
_atomic_(0);
timer_val++;
_endatomic_();
}
************************************************************************
******
C167CR CAN Ap. Note project
Header file for CAN hardware (non RTX-166 ap. note only)
/* Given a message id, the following macro computes the value to write
to
the arbitr member of a CAN message object structure. If a standard
(i.e., 11-bit) identifier is being used, the significant bits are
28...18, not 10...0. If you are specifying 11-bit message ids in bit
positions 10...0 and wish to use this macro, make sure the id is an
unsigned long, and shift it left 18 bit positions, e.g.,
ARBITR((unsigned long)std_id << 18)
*/
#define ARBITR(id) ((unsigned long)(id) >> 21 & 0x000000ff | \
(unsigned long)(id) >> 5 & 0x0000ff00 | \
(unsigned long)(id) << 11 & 0x00ff0000 | \
(unsigned long)(id) << 27)
/* The MSG_CFG macro computes the value for a CAN object message
configuration register (msg_cfg member of the CAN_MSGOBJ[]).
dlc is data length code. must be 0...8.
dir is direction. 0 (CANDIR_RECEIVE) receive; 1 (CANDIR_TRANSMIT)
transmit
xtd is extended flag. 0 standard (11 bit) id; 1 extended (29 bit) id
*/
#define MSG_CFG(dlc,dir,xtd) ((dlc) << 4 | (dir) << 3 | (xtd) << 2)
#define CANDIR_RECEIVE 0
#define CANDIR_TRANSMIT 1
void
begin_can_init(void);
void
end_can_init(
unsigned interrupt_enable_flags);
int
copy_received_can_message(
int object_number,
void *buf);
int
update_can_transmit_message(
int object_number,
void *buf,
int length);
These are not standardized, but must be defined for each network design.
#define CAN_TIME_MSG (0x555ul << 18) /* 11-bit id: 101 0101 0101 */
#define LEN_CAN_TIME_MSG 4
/
************************************************************************
******
Start of CAN initialization
The mask registers, and any message objects that will actually be used,
must
be set up separately, and then end_can_init() should be called.
Returns: nothing.
------------------------------------------------------------------------
-----*/
void
begin_can_init(void)
{
int object_number;
CAN_BIT_TIMING = BIT_TIMING;
/
************************************************************************
******
End of CAN initialization
The CAN module has only a single interrupt request line and vector, for
many
possible causes of interrupts. For each possible type of CAN interrupt,
there
is an interrupt enable bit (EIE and SIE bits in the control/status
register,
and TXIE and RXIE bits in the message control registers for the CAN
message
objects). There is also an overall CAN interrupt enable (IE bit in the
control/status register) which must be set for the CAN module to
generate any
interrupts.
Returns: nothing.
------------------------------------------------------------------------
-----*/
void
end_can_init(
unsigned interrupt_enable_flags)
{
CAN_CTL_STAT = interrupt_enable_flags;
}
/
************************************************************************
******
Copy a message from a CAN object to a buffer.
This function ensures that the copied data come from a single version of
the
message. If a new version of the message is received while the copy is
in
progress, the function will start over, copying the new version.
cano = &CAN_MSGOBJ[object_number];
/* The CAN controller can update the message while the CPU is trying
to
process it. This could cause the CPU to use data that come partly
from the older message and partly from the newer message.
That could be very, very bad.
To prevent this, follow these steps:
(1) clear NEWDAT
(2) process the message (actually, just copy it to another
location
for more thorough processing later)
(3) Check NEWDAT: if NEWDAT is set, it means the CAN controller
has
updated the message (i.e., received a new message).
The copied message may be corrupt, so go back to step 1.
*/
do {
/* Clear NEWDAT */
cano->msg_ctl = NEWDAT_CLR;
src = cano->msg;
dest = (unsigned char *)buf;
for (stop = dest + length; dest != stop; ) {
*dest++ = *src++;
}
}
} while (cano->msg_ctl & NEWDAT_); /* Check NEWDAT */
return (length);
}
/
************************************************************************
******
Update a CAN transmit object with new data from a buffer.
This function ensures that a partially updated form of the message will
not be transmitted.
cano = &CAN_MSGOBJ[object_number];
/* The Data Length Code of the message object and the variable
'length'
must match. Change one to equal the other.
The Data Length Code for the message is in bits 7...4 of the
message configuration register.
*/
if (length < 0) {
/* Get length from the message object */
length = cano->msg_cfg >> 4;
}
else {
/* Set data length code in message object */
cano->msg_cfg = cano->msg_cfg & 0xf | length << 4;
}
return (length);
}
/
************************************************************************
******
CAN interrupt handler
0: no interrupt pending
1: status change interrupt
2: message 15 interrupt
2+N: message N (1 <= N <= 14) interrupt
When several interrupt conditions exist, the one associated with the
lowest
value of INTID (other than 0) takes precedence, i.e., its value appears
in
the INTID field. Once this interrupt has been cleared, the next
interrupt
source has its value appear in INTID. You must clear all interrupt
sources
for the CAN module (i.e., get INTID to 0) before returning from the
interrupt
handler or no further CAN interrupts will be generated.
Since this example program doesn't use CAN message interrupts, this
function
doesn't really need to have any code to deal with them. Absolute
minimal
message interrupt handling is provided for the benefit of people who
want
to use this program as a skeleton for more elaborate CAN programs. Of
course,
this skeleton may be anatomically unfit for your project.
------------------------------------------------------------------------
-----*/
void
can_interrupt(void) interrupt 0x40
{
unsigned char interrupt_id;
int message_number;
while (1) {
switch (interrupt_id = CAN_INTID) {
case 0 : /* no interrupt */
return;