manually merged with ARM version

This commit is contained in:
2025-11-13 17:43:55 +03:00
parent f978759ae0
commit 04015fb4cb
463 changed files with 119514 additions and 45 deletions

View File

@ -0,0 +1,74 @@
/***************************************************************************//**
@addtogroup ltimer
@{
@file lclock.h
Файл содержит заголовки функций для работы с системным счетчиком. Сами функции
реализуются портом для соответствующей платформы.
@author Borisov Alexey <borisov@lcard.ru>
*****************************************************************************/
#ifndef LCLOCK_H_
#define LCLOCK_H_
#include "lclock_arch.h"
#include "lcspec.h"
#ifndef LCLOCK_TICKS_PER_SECOND
/** Константа, определяющее количество отсчетов системного счетчика в секунду */
#define LCLOCK_TICKS_PER_SECOND 1000
#endif
#if LCLOCK_TICKS_PER_SECOND == 1000
/** Макрос для перевода интервала в мс в количество отсчетов системного счетчика */
#define LTIMER_MS_TO_CLOCK_TICKS(tout) (tout)
/** Макрос для перевода интервала в количестве отсчетов системного счетчика в интервал в мс */
#define LTIMER_CLOCK_TICKS_TO_MS(tout) (tout)
#else
#define LTIMER_MS_TO_CLOCK_TICKS(tout) ((tout)*(LCLOCK_TICKS_PER_SECOND/1000))
#define LTIMER_CLOCK_TICKS_TO_MS(tout) ((tout)*1000/LCLOCK_TICKS_PER_SECOND)
#endif
/** Маска для выделения старшего бита в типе #t_lclock_ticks */
#define LCLOCK_HIGH_BIT (((t_lclock_ticks)-1)/2 + 1)
/** Проверка, установлен ли старший бит для типа #t_lclock_ticks. Если
переменная данного типа содержит интервал в отсчетах системного счетчика,
полученный как разность значений отсчетов счетчика, то данный макрос
можно использовать как признак, отрицательный ли интервал */
#define LCLOCK_IS_NEG(clock) ((clock) & LCLOCK_HIGH_BIT)
#ifdef __cplusplus
extern "C" {
#endif
/** Инициализация системного счетчика заданным значением и его запуск */
void lclock_init_val(t_lclock_ticks init_val);
/** Получение текущего значения системного счетчика */
t_lclock_ticks lclock_get_ticks(void);
/** Запуск системного счетчика в случае, если его начальное значение не важно */
static LINLINE void lclock_init(void) {
lclock_init_val(0);
}
/** Проверка, был ли уже инициализирован системный счетчик */
char lclock_is_initialized(void);
/** Запрет работы системного счетчика */
void lclock_disable(void);
/** Для некоторых портов есть возможность реализовать пользовательскую функцию,
* которая будет вызываться раз в мс. Для этого необходимо глобально определить
* LCLOCK_USE_USER_MS_CB и реализовать функцию lclock_user_ms_cb() */
#ifdef LCLOCK_USE_USER_MS_CB
extern void lclock_user_ms_cb(void);
#endif
#ifdef __cplusplus
}
#endif
#endif /* LCLOCK_H_ */
/** @} */

View File

@ -0,0 +1,56 @@
# Файл для включения в проект на CMAKE.
# Перед включением необходимо определить переменные
# LTIMER_DIR - путь к директории, где находится ltimer.cmake
# LCSPEC_DIR - путь к директории, где находится файлы lcspec
#
# После включения будут установлены следующие перменные:
# LTIMER_HEADERS - используемые заголовочные файлы
# LTIMER_SOURCES - используемые файлы исходных кодов
# LTIMER_LIBS - используемые библиотеки
# LTIMER_DEFINITIONS - используемые определения компилятора
cmake_policy(PUSH)
cmake_minimum_required(VERSION 2.8.12)
include(CheckLibraryExists)
include(CheckFunctionExists)
set (LTIMER_HEADERS
${LTIMER_DIR}/ltimer.h
${LCSPEC_DIR}/lcspec.h
)
if(UNIX)
set(LTIMER_SOURCES ${LTIMER_DIR}/ports/linux/lclock.c)
include_directories(${LTIMER_DIR}/ports/linux)
elseif(WIN32)
set(LTIMER_SOURCES ${LTIMER_DIR}/ports/win/lclock.c)
include_directories(${LTIMER_DIR}/ports/win)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "QNX4")
set(LTIMER_SOURCES ${LTIMER_DIR}/ports/linux/lclock.c)
include_directories(${LTIMER_DIR}/ports/linux)
endif(UNIX)
include_directories(${LCSPEC_DIR} ${LTIMER_DIR})
if(UNIX)
check_library_exists(rt clock_gettime "" HAVE_LIBRT)
if(HAVE_LIBRT)
set(LTIMER_LIBS ${TIMER_LIBS} rt)
else(HAVE_LIBRT)
set(CMAKE_REQUIRED_INCLUDES time.h)
# проверяем наличие clock_gettime вне librt.
# если нет, то можем откатиться к gettimeofday
check_function_exists("clock_gettime" HAVE_CLOCKGETTIME)
if(NOT HAVE_CLOCKGETTIME)
set(LTIMER_DEFINITIONS NO_CLOCKGETTIME)
endif(NOT HAVE_CLOCKGETTIME)
endif(HAVE_LIBRT)
endif(UNIX)
cmake_policy(POP)

