OCEOS/oceos timed actions/oceos port external timer
Jump to navigation
Jump to search
/*
* ARM Cortex-M7 SAMV71Q21 Timer Example.
* oceos_port_external_timer.c
*
* Created on: 24 march 2022
* Author: Alex
*
*/
#include <stddef.h>
#include "sam.h"
#include "oceos.h"
#define EXTERNAL_TIMER_INDEX 0
#define EXTERNAL_TIMER_PRIORITY 1
#define EXTERNAL_TIMER_COUNER_MSK 0xFFFF
#define ENABLE_WAVE_MODE (0x1 << TC_CMR_WAVE_Pos)
#define TC_CMR_WAVE_SEL_Pos 13
#define SET_WAVE_SELECT (~(0x3 << TC_CMR_WAVE_SEL_Pos)) //00
#define TC_CMR_CPCSTOP_Pos 6
#define TC_CMR_CPCSTOP (0x1 << TC_CMR_CPCSTOP_Pos)
extern const unsigned int __oceos_bsp_sysfreq;
static Tc *timer_regs;
static TcChannel *tc;
/**
* Used in OCEOS internally, max counter value in microseconds
*/
extern unsigned int OCEOS_MAX_TIMER_COUNTER_VALUE;
volatile float base_scaler = 0.0f;
/**
* User has to implement this function to initialize external timer
* to be used with timed actions,semaphores and data qs.
*/
enum DIRECTIVE_STATUS oceos_external_timer_init() {
// Remove write protect from PMC
U32_t pmc_was_enabled = 0U;
if (0 != (PMC->PMC_WPMR & PMC_WPMR_WPEN)) {
PMC->PMC_WPMR = PMC_WPMR_WPKEY_PASSWD;
pmc_was_enabled = 1U;
}
// Enable Clock
PMC->PMC_PCER0 |= PMC_PCER0_PID23;
// Enable write protect
if (1U == pmc_was_enabled) {
PMC->PMC_WPMR = PMC_WPMR_WPKEY_PASSWD | PMC_WPMR_WPEN;
}
timer_regs = (Tc *)TC0;
tc = &(timer_regs->TC_CHANNEL[EXTERNAL_TIMER_INDEX]);
// Remove Timer Unit protection
U32_t tc_was_protected = 0U;
if (0U != (timer_regs->TC_WPMR & TC_WPMR_WPEN)) {
timer_regs->TC_WPMR = TC_WPMR_WPKEY_PASSWD;
tc_was_protected = 1U;
}
// Enable Wave Mode
tc->TC_CMR |= ENABLE_WAVE_MODE;
// Set WAVESEL to 00
tc->TC_CMR &= (U32_t)SET_WAVE_SELECT;
// Set TC_CMR_CPCSTOP and Clock input
tc->TC_CMR |= (TC_CMR_CPCSTOP | TC_CMR_TCCLKS_TIMER_CLOCK2_Val); // MCK/8
// Set Block Clock
timer_regs->TC_BMR &= (U32_t)(~(1 << EXTERNAL_TIMER_INDEX));
// Enable Timer interrupt (RC Compare)
tc->TC_IER = TC_IER_CPCS;
// Enable Timer Interrupt in NVIC
NVIC_EnableIRQ(TC0_IRQn);
// Set Priority for interrupt number, should not be zero as this is the highest priority
// and used by SysTick to update time counter
NVIC_SetPriority(TC0_IRQn, EXTERNAL_TIMER_PRIORITY);
//TC_CMR_TCCLKS_TIMER_CLOCK1 => MCK / 8
base_scaler = (float)(__oceos_bsp_sysfreq / 8.0f) / 1000000.0f;
// Calculate max reload time in ns
// Used in OCEOS internally
OCEOS_MAX_TIMER_COUNTER_VALUE = EXTERNAL_TIMER_COUNER_MSK / base_scaler;
// Enable clock
tc->TC_CCR = TC_CCR_CLKEN;
// Re-enable Timer Protection if was protected
if (1U == tc_was_protected) {
timer_regs->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN;
}
return SUCCESSFUL;
}
/**
* User has to implement this function to start external timer
* to be used with timed actions,semaphores and data qs.
*/
enum DIRECTIVE_STATUS oceos_external_timer_start(U32_t act_time) {
if (NULL == timer_regs || NULL == tc) {
oceos_log_add_entry(LOG_TIMED_ACTION_NOT_INIT, 0x1);
return NOT_CONFIGURED;
}
// Remove protection
U32_t tc_was_protected = 0U;
if (0 != (timer_regs->TC_WPMR & TC_WPMR_WPEN)) {
timer_regs->TC_WPMR = TC_WPMR_WPKEY_PASSWD;
tc_was_protected = 1U;
}
// Set Register C for compare
tc->TC_RC = base_scaler * act_time;
// Enable Protection
if (1U == tc_was_protected) {
timer_regs->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN;
}
// Enable clock
tc->TC_CCR = TC_CCR_CLKEN;
if (0 == (tc->TC_SR & TC_SR_CLKSTA)) {// check if set
oceos_log_add_entry(LOG_TIMED_ACTION_NOT_INIT, 0x2);
return NOT_CONFIGURED;
}
// Start clock
tc->TC_CCR = TC_CCR_SWTRG;
return SUCCESSFUL;
}
/**
* User has to implement this function to stop external timer
* to be used with timed actions,semaphores and data qs.
*/
enum DIRECTIVE_STATUS oceos_external_timer_stop() {
if (NULL == tc) {
oceos_log_add_entry(LOG_TIMED_ACTION_NOT_INIT, 0x1);
return NOT_CONFIGURED;
}
tc->TC_CCR = TC_CCR_CLKDIS;
if (0 != (tc->TC_SR & TC_SR_CLKSTA)) {
oceos_log_add_entry(LOG_TIMED_ACTION_TIMER_STOP_FAIL, 0x2);
return FAILED_TO_SET_REGISTER;
}
return SUCCESSFUL;
}
/**
* IRQ handler for timed action timer.
* This function label should be present in Vector table
*/
void oceos_TC0_IRQHandler() {
// Clear timer interrupt Pending bit in register
tc->TC_SR;
// Call Timed action
__oceos_timed_action_do();
}