Главная » Статьи » MCP2515 - CAN контроллер
MCP2515 — CAN контроллер

MCP2515 — CAN контроллер

Бывает так, что у примененного микроконтроллера нет встроенного CAN контроллера, или имеющихся не хватает. В этом случае на помощь приходит контроллер CAN на микросхеме компании Microchip MCP2515. Под катом я расскажу об основных приемах работы с этой микросхемой. Микросхема MCP2515 позиционируется как улучшенная замена MCP2510.

Самое основное о MCP2515

MCP2515 обеспечивает реализацию протокола CAN по SPI шине. Краткие характеристики микросхемы:

  • Соответствует стандарту CAN V2.0B.
  • Стандартные и расширенные ID и возможность удаленных запросов данных.
  • Шесть 29 битных фильтра для приема сообщений.
  • Две 29 битных маски для приема сообщений.
  • Высокоскоростной SPI, до 10 МГц.
  • Выход программируемого делителя частоты.
  • Напряжение питания от 2,7В до 5,5В.

Различные конфигурации корпусов.

Корпуса и цоколевка MCP2515

Корпуса и цоколевка MCP2515

Обмен с MCP2515 по SPI

Первым делом необходимо научиться читать и писать в регистры MCP2515 по SPI каналу. Для управления используется четыре линии SPI:

  • CS (активный 0) — выбор чипа на шине SPI;
  • SCK — тактирование мастером (обычно в роли ведущего выступает микроконтроллер);
  • SI — линия передачи данных от МК к MCP2515;
  • SO — линия передачи данных от MCP2515 к МК.

Чтобы можно было быстро реагировать на получение сообщений и оптимизацию работы с SPI, у MCP2515 имеется несколько выходов, которые являются флагами событий микросхемы и которые можно использовать для запуска внешнего прерывания в микроконтроллере. К таким выходам относятся #RX0BF и #RX1BF.

Я управлял микросхемой MCP2515 при помощи микроконтроллера семейства dsPIC33F, соответственно и код приведу для этого микроконтроллера. SPI микроконтроллера настроен в режим 00, посылки по 8 бит. На плате, которая мне досталась, #RX0BF и #RX1BF задействованы не были — MCP2515 связана с МК только по SPI.

/* =============================================================================
 * ПЕРЕДАТЬ и ПОЛУЧИТЬ БАЙТ ПО SPI1
 */
unsigned char BUTE_SPI1(unsigned char bt)
{
 unsigned char SPIdata = 0;
 while(SPI1STATbits.SPITBF); // Ожидаем когда освободится буфер от передачи
 SPI1BUF = bt; // Передаем посылку (старшим битом вперед)
 while(!SPI1STATbits.SPIRBF); // Ожидаем получения данных
 SPIdata = SPI1BUF;
 return SPIdata;
}

В большинстве случаев общение с MCP2515 производится по алгоритму:

  • выбрать нужную MCP2515 сигналом CS;
  • отправить команду;
  • отправить адрес регистра;
  • отправить значение в регистр (в случае чтения эта операция вызовет чтение содержимого регистра).

Пример записи произвольной информации в регистр

/* =============================================================================
 * ЗАПИСАТЬ В РЕГИСТР В MCP2515
 */
void mcp_write(unsigned char RegName, unsigned char Data)
{
 MCP_CS_OFF; // Не выбрали микросхему
 __delay_us(2); // Подождали 2 микросекунды
 MCP_CS_ON; // Выбрали микросхему сигналом CS
 __delay_us(2);
 BUTE_SPI1(WRITE); // WRITE = 0b00000010 = 0x02
 BUTE_SPI1(RegName); // Адрес регистра
 return BUTE_SPI1(Data);
 MCP_CS_OFF;
 __delay_us(2);
}

Пример чтения  информации из регистра

/* =============================================================================
 * ПРОЧИТАТЬ РЕГИСТР В MCP2515
 */
unsigned char mcp_read(unsigned char RegName)
{
 MCP_CS_OFF; // Не выбрали микросхему
 __delay_us(2); // Подождали 2 микросекунды
 MCP_CS_ON; // Выбрали микросхему сигналом CS
 __delay_us(2);
 BUTE_SPI1(READ); // READ = 0b00000011 = 0x03
 BUTE_SPI1(RegName); // Адрес регистра
 return BUTE_SPI1(0x00);
 MCP_CS_OFF;
 __delay_us(2);
}