View File

@ -0,0 +1,278 @@
/***************************************************************************//**
@defgroup ltimer Таймер
Модуль представляет собой набор функций для реализации таймера на основе
системных часов процессора (контроллера) или ОС.
Работа таймера основана на системном счетчике, который должен равномерно
увеличиваться с течением времени.
Реализация функций для инициализации системного счетчика и получения его значения
реализуются для каждой платформы своим портом. Также порт определяет количество
тиков системного счетчика за секунду с помощью константы #LCLOCK_TICKS_PER_SECOND
и тип #t_lclock_ticks для представления текущего значения системного счетчика.
Эти функции могут использоваться как напрямую, так и через общее API для работы
с таймером из ltimer.h, который может использоваться для отсчета интервалов
времени.
Все функции принимают значения в отсчетах системного счетчика, поэтому необходимо
использовать константу #LCLOCK_TICKS_PER_SECOND для перевода времени в количество отсчетов.
Также можно использовать макросы LTIMER_MS_TO_CLOCK_TICKS() и LTIMER_CLOCK_TICKS_TO_MS()
для перевода интервалов в миллисекундах в количество отсчетов и наоборот.
Для работы с модулем в проекте нужно добавить в стандартные пути
для включения заголовочных файлов пути к файлу ltimer.h и к директории с портом
для используемой платформы, а также путь к файлу lcspec.h, в котором
описаны специфические для компилятора макросы (в данном случае используется
#LINLINE для определения inline-функций). Также необходимо в исходники
добавить файл lclock.c из нужного порта.
При работе с системным счетчиком контроллера перед вызовом функций данного модуля
необходимо вызвать функцию lclock_init() (или lclock_init_val(), если нужно задать
начальное значение системного счетчика). При работе с системными часами ОС
обычно эта функция не требуется, так как таймер ОС уже инициализирован
самой ОС (однако ее вызов можно оставить, так как каждый порт реализует хотя бы
"пустую" версию этой функции).
Для работы с системным счетчиком напрямую используется функция lclock_get_ticks(),
возвращающая значение системного счетчика.
Для работы с API таймера, необходимо объявить переменную типа #t_ltimer, которая
будет хранить состояние таймра. Работать с полями структуры напрямую не рекомендуется.
Вместо этого следует использовать функции из ltimer.h, которые принимают эту
переменную в качестве первого аргумента.
При стандартной работе, сперва таймер устанавливается для отсчета заданного
интервала с помощью ltimer_set(). Проверить, истек ли заданный интервал,
можно с помощью ltimer_expired(). Количество отсчетов системного счетчика
до истечения интервала можно получить с помощью ltimer_expiration().
Перезапустить таймер на установленный в предыдущем ltimer_set() интервал можно
с помощью ltimer_reset() или ltimer_restart() (относительно времени последнего
истечения таймера или текущего времени соответственно).
Например, если какие-то действия нужно выполнять в течении заданного интервала,
то это можно сделать следующим образом:
@code
//время интервала в мс
#define TIMEOUT_MS 200
void main(void) {
t_ltimer tmr;
//инициализируем системный счетчик
lclock_init();
// устанавливаем таймер на заданное кол-во мс
ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(TIMEOUT_MS));
while (!ltimer_expired(&tmr)) {
//выполняем требуемые действия
}
//интервал завершился
}
@endcode
В качестве основной идеи была взята реализация таймера для стека uIP от
Adam Dunkels <adam@sics.se>
*****************************************************************************/
/***************************************************************************//**
@addtogroup ltimer
@{
@file ltimer.h
Файл содержит описание функций для работы с таймером. Все функции реализованы
как inline-функции, так что файл содержит и реализацию функций
@author Borisov Alexey <borisov@lcard.ru>
*****************************************************************************/
#ifndef __LTIMER_H__
#define __LTIMER_H__
#include "lclock.h"
#include "lcspec.h"
/** Структура для описания состояния таймера */
typedef struct ltimer {
t_lclock_ticks start; /**< Значение системного таймера, с которого ведется отсчет */
t_lclock_ticks interval; /**< Интервал времени, после которого таймер считается истекшим */
} t_ltimer;
/***************************************************************************//**
@brief Получить время запуска таймера
@param[in] t Указатель на состояние таймера
@return Значение времени запуска таймера в системных клоках
******************************************************************************/
static LINLINE t_lclock_ticks ltimer_start_time(t_ltimer *t) {
return t->start;
}
/***************************************************************************//**
@brief Получить время срабатывания таймера
@param[in] t Указатель на состояние таймера
@return Значение времени срабатывания таймера в системных клоках
******************************************************************************/
static LINLINE t_lclock_ticks ltimer_expiration_time(t_ltimer *t) {
return t->start + t->interval;
}
/***************************************************************************//**
@brief Получить установленный интервал для таймера
@param[in] t Указатель на состояние таймера
@return Значение установленного интервала в системных клоках
******************************************************************************/
static LINLINE t_lclock_ticks ltimer_interval(t_ltimer *t) {
return t->interval;
}
/***************************************************************************//**
@brief Установить временной интервал относительно заданного времени
Функция устанавливает таймер на заданный интервал, аналогично ltimer_set(),
но относительно заданного времени (значения системного счетчика), а не
относительно текущего.
С помощью функции ltimer_expired() можно в дальнейшем проверить, истек ли
заданный интервал.
@param[in] t Указатель на состояние таймера
@param[in] interval Интервал, через который таймер истечет в системных клоках.
@param[in] start_time Значение системного счетчика, относительно которого
устанавливается временной интервал
******************************************************************************/
static LINLINE void ltimer_set_at(t_ltimer *t, t_lclock_ticks interval, t_lclock_ticks start_time) {
t->interval = interval;
t->start = start_time;
}
/***************************************************************************//**
@brief Установить временной интервал
Функция устанавливает таймер на заданный интервал относительно текущего времени.
С помощью функции ltimer_expired() можно в дальнейшем проверить, истек ли
заданный интервал.
@param[in] t Указатель на состояние таймера
@param[in] interval Интервал, через который таймер истечет в системных клоках.
******************************************************************************/
static LINLINE void ltimer_set(t_ltimer *t, t_lclock_ticks interval) {
ltimer_set_at(t, interval, lclock_get_ticks());
}
/***************************************************************************//**
@brief Установить временной интервал в мс
Функция устанавливает таймер на заданный интервал в милисекундах относительно
текущего времени.
С помощью функции ltimer_expired() можно в дальнейшем проверить, истек ли
заданный интервал.
@param[in] t Указатель на состояние таймера
@param[in] ms Интервал, через который таймер истечет в милисекундах.
******************************************************************************/
static LINLINE void ltimer_set_ms(t_ltimer *t, unsigned ms) {
ltimer_set(t, LTIMER_MS_TO_CLOCK_TICKS(ms));
}
/***************************************************************************//**
@brief Сброс таймера.
Данная функции перезапускает таймер на интервал, заданный в последнем ltimer_set()
относительно времени последнего истечения таймера (а не текущего времени, как
ltimer_restart()). По сути функция продлевает время истечения таймера на тот
же интервал, что был задан. Интервалы между срабатыванием таймеров
сохраняется во времени, в отличие от использования ltimer_restart().
@param[in] t Указатель на состояние таймера
*****************************************************************************/
static LINLINE void ltimer_reset(t_ltimer *t) {
t->start += t->interval;
}
/***************************************************************************//**
@brief Перезапуск таймера с заданного времени.
Данная функции перезапускает таймер на интервал, заданный в последнем ltimer_set(),
относительно текущего времени, начиная с указанного времени.
@param[in] t Указатель на состояние таймера
@param[in] start_time Значение системного счетчика, соответствующего времени,
с которого перезапускается таймер
*****************************************************************************/
static LINLINE void ltimer_restart_at(t_ltimer *t, t_lclock_ticks time) {
t->start = time;
}
/***************************************************************************//**
@brief Перезапуск таймера.
Данная функции перезапускает таймер на интервал, заданный в последнем ltimer_set(),
относительно текущего времени.
@note Время срабатывания периодического таймер будет "плыть" при использовании
данной функции (из-за случайной разницы между текущим временем и временем
завершения предыдущего интервала). Для периодического таймера можно использовать
ltimer_reset()
@param[in] t Указатель на состояние таймера
*****************************************************************************/
static LINLINE void ltimer_restart(t_ltimer *t) {
ltimer_restart_at(t, lclock_get_ticks());
}
/***************************************************************************//**
@brief Проверка, истечет ли заданный интервал в определенное время
Функция проверяет, истечет ли установленный с помощью ltimer_set() интервал
в моент времени, определяемый заданным значением системного счетчика.
@param[in] t Указатель на состояние таймера
@param[in] exp_time Значение системного счетчика, для которого проверяется,
истечет ли таймер в данный момент
@return Не ноль, если интервал истечет, иначе --- ноль
******************************************************************************/
static LINLINE int ltimer_expired_at(const t_ltimer *t, t_lclock_ticks exp_time) {
return (t_lclock_ticks)(exp_time - t->start) > (t_lclock_ticks)t->interval;
}
/***************************************************************************//**
@brief Проверка, истек ли заданный интервал
Функция проверяет, истек ли заданный с помощью ltimer_set() интервал.
@param[in] t Указатель на состояние таймера
@return Не ноль, если интервал истек, иначе --- ноль
******************************************************************************/
static LINLINE int ltimer_expired(const t_ltimer *t) {
return ltimer_expired_at(t, lclock_get_ticks());
}
/***************************************************************************//**
@brief Получить время до истечения интервала от заданного момента
Функция возвращает значение интервала времени (в системных клоках) от заданного
момента до времени истечения установленного с помощью ltimer_set() интервала.
@param[in] t Указатель на состояние таймера
@param[in] cur_time Значение системного счетчика, от которого считается время
до момента истечения интервала
@return Время (в клоках системного счетчика) до истечения интервала
*******************************************************************************/
static LINLINE t_lclock_ticks ltimer_expiration_from(const t_ltimer *t, t_lclock_ticks cur_time) {
t_lclock_ticks expired = (cur_time-t->start);
return (expired > t->interval) ? 0 : t->interval - expired;
}
/***************************************************************************//**
@brief Получить время до истечения интервала
Функция возвращает значение интервала времени (в системных клоках) от текущего
момента до времени истечения установленного с помощью ltimer_set() интервала.
@param[in] t Указатель на состояние таймера
@return Время (в клоках системного счетчика) до истечения интервала
*******************************************************************************/
static LINLINE t_lclock_ticks ltimer_expiration(const t_ltimer *t) {
return ltimer_expiration_from(t, lclock_get_ticks());
}
#endif /* __LTIMER_H__ */
/** @} */

