Easyelectronics.ru

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

Часовой пояс: 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 Кб]
Скачиваний: 83
Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Адаптация библиотеки под STM32
СообщениеДобавлено: 03 июл 2019, 10:13 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 2128
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
Сообщения: 3531
Я так понял, эта портянка текста описывает программные таймеры?
Программные таймеры реализуются на основе одного аппаратного системного таймера в ядре ARM - SysTick. Прерывания следуют с частотой обновлений SysTick, и в прерывании считают программные таймеры. Просто напишите запуск системного таймера с выбранной частотой SysTick_Config(SystemCoreClock/100), где SystemCoreClock - системная частота (частота МК) в герцах, и впишите в обработчик прерываний системного таймера void SysTick_Handler(void) счетчики программных таймеров.


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

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


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

Зарегистрирован: 30 мар 2015, 23:56
Сообщения: 720
Ну и ересь...
Программный таймер не должен блокировать физический. Один единственный физический таймер должен используется как основа для множества программных. Тут два варианта для проверки времени программного таймера: фиксированный по аппаратному таймеру, и произвольный программный. Различие в самой проверке, и способе хранения переменной времени.
Для фиксированной проверки требуется точное место хранения переменных внешних программных таймеров. Так чтобы функция в прерывании смогла их найти, проверить, и выполнить какое-то действие. В этом случае одного счётчика уже не хватает, требуется описание действий в случае выполнения условий сравнения времени, и очень желательно в стандартном для всего проекта виде. Но зато проверка получается очень простой и быстрой.
Для программной проверки всё намного проще. Проверяем событие переполнения в общем программном цикле, и чего-то там делаем прямо в том-же цикле. Сама проверка сложнее. Так как аппаратный таймер может переполняться - то сравнение нужно вывести в линейную область, там где возможность переполнения контролируется. Проще всего это сделать представив аппаратный таймер как число со знаком. Потом от нуля отнимаем сумму значения текущего времени аппаратного счётчика и вашей программной задержки, полученное значение храним для сравнения. В момент проверки суммируем аппаратный счётчик с сохранённой переменной, как только станет больше нуля - чего-то делаем.
Может получится так что время циклов проверки многократно превышает значение задержки, а вам требуется подобие цикла. Тогда находим остаток от суммы проверки делённый на вашу программную задержку, полученное значение отнимаем от новой установки времени.
Литературный способ, который меня очень раздражает.
Код:
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 часов


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

Сейчас этот форум просматривают: нет зарегистрированных пользователей


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

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

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