/*---------------------------------------------------------------------------------------------------------*/
/* */
/* Copyright(c) 2009 Nuvoton Technology Corp. All rights reserved. */
/* */
/*---------------------------------------------------------------------------------------------------------*/
#include <stdio.h>
#include "M051Series.h"
#include "LCD_Driver.h"
#define PLLCON_SETTING CLK_PLLCON_50MHz_HXT
#define PLL_CLOCK 50000000
uint32_t g_u32Freq = 0;
uint32_t g_u32DutyCycle = 0;
uint32_t g_u32RisingCnt = 0;
uint32_t g_u32FallingCnt = 0;
char g_strBuf[32] = {0};
void PWMA_IRQHandler(void)
{
uint32_t u32Reg;
u32Reg = PWMA->CCR0;
/* Clear capture interrupt flag */
PWMA->CCR0 |= PWM_CCR0_CAPIF0_Msk;
/* Falling edge */
if(u32Reg & PWM_CCR0_CFLRI0_Msk)
{
g_u32FallingCnt = PWMA->CFLR0;
/* Clear falling event flag */
PWMA->CCR0 |= PWM_CCR0_CFLRI0_Msk;
}
/* Rising edge */
if(u32Reg & PWM_CCR0_CRLRI0_Msk)
{
g_u32RisingCnt = PWMA->CRLR0;
/* Clear rising event flag */
PWMA->CCR0 |= PWM_CCR0_CRLRI0_Msk;
}
/* Clear PWM0 interrupt flag */
PWMA->PIIR = PWM_PIIR_PWMIF0_Msk;
}
void SYS_Init(void)
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init System Clock */
/*---------------------------------------------------------------------------------------------------------*/
/* Enable Internal RC clock */
CLK->PWRCON |= CLK_PWRCON_OSC22M_EN_Msk;
/* Waiting for IRC22M clock ready */
while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_OSC22M_STB_Msk));
/* Switch HCLK clock source to internal RC */
CLK->CLKSEL0 &= ~CLK_CLKSEL0_HCLK_S_Msk;
CLK->CLKSEL0 |= CLK_CLKSEL0_HCLK_S_HIRC;
/* Set PLL to power down mode and PLL_STB bit in CLKSTATUS register will be cleared by hardware.*/
CLK->PLLCON |= CLK_PLLCON_PD_Msk;
/* Enable external 12MHz XTAL */
CLK->PWRCON |= CLK_PWRCON_XTL12M_EN_Msk;
/* Enable PLL and Set PLL frequency */
CLK->PLLCON = PLLCON_SETTING;
/* Waiting for clock ready */
while(!(CLK->CLKSTATUS & (CLK_CLKSTATUS_PLL_STB_Msk | CLK_CLKSTATUS_XTL12M_STB_Msk)));
/* Switch HCLK clock source to PLL, STCLK to HCLK/2 */
CLK->CLKSEL0 = CLK_CLKSEL0_STCLK_S_HCLK_DIV2 | CLK_CLKSEL0_HCLK_S_PLL;
/* Enable IP clock */
CLK->APBCLK = CLK_APBCLK_UART0_EN_Msk | CLK_APBCLK_SPI0_EN_Msk |
CLK_APBCLK_PWM01_EN_Msk | CLK_APBCLK_ADC_EN_Msk;
/* IP clock source */
CLK->CLKSEL1 = CLK_CLKSEL1_UART_S_PLL | CLK_CLKSEL1_PWM01_S_HCLK;
/* Update System Core Clock */
/* User can use SystemCoreClockUpdate() to calculate PllClock, SystemCoreClock and CycylesPerUs automatically. */
//SystemCoreClockUpdate();
PllClock = PLL_CLOCK; // PLL
SystemCoreClock = PLL_CLOCK / 1; // HCLK
CyclesPerUs = PLL_CLOCK / 1000000; // For SYS_SysTickDelay()
/*---------------------------------------------------------------------------------------------------------*/
/* Init I/O Multi-function */
/*---------------------------------------------------------------------------------------------------------*/
/* Set P3 multi-function pins for UART0 RXD and TXD */
SYS->P3_MFP = SYS_MFP_P30_RXD0 | SYS_MFP_P31_TXD0;
/* Set P1.4, P1.5, P1.6, P1.7 for SPI0 to driver LCD */
SYS->P1_MFP = SYS_MFP_P14_SPISS0 | SYS_MFP_P15_MOSI_0 | SYS_MFP_P16_MISO_0 | SYS_MFP_P17_SPICLK0;
/* Set P2.0 => PWM0, P2.1 => PWM1 */
SYS->P2_MFP = SYS_MFP_P20_PWM0 | SYS_MFP_P21_PWM1;
}
void UART0_Init(void)
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init UART */
/*---------------------------------------------------------------------------------------------------------*/
UART0->BAUD = UART_BAUD_MODE2 | UART_BAUD_MODE2_DIVIDER(__HXT, 115200);
UART0->LCR = UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1;
}
void PWMA_Init(void)
{
/* PWM Timer0: clk = HCLK / 2 / 1, Freq = clk / 65536, Max cycles = 65536 */
/* PWM Timer1: clk = HCLK / 2 / 16, Freq = clk / 1000, duty cycle = 200/1000 % */
PWM_SET_PRESCALER(PWMA, PWM_CH1, 1);
PWM_SET_DIVIDER(PWMA, PWM_CH0, PWM_CLK_DIV_1);
PWM_SET_DIVIDER(PWMA, PWM_CH1, PWM_CLK_DIV_16);
/* Enable PWM0,1 counter. We must set PWM mode before setting CNR, CMR. */
PWMA->PCR = PWM_PCR_CH1EN_Msk | PWM_PCR_CH1MOD_Msk |
PWM_PCR_CH0EN_Msk | PWM_PCR_CH0MOD_Msk;
/* Enable PWM0 as input capture mode */
PWMA->CCR0 = PWM_CCR0_CFLRI0_Msk | PWM_CCR0_CRLRI0_Msk | PWM_CCR0_CAPCH0EN_Msk |
PWM_CCR0_CFL_IE0_Msk | PWM_CCR0_CRL_IE0_Msk;
PWMA->CNR0 = 0xffff;
PWMA->CMR0 = 0;
PWMA->CNR1 = 1000 - 1;
PWMA->CMR1 = 200 - 1;
/* Enable Interrupt */
PWMA->PIER = PWM_PIER_PWMIE0_Msk;
NVIC_EnableIRQ(PWMA_IRQn);
/* Enable PWM1 Output */
PWMA->POE = PWM_POE_PWM1_Msk;
/* Need to make sure PWM timer0 ready before enable capture */
while(PWMA->PDR0 == 0);
/* Enable PWM0 Capture */
PWMA->CAPENR = 1;
}
/*----------------------------------------------------------------------------
MAIN function
----------------------------------------------------------------------------*/
int32_t main(void)
{
/* Unlock protected registers */
SYS_UnlockReg();
/* Init system, IP clock and multi-function I/O */
SYS_Init();
/* Lock protected registers */
SYS_LockReg();
/* Init UART0 for printf */
UART0_Init();
/* Init SPI0 and LCD */
LCD_Init();
LCD_EnableBackLight();
LCD_ClearScreen();
LCD_Print(0, "IN:P2.0(400~100kHz)");
LCD_Print(1, "OUT:P2.1(1500Hz)");
/* Init PWMA channel 0 to be capture mode and channel 1 to be output mode */
PWMA_Init();
/*
PWM timer 0 is set as input capture function.
PWM0 will down-count from 0xFFFF. When capture rising and falling event, the count value will
be recorded by g_u32RisingCnt, g_u32FallingCnt in ISR.
We can use g_u32RisingCnt and g_u32FallingCnt to calculate input frequency and duty cycle.
PWM timer 1 is set as PWM output.
*/
while(1)
{
uint32_t u32Tmp1, u32Tmp2;
char strClearFreqVal[15] = "Freq: ";
char strClearDutyVal[15] = "Duty: ";
u32Tmp1 = (0xFFFF - g_u32RisingCnt); // low interval
u32Tmp2 = (0xFFFF - g_u32FallingCnt); // high interval
g_u32Freq = u32Tmp1 + u32Tmp2;
if(g_u32Freq)
g_u32Freq = 24000000 / g_u32Freq;
if(u32Tmp2 + u32Tmp2)
g_u32DutyCycle = u32Tmp2 * 200 / (u32Tmp1 + u32Tmp2) + 1 >> 1;
sprintf(g_strBuf, "Freq:%dHz", g_u32Freq);
LCD_Print(2, strClearFreqVal);
LCD_Print(2, g_strBuf);
sprintf(g_strBuf, "Duty:%d ", g_u32DutyCycle);
LCD_Print(3, strClearDutyVal);
g_strBuf[8] = '%';
LCD_Print(3, g_strBuf);
}
}
|