View File

@ -0,0 +1,45 @@
# makefile для включения в проект.
#
# на входе принимает параметры:
# TARGET_CPU (или может быть переопределен через LTIMER_TARGET) - если явно
# не установлена переменная LTIMER_PORT, то по данной переменной
# выбирается подходящий порт
# LTIMER_PORT - опционально можно явно указать порт (на случай, если несколько
# портов могут относится к одной архитектуре)
# LSCPEC_DIR - путь к определениям к lcspec (по-умолчанию ../lcspec относительно данного файла)
#
# устанавливает следующие параметры:
# LTIMER_SRC - исходные файлы на C
# LTIMER_INC_DIRS - директории с заголовками, которые должны быть добавлены
# в список директорий для поиска заголовков проекта
LTIMER_MAKEFILE = $(abspath $(lastword $(MAKEFILE_LIST)))
LTIMER_DIR := $(dir $(LTIMER_MAKEFILE))
LCSPEC_DIR ?= $(LTIMER_DIR)/../lcspec
LTIMER_TARGET ?= $(TARGET_CPU)
ifndef LTIMER_PORT
ifeq ($(LTIMER_TARGET), lpc17xx)
LTIMER_PORT = cm_systick
else ifeq ($(LTIMER_TARGET), lpc43xx)
LTIMER_PORT = cm_systick
else ifeq ($(LTIMER_TARGET), lpc11u6x)
LTIMER_PORT = cm_systick
else ifeq ($(LTIMER_TARGET), bf609)
LTIMER_PORT = bf_core_tmr
else ifeq ($(LTIMER_TARGET), imx6)
LTIMER_PORT = imx6_epit
else ifeq ($(LTIMER_TARGET), stm32h7xx)
LTIMER_PORT = cm_systick
endif
endif
ifndef LTIMER_PORT
$(error unknown port. LTIMER_PORT or one of supported target in LTIMER_TARGET or TARGET_CPU must be specified)
endif
LTIMER_SRC := $(LTIMER_DIR)/ports/$(LTIMER_PORT)/lclock.c
LTIMER_INC_DIRS := $(LCSPEC_DIR) $(LTIMER_DIR) $(LTIMER_DIR)/ports/$(LTIMER_PORT)

