Настройка таймингов работы CAN шины является одним из наиболее важных моментов в настройке bxCan. Если ошибиться, то устройство может оказаться полностью работоспособным в режиме отладки и отказаться работать при подключении к рабочей шине CAN.

Наверное больше всего возникает вопросов в том, что же это такое и как правильно эти тайминги настроить.

 

Опять теория

Напомню, что протокол CAN (Controller Area Network) - представляет собой асинхронную последовательную шину с битовым кодирование NRZ (Non Return to Zero), разработанную для быстрой и надежной связи в жестких условиях, такие как автомобильные или промышленные сети. Протокол CAN позволяет программно настраивать скорость передачи данных в широком диапазоне (до 1 Мбита). Для того, чтобы работа CAN шины была стабильной, необходимо правильно указать параметры настройки синхронизации и временных интервалов (таймингов).

Синхронизация и тайминги в CAN — важный и сложный вопрос, но благодаря сложности и продуманности становится не так важна возможная рассинхронизация и нестабильность тактовых частот узлов сети, а связь становится возможной даже в сложных условиях, когда на линию могут воздействовать различные помехи.

Так давайте же разберемся в этом подробнее:

Рис. 1. Bit Timing

 

Механизм синхронизации битов контролирует шину и выполняет выборку и корректировку точек захвата бита (Sample Point) путем синхронизации при начале передаче бита и ресинхронизации при прекращении передачи этого бита.

Этот процесс можно объяснить путем простого деления номинального времени передачи бита на три сегмента:

Сегмент синхронизации (SYNC_SEG): изменение бита, как ожидается, произойдет в течение этого отрезка времени. Он имеет фиксированную длину одного кванта времени (1 х tq). 
Сегмент фазы 1 (BS1): определяет местоположение точки захвата (Sample Point). Он включает в себя Prop_Seg и PHASE_SEG1 стандарта CAN. Его продолжительность программируется от 1 до 16 квантов времени, но может быть автоматически увеличена для компенсации положительной фазы дрейфов из-за различий в частоте работы на различных узлах сети.
Сегмент фазы 2 (BS2): определяет местоположение точки передачи. Он представляет собой PHASE_SEG2 стандарта CAN. Его продолжительность программируется от 1 до 8 квантов времени, но также может быть автоматически изменена в сторону уменьшения для компенсации отрицательной фазы заносов.  

Ширина перехода ресинхронизации (SJW - reSynchronization Jump Width) определяет максимальное количество квантов времени, на которое может быть увеличено или уменьшено количество квантов времени битовых сегментов. Возможные значения этого показателя составляют от 1-го до 4-х квантов.

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

Если этот переход обнаружен в сегменте BS1 вместо сегмента Sync_Seg, то сегмент BS1 продлевается таким образом, чтобы достичь точки захвата бита путем увеличения длительности сегментов на значение SJW. И наоборот, если переход обнаружен в сегменте BS2 вместо Sync_Seg, то BS2 укорачивается так, чтобы точка захвата сформировалась раньше. Таким образом происходит постоянная пересинхронизация  с целью синхронизации с другими узлами шины. (Забавно звучит :) )

Согласно стандарту CAN, оптимальный момент времени для Sample Point составляет 87.5% от номинальной длительности передачи бита. 

Расчет временных интервалов и регистры, в которых они хранятся - приведен на рисунке 2.

Рис. 2. Расчет временных интервалов

  

APB Clock - это частота, с которой работает периферия микроконтроллера. Она настраивается при запуске программы на микроконтроллере, но об этом ниже.

Стоит заметить, что для предотвращения ошибок  программирования, конфигурация регистра CAN_BTR (Bit Timing Register) возможна только тогда, когда bxCan находится в режиме ожидания.

 

Теперь, когда Вы это все прочитали и половину не поняли, опишу простыми словами (далее цитата с одного из форумов, очень понравилась :)) :

Бит поделен на сегменты, каждый сегмент состоит из квантов, кол-во которых вы настраиваете:

• Сегмент синхронизации - по нему идет синхронизация с шиной, для длинных шин с заваленными фронтами его делают чуть шире.
• Сегмент фазы 1 (BS1) - это кванты, которые аппаратная часть выжидает, прежде чем сделать захват состояния шины.
• Сегмент фазы 2 (BS2) - это кванты, которые пройдут прежде, чем начнется прием нового бита.

Сумма этих квантов * период кванта = периоду бита выбранной скорости.

BS1 и BS2 в разных узлах сети могут быть разные, это зависит еще от частоты микроконтроллера, аппаратными средствами может изменяться на величину SJW.

 

 

Реализация

Разобравшись с теорией, приступим к реализации.

Тактирование

Рассмотрим все на примере STM32F103C8 в CooCox CoIDE.

Разработчики уже позаботились о нас и при создании чистого проекта по умолчанию настраивает работу микроконтроллера на максимальную для него частоту. В нашем случае это STM32F103C8 с максимальной частотой работы 72MHz.