Команды (инструкции) MCP2515

Вы, наверное, уже заметили, что выше использовались команды READ, WRITE и приводились их значения. Откуда я их взял? Из datasheet, а чтобы было удобнее, я выписал их в отдельный *.h файл, привожу команды микросхемы MCP2515 ниже

#define RESET           0b11000000 // Сброс MCP2515
#define READ            0b00000011 // Читать регистр MCP2515
#define WRITE           0b00000010 // Записать в регистр MCP2515
#define WRITEBIT        0b00000101
#define READBUF0_RX_SH  0b10010000
#define READBUF0_RX_D0  0b10010010
#define READBUF1_RX_SH  0b10010100
#define READBUF1_RX_D0  0b10010110
#define LOADBUF0_TX_SH  0b01000000
#define LOADBUF0_TX_D0  0b01000001
#define LOADBUF1_TX_SH  0b01000010
#define LOADBUF1_TX_D0  0b01000011
#define LOADBUF2_TX_SH  0b01000100
#define LOADBUF2_TX_D0  0b01000101
#define RTS_TXB0        0b10000001 // Отправить сообщение из буфера 1
#define RTS_TXB1        0b10000010 // Отправить сообщение из буфера 2
#define RTS_TXB2        0b10000100 // Отправить сообщение из буфера 3
#define RTS_TXB_ALL     0b10000111 // Отправить сообщения из всех буферов

Команды вроде READBUF0_RX_D0 позволяют экономить на количестве SPI посылок. Так мы вначале указываем, что хотим прочитать данные из буфера, после чего посылаем восемь пустых байт для чтения восьми байт буфера.

/* =============================================================================
 * ПОЛУЧИТЬ 8 БАЙТ ИЗ MCP2515
 */
void mcp_getCAN(void)
{
 unsigned long Word = 0;
 MCP_CS_OFF; // Снять CS с MCP
 __delay_us(2); // Ждем...
 MCP_CS_ON; // Выбрали
 __delay_us(2);
 BUTE_SPI1(READBUF0_RX_D0); // Говорим, что хотим читать данные из буфера 0
 mcp_Rx0DATA[0] = BUTE_SPI1(0x00);
 mcp_Rx0DATA[1] = BUTE_SPI1(0x00);
 mcp_Rx0DATA[2] = BUTE_SPI1(0x00);
 mcp_Rx0DATA[3] = BUTE_SPI1(0x00);
 mcp_Rx0DATA[4] = BUTE_SPI1(0x00);
 mcp_Rx0DATA[5] = BUTE_SPI1(0x00);
 mcp_Rx0DATA[6] = BUTE_SPI1(0x00);
 mcp_Rx0DATA[7] = BUTE_SPI1(0x00);
 __delay_us(2);
 MCP_CS_OFF;
 __delay_us(2);
 }

Список команд приведен в Datasheet:

Список инструкций для MCP2515

Список инструкций для MCP2515

Регистры MCP2515

Регистры контроллера MCP2515 приведены в Datasheet

Список регистров MCP2515

Список регистров MCP2515

Разумеется, в таком виде пользоваться ими неудобно, поэтому я их тоже вложил в  *.h файл и местами даже расшифровал:

// Регистры
#define		CANSTAT		0b00001110
#define		CANCTRL		0b00001111  // В PIC18 - CANCON

#define		RXF0SIDH	0b00000000
#define		RXF0SIDL	0b00000001
#define		RXF0EID8	0b00000010
#define		RXF0EID0	0b00000011
#define		RXF1SIDH	0b00000100
#define		RXF1SIDL	0b00000101
#define		RXF1EID8	0b00000110
#define		RXF1EID0	0b00000111
#define		RXF2SIDH	0b00001000
#define		RXF2SIDL	0b00001001
#define		RXF2EID8	0b00001010
#define		RXF2EID0	0b00001011
#define		BFPCTRL		0b00001100
#define		TXRTSCTRL	0b00001101