View File

@ -0,0 +1,12 @@
#include "chip.h"
#include "lclock_arch.h"
t_lclock_ticks g_lclock_tiks_per_sec;
void lclock_init_val(t_lclock_ticks init_val) {
g_lclock_tiks_per_sec = chip_gtim_freq();
}
t_lclock_ticks lclock_get_ticks(void) {
return chip_gtim_cntr();
}

View File

@ -0,0 +1,15 @@
#ifndef LCLOCK_ARCH_H
#define LCLOCK_ARCH_H
#include <stdint.h>
typedef uint64_t t_lclock_ticks;
extern t_lclock_ticks g_lclock_tiks_per_sec;
#define LCLOCK_TICKS_PER_SECOND g_lclock_tiks_per_sec
#endif // LCLOCK_ARCH_H

View File

@ -0,0 +1,70 @@
#include "chip.h"
#include "lclock.h"
static volatile t_lclock_ticks lclock_systicks;
static uint8_t f_initialized = 0;
ISR(TIMER2_COMPA_vect) {
lclock_systicks++;
}
#define CLOCK_IRQ_TICKS (CHIP_CLK_SYS_FREQ/LCLOCK_TICKS_PER_SECOND)
#if CLOCK_IRQ_TICKS < 256
#define LCLOCK_SYS_CLK_DIV 1
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_1
#elif CLOCK_IRQ_TICKS/8 < 256
#define LCLOCK_SYS_CLK_DIV 8
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_8
#elif CLOCK_IRQ_TICKS/32 < 256
#define LCLOCK_SYS_CLK_DIV 32
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_32
#elif CLOCK_IRQ_TICKS/64 < 256
#define LCLOCK_SYS_CLK_DIV 64
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_64
#elif CLOCK_IRQ_TICKS/128 < 256
#define LCLOCK_SYS_CLK_DIV 128
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_128
#elif CLOCK_IRQ_TICKS/256 < 256
#define LCLOCK_SYS_CLK_DIV 256
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_256
#elif CLOCK_IRQ_TICKS/1024 < 256
#define LCLOCK_SYS_CLK_DIV 1024
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_1024
#else
#error "unsupported system clock frequency"
#endif
/*************************************************************************
* инициализация системного таймера
* использует для этого RIT
* ***********************************************************************/
void lclock_init_val(t_lclock_ticks init_val) {
/* инициализируем счетчик */
lclock_systicks = init_val;
f_initialized = 1;
CHIP_REG_TIMSK2 = CHIP_REGFLD_TIMSK0_OCIE0A;
CHIP_REG_OCR2A = ((CLOCK_IRQ_TICKS + LCLOCK_SYS_CLK_DIV/2)/LCLOCK_SYS_CLK_DIV -1);
CHIP_REG_TCCR2A = LBITFIELD_SET(CHIP_REGFLD_TCCR0A_WGM0_01, CHIP_REGFLDVAL_TC2_WGM_CTC);
CHIP_REG_TCCR2B = LBITFIELD_SET(CHIP_REGFLD_TCCR0B_WGM0_2, CHIP_REGFLDVAL_TC2_WGM_CTC >> 2)
| LBITFIELD_SET(CHIP_REGFLD_TCCR0B_CS, LCLOCK_TCCR0B_CS_RVAL);
}
char lclock_is_initialized(void) {
return f_initialized;
}
t_lclock_ticks lclock_get_ticks(void) {
return lclock_systicks;
}
void lclock_disable(void) {
CHIP_REG_TCCR2B = 0;
f_initialized = 0;
}