Но нам нужны не стандартные настройки, а свои, так как играясь с калькулятором (см. ниже) мы выяснили, что нам нужна частота периферии 16MHz. Для экспериментов я создал проект в STM32CubeMX и поигрался с Clock configuration. Получилась следующая картинка:

Рис. 3. Настройка тактирования микроконтроллера STM32F103C8

Из рисунка мы видим что для того, чтобы настроить периферию для работы на частоте 16MHz, мы должны настроить работу контроллера на максимальной частоте 64MHz. Для этого нам необходимо установить множитель PLLMul равным восьми (8MHz кварц * 8 = 64MHz). Затем выставляем делитель для периферии (APB1 prescaller) равный 4. В итоге получили частоту шину ту, которую и хотели - 16MHz.

С теорией разобрались, теперь реализуем это все в коде:

Листинг №1. Настройка тактирования микроконтроллера
    /**
    * @brief  Настройка тактирования микроконтроллера
    * @brief  Ядро - 64MHz, перефирия APB1 - 16 MHz
    *
    * @note   Эта функция предназначена для настройки микроконтроллеров серия STM32F103C8.
    * @param  None
    * @retval None
    */
void RCC_Config(void)
{
	// Для настройки CAN в максимальном режиме работы на скорости до 1Mb нам необходимо
	// Настроить частоту перефирии APB1 на 16 MHz

	RCC_ClocksTypeDef RCC_Clocks;
	ErrorStatus HSEStartUpStatus;

	// Сбросим настройки тактирования системы
	RCC_DeInit();                                                    // RCC system reset

	// Включим внешний кварц, как источник сигнала
	RCC_HSEConfig(RCC_HSE_ON);                                       // Enable HSE

	HSEStartUpStatus = RCC_WaitForHSEStartUp();                      // Подождем включения HSE

	if (HSEStartUpStatus == SUCCESS) {                               // Если включился кварц
		// Настроим тактирование так, как нам требуется
		RCC_HCLKConfig(RCC_SYSCLK_Div1);                         // HCLK = SYSCLK     (64MHz)
		RCC_PCLK1Config(RCC_HCLK_Div4);                          // PCLK1 = HCLK / 8  (16MHz)
		RCC_PCLK2Config(RCC_HCLK_Div1);                          // PCLK2 = HCLK         (64MHz)
		RCC_ADCCLKConfig(RCC_PCLK2_Div2);                        // ADC CLK

		RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_8);     // PLLCLK = 8MHz * 8 = 64 MHz
		RCC_PLLCmd(ENABLE);                                      // Включаем PLL

		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {}   // Ждем включения PLL

		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);               // Выбираем PLL как источник
                                                                         // системного тактирования

		while (RCC_GetSYSCLKSource() != 0x08) {}                 // Ждем, пока не установится PLL,
                                                                         // как источник системного тактирования
	}

	// Предназначен для отладки, проверяем, как настроены частоты устройства
	RCC_GetClocksFreq (&RCC_Clocks);
}

Код я постарался по максимуму прокомментировать, нам осталось только вставить его в наш проект.

Небольшое замечание: если на Вашем устройстве не используется внешний кварц, то по этому коду микроконтроллер будет настроен на частоту работы в 8MHz. 

Также, в строке 47 приведенного код стоит функция получения текущих настроек тактовой частоты. В рабочем проекте ее можно убрать.

Если остановится на ней отладчиком и отследить содержимое переменной RCC_Clocks, то мы увидим примерно следующее содержание:

Рис. 4. Результат настройки тактирования

Видно, что после инициализации у нас процессор работает на частоте 64000000 (64MHz), а частота работы периферии APB1 составляет 16000000 (16MHz). Мы добились желаемого результата.

 

Настройка таймингов

Настроив тактирование нашего контроллера (напомню, учимся на STM32F103Cx), перейдем к настройке таймингов.

Для этого удобнее всего пользоваться калькуляторами, я, например, пользуюсь вот этим. Достаточно выбрать семейство микроконтроллеров, указать частоту шины и нажать кнопку "Request Table". Калькулятор нам предложит различные комбинации таймингов и желтым цветом укажет на оптимальные:

Рис.5. Результат работы калькулятора

Поигравшись с частотой работы периферии, мы видим, что оптимальным для нас будет частота в 16MHz. На эту частоту работы мы и настроили чуть выше работу периферии микроконтроллера. Теперь же опишем в нашей программе настройку таймингов работы CAN шины.

Для начала опишем определения прескалера, чтобы было удобнее в дальнейшем настраивать скорость на нашем устройстве:

Листинг №2. Описание определений прескалера
	// Выбор скорости шины
	// Необходимо раскомментировать нужную строку
	#define CAN1_SPEED_PRESCALE               1                        // 1000 Kb
	// #define CAN1_SPEED_PRESCALE            2                        // 500 Kb
	// #define CAN1_SPEED_PRESCALE            4                        // 250 Kb
	// #define CAN1_SPEED_PRESCALE            8                        // 125 Kb
	// #define CAN1_SPEED_PRESCALE            10                       // 100 Kb
	// #define CAN1_SPEED_PRESCALE            12                       // 83.3 Kb
	// #define CAN1_SPEED_PRESCALE            20                       // 50 Kb
	// #define CAN1_SPEED_PRESCALE            50                       // 20 Kb
	// #define CAN1_SPEED_PRESCALE            100                      // 10 Kb

