Notice: Memcache::get(): Server localhost (tcp 11211) failed with: Connection refused (111) in /home/a146/www/we.easyelectronics.ru/engine/lib/external/DklabCache/Zend/Cache/Backend/Memcached.php on line 134
Использование модулей CAN на STM32 для разных целей / STM32 / Сообщество EasyElectronics.ru

Использование модулей CAN на STM32 для разных целей

В последнее время, к сожалению, выросла цена на многие импортные радиодетали, в том числе и на отладочные платы с микроконтроллерами. А потребность в изготовлении разных поделок к счастью не пропала. Волей случая у меня в руках оказалось несколько интересных модулей от компании Starline, которая выпускает автомобильные сигнализации и много других полезных вещей (Можете поспрашивать у установщиков сигнализаций, или на сайте производителя). Целей раскрыть секреты работы этих модулей не стояло. Но ввиду их хорошего изготовления и оснащения оставить пропадать их без дела наше время тоже нехорошо.
Вкратце о модулях:
Модуль CAN — STM32F103RBT8 + SST25V016 + TJA1042, силовые ключи, микросхемы питания.
Модуль 2CAN — STM32F105RBT8 + SST25V032 + TJA1048, микросхемы питания.





(процессоры STM32F103 и STM32F105 (7) друг от друга функционально отличаются блоками тактирования, USB и CAN, надо обратить на это внимание далее)
Вооружившись тестером, разрисовал схемы модулей, возможно с ошибками. Наиболее интересным естественно оказывается модуль 2CAN, он позволяет одновременную работу USB FS и двух приемопередатчиков CAN. У первого модуля либо CAN, либо USB.
Скриншот схемы модуля CAN:



для поделок организация ввода вывода неплохая, но модуль 2CAN для интеграции в автомобиль интереснее, схема:



Так как на некоторых компонентах была неизвестная мне маркировка, то соответственно, я рисовал своё видение схемы.

Из модуля CAN на досуге сделал два полезных устройства – блок управления ходовыми огнями, и блок тестирования шаговых двигателей. Причем управление этими блоками осуществлялось как с внешних датчиков, так и по шине USB. Со стороны компьютера, подключенные блоки виделись как устройства с последовательным портом RS232. Причины изготовления блока управления ходовыми огнями – установленные китайские жгут чрезмерным током свои же светодиоды, от любой импульсной помехи выгорают с дымом. Блок их управления, не защищены от влаги, нет защиты от помех по питанию, нет экранировки. На CAN модуль была возложена функция управления логикой работы ходовых огней и дублирующих сигналов поворота, управление силовым транзистором повышающего преобразователя напряжения (на линейки светодиодов требуется порядка 24В), управление силовыми транзисторами, подающие питание на 4 линейки светодиодов, задержка выключения света в течение заданного времени после выключения зажигания.

Вот внутренности фонарей:


В вот так выглядят внутренности драйвера после непродолжительной работы:

Помехи от проводов от китайского ксенона погасили ходовые огни :). Ну а если делать с большим запасом надежности, и использовать модуль CAN, получается примерно так (еще без корпуса на этапе настройки под капризы заказчика):



Схема обвязки для модуля довольно простая (скриншот):


Устройство тестирования шаговых двигателей, применяемых в автомобиле, задавать режим работы можно с компьютера (через терминал), и с кнопок тоже:



Это все конечно баловство, но работает. Вот подключится к блокам управления автомобиля уже интереснее. Модуль 2CAN решил подключить к центральному блоку управления легкового автомобиля, и по USB подключить его к персональному компьютеру, чтобы иметь возможность видеть какими данными обмениваются многочисленные блоки управления в автомобиле (оснащенного CAN шиной), и по необходимости самому посылать произвольные команды. Для начала, чтобы потренироваться пересылать данные по CAN шине между собой (двумя интегрированными на модуле блоками CAN), желательно сделать вот такую схему:


Хотя бы так:


С другой стороны:


Но если вы подключаетесь уже к готовой функционирующей сети CAN, то это делать нет необходимости. К модулю допаяны светодиоды и кнопка, для отладки и наблюдения за работой модуля. И контакты для программирования по SWD. Что и куда подробно написано в комментариях в проекте. Модуль также при подключении к компьютеру по USB и будет определяться как последовательный порт (с использованием драйвера от ST). На что надо обратить внимание, блоки CAN микроконтроллера будут инициализироваться если:

Выводы микроконтроллера правильно сконфигурированы.

Выводы подключены к микросхемам – драйверам CAN шины.

На CAN шине выставлено правильное напряжение.

форма сигналов должна быть примерно такой:



Небольшая проблема возникла при приеме сигналов в модуль CAN2 (Sleave), нет смысла искать ответа в интернете и на форумах, в большинстве случаев будет лишняя трата времени, да и примеры готовые то в eclipse, то Iar, или вообще на ассемблере. А Я вот пишу в Keil (можно скачать бесплатно, немного обрезанную функционально версию). Оказывается, надо любить внимательно читать комментарии в стандартной библиотеке от STM. Необходимо просто правильно настраивать фильтр приема сообщений, и вот как раз на CAN2 (CAN Sleave) там отдельная процедура дополнительная. Для примера и приведу инициализацию CAN Sleave:

Выводы:

//---------------------------------------------------------------
void CAN2_IOInit(void)
{
  GPIO_InitTypeDef    GPIO_InitStructure;
// Config CAN2 pin TX
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_CAN2_TX;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIO_CAN2, &GPIO_InitStructure);
// Config CAN2 pin RX
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_CAN2_RX;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIO_CAN2, &GPIO_InitStructure);
  GPIO_PinRemapConfig(GPIO_Remap_CAN2, ENABLE);  
  //режим работы трансивера 2 — нормальный/0-только слушаем  
  GPIO_InitStructure.GPIO_Pin = STBN2_GPIO_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(STBN2_GPIO_PORT, &GPIO_InitStructure);
  GPIO_WriteBit(STBN2_GPIO_PORT,STBN2_GPIO_PIN, Bit_SET);
}

Прерывания:

//---------------------------------------------------------------
void nvic_can2(void)
{
 NVIC_InitTypeDef     NVIC_InitStructure;
//настроим прерывание для приема CAN1 сообщения
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
 // прерывание по приему в фифо 0
 NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x1;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);
 // прерывание по приему в фифо 1
 NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX1_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x2;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);
 //прерывание по освобождению буфера передачи
 NVIC_InitStructure.NVIC_IRQChannel = CAN2_TX_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x3;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);
 //прерывание изменения статуса CAN2
 NVIC_InitStructure.NVIC_IRQChannel = CAN2_SCE_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x4;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);
}
//---------------------------------------------------------------

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

//---------------------------------------------------------------
//настроим CAN2, Sleave на нормальный режим,
//не инициализируется если неправильно сконфигурированы выводы или неправильное напряжение на драйвере
void mycan2_init(void)
{
 CAN_InitTypeDef        CAN_InitStructure;
 //тактирование выводов
 RCC_APB1PeriphClockCmd( RCC_APB2Periph_GPIO_CAN2, ENABLE);
 //тактирование модулей CAN
 RCC_APB1PeriphClockCmd( RCC_APB1Periph_CAN2, ENABLE);
 CAN2_IOInit();
 CAN_DeInit(CAN2);    // CAN register deinit
 CAN_StructInit(&CAN_InitStructure);
 // CAN cell init
 CAN_InitStructure.CAN_ABOM = DISABLE;
 CAN_InitStructure.CAN_AWUM = DISABLE;
 CAN_InitStructure.CAN_NART = ENABLE;
 CAN_InitStructure.CAN_RFLM = DISABLE;
 CAN_InitStructure.CAN_TXFP = DISABLE;
 CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
 //CAN_InitStructure.CAN_Mode = CAN_Mode_Silent;  //слушаем шину
 //CAN_InitStructure.CAN_Mode = CAN_Mode_LoopBack; //для тестирования без других внешних устройств

 //CAN_InitStructure.CAN_Mode = CAN_Mode_Silent_LoopBack;
// APB1 у нас работает на частоте 36МГц,
//Рекомендуется принимать следующие значения таймингов
//BaudRate= 1000  BRP=  4  SJW = 1  BS1= 4 BS2= 4
//BaudRate= 500   BRP=  9  SJW = 1  BS1= 3 BS2= 4
//BaudRate= 250   BRP= 16  SJW = 1  BS1= 4 BS2= 4
//BaudRate= 125   BRP= 32  SJW = 1  BS1= 4 BS2= 4
//нам тут надо на 250
 CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
 CAN_InitStructure.CAN_BS1 = CAN_BS1_4tq;
 CAN_InitStructure.CAN_BS2 = CAN_BS2_4tq;
 CAN_InitStructure.CAN_Prescaler = 16;
 
 do
 {
   LedG(1);   //если инициализация не прошла, то светим зеленым
   Delay(100);
   LedG(0);
   Delay(10);
 }
 while(CAN_Init(CAN2, &CAN_InitStructure) == CAN_InitStatus_Failed);
   LedG(0);
 // Разрешение прерываний от модулей CAN2
 CAN_ITConfig(CAN2, CAN_IT_FMP0 |
           CAN_IT_FMP1 |
           CAN_IT_TME |
           CAN_IT_EWG |
           CAN_IT_EPV |
           CAN_IT_LEC |
           CAN_IT_ERR,
           ENABLE);
}
//---------------------------------------------------------------