#define		RXF3SIDH	0b00010000
#define		RXF3SIDL	0b00010001
#define		RXF3EID8	0b00010010
#define		RXF3EID0	0b00010011
#define		RXF4SIDH	0b00010100
#define		RXF4SIDL	0b00010101
#define		RXF4EID8	0b00010110
#define		RXF4EID0	0b00010111
#define		RXF5SIDH	0b00011000
#define		RXF5SIDL	0b00011001
#define		RXF5EID8	0b00011010
#define		RXF5EID0	0b00011011
#define		TEC		0b00011100
#define		REC		0b00011101

#define		RXM0SIDH	0b00100000
#define		RXM0SIDL	0b00100001
#define		RXM0EID8	0b00100010
#define		RXM0EID0	0b00100011
#define		RXM1SIDH	0b00100100
#define		RXM1SIDL	0b00100101
#define		RXM1EID8	0b00100110
#define		RXM1EID0	0b00100111
#define		CNF3		0b00101000 // 0x02
#define		CNF2		0b00101001 // 0x90
#define		CNF1		0b00101010 // BRP_VAL_CAN(125000)
#define		CANINTE		0b00101011 // PIE3, Устанавливаем желаемые флаги прерываний
#define		CANINTF		0b00101100 // INTERRUPT FLAG
#define		EFLG		0b00101101

#define		TXB0CTRL	0b00110000
#define		TXB0SIDH	0b00110001 // Идентификатор стандартного сообщения приемного буфера 0, СТАРШИЙ байт
#define		TXB0SIDL	0b00110010 // Идентификатор стандартного сообщения приемного буфера 0, МЛАДШИЙ байт
#define		TXB0EID8	0b00110011 // Идентификатор расширенного сообщения приемного буфера 0, СТАРШИЙ байт
#define		TXB0EID0	0b00110100 // Идентификатор расширенного сообщения приемного буфера 0, МЛАДШИЙ байт
#define		TXB0DLC		0b00110101
/*      TXB0DLC = 0b00001000
 *                   |||++++-- [DLC] Количество байт данных в сообщении (1000 - 8 байт)
 *                   |++------ [] Резерв протокола CAN
 *                   +-------- [RTR] Бит удаленного запроса данных
 */
#define		TXB0D0		0b00110110 // Байт данных 0 передающего буфера 0
#define		TXB0D1		0b00110111
#define		TXB0D2		0b00111000
#define		TXB0D3		0b00111001
#define		TXB0D4		0b00111010
#define		TXB0D5		0b00111011
#define		TXB0D6		0b00111100
#define		TXB0D7		0b00111101 // Байт данных 7 передающего буфера 0

#define		TXB1CTRL	0b01000000
#define		TXB1SIDH	0b01000001 // Идентификатор стандартного сообщения приемного буфера 0, СТАРШИЙ байт
#define		TXB1SIDL	0b01000010 // Идентификатор стандартного сообщения приемного буфера 0, МЛАДШИЙ байт
#define		TXB1EID8	0b01000011 // Идентификатор расширенного сообщения приемного буфера 0, СТАРШИЙ байт
#define		TXB1EID0	0b01000100 // Идентификатор расширенного сообщения приемного буфера 0, МЛАДШИЙ байт
#define		TXB1DLC		0b01000101
#define		TXB1D0		0b01000110
#define		TXB1D1		0b01000111
#define		TXB1D2		0b01001000
#define		TXB1D3		0b01001001
#define		TXB1D4		0b01001010
#define		TXB1D5		0b01001011
#define		TXB1D6		0b01001100
#define		TXB1D7		0b01001101

#define		TXB2CTRL	0b01010000
#define		TXB2SIDH	0b01010001 // Идентификатор стандартного сообщения приемного буфера 0, СТАРШИЙ байт
#define		TXB2SIDL	0b01010010 // Идентификатор стандартного сообщения приемного буфера 0, МЛАДШИЙ байт
#define		TXB2EID8	0b01010011 // Идентификатор расширенного сообщения приемного буфера 0, СТАРШИЙ байт
#define		TXB2EID0	0b01010100 // Идентификатор расширенного сообщения приемного буфера 0, МЛАДШИЙ байт
                                                // см значения ниже
