Easyelectronics.ru

Электроника для всех
Текущее время: 19 окт 2019, 00:01

Часовой пояс: UTC + 5 часов



JLCPCB – Прототипы печатных плат за $2/10pcs (Любой цвет!)
Крупнейший производитель печатных плат и прототипов. Более 600000 клиентов и свыше 10000 заказов в день!
Получите скидку на почтовую отправку при первом заказе в JLCPCB!

Начать новую тему Ответить на тему  [ Сообщений: 5 ] 
Автор Сообщение
 Заголовок сообщения: Адаптация библиотеки под STM32
СообщениеДобавлено: 03 июл 2019, 09:30 
Здравствуйте!

Зарегистрирован: 02 июл 2019, 17:33
Сообщения: 1
Нужно адаптировать библиотеку от ATMega под мк STM32. Студент, прохожу практику с мк знакомлюсь впервые, много чего не знаю. Нужно исправить функции SoftTimerRefInit и mTimerHandler под STM32. Прошу поделиться знаниями (литературой)
Код:
#ifndef __SOFTTIMER_C
#define __SOFTTIMER_C

#include <stm320f0xхx.h>
#include "Macros.h"
#include "SoftTimer.h"

// DEBUG:
#include "Port.h"

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

// Версия 08.05.2019
// Для таймеров, создаваемых внутри функции таймера введён флаг блокировки
// объявленного таймера, запрещающий его запуск в текущем тике.
// Решена проблема интервала запуска синхронизированных таймеров.

// Версия 27.12.2017
// Добавлен указатель на данные для задачи таймера, исправлены имена,
// добавлена защита от неподдерживаемых входных типов и сокрытие данных

//XXXXXXXXXXXXXXXXXXXXXXXXXXX Определения XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

#define mTimersMAX 15 // Максимальное число таймеров

#define mTimerNumber 4 // Номер модуля системного таймера

#define mTimerIRQ_Priority  mIntLevLow // Приоритет прерываний для системного таймера

#define mTimerDiv 16 // Делитель тактовой частоты системного таймера

#define mTimerTick (uint16_t)((mSoftTimerLengthMS * 1e-3 * mBaseClock_Hz) / mTimerDiv) // Период системного таймера в тиках

//------------------------------------------------------------------------------
// _Glue - склеивает параметр с константным выражением
// _GlueWrap - разворачивает в макрос _Glue переданный в _GlueWrap параметр

//#define mTimerInst_Glue(...)            TC ## __VA_ARGS__
//#define mTimerInst_GlueWrap(vTmrNum)    mTimerInst_Glue(vTmrNum)
//#define mTimerInst                      mTimerInst_GlueWrap(mTimerNumber) // TCx

//#define mTimerPM_Pos_Glue(...)          PM_APBCMASK_TC ## __VA_ARGS__ ## _Pos
//#define mTimerPM_Pos_GlueWrap(vTmrNum)  mTimerPM_Pos_Glue(vTmrNum)
//#define mTimerPM_Pos                    mTimerPM_Pos_GlueWrap(mTimerNumber) // PM_APBCMASK_TCx_Pos

//#define mTimerHandler_Glue(...)         TC ## __VA_ARGS__ ## _Handler
//#define mTimerHandler_GlueWrap(vTmrNum) mTimerHandler_Glue(vTmrNum)
//#define mTimerHandler                   mTimerHandler_GlueWrap(mTimerNumber) // TCx_Handler

//#define mTimerGCLK_ID_Glue(...)         TC ## __VA_ARGS__ ## _GCLK_ID
//#define mTimerGCLK_ID_GlueWrap(vTmrNum) mTimerGCLK_ID_Glue(vTmrNum)
//#define mTimerGCLK_ID                   mTimerGCLK_ID_GlueWrap(mTimerNumber) // TCx_GCLK_ID