И фильтр сообщений:

//---------------------------------------------------------------
// CAN Sleave filter init
// для этого кана надо особым образом задать номер фильтра,
// а затем указать номер фильтра
void canfilter2_init(void)
{
 CAN_FilterInitTypeDef   CAN_FilterInitStructure;
 CAN_SlaveStartBank(1);                    //задаем номер фильтра для can-слейва
 CAN_FilterInitStructure.CAN_FilterNumber = 1;         //и ссылаемся на него
 CAN_FilterInitStructure.CAN_FilterMode       = CAN_FilterMode_IdMask;
 CAN_FilterInitStructure.CAN_FilterScale      = CAN_FilterScale_32bit;
 CAN_FilterInitStructure.CAN_FilterIdHigh      = 0x0000;
 CAN_FilterInitStructure.CAN_FilterIdLow      = 0x0000;
 CAN_FilterInitStructure.CAN_FilterMaskIdHigh    = 0x0000;
 CAN_FilterInitStructure.CAN_FilterMaskIdLow    = 0x0000;
 CAN_FilterInitStructure.CAN_FilterFIFOAssignment  = 0;
 CAN_FilterInitStructure.CAN_FilterActivation    = ENABLE;  //нет фильтра — нет приема
 CAN_FilterInit(&CAN_FilterInitStructure);
}
//---------------------------------------------------------------

Обработчик прерываний CAN Sleave:

/*======================================================================================*/
void CAN2_RX0_IRQHandler(void)
{
 LedB(1);
 if (CAN_GetITStatus(CAN2,CAN_IT_FMP0))
  {
   CAN_ClearITPendingBit(CAN2, CAN_IT_FMP0);
   CAN_Receive(CAN2, CAN_FIFO0, &msg_buf2);
   CAN_FIFORelease(CAN2,CAN_FIFO0);
   can2_resive0=1;
  }
}
/*======================================================================================*/
void CAN2_RX1_IRQHandler(void)
{
 LedB(1);
 if (CAN_GetITStatus(CAN2,CAN_IT_FMP1))
  {
   CAN_ClearITPendingBit(CAN2, CAN_IT_FMP1);
   CAN_Receive(CAN2, CAN_FIFO1, &msg_buf2);
   CAN_FIFORelease(CAN2,CAN_FIFO1);
   can2_resive1=1;
  }
}
/*======================================================================================*/
void CAN2_TX_IRQHandler(void)
{
 LedR(1); 
  if (CAN_GetITStatus(CAN2,CAN_IT_TME))
   {                
      CAN_ClearITPendingBit(CAN2,CAN_IT_TME);
  }
}
/*======================================================================================*/
//прерывание по изменению состояния CAN2
void CAN2_SCE_IRQHandler(void)
{
  LedG(1); //была ошибка   
 if (CAN_GetITStatus(CAN2,CAN_IT_ERR)==SET)
  {
   CAN_ClearITPendingBit(CAN2,CAN_IT_ERR);  //Error Interrupt
  }
 if (CAN_GetITStatus(CAN2,CAN_IT_LEC)==SET)  //Last error code Interrupt
  {
   CAN_ClearITPendingBit(CAN2,CAN_IT_LEC);
  }
 if (CAN_GetITStatus(CAN2,CAN_IT_EPV)==SET)  //Error passive Interrupt
  {
   CAN_ClearITPendingBit(CAN2,CAN_IT_EPV);
  }
 if (CAN_GetITStatus(CAN2,CAN_IT_EWG)==SET)  //Error warning Interrupt
  {
   CAN_ClearITPendingBit(CAN2,CAN_IT_EWG);
  }
 if (CAN_GetITStatus(CAN2,CAN_IT_BOF)==SET)  //Error warning Interrupt
  {
   CAN_ClearITPendingBit(CAN2,CAN_IT_BOF);  //Bus-off Interrupt
  }
}

