View Single Post
Old 12-17-2010, 02:33 AM   #4119 (permalink)
DJBecker
EcoModding Apprentice
 
Join Date: Nov 2010
Location: Annapolis
Posts: 159
Thanks: 0
Thanked 32 Times in 27 Posts
It's not very difficult to have an AVR use a Microchip MCP2515 CAN controller over SPI. And the chip is very inexpensive -- Avnet has them $1.72 in a DIP, with the MCP2551 transceiver costing only $1.12 (or even less for other brands, if you don't plan on using sleep mode).

Well, actually it was a bit of a PITA to get it working, but once working it seemed that it should have been easy. I ended writing the code for the MCP3008 SPI A/D converter to convince myself that I was using the SPI interface correctly. Of course that part worked the first time.

The problem turned out to be my clock, combined with the reset start-up time. The CAN controller needs a fast clock that is stable for a bit before you start using it. I didn't want the extra parts for an independent crystal, so I was clocking from an AVR timer output. The working configuration was setting the timer output at the maximum rate, going off and doing some other initialization, sending a reset command, do something else, then come back and set up the configuration registers. If you poll waiting for the reset to finish, make certain that you turn off or feed the watchdog, else you'll get bitten.

For the SPI interface you need the three SPI pins (MOSI/MISO/SCK) which can be shared with other SPI devices, and a dedicated chip select per SPI device (any free output will do, it doesn't need to be SS). The CAN controller also uses a timer output pin for its clock, and optionally an input for raising interrupts.

I'm currently just polling the status in the main loop and not using the interrupt, but I'll need it when I get around to implementing sleep mode.

The MCP2515 has five pins that can be used as general purpose inputs and outputs, so you can make up for losing the I/O pins on the AVR if you are running short.

The following is the clock setup for the Mega 1280 board that we are using for our motor controller.


/* Timer 4 is used to clock the CAN controller.
* It needs a 50% duty cycle clock that's at least 10x (preferably 16x)
* the max bit rate, which may be 250K, 500K or 1000Kbps.
* To get a 8MHz out from a 16MHz sys clock we must use mode 4 or 12.
* We set to mode 4: clear timer on compare w/ OCR4A.
*/
#define TIMER4_MODE 4
TIMSK4 = 0; /* Clear the interrupt flags. */
TCCR4B = 0; /* Stop the counter to load with zero. */
TCNT4 = 0;
OCR4A = 0; /* Max count is 1, divide by 2. */
/* Toggle OC4A on match, implicit divide by two. */
TCCR4A = (1 << COM4A0) | ((TIMER4_MODE & 0x3) << WGM40);
/* Bypass pre-scaler to use 16MHz clock, set upper mode bits. */
TCCR4B = (1 << CS40) | ((TIMER4_MODE & 0xC) << (WGM42 - 2));
/* OC4A output is on PH3.
* PH4/PWM7/OC4B is the tach opto input -- pull-up active.
* PH5/PWM8 drives the tach LED.
* PWM9/PH6/OC2B is pulled high as an alternate input
* Enable the pins as outputs. */
PORTH = 0x70;
DDRH = 0x28;

Last edited by DJBecker; 12-17-2010 at 09:18 AM..
  Reply With Quote
The Following User Says Thank You to DJBecker For This Useful Post:
MPaulHolmes (12-17-2010)