View File

@ -0,0 +1,10 @@
#ifndef LCLOCK_ARCH_H
#define LCLOCK_ARCH_H
#include <stdint.h>
#define LCLOCK_TICKS_PER_SECOND 1000
typedef uint32_t t_lclock_ticks;
#endif // LCLOCK_ARCH_H

View File

@ -0,0 +1,47 @@
/***************************************************************************//**
@ingroup ltimer_bf_core_tmr
@file ports/bf_core_tmr/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком
для процессора BlackFin
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include "lclock.h"
/* файл должен определять LPC_SYSCLK и включать cmsis.h */
#include "chip.h"
volatile t_lclock_ticks lclock_systicks;
static char f_initialized = 0;
ISR(lclock_isr);
/*************************************************************************
* инициализация системного таймера
* ***********************************************************************/
void lclock_init_val(t_lclock_ticks init_val) {
/* инициализируем счетчик */
lclock_systicks = init_val;
REGISTER_ISR(6, lclock_isr);
*pTCNTL = BITM_TCNTL_AUTORLD | BITM_TCNTL_PWR;
*pTPERIOD = CHIP_CLKF_CCLK/LCLOCK_TICKS_PER_SECOND;
*pTSCALE = 0;
*pTCNTL |= BITM_TCNTL_EN;
f_initialized = 1;
}
char lclock_is_initialized(void) {
return f_initialized;
}
void lclock_disable(void) {
*pTCNTL = 0;
f_initialized = 0;
}
ISR(lclock_isr) {
lclock_systicks++;
#ifdef LCLOCK_USE_USER_MS_CB
lclock_user_ms_cb();
#endif
}

View File

@ -0,0 +1,38 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_bf_core_tmr Порт таймера для BlackFin
Порт для работы с таймером для сигнальных процессоров BlackFin от Analog Devices.
Для получения системного счетчика использует таймер ядра
*****************************************************************************/
/***************************************************************************//**
@ingroup ltimer_bf_core_tmr
@file ports/bf_core_tmr/lclock_arch.h
Файл содержит определение типов и констант для работы с системным счетчиком
для процессоров BlackFin
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#include "lcspec.h"
#ifndef LCLOCK_TICKS_PER_SECOND
/** Количество тиков системного таймера в секунду */
#define LCLOCK_TICKS_PER_SECOND 1000
#endif
/** Тип для представления количества системных тиков */
typedef unsigned int t_lclock_ticks;
extern volatile t_lclock_ticks lclock_systicks;
static LINLINE t_lclock_ticks lclock_get_ticks(void) {
return lclock_systicks;
}
#endif /* LCLOCK_ARCH_H_ */

View File

