OCEOS/oceos timed actions/oceos port external timer

From wiki
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();
}