Добавлю и тактирование процессора stm32f105 (у stm32f103 все проще):

RCC_DeInit();
                    RCC_HSEConfig(RCC_HSE_ON);     // включаем внешний генератор HSE 16MHz
                    RCC_WaitForHSEStartUp();         // ждем пока включится
                    /* Enable Prefetch Buffer */
                    // разрешаем буфер предварительного чтения флеша
                    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
                    /* Flash 2 wait state */
                    //для частоты от 48MHz до 72MHz требуется два такта ожидания чтения флеша 
                    FLASH_SetLatency(FLASH_Latency_2);

                    /* HCLK = SYSCLK */
                    RCC_HCLKConfig(RCC_SYSCLK_Div1);
                    /* PCLK1 = HCLK / 2 = 36MHZ но частота для таймеров  * 2 в данном случае */
                    RCC_PCLK1Config(RCC_HCLK_Div2);    //зададим частоту шины APB1 и ее периферии
                    /* PCLK2 = HCLK / 2 = 36MHZ но частота для таймеров  * 2 в данном случае */
                    RCC_PCLK2Config(RCC_HCLK_Div2); //зададим частоту шины APB2 и ее периферии
                    //зададим частоту ADC (максимум 14МГЦ)
                    /* PCLK2 / 4 = 9 MHZ */
                    RCC_ADCCLKConfig(RCC_PCLK2_Div4);
                    // Configure PLLs ********************************************************
                    // PPL2 configuration: PLL2CLK = (HSE / 16) * 8 = 8 MHz
                    RCC_PREDIV2Config(RCC_PREDIV2_Div16);
                    RCC_PLL2Config(RCC_PLL2Mul_8);

                    // Enable PLL2
                    RCC_PLL2Cmd(ENABLE);
                    // Wait till PLL2 is ready
                    while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET){}
                    // PPL1 configuration: PLLCLK = (PLL2 ) * 9 = 72 MHz
                    RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div1);
                    RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);                    
                    // команда запустить тактирование от PLL
                    RCC_PLLCmd(ENABLE);
                    /* Wait till PLL is ready */
                    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}
                    /* Select PLL as system clock source */
                    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
                    /* Wait till PLL is used as system clock source */
                    while (RCC_GetSYSCLKSource() != 0x08){}
  //включаем тактирование модулей GPIO и ADC

                    RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOA |
                                                                    RCC_APB2Periph_GPIOB |
                                                                    RCC_APB2Periph_GPIOC |
                                                                    RCC_APB2Periph_AFIO     |
                                                                    RCC_APB2Periph_ADC1,
                                                                    ENABLE); 


Все подробно можно посмотреть будет уже в проекте (KEIL).



Что в итоге получилось:


Слева направо: плата STM32L в качестве программатора, модуль 2CAN, центральный блок управления автомобиля с двумя шинами CAN (высокоскоростная и низкоскоростная).

Вид без корпуса на процессор блока управления:



После того как запрограммировали модуль (прямо из KEIL, ST-Link SWD), через пару секунд после подключения USB кабеля в micro-USB разъем модуля 2CAN в компьютере определяется последовательный порт. Добавляем драйвера по необходимости, настраиваем номер порта, запускаем терминал, подаем команду "?"+«Enter», модуль отвечает своим меню:


Подаем питание на блок управления автомобиля (в соответствии с документацией производителя), и видим сообщения, в которых блок управления пытается понять где сам автомобиль:


Сигнал CANH на приборе(CANL зеркален по горизонтали и немного смещен):


В остальном все заработало без проблем. Данные с блока управления автомобиля по его шинам CAN High Speed (500) и CAN Low Speed (250) сыпались в терминал без ошибок и пропусков. Более глобальной цели на данный момент я не ставил. В проекте часть кода заимствована из выложенных проектов других людей, часть написал, конечно сам. Добавлял комментарии на русском. Так как управление модулем происходило по виртуальному последовательному порту, через программу «Терминал», в микроконтроллере постоянно работает процедура, принимающая данные от компьютера, разбирающая их на команды и аргументы. Нажав в терминале «?» и «Enter», получим от микроконтроллера список доступных команд и аргументов. По крайней мере, можно наверняка найти и другие недорогие способы использования для подобных вещей. В остальном, думаю разберетесь. Если что, можно задавать вопросы. Попробую выложить заодно файлы проектов, схем и документации, как появится возможность на этой страничке. Или если есть куда выложить мег. 70 полного архива, включающего полную документации и библиотеки. Извиняюсь за стиль кода и изложение, так как программирование не моя основная работа, делал все урывками, и ушло на все времени две недели.