@ -0,0 +1,66 @@
/***************************************************************************//**
@ingroup ltimer_cm_systick
@file ports/cm_systick/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком
для Cortex-M с использованием системного таймера.
Порт требует наличие файла chip.h, который включает определение LPC_SYSCLK
и включать функции CMSIS (используется SysTick_Config).
Если LPC_SYSCLK не определена, то используется значение из переменной SystemCoreClock
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include "lclock.h"
/* файл должен определять LPC_SYSCLK и включать cmsis.h */
#include "chip.h"
#ifndef LCLOCK_IN_CLK_FREQ
#ifdef CHIP_CLK_SYSTICK_FREQ
/* используем частоту SysTick, если она определена в chip */
#define LCLOCK_IN_CLK_FREQ CHIP_CLK_SYSTICK_FREQ
#elif defined LPC_SYSCLK
/* для совместимости с версией chip, где определялось только значение LPC_SYSCLK */
#define LCLOCK_IN_CLK_FREQ LPC_SYSCLK
#else
/* если другие варианты не определены, то используем вариант с внешней
* переменной, который в частности используется в lpcopen */
extern uint32_t SystemCoreClock;
#define LCLOCK_IN_CLK_FREQ SystemCoreClock
#endif
#endif
volatile t_lclock_ticks lclock_systicks;
static char f_initialized = 0;
/*************************************************************************
* инициализация системного таймера
* ***********************************************************************/
void lclock_init_val(t_lclock_ticks init_val) {
/* инициализируем счетчик */
lclock_systicks = init_val;
SysTick_Config(LCLOCK_IN_CLK_FREQ / LCLOCK_TICKS_PER_SECOND);
f_initialized = 1;
}
char lclock_is_initialized(void) {
return f_initialized;
}
void lclock_disable(void) {
SysTick->CTRL = 0;
f_initialized = 0;
}
/* обработка прерывания от системного таймера - обновление числа тиков */
#if defined ( __ICCARM__ )
void SysTick_Handler(void) {
#else
void SysTick_IRQHandler(void) {
#endif
lclock_systicks++;
#ifdef LCLOCK_USE_USER_MS_CB
lclock_user_ms_cb();
#endif
}

View File

@ -0,0 +1,44 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_cm_systick Порт таймера для Cortex-M
Порт для работы с таймером для микроконтроллеров с ядром Cortex-M.
Для получения системного счетчика использует системный таймер (SysTick).
*****************************************************************************/
/***************************************************************************//**
@ingroup ltimer_cm_systick
@file ports/cm_systick/lclock_arch.h
Файл содержит определение типов и констант для работы с системным счетчиком
для процессоров с ядром Cortex-M с использованием системного таймера.
Порт использует внешний файл chip.h, в котором должно быть определено
значение частоты входной частоты системного таймера одним из следующих способов
(в порядке убывания приоритетов):
- определен явно макрос LCLOCK_IN_CLK_FREQ
- определен макрос CHIP_CLK_SYSTICK_FREQ (в новых версиях библиотеки chip)
- определен макрос LPC_SYSCLK (старая версия библиотеки chip или порта контроллера для LPC)
- в проекте должна существовать глобальная переменная SystemCoreClock типа uint32_t,
которая на момент lcock_init() должна содержать действительную частоту
системного таймера
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#include "lcspec.h"
/** Количество тиков системного таймера в секунду */
#define LCLOCK_TICKS_PER_SECOND 1000
/** Тип для представления количества системных тиков */
typedef unsigned int t_lclock_ticks;
extern volatile t_lclock_ticks lclock_systicks;
static LINLINE t_lclock_ticks lclock_get_ticks(void) {
return lclock_systicks;
}
#endif /* LCLOCK_ARCH_H_ */

View File

@ -0,0 +1,7 @@
#ifndef LCLOCK_CONF_H
#define LCLOCK_CONF_H
/* задает, какой именно EPIT таймер будет использован (HW_EPIT1 или HW_EPIT2) */
#define LCLOCK_CONF_EPIT_INST HW_EPIT2
#endif // LCLOCK_CONF_H

View File

@ -0,0 +1,79 @@
/***************************************************************************//**
@ingroup ltimer_imx6_epit
@file ports/imx6_epit/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком
для процессора imx6, использующую один из EPIT-таймеров.
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include <stdint.h>
#include "lclock.h"
#include "core/ccm_pll.h"
#include "registers/regsepit.h"
//! @brief Available clock sources for the timers.
enum _timer_clock_sources {
CLKSRC_OFF = 0, //!< clock source is OFF
CLKSRC_IPG_CLK = 1, //!< clock source is peripheral clock
CLKSRC_PER_CLK = 2, //!< clock source is high-freq reference clock
CLKSRC_CLKIN = 3, //!< clock source is external from a CLKIN input
CLKSRC_CKIL = 3 //!< clock source is low-freq reference clock
};
static char f_initialized = 0;
/*************************************************************************
* инициализация системного таймера
* использует для этого RIT
* ***********************************************************************/
void lclock_init_val(t_lclock_ticks init_val) {
uint32_t freq = get_main_clock(IPG_CLK);
uint32_t control_reg_tmp = 0;
uint32_t base = REGS_EPIT_BASE(LCLOCK_CONF_EPIT_INST);
uint32_t prescaler = freq / LCLOCK_TICKS_PER_SECOND;
// enable the source clocks to the EPIT port
clock_gating_config(base, CLOCK_ON);
// start with a known state by disabling and reseting the module
HW_EPIT_CR_WR(LCLOCK_CONF_EPIT_INST, BM_EPIT_CR_SWR);
// wait for the reset to complete
while ((HW_EPIT_CR(LCLOCK_CONF_EPIT_INST).B.SWR) != 0) ;
// set the reference source clock for the counter
control_reg_tmp |= BF_EPIT_CR_CLKSRC(CLKSRC_IPG_CLK);
// set the counter clock prescaler value - 0 to 4095
control_reg_tmp |= BF_EPIT_CR_PRESCALAR(prescaler-1);
// set behavior for low power mode
control_reg_tmp |= BM_EPIT_CR_WAITEN;
control_reg_tmp |= BM_EPIT_CR_STOPEN;
// make the counter start from a known value when enabled, this is loaded from
// EPITLR register if RLD=reload_mode=1 or 0xFFFFFFFF if RLD=reload_mode=0
control_reg_tmp |= BM_EPIT_CR_IOVW | BM_EPIT_CR_ENMOD;
// finally write the control register
HW_EPIT_CR_WR(LCLOCK_CONF_EPIT_INST, control_reg_tmp);
// finally, enable the counter
HW_EPIT_CR_SET(LCLOCK_CONF_EPIT_INST, BM_EPIT_CR_EN);
f_initialized = 1;
}
char lclock_is_initialized(void) {
return f_initialized;
}
t_lclock_ticks lclock_get_ticks(void) {
t_lclock_ticks val = -HW_EPIT_CNR_RD(LCLOCK_CONF_EPIT_INST);
return val;
}

View File

@ -0,0 +1,29 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_imx6_epit Порт таймера для процессора iMX6
Порт для работы с таймером для процессоров iMX6 от Freescale на базе таймера EPIT.
Для данного порта необходим файл в проекте lclock_conf.h, который бы задавал номер
используемого EPIT-таймера
*****************************************************************************/
/***************************************************************************//**
@ingroup ltimer_imx6_epit
@file ports/imx6_epit/lclock_arch.h
Файл содержит определение типов и констант для работы с системным таймером
для процессоров iMX6 от Freescale на базе таймера EPIT.
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#include "lclock_conf.h"
#ifndef LCLOCK_TICKS_PER_SECOND
#define LCLOCK_TICKS_PER_SECOND 1000000
#endif
typedef unsigned int t_lclock_ticks;
#endif /* LCLOCK_ARCH_H_ */

View File

@ -0,0 +1,34 @@
#include "lclock_arch.h"
static char f_initialized = 0;
char lclock_is_initialized(void) {
return f_initialized;
}
void lclock_init_val(t_lclock_ticks init_val) {
chip_per_clk_en(CHIP_PER_CLK_NUM_SYSCTR);
CHIP_REGS_SYSCTR_CTRL->CNTCR = 0;
CHIP_REGS_SYSCTR_CTRL->CNTCV0 = init_val & 0xFFFFFFFFUL;
CHIP_REGS_SYSCTR_CTRL->CNTCV1 = (init_val >> 32) & 0xFFFFFFFFUL;
CHIP_REGS_SYSCTR_CTRL->CNTCR = CHIP_REGFLD_SYSCTR_CNTCR_EN | CHIP_REGFLD_SYSCTR_CNTCR_FCR(0);
f_initialized = 1;
}
void lclock_disable(void) {
CHIP_REGS_SYSCTR_CTRL->CNTCR = 0;
chip_per_clk_dis(CHIP_PER_CLK_NUM_SYSCTR);
f_initialized = 0;
}
t_lclock_ticks lclock_get_ticks(void) {
chip_isb();
uint32_t h1 = CHIP_REGS_SYSCTR_CTRL->CNTCV1;
uint32_t l = CHIP_REGS_SYSCTR_CTRL->CNTCV0;
uint32_t h2 = CHIP_REGS_SYSCTR_CTRL->CNTCV1;
if ((h2 != h1) && (l > 0x80000000U)) {
h2 = h1;
}
return ((uint64_t)h2 << 32) | l;
}

View File

@ -0,0 +1,12 @@
#ifndef LCLOCK_ARCH_H
#define LCLOCK_ARCH_H
#include <chip.h>
#include <stdint.h>
typedef uint64_t t_lclock_ticks;
#define LCLOCK_TICKS_PER_SECOND CHIP_CLK_SYSCTR_BASE_FREQ
#endif // LCLOCK_ARCH_H

View File

@ -0,0 +1,58 @@
/***************************************************************************//**
@ingroup ltimer_linux
@file ports/linux/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком в OC Linux
через clock_gettime() из librt.
@date 16.09.2011
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include "lclock.h"
#include <time.h>
#include <stddef.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_SYS_TIMERS_H
#include <sys/timers.h>
#endif
#ifdef NO_CLOCKGETTIME
#include <sys/time.h>
#else
#ifdef CLOCK_MONOTONIC
#define LTIMER_CLK_ID CLOCK_MONOTONIC
#else
#define LTIMER_CLK_ID TIMEOFDAY
#endif
#endif
void lclock_init_val(t_lclock_ticks init_val) {
/* инициализация системного таймера не требуется */
}
char lclock_is_initialized(void) {
return 1;
}
t_lclock_ticks lclock_get_ticks(void) {
#ifdef NO_CLOCKGETTIME
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000 + tv.tv_usec/1000;
#else
struct timespec tp;
clock_gettime(LTIMER_CLK_ID, &tp);
return tp.tv_sec*1000 + tp.tv_nsec/1000000;
#endif
}