//#define mTimerIRQ_Glue(...)             TC ## __VA_ARGS__ ## _IRQn
//#define mTimerIRQ_GlueWrap(vTmrNum)     mTimerIRQ_Glue(vTmrNum)
//#define mTimerIRQ                       mTimerIRQ_GlueWrap(mTimerNumber) // TCx_IRQn

//#define mTimerDiv_Glue(...)             TC_CTRLA_PRESCALER_DIV ## __VA_ARGS__ ## _Val
//#define mTimerDiv_GlueWrap(vTmrDiv)     mTimerDiv_Glue(vTmrDiv)
//#define mTimerDivVal                    mTimerDiv_GlueWrap(mTimerDiv) // TC_CTRLA_PRESCALER_DIVx_Val

//XXXXXXXXXXXXXXXXXXXXXXXXXXX Типы данных XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

typedef enum // Список состояний таймера
{
cTimerIdle,   // неработающий
cTimerActive, // активный/работающий
cTimerLocked, // заблокированный
cTimerDone    // отработавший
}eTimerState;

struct sTimer// Структура программного таймера
{
uint16_t DelayTicks;       // Задержка до запуска задачи
uint16_t PeriodTicks;      // Период повторения
eTimerState State;         // Текущее состояние
tfTimerCallback pCallback; // Задача таймера
void *pData;               // Данные задачи
};

//XXXXXXXXXXXXXXXXXXXXXXXXXXX Переменные XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

uint8_t TimersNum; // Переменная количества созданных таймеров

uint8_t bTimerLock; // Флаг блокировки объявляемого таймера

struct sTimer asTimerInstance[mTimersMAX]; // Массив таймеров

//XXXXXXXXXXXXXXXXXXXXXXXX Внешние переменные XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

bool gbTimersCheck; // Флаг проверки программных таймеров

//XXXXXXXXXXXXXXXXXXXXXXXX Прототипы функций XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXX Функции XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

//------------------------------------------------------------------------------
// Инициализация опоры программных таймеров ------------------------------------
void SoftTimerRefInit (void)
{
// Настройка источника тактовых колебаний для TC: ------------------------------

// Включение такта шины APBC для TC (выключен по умолчанию после reset)
PM->APBCMASK.reg |= (uint32_t)(1U << mTimerPM_Pos);

// Каналы мультиплексора GCLK для модуля TC сгруппированы парами: (TC0,TC1), (TC2,TC3), и т.д.

// Настройка канала мультиплексора GCLK для модуля TC, включение канала
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_GEN_GCLK1_Val << GCLK_CLKCTRL_GEN_Pos  ) | // Выбор стабильного кварцевого генератора GCLK
                     (mTimerGCLK_ID              << GCLK_CLKCTRL_ID_Pos   ) | // Выбор канала мультиплексора TC
                     (1U                         << GCLK_CLKCTRL_CLKEN_Pos) ; // Включение канала

// Разрешение прерывания в ядре для линии TC в NVIC:
NVIC_SetPriority(mTimerIRQ, mTimerIRQ_Priority);
NVIC_EnableIRQ(mTimerIRQ);

// Настройка модуля TC: --------------------------------------------------------

mTimerInst->COUNT16.CTRLA.reg = (1U << TC_CTRLA_SWRST_Pos); // Программный сброс всех регистров модуля
while(mTimerInst->COUNT16.CTRLA.reg & (1U << TC_CTRLA_SWRST_Pos)); // Ожидание синхронизации модуля (такт обязан быть включен!)

mTimerInst->COUNT16.INTENSET.reg = (1U << (TC_INTENSET_MC_Pos)); // Прерывание по достижению CC[0]

mTimerInst->COUNT16.CTRLA.reg =
(TC_CTRLA_MODE_COUNT16_Val    << TC_CTRLA_MODE_Pos      ) | // Режим 16-битного счётчика
(TC_CTRLA_WAVEGEN_MFRQ_Val    << TC_CTRLA_WAVEGEN_Pos   ) | // "Match Freq" - top=CC0, WO[x] toggles on match CCx
(mTimerDivVal                 << TC_CTRLA_PRESCALER_Pos ) | // Делитель тактовой частоты GCLK для TC
(TC_CTRLA_PRESCSYNC_PRESC_Val << TC_CTRLA_PRESCSYNC_Pos ) ; // Способ синхронизации счётчика "с выходом предделителя"

