Например TDA7294

РадиоКот > Статьи

Введение в MCP2515

Автор: Алексей, grom2, krukspb@yandex.ru
Опубликовано 28.11.2012.
Создано при помощи КотоРед.

 Возникла у меня необходимость пообщаться с CAN контроллером MCP2515 производства Microchip. Поиск примеров кода в русскоязычных интернетах не увенчался успехом, пример обнаруженный на форуме микрочипа воодушевлял только до его прошивки в АТмегу и проверки... и по результатам изысканий родилась идея написать статью. О самом интерфейсе писать не буду.

Я расскажу, как правильно инициализировать MCP2515, и в режиме loopback гонять контрольный байт.

Алгоритм работы с MCP2515 достаточно прост - инициализация, запись данных на отправку в буферы TXnDF, отправка данных в CAN драйвер, считывание данных из регистров RXnDF.
Для работы достаточно подключить контроллер к АТмеге через SPI (режим 00 или 11). Так же можно использовать выходы прерываний #INT, #RX0BF и #RX1BF (предварительно их включить как прерывание в соответствующем регистре), входы #TX0RTS, #TX1RTS и #TX2RTS можно использовать для отправки данных из соответствующих буферов.

Итак, после подачи питания/резета контроллер находится в режиме Configuration mode, в чем можно убедиться, посмотрев регистр CANSTAT:

//Read from CANSTAT reg
CS1=0;
delay_us(2);
spi(0x03);
spi(0x0E);
data=spi(0x00);
delay_us(2);
CS1=1;
PORTA=data;
delay_ms(1000);
PORTA=0;
delay_ms(1000);

Горит только PORTА.7 - все нормально.
Затем записываем в регистр CANINTE какие мы хотим видеть флаги прерываний:

//Set config to CANINTE reg
CS1=0;
delay_us(2);
spi(0x02);
spi(0x2B);
spi(0xFF); //set all
delay_us(2);
CS1=1;
delay_us(2);

Пишем в регистр RXBnCTRL

//Set config to RXB0CTRL reg
CS1=0;
delay_us(2);
spi(0x02);
spi(0x60);
spi(0x04); //set rollover
delay_us(2);
CS1=1;
delay_us(2);

Теперь у нас при наполнении регистра RXB0 (запись восьми байт) данные переходят в регистр RXB1.
Устанавливаем идентификаторы принимаемых данных:

//Set config to RXB0SIDH reg
CS1=0;
delay_us(2);
spi(0x02);
spi(0x61);
spi(0x0F); //set indentifier
delay_us(2);
CS1=1;
delay_us(2);

//Set config to RXB0SIDL reg
CS1=0;
delay_us(2);
spi(0x02);
spi(0x62);
spi(0x00); //set indentifier
delay_us(2);
CS1=1;
delay_us(2);

Идентификаторы отправляемых данных можно установить при записи в регистры TXBn а можно и отдельно.
Устанавливаем сколько байт мы примем:

//Set config to RXB0DLC reg
CS1=0;
delay_us(2);
spi(0x02);
spi(0x62);
spi(0x08); //set data length code
delay_us(2);
CS1=1;
delay_us(2);

Устанавливаем назначение выводов #RX0BF и #RX1BF:

//Set config to BFPCTRL reg
CS1=0;
delay_us(2);
spi(0x02);
spi(0x0C);
spi(0x0F); //set RXnBF pins like the interrapt pins
delay_us(2);
CS1=1;
delay_us(2);

Теперь на них будет 0, когда данные будут в соответствующем буфере.
Итак, можно выбрать режим, включить клоковый выход CLKOUT, задать значение делителя:

//Set config to CANCTRL reg

CS1=0;
delay_us(2);
spi(0x02);
spi(0x0F);
spi(0x5D); //set loopback mode, ABAR,OSM,CLKEN,Fout=Fin/2
delay_us(2);
CS1=1;
delay_us(20);

Режим - loopback, CLKOUT включен, входная частота сразу делится пополам, что можно наблюдать осциллографом. Инициализация закончена, хотя можно еще записать кучу других нужных регистров, пора передавать данные.
Записываем данные в TXBn начиная с регистра TXBnSIDH, если используем команду SPI LOAD TX BUFFER

CS1=0;
delay_us(2);

a=2*nB+0x40; //nB - номер буффера 0, 1 или 2
spi(a);
spi(0x0F);// TXBnSIDH
spi(0x00);// TXBnSIDL
spi(0x00);// TXBnEID8
spi(0x00);// TXBnEID0
spi(0x08);// TXBnDLC
spi(data);// TXBnD0
spi(0x02);// TXBnD1
spi(0x03);// TXBnD2
spi(0x04);// TXBnD3
spi(0x05);// TXBnD4
spi(0x06);// TXBnD5
spi(0x07);// TXBnD6
spi(0x08);// TXBnD7
delay_us(2);

Можно записать и используя адреса регистров, тогда, единожды прописав регистры TXBnSIDHTXBnSIDLTXBnEID8TXBnEID0 и TXBnDLC, можно записывать данные в регистры TXBnиспользуя команду LOAD TX BUFFER, начиная с байта данных D0 (значение а, естественно, вычисляется по-другому, см. даташит).
Теперь надо поставить буфер в режим ожидания отправки:

//Set config to TXB0CTRL reg
CS1=0;
delay_us(2);
spi(0x02);
spi(0x30);
spi(0x08); //set TXREQ bit
delay_us(2);
CS1=1;
delay_us(2);

Готово, можно проверить записанные данные, считав из регистров TXBnDm, например: 

//Read from TXB0D7 reg
CS1=0;
delay_us(2);
spi(0x03);
spi(0x3D);
data=spi(0x00);
delay_us(2);
CS1=1;
PORTA=data;
delay_ms(1000);
PORTA=0;

Моргнул PORTА.3 - все в порядке. Посылаем команду на отправку из TXB0:

delay_us(2);
CS1=0;
delay_us(2);
spi(0x81);//write to RTS transmit 0 buff
delay_us(2);
CS1=1;
delay_us(2);

Попробуем считать. Запускаем цикл считывания из регистра CANINTF, пока бит RX1IF не станет равным 1, и считываем данные из регистра RX1B (nB=1). Почему из первого? Так данные заполнили регистр RX0B и перешли в RX1B:

do {
CS1=0;
delay_us(2);

spi(0x03);
spi(0x2C);
IF=spi(0x00);

CS1=1;}

while ((IF&0x02)==0);
CS1=0;
delay_us(2);

a=0x92;
a=a+(0x04*nB); //start at RXBnD0
spi(a);
data=spi(0x00); // RXBnD0
spi(0x00); // RXBnD1
spi(0x00); // RXBnD2
spi(0x00); // RXBnD3
spi(0x00); // RXBnD4
spi(0x00); // RXBnD5
spi(0x00); // RXBnD6
spi(0x00); // RXBnD7

PORTA=data;
delay_ms(500);
PORTA=0;

Готово, PORTА показывает то, что было послано.
В моем примере задействованы далеко не все возможности MCP2515, да и передачи данных в шину не было. Но для знакомства с контроллером уже не надо ломать голову=)


 


Все вопросы в Форум.


ID: 1435