#define		TXB2DLC		0b01010101
#define		TXB2D0		0b01010110
#define		TXB2D1		0b01010111
#define		TXB2D2		0b01011000
#define		TXB2D3		0b01011001
#define		TXB2D4		0b01011010
#define		TXB2D5		0b01011011
#define		TXB2D6		0b01011100
#define		TXB2D7		0b01011101

#define		RXB0CTRL	0b01100000 // см. RXBnCON
/*     RXB0CTRL =   -WW-
 *     RXB0CTRL = 0b01100000
 *                   || |||+-- Активный приемный фильтр0 или фильтр1
 *                   || ||+---
 *                   || |+----  если буфер 0 переполнен данные будут записаны в буфер 1
 *                   || +-----  принят запрос удаленной передачи
 *                   ++------- [RXM] Режим приемного буфера: принимать все сообщения;  принимать только расширенные;  принимать только стандартные;  принимать сообщения без ошибок
 *
 *
 */
#define		RXB0SIDH	0b01100001 // Идентификатор стандартного сообщения приемного буфера 0, СТАРШИЙ байт
#define		RXB0SIDL	0b01100010 // Идентификатор стандартного сообщения приемного буфера 0, МЛАДШИЙ байт
#define		RXB0EID8	0b01100011 // Идентификатор расширенного сообщения приемного буфера 0, СТАРШИЙ байт
#define		RXB0EID0	0b01100100 // Идентификатор расширенного сообщения приемного буфера 0, МЛАДШИЙ байт
/*
 *   S10          S3     S2 S1 S0 SRR IDE -  E17 E16      E15              E8    E7               E0
 *  |______________|    |__|__|__|___|___|__|___|___|    |___________________|  |___________________|
 *       SIDH                        SIDL                        EID8                    EID0
 * IDE: 1=расширенное сообщение;   0=стандартное
 * SRR: 1=удаленный запрос
 * Sx - стандартный идентификатор
 * Ex - расширенный идентификатор
 * Идентификатор по умолчанию 0x1FFEFFFF (11111111111101111111111111111) получается такой:
 *     11111111    111 010 10    11111111    11111111
 *     RXB0SIDH     RXB0SIDL     RXB0EID8    RXB0EID0
 */
#define		RXB0DLC		0b01100101
#define		RXB0D0		0b01100110
#define		RXB0D1		0b01100111
#define		RXB0D2		0b01101000
#define		RXB0D3		0b01101001
#define		RXB0D4		0b01101010
#define		RXB0D5		0b01101011
#define		RXB0D6		0b01101100
#define		RXB0D7		0b01101101

#define		RXB1CTRL	0b01110000
#define		RXB1SIDH	0b01110001
#define		RXB1SIDL	0b01110010
#define		RXB1EID8	0b01110011
#define		RXB1EID0	0b01110100
#define		RXB1DLC		0b01110101
#define		RXB1D0		0b01110110
#define		RXB1D1		0b01110111
#define		RXB1D2		0b01111000
#define		RXB1D3		0b01111001
#define		RXB1D4		0b01111010
#define		RXB1D5		0b01111011
#define		RXB1D6		0b01111100
#define		RXB1D7		0b01111101

Полезно помнить — CAN в MCP2515 близок по функциональности и регистровому составу модулю CAN в микроконтроллерах серии PIC18. На CAN модуль этих микроконтроллеров имеется русскоязычное описание

Can Pic18cxx8
Can Pic18cxx8
can_pic18cxx8.pdf
740.7 KiB
862 Downloads
Детали

Даже если нет нужного регистра — не отчаивайтесь! Пройдитесь поиском по названию конкретного бита в регистре. Уверен — найдете все необходимое!

Инициализация MCP2515

Контроллер MCP2515 после включения питания находится в режиме конфигурации, в чем можно убедиться получив биты OPMOD из регистра CANSTAT:

reg = mcp_read(CANSTAT); // reg содержит значение регистра CANSTAT.

Седьмой, шестой и пятый биты — биты OPMOD2..OPMOD0.