mTimerInst->COUNT16.CTRLBCLR.reg = (1U << TC_CTRLBCLR_DIR_Pos); // CLR: counting up, SET: counting down

mTimerInst->COUNT16.CC[0].reg = mTimerTick;  // Предельное значение таймера (TOP)
//mTimerInst->COUNT16.CC[1].reg = mTimerTick; // Значение сравнения (COMP1)

mTimerInst->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; // Разрешение работы (сразу начинает считать)
//mTimerInst->COUNT16.CTRLBSET.reg = (TC_CTRLBSET_CMD_STOP_Val << TC_CTRLBSET_CMD_Pos); // Остановка таймера
}

//------------------------------------------------------------------------------
// Функция обработчика прерывания программных таймеров -------------------------
void SoftTimerInterrupt (void)
{ gbTimersCheck = true; } // Флаг проверки программных таймеров

//------------------------------------------------------------------------------
// Обработчик прерывания опоры программных таймеров ----------------------------
void mTimerHandler (void)
{
// Прерывание по достижению максимального значения (переполнению) TOP=COMP0
if(mTimerInst->COUNT16.INTFLAG.reg & (1U << (TC_INTFLAG_MC_Pos))) // Match Compare 0 Flag
   {
   mTimerInst->COUNT16.INTFLAG.reg = (1U << (TC_INTFLAG_MC_Pos)); // Сброс Match Compare 0 Flag
   
   SoftTimerInterrupt(); // Функция обработчика прерывания системного таймера
   }
// Прочие прерывания
else
   {
   // Сброс прочих флагов
   mTimerInst->COUNT16.INTFLAG.reg = (1U << (TC_INTFLAG_MC_Pos+1) )|
                                     (1U << TC_INTFLAG_OVF_Pos    )|
                                     (1U << TC_INTFLAG_ERR_Pos    )|
                                     (1U << TC_INTFLAG_SYNCRDY_Pos);
   }
}

//------------------------------------------------------------------------------
// Функция установки начальных значений таймеров -------------------------------
void SoftTimersInit (void)
{
for(uint8_t i=0; i<mTimersMAX; i++)
   {
   asTimerInstance[i].DelayTicks = 0;
   asTimerInstance[i].PeriodTicks = 0;
   asTimerInstance[i].State = cTimerIdle;
   asTimerInstance[i].pCallback = NULL; // Задача таймера
   asTimerInstance[i].pData = NULL; // Данные задачи
   }

TimersNum = 0; // Переменная количества созданных таймеров
gbTimersCheck = false; // Флаг проверки таймеров
}

//------------------------------------------------------------------------------
// Функция создания программного таймера ---------------------------------------
hTimer TimerCreate (uint16_t DelayTicks, uint16_t PeriodTicks, tfTimerCallback pTask, void *pData)
{
for(uint8_t i=0; i<mTimersMAX; i++) // Поиск свободного таймера
   if(asTimerInstance[i].State == cTimerIdle)
     {
     asTimerInstance[i].DelayTicks = DelayTicks;
     asTimerInstance[i].PeriodTicks = PeriodTicks;
     
     // Таймер, объявляемый в цикле проверки таймеров
     // может сработать в этом же цикле без задержки,
     // поэтому он блокируется до конца текущего цикла
     if(bTimerLock) // Флаг блокировки объявляемого таймера
       {asTimerInstance[i].State = cTimerLocked;} // Блокировка объявляемых таймеров
     else
       {asTimerInstance[i].State = cTimerActive;} // Таймер активный/работающий
     
     asTimerInstance[i].pCallback = pTask;
     asTimerInstance[i].pData = pData;
     
     if((i+1)>TimersNum) {TimersNum = (i+1);} // Количество объявленных таймеров увеличилось
     
     return &asTimerInstance[i]; // Возврат адреса объявленного таймера
     }

return NULL;
}

