/**************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url] main.c
* [url=home.php?mod=space&uid=895143]@version[/url] V1.00
* $Revision: 1 $
* $Date: 19/07/24 8:14p $
* [url=home.php?mod=space&uid=247401]@brief[/url] Use Mini51 PWM Channel 0 (P2.2) to control 4-wire PWM fan speed
* and use Timer 0 external capture pin (P3.2) to detect fan speed
* in RPM
*
* @note
* Copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
******************************************************************************/
#include <stdio.h>
#include "Mini51Series.h"
/*---------------------------------------------------------------------------*/
/* Define */
/*---------------------------------------------------------------------------*/
#define Fan_Pole 4
/*---------------------------------------------------------------------------*/
/* Global variables */
/*---------------------------------------------------------------------------*/
volatile uint8_t g_u8DetectFlag;
uint8_t g_u8PWMDuty;
/*---------------------------------------------------------------------------*/
/* Functions */
/*---------------------------------------------------------------------------*/
void SYS_Init(void);
void UART_Init(void);
void TMR0_Init(void);
void PWM_Init(void);
void Delay_mS(uint32_t m_second);
void TMR0_IRQHandler(void)
{
uint32_t u32_FanRPM;
/* Stop Timer 0 */
TIMER_Stop(TIMER0);
/* Calculate RPM = (Timer 0 Clock Source Frequency / (Fan_Pole * Timer 0 Capture Value)) * 60 */
u32_FanRPM = (22118400 / (Fan_Pole * TIMER_GetCaptureData(TIMER0))) * 60;
printf("%d RPM.\n", u32_FanRPM);
/* Clear Timer 0 Capture interrupt flag */
TIMER_ClearCaptureIntFlag(TIMER0);
/* Set Detect done flag*/
g_u8DetectFlag = 1;
}
void SYS_Init(void)
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init System Clock */
/*---------------------------------------------------------------------------------------------------------*/
/* Enable Internal RC clock */
CLK_EnableXtalRC(CLK_PWRCON_OSC22M_EN_Msk);
/* Waiting for IRC22M clock ready */
CLK_WaitClockReady(CLK_CLKSTATUS_OSC22M_STB_Msk);
/* Switch HCLK clock source to Internal RC and HCLK source divide 1 */
CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HIRC, CLK_CLKDIV_HCLK(1));
/* Update System Core Clock */
/* User can use SystemCoreClockUpdate() to calculate SystemCoreClock and CycylesPerUs automatically. */
SystemCoreClockUpdate();
/* Enable UART module clock */
CLK_EnableModuleClock(UART_MODULE);
/* Enable Timer 0 module clock */
CLK_EnableModuleClock(TMR0_MODULE);
/* Enable Timer 1 module clock */
CLK_EnableModuleClock(TMR1_MODULE);
/* Enable PWM module clock */
CLK_EnableModuleClock(PWM01_MODULE);
/* Select UART module clock source */
CLK_SetModuleClock(UART_MODULE, CLK_CLKSEL1_UART_S_HIRC, CLK_CLKDIV_UART(1));
/* Select Timer 0 module clock source */
CLK_SetModuleClock(TMR0_MODULE, CLK_CLKSEL1_TMR0_S_HIRC, 0);
/* Select Timer 1 module clock source */
CLK_SetModuleClock(TMR1_MODULE, CLK_CLKSEL1_TMR1_S_HIRC, 0);
/* Select PWM module clock source */
CLK_SetModuleClock(PWM01_MODULE, CLK_CLKSEL1_PWM01_S_HCLK, 0);
/*---------------------------------------------------------------------------------------------------------*/
/* Init I/O Multi-function */
/*---------------------------------------------------------------------------------------------------------*/
/* Set P1 multi-function pins for UART RXD, TXD */
SYS->P1_MFP = (SYS->P1_MFP & ~(SYS_MFP_P12_Msk | SYS_MFP_P13_Msk)) | (SYS_MFP_P12_RXD | SYS_MFP_P13_TXD);
/* Set P3 multi function pin for Timer 0 capture pin */
SYS->P3_MFP = (SYS->P3_MFP & ~SYS_MFP_P32_Msk) | SYS_MFP_P32_T0EX;
/* Set P2 multi function pin for PWM Channel 0 pin */
SYS->P2_MFP = (SYS->P2_MFP & ~SYS_MFP_P22_Msk) | SYS_MFP_P22_PWM0;
}
void UART_Init(void)
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init UART */
/*---------------------------------------------------------------------------------------------------------*/
/* Reset IP */
SYS_ResetModule(UART_RST);
/* Configure UART and set UART Baudrate */
UART_Open(UART, 115200);
}
void TMR0_Init(void)
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init Timer 0 */
/*---------------------------------------------------------------------------------------------------------*/
/* Reset IP */
SYS_ResetModule(TMR0_RST);
/* Give a dummy target frequency here. Will over write capture resolution with macro */
TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 1000000);
/* Update prescale to set proper resolution */
TIMER_SET_PRESCALE_VALUE(TIMER0, 0);
/* Set compare value as large as possible, so don't need to worry about counter overrun too frequently */
TIMER_SET_CMP_VALUE(TIMER0, 0xFFFFFF);
/* Configure Timer 0 trigger counting mode and level change trigger.
The high to low transition on Timer 0 external capture pin is detected to reset TDR as 0
and then starts counting, while low to high transition stops counting. */
TIMER_EnableCapture(TIMER0, TIMER_CAPTURE_TRIGGER_COUNTING_MODE, TIMER_CAPTURE_FALLING_THEN_RISING_EDGE);
/* Enable T0EX debounce function */
TIMER0->TEXCON |= TIMER_TEXCON_TEXDB_Msk;
/* Enable timer interrupt */
TIMER_EnableCaptureInt(TIMER0);
NVIC_EnableIRQ(TMR0_IRQn);
}
void PWM_Init(void)
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init PWM Channel 0 */
/*---------------------------------------------------------------------------------------------------------*/
/* Reset IP */
SYS_ResetModule(PWM_RST);
/* Set PWM Channel 0 frequency to 25 kHz and initial duty 100% */
PWM_ConfigOutputChannel(PWM, 0, 25000, 100);
/* Enable PWM Channel 0 output */
PWM_EnableOutput(PWM, BIT0);
}
void Delay_mS(uint32_t m_second)
{
uint32_t i;
for (i = 0; i < m_second; i++)
{
TIMER_Delay(TIMER1, 1000);
}
}
int main(void)
{
uint8_t u8Action;
/* Unlock protected registers */
SYS_UnlockReg();
/* Init System, IP clock and multi-function I/O */
SYS_Init();
/* Lock protected registers */
SYS_LockReg();
/* Init UART for printf */
UART_Init();
/* Init Timer 0 */
TMR0_Init();
/* Init PWM Channel 0 */
PWM_Init();
printf("\n\nCPU [url=home.php?mod=space&uid=72445]@[/url] %d Hz\n", SystemCoreClock);
printf("+-----------------------------------------------------------------+\n");
printf("| 4-wire PWM Fan Control Sample Code |\n");
printf("| Use PWM Channel 0 to control fan speed |\n");
printf("| and use Timer 0 Capture mode to detect fan speed in RPM. |\n");
printf("| Please connect PWM Channel 0 (P2.2) to fan control pin |\n");
printf("| and connect Timer 0 external capture pin (P3.2) to fan |\n");
printf("| sense pin. |\n");
printf("+-----------------------------------------------------------------+\n");
/* Test maximum fan speed */
/* Start PWM Channel 0 */
PWM_Start(PWM, BIT0);
/* Wait 3 seconds */
Delay_mS(3000);
/* Start Timer 0 to detect the time which fan takes when rotating one round */
g_u8DetectFlag = 0;
printf("The maximum fan speed is ");
TIMER_Start(TIMER0);
while (!g_u8DetectFlag);
/* Test maximum fan speed */
/* Force PWM Channel 0 output low */
PWM->PHCHG = PWM->PHCHGNXT & ~(PWM_PHCHGNXT_PWM0_Msk | PWM_PHCHGNXT_D0_Msk);
/* Wait 3 seconds */
Delay_mS(3000);
/* Start Timer 0 to detect the time which fan takes when rotating one round */
g_u8DetectFlag = 0;
printf("The mimimum fan speed is ");
TIMER_Start(TIMER0);
while (!g_u8DetectFlag);
/* Current PWM duty */
g_u8PWMDuty = 60;
while (1)
{
printf("\n\nCurrent PWM duty is %d%%, please enter your action.\n", g_u8PWMDuty);
printf("(1: Increase 10%%; 2: Increase 1%%; 3: Decrease 10%%; 4: Decrease 1%%)\n");
u8Action = getchar();
printf("%c\n", u8Action);
switch (u8Action)
{
case '1':
{
/* Increase PWM duty 10% */
(g_u8PWMDuty > 90) ? (g_u8PWMDuty = 100) : (g_u8PWMDuty += 10);
break;
}
case '2':
{
/* Increase PWM duty 1% */
(g_u8PWMDuty > 99) ? (g_u8PWMDuty = 100) : (g_u8PWMDuty++);
break;
}
case '3':
{
/* Decrease PWM duty 10% */
(g_u8PWMDuty < 10) ? (g_u8PWMDuty = 0) : (g_u8PWMDuty -= 10);
break;
}
case '4':
{
/* Decrease PWM duty 1% */
(g_u8PWMDuty < 1) ? (g_u8PWMDuty = 0) : (g_u8PWMDuty--);
break;
}
default:
{
continue;
}
}
/* Set PWM Channel 0 frequency and duty */
if (g_u8PWMDuty > 0)
{
PWM->PHCHG |= PWM_PHCHGNXT_PWM0_Msk;
PWM_ConfigOutputChannel(PWM, 0, 25000, g_u8PWMDuty);
}
else
PWM->PHCHG = PWM->PHCHGNXT & ~(PWM_PHCHGNXT_PWM0_Msk | PWM_PHCHGNXT_D0_Msk);
/* Wait 3 seconds */
printf("Changing... ");
Delay_mS(3000);
/* Start Timer 0 to detect the time which fan takes when rotating one round */
g_u8DetectFlag = 0;
printf("Current fan speed is ");
TIMER_Start(TIMER0);
while (!g_u8DetectFlag);
}
}
/*** (C) COPYRIGHT 2019 Nuvoton Technology Corp. ***/
|