/*      OPMOD2  OPMOD1  OPMOD0  Режим работы
 *        0       0       0     - нормальный режим
 *        0       0       1     - спящий режим
 *        0       1       0     - режим петли
 *        0       1       1     - только прослушивание шины
 *        1       0       0     - режим настройки (по умолчанию после сброса)

Устанавливаем флаги прерываний

mcp_write(CANINTE,0x00); // не используются

Устанавливаем идентификатор

mcp_write(TXB0SIDH,0b11111111);
mcp_write(TXB0SIDL,0b11101010);
mcp_write(TXB0EID8,0b11111111);
mcp_write(TXB0EID0,0b11111111);

mcp_write(RXB0SIDH,0b11111111);
mcp_write(RXB0SIDL,0b11101010);
mcp_write(RXB0EID8,0b11111111);
mcp_write(RXB0EID0,0b11111111);

mcp_write(CANCTRL,0b00001011);

Настраиваем приемный буфер

mcp_write(RXB0CTRL,0b01100000);

Настройку скорости я позаимствовал на просторах интернета. В заголовочный файл добавил строки:

// Настройка скорости
#define FOSC 8000000
#define NTQmy 8
#define BRP_VAL_CAN(BITRATE) ((FOSC /(2*NTQmy*BITRATE))-1)

А в код добавил SPI команды:

  // Настройка скорости
  mcp3_write(CNF1,BRP_VAL_CAN(125000));
  mcp3_write(CNF2,0x90); //144   10010000
                         //      *-+++***
  mcp3_write(CNF3,0x02); //  2   00000010
                         //      **---+++

Как видим, скорость зависит от содержимого регистров CNF. В моем случае частота кварца на MCP2515 составили 8МГц, а требуемая мне скорость обмена по шине CAN 125кБит. Именно на этой скорости работала CAN шина к которой я подключался.
В сети имеется русскоязычное руководство от Microchip по настройке CAN модулей и расчету скоростей обмена:

AN754 Ponimanie Bitovoi Sinhronizacii CAN Rus
AN754 Ponimanie Bitovoi Sinhronizacii CAN Rus
AN754_ponimanie_bitovoi_sinhronizacii_CAN_rus.pdf
267.0 KiB
967 Downloads
Детали

Прием и передача

При приеме сообщения последовательность следующая: в цикле проверяем наличие новых данных. Если новые данные обнаружены — производим чтение.

/* =============================================================================
 * ПРОВЕРИТЬ НАЛИЧИЕ НОВЫХ ДАННЫХ В MCP3
 */
unsigned char mcp_newCAN(void)
{
unsigned char intf = 0;
return 0;
MCP_CS_OFF;
__delay_us(2);

MCP_CS_ON;
__delay_us(2);
BUTE_SPI1(READ);
BUTE_SPI1(CANINTF);
intf = BUTE_SPI1(0x00);
if (intf & 0b00000010) {return 1;}
__delay_us(2);
MCP_CS_OFF;
__delay_us(2);
}

Процедура mcp_newCAN() крутится в главном цикле

mcp_Dnew = mcp_newCAN();

Если обнаруживается новое сообщение, то выполняется чтение:

    /* Если получили сообщение по CAN3 */
    if (mcp_Dnew)
    {
      mcp_getCAN(); // теперь данные в mcp_Rx0DATA[] и в mcp_RxWORD[]
      mcp_Dnew = 0;
      ........
      ........
    }

mcp_getCAN() рассмотрели выше.

Напоследок

Имеется не нулевая вероятность, что в дальнейшем мне придется столкнуться с MCP2515 более плотно. Это означает, что материал будет либо дополнен, либо вообще полностью переделан. Мне интересно — хотели бы вы видеть отладочную плату на MCP2515? И если хотели бы, то что там должно быть:

  • количество MCP2515
  • корпус MCP2515 (DIP, SOIC, TSSOP, QFN)
  • наличие и тип микроконтроллера
  • встроенные драйвера CAN шины
  • встроенное питание
  • ets

Ну и какую цену при покупке готового отладочного устройства либо при самостоятельном изготовлении всего этого вы считаете приемлемой? Все — в комментариях =)

И как бонус выложу Datasheet MCP2515

MCP2515
MCP2515
mcp2515.pdf
1.2 MiB
678 Downloads
Детали

А еще есть функциональный аналог — IN2515, и описание на русском

IN2515
IN2515
in2515.pdf
368.0 KiB
385 Downloads
Детали