//------------------------------------------------------------------------------
// Функция продления программного таймера --------------------------------------
bool TimerExtend (uint16_t DelayTicks, hTimer pTimer)
{
if(pTimer >= &asTimerInstance[0] && // Защита от продления по недоступному адресу
    pTimer <= &asTimerInstance[mTimersMAX-1] &&
    pTimer->State == cTimerActive) // Таймер активный/работающий
   {
   pTimer->DelayTicks = DelayTicks; // Обновление задержки до запуска задачи
   return true;
   }

return false; // Ошибочное состояние. Должен удаляться адрес в callback
}

//------------------------------------------------------------------------------
// Функция удаления программного таймера ---------------------------------------
bool TimerDelete (hTimer pTimer)
{
// TO DO: При отработке таймера и переводе в cTimerIdle,
// возможен его захват другим процессом,
// тогда дескриптор недействителен
// Задача таймера должна очищать дескриптор, если хранит его.

// Защита от удаления по недоступному адресу
if(pTimer >= &asTimerInstance[0] &&
    pTimer <= &asTimerInstance[mTimersMAX-1])
   {
   pTimer->State = cTimerIdle; // неработающий
   pTimer->PeriodTicks = 0;
   pTimer->DelayTicks = 0;
   pTimer->pCallback = NULL; // сброс задачи таймера
   pTimer->pData = NULL; // сброс данных задачи таймера
   
   // Удаление последнего в списке объявленных
   if(pTimer == &asTimerInstance[TimersNum-1])
     { TimersNum--; }
   
   return true;
   }

return false; // Ошибочное состояние
}

//------------------------------------------------------------------------------
// Функция проверки программных таймеров ---------------------------------------
void TimersCheck (void)
{
bTimerLock = (uint8_t)true; // Флаг блокировки объявляемого таймера

for(uint8_t i=0; i<TimersNum; i++) // Перебор созданных таймеров
   {
   if(asTimerInstance[i].State == cTimerActive) // Таймер активный/работающий
     {
     if(asTimerInstance[i].DelayTicks == 0) // Задержка до запуска задачи истекла
       {
       hTimer pTimer = &asTimerInstance[i]; // Извлечение адреса сработавшего таймера
       
       if(pTimer->PeriodTicks != 0) // Таймер периодический
         { pTimer->DelayTicks = (pTimer->PeriodTicks); } // Перезапуск таймера
       else // Таймер однократный
         {
         // TO DO: Однократный таймер удаляется, а дескриптор остаётся!
         // Задача таймера должна очищать дескриптор, если хранит его.
         
         pTimer->State = cTimerIdle; // Остановка, перевод в неработающее состояние
         if(i == TimersNum-1) { TimersNum--; } // Удаление последнего в списке объявленных
         }
       
       pTimer->pCallback(pTimer->pData); // Запуск задачи
       }
     else // Отсчёт задержки до запуска
       {asTimerInstance[i].DelayTicks--;}
     } // Хвост "Таймер активный/работающий"
   } // Хвост "Перебор созданных таймеров"

bTimerLock = (uint8_t)false; // Флаг блокировки объявляемого таймера

for(uint8_t i=0; i<TimersNum; i++) // Перебор созданных таймеров
   if(asTimerInstance[i].State == cTimerLocked) // Таймер заблокирован
     { asTimerInstance[i].State = cTimerActive; } // Разблокировка проверенного таймера

}

//------------------------------------------------------------------------------

#endif // __SOFTTIMER_C


Вложения:
SoftTimer.h [1.52 Кб]
Скачиваний: 135
Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Адаптация библиотеки под STM32
СообщениеДобавлено: 03 июл 2019, 10:13 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 2284
ArturAster писал(а):
Нужно адаптировать библиотеку от ATMega

Это не atmega:
PM->APBCMASK.reg |= (uint32_t)(1U << mTimerPM_Pos);