View File

@ -0,0 +1,30 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_linux Порт таймера для Linux
Порт для работы с таймером в ОС Linux. Для получения системного счетчика
использует функцию clock_gettime() из librt для получения CLOCK_MONOTONIC,
который нельзя устанавливать и дает приемлемую точность (если нет в ОС, то
используется TIMEOFDAY).
*****************************************************************************/
/***************************************************************************//**
@ingroup ltimer_linux
@file ports/linux/lclock_arch.h
Файл содержит определение типов и констант для работы с системным счетчиком
в OC Linux через функцию clock_gettime().
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#include <stdint.h>
/* Возвращаем счетчик в миллисекундах, хотя clock_gettime() может дать нс,
но реально они не изменяются + с мс сохраняется достаточное время
переполнения для 32-битного счетчика */
#define LCLOCK_TICKS_PER_SECOND 1000
/* для простоты и скорости операций используем 32-битное слово */
typedef uint32_t t_lclock_ticks;
#endif /* LCLOCK_ARCH_H_ */

View File

@ -0,0 +1,70 @@
/***************************************************************************//**
@ingroup ltimer_lpc17xx_rit
@file ports/lpc17xx_rit/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком
в LPC17xx с использованием RIT.
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include "lclock.h"
#include "LPC17xx.h"
#include "iolpc17XX.h"
#include "system_LPC17xx.h"
static volatile t_lclock_ticks lclock_systicks;
static char f_initialized = 0;
/*************************************************************************
* инициализация системного таймера
* использует для этого RIT
* ***********************************************************************/
void lclock_init_val(t_lclock_ticks init_val) {
/* инициализируем счетчик */
lclock_systicks = init_val;
/* подаем питание на RIT */
LPC_SC->PCONP |= LPC_SC_PCONP_PCRIT_Msk;
/* останавливаем счетчик (на случай если был запущен) и иницилизируем его */
LPC_RIT->RICTRL =0;
LPC_RIT->RICOUNTER = 0;
LPC_RIT->RICOMPVAL = SystemCoreClock / (4 * 1000);
LPC_RIT->RIMASK = 0x0;
LPC_RIT->RICTRL = LPC_RIT_RICTRL_RITENCLR_Msk | LPC_RIT_RICTRL_RITEN_Msk
| LPC_RIT_RICTRL_RITENBR_Msk;
/* разрешаем прерывания */
NVIC_EnableIRQ(RIT_IRQn);
f_initialized = 1;
}
char lclock_is_initialized(void) {
return f_initialized;
}
t_lclock_ticks lclock_get_ticks(void) {
return lclock_systicks;
}
void lclock_disable(void) {
NVIC_DisableIRQ(RIT_IRQn);
LPC_RIT->RICTRL = 0;
f_initialized = 0;
}
/* обработка прерывания от RIT - обновление числа тиков */
#include "lcspec_interrupt.h"
void RIT_IRQHandler(void) {
LPC_RIT->RICTRL |= LPC_RIT_RICTRL_RITINT_Msk;
lclock_systicks++;
#ifdef LCLOCK_USE_USER_MS_CB
lclock_user_ms_cb();
#endif
}

