board707 / w80x_arduino

w806 package for Arduino IDE
GNU Lesser General Public License v2.1
68 stars 12 forks source link

Timer interrupt #12

Closed board707 closed 1 year ago

board707 commented 1 year ago

Попытался помигать диодом через таймер. Взял пример работы с таймером из SDK и ример HAL_LED Сконфигурировал таймер с периодом в 1 сек и в обработчик прерывания по переполнению положил код мигания светодиодами из HAL_LED. Код компилируется без ошибок, но не мигает. Вот код. Посмотрите, может что посоветуете.

#include <stdio.h>
#include <Arduino.h>

void Error_Handler_tim(void);
static void TIM1_Init(void);

TIM_HandleTypeDef htim1;
static volatile uint8_t key_flag = 0;

static void GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIO_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_24 | GPIO_PIN_25 | GPIO_PIN_26;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}
static void TIM1_Init(void)
{
    htim1.Instance = TIM1;
    htim1.Init.Unit = TIM_UNIT_MS;
    htim1.Init.Period = 1000;
    htim1.Init.AutoReload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
    {
        printf("TIM init error\r\n");
        Error_Handler_tim();
    }

     if (HAL_TIM_Base_Start_IT(&htim1) != HAL_OK)
    {
        printf("TIM start_it error\r\n");
        Error_Handler_tim();
    }
   HAL_NVIC_SetPriority(TIM_IRQn, 0);
   HAL_NVIC_EnableIRQ(TIM_IRQn);
}

void setup() {

    printf("Led Demo\r\n");

    HAL_Init();
    GPIO_Init();
    TIM1_Init();

}
void blink() {
  key_flag++;
    //printf("fire\r\n");
    if (key_flag % 3 == 0)
    {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_24, (GPIO_PinState)0);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_25, (GPIO_PinState)1);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_26, (GPIO_PinState)1);
    }
    else if (key_flag % 3 == 1)
    {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_24, (GPIO_PinState)1);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_25, (GPIO_PinState)0);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_26, (GPIO_PinState)1);
    }
    else
    {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_24, (GPIO_PinState)1);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_25, (GPIO_PinState)1);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_26, (GPIO_PinState)0);
    }
}
void loop() {

    HAL_Delay(500);
}

void Error_Handler_tim(void)
{
    while (1);
}

void HAL_TIM_Callback(TIM_HandleTypeDef *htim)
{

    if (htim->Instance == TIM1)
    {
        blink();
    }

}

__attribute__((isr)) void TIM0_5_IRQHandler(void)
{

    HAL_TIM_IRQHandler(&htim1);
 }
AnatolSher commented 1 year ago

Привет! В процедуру инициализации таймера нужно добавить строку HAL_RCC_TIM_CLK_ENABLE(); Функцию attribute__((isr)) void TIM0_5_IRQHandler(void) {

HAL_TIM_IRQHandler(&htim1);

} Перенести в wm_it.c, и туда же добавить объявление extern TIM_HandleTypeDef htim1; Все работает

PS. Но так прерывания не обрабатываются. :) Принято в обработчике прерывания делать минимальные движения с кодом. Например там можно инкрементировать key_flag. А код из blink() имплементировать в loop() без HAL_Delay(500)

В стиле Ардуино это будет так `#include

include

define LED0 PB0

define LED1 PB1

define LED2 PB2

void Error_Handler_tim(void); static void TIM1_Init(void);

TIM_HandleTypeDef htim1; static volatile uint8_t key_flag = 0;

void setup() {

printf("Led Demo\r\n");
pinMode(LED0,OUTPUT);
pinMode(LED1,OUTPUT);
pinMode(LED2,OUTPUT);
TIM1_Init();

}

void loop() {

if (key_flag % 3 == 0)
{
    digitalWrite(LED0,LOW);
    digitalWrite(LED1,HIGH);
    digitalWrite(LED2,HIGH);
}
else if (key_flag % 3 == 1)
{
    digitalWrite(LED0,HIGH);
    digitalWrite(LED1,LOW);
    digitalWrite(LED2,HIGH);
}
else
{
    digitalWrite(LED0,HIGH);
    digitalWrite(LED1,HIGH);
    digitalWrite(LED2,LOW);
}

}

static void TIM1_Init(void) { __HAL_RCC_TIM_CLK_ENABLE(); htim1.Instance = TIM1; htim1.Init.Unit = TIM_UNIT_MS; htim1.Init.Period = 1000; htim1.Init.AutoReload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&htim1) != HAL_OK) { printf("TIM init error\r\n"); Error_Handler_tim(); }

 if (HAL_TIM_Base_Start_IT(&htim1) != HAL_OK)
{
    printf("TIM start_it error\r\n");
    Error_Handler_tim();
}

HAL_NVIC_SetPriority(TIM_IRQn, 0); HAL_NVIC_EnableIRQ(TIM_IRQn); }

void Error_Handler_tim(void) { while (1); }

void HAL_TIM_Callback(TIM_HandleTypeDef *htim) {

if (htim->Instance == TIM1)
{
    key_flag++;
}

} ` Для AIR103 лампочки надо перестроить Проверял в новой сборке для HAL 0.6.0

board707 commented 1 year ago

Да, спасибо, работает. То что нужен запуск тактирования - это понятно. А вот почему нужно TIM0_5_IRQHandler(void) обязательно в wm_it.c перенести - не вполне понимаю.

так прерывания не обрабатываются. :) Принято в обработчике прерывания делать минимальные движения

это я в курсе :) но в данном случае, считаю, обработчик получился совсем небольшим, всего-то мы пишем три бита в регистр порта.

Кстати, в примере hal_led у вас есть небольшая ошибка. В качестве задержки стоит функция HAL_DELAY(500); Но это же в микросекундах, как я понял. Реально если запустить пример так как он написан - светодиоды горят все три вполнакала. Я заменил HAL_DELAY(500); на delay(500) и лампочки стали мигать как положено.

AnatolSher commented 1 year ago

Да... там я проморгал. Пример был подготовлен раньше чем мы правки в Core сделали. HAL_Delay() - это микросекунды На счет wm_it.c сам тоже озадачился... С другой стороны в STM32 HAL тоже такой подход, Видимо китайцы один к одному слизали :)

board707 commented 1 year ago

Думаю, что по итогам этой ветки TIM0_5_IRQHandler(void) надо добавить в wm_it.c по дефолту. А __HAL_RCC_TIM_CLK_ENABLE() куда-нибудь в HAL_INIT() или Arduino.c. А вот инициализацию самого таймера пусть пользователи делают сами, я попробую для этого библиотеку написать, типа как HardwareTimer() для СТМ

AnatolSher commented 1 year ago

Так можно... Но есть одно НО! Нужно понять сколько пользовательских таймеров и под какими номерами можно выделить ардуинщику. Бикоз, в будущем, будет стоять задача интегрировать RTOS. Я пока не знаю какие номера таймеров она может занять.

board707 commented 1 year ago

Думаю что нужно предусмотреть работу как в РТОС, так и без нее. Затачивать чип только под РТОС, как это сделано в ЕСП32 - мне бы очень не хотелось. А это значит, что при работе на "голом чипе" нужно отдать пользователю все имеющиеся таймеры, а под РТОС - ввести ограничения. То есть я за то, чтобы пока никаких таймеров под РТОС не резервировать.

board707 commented 1 year ago

Извиняюсь, а в Дискуссиях Вы мои сообщения видите? А то что-то совсем ничего не пишете :)

AnatolSher commented 1 year ago

Тогда в Arduino.h нужно определить все доступные таймеры, а в wm_it.c добавить хендлеры для них.

board707 commented 1 year ago

в wm_it.c добавить хендлеры для них.

Таймеры создать надо, а вот хендлеров больше не нужно, если я не ошибаюсь. Прерывание то у нас одно единственное на все 6 таймеров. И хендлер один, он уже в wm_tim.c определен. Пользователю нужно будет сконфигурировать и запустить таймер и зарегистрировать кэлбек для него.

AnatolSher commented 1 year ago

Не одно image

AnatolSher commented 1 year ago

Кстати, можно функции millis(),micros(),delay(),delayMicroseconds() сделать на TIM0 и вернуть тики процессора к миллисекундам. Будет как в настоящем Ардуино... Хотя особого смысла я в этом не вижу :)

board707 commented 1 year ago

хм, вы меня озадачили.... а сейчас они в чем? Вроде пользовался уже delay() - похоже на миллисекунды :)

AnatolSher commented 1 year ago

Сейчас все работает так как задекларировано. В мс и мкс. За счет того что системные тики перестроены на микросекундные интервалы(были миллисекунды). image

Это не существенная нагрузка на ядро. При тактовой в 240Мгц это всего лишь 1/240 производительности. Но можно все вернуть в зад и сделать на таймере