Mgeo
Чт, 04 октября 2018 г., 9:26
Привет,
Я пытаюсь собрать пример минимального примера аппаратного захвата входного захвата с использованием прерываний для измерения входного потока импульса (на данный момент один импульсный поток, с 6 входами, которые в конечном итоге будут захвачены для моего предполагаемого приложения.
Я документирую свои усилия здесь, в этой теме.
Джордж
Фон
Я надеюсь получить достаточно понимания этого ядра и управления таймером STM32 для порта этого приложения контроллера полета (http: // www.броккинг.net/ymfc-32_main.HTML). Первоначально это было разработано вокруг немного более ранней версии Roger Libmaple на основе Libmaple Core (Core (http: // www.броккинг.net/ymfc-32_downloads.HTML). Он использует некоторые манипуляции с битом более низкого уровня TIM2-4 для входного захвата на основе прерываний импульсных входов, а также аппаратного управления ШИМ. Приложение использует TIM2 и TIM3 (входной захват пилотных команд из RC -приемника), а также TIM4 (SWM.
Типичный обработчик прерываний входного захвата (переключает направление края входного захвата в рамках прерывания, чтобы получить достаточно входных каналов (необходимы 6 входов на захват импульсов):
Я пытаюсь собрать пример минимального примера аппаратного захвата входного захвата с использованием прерываний для измерения входного потока импульса (на данный момент один импульсный поток, с 6 входами, которые в конечном итоге будут захвачены для моего предполагаемого приложения.
Я документирую свои усилия здесь, в этой теме.
Джордж
Фон
Я надеюсь получить достаточно понимания этого ядра и управления таймером STM32 для порта этого приложения контроллера полета (http: // www.броккинг.net/ymfc-32_main.HTML). Первоначально это было разработано вокруг немного более ранней версии Roger Libmaple на основе Libmaple Core (Core (http: // www.броккинг.net/ymfc-32_downloads.HTML). Он использует некоторые манипуляции с битом более низкого уровня TIM2-4 для входного захвата на основе прерываний импульсных входов, а также аппаратного управления ШИМ. Приложение использует TIM2 и TIM3 (входной захват пилотных команд из RC -приемника), а также TIM4 (SWM.
Типичный обработчик прерываний входного захвата (переключает направление края входного захвата в рамках прерывания, чтобы получить достаточно входных каналов (необходимы 6 входов на захват импульсов):
void handler_channel_1(void) { //This function is called when channel 1 is captured.
if (0b1 & GPIOA_BASE->IDR >> 0) { //If the receiver channel 1 input pulse on A0 is high.
channel_1_start = TIMER2_BASE->CCR1; //Record the start time of the pulse.
TIMER2_BASE->CCER |= TIMER_CCER_CC1P; //Change the input capture mode to the falling edge of the pulse.
}
else { //If the receiver channel 1 input pulse on A0 is low.
channel_1 = TIMER2_BASE->CCR1 - channel_1_start; //Calculate the total pulse time.
if (channel_1 < 0)channel_1 += 0xFFFF; //If the timer has rolled over a correction is needed.
TIMER2_BASE->CCER &= ~TIMER_CCER_CC1P; //Change the input capture mode to the rising edge of the pulse.
}
}
Mgeo
Пт 5 октября 2018 г. 9:53 утра
Моя тестовая настройка:
Arduino Ide 1.85, бег на ноутбуке Win 10.
STM32 Arduino "Официальный" Core v1.3.0, установлен на https: // github.com/stm32duino/wiki/wiki/
Доска Nucleo-F103RB, ST-Link заменен на прошивку J-Link (https: // www.Сеггер.com/products/debug-p ... -на борту/)
Отладчик Segger Ozone (https: // www.Сеггер.com/продукты/Разработка ... -отладчик/)
Логический анализатор SALEAE (https: // www.Сали.ком/)
Некоторые перемычки
Также:
Источник, составленный с использованием опции «Debug (-g)»
Сначала - генерировать периодическую форму импульсного волны на ядрео. Я использую функцию аналога для этой цели. Ниже приведен тестовый эскиз и его выход, измеренный на логическом анализаторе. Выход импульса выглядит так, как и ожидалось, импульсный поток 1 кГц с 25% положительным ШИМ (= 63/255).
Arduino Ide 1.85, бег на ноутбуке Win 10.
STM32 Arduino "Официальный" Core v1.3.0, установлен на https: // github.com/stm32duino/wiki/wiki/
Доска Nucleo-F103RB, ST-Link заменен на прошивку J-Link (https: // www.Сеггер.com/products/debug-p ... -на борту/)
Отладчик Segger Ozone (https: // www.Сеггер.com/продукты/Разработка ... -отладчик/)
Логический анализатор SALEAE (https: // www.Сали.ком/)
Некоторые перемычки
Также:
Источник, составленный с использованием опции «Debug (-g)»
Сначала - генерировать периодическую форму импульсного волны на ядрео. Я использую функцию аналога для этой цели. Ниже приведен тестовый эскиз и его выход, измеренный на логическом анализаторе. Выход импульса выглядит так, как и ожидалось, импульсный поток 1 кГц с 25% положительным ШИМ (= 63/255).
const int testPwmOutputPin = PA0; // PA_0,D46/A0 <<-- works
//const int testPwmOutputPin = A0; // PA_0,D46/A0 <<-- works
//const int testPwmOutputPin = PA_0; // PA_0,D46/A0 <<-- does not work
void setup() {
Serial.begin(115200);
Serial.println("Initializing...");
// initialize digital pins
pinMode(LED_BUILTIN, OUTPUT);
pinMode(testPwmOutputPin, OUTPUT);
analogWrite(testPwmOutputPin, 63);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
Mgeo
Сб 6 октября 2018 г. 10:08
Средственно, в моем простом выводе выше пример, я попытался понять псевдонимы имени вывода, выполнив поиск по файлам. Я обнаружил, что для аналогового вывода 0 для моего варианта ucleo-f103rb должен быть PA_0 за https: // github.com/stm32duino/arduino_c ... н.д.CPP#178
Но тестирование показало, что A0 работает, PA0 также работает, но PA_0 хорошо компилируется, но я не получаю вывод ШИМ. Это следовало ожидать? Кажется, это не вписывается в пример, который я использовал отсюда (https: // www.STM32duino.com/viewtopic.PHP?P = 34555#P34555).
См. Предыдущие примеры определения кода.
Но тестирование показало, что A0 работает, PA0 также работает, но PA_0 хорошо компилируется, но я не получаю вывод ШИМ. Это следовало ожидать? Кажется, это не вписывается в пример, который я использовал отсюда (https: // www.STM32duino.com/viewtopic.PHP?P = 34555#P34555).
См. Предыдущие примеры определения кода.
const int testPwmOutputPin = PA0; // PA_0,D46/A0 <<-- works
//const int testPwmOutputPin = A0; // PA_0,D46/A0 <<-- works
//const int testPwmOutputPin = PA_0; // PA_0,D46/A0 <<-- does not work
Mgeo
Сб 6 октября 2018 г. 10:34
Отслеживание моего простого примера в отладчике озона, я вижу, что аналоговая запись с A0 использует TIM2, как и ожидалось, так как PIN PIN PIN - по умолчанию TIM2_CH1 в DataShip DataShing STM32F103.
Таким образом, для моих примеров захвата ввода я буду ориентироваться на TIM3 и TIM4 и надеюсь, что за кулисами не будет никакого другого.
Спасибо,
Джордж
Таким образом, для моих примеров захвата ввода я буду ориентироваться на TIM3 и TIM4 и надеюсь, что за кулисами не будет никакого другого.
Спасибо,
Джордж
Mgeo
Сб 6 октября 2018 г. 11:04
В инструменте STM32Cubemx мы можем быстро обнаружить, что карты TIM3_CH1 по умолчанию по умолчанию, поэтому я подключу перемычку с моего известного хорошего 1 кГц / 25% -ного цикла ШИО ШИМ на PA0 / A0 к PA6 на плате Nucleo.
Вот фото, чтобы показать, как это выглядит в STM32Cubemx:
Этот пост (https: // www.STM32duino.com/viewtopic.PHP?P = 44629#P44629) говорит мне, что HAL доступны на уровне Sketch, и что некоторые драйверы HAL включены по умолчанию. Hal Conf доступен в варианте. Например, для нуклео F103RB находится в https: // github.com/stm32duino/arduino_c ... hal_conf.час В этом файле я вижу, что Тим был включен для моей платы с #define hal_tim_module_enabled, поэтому я думаю, что я хорошо перейти с TIM3/TIM4. Я ожидал этого, но хорошо знать, как подтвердить.
Важно помнить для будущего использования -
Если вам нужен модуль HAL, не включен, можно создать "build_opt.Файл H "на уровне эскиза, затем добавьте желаемый модуль:
"-DHAL_CRC_MODULE_ENABLE -DHAL_XXX_MODULE_ENABLED ..." и т. д.
Вот фото, чтобы показать, как это выглядит в STM32Cubemx:
Этот пост (https: // www.STM32duino.com/viewtopic.PHP?P = 44629#P44629) говорит мне, что HAL доступны на уровне Sketch, и что некоторые драйверы HAL включены по умолчанию. Hal Conf доступен в варианте. Например, для нуклео F103RB находится в https: // github.com/stm32duino/arduino_c ... hal_conf.час В этом файле я вижу, что Тим был включен для моей платы с #define hal_tim_module_enabled, поэтому я думаю, что я хорошо перейти с TIM3/TIM4. Я ожидал этого, но хорошо знать, как подтвердить.
Важно помнить для будущего использования -
Если вам нужен модуль HAL, не включен, можно создать "build_opt.Файл H "на уровне эскиза, затем добавьте желаемый модуль:
"-DHAL_CRC_MODULE_ENABLE -DHAL_XXX_MODULE_ENABLED ..." и т. д.
Рик Кимбалл
Сб 06 октября 2018 г. 12:10
[Mgeo - Сб 6 октября 2018 г. 10:34] - Если кто-то знает полезную работу, пожалуйста, сообщите.Используйте что -то вроде Imgur.com или flickr.com или tinypic.компонент
fpistm
Сб, 6 октября 2018 г., 16:48
PA_0 - это имя PIN -кода, а не номер PIN -кода.
PA0 не равен PA_0.
Это компиляция с использованием PA_0, потому что это также UINT32_T по запросу
PA0 не равен PA_0.
Это компиляция с использованием PA_0, потому что это также UINT32_T по запросу
analogWrite( uint32_t ulPin, uint32_t ulValue ) ;
Mgeo
Сб 6 октября 2018 г., 22:00
Отлично спасибо за входные данные. Понятно, что мне нужно знать о том, какие таймеры используются функциями Arduino, такими как Analogwrite, если я хочу взять второй TIM для моего собственного использования HAL в качестве захвата ввода.
Мой тестовый эскиз (по вышеуказанному) будет иметь фоновую функцию светодиодного мигания сердца с использованием функции Delay (). Я надеюсь, что задержка использует Systick в качестве таймера системы и не использует один из таймеров F103RB (TIM1, TIM2, TIM3, TIM4).
Джордж
Мой тестовый эскиз (по вышеуказанному) будет иметь фоновую функцию светодиодного мигания сердца с использованием функции Delay (). Я надеюсь, что задержка использует Systick в качестве таймера системы и не использует один из таймеров F103RB (TIM1, TIM2, TIM3, TIM4).
Джордж
Mgeo
Солнце 07 октября 2018 г. 9:48
От UM1725, руководство пользователя, описание драйверов STM32F4 HAL и LL
https: // www.ул.com/content/ccc/resource ... 105879.PDF
Если я правильно понимаю вещи, я думаю, что мне нужно сделать шаги, выделенные ниже синим цветом на TIM3, чтобы иметь возможность захватить сгенерированный TIM2 -поток импульсного импульса, который я сгенерировал на PA0, используя AnalogWrite (), как показано выше. Я не уверен в том, что «настроить эти контакты TIM в режиме альтернативной функции, используя hal_gpio_init ()» и как мне нужно сделать это на F1.
65.2 Описание API API прошивки TIM
65.2.2 Как использовать этот драйвер
1. Инициализировать ресурсы низкого уровня TIM, внедрив следующие функции
в зависимости от используемой функции:
Время база: hal_tim_base_mspinit ()
Входной захват: hal_tim_ic_mspinit ()
Выход Сравнение: hal_tim_oc_mspinit ()
Generation: HAL_TIM_PWM_MSPINIT ()
Выход режима однопульсного режима: hal_tim_onepulse_mspinit ()
Выход режима энкодера: hal_tim_encoder_mspinit ()
2. Инициализируйте ресурсы низкого уровня TIM:
а. Включить интерфейс TIM с использованием __timx_clk_enable ();
беременный. Конфигурация Тим Пинс
Включите часы для TIM GPIOS, используя следующую функцию:
__Gpiox_clk_enable ();
Настройте эти контакты TIM в режиме альтернативной функции, используя hal_gpio_init ();
3. Внешние часы можно настроить, если это необходимо (часы по умолчанию - внутренние часы
из APBX), используя следующую функцию: hal_tim_configclocksource, часы
Конфигурация должна быть выполнена перед какой -либо начальной функцией.
4. Настройте TIM в желаемом режиме функционирования, используя одну из инициализации
Функция этого драйвера:
HAL_TIM_BASE_INIT: использовать таймер для создания простой временной базы
HAL_TIM_OC_INIT и HAL_TIM_OC_CONFIGCHANLANLE: для использования таймера для
Сгенерировать выходной сигнал сравнения.
HAL_TIM_PWM_INIT и HAL_TIM_PWM_CONFIGCHCHANLEN: для использования таймера для
генерировать сигнал ШИМ.
HAL_TIM_IC_INIT и HAL_TIM_IC_CONFIGCHANLANLE: для использования таймера для измерения
внешний сигнал.
HAL_TIM_ONEPULSE_INIT и HAL_TIM_ONEPULSE_CONFIGCHANLANL: для использования
Таймер в одном режиме пульса.
hal_tim_encoder_init: использовать интерфейс энкодера таймера.
5. Активируйте периферийную работу TIM, используя одну из начальных функций в зависимости от этой функции
использовал:
База времени: hal_tim_base_start (), hal_tim_base_start_dma (),
Hal_tim_base_start_it ()
Захват ввода: hal_tim_ic_start (), hal_tim_ic_start_dma (),
Hal_tim_ic_start_it ()
Выход Сравнение: hal_tim_oc_start (), hal_tim_oc_start_dma (),
Hal_tim_oc_start_it ()
Generation: HAL_TIM_PWM_START (), HAL_TIM_PWM_START_DMA (),
Hal_tim_pwm_start_it ()
Выход режима однопульсного режима: hal_tim_onepulse_start (),
HAL_TIM_ONEPULSE_START_IT ()
Выход режима энкодера: hal_tim_encoder_start (),
Hal_tim_encoder_start_dma (), hal_tim_encoder_start_it ().
6. Взрыв DMA управляется с двумя следующими функциями:
Hal_tim_dmaburst_writestart () hal_tim_dmaburst_readstart ()
https: // www.ул.com/content/ccc/resource ... 105879.PDF
Если я правильно понимаю вещи, я думаю, что мне нужно сделать шаги, выделенные ниже синим цветом на TIM3, чтобы иметь возможность захватить сгенерированный TIM2 -поток импульсного импульса, который я сгенерировал на PA0, используя AnalogWrite (), как показано выше. Я не уверен в том, что «настроить эти контакты TIM в режиме альтернативной функции, используя hal_gpio_init ()» и как мне нужно сделать это на F1.
65.2 Описание API API прошивки TIM
65.2.2 Как использовать этот драйвер
1. Инициализировать ресурсы низкого уровня TIM, внедрив следующие функции
в зависимости от используемой функции:
Время база: hal_tim_base_mspinit ()
Входной захват: hal_tim_ic_mspinit ()
Выход Сравнение: hal_tim_oc_mspinit ()
Generation: HAL_TIM_PWM_MSPINIT ()
Выход режима однопульсного режима: hal_tim_onepulse_mspinit ()
Выход режима энкодера: hal_tim_encoder_mspinit ()
2. Инициализируйте ресурсы низкого уровня TIM:
а. Включить интерфейс TIM с использованием __timx_clk_enable ();
беременный. Конфигурация Тим Пинс
Включите часы для TIM GPIOS, используя следующую функцию:
__Gpiox_clk_enable ();
Настройте эти контакты TIM в режиме альтернативной функции, используя hal_gpio_init ();
3. Внешние часы можно настроить, если это необходимо (часы по умолчанию - внутренние часы
из APBX), используя следующую функцию: hal_tim_configclocksource, часы
Конфигурация должна быть выполнена перед какой -либо начальной функцией.
4. Настройте TIM в желаемом режиме функционирования, используя одну из инициализации
Функция этого драйвера:
HAL_TIM_BASE_INIT: использовать таймер для создания простой временной базы
HAL_TIM_OC_INIT и HAL_TIM_OC_CONFIGCHANLANLE: для использования таймера для
Сгенерировать выходной сигнал сравнения.
HAL_TIM_PWM_INIT и HAL_TIM_PWM_CONFIGCHCHANLEN: для использования таймера для
генерировать сигнал ШИМ.
HAL_TIM_IC_INIT и HAL_TIM_IC_CONFIGCHANLANLE: для использования таймера для измерения
внешний сигнал.
HAL_TIM_ONEPULSE_INIT и HAL_TIM_ONEPULSE_CONFIGCHANLANL: для использования
Таймер в одном режиме пульса.
hal_tim_encoder_init: использовать интерфейс энкодера таймера.
5. Активируйте периферийную работу TIM, используя одну из начальных функций в зависимости от этой функции
использовал:
База времени: hal_tim_base_start (), hal_tim_base_start_dma (),
Hal_tim_base_start_it ()
Захват ввода: hal_tim_ic_start (), hal_tim_ic_start_dma (),
Hal_tim_ic_start_it ()
Выход Сравнение: hal_tim_oc_start (), hal_tim_oc_start_dma (),
Hal_tim_oc_start_it ()
Generation: HAL_TIM_PWM_START (), HAL_TIM_PWM_START_DMA (),
Hal_tim_pwm_start_it ()
Выход режима однопульсного режима: hal_tim_onepulse_start (),
HAL_TIM_ONEPULSE_START_IT ()
Выход режима энкодера: hal_tim_encoder_start (),
Hal_tim_encoder_start_dma (), hal_tim_encoder_start_it ().
6. Взрыв DMA управляется с двумя следующими функциями:
Hal_tim_dmaburst_writestart () hal_tim_dmaburst_readstart ()
Mgeo
Солнце 07 октября 2018 г. 14:12
Я ушел в поисках примеров ввода HAL, пакета CubeMX F1 поставляется с примером/проектами/STM3210E_EVAL/Примеры/TIM/TIM_INPUT_CAPUTE, который я изучал и пытался использовать здесь.
Я собрал минимальный тестовый эскиз ниже.
Тим3
Я начал с использования основного таймера STM.Функции на основе C для инициализации TIM3, кражи кода из более раннего примера Mlink Timer Timer в других местах на этом форуме (https: // www.STM32duino.com/viewtopic.PHP?P = 49394#P49394).
Затем я использовал пример Cubemx f1 TIM_INPUT_CAPUTE в качестве руководства для инициализации TIM4. Я думаю, что делаю что -то не так с тем, как я определяю TIM4. Я сбросил сериал TIM3/TIM4 -регистрации.Функция печати, я вижу, что TIM3 правильно инициализируется, но ничего не происходит с TIM4. То же самое и True Stopping через код с озоновым отладчиком.
В этот момент я почесал голову, почему, так что я публикую то, что я даю до сих пор ищу какие -либо советы.
Спасибо,
Джордж
Минимальный тестовый эскиз:
Я собрал минимальный тестовый эскиз ниже.
Тим3
Я начал с использования основного таймера STM.Функции на основе C для инициализации TIM3, кражи кода из более раннего примера Mlink Timer Timer в других местах на этом форуме (https: // www.STM32duino.com/viewtopic.PHP?P = 49394#P49394).
Затем я использовал пример Cubemx f1 TIM_INPUT_CAPUTE в качестве руководства для инициализации TIM4. Я думаю, что делаю что -то не так с тем, как я определяю TIM4. Я сбросил сериал TIM3/TIM4 -регистрации.Функция печати, я вижу, что TIM3 правильно инициализируется, но ничего не происходит с TIM4. То же самое и True Stopping через код с озоновым отладчиком.
В этот момент я почесал голову, почему, так что я публикую то, что я даю до сих пор ищу какие -либо советы.
Спасибо,
Джордж
Минимальный тестовый эскиз:
#define TIMER_PERIOD TIM3
#define TIMER_INPUT_CAPTURE TIM4
// Handle for stimer
static stimer_t TIM_Handle;
// Timer handle declaration
static TIM_HandleTypeDef TimHandle;
// Timer Input Capture Configuration Structure declaration
TIM_IC_InitTypeDef sICConfig;
const int PwmOutputPin = PA0; // PA_0,D46/A0 -- USES TIM2
const int CaptureInputPin = PA6;
const int TestOutputPin = D7; // PA_8,D7
extern "C" void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
UNUSED(htim);
digitalWrite(TestOutputPin, !digitalRead(LED_BUILTIN));
}
void setup() {
Serial.begin(115200);
Serial.println("Initializing...");
Serial.println();
// initialize digital pins
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PwmOutputPin, OUTPUT);
pinMode(TestOutputPin, OUTPUT);
// initialize the input capture pin
// ??? --- I'm not sure if this is enough, do I need to configure my input pin as an 'Input Capture' alternate function --- ???
pinMode(CaptureInputPin, INPUT);
// create a 1KHz 25% (256/4 - 1) duty PWM on testPwmOutputPin
// NOTE - uses TIM associated with output pin
analogWrite(PwmOutputPin, (64 - 1));
// ------- Period TIM3 Setup -------------------------
// Set Period timer TIM instance
TIM_Handle.timer = TIM3;
// Period timer set to 10ms
TimerHandleInit(&TIM_Handle, 10000 - 1, ((uint32_t)(getTimerClkFreq(TIM3) / (1000000)) - 1));
//attachIntHandle(&TIM_Handle, blink);
Print_TIM3_Regs();
// ------- Input Capture TIM4 Setup -------------------------
// Set Input Capture TIM instance
TimHandle.Instance = TIM4;
// Initialize TIM peripheral (prescale of (64-1) and 64MHz clock gives 1us tick)
TimHandle.Init.Period = 0xFFFF;
TimHandle.Init.Prescaler = (64 - 1);
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if(HAL_TIM_IC_Init(&TimHandle) != HAL_OK)
_Error_Handler("HAL TIM IC Init error", 1);
// Configure the Input Capture of channel 1
sICConfig.ICPolarity = TIM_ICPOLARITY_RISING;
sICConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;
sICConfig.ICPrescaler = TIM_ICPSC_DIV1;
sICConfig.ICFilter = 0;
if(HAL_TIM_IC_ConfigChannel(&TimHandle, &sICConfig, TIM_CHANNEL_1) != HAL_OK)
_Error_Handler("HAL TIM IC Channel Config error", 2);
// Start the Input Capture in interrupt mode
if(HAL_TIM_IC_Start_IT(&TimHandle, TIM_CHANNEL_2) != HAL_OK)
_Error_Handler("HAL TIM_IC_Start_IT error", 3);
Print_TIM4_Regs();
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
void Print_TIM3_Regs() {
Serial.print("TIM3->CR1: "); Serial.println(TIM3->CR1, HEX);
Serial.print("TIM3->CR2: "); Serial.println(TIM3->CR2, HEX);
Serial.print("TIM3->DIER: "); Serial.println(TIM3->DIER, HEX);
Serial.print("TIM3->SR: "); Serial.println(TIM3->SR, HEX);
Serial.print("TIM3->CNT: "); Serial.println(TIM3->CNT, HEX);
Serial.print("TIM3->PSC: "); Serial.println(TIM3->PSC, HEX);
Serial.print("TIM3->ARR: "); Serial.println(TIM3->ARR, HEX);
Serial.println();
}
void Print_TIM4_Regs() {
Serial.print("TIM4->CR1: "); Serial.println(TIM4->CR1, HEX);
Serial.print("TIM4->CR2: "); Serial.println(TIM4->CR2, HEX);
Serial.print("TIM4->DIER: "); Serial.println(TIM4->DIER, HEX);
Serial.print("TIM4->SR: "); Serial.println(TIM4->SR, HEX);
Serial.print("TIM4->CNT: "); Serial.println(TIM4->CNT, HEX);
Serial.print("TIM4->PSC: "); Serial.println(TIM4->PSC, HEX);
Serial.print("TIM4->ARR: "); Serial.println(TIM4->ARR, HEX);
while(1) {}
}
void _Error_Handler(const char * msg, int val) {
Serial.print("Error: ");
Serial.print(msg);
Serial.print(" Err: ");
Serial.println(val);
while(1) {}
}
Рик Кимбалл
Солнце 07 октября 2018 г. 15:22
Может, вы боретесь с функцией SPI. Почему бы вам не захватить на PA0 и не использовать какой -то другой PIN -код для создания ШИН.
Это какой -то код, который использует только необработанные регистры ... Он не будет компилироваться для вас, но даст вам и представил, что минимальная настройка перечислена для PA0 и TIM2_CH1.
Это какой -то код, который использует только необработанные регистры ... Он не будет компилироваться для вас, но даст вам и представил, что минимальная настройка перечислена для PA0 и TIM2_CH1.
/*
fabooh - TIM2CH1 input capture from PA0
*/
serial_default_t<115200, F_CPU, TX_PIN, RX_PIN> Serial;
volatile uint16_t chan1;
PA_0 PA0;
static void input_timer_setup()
{
pinMode(PA0, INPUT_PULLDOWN);
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
NVIC_EnableIRQ(TIM2_IRQn); // Enable TIM2 IRQ
TIM2->CR1 = 0; // disable TIM2, required to configure
TIM2->CR2 = 0;
TIM2->DCR = 0;
TIM2->EGR = 0;
TIM2->SMCR = 0;
TIM2->CCMR1 = // CC1 channel is configured as input, IC1 is mapped on TI1.
TIM_CCMR1_CC1S_0
// digital filter 8 CLK_INT samples required to trigger
| (0b011 << TIM_CCMR1_IC1F_Pos)
;
TIM2->CCMR2 = 0;
TIM2->CCER = TIM_CCER_CC1E; // input capture enable for CCR1 rising
TIM2->PSC = (F_CPU/1000000)-1; // make each TIM2 CNT tick is 1 microsecond
TIM2->ARR = 0xFFFF; // count from 0 - 65535, then wrap
TIM2->DIER = TIM_DIER_CC1IE; // interrupt enable on CCR1 input
TIM2->CR1 = TIM_CR1_CEN; // enable TIM2
}
void setup() {
Serial.begin(115200);
input_timer_setup();
delay(1);
}
volatile unsigned new_capture=0;
void loop() {
delay(100);
if ( new_capture ) {
Serial << millis() << "," << chan1 << endl;
new_capture=0;
}
}
static void handle_tim2ch1_inputcapture(void) {
static uint16_t chan1_start;
// if PA0 is high, grab start time & setup falling capture
// in either case, we have to flip capture bit to time next edge
if ( GPIOA->IDR & 0x1 ) {
chan1_start = TIM2->CCR1;
TIM2->CCER |= TIM_CCER_CC1P; // capture on falling edge
}
else {
new_capture=1;
chan1 = TIM2->CCR1 - chan1_start;
TIM2->CCER &= ~TIM_CCER_CC1P; // capture on rising edge
}
// NOTE: reading CCR1 clears the TIM2->SR CC1IF flag
// that means we don't have to clear it explicitly
}
// override the default TIM2 interrupt handler
// and look and handle TIM2CH1 input capture events
extern "C" void TIM2_IRQHandler()
{
if ( TIM2->SR & TIM_SR_CC1IF ) {
handle_tim2ch1_inputcapture();
}
}
Mgeo
Пн, 8 октября 2018 г. 1:06
Хороший прогресс сегодня вечером. В попытке подтвердить мой подход конфигурации TIM, я использовал STM32Cubemx для настройки проекта на основе Nucleo-F103RB, настройки TIM3 для захвата ввода на канале 1. Я скопировал код конфигурации проекта в свой эскиз для тестирования.
Теперь я могу получить значения регистра TIM3 для обновления. Мне все еще не совсем ясно, что у меня было неправильно, я думаю, что не смог прочитать руководство HAL достаточно близко, и не смог правильно активировать периферийное устройство TIM, поэтому любые попытки изменения в регистрации не смогли обновить аппаратное обеспечение.
Во всяком случае, я могу включить TIM3 в режиме захвата. Я установил точку останова в моем HAL_TIM_IC_CAPTURECALLBACK () в озоне, теперь он выглядит для стрельбы! Далее я подключу логический анализатор и посмотрю, будет ли что -то запустить, как и ожидалось (помните, что PWM на PA0 перемычка к PA6 / TIM3_CH1).
Джордж
Конфигурация проекта STM32Cubemx (щелкните правой кнопкой мыши на изображение и открыть в новой вкладке облегчает просмотр):
Эскиз теста:
Теперь я могу получить значения регистра TIM3 для обновления. Мне все еще не совсем ясно, что у меня было неправильно, я думаю, что не смог прочитать руководство HAL достаточно близко, и не смог правильно активировать периферийное устройство TIM, поэтому любые попытки изменения в регистрации не смогли обновить аппаратное обеспечение.
Во всяком случае, я могу включить TIM3 в режиме захвата. Я установил точку останова в моем HAL_TIM_IC_CAPTURECALLBACK () в озоне, теперь он выглядит для стрельбы! Далее я подключу логический анализатор и посмотрю, будет ли что -то запустить, как и ожидалось (помните, что PWM на PA0 перемычка к PA6 / TIM3_CH1).
Джордж
Конфигурация проекта STM32Cubemx (щелкните правой кнопкой мыши на изображение и открыть в новой вкладке облегчает просмотр):
Эскиз теста:
static TIM_HandleTypeDef htim3;
const int PwmOutputPin = PA0; // PA_0,D46/A0 -- USES TIM2
const int CaptureInputPin = PA6;
const int TestOutputPin = D15;
extern "C" void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
UNUSED(htim);
digitalWrite(TestOutputPin, !digitalRead(TestOutputPin));
}
void setup() {
Serial.begin(115200);
Serial.println("Initializing...");
Serial.println();
// initialize digital pins
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PwmOutputPin, OUTPUT);
pinMode(TestOutputPin, OUTPUT);
// initialize the input capture pin
// ??? --- I'm not sure if this is enough, do I need to configure my input pin as an 'Input Capture' alternate function --- ???
pinMode(CaptureInputPin, INPUT);
// create a 1KHz 25% (256/4 - 1) duty PWM on testPwmOutputPin
// NOTE - uses TIM associated with output pin
analogWrite(PwmOutputPin, (64 - 1));
Print_TIM2_Regs();
// ------- Input Capture TIM3 Setup -------------------------
// TIM3_IRQn interrupt configuration
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_IC_InitTypeDef sConfigIC;
htim3.Instance = TIM3;
htim3.Init.Prescaler = (64 - 1);
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 0xFFFF;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_IC_Init(&htim3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
TIM3->CR1 = TIM_CR1_CEN;
TIM3->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE;
TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E;
Print_TIM3_Regs();
}
void loop() {
Serial.println("loop");
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
void Print_TIM2_Regs() {
Serial.print("TIM2->CR1: "); Serial.println(TIM2->CR1, HEX);
Serial.print("TIM2->CR2: "); Serial.println(TIM2->CR2, HEX);
Serial.print("TIM2->DIER: "); Serial.println(TIM2->DIER, HEX);
Serial.print("TIM2->SR: "); Serial.println(TIM2->SR, HEX);
Serial.print("TIM2->CNT: "); Serial.println(TIM2->CNT, HEX);
Serial.print("TIM2->PSC: "); Serial.println(TIM2->PSC, HEX);
Serial.print("TIM2->ARR: "); Serial.println(TIM2->ARR, HEX);
Serial.println();
}
void Print_TIM3_Regs() {
Serial.print("TIM3->CR1: "); Serial.println(TIM3->CR1, HEX);
Serial.print("TIM3->CR2: "); Serial.println(TIM3->CR2, HEX);
Serial.print("TIM3->DIER: "); Serial.println(TIM3->DIER, HEX);
Serial.print("TIM3->SR: "); Serial.println(TIM3->SR, HEX);
Serial.print("TIM3->CNT: "); Serial.println(TIM3->CNT, HEX);
Serial.print("TIM3->PSC: "); Serial.println(TIM3->PSC, HEX);
Serial.print("TIM3->ARR: "); Serial.println(TIM3->ARR, HEX);
Serial.println();
}
void _Error_Handler(const char * msg, int val) {
Serial.print("Error: ");
Serial.print(msg);
Serial.print(" Err: ");
Serial.println(val);
while(1) {}
}
Mgeo
Пн, 8 октября 2018 г. 9:23
Вы можете увидеть в вышеуказанном коде, что я переключаю цифровой выходной вывод в обработчике прерываний, чтобы менять состояние PIN. Поэтому, если мы подчерким логический анализатор к прикреплению PA6 (вход по потоку импульса PWM к TIM3_CH1) и D15 (цифровой вывод, переключенный обработчиком прерываний), мы должны увидеть, работают ли вещи, как мы ожидаем. Это будет D15 изменение состояния на каждом растущем краю PA6. В прикрепленном захвате вы можете видеть, что это именно то, что мы видим.
Белый трассировка: штифт PA6 = PWM -импульсный поток в качестве ввода в TIM3_CH1
Orange Trace: Pin D15 = цифровой вывод, переключенный обработчиком прерываний
Белый трассировка: штифт PA6 = PWM -импульсный поток в качестве ввода в TIM3_CH1
Orange Trace: Pin D15 = цифровой вывод, переключенный обработчиком прерываний
Mgeo
Пт 12 октября 2018 г. 8:56 утра
Программа, которую я надеюсь, переносить, измеряет ширину импульса на входном штифте, используя один канал TIM, перевернув бит CC1P в регистрации TIMX CCER внутри обработчика прерываний. Я добавил эту логику в тестовую программу и теперь могу успешно измерить ширину импульса, выводя результат в серийный вывод терминала.
#define HAL_WAY 0
static TIM_HandleTypeDef htim3;
const int PwmOutputPin = PA0; // PA_0,D46/A0 -- USES TIM2
const int CaptureInputPin = PA6;
const int TestOutputPin = D15;
volatile int32_t channel_1_start;
volatile int32_t channel_1;
extern "C" void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
UNUSED(htim);
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)) {
// if (0b1 & GPIOA->IDR >> 6) { // If the receiver channel 1 input pulse on A6 is high.
channel_1_start = TIM3->CCR1; // Record the start time of the pulse.
TIM3->CCER |= TIM_CCER_CC1P; // Change the input capture mode to the falling edge of the pulse.
}
else { // If the receiver channel 1 input pulse on A0 is low.
channel_1 = TIM3->CCR1 - channel_1_start; // Calculate the total pulse time.
if (channel_1 < 0)channel_1 += 0xFFFF; // If the timer has rolled over a correction is needed.
TIM3->CCER &= ~TIM_CCER_CC1P; // Change the input capture mode to the rising edge of the pulse.
}
//digitalWrite(TestOutputPin, !digitalRead(TestOutputPin)); // the Arduino way (works)
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8); // the HAL way (also works)
}
void setup() {
Serial.begin(115200);
Serial.println("Initializing...");
Serial.println();
// initialize digital pins
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PwmOutputPin, OUTPUT);
pinMode(TestOutputPin, OUTPUT);
// initialize the input capture pin
// ??? --- I'm not sure if this is enough, do I need to configure my input pin as an 'Input Capture' alternate function --- ???
pinMode(CaptureInputPin, INPUT);
// create a 1KHz 25% (256/4 - 1) duty PWM on testPwmOutputPin
// NOTE - uses TIM associated with output pin
analogWrite(PwmOutputPin, (64 - 1));
Print_TIM2_Regs();
// ------- Input Capture TIM3 Setup -------------------------
// TIM3_IRQn interrupt configuration
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_IC_InitTypeDef sConfigIC;
htim3.Instance = TIM3;
htim3.Init.Prescaler = (64 - 1);
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 0xFFFF;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_IC_Init(&htim3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
//sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
TIM3->CR1 = TIM_CR1_CEN;
TIM3->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE;
//TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E;
TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P;
Print_TIM3_Regs();
}
void loop() {
float ch1_msec = ((float) channel_1 / 1000.0);
Serial.print("channel_1(mSec): "); Serial.println(ch1_msec);
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500);
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500);
}
void Print_TIM2_Regs() {
Serial.print("TIM2->CR1: "); Serial.println(TIM2->CR1, HEX);
Serial.print("TIM2->CR2: "); Serial.println(TIM2->CR2, HEX);
Serial.print("TIM2->DIER: "); Serial.println(TIM2->DIER, HEX);
Serial.print("TIM2->SR: "); Serial.println(TIM2->SR, HEX);
Serial.print("TIM2->CNT: "); Serial.println(TIM2->CNT, HEX);
Serial.print("TIM2->PSC: "); Serial.println(TIM2->PSC, HEX);
Serial.print("TIM2->ARR: "); Serial.println(TIM2->ARR, HEX);
Serial.println();
}
void Print_TIM3_Regs() {
Serial.print("TIM3->CR1: "); Serial.println(TIM3->CR1, HEX);
Serial.print("TIM3->CR2: "); Serial.println(TIM3->CR2, HEX);
Serial.print("TIM3->DIER: "); Serial.println(TIM3->DIER, HEX);
Serial.print("TIM3->SR: "); Serial.println(TIM3->SR, HEX);
Serial.print("TIM3->CNT: "); Serial.println(TIM3->CNT, HEX);
Serial.print("TIM3->PSC: "); Serial.println(TIM3->PSC, HEX);
Serial.print("TIM3->ARR: "); Serial.println(TIM3->ARR, HEX);
Serial.println();
}
void _Error_Handler(const char * msg, int val) {
Serial.print("Error: ");
Serial.print(msg);
Serial.print(" Err: ");
Serial.println(val);
while(1) {}
}
Mgeo
Пт 12 октября 2018 г. 10:28
Далее и, возможно, окончательная задача - перенести этот пример на F3, чтобы проверить переносимость захвата ввода с примером прерывания между семьями. Я хотел перенести математическое интенсивное применение в это ядро HAL, чтобы методично перейти от вариантов F1 к вариантам F3/F4, которые имеют FPU.
Я использую ucleo-f302r8, который у меня есть. Сначала убедитесь, что я могу сгенерировать вывод ШИМ на выводе с аппаратным таймером, как мы сделали на F1. Мне нужно было перенести сериал в Serial2, чтобы работать серийным монитором. Я смотрел на вариант.H для F302R8 против F103RB, но для меня еще не очевидно, почему это так, но он так работает дальше. Я использую PB8 для генерации вывода ШИМ, который выглядит на карту с TIM16_CH1 (TIM16, TIM17 - одноканальные только на 'F302).
Простой тестовый эскиз для F302R8
Я использую ucleo-f302r8, который у меня есть. Сначала убедитесь, что я могу сгенерировать вывод ШИМ на выводе с аппаратным таймером, как мы сделали на F1. Мне нужно было перенести сериал в Serial2, чтобы работать серийным монитором. Я смотрел на вариант.H для F302R8 против F103RB, но для меня еще не очевидно, почему это так, но он так работает дальше. Я использую PB8 для генерации вывода ШИМ, который выглядит на карту с TIM16_CH1 (TIM16, TIM17 - одноканальные только на 'F302).
Простой тестовый эскиз для F302R8
// From PeripheralPins.c
// {PB_8, TIM16, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM16, 1, 0)}, // TIM16_CH1
const int testPwmOutputPin = PB8; // PB_8 = D15
#define MySerial Serial2
void setup() {
MySerial.begin(115200);
MySerial.println("Initializing...");
// initialize digital pins
pinMode(LED_BUILTIN, OUTPUT);
pinMode(testPwmOutputPin, OUTPUT);
analogWrite(testPwmOutputPin, 63);
}
void loop() {
MySerial.println("loop");
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500); // wait for a second
}
Mgeo
Пт 19 октября 2018 г., 7:27 утра
Мой ucleo-f303re прибыл, поэтому я переключил свой пример на F303RE.
Мне потребовалось некоторое время, чтобы прорваться через HAL, DataSheet и REFORMEANT RECOMPLAY, чтобы перенести мой пример с F103RB на F303RE, больше работы, чем я бы надеялся. После хорошего количества чтения и использования инструмента Cubemx для понимания различий и шагов инициализации ключей, у меня наконец-то есть пример, работая на демо-плате Nucleo-F303R. Я узнал, что F1 обрабатывает альтернативное назначение функции PIN -функции иным образом, чем остальная часть семейства STM32, а также F303 работает на уровне 72 МГц вместо 64 МГц и т. Д. Но основная структура примера F1 более или менее не повреждена, сейчас все работает с кодом ниже.
Так что я думаю, что в этот момент я достиг своей цели обучения. У меня, вероятно, есть несколько дублирующих шагов инициализации в моем коде, что ядро также может быть дублированием, и есть некоторая работа, которая может быть выполнена по таймеру ядра.C функции. На этом этапе я объявлю этот [решен] и перейду к портированию моего приложения.
Некоторые полезные ссылки для будущего справки:
STM Core Hardwaretimer в стадии строительства - https: // github.com/stm32duino/arduino_c ... Проблемы/146
HAL VS LL против SPL - https: // блог.Домски.PL/SPL-VS-HAL-WHICH ... ry-part-2/
Джордж
Ардуино-тестовый эскиз для нуклео-F303RE:
Мне потребовалось некоторое время, чтобы прорваться через HAL, DataSheet и REFORMEANT RECOMPLAY, чтобы перенести мой пример с F103RB на F303RE, больше работы, чем я бы надеялся. После хорошего количества чтения и использования инструмента Cubemx для понимания различий и шагов инициализации ключей, у меня наконец-то есть пример, работая на демо-плате Nucleo-F303R. Я узнал, что F1 обрабатывает альтернативное назначение функции PIN -функции иным образом, чем остальная часть семейства STM32, а также F303 работает на уровне 72 МГц вместо 64 МГц и т. Д. Но основная структура примера F1 более или менее не повреждена, сейчас все работает с кодом ниже.
Так что я думаю, что в этот момент я достиг своей цели обучения. У меня, вероятно, есть несколько дублирующих шагов инициализации в моем коде, что ядро также может быть дублированием, и есть некоторая работа, которая может быть выполнена по таймеру ядра.C функции. На этом этапе я объявлю этот [решен] и перейду к портированию моего приложения.
Некоторые полезные ссылки для будущего справки:
STM Core Hardwaretimer в стадии строительства - https: // github.com/stm32duino/arduino_c ... Проблемы/146
HAL VS LL против SPL - https: // блог.Домски.PL/SPL-VS-HAL-WHICH ... ry-part-2/
Джордж
Ардуино-тестовый эскиз для нуклео-F303RE:
#define HAL_WAY 0
// {PB_5, TIM17, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF10_TIM17, 1, 0)}, // TIM17_CH1
static TIM_HandleTypeDef htim17;
// From PeripheralPins.c
const int PwmOutputPin = PB8; // PB_8 = D15, uses TIM16_CH1
const int CaptureInputPin = PB5; // D4, also TIM17_CH1 Alternate Function
const int TestOutputPin = PA7; // D11
volatile int32_t channel_1_start;
volatile int32_t channel_1;
extern "C" void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
UNUSED(htim);
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5)) {
// if (0b1 & GPIOB->IDR >> 5) { // If the receiver channel 1 input pulse on PB5 is high.
channel_1_start = TIM17->CCR1; // Record the start time of the pulse.
TIM17->CCER |= TIM_CCER_CC1P; // Change the input capture mode to the falling edge of the pulse.
}
else { // If the receiver channel 1 input pulse on PB5 is low.
channel_1 = TIM17->CCR1 - channel_1_start; // Calculate the total pulse time.
if (channel_1 < 0)channel_1 += 0xFFFF; // If the timer has rolled over a correction is needed.
TIM17->CCER &= ~TIM_CCER_CC1P; // Change the input capture mode to the rising edge of the pulse.
}
digitalWrite(TestOutputPin, !digitalRead(TestOutputPin)); // the Arduino way (works)
//HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_15); // the HAL way (also works)
}
void setup() {
Serial.begin(115200);
Serial.print("Initializing...");
Serial.println(getTimerClkFreq(TIM1));
Serial.println();
// initialize digital pins
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PwmOutputPin, OUTPUT);
pinMode(TestOutputPin, OUTPUT);
// initialize the input capture pin
// ??? --- I'm not sure if this is enough, do I need to configure my input pin as an 'Input Capture' alternate function --- ???
pinMode(CaptureInputPin, INPUT);
// create a 1KHz 25% (256/4 - 1) duty PWM on testPwmOutputPin
// NOTE - uses TIM associated with output pin
analogWrite(PwmOutputPin, (64 - 1));
Print_TIM16_Regs();
// ------- Input Capture TIM17 Setup -------------------------
RCC_PeriphCLKInitTypeDef PeriphClkInit;
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_TIM17;
PeriphClkInit.Tim17ClockSelection = RCC_TIM17CLK_HCLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
GPIO_InitTypeDef GPIO_InitStruct;
// Peripheral clock enable
__HAL_RCC_TIM17_CLK_ENABLE();
// TIM17 GPIO Configuration
// PB5 --> TIM17_CH1
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF10_TIM17;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// TIM17 interrupt Init
HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM17_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM17_IRQn);
TIM_IC_InitTypeDef sConfigIC;
htim17.Instance = TIM17;
htim17.Init.Prescaler = (72 - 1);
htim17.Init.CounterMode = TIM_COUNTERMODE_UP;
htim17.Init.Period = 0xFFFF;
htim17.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim17.Init.RepetitionCounter = 0;
htim17.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim17) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_IC_Init(&htim17) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim17, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
TIM17->CR1 = TIM_CR1_CEN;
TIM17->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE;
TIM17->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E;
//TIM17->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P;
Print_TIM17_Regs();
}
void loop() {
float ch1_msec = ((float) channel_1 / 1000.0);
Serial.print("channel_1(mSec): "); Serial.println(ch1_msec);
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500);
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500);
}
void Print_TIM17_Regs() {
Serial.print("TIM17->CR1: "); Serial.println(TIM17->CR1, HEX);
Serial.print("TIM17->CR2: "); Serial.println(TIM17->CR2, HEX);
Serial.print("TIM17->DIER: "); Serial.println(TIM17->DIER, HEX);
Serial.print("TIM17->SR: "); Serial.println(TIM17->SR, HEX);
Serial.print("TIM17->CNT: "); Serial.println(TIM17->CNT, HEX);
Serial.print("TIM17->PSC: "); Serial.println(TIM17->PSC, HEX);
Serial.print("TIM17->ARR: "); Serial.println(TIM17->ARR, HEX);
Serial.println();
}
void Print_TIM16_Regs() {
Serial.print("TIM16->CR1: "); Serial.println(TIM16->CR1, HEX);
Serial.print("TIM16->CR2: "); Serial.println(TIM16->CR2, HEX);
Serial.print("TIM16->DIER: "); Serial.println(TIM16->DIER, HEX);
Serial.print("TIM16->SR: "); Serial.println(TIM16->SR, HEX);
Serial.print("TIM16->CNT: "); Serial.println(TIM16->CNT, HEX);
Serial.print("TIM16->PSC: "); Serial.println(TIM16->PSC, HEX);
Serial.print("TIM16->ARR: "); Serial.println(TIM16->ARR, HEX);
Serial.println();
}
void _Error_Handler(const char * msg, int val) {
Serial.print("Error: ");
Serial.print(msg);
Serial.print(" Err: ");
Serial.println(val);
while(1) {}
}
Mgeo
Ср 24 октября 2018 г., 9:27
Я вернулся к нуклео-F103RB и очищаю некоторые из прямых битовых манипуляций, которые я делал, перемещая его на функции HAL в соответствии с HAL Way. Это потребовалось некоторое поиск кода HAL, но в конечном итоге он работал.
Я также преследовал стек вызовов, который, наконец, называет мой обработчик прерываний захвата в моем эскизе. Когда перерывы TIM3 CC HW, мы проходим:
Tim3_irqhandler () (таймер.C: 1075) -->
Hal_tim_irqhandler () (stm32f1xx_hal_tim.C: 2784) -->
Hal_tim_ic_capturecallback () (мой эскиз ino)
Вы можете увидеть стек вызовов на средней правой панели крышки экрана озона ниже (щелкните правой кнопкой мыши изображение на новую вкладку браузера, чтобы увидеть его лучше).
Мне трудно понять, какие комбинации команд HAL делают, что и как проверить, что он делает то, что я ожидаю, не смотря на код HAL, плюс листы данных и справочные руководства. Казалось бы, это победит цель слоя аппаратной абстракции. Я могу исследовать функции LL, поскольку они кажутся более прямыми и проверенными.
Джордж
Я также преследовал стек вызовов, который, наконец, называет мой обработчик прерываний захвата в моем эскизе. Когда перерывы TIM3 CC HW, мы проходим:
Tim3_irqhandler () (таймер.C: 1075) -->
Hal_tim_irqhandler () (stm32f1xx_hal_tim.C: 2784) -->
Hal_tim_ic_capturecallback () (мой эскиз ino)
Вы можете увидеть стек вызовов на средней правой панели крышки экрана озона ниже (щелкните правой кнопкой мыши изображение на новую вкладку браузера, чтобы увидеть его лучше).
Мне трудно понять, какие комбинации команд HAL делают, что и как проверить, что он делает то, что я ожидаю, не смотря на код HAL, плюс листы данных и справочные руководства. Казалось бы, это победит цель слоя аппаратной абстракции. Я могу исследовать функции LL, поскольку они кажутся более прямыми и проверенными.
Джордж
#define HAL_WAY
static TIM_HandleTypeDef htim3;
const int PwmOutputPin = PA0; // PA_0,D46/A0 -- USES TIM2
const int CaptureInputPin = PA6;
const int TestOutputPin = D15;
volatile int32_t channel_1_start;
volatile int32_t channel_1;
extern "C" void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
UNUSED(htim);
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)) {
// if (0b1 & GPIOA->IDR >> 6) { // If the receiver channel 1 input pulse on A6 is high.
channel_1_start = TIM3->CCR1; // Record the start time of the pulse.
TIM3->CCER |= TIM_CCER_CC1P; // Change the input capture mode to the falling edge of the pulse.
}
else { // If the receiver channel 1 input pulse on A0 is low.
channel_1 = TIM3->CCR1 - channel_1_start; // Calculate the total pulse time.
if (channel_1 < 0)channel_1 += 0xFFFF; // If the timer has rolled over a correction is needed.
TIM3->CCER &= ~TIM_CCER_CC1P; // Change the input capture mode to the rising edge of the pulse.
}
#ifdef HAL_WAY
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8); // the HAL way (also works)
#else
digitalWrite(TestOutputPin, !digitalRead(TestOutputPin)); // the Arduino way (works)
#endif
}
void setup() {
Serial.begin(115200);
Serial.print("Initializing...");
Serial.println(getTimerClkFreq(TIM1));
Serial.println();
// initialize digital pins
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PwmOutputPin, OUTPUT);
pinMode(TestOutputPin, OUTPUT);
// initialize the input capture pin
// ??? --- I'm not sure if this is enough, do I need to configure my input pin as an 'Input Capture' alternate function --- ???
pinMode(CaptureInputPin, INPUT);
// create a 1KHz 25% (256/4 - 1) duty PWM on testPwmOutputPin
// NOTE - uses TIM associated with output pin
analogWrite(PwmOutputPin, (64 - 1));
Print_TIM2_Regs();
// ------- Input Capture TIM3 Setup -------------------------
GPIO_InitTypeDef GPIO_InitStruct;
/*
// TIM3 GPIO Configuration
// PB4 -> TIM3_CH1
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
__HAL_AFIO_REMAP_TIM3_PARTIAL();
*/
// TIM3 interrupt Init
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_IC_InitTypeDef sConfigIC;
htim3.Instance = TIM3;
htim3.Init.Prescaler = (64 - 1);
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 0xFFFF;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_IC_Init(&htim3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
#ifdef HAL_WAY
__HAL_TIM_ENABLE_IT(&htim3, TIM_IT_CC1 | TIM_IT_CC2);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start (&htim3, TIM_CHANNEL_1);
#else
TIM3->CR1 = TIM_CR1_CEN;
TIM3->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE;
//TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E;
TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P;
#endif
Print_TIM3_Regs();
}
void loop() {
float ch1_msec = ((float) channel_1 / 1000.0);
Serial.print("channel_1(mSec): "); Serial.println(ch1_msec);
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500);
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500);
}
void Print_TIM2_Regs() {
Serial.print("TIM2->CR1: "); Serial.println(TIM2->CR1, HEX);
Serial.print("TIM2->CR2: "); Serial.println(TIM2->CR2, HEX);
Serial.print("TIM2->DIER: "); Serial.println(TIM2->DIER, HEX);
Serial.print("TIM2->CCER: "); Serial.println(TIM2->CCER, HEX);
Serial.print("TIM2->SR: "); Serial.println(TIM2->SR, HEX);
Serial.print("TIM2->CNT: "); Serial.println(TIM2->CNT, HEX);
Serial.print("TIM2->PSC: "); Serial.println(TIM2->PSC, HEX);
Serial.print("TIM2->ARR: "); Serial.println(TIM2->ARR, HEX);
Serial.println();
}
void Print_TIM3_Regs() {
Serial.print("TIM3->CR1: "); Serial.println(TIM3->CR1, HEX);
Serial.print("TIM3->CR2: "); Serial.println(TIM3->CR2, HEX);
Serial.print("TIM3->DIER: "); Serial.println(TIM3->DIER, HEX);
Serial.print("TIM3->CCER: "); Serial.println(TIM3->CCER, HEX);
Serial.print("TIM3->SR: "); Serial.println(TIM3->SR, HEX);
Serial.print("TIM3->CNT: "); Serial.println(TIM3->CNT, HEX);
Serial.print("TIM3->PSC: "); Serial.println(TIM3->PSC, HEX);
Serial.print("TIM3->ARR: "); Serial.println(TIM3->ARR, HEX);
Serial.println();
}
void _Error_Handler(const char * msg, int val) {
Serial.print("Error: ");
Serial.print(msg);
Serial.print(" Err: ");
Serial.println(val);
while(1) {}
}
Mgeo
Сб 27 октября 2018 12:03
Успешное переоборудование TIM3 -канала 1 ввода из PA6 по умолчанию в альтернативный PB4 с использованием __HAL_AFIO_REMAP_TIM3_Partial ():
#define HAL_WAY
static TIM_HandleTypeDef htim3;
const int PwmOutputPin = PA0; // PA_0,D46/A0 -- USES TIM2
const int CaptureInputPin = PB4;
const int TestOutputPin = D15;
volatile int32_t channel_1_start;
volatile int32_t channel_1;
extern "C" void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
UNUSED(htim);
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)) {
// if (0b1 & GPIOA->IDR >> 6) { // If the receiver channel 1 input pulse on A6 is high.
channel_1_start = TIM3->CCR1; // Record the start time of the pulse.
TIM3->CCER |= TIM_CCER_CC1P; // Change the input capture mode to the falling edge of the pulse.
}
else { // If the receiver channel 1 input pulse on A0 is low.
channel_1 = TIM3->CCR1 - channel_1_start; // Calculate the total pulse time.
if (channel_1 < 0)channel_1 += 0xFFFF; // If the timer has rolled over a correction is needed.
TIM3->CCER &= ~TIM_CCER_CC1P; // Change the input capture mode to the rising edge of the pulse.
}
#ifdef HAL_WAY
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8); // the HAL way (also works)
#else
digitalWrite(TestOutputPin, !digitalRead(TestOutputPin)); // the Arduino way (works)
#endif
}
void setup() {
Serial.begin(115200);
Serial.print("Initializing...");
Serial.println(getTimerClkFreq(TIM1));
Serial.println();
// initialize digital pins
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PwmOutputPin, OUTPUT);
pinMode(TestOutputPin, OUTPUT);
// initialize the input capture pin
// ??? --- I'm not sure if this is enough, do I need to configure my input pin as an 'Input Capture' alternate function --- ???
pinMode(CaptureInputPin, INPUT);
// create a 1KHz 25% (256/4 - 1) duty PWM on testPwmOutputPin
// NOTE - uses TIM associated with output pin
analogWrite(PwmOutputPin, (64 - 1));
Print_TIM2_Regs();
// ------- Input Capture TIM3 Setup -------------------------
GPIO_InitTypeDef GPIO_InitStruct;
/*
// TIM3 GPIO Configuration
// PB4 -> TIM3_CH1
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
*/
__HAL_AFIO_REMAP_TIM3_PARTIAL();
// TIM3 interrupt Init
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_IC_InitTypeDef sConfigIC;
htim3.Instance = TIM3;
htim3.Init.Prescaler = (64 - 1);
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 0xFFFF;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_IC_Init(&htim3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
#ifdef HAL_WAY
__HAL_TIM_ENABLE_IT(&htim3, TIM_IT_CC1 | TIM_IT_CC2);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start (&htim3, TIM_CHANNEL_1);
#else
TIM3->CR1 = TIM_CR1_CEN;
TIM3->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE;
//TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E;
TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P;
#endif
Print_TIM3_Regs();
}
void loop() {
float ch1_msec = ((float) channel_1 / 1000.0);
Serial.print("channel_1(mSec): "); Serial.println(ch1_msec);
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500);
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500);
}
void Print_TIM2_Regs() {
Serial.print("TIM2->CR1: "); Serial.println(TIM2->CR1, HEX);
Serial.print("TIM2->CR2: "); Serial.println(TIM2->CR2, HEX);
Serial.print("TIM2->DIER: "); Serial.println(TIM2->DIER, HEX);
Serial.print("TIM2->CCER: "); Serial.println(TIM2->CCER, HEX);
Serial.print("TIM2->SR: "); Serial.println(TIM2->SR, HEX);
Serial.print("TIM2->CNT: "); Serial.println(TIM2->CNT, HEX);
Serial.print("TIM2->PSC: "); Serial.println(TIM2->PSC, HEX);
Serial.print("TIM2->ARR: "); Serial.println(TIM2->ARR, HEX);
Serial.println();
}
void Print_TIM3_Regs() {
Serial.print("TIM3->CR1: "); Serial.println(TIM3->CR1, HEX);
Serial.print("TIM3->CR2: "); Serial.println(TIM3->CR2, HEX);
Serial.print("TIM3->DIER: "); Serial.println(TIM3->DIER, HEX);
Serial.print("TIM3->CCER: "); Serial.println(TIM3->CCER, HEX);
Serial.print("TIM3->SR: "); Serial.println(TIM3->SR, HEX);
Serial.print("TIM3->CNT: "); Serial.println(TIM3->CNT, HEX);
Serial.print("TIM3->PSC: "); Serial.println(TIM3->PSC, HEX);
Serial.print("TIM3->ARR: "); Serial.println(TIM3->ARR, HEX);
Serial.println();
}
void _Error_Handler(const char * msg, int val) {
Serial.print("Error: ");
Serial.print(msg);
Serial.print(" Err: ");
Serial.println(val);
while(1) {}
}
Mgeo
Сб 27 октября 2018 г. 20:39
Следующий в моем списке приведен пример четырех входного канала на одном TIM на F103RB.
Я выкопал старый Homebrew Avr Attiny84 RC-симулятор Pulse Pulse, устройство AVR запрограммировано на генерацию 6 отдельных последовательных импульсов 1-2 мс. Подобно каналу 1-6 сервоприводов в ниже. Я подключил 6 каналов симулятора до моей платы Nucleo-F103RB на канале TIM3 1-4 и TIM4 канала 1-2.
Изучение hal_tim_irqhandler Я вижу, что обработчик использует __hal_tim_get_it_source (), чтобы определить источник прерывания TIM. В рутине Хтим->Канал используется для сохранения активного канала TIM перед вызовом HAL_TIM_IC_CAPTURECALLBACK (), поэтому я могу использовать его в расчетах по ширине импульса канала.
Я выкопал старый Homebrew Avr Attiny84 RC-симулятор Pulse Pulse, устройство AVR запрограммировано на генерацию 6 отдельных последовательных импульсов 1-2 мс. Подобно каналу 1-6 сервоприводов в ниже. Я подключил 6 каналов симулятора до моей платы Nucleo-F103RB на канале TIM3 1-4 и TIM4 канала 1-2.
Изучение hal_tim_irqhandler Я вижу, что обработчик использует __hal_tim_get_it_source (), чтобы определить источник прерывания TIM. В рутине Хтим->Канал используется для сохранения активного канала TIM перед вызовом HAL_TIM_IC_CAPTURECALLBACK (), поэтому я могу использовать его в расчетах по ширине импульса канала.
//#define HAL_WAY
/*
I.) ATMEL ATTINY84/ARDUINO ppm generator test rig pinout-------------------*
+--\/--+
VCC 1 | | 14 GND
CH1 (D0) PB0 2 | | 13 AREF (D10)
CH2 (D1) PB1 3 | | 12 PA1 (D9) SoftSerial Tx
PB3 4 | | 11 PA2 (D8) SoftSerial Rx
CH3 (D2) PB2 5 | | 10 PA3 (D7)
CH4 (D3) PA7 6 | | 9 PA4 (D6) CH6
(*PPMout)--> ppm (D4) PA6 7 | | 8 PA5 (D5) CH5
+------+
II.) STM32 Nucleo-F103RB default peripheral pins---------------------------*
PA0 = WKUP / USART2_CTS / ADC12_IN0 / TIM2_CH1_ETR
PA1 = USART2_RTS / ADC12_IN1 / TIM2_CH2
PA2 = USART2_TX(9) / ADC12_IN2 / TIM2_CH3
PA3 = USART2_RX / ADC12_IN3 / TIM2_CH4
PA6 = SPI1_MISO / ADC12_IN6 / TIM3_CH1
PA7 = SPI1_MOSI / ADC12_IN7 / TIM3_CH2
PB0 = ADC12_IN8 / TIM3_CH3
PB1 = ADC12_IN9 / TIM3_CH4
PB6 = I2C1_SCL / TIM4_CH1
PB7 = I2C1_SDA / TIM4_CH2
PB8 = TIM4_CH3
PB9 = TIM4_CH4
---------------------------------------------------------------------------*/
static TIM_HandleTypeDef htim3;
static TIM_HandleTypeDef htim4;
const int PwmOutputPin = PA0; // PA_0,D46/A0 -- USES TIM2
const int CaptureInputPin1 = PA6;
const int CaptureInputPin2 = PA7;
const int CaptureInputPin3 = PB0;
const int CaptureInputPin4 = PB1;
const int CaptureInputPin5 = PB6;
const int CaptureInputPin6 = PB7;
const int TestOutputPin = D15;
volatile int32_t channel_1_start, channel_1;
volatile int32_t channel_2_start, channel_2;
volatile int32_t channel_3_start, channel_3;
volatile int32_t channel_4_start, channel_4;
volatile int32_t channel_5_start, channel_5;
volatile int32_t channel_6_start, channel_6;
extern "C" void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
long address;
address = (long) htim->Instance;
switch (address)
{
case TIM3_BASE :
digitalWrite(TestOutputPin, !digitalRead(TestOutputPin)); // the Arduino way (works)
break;
case TIM4_BASE :
digitalWrite(TestOutputPin, !digitalRead(TestOutputPin)); // the Arduino way (works)
break;
default :
break;
}
if (htim->Instance == TIM3) {
switch(htim->Channel)
{
case HAL_TIM_ACTIVE_CHANNEL_1 :
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)) { // if the receiver channel 1 input pulse on A6 is high
channel_1_start = TIM3->CCR1; // record the start time of the pulse
TIM3->CCER |= TIM_CCER_CC1P; // change the input capture mode to the falling edge of the pulse
} else { // if the receiver channel 1 input pulse on A6 is low
channel_1 = TIM3->CCR1 - channel_1_start; // calculate the total pulse time
if (channel_1 < 0)channel_1 += 0xFFFF; // if the timer has rolled over a correction is needed
TIM3->CCER &= ~TIM_CCER_CC1P; // change the input capture mode to the rising edge of the pulse
}
break;
case HAL_TIM_ACTIVE_CHANNEL_2 :
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7)) { // if the receiver channel 2 input pulse on A7 is high
channel_2_start = TIM3->CCR2; // record the start time of the pulse
TIM3->CCER |= TIM_CCER_CC2P; // change the input capture mode to the falling edge of the pulse
} else { // if the receiver channel 2 input pulse on A7 is low
channel_2 = TIM3->CCR2 - channel_2_start; // calculate the total pulse time
if (channel_2 < 0)channel_2 += 0xFFFF; // if the timer has rolled over a correction is needed
TIM3->CCER &= ~TIM_CCER_CC2P; // change the input capture mode to the rising edge of the pulse
}
break;
case HAL_TIM_ACTIVE_CHANNEL_3 :
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0)) { // if the receiver channel 3 input pulse on B0 is high
channel_3_start = TIM3->CCR3; // record the start time of the pulse
TIM3->CCER |= TIM_CCER_CC3P; // change the input capture mode to the falling edge of the pulse
} else { // if the receiver channel 3 input pulse on B0 is low
channel_3 = TIM3->CCR3 - channel_3_start; // calculate the total pulse time
if (channel_3 < 0)channel_3 += 0xFFFF; // if the timer has rolled over a correction is needed
TIM3->CCER &= ~TIM_CCER_CC3P; // change the input capture mode to the rising edge of the pulse
}
break;
case HAL_TIM_ACTIVE_CHANNEL_4 :
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1)) { // if the receiver channel 4 input pulse on B1 is high
channel_4_start = TIM3->CCR4; // record the start time of the pulse
TIM3->CCER |= TIM_CCER_CC4P; // change the input capture mode to the falling edge of the pulse
} else { // if the receiver channel 4 input pulse on B4 is low
channel_4 = TIM3->CCR4 - channel_4_start; // calculate the total pulse time
if (channel_4 < 0)channel_4 += 0xFFFF; // if the timer has rolled over a correction is needed
TIM3->CCER &= ~TIM_CCER_CC4P; // change the input capture mode to the rising edge of the pulse
}
break;
default :
break;
}
} else if (htim->Instance == TIM4) {
switch(htim->Channel)
{
case HAL_TIM_ACTIVE_CHANNEL_1 :
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6)) { // if the receiver channel 5 input pulse on B6 is high
channel_5_start = TIM4->CCR1; // record the start time of the pulse
TIM4->CCER |= TIM_CCER_CC1P; // change the input capture mode to the falling edge of the pulse
} else { // if the receiver channel 5 input pulse on B6 is low
channel_5 = TIM4->CCR1 - channel_5_start; // calculate the total pulse time
if (channel_5 < 0)channel_5 += 0xFFFF; // if the timer has rolled over a correction is needed
TIM4->CCER &= ~TIM_CCER_CC1P; // change the input capture mode to the rising edge of the pulse
}
break;
case HAL_TIM_ACTIVE_CHANNEL_2 :
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7)) { // if the receiver channel 6 input pulse on B7 is high
channel_6_start = TIM4->CCR2; // record the start time of the pulse
TIM4->CCER |= TIM_CCER_CC2P; // change the input capture mode to the falling edge of the pulse
} else { // if the receiver channel 6 input pulse on B7 is low
channel_6 = TIM4->CCR2 - channel_6_start; // calculate the total pulse time
if (channel_6 < 0)channel_6 += 0xFFFF; // if the timer has rolled over a correction is needed
TIM4->CCER &= ~TIM_CCER_CC2P; // change the input capture mode to the rising edge of the pulse
}
break;
default :
break;
}
}
#ifdef HAL_WAY
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8); // the HAL way (also works)
#else
digitalWrite(TestOutputPin, !digitalRead(TestOutputPin)); // the Arduino way (works)
#endif
}
void setup() {
Serial.begin(115200);
Serial.print("Initializing...");
Serial.println(getTimerClkFreq(TIM1));
Serial.println();
// initialize digital pins
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PwmOutputPin, OUTPUT);
pinMode(TestOutputPin, OUTPUT);
// initialize the input capture pins
pinMode(CaptureInputPin1, INPUT);
pinMode(CaptureInputPin2, INPUT);
pinMode(CaptureInputPin3, INPUT);
pinMode(CaptureInputPin4, INPUT);
pinMode(CaptureInputPin5, INPUT);
pinMode(CaptureInputPin6, INPUT);
// create a 1KHz 25% (256/4 - 1) duty PWM on testPwmOutputPin
// NOTE - uses TIM associated with output pin
analogWrite(PwmOutputPin, (64 - 1));
Print_TIM2_Regs();
// ------- Input Capture TIM3 Setup -------------------------
GPIO_InitTypeDef GPIO_InitStruct;
// TIM3 interrupt Init
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_IC_InitTypeDef sConfigIC;
htim3.Instance = TIM3;
htim3.Init.Prescaler = (64 - 1);
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 0xFFFF;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_IC_Init(&htim3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_4) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
#ifdef HAL_WAY
__HAL_TIM_ENABLE_IT(&htim3, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start (&htim3, TIM_CHANNEL_1);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start (&htim3, TIM_CHANNEL_2);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start (&htim3, TIM_CHANNEL_3);
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_4, TIM_INPUTCHANNELPOLARITY_FALLING);
HAL_TIM_IC_Start (&htim3, TIM_CHANNEL_4);
#else
TIM3->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE;
TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC2E | TIM_CCER_CC2P | TIM_CCER_CC3E | TIM_CCER_CC3P | TIM_CCER_CC4E | TIM_CCER_CC4P;
TIM3->CR1 = TIM_CR1_CEN;
#endif
Print_TIM3_Regs();
// ------- Input Capture TIM3 Setup -------------------------
// TIM3 interrupt Init
HAL_NVIC_SetPriority(TIM4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
htim4.Instance = TIM4;
htim4.Init.Prescaler = (64 - 1);
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 0xFFFF;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_IC_Init(&htim4) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
TIM4->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE;
TIM4->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC2E | TIM_CCER_CC2P;
TIM4->CR1 = TIM_CR1_CEN;
Print_TIM4_Regs();
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500);
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500);
float ch1_msec = ((float) channel_1 / 1000.0);
float ch2_msec = ((float) channel_2 / 1000.0);
float ch3_msec = ((float) channel_3 / 1000.0);
float ch4_msec = ((float) channel_4 / 1000.0);
float ch5_msec = ((float) channel_5 / 1000.0);
float ch6_msec = ((float) channel_6 / 1000.0);
Serial.print("channel_1(mSec): "); Serial.print(ch1_msec);
Serial.print(" | channel_2(mSec): "); Serial.print(ch2_msec);
Serial.print(" | channel_3(mSec): "); Serial.print(ch3_msec);
Serial.print(" | channel_4(mSec): "); Serial.print(ch4_msec);
Serial.print(" | channel_5(mSec): "); Serial.print(ch5_msec);
Serial.print(" | channel_6(mSec): "); Serial.println(ch6_msec);
}
void Print_TIM2_Regs() {
Serial.print("TIM2->CR1: "); Serial.println(TIM2->CR1, HEX);
Serial.print("TIM2->CR2: "); Serial.println(TIM2->CR2, HEX);
Serial.print("TIM2->DIER: "); Serial.println(TIM2->DIER, HEX);
Serial.print("TIM2->CCER: "); Serial.println(TIM2->CCER, HEX);
Serial.print("TIM2->SR: "); Serial.println(TIM2->SR, HEX);
Serial.print("TIM2->CNT: "); Serial.println(TIM2->CNT, HEX);
Serial.print("TIM2->PSC: "); Serial.println(TIM2->PSC, HEX);
Serial.print("TIM2->ARR: "); Serial.println(TIM2->ARR, HEX);
Serial.println();
}
void Print_TIM3_Regs() {
Serial.print("TIM3->CR1: "); Serial.println(TIM3->CR1, HEX);
Serial.print("TIM3->CR2: "); Serial.println(TIM3->CR2, HEX);
Serial.print("TIM3->DIER: "); Serial.println(TIM3->DIER, HEX);
Serial.print("TIM3->CCER: "); Serial.println(TIM3->CCER, HEX);
Serial.print("TIM3->SR: "); Serial.println(TIM3->SR, HEX);
Serial.print("TIM3->CNT: "); Serial.println(TIM3->CNT, HEX);
Serial.print("TIM3->PSC: "); Serial.println(TIM3->PSC, HEX);
Serial.print("TIM3->ARR: "); Serial.println(TIM3->ARR, HEX);
Serial.println();
}
void Print_TIM4_Regs() {
Serial.print("TIM4->CR1: "); Serial.println(TIM4->CR1, HEX);
Serial.print("TIM4->CR2: "); Serial.println(TIM4->CR2, HEX);
Serial.print("TIM4->DIER: "); Serial.println(TIM4->DIER, HEX);
Serial.print("TIM4->CCER: "); Serial.println(TIM4->CCER, HEX);
Serial.print("TIM4->SR: "); Serial.println(TIM4->SR, HEX);
Serial.print("TIM4->CNT: "); Serial.println(TIM4->CNT, HEX);
Serial.print("TIM4->PSC: "); Serial.println(TIM4->PSC, HEX);
Serial.print("TIM4->ARR: "); Serial.println(TIM4->ARR, HEX);
Serial.println();
}
void _Error_Handler(const char * msg, int val) {
Serial.print("Error: ");
Serial.print(msg);
Serial.print(" Err: ");
Serial.println(val);
while(1) {}
}