/* Copyright Statement:
 *
 * This software/firmware and related documentation ("AutoChips Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to AutoChips Inc. and/or its licensors. Without
 * the prior written permission of AutoChips inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of AutoChips Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * AutoChips Inc. (C) 2023. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("AUTOCHIPS SOFTWARE")
 * RECEIVED FROM AUTOCHIPS AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. AUTOCHIPS EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES AUTOCHIPS PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE AUTOCHIPS SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN AUTOCHIPS
 * SOFTWARE. AUTOCHIPS SHALL ALSO NOT BE RESPONSIBLE FOR ANY AUTOCHIPS SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND AUTOCHIPS'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE AUTOCHIPS SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT AUTOCHIPS'S OPTION, TO REVISE OR REPLACE THE
 * AUTOCHIPS SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO AUTOCHIPS FOR SUCH AUTOCHIPS SOFTWARE AT ISSUE.
 */
/******************************************************************************
 * @version: V1.0.0
 ******************************************************************************/

/*!
 * @file timer_pwm.c
 *
 * @brief timer work on TIMER mode.
 * This program outputs PWM through timer;
 * The clock source of the timer is the bus clock, it's period is 10us;
 * The period of PWM is 1ms (100*10us);
 * Every 100ms, change the duty cycle of PWM;
 * Realize the function of the breathing light by modifying the duty cycle;
 * PWM output on PC7, control a green LED.
 *
 */

/* ===========================================  Includes  =========================================== */
#include <stdint.h>
#include <string.h>

#include "ac7803x_debugout.h"
#include "ac780x_gpio.h"
#include "ac780x_timer.h"
#include "ac780x_timer_reg.h"

#include "timer_pwm.h"
#include "gpio.h"

/* ============================================  Define  ============================================ */
#define TIMER_CLK_SR            (TIMER_CLKSR_APB)          /* timer clock source APB */
#define CNT_FREQ                ((APB_BUS_FREQ/100000)-1)  /* timer ch0's period 10us*/

#define PWM_CYCLE               (100)    /* PWM period time, 100*cnt, in this example, cnt = 10us*/
#define PWM_DUTY_CHANGE_CYCLE   (10000)  /* Change the duty cycle every 10000*cnt, 100ms */

#define PWM_SCHEDULE_SIZE       (24)     /* pwm schedule table size */

/* ===========================================  Typedef  ============================================ */

/* ==========================================  Variables  =========================================== */
static uint8_t g_pwmScheduleTbl[PWM_SCHEDULE_SIZE] = 
    {1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 7, 8, 10, 12, 15, 18, 21, 21, 24};  /* pwm schedule table */
static uint8_t g_pwmDuty = 1;  /* PWM duty cycle */

/* ====================================  Functions declaration  ===================================== */

/* ======================================  Functions define  ======================================== */
/*!
 * @brief Timer channel0 timeout callback function.
 *
 * @param device: the Timer channel0.
 * @param wpara: the value of TIMER_SR(Timer interrupt flag register).
 * @param lpara: unused.
 */
void TIMER_CH0CallBack(void* device, uint32_t wpara, uint32_t lpara)
{
    static uint32_t cnt = 0;    /* 10us counter */
    static uint32_t dir = 1;    /* 1: duty up, 0: duty down */
    static int idx = 0;    /* the index of PWM duty */

    cnt++;                      /* Update the counter */

    if (0 == (cnt % PWM_CYCLE)) /* Set GPIO HIGH at the beginning of the duty */
    {
        LED1_ON;
    }

    if (g_pwmDuty == (cnt % PWM_CYCLE)) /* Set GPIO LOW at the end of the duty */
    {
        LED1_OFF;
    }

    if (0 == (cnt % PWM_DUTY_CHANGE_CYCLE)) /* Update the duty cycle, when the time arrives */
    {
        cnt = 0;
        g_pwmDuty = g_pwmScheduleTbl[idx];  /* refresh PWM duty */
        if (1 == dir)  // duty up
        {
            idx++;
            if(idx == PWM_SCHEDULE_SIZE)
            {
                idx = PWM_SCHEDULE_SIZE - 1;
                dir = 0;  /* change to duty down */
            }
        }
        else  // duty down
        {
            idx--;
            if(idx == -1)
            {
                idx = 0;
                dir = 1;  /* change to duty up */
            }
        }
    }
}

/*!
 * @brief Timer init.
 *
 */
void Timer_Init(void)
{
    TIMER_ConfigType config;
    memset(&config, 0U, sizeof(config));

    /* Initialization, complete before operating other registers, otherwise a hardfault error occurs */
    TIMER_Init(TIMER_CLK_SR); /* timer sel：APB_BUS_FREQ */

    // channel 0, T = 10us
    config.timeMode    = TIMER_WORKMODE_TIMER;  /* timer mode */
    config.chainModeEn = DISABLE;               /* The chain mode of channel 0 cannot be enabled, otherwise
                                                   it has no clock source and can't count  */
    config.bypEn       = ENABLE;                /* bypass the prescaler */
    config.interruptEn = ENABLE;                /* enable the channel interrupt */
    config.periodValue = CNT_FREQ;              /* period 10us */
    config.callback    = TIMER_CH0CallBack;     /* set callback */
    config.cvalReadSel = TIMER_BCLK_FCLK_1;     /* BUSCLK/FUNCTION CLK == 1 */

    TIMER_InitChannel(TIMER_CHANNEL0, &config); /* TIMER_InitChannel will not change the para config */
}

/* =============================================  EOF  ============================================== */
