/**
  ******************************************************************************
  * @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 CLOCKSWITCH_TIMEOUT_VALUE  ((uint32_t)5000) /* 5 s    */

#define ERROR_CLKSWITCH_TIMEOUT    0x02

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

/* Private user code ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static __INLINE void APP_SystemClockConfig(void);
static __INLINE void APP_GPIOConfig_MCO(void);
static __INLINE void APP_GPIOConfig_LED(void);
static __INLINE void APP_GPIOConfig_Button(void);
static __INLINE void APP_Delay(int32_t Delay);

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

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

  APP_GPIOConfig_Button(); /* Button config */
  
  APP_GPIOConfig_LED(); /* LED config */
  
  /* Wait for Button pressed PA0 */ 
  while((GPIOA->IDR & 0x1) == 0)
  {
  }
  
  APP_SystemClockConfig();
  
  if (error != 0)
  {
    while(1) /* endless loop */
    {
    }
  }
  
  SysTick_Config(16000); /* 1ms config */
  
  APP_GPIOConfig_MCO();
  RCC->CFGR = ((RCC->CFGR & (~RCC_CFGR_MCOSEL)) | RCC_CFGR_MCOSEL_0);/* Select system clock to be output on the MCO without prescaler */
  
  while (1) /* Infinite loop */
  {   
    APP_Delay(1000); /* Delay 1s */
    GPIOA->ODR ^= (1<<1); /* Toggle green led on PA1 */ 
  }
}

/**
  * @brief  This function provides accurate delay (in milliseconds)
  * @param  Delay specifies the delay time length, in milliseconds.
  * @retval None
  */
static __INLINE void APP_Delay(int32_t Delay)
{
  uint32_t tickstart = 0;
  tickstart = Tick;
  if (Delay  < 0xffffffff)
  {
    Delay ++;
  }
  while ((Tick - tickstart ) < (Delay)) 
  {

  }
}

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

  RCC->CR |= RCC_CR_HSEON; /* (1) */
  
  RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_HPRE));  /* (2) */

  RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_SW)) | RCC_CFGR_SW_HSE; /* (3) */
  tickstart = Tick;
  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSE) /* (4) */
  {
    if ((Tick - tickstart ) > CLOCKSWITCH_TIMEOUT_VALUE)
    {
      error = ERROR_CLKSWITCH_TIMEOUT; /* Report an error */
      return;
    }
  }

  RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_PPRE));  /* (5) */
}

/**
  * @brief   This function enables the peripheral clocks on GPIO port A,
  *         configures GPIO PA1 in output mode for the Green LED pin
  * @param   None
  * @retval  None
  */
static __INLINE void APP_GPIOConfig_LED(void)
{  
  /* (1) Enable the peripheral clock of GPIOA */
  /* (2) Select output mode (01) on GPIOA pin 1 */
  /* (3) Select push-pull output type on GPIOA pin 1 */
  /* (4) Select low output speed on GPIOA pin 1 */
  RCC->IOPENR |= RCC_IOPENR_GPIOAEN ; /* (1) */  
  GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE1)) 
               | (GPIO_MODER_MODE1_0); /* (2) */  
  /* GPIOA->OTYPER &= ~(GPIO_OTYPER_OT1); */  /* (3) */
  /* GPIOA->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED1); */  /* (4) */
}

/**
  * @brief   This function enables the peripheral clocks on GPIO port A,
  *         configures GPIO PA0 in input mode for the Button
  * @param   None
  * @retval  None
  */
static __INLINE void APP_GPIOConfig_Button(void)
{  
  /* (1) Enable the peripheral clock of GPIOA */
  /* (2) Select input mode (00) on GPIOA pin 0 */
  /* (3) Select no pull on GPIOA pin 0 */
  RCC->IOPENR |= RCC_IOPENR_GPIOAEN ; /* (1) */  
  GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE0)); /* (2) */ 
  /* GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD0); */  /* (3) */ 
}

/**
  * @brief   This function enables the peripheral clocks on GPIO port A,
  *         configures GPIO PA7 as Alternate function and output very high speed.
  * @param   None
  * @retval  None
  */
static __INLINE void APP_GPIOConfig_MCO(void)
{  
  /* (1) Enable the peripheral clock of GPIOA */
  /* (2) Select alternate function mode(10) on GPIOA pin 7 */
  /* (3) Select AF4 for GPIOA pin 7 */
  /* (4) Select push-pull output type on GPIOA pin 7 */
  /* (5) Select very high speed on GPIOA pin 7 */
  
  RCC->IOPENR |= RCC_IOPENR_GPIOAEN ; /* (1) */  
  GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE7)) | (GPIO_MODER_MODE7_1); /* (2) */
  GPIOA->AFR = ((GPIOA->AFR & (~GPIO_AFR_AFSEL7)) | GPIO_AFR_AFSEL7_2); /* (3) */
  /* GPIOA->OTYPER &= ~(GPIO_OTYPER_OT1); */  /* (4) */
  GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED7; /* (5) */
}
/******************************************************************************/
/*            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 function handles PPP interrupt request.
  * @param  None
  * @retval None
  */
/*void PPP_IRQHandler(void)
{
}*/

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