Dieses Modul enthält alle benötigten hardwarenahen Funktionen. Der Beispielcode ist für einen STM32-Prozessor vorgesehen und die Signallingfunktion wird mit Hilfe der RTOS-APIs realisiert.
Im oberen Teil befinden sich die Initialisierungen und die Arbeitsroutinen für den Timer.
/*M>---------------------------------------------------------------------------
* Project: DALI-Stack HAL
* Description: Abstraction Layer between DALI-low-level driver and uC Timer, Interrupts, etc.
*
* Copyright (c) by mbs GmbH, Krefeld, info@mbs-software.de
* All rights reserved.
--------------------------------------------------------------------------<M*/
#include "app_common.h"
#include "system.h"
#include "dali_ll_hal.h"
TIM_HandleTypeDef htim16;
void Error_Handler(void);
void Tim16BaseMspInitCb(TIM_HandleTypeDef *htim);
void Tim16BaseMspDeInitCb(TIM_HandleTypeDef *htim);
void Tim16init(void);
void dalill_timerInterrupt();
void Tim16init(void)
{
htim16.Instance = TIM16;
htim16.Init.Prescaler = 31;
htim16.Init.CounterMode = TIM_COUNTERMODE_UP;
htim16.Init.Period = 10000;
htim16.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim16.Init.RepetitionCounter = 0;
htim16.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim16) != HAL_OK)
{
Error_Handler();
}
}
/*----------------------------------------------------------------*/
void Tim16BaseMspInitCb(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN TIM16_MspInit 0 */
/* USER CODE END TIM16_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM16_CLK_ENABLE();
/* TIM16 interrupt Init */
HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
}
/*----------------------------------------------------------------*/
void Tim16BaseMspDeInitCb(TIM_HandleTypeDef *htim)
{
__HAL_RCC_TIM16_CLK_DISABLE();
}
/*----------------------------------------------------------------*/
void dalill_initHardware()
{
HAL_TIM_RegisterCallback(&htim16, HAL_TIM_BASE_MSPINIT_CB_ID, Tim16BaseMspInitCb);
HAL_TIM_RegisterCallback(&htim16, HAL_TIM_BASE_MSPDEINIT_CB_ID, Tim16BaseMspDeInitCb);Tim16init();
HAL_TIM_RegisterCallback(&htim16, HAL_TIM_PERIOD_ELAPSED_CB_ID, dalill_timerInterrupt);
}
/*----------------------------------------------------------------*/
// extern dalill_bus_t dalill_bus_lines_g[]; Only used for Multibus !
uint32_t dalill_getCurrentTimerVal(dalill_bus_t* pDalill_bus)
{
return htim16.Instance->CNT;
}
uint32_t dalill_getTimerPeriod(dalill_bus_t* pDalill_bus)
{
return htim16.Init.Period+1;
}
void dalill_startTimer()
{
HAL_TIM_Base_Start_IT(&htim16);
}
void dalill_setTimerPeriod(uint16_t uPeriod,dalill_bus_t* pDalill_bus)
{
__HAL_TIM_SET_AUTORELOAD(&htim16, uPeriod + dalill_getCurrentTimerVal(pDalill_bus) - 1);
}
/*! Set/Read GPIOs of Bus 0 */
uint8_t dalill_getBusState()
{
return HAL_GPIO_ReadPin(DALI_IN_GPIO_Port, DALI_IN_Pin)?0:1;
}
void dalill_setBusStateHigh()
{
HAL_GPIO_WritePin(DALI_OUT_GPIO_Port, DALI_OUT_Pin, GPIO_PIN_RESET);
}
void dalill_setBusStateLow()
{
HAL_GPIO_WritePin(DALI_OUT_GPIO_Port, DALI_OUT_Pin, GPIO_PIN_SET);
}
// Signalling
extern osThreadId_t DALI_ThreadId;
void dalill_signalToThread()
{
osThreadFlagsSet (DALI_ThreadId, DALI_FLAG);
}
// block and release interrupts
void enableIRQ()
{
__enable_irq();
}
void disableIRQ()
{
__disable_irq();
}
Zielhardware
Sollte die Zielhardware keine direkte Möglichkeit zur Verfügung stellen, den aktuellen Timerwert auszulesen und/oder zu verändern oder auch den Timerauslösewert zu setzen, so können die Funktionen dalill_getCurrentTimerVal, dalill_getTimerPeriod und dalill_setTimerPeriod selbst implementiert werden.
TimerInterrupt-Routine
Hierzu muss die TimerInterupt-Routine mindestens alle 10 μs aufgerufen werden und weiterhin, abhängig von einem Zähler, auch die Timerroutine des Low Level Treibers.
Die dazu notwendigen Variablen sind schon in der Struktur dalill_bus_t in dali_ll.h definiert. Das sind die Membervariablen vom Typ uint32_t tick_cnt und tim_period.
GPIO-Manipulation
Die Routinen zur GPIO-Manipulation in diesem Beispiel sind für eine Hardware mit invertierendem Businterface vorgesehen.
Timerfunktionen
Die Timerfunktionen gehen von einem Timer aus, der aufwärts zählt und dessen Periode mit alill_setTimerPeriod verlängert werden kann, auch noch während sie bereits abläuft.
Die Funktion dalill_getCurrentTimerVal geht davon aus, dass der Timercounter kontinuierlich weiter zählt auch wenn die Periode verlängert wird. Bei der Verlängerung wird also kein Timer-Interrupt ausgelöst.
„getTimerPeriod“ liefert den aktuellen Maximalwert des Timers.
Hinweis
Ist dieses Verhalten durch den Timer der Zielhardware so nicht zu erreichen, muss es simuliert werden damit der Low Level Treiber ordnungsgemäß funktioniert.
IRQ-Funktionen
Die Callbacks „enableIRQ“ und „disableIRQ“ dienen dem Blockieren und Freigeben der Prozessorinterrupts. Das ist notwendig damit die Schreib- und Lesevorgänge auf die I/O-Queues im Interrupt atomar sind.
Weil diese Aktion auf jeder Zielhardware anders ist, wurde sie in Callbacks verlegt.
Hinweis
Wird dieser Mechanismus nicht benutzt, muss der Callback mit NULL initialisiert werden.