View File

@ -0,0 +1,24 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_lpc17xx_rit Порт таймера для LPC17xx
Порт для работы с таймером для микроконтроллеров семейства LPC17xx (Cortex-M3).
Для получения системного счетчика использует RIT (Repetitive Interrupt Timer).
*****************************************************************************/
/***************************************************************************//**
@ingroup timer_lpc17xx_rit
@file ports/lpc17xx_rit/lclock_arch.h
Файл содержит определение типов и констант для работы с системным счетчиком
в LPC17xx с использованием RIT.
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#define LCLOCK_TICKS_PER_SECOND 1000
typedef unsigned int t_lclock_ticks;
#endif /* LCLOCK_ARCH_H_ */

View File

@ -0,0 +1,22 @@
#include "chip.h"
#include "lclock_arch.h"
void lclock_init_val(t_lclock_ticks init_val) {
uint32_t l = init_val & 0xFFFFFFFF;
uint32_t h = (init_val >> 32) & 0xFFFFFFFF;
if (l < 0xE0000000) {
CHIP_REGS_MCHTMR->MTIME.l = l;
CHIP_REGS_MCHTMR->MTIME.h = h;
} else {
CHIP_REGS_MCHTMR->MTIME.l = 0;
CHIP_REGS_MCHTMR->MTIME.h = h;
CHIP_REGS_MCHTMR->MTIME.l = l;
}
}
t_lclock_ticks lclock_get_ticks(void) {
return CHIP_REGS_MCHTMR->MTIME.val64;
}

View File

@ -0,0 +1,11 @@
#ifndef LCLOCK_ARCH_H
#define LCLOCK_ARCH_H
#include "chip.h"
typedef uint64_t t_lclock_ticks;
#define LCLOCK_TICKS_PER_SECOND CHIP_CLK_MCHTMR_FREQ
#endif // LCLOCK_ARCH_H

View File

@ -0,0 +1,18 @@
#include "chip.h"
#include "lclock_arch.h"
void lclock_init_val(t_lclock_ticks init_val) {
CHIP_REGS_STK->CTLR = 0;
CHIP_REGS_STK->CNTH = (init_val >> 32) & 0xFFFFFFFF;
CHIP_REGS_STK->CNTL = init_val & 0xFFFFFFFF;
CHIP_REGS_STK->CTLR |= CHIP_REGFLD_STK_CTLR_STE;
}
t_lclock_ticks lclock_get_ticks(void) {
uint32_t h = CHIP_REGS_STK->CNTH;
uint32_t l = CHIP_REGS_STK->CNTL;
uint32_t h2 = CHIP_REGS_STK->CNTH;
return ((uint64_t)h << 32) | l;
}

View File

@ -0,0 +1,11 @@
#ifndef LCLOCK_ARCH_H
#define LCLOCK_ARCH_H
#include "chip.h"
typedef uint64_t t_lclock_ticks;
#define LCLOCK_TICKS_PER_SECOND (CHIP_CLK_SYSTICK_FREQ/8)
#endif // LCLOCK_ARCH_H

View File

@ -0,0 +1,24 @@
/***************************************************************************//**
@ingroup ltimer_win
@file ports/win/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком
в OC Windows через функцию GetTickCount().
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include "lclock.h"
void lclock_init_val(t_lclock_ticks init_val) {
}
char lclock_is_initialized(void) {
return 1;
}
t_lclock_ticks lclock_get_ticks(void) {
return GetTickCount();
}

View File

@ -0,0 +1,30 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_win Порт таймера для Windows
Порт для работы с таймером в ОС Windows. Для получения системного счетчика
использует функцию WinApi GetTickCount().
*****************************************************************************/
/***************************************************************************//**
@ingroup ltimer_win
@file ports/win/lclock_arch.h
Файл содержит определение типов и констант для работы с системным счетчиком
в OC Windows через функцию GetTickCount().
@date 10.06.2011
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include "Windows.h"
/* GetTickCount() возвращает счетчик в миллисекундах */
#define LCLOCK_TICKS_PER_SECOND 1000
/* GetTickCount() возвращает в качестве значения DWORD */
typedef DWORD t_lclock_ticks;
#endif /* LCLOCK_ARCH_H_ */