Метки:: ,

11 Отзывы Ваш отзыв

  1. AVL #

    Спасибо за статью, мне она оказалась полезной.
    Есть у меня вопросы, но задам их попозже, уже как сам не смогу разобраться.
    Прилагаю описание регистров в ХЕКСах, а не в бинарнике, оно так, иногда, бывает удобнее.

    #define RXF0SIDH 0x00
    #define RXF0SIDL 0x01
    #define RXF0EID8 0x02
    #define RXF0EID0 0x03

    #define RXF1SIDH 0x04
    #define RXF1SIDL 0x05
    #define RXF1EID8 0x06
    #define RXF1EID0 0x07

    #define RXF2SIDH 0x08
    #define RXF2SIDL 0x09
    #define RXF2EID8 0x0A
    #define RXF2EID0 0x0B

    #define BFPCTRL 0x0C
    #define B1BFS 0x20
    #define B0BFS 0x10
    #define B1BFE 0x08
    #define B0BFE 0x04
    #define B1BFM 0x02
    #define B0BFM 0x01

    #define TXRTSCTRL 0x0D
    #define B2RTS 0x20
    #define B1RTS 0x10
    #define B0RTS 0x08
    #define B2RTSM 0x04
    #define B1RTSM 0x02
    #define B0RTSM 0x01

    #define CANSTAT 0x0E
    #define OPMOD2 0x80
    #define OPMOD1 0x40
    #define OPMOD0 0x20
    #define ICOD2 0x08
    #define ICOD1 0x04
    #define ICOD0 0x02

    #define CANCTRL 0x0F
    #define REQOP2 0x80
    #define REQOP1 0x40
    #define REQOP0 0x20
    #define ABAT 0x10
    #define OSM 0x08
    #define CLKEN 0x04
    #define CLKPRE1 0x02
    #define CLKPRE0 0x01

    #define RXF3SIDH 0x10
    #define RXF3SIDL 0x11
    #define RXF3EID8 0x12
    #define RXF3EID0 0x13

    #define RXF4SIDH 0x14
    #define RXF4SIDL 0x15
    #define RXF4EID8 0x16
    #define RXF4EID0 0x17

    #define RXF5SIDH 0x18
    #define RXF5SIDL 0x19
    #define RXF5EID8 0x1A
    #define RXF5EID0 0x1B

    #define TEC 0x1C
    #define REC 0x1D

    #define RXM0SIDH 0x20
    #define RXM0SIDL 0x21
    #define RXM0EID8 0x22
    #define RXM0EID0 0x23

    #define RXM1SIDH 0x24
    #define RXM1SIDL 0x25
    #define RXM1EID8 0x26
    #define RXM1EID0 0x27

    #define CNF3 0x28
    #define SOF 0x80
    #define WAKFIL 0x40
    #define PHSEG22 0x04
    #define PHSEG21 0x02
    #define PHSEG20 0x01

    #define CNF2 0x29
    #define BTLMODE 0x80
    #define SAM 0x40
    #define PHSEG12 0x20
    #define PHSEG11 0x10
    #define PHSEG10 0x08
    #define PRSEG2 0x04
    #define PRSEG1 0x02
    #define PRSEG0 0x01

    #define CNF1 0x2A
    #define SJW1 0x80
    #define SJW0 0x40
    #define BRP5 0x20
    #define BRP4 0x10
    #define BRP3 0x08
    #define BRP2 0x04
    #define BRP1 0x02
    #define BRP0 0x01

    #define CANINTE 0x2B
    #define MERRE 0x80
    #define WAKIE 0x40
    #define ERRIE 0x20
    #define TX2IE 0x10
    #define TX1IE 0x08
    #define TX0IE 0x04
    #define RX1IE 0x02
    #define RX0IE 0x01

    #define CANINTF 0x2C
    #define MERRF 0x80
    #define WAKIF 0x40
    #define ERRIF 0x20
    #define TX2IF 0x10
    #define TX1IF 0x08
    #define TX0IF 0x04
    #define RX1IF 0x02
    #define RX0IF 0x01

    #define EFLG 0x2D
    #define RX1OV 0x80
    #define RRX0OVR 0x40
    #define TXBO 0x20
    #define TXEP 0x10
    #define RXEP 0x08
    #define TXWAR 0x04
    #define RXWAR 0x02
    #define EWARN 0x01

    #define TXB0CTRL 0x30
    #define ABTF 0x40
    #define MLOA 0x20
    #define TXERR 0x10
    #define TXREQ 0x08
    #define TXP1 0x02
    #define TXP0 0x01
    #define TXP_MASK 0x03

    #define TXB0SIDH 0x31
    #define TXB0SIDL 0x32
    #define TXB0EID8 0x33
    #define TXB0EID0 0x34
    #define TXB0DLC 0x35
    #define TXB0D0 0x36
    #define TXB0D1 0x37
    #define TXB0D2 0x38
    #define TXB0D3 0x39
    #define TXB0D4 0x3A
    #define TXB0D5 0x3B
    #define TXB0D6 0x3C
    #define TXB0D7 0x3D

    #define TXB1CTRL 0x40
    #define TXB1SIDH 0x41
    #define TXB1SIDL 0x42
    #define TXB1EID8 0x43
    #define TXB1EID0 0x44
    #define TXB1DLC 0x45
    #define TXB1D0 0x46
    #define TXB1D1 0x47
    #define TXB1D2 0x48
    #define TXB1D3 0x49
    #define TXB1D4 0x4A
    #define TXB1D5 0x4B
    #define TXB1D6 0x4C
    #define TXB1D7 0x4D

    #define TXB2CTRL 0x50
    #define TXB2SIDH 0x51
    #define TXB2SIDL 0x52
    #define TXB2EID8 0x53
    #define TXB2EID0 0x54
    #define TXB2DLC 0x55
    #define TXB2D0 0x56
    #define TXB2D1 0x57
    #define TXB2D2 0x58
    #define TXB2D3 0x59
    #define TXB2D4 0x5A
    #define TXB2D5 0x5B
    #define TXB2D6 0x5C
    #define TXB2D7 0x5D

    #define RXB0CTRL 0x60
    #define RXM1 0x40
    #define RXM0 0x20
    #define RXRTR 0x08
    #define BUKT 0x04
    #define BUKT1 0x02
    #define FILHIT0 0x01

    //rx buffers regs
    #define RXB0SIDH 0x61
    #define RXB0SIDL 0x62
    #define RXB0EID8 0x63
    #define RXB0EID0 0x64
    #define RXB0DLC 0x65
    #define RXB0D0 0x66
    #define RXB0D1 0x67
    #define RXB0D2 0x68
    #define RXB0D3 0x69
    #define RXB0D4 0x6A
    #define RXB0D5 0x6B
    #define RXB0D6 0x6C
    #define RXB0D7 0x6D

    #define RXB1CTRL 0x70
    #define FILHIT2 0x04
    #define FILHIT1 0x02

    #define RXB1SIDH 0x71
    #define RXB1SIDL 0x72
    #define RXB1EID8 0x73
    #define RXB1EID0 0x74
    #define RXB1DLC 0x75
    #define RXB1D0 0x76
    #define RXB1D1 0x77
    #define RXB1D2 0x78
    #define RXB1D3 0x79
    #define RXB1D4 0x7A
    #define RXB1D5 0x7B
    #define RXB1D6 0x7C
    #define RXB1D7 0x7D

    #define SID10 0x80
    #define SID9 0x40
    #define SID8 0x20
    #define SID7 0x10
    #define SID6 0x08
    #define SID5 0x04
    #define SID4 0x02
    #define SID3 0x01
    #define SID2 0x80
    #define SID1 0x40
    #define SID0 0x20
    #define SRR 0x10
    #define IDE 0x08
    #define EXIDE 0x08
    #define EID17 0x02
    #define EID16 0x01
    #define EID15 0x80
    #define EID14 0x40
    #define EID13 0x20
    #define EID12 0x10
    #define EID11 0x08
    #define EID10 0x04
    #define EID9 0x02
    #define EID8 0x01
    #define EID7 0x80
    #define EID6 0x40
    #define EID5 0x20
    #define EID4 0x10
    #define EID3 0x08
    #define EID2 0x04
    #define EID1 0x02
    #define EID0 0x01

    #define RTR 0x40
    #define RB1 0x20
    #define RB0 0x10

    #define DLC3 0x08
    #define DLC2 0x04
    #define DLC1 0x02
    #define DLC0 0x01
    #define DLEN_MASK 0x0F

    //SPI instructions

    #define CMD_RESET 0xC0
    #define CMD_READ 0x03
    #define CMD_READ_RX 0x90
    #define RX0ID 0x00
    #define RX0DATA 0x02
    #define RX1ID 0x04
    #define RX1DATA 0x06
    #define RX_MASK 0x06

    #define CMD_WRITE 0x02
    #define CMD_WRITE_TX 0x40
    #define TX0ID 0x00
    #define TX0DATA 0x01
    #define TX1ID 0x02
    #define TX1DATA 0x03
    #define TX2ID 0x04
    #define TX2DATA 0x05
    #define TX_MASK 0x07

    #define CMD_RTS 0x80
    #define CMD_RTS0 0x01
    #define CMD_RTS1 0x02
    #define CMD_RTS2 0x04
    #define CMD_RTS_MASK 0x07

    #define CMD_READ_STATUS 0xA0
    #define CMD_RX_STATUS 0xB0
    #define RX_STATUS_NOMSG 0x00
    #define RX_STATUS_MSG0 0x40
    #define RX_STATUS_MSG1 0x80
    #define RX_STATUS_MSGBOTH 0xC0

    #define RX_STATUS_DATA 0x00
    #define RX_STATUS_REMOTE 0x10
    #define RX_STATUS_EXTDATA 0x20
    #define RX_STATUS_EXTREMOTE 0x30

    #define RX_STATUS_RXF0 0x00
    #define RX_STATUS_RXF1 0x01
    #define RX_STATUS_RXF2 0x02
    #define RX_STATUS_RXF3 0x03
    #define RX_STATUS_RXF4 0x04
    #define RX_STATUS_RXF5 0x05
    #define RX_STATUS_RXF0ROLL 0x06
    #define RX_STATUS_RXF1ROLL 0x07

    #define CMD_BIT_MODIFY 0x05

  2. AVL #

    Вот Вы написали «Прием и передача», а описали только «Приём»…
    А мне как-раз интересно как задаётся ИД посылки в КАН-шину.

  3. AVL #

    На счёт отладочной платы, то лично мне интересен-бы был вариант с двумя комплектами контроллеров и драйверов, что б, к примеру, сделать КАН-фильтр. Процессор Атмега8, кпримеру, в СОИК корпусе. Но сейчас уже можно купить не дорого процессор с КАНом на борту, но это статься не о таком решении вопроса.

  4. AVL #

    Про фильтры и маски можете дорассказать?
    Спасибо!

  5. Кулхацкер #

    в примере совсем не ясно, как задавались биты cnf1-3
    pdf по ссылке слишком заумный и не дает простых ответов.
    интересует, ход рассуждений, как посчитать биты для кварца 16МГц и скорости шины 500 кбод (без каких-то особых требований к длине шины)
    попробовал подставил в формулу данные — получил на выходе единицу в cnf1 — уверенности в том, что не нужно изменять остальные биты нет…

    • Я настраивал скорость кодом приведенным ниже. Частота генератора MCP2515 8,0 МГц, скорость обмена 125 кбит.
      В заголовочном файле:
      =====================================
      // Настройка скорости
      #define FOSC 8000000
      #define NTQmy 8
      #define BRP_VAL_CAN(BITRATE) ((FOSC /(2*NTQmy*BITRATE))-1)
      =====================================
      В си-файле:
      // Настройка скорости
      mcp3_write(CNF1,BRP_VAL_CAN(125000));

  6. DEnis #

    Здравствуйте,

    всё уже написано до нас, в линуксе есть готовый драйвер для работы с mcp251x.
    http://lxr.free-electrons.com/source/drivers/net/can/mcp251x.c?v=2.6.33
    оттуда можно взять готовые функции переписать их для своего контроллера и будет Вам счастье.

  7. ALEX #

    Автор молодец! Благодаря этой статье я быстро смог побороть МСР2515. Всё разжевал и выложил на блюдечке. Спасибо.

Ваш отзыв