Или спрашивайте тут, постараюсь ответить (статья начала 2015 года).

Далее, на примере данного блока напишу работу с автомобилем.

(в связи с кончиной сайта, где я раньше публиковался, ветка общения со специалистами пропала к сожалению)

С уважением, Астанин Сергей.
ICQ 164487932
Проект приложен.
схемы в лучшем разрешении в pdf в архивах.
  • +8
  • 18 февраля 2016, 16:54
  • astaninss
  • 3

Комментарии (28)

RSS свернуть / развернуть
А могли бы скинуть отдельно ссылки на архив с проектом и на архив с мусором в виде той документации, что заняла 99% из Вашего архива. Захотел взглянуть на код, и пришлось скачать почти целых 70Мб посторонних файлов. Коду есть куда рости=) Не примите за критику, просто к слову=)
0
Почищенный от «мусора» проект вообще желательно к топику приаттачить, а не на стороннем ресурсе выкладывать.
0
А что за осцил на фотке? Если не секрет, то какая основная работа у Вас?
0
А что за осцил на фотке?
OWON56062 вроде как…
0
Не особо гуглится=( Похож на DSO5xxx
0
Похож на DSO5xxx
Да — SDS я не заметил. Но не гуглится почему-то.
0
Owon SDS6062, на нем же написано.
0
Благодарю, сам не рассмотрел.Может есть какая информация о его цена/качество? Аналоги… стоит ли присматриваться?
0
Понятия не имею. Раньше, несколько лет назад, ОВОНы проходили по разряду «тормозноват, но за такую-то цену!», нынче хз — вроде конкуренты по цене есть.
0
пока в автоцентре работаю…
Стоит ли опубликовать еще подобное тут (не всегда свзанное с STM32)?
0
Оф. сервис?
Тут в последнее время публикуют и не такое=) Думаю что интерес будет в любом случае
0
Подскажите, пожалуйста, а ELM327 нельзя использовать для этих целей?
0
думаю нет, там функционал свой, и ограничен прошивкой микроконтроллера, который сам занимается трансляцией в основном команд протокола OBD2.
0
CAN Sleave — только на приём может работать?
0
Slave? В STM32? Может работать как захотите (хотя есть небольшие ограничения). Вот только не ясно, что Вам помешало посмотреть в сдаташит на контроллер?
0
Файл в приложении был испорчен, выложил заново.
0
Ща вообще никаких аттачей нет.
0
действительно странно, пытаюсь выложить, сохраняюсь — нет его… может сбой какой либо, либо не судьба, попозже попробую…
0
продублировал:
yadi.sk/d/jpxagNnxpjZN6
0
Ходовые огни назад в отражатель светят? Интересная конструкция фары
0
Модуль 2CAN может работать с шиной Fault Tolerant CAN Transceiver?
0
Судя по начинке модуля — нет, не может.
Драйвер должен быть TJA1055, а установлен TJA1048.
Просто заменой одной микросхемы на другую решить вопрос не получится. Распиновка разная.
0
Поделитесь, пожалуйста, схемой 2CAN модуля.
0
Добавил
0
Спасибо!
0
Тем, кто будет использовать фильтры в CAN модуле. Обратите внимание, если вы настроите фильтр не на прием всех сообщений (0 во все регистры), то маску надо смещать на три бита влево, иначе не заработает (точнее заработает, но будет фильтровать совсем не те сообщения). В даташите о том ни слова, но разглядывая регистры в том же даташите это можно понять.
0
Мне понравилось, что они включили в в фильтрацию RTR
На картинке Figure 229. Filter bank scale configuration — register organization вроде-бы все понятно нарисовано.

У 105/107 есть еще прикол в том, что надо обязательно указатель на фильтры CAN2 инициализировать. Иначе он указывает куда-то вдаль и приема нет. :)
0
Я и говорю, текстом не написано, но по картинке — понятно.
Текстом там «Положите желаемую маску в регистр», а остальное додумывай дальше:)
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.