Значения прескалера выбрали исходя из результатов работы калькулятора с настройкой на частоту работы периферии нашего микроконтроллера равной 16MHz.

Теперь выполним саму инициализацию CAN:

Листинг №3. Инициализация CAN
	CAN_DeInit( CAN1);
	CAN_StructInit(&CAN_InitStructure);

	// CAN cell init
	CAN_InitStructure.CAN_TTCM = DISABLE;
	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_LoopBack;     // Для тестирования без подключенных устройств шины
	CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
	CAN_InitStructure.CAN_BS1 = CAN_BS1_13tq;
	CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
	CAN_InitStructure.CAN_Prescaler = CAN1_SPEED_PRESCALE;     // Выбираем нужную скорость
	CAN_Init(CAN1, &CAN_InitStructure);

Описание всех параметров мы рассматривали в предыдущей статье (STM32. Реализация протокола CAN на базе МК STM32F103), здесь же рассмотрим только те параметры, которые непосредственно связаны с настройкой таймингов шины:

Таб. 1. Параметры настройки таймингов CAN
Параметр Расшифровка Пояснение
CAN_SJW Размер SJW SJW (reSynchronization Jump Width) определяет максимальное количество квантов времени, на которое может быть увеличено или уменьшено количество квантов времени битовых сегментов. Возможные значения этого показателя от 1-го до 4-х квантов.
CAN_BS1 Длина сегмента фазы 1 BS1 (Bit Segment 1) - определяет местоположение точки захвата (Sample Point). Он включает в себя Prop_Seg и PHASE_SEG1 стандарта CAN. Его продолжительность программируется от 1 до 16 квантов времени.
CAN_BS2 Длина сегмента фазы 2 BS2 (Bit Segment 2) - определяет местоположение точки передачи. Он представляет собой PHASE_SEG2 стандарта CAN. Его продолжительность программируется от 1 до 8 квантов времени.
CAN_Prescaler Множитель Множитель, из значения которого рассчитывается размер кванта времени. Рассчитывается исходя от частоты работы периферии микроконтроллера.
Важно не путать с частотой работы самого контроллера!

 

Все эти параметры мы заполняем исходя из результатов, полученных с помощью калькулятора, за исключение SJW - на больших скоростях шины, рекомендуется его ставить равным единице, а вот если у нас "длинная" шина, то лучше его выставлять больше. Параметр SJW может принимать значения в диапазоне от 1-го до 4-х.

На этом о таймингах все, если у Вас есть замечания и/или предложения по наполнению статьи - оставляйте в комментариях.

 

 

Заключение

Я очень надеюсь, что это статья поможет новичкам. Мне самому пришлось изучать кучу форумов и мануалы от ST, чтобы разобраться с правильной настройкой CAN. Именно поэтому я постарался максимально просто расписать здесь настройку таймингов, чтобы у начинающих в этом непростом деле быстрее сложилось понимание данного процесса.

За основу для статьи как обычно взяты материалы Programming Reference (перевод мой) для микроконтроллеров STM32 серии F103x с моими комментариями и пояснениями. А также информация с некоторых форумов.

Во вложение добавлены исходники примера настройки таймингов CAN и тактирования контроллера с тестовым примером отправки данных по шине.

 

 

Вложения:
ФайлОписаниеРазмер файла:
Скачать этот файл (CAN_protocol_stm32f103_test_timing.zip)CAN_protocol_stm32f103_test_timing.zipТестовая прошивка220 kB

Комментарии  

#1 Ярослав 08.05.2018 11:59
Спасибо огромное! Реально очень ценно, когда натыкаешься на такие подробные мануалы.
Цитировать
#2 Админ 08.05.2018 12:12
Спасибо огромное!
Я очень старался ))))
Цитировать
#3 Сергей 23.07.2018 16:55
Большущее спасибо Автору!
Расписано идеально!
Цитировать
#4 Админ 23.07.2018 19:00
Цитирую Сергей:
Большущее спасибо Автору!
Расписано идеально!

Спасибо, я рад - значит не зря старался. :lol:
Цитировать
#5 Александр 06.10.2018 19:26
Реально помогло. Спасибо, побольше бы таких статей
Цитировать
#6 Влад 12.12.2018 14:57
Спасибо. Реально помогло. Доходчиво и без воды.
Цитировать
#7 Админ 12.12.2018 14:58
Цитирую Влад:
Спасибо. Реально помогло. Доходчиво и без воды.

Спасибо, я старался :lol:
Цитировать
#8 Виталий 14.02.2020 19:25
Спасибо большое. Перенёс Ваш код в свой проект, заработало. Буду теперь детально разбираться.
Цитировать
#9 Благодарный юзер 30.06.2020 17:53
Отличный материал. Спасибо!
Цитировать
#10 Кирилл 05.07.2020 01:28
Спасибо огромное! Отличная статья, я наконец понял, как работает настройка скорости
Цитировать