Пойди прочитай, чем серия AVR ATMega от Atmel SAM отличается для начала. Это можно просто нагуглить, без литературы. Для начала.


Последний раз редактировалось NStorm 03 июл 2019, 10:30, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Адаптация библиотеки под STM32
СообщениеДобавлено: 03 июл 2019, 10:21 
Старожил
Аватара пользователя

Зарегистрирован: 22 июл 2017, 11:48
Сообщения: 3646
Я так понял, эта портянка текста описывает программные таймеры?
Программные таймеры реализуются на основе одного аппаратного системного таймера в ядре ARM - SysTick. Прерывания следуют с частотой обновлений SysTick, и в прерывании считают программные таймеры. Просто напишите запуск системного таймера с выбранной частотой SysTick_Config(SystemCoreClock/100), где SystemCoreClock - системная частота (частота МК) в герцах, и впишите в обработчик прерываний системного таймера void SysTick_Handler(void) счетчики программных таймеров.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Адаптация библиотеки под STM32
СообщениеДобавлено: 03 июл 2019, 11:00 
Старожил

Зарегистрирован: 26 ноя 2012, 10:28
Сообщения: 3999
Откуда: КЧР, поселок Нижний Архыз
Чем выкладывать портянку, проще было ТЗ выложить и озвучить сумму!


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Адаптация библиотеки под STM32
СообщениеДобавлено: 03 июл 2019, 18:43 
Старожил
Аватара пользователя

Зарегистрирован: 30 мар 2015, 23:56
Сообщения: 744
Ну и ересь...
Программный таймер не должен блокировать физический. Один единственный физический таймер должен используется как основа для множества программных. Тут два варианта для проверки времени программного таймера: фиксированный по аппаратному таймеру, и произвольный программный. Различие в самой проверке, и способе хранения переменной времени.
Для фиксированной проверки требуется точное место хранения переменных внешних программных таймеров. Так чтобы функция в прерывании смогла их найти, проверить, и выполнить какое-то действие. В этом случае одного счётчика уже не хватает, требуется описание действий в случае выполнения условий сравнения времени, и очень желательно в стандартном для всего проекта виде. Но зато проверка получается очень простой и быстрой.
Для программной проверки всё намного проще. Проверяем событие переполнения в общем программном цикле, и чего-то там делаем прямо в том-же цикле. Сама проверка сложнее. Так как аппаратный таймер может переполняться - то сравнение нужно вывести в линейную область, там где возможность переполнения контролируется. Проще всего это сделать представив аппаратный таймер как число со знаком. Потом от нуля отнимаем сумму значения текущего времени аппаратного счётчика и вашей программной задержки, полученное значение храним для сравнения. В момент проверки суммируем аппаратный счётчик с сохранённой переменной, как только станет больше нуля - чего-то делаем.
Может получится так что время циклов проверки многократно превышает значение задержки, а вам требуется подобие цикла. Тогда находим остаток от суммы проверки делённый на вашу программную задержку, полученное значение отнимаем от новой установки времени.
Литературный способ, который меня очень раздражает.
Код:
int32_t programm_time_mc(int32_t * timer_name, int32_t timer_mc)
{
    int32_t tim = all_sustem.system_us;
    int32_t tim2 = 0;
    if (*timer_name == 0)
    {
        *timer_name = 1 - (timer_mc + tim);
    }else
    {
        tim2 = tim + *timer_name;
        if (tim2 >= timer_mc)
        {
            tim2 %= timer_mc;
            if  (tim2 == 0) tim2++;
            *timer_name = tim2 - (timer_mc + tim);
        }else if (tim2 > 0)
        {
            *timer_name = tim2 - (timer_mc + tim);
        }else tim2 = 0;
    };
    return tim2;
};

_________________
Потоковая OS


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 5 ] 

Часовой пояс: UTC + 5 часов


Кто сейчас на конференции

Сейчас этот форум просматривают: Google [Bot], VladislavS


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB