/**
  ******************************************************************************
  * @file    main.c
  * @author  MCU Application Team
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 Puya Semiconductor Co.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by Puya under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "ms32c0xx.h"

/* Private define ------------------------------------------------------------*/
#define HSI_TIMEOUT_VALUE          ((uint32_t)100)  /* 100 ms */
#define CLOCKSWITCH_TIMEOUT_VALUE  ((uint32_t)5000) /* 5 s    */

#define ERROR_HSI_TIMEOUT          0x01
#define ERROR_CLKSWITCH_TIMEOUT    0x02

/* Private variables ---------------------------------------------------------*/
static __IO uint32_t Tick;
volatile uint16_t error = 0; 

/* Frequency of the signal applied on TI1 based on 2MHz clock */
uint32_t Frequency = 0;
/* High signal time based on 2MHz clock*/
uint16_t DutyCycle = 0; 

/* Private user code ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static __INLINE void APP_SystemClockConfig(void);
static __INLINE void APP_PWMConfig(void);

/**
  * @brief  Main program.
  * @param  None
  * @retval int
  */
int main(void)
{
  SysTick_Config(8000); /* 1ms config */
  APP_SystemClockConfig();

  RCC->APBENR1 |= (RCC_APBENR1_PWREN);  
  RCC->APBENR2 |= (RCC_APBENR2_SYSCFGEN);

  APP_PWMConfig();  

  while (1) /* Infinite loop */
  {   

  }
}

/**
  * @brief   This function configures the TIM1 as PWM mode 1 and center-aligned
  *         and enables the peripheral clock on TIM1 and on GPIOB.
  *         It configures GPIO PA5 as Alternate function for TIM1_CH1
  *         To use another timer, channel or GPIO, the RCC and GPIO configuration 
  *         must be adapted according to the datasheet.
  *         In case of other timer, the interrupt sub-routine must also be renamed
  *         with the right handler and the NVIC configured correctly.
  * @param   None
  * @retval  None
  */
static __INLINE void APP_PWMConfig(void)
{
  /* Configure NVIC for TIM1 */
  /* (1) Enable Interrupt on TIM1 */
  /* (2) Set priority for TIM1*/
  NVIC_EnableIRQ(TIM1_CC_IRQn); /* (1) */
  NVIC_SetPriority(TIM1_CC_IRQn,0); /* (2) */
  
  /* (1) Enable the peripheral clock of Timer 1 */
  /* (2) Enable the peripheral clock of GPIOA */
  /* (3) Select alternate function mode on GPIOA pin 0 */
  /* (4) Select AF2 on PA5 in AFRL for TIM1_CH1 */
  
  RCC->APBENR2 |= RCC_APBENR2_TIM1EN; /* (1) */
  RCC->IOPENR |= RCC_IOPENR_GPIOAEN; /* (2) */
  GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE5)) \
               | (GPIO_MODER_MODE5_1); /* (3) */  
  GPIOA->AFR = (GPIOA->AFR & ~(GPIO_AFR_AFSEL5)) \
                | (0x2 << (5 * 4 )); /* (4) */
  
  
  /* (1) Select the active input TI1 for TIM1_CCR1 (CC1S = 01), 
         select the active input TI1 for TIM1_CCR2 (CC2S = 10) */ 
  /* (2) Set prescale(CK_CNT = CK_INT/12) */
  /* (3) Select TI1FP1 as valid trigger input (TS = 101)
         configure the slave mode in reset mode (SMS = 100) */
  /* (4) Enable capture by setting CC1E and CC2E 
         select the rising edge on CC1 and CC1N (CC1P = 0 and CC1NP = 0, reset value),
         select the falling edge on CC2 (CC2P = 1). */
  /* (5) Enable interrupt on Capture/Compare 1 */
  /* (6) Enable counter */  
  
  TIM1->CCMR1 = (TIM1->CCMR1 & ~(TIM_CCMR1_CC1S | TIM_CCMR1_CC2S)) \
               | TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_1; /* (1)*/
  TIM1->PSC = 4 - 1; /* (2) */
  TIM1->SMCR = (TIM1->SMCR & ~(TIM_SMCR_TS | TIM_SMCR_SMS)) \
               | TIM_SMCR_TS_2 | TIM_SMCR_TS_0 | TIM_SMCR_SMS_2; /* (3) */
  TIM1->CCER = (TIM1->CCER & ~(TIM_CCER_CC1P | TIM_CCER_CC1NP | TIM_CCER_CC2P | TIM_CCER_CC2NP)) \
               | TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC2P; /* (4) */  
  TIM1->DIER |= TIM_DIER_CC1IE; /* (5) */
  TIM1->CR1 |= TIM_CR1_CEN; /* (6) */
}

/**
  * @brief  This function configures the system clock @8MHz 
  *         assuming the registers have their reset value before the call.
  *         SYSTEM CLOCK  = HSI DIV1
  *         FLASH LATENCY = 0
  * @param  None
  * @retval None
  */
static __INLINE void APP_SystemClockConfig(void)
{
  uint32_t tickstart = 0;
  /* (1) HSI DIV1 and Enable HSI */
  /* (2) Set HSI 8M and Triming Data */
  /* (3) Wait for HSI ready flag */
  /* (4) Set AHB divider:HCLK = SYSCLK */
  /* (5) Select HSISYS as system clock */
  /* (6) Wait for clock switched on HSI */
  /* (7) Set APB divider:PCLK = HCLK */

  RCC->CR = (RCC->CR &~(RCC_CR_HSIDIV)) | RCC_CR_HSION;                        /* (1) */

  RCC->ICSCR = (RCC->ICSCR & 0xFFFE0000) | (0 << RCC_ICSCR_HSI_FS_CR_Pos) | \
               ((*(uint32_t *)(0x1FFF0080)) & 0xFFFF);                         /* (2) */

  tickstart = Tick;
  while ((RCC->CR & (RCC_CR_HSIRDY)) != (RCC_CR_HSIRDY ))                      /* (3) */
  {
    if ((Tick - tickstart ) > HSI_TIMEOUT_VALUE)
    {
      error = ERROR_HSI_TIMEOUT; /* Report an error */
      return;
    }
  }

  RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_HPRE));                                  /* (4) */

  RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_SW)) | RCC_CFGR_SW_HSISYS;               /* (5) */
  tickstart = Tick;
  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSISYS)                    /* (6) */
  {
    if ((Tick - tickstart ) > CLOCKSWITCH_TIMEOUT_VALUE)
    {
      error = ERROR_CLKSWITCH_TIMEOUT; /* Report an error */
      return;
    }
  }
 
  RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_PPRE));                                  /* (7) */
}

/******************************************************************************/
/*            Cortex-M0 Plus Processor Exceptions Handlers                    */
/******************************************************************************/

/**
  * @brief  This function handles NMI exception.
  * @param  None
  * @retval None
  */
void NMI_Handler(void)
{
}

/**
  * @brief  This function handles Hard Fault exception.
  * @param  None
  * @retval None
  */
void HardFault_Handler(void)
{
  /* Go to infinite loop when Hard Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles SVCall exception.
  * @param  None
  * @retval None
  */
void SVC_Handler(void)
{
}

/**
  * @brief  This function handles PendSVC exception.
  * @param  None
  * @retval None
  */
void PendSV_Handler(void)
{
}


/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{
  Tick++;
}

/******************************************************************************/
/*                 MS32C001B Peripherals Interrupt Handlers                   */
/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
/*  available peripheral interrupt handler's name please refer to the startup */
/*  file (startup_ms32c001bxx.s).                                             */
/******************************************************************************/

/**
  * @brief   This interrupt subroutine uses the contents of
  *          CCR1 and CCR2 to calculate frequency and dutycycle
  *         when available.
  * @param   None
  * @retval  None
  */
void TIM1_CC_IRQHandler(void)
{
  if ((TIM1->SR & (TIM_SR_CC1IF | TIM_SR_CC1OF) ) == TIM_SR_CC1IF)
  {
    if (TIM1->CCR1 != 0)
    {
      Frequency = 8000000 / (TIM1->CCR1 + 1) / (TIM1->PSC + 1);
      DutyCycle = ((TIM1->CCR2 + 1) * 100) / (TIM1->CCR1 + 1);
      error = 0;
    }
  }  
  else
  {
    TIM1->SR = ~(TIM_SR_CC1OF | TIM_SR_CC1IF); /* Clear the flags */
  }
}

/************************ (C) COPYRIGHT Puya *****END OF FILE******************/
