添加PAN159资料

This commit is contained in:
SXHome
2021-09-26 17:19:12 +08:00
parent 2109411cf7
commit 7fd213ef33
3783 changed files with 1783056 additions and 0 deletions
@@ -0,0 +1,97 @@
/**************************************************************************//**
* @file acmp.c
* @version V1.00
* $Revision: 2 $
* $Date: 15/02/24 7:19p $
* @brief Mini58 series Analog Comparator(ACMP) driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "Mini58Series.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_ACMP_Driver ACMP Driver
@{
*/
/** @addtogroup Mini58_ACMP_EXPORTED_FUNCTIONS ACMP Exported Functions
@{
*/
/**
* @brief Configure the specified ACMP module
*
* @param[in] acmp The base address of ACMP module
* @param[in] u32ChNum comparator number.
* @param[in] u32NegSrc is comparator negative input selection. Including:
* - \ref ACMP_VNEG_PIN
* - \ref ACMP_VNEG_BANDGAP
* - \ref ACMP_VNEG_4_OVER_24_VDD
* - \ref ACMP_VNEG_5_OVER_24_VDD
* - \ref ACMP_VNEG_6_OVER_24_VDD
* - \ref ACMP_VNEG_7_OVER_24_VDD
* - \ref ACMP_VNEG_8_OVER_24_VDD
* - \ref ACMP_VNEG_9_OVER_24_VDD
* - \ref ACMP_VNEG_10_OVER_24_VDD
* - \ref ACMP_VNEG_11_OVER_24_VDD
* - \ref ACMP_VNEG_12_OVER_24_VDD
* - \ref ACMP_VNEG_13_OVER_24_VDD
* - \ref ACMP_VNEG_14_OVER_24_VDD
* - \ref ACMP_VNEG_15_OVER_24_VDD
* - \ref ACMP_VNEG_16_OVER_24_VDD
* - \ref ACMP_VNEG_17_OVER_24_VDD
* - \ref ACMP_VNEG_18_OVER_24_VDD
* - \ref ACMP_VNEG_19_OVER_24_VDD
*
* @param[in] u32HysteresisEn is the hysteresis function option. Including:
* - \ref ACMP_HYSTERESIS_ENABLE or
* - \ref ACMP_HYSTERESIS_DISABLE
* @return None
*/
void ACMP_Open(ACMP_T *acmp, uint32_t u32ChNum, uint32_t u32NegSrc, uint32_t u32HysteresisEn)
{
if(u32NegSrc != ACMP_VNEG_PIN)
ACMP->VREF = u32NegSrc;
ACMP->CTL[u32ChNum] = (ACMP->CTL[u32ChNum] & (~(ACMP_CTL_NEGSEL_Msk | ACMP_CTL_HYSSEL_Msk))) |
((u32NegSrc != ACMP_VNEG_PIN ? ACMP_CTL_NEGSEL_Msk : 0) | u32HysteresisEn | ACMP_CTL_ACMPEN_Msk);
}
/**
* @brief This function close comparator
*
* @param[in] acmp The base address of ACMP module
* @param[in] u32ChNum comparator number.
*
* @return None
*/
void ACMP_Close(ACMP_T *acmp, uint32_t u32ChNum)
{
ACMP->CTL[u32ChNum] &= (~ACMP_CTL_ACMPEN_Msk);
}
/*@}*/ /* end of group Mini58_ACMP_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_ACMP_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
#ifdef __cplusplus
}
#endif
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,226 @@
/**************************************************************************//**
* @file adc.c
* @version V1.00
* $Revision: 4 $
* $Date: 15/07/21 3:15p $
* @brief Mini58 series ADC driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "Mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_ADC_Driver ADC Driver
@{
*/
/** @addtogroup Mini58_ADC_EXPORTED_FUNCTIONS ADC Exported Functions
@{
*/
/**
* @brief This API configures ADC module to be ready for convert the input from selected channel
* @param[in] adc Base address of ADC module
* @param[in] u32InputMode This parameter is unused
* @param[in] u32OpMode This parameter is unused
* @param[in] u32ChMask Channel enable bit. Each bit corresponds to a input channel. Bit 0 is channel 0, bit 1 is channel 1...
* @return None
* @note Mini58 series MCU ADC can only convert 1 channel at a time. If more than 1 channels are enabled, only channel
* with smallest number will be convert.
* @note This API does not turn on ADC power nor does trigger ADC conversion
*/
void ADC_Open(ADC_T *adc,
uint32_t u32InputMode,
uint32_t u32OpMode,
uint32_t u32ChMask)
{
ADC->CHEN = (ADC->CHEN & ~(ADC_CHEN_CHEN0_Msk |
ADC_CHEN_CHEN1_Msk |
ADC_CHEN_CHEN2_Msk |
ADC_CHEN_CHEN3_Msk |
ADC_CHEN_CHEN4_Msk |
ADC_CHEN_CHEN5_Msk |
ADC_CHEN_CHEN6_Msk |
ADC_CHEN_CHEN7_Msk)) | u32ChMask;
return;
}
/**
* @brief Disable ADC module
* @param[in] adc Base address of ADC module
* @return None
*/
void ADC_Close(ADC_T *adc)
{
SYS->IPRST1 |= SYS_IPRST1_ADCRST_Msk;
SYS->IPRST1 &= ~SYS_IPRST1_ADCRST_Msk;
return;
}
/**
* @brief Configure the hardware trigger condition and enable hardware trigger
* @param[in] adc Base address of ADC module
* @param[in] u32Source Decides the hardware trigger source. Valid values are:
* - \ref ADC_TRIGGER_BY_EXT_PIN
* - \ref ADC_TRIGGER_BY_PWM
* @param[in] u32Param While ADC trigger by PWM, this parameter is used to set the delay between PWM
* trigger and ADC conversion. Valid values are from 0 ~ 0xFF, and actual delay
* time is (4 * u32Param * HCLK). While ADC trigger by external pin, this parameter
* is used to set trigger condition. Valid values are:
* - \ref ADC_FALLING_EDGE_TRIGGER
* - \ref ADC_RISING_EDGE_TRIGGER
* @return None
*/
void ADC_EnableHWTrigger(ADC_T *adc,
uint32_t u32Source,
uint32_t u32Param)
{
ADC->CTL &= ~(ADC_TRIGGER_BY_PWM | ADC_RISING_EDGE_TRIGGER | ADC_CTL_HWTRGEN_Msk);
if(u32Source == ADC_TRIGGER_BY_EXT_PIN) {
ADC->CTL |= u32Source | u32Param | ADC_CTL_HWTRGEN_Msk;
} else {
ADC->TRGDLY = (ADC->TRGDLY & ~ADC_TRGDLY_DELAY_Msk) | u32Param;
ADC->CTL |= u32Source | ADC_CTL_HWTRGEN_Msk;
}
return;
}
/**
* @brief Disable hardware trigger ADC function.
* @param[in] adc Base address of ADC module
* @return None
*/
void ADC_DisableHWTrigger(ADC_T *adc)
{
ADC->CTL &= ~(ADC_TRIGGER_BY_PWM | ADC_RISING_EDGE_TRIGGER | ADC_CTL_HWTRGEN_Msk);
return;
}
/**
* @brief Set ADC sample time for designated channel.
* @param[in] adc Base address of ADC module
* @param[in] u32ChNum This parameter is not used
* @param[in] u32SampleTime ADC sample ADC time, valid values are
* - \ref ADC_SAMPLE_CLOCK_0
* - \ref ADC_SAMPLE_CLOCK_1
* - \ref ADC_SAMPLE_CLOCK_2
* - \ref ADC_SAMPLE_CLOCK_4
* - \ref ADC_SAMPLE_CLOCK_8
* - \ref ADC_SAMPLE_CLOCK_16
* - \ref ADC_SAMPLE_CLOCK_32
* - \ref ADC_SAMPLE_CLOCK_64
* - \ref ADC_SAMPLE_CLOCK_128
* - \ref ADC_SAMPLE_CLOCK_256
* - \ref ADC_SAMPLE_CLOCK_512
* - \ref ADC_SAMPLE_CLOCK_1024
* @return None
*/
void ADC_SetExtraSampleTime(ADC_T *adc,
uint32_t u32ChNum,
uint32_t u32SampleTime)
{
ADC->EXTSMPT = (ADC->EXTSMPT & ~ADC_EXTSMPT_EXTSMPT_Msk) | u32SampleTime;
}
/**
* @brief Enable the interrupt(s) selected by u32Mask parameter.
* @param[in] adc Base address of ADC module
* @param[in] u32Mask The combination of interrupt status bits listed below. Each bit
* corresponds to a interrupt status. This parameter decides which
* interrupts will be enabled.
* - \ref ADC_ADIF_INT
* - \ref ADC_CMP0_INT
* - \ref ADC_CMP1_INT
* @return None
*/
void ADC_EnableInt(ADC_T *adc, uint32_t u32Mask)
{
if(u32Mask & ADC_ADIF_INT)
ADC->CTL |= ADC_CTL_ADCIEN_Msk;
if(u32Mask & ADC_CMP0_INT)
ADC->CMP0 |= ADC_CMP0_ADCMPIE_Msk;
if(u32Mask & ADC_CMP1_INT)
ADC->CMP1 |= ADC_CMP1_ADCMPIE_Msk;
return;
}
/**
* @brief Disable the interrupt(s) selected by u32Mask parameter.
* @param[in] adc Base address of ADC module
* @param[in] u32Mask The combination of interrupt status bits listed below. Each bit
* corresponds to a interrupt status. This parameter decides which
* interrupts will be disabled.
* - \ref ADC_ADIF_INT
* - \ref ADC_CMP0_INT
* - \ref ADC_CMP1_INT
* @return None
*/
void ADC_DisableInt(ADC_T *adc, uint32_t u32Mask)
{
if(u32Mask & ADC_ADIF_INT)
ADC->CTL &= ~ADC_CTL_ADCIEN_Msk;
if(u32Mask & ADC_CMP0_INT)
ADC->CMP0 &= ~ADC_CMP0_ADCMPIE_Msk;
if(u32Mask & ADC_CMP1_INT)
ADC->CMP1 &= ~ADC_CMP1_ADCMPIE_Msk;
return;
}
/**
* @brief ADC PWM Sequential Mode Control.
* @param[in] adc Base address of ADC module
* @param[in] u32SeqTYPE This parameter decides which type will be selected.
* - \ref ADC_SEQMODE_TYPE_23SHUNT
* - \ref ADC_SEQMODE_TYPE_1SHUNT
* @param[in] u32ModeSel This parameter decides which mode will be selected.
* - \ref ADC_SEQMODE_MODESELECT_CH01
* - \ref ADC_SEQMODE_MODESELECT_CH12
* - \ref ADC_SEQMODE_MODESELECT_CH02
* @return None
*/
void ADC_SeqModeEnable(ADC_T *adc, uint32_t u32SeqTYPE, uint32_t u32ModeSel)
{
// Enable ADC Sequential Mode
ADC->SEQCTL = ADC->SEQCTL | ADC_SEQCTL_SEQEN_Msk;
// Select ADC Sequential Mode Type
ADC->SEQCTL = (ADC->SEQCTL & ~(ADC_SEQCTL_SEQTYPE_Msk)) | (u32SeqTYPE << ADC_SEQCTL_SEQTYPE_Pos);
// Select ADC Sequential Mode Type
ADC->SEQCTL = (ADC->SEQCTL & ~(ADC_SEQCTL_MODESEL_Msk)) | (u32ModeSel << ADC_SEQCTL_MODESEL_Pos);
return;
}
/**
* @brief ADC PWM Sequential Mode PWM Trigger Source and type.
* @param[in] adc Base address of ADC module
* @param[in] u32SeqModeTriSrc1 This parameter decides first PWM trigger source and type.
* @param[in] u32SeqModeTriSrc2 This parameter decides second PWM trigger source and type.
*
*
* @return None
*/
void ADC_SeqModeTriggerSrc(ADC_T *adc, uint32_t u32SeqModeTriSrc1, uint32_t u32SeqModeTriSrc2)
{
// Select PWM Trigger Source Selection for TRG1CTL or TRG2CTL
ADC->SEQCTL = (ADC->SEQCTL & ~(ADC_SEQCTL_TRG1CTL_Msk)) | (u32SeqModeTriSrc1 << ADC_SEQCTL_TRG1CTL_Pos);
ADC->SEQCTL = (ADC->SEQCTL & ~(ADC_SEQCTL_TRG2CTL_Msk)) | (u32SeqModeTriSrc2 << ADC_SEQCTL_TRG2CTL_Pos);
return;
}
/*@}*/ /* end of group Mini58_ADC_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_ADC_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,615 @@
/**************************************************************************//**
* @file clk.c
* @version V1.00
* $Revision: 15 $
* $Date: 15/06/05 9:39a $
* @brief Mini58 series CLK driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "Mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_CLK_Driver CLK Driver
@{
*/
/** @addtogroup Mini58_CLK_EXPORTED_FUNCTIONS CLK Exported Functions
@{
*/
/**
* @brief This function disable frequency output function.
* @return None
*/
void CLK_DisableCKO(void)
{
/* Disable CKO clock source */
CLK->APBCLK &= (~CLK_APBCLK_CLKOCKEN_Msk);
}
/**
* @brief This function enable frequency divider module clock,
* enable frequency divider clock function and configure frequency divider.
* @param[in] u32ClkSrc is frequency divider function clock source
* - \ref CLK_CLKSEL2_CLKOSEL_XTAL
* - \ref CLK_CLKSEL2_CLKOSEL_LIRC
* - \ref CLK_CLKSEL2_CLKOSEL_HCLK
* - \ref CLK_CLKSEL2_CLKOSEL_HIRC
* @param[in] u32ClkDiv Set the clock divider to CKO. 0 <= u32ClkDiv <= 15
* @param[in] u32ClkDivBy1En is frequency divided by one enable.
* @return None
*
* @details Output selected clock to CKO. The output clock frequency is divided by u32ClkDiv.
* The formula is:
* CKO frequency = (Clock source frequency) / 2^(u32ClkDiv + 1)
* This function is just used to set CKO clock.
* User must enable I/O for CKO clock output pin by themselves.
*/
void CLK_EnableCKO(uint32_t u32ClkSrc, uint32_t u32ClkDiv, uint32_t u32ClkDivBy1En)
{
/* CKO = clock source / 2^(u32ClkDiv + 1) */
CLK->CLKOCTL = CLK_CLKOCTL_CLKOEN_Msk | u32ClkDiv | u32ClkDivBy1En<<CLK_CLKOCTL_DIV1EN_Pos;
/* Enable CKO clock source */
CLK->APBCLK |= CLK_APBCLK_CLKOCKEN_Msk;
/* Select CKO clock source */
CLK->CLKSEL2 = (CLK->CLKSEL2 & (~CLK_CLKSEL2_CLKOSEL_Msk)) | u32ClkSrc;
}
/**
* @brief This function let system enter to Power-down mode.
* @return None
*/
void CLK_PowerDown(void)
{
SCB->SCR = SCB_SCR_SLEEPDEEP_Msk;
CLK->PWRCTL |= (CLK_PWRCTL_PDEN_Msk | CLK_PWRCTL_PDWKIF_Msk);
__WFI();
}
/**
* @brief This function let system enter to Idle mode
* @return None
*/
void CLK_Idle(void)
{
CLK->PWRCTL |= (CLK_PWRCTL_PDEN_Msk | CLK_PWRCTL_PDWKIF_Msk);
__WFI();
}
/**
* @brief This function get external high frequency crystal frequency. The frequency unit is Hz.
* @return None
*/
uint32_t CLK_GetHXTFreq(void)
{
if((CLK->PWRCTL & CLK_PWRCTL_XTLEN_Msk)==CLK_PWRCTL_XTLEN_HXT )
return __HXT;
else
return 0;
}
/**
* @brief This function get external low frequency crystal frequency. The frequency unit is Hz.
* @return LXT frequency
*/
uint32_t CLK_GetLXTFreq(void)
{
if((CLK->PWRCTL & CLK_PWRCTL_XTLEN_Msk )==CLK_PWRCTL_XTLEN_LXT )
return __XTAL;
else
return 0;
}
/**
* @brief This function get HCLK frequency. The frequency unit is Hz.
* @return HCLK frequency
*/
uint32_t CLK_GetHCLKFreq(void)
{
SystemCoreClockUpdate();
return SystemCoreClock;
}
/**
* @brief This function get CPU frequency. The frequency unit is Hz.
* @return CPU frequency
*/
uint32_t CLK_GetCPUFreq(void)
{
SystemCoreClockUpdate();
return SystemCoreClock;
}
/**
* @brief Set HCLK frequency
* @param[in] u32Hclk is HCLK frequency. The range of u32Hclk is 26 MHz ~ 50 MHz.
* @return HCLK frequency
* @details This function is used to set HCLK frequency. The frequency unit is Hz.
* It would configure PLL frequency to 100MHz ~ 200MHz,
* set HCLK clock divider as 2 and switch HCLK clock source to PLL.
* The register write-protection function should be disabled before using this function.
*/
uint32_t CLK_SetCoreClock(uint32_t u32Hclk)
{
uint32_t u32HIRCSTB;
/* Read HIRC clock source stable flag */
u32HIRCSTB = CLK->STATUS & CLK_STATUS_HIRCSTB_Msk;
/* The range of u32Hclk is 25 MHz ~ 50 MHz */
if(u32Hclk > FREQ_50MHZ)
u32Hclk = FREQ_50MHZ;
if(u32Hclk < FREQ_25MHZ)
u32Hclk = FREQ_25MHZ;
/* Switch HCLK clock source to HIRC clock for safe */
CLK->PWRCTL |= CLK_PWRCTL_HIRCEN_Msk;
CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);
CLK->CLKSEL0 |= CLK_CLKSEL0_HCLKSEL_Msk;
CLK->CLKDIV &= (~CLK_CLKDIV_HCLKDIV_Msk);
/* Configure PLL setting if HXT clock is enabled */
if( (CLK->PWRCTL & CLK_PWRCTL_XTLEN_Msk)==CLK_PWRCTL_XTLEN_HXT )
u32Hclk = CLK_EnablePLL(CLK_PLLCTL_PLLSRC_HXT, (u32Hclk << 1));
/* Configure PLL setting if HXT clock is not enabled */
else {
u32Hclk = CLK_EnablePLL(CLK_PLLCTL_PLLSRC_HIRC, (u32Hclk << 1));
/* Read HIRC clock source stable flag */
u32HIRCSTB = CLK->STATUS & CLK_STATUS_HIRCSTB_Msk;
}
/* Select HCLK clock source to PLL,
Select HCLK clock source divider as 2
and update system core clock
*/
//CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_PLL, CLK_CLKDIV_HCLK(2));
CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_PLL, CLK_CLKDIV_HCLK(2));
/* Disable HIRC if HIRC is disabled before setting core clock */
if(u32HIRCSTB == 0)
CLK->PWRCTL &= ~CLK_PWRCTL_HIRCEN_Msk;
/* Return actually HCLK frequency is PLL frequency divide 2 */
return u32Hclk >> 1;
}
/**
* @brief This function set HCLK clock source and HCLK clock divider
* @param[in] u32ClkSrc is HCLK clock source. Including :
* - \ref CLK_CLKSEL0_HCLKSEL_XTAL
* - \ref CLK_CLKSEL0_HCLKSEL_LIRC
* - \ref CLK_CLKSEL0_HCLKSEL_HIRC
* @param[in] u32ClkDiv is HCLK clock divider. Including :
* - \ref CLK_CLKDIV_HCLK(x)
* @return None
*/
void CLK_SetHCLK(uint32_t u32ClkSrc, uint32_t u32ClkDiv)
{
/* Apply new Divider */
CLK->CLKDIV = (CLK->CLKDIV & ~CLK_CLKDIV_HCLKDIV_Msk) | u32ClkDiv;
/* Switch HCLK to new HCLK source */
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_HCLKSEL_Msk) | u32ClkSrc;
/* Update System Core Clock */
SystemCoreClockUpdate();
}
/**
* @brief This function set selected module clock source and module clock divider
* @param[in] u32ModuleIdx is module index.
* @param[in] u32ClkSrc is module clock source.
* @param[in] u32ClkDiv is module clock divider.
* @return None
* @details Valid parameter combinations listed in following table:
*
* |Module index |Clock source |Divider |
* | :---------------- | :----------------------------------- | :--------------------- |
* |\ref WDT_MODULE |\ref CLK_CLKSEL1_WDTSEL_XTAL | x |
* |\ref WDT_MODULE |\ref CLK_CLKSEL1_WDTSEL_HCLK_DIV2048 | x |
* |\ref WDT_MODULE |\ref CLK_CLKSEL1_WDTSEL_LIRC | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0SEL_XTAL | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0SEL_LIRC | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0SEL_HCLK | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0SEL_TM0 | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0SEL_HIRC | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1SEL_XTAL | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1SEL_LIRC | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1SEL_HCLK | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1SEL_TM1 | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1SEL_HIRC | x |
* |\ref CLKO_MODULE |\ref CLK_CLKSEL2_CLKOSEL_XTAL | x |
* |\ref CLKO_MODULE |\ref CLK_CLKSEL2_CLKOSEL_HCLK | x |
* |\ref CLKO_MODULE |\ref CLK_CLKSEL2_CLKOSEL_HIRC | x |
* |\ref I2C0_MODULE | x | x |
* |\ref I2C1_MODULE | x | x |
* |\ref SPI0_MODULE |\ref CLK_CLKSEL1_SPISEL_XTAL | x |
* |\ref SPI0_MODULE |\ref CLK_CLKSEL1_SPISEL_HCLK | x |
* |\ref SPI0_MODULE |\ref CLK_CLKSEL1_SPISEL_PLL | x |
* |\ref UART0_MODULE |\ref CLK_CLKSEL1_UARTSEL_XTAL |\ref CLK_CLKDIV_UART(x) |
* |\ref UART0_MODULE |\ref CLK_CLKSEL1_UARTSEL_PLL |\ref CLK_CLKDIV_UART(x) |
* |\ref UART0_MODULE |\ref CLK_CLKSEL1_UARTSEL_HIRC |\ref CLK_CLKDIV_UART(x) |
* |\ref UART1_MODULE |\ref CLK_CLKSEL1_UARTSEL_XTAL |\ref CLK_CLKDIV_UART(x) |
* |\ref UART1_MODULE |\ref CLK_CLKSEL1_UARTSEL_PLL |\ref CLK_CLKDIV_UART(x) |
* |\ref UART1_MODULE |\ref CLK_CLKSEL1_UARTSEL_HIRC |\ref CLK_CLKDIV_UART(x) |
* |\ref PWMCH01_MODULE |\ref CLK_CLKSEL1_PWMCH01SEL_HCLK | x |
* |\ref PWMCH23_MODULE |\ref CLK_CLKSEL1_PWMCH23SEL_HCLK | x |
* |\ref PWMCH45_MODULE |\ref CLK_CLKSEL2_PWMCH45SEL_HCLK | x |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADCSEL_XTAL |\ref CLK_CLKDIV_ADC(x) |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADCSEL_PLL |\ref CLK_CLKDIV_ADC(x) |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADCSEL_HCLK |\ref CLK_CLKDIV_ADC(x) |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADCSEL_HIRC |\ref CLK_CLKDIV_ADC(x) |
* |\ref ACMP_MODULE | x | x |
* |\ref WWDT_MODULE |\ref CLK_CLKSEL2_WWDTSEL_HCLK_DIV2048 | x |
* |\ref WWDT_MODULE |\ref CLK_CLKSEL2_WWDTSEL_LIRC | x |
*/
void CLK_SetModuleClock(uint32_t u32ModuleIdx, uint32_t u32ClkSrc, uint32_t u32ClkDiv)
{
uint32_t u32tmp=0,u32sel=0,u32div=0;
if(MODULE_CLKSEL_Msk(u32ModuleIdx)!=MODULE_NoMsk) {
u32sel = (uint32_t)&CLK->CLKSEL0+((MODULE_CLKSEL(u32ModuleIdx))*4);
u32tmp = *(volatile uint32_t *)(u32sel);
u32tmp = ( u32tmp & ~(MODULE_CLKSEL_Msk(u32ModuleIdx)<<MODULE_CLKSEL_Pos(u32ModuleIdx)) ) | u32ClkSrc;
*(volatile uint32_t *)(u32sel) = u32tmp;
}
if(MODULE_CLKDIV_Msk(u32ModuleIdx)!=MODULE_NoMsk) {
u32div =(uint32_t)&CLK->CLKDIV+((MODULE_CLKDIV(u32ModuleIdx))*4);
u32tmp = *(volatile uint32_t *)(u32div);
u32tmp = ( u32tmp & ~(MODULE_CLKDIV_Msk(u32ModuleIdx)<<MODULE_CLKDIV_Pos(u32ModuleIdx)) ) | u32ClkDiv;
*(volatile uint32_t *)(u32div) = u32tmp;
}
}
/**
* @brief This function set SysTick clock source
* @param[in] u32ClkSrc is module clock source. Including
* - \ref CLK_CLKSEL0_STCLKSEL_XTAL
* - \ref CLK_CLKSEL0_STCLKSEL_XTAL_DIV2
* - \ref CLK_CLKSEL0_STCLKSEL_HCLK_DIV2
* - \ref CLK_CLKSEL0_STCLKSEL_HIRC_DIV2
* @return None
*/
void CLK_SetSysTickClockSrc(uint32_t u32ClkSrc)
{
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_STCLKSEL_Msk) | u32ClkSrc;
}
/**
* @brief Enable System Tick counter
* @param[in] u32ClkSrc is System Tick clock source. Including:
* - \ref CLK_CLKSEL0_STCLKSEL_XTAL
* - \ref CLK_CLKSEL0_STCLKSEL_XTAL_DIV2
* - \ref CLK_CLKSEL0_STCLKSEL_HCLK_DIV2
* - \ref CLK_CLKSEL0_STCLKSEL_HIRC_DIV2
* - \ref CLK_CLKSEL0_STCLKSEL_HCLK
* @param[in] u32Count is System Tick reload value. It should be 0x1~0xFFFFFF.
* @return None
* @details This function set System Tick clock source, reload value, enable System Tick counter and interrupt.
* The register write-protection function should be disabled before using this function.
*/
void CLK_EnableSysTick(uint32_t u32ClkSrc, uint32_t u32Count)
{
SysTick->CTRL=0;
if( u32ClkSrc== CLK_CLKSEL0_STCLKSEL_HCLK ) /* Set System Tick clock source */
SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk;
else {
SysTick->CTRL &= ~SysTick_CTRL_CLKSOURCE_Msk;
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_STCLKSEL_Msk) | u32ClkSrc;
}
SysTick->LOAD = u32Count; /* Set System Tick reload value */
SysTick->VAL = 0; /* Clear System Tick current value and counter flag */
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; /* Set System Tick counter enabled */
}
/**
* @brief Disable System Tick counter
* @return None
* @details This function disable System Tick counter.
*/
void CLK_DisableSysTick(void)
{
SysTick->CTRL = 0; /* Set System Tick counter disabled */
}
/**
* @brief This function enable clock source
* @param[in] u32ClkMask is clock source mask. Including :
* - \ref CLK_PWRCTL_XTLEN_HXT or \ref CLK_PWRCTL_XTLEN_LXT,
* - \ref CLK_PWRCTL_LIRCEN_Msk
* - \ref CLK_PWRCTL_HIRCEN_Msk
* @return None
*/
void CLK_EnableXtalRC(uint32_t u32ClkMask)
{
if(u32ClkMask & CLK_PWRCTL_XTLEN_Msk)
CLK->PWRCTL = (CLK->PWRCTL & ~CLK_PWRCTL_XTLEN_Msk) | u32ClkMask;
else
CLK->PWRCTL |= u32ClkMask;
}
/**
* @brief This function disable clock source
* @param[in] u32ClkMask is clock source mask. Including :
* - \ref CLK_PWRCTL_XTLEN_Msk,
* - \ref CLK_PWRCTL_LIRCEN_Msk,
* - \ref CLK_PWRCTL_HIRCEN_Msk,
* @return None
*/
void CLK_DisableXtalRC(uint32_t u32ClkMask)
{
CLK->PWRCTL &=~u32ClkMask;
}
/**
* @brief This function enable module clock
* @param[in] u32ModuleIdx is module index. Including :
* - \ref WDT_MODULE
* - \ref TMR0_MODULE
* - \ref TMR1_MODULE
* - \ref CLKO_MODULE
* - \ref I2C0_MODULE
* - \ref I2C1_MODULE
* - \ref SPI0_MODULE
* - \ref UART0_MODULE
* - \ref UART1_MODULE
* - \ref PWMCH01_MODULE
* - \ref PWMCH23_MODULE
* - \ref PWMCH45_MODULE
* - \ref ADC_MODULE
* - \ref ACMP_MODULE
* - \ref WWDT_MODULE
* @return None
*/
void CLK_EnableModuleClock(uint32_t u32ModuleIdx)
{
*(volatile uint32_t *)((uint32_t)&CLK->AHBCLK+(MODULE_APBCLK(u32ModuleIdx)*4)) |= 1<<MODULE_IP_EN_Pos(u32ModuleIdx);
}
/**
* @brief This function disable module clock
* @param[in] u32ModuleIdx is module index
* - \ref WDT_MODULE
* - \ref TMR0_MODULE
* - \ref TMR1_MODULE
* - \ref CLKO_MODULE
* - \ref I2C0_MODULE
* - \ref I2C1_MODULE
* - \ref SPI0_MODULE
* - \ref UART0_MODULE
* - \ref UART1_MODULE
* - \ref PWMCH01_MODULE
* - \ref PWMCH23_MODULE
* - \ref PWMCH45_MODULE
* - \ref ADC_MODULE
* - \ref ACMP_MODULE
* - \ref WWDT_MODULE
* @return None
*/
void CLK_DisableModuleClock(uint32_t u32ModuleIdx)
{
*(volatile uint32_t *)((uint32_t)&CLK->AHBCLK+(MODULE_APBCLK(u32ModuleIdx)*4)) &= ~(1<<MODULE_IP_EN_Pos(u32ModuleIdx));
}
/**
* @brief Set PLL frequency
* @param[in] u32PllClkSrc is PLL clock source. Including :
* - \ref CLK_PLLCTL_PLLSRC_HXT
* - \ref CLK_PLLCTL_PLLSRC_HIRC
* @param[in] u32PllFreq is PLL frequency.
* @return PLL frequency
* @details This function is used to configure PLLCTL register to set specified PLL frequency.
* The register write-protection function should be disabled before using this function.
*/
uint32_t CLK_EnablePLL(uint32_t u32PllClkSrc, uint32_t u32PllFreq)
{
uint32_t u32PllSrcClk, u32NR, u32NF, u32NO, u32CLK_SRC , u32NRT;
uint32_t u32Tmp, u32Tmp2, u32Tmp3, u32Min, u32MinNF, u32MinNR,u32Best;
/* Disable PLL first to avoid unstable when setting PLL */
CLK_DisablePLL();
/* PLL source clock is from HXT */
if(u32PllClkSrc == CLK_PLLCTL_PLLSRC_HXT) {
/* Enable HXT clock */
CLK->PWRCTL = (CLK->PWRCTL & ~CLK_PWRCTL_XTLEN_Msk) | CLK_PWRCTL_XTLEN_HXT ;
/* Wait for HXT clock ready */
CLK_WaitClockReady(CLK_STATUS_XTLSTB_Msk);
/* Select PLL source clock from HXT */
u32CLK_SRC = CLK_PLLCTL_PLLSRC_HXT;
u32PllSrcClk = __XTAL;
/* u32NR start from 2 */
u32NRT = 2;
}
/* PLL source clock is from HIRC */
else {
/* Enable HIRC clock */
CLK->PWRCTL |= CLK_PWRCTL_HIRCEN_Msk;
/* Wait for HIRC clock ready */
CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);
/* Select PLL source clock from HIRC */
u32CLK_SRC = CLK_PLLCTL_PLLSRC_HIRC;
u32PllSrcClk = __HIRC;
/* u32NR start from 4 when FIN = 22.1184MHz to avoid calculation overflow */
u32NRT = 4;
}
/* Select "NO" according to request frequency */
if((u32PllFreq <= FREQ_200MHZ) && (u32PllFreq > FREQ_100MHZ)) {
u32NO = 0;
u32PllFreq = u32PllFreq;
} else if((u32PllFreq <= FREQ_100MHZ) && (u32PllFreq >= FREQ_50MHZ)) {
u32NO = 1;
u32PllFreq = u32PllFreq << 1;
} else if((u32PllFreq < FREQ_50MHZ) && (u32PllFreq >= FREQ_25MHZ)) {
u32NO = 3;
u32PllFreq = u32PllFreq << 2;
} else {
/* Wrong frequency request. Just return default setting. */
goto lexit;
}
/* Find best solution */
u32Min = (uint32_t) - 1;
u32MinNR = 0;
u32MinNF = 0;
for(u32NR=u32NRT; u32NR <= 33; u32NR++) {
u32Tmp = u32PllSrcClk / u32NR;
if((u32Tmp > 1600000) && (u32Tmp < 15000000)) {
for(u32NF = 2; u32NF <= 513; u32NF++) {
u32Tmp2 = u32Tmp * u32NF;
if((u32Tmp2 >= 100000000) && (u32Tmp2 <= 200000000)) {
u32Tmp3 = (u32Tmp2 > u32PllFreq) ? u32Tmp2 - u32PllFreq : u32PllFreq - u32Tmp2;
if(u32Tmp3 < u32Min) {
u32Min = u32Tmp3;
u32MinNR = u32NR;
u32MinNF = u32NF;
/* Break when get good results */
if(u32Min == 0) {
/* Enable and apply new PLL setting. */
CLK->PLLCTL = u32CLK_SRC | (u32NO << 14) | ((u32MinNR - 2) << 9) | (u32MinNF - 2);
/* Wait for PLL clock stable */
CLK_WaitClockReady(CLK_STATUS_PLLSTB_Msk);
/* Return actual PLL output clock frequency */
return u32PllSrcClk / ((u32NO + 1) * u32MinNR) * u32MinNF;
}
}
}
}
}
}
/* Find best solution */
u32Best = u32Min;
u32Min = (uint32_t) - 1;
u32MinNR = 0;
u32MinNF = 0;
for(u32NR=u32NRT; u32NR <= 33; u32NR++) {
u32Tmp = u32PllSrcClk / u32NR;
if((u32Tmp > 1600000) && (u32Tmp < 15000000)) {
for(u32NF = 2; u32NF <= 513; u32NF++) {
u32Tmp2 = u32Tmp * u32NF;
if((u32Tmp2 >= 100000000) && (u32Tmp2 <= 200000000)) {
u32Tmp3 = (u32Tmp2 > u32PllFreq) ? u32Tmp2 - u32PllFreq : u32PllFreq - u32Tmp2;
if(u32Tmp3 < u32Min) {
u32Min = u32Tmp3;
u32MinNR = u32NR;
u32MinNF = u32NF;
/* Break when get good results */
if(u32Min == u32Best) {
/* Enable and apply new PLL setting. */
CLK->PLLCTL = u32CLK_SRC | (u32NO << 14) | ((u32MinNR - 2) << 9) | (u32MinNF - 2);
/* Wait for PLL clock stable */
CLK_WaitClockReady(CLK_STATUS_PLLSTB_Msk);
/* Return actual PLL output clock frequency */
return u32PllSrcClk / ((u32NO + 1) * u32MinNR) * u32MinNF;
}
}
}
}
}
}
lexit:
/* Apply default PLL setting and return */
if(u32PllClkSrc == CLK_PLLCTL_PLLSRC_HXT)
CLK->PLLCTL = CLK_PLLCTL_72MHz_HXT; /* 72MHz */
else
CLK->PLLCTL = CLK_PLLCTL_72MHz_HIRC; /* 71.8848MHz */
/* Wait for PLL clock stable */
CLK_WaitClockReady(CLK_STATUS_PLLSTB_Msk);
return CLK_GetPLLClockFreq();
}
/**
* @brief Disable PLL
* @param None
* @return None
* @details This function set PLL in Power-down mode.
* The register write-protection function should be disabled before using this function.
*/
void CLK_DisablePLL(void)
{
CLK->PLLCTL |= CLK_PLLCTL_PD_Msk;
}
/**
* @brief This function execute delay function.
* @param[in] us Delay time. The Max value is 2^24 / CPU Clock(MHz). Ex:
* 50MHz => 335544us, 48MHz => 349525us, 28MHz => 699050us ...
* @return None
* @details Use the SysTick to generate the delay time and the UNIT is in us.
* The SysTick clock source is from HCLK, i.e the same as system core clock.
*/
void CLK_SysTickDelay(uint32_t us)
{
SysTick->LOAD = us * CyclesPerUs;
SysTick->VAL = (0x00);
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
/* Waiting for down-count to zero */
while((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0);
SysTick->CTRL = 0;
}
/**
* @brief This function check selected clock source status
* @param[in] u32ClkMask is selected clock source. Including
* - \ref CLK_STATUS_CLKSFAIL_Msk
* - \ref CLK_STATUS_HIRCSTB_Msk
* - \ref CLK_STATUS_LIRCSTB_Msk
* - \ref CLK_STATUS_XTLSTB_Msk
*
* @return 0 clock is not stable
* 1 clock is stable
*
* @details To wait for clock ready by specified CLKSTATUS bit or timeout (~5ms)
*/
uint32_t CLK_WaitClockReady(uint32_t u32ClkMask)
{
int32_t i32TimeOutCnt = 2160000;
while((CLK->STATUS & u32ClkMask) != u32ClkMask) {
if(i32TimeOutCnt-- <= 0)
return 0;
}
return 1;
}
/*@}*/ /* end of group Mini58_CLK_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_CLK_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,310 @@
/**************************************************************************//**
* @file fmc.c
* @version V1.00
* $Revision: 6 $
* $Date: 15/05/26 6:31p $
* @brief Mini58 series FMC driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
//* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include "Mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_FMC_Driver FMC Driver
@{
*/
/** @addtogroup Mini58_FMC_EXPORTED_FUNCTIONS FMC Exported Functions
@{
*/
/**
* @brief Disable all FMC functions
*
* @return None
*/
void FMC_Close(void)
{
FMC->ISPCTL &= ~FMC_ISPCTL_ISPEN_Msk;
}
/**
* @brief Erase a page. The page size is 512 bytes.
* @param[in] u32PageAddr Flash page address. Must be a 512-byte aligned address.
* @retval 0 Success
* @retval -1 Erase failed
*/
int32_t FMC_Erase(uint32_t u32PageAddr)
{
FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
FMC->ISPADDR = u32PageAddr;
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) ;
if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk) {
FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
return -1;
}
return 0;
}
/**
* @brief get the current boot source
* @retval 0 This chip is currently booting from APROM
* @retval 1 This chip is currently booting from LDROM
*/
int32_t FMC_GetBootSource (void)
{
if (FMC->ISPCTL & FMC_ISPCTL_BS_Msk)
return 1;
else
return 0;
}
/**
* @brief Enable FMC ISP function
*/
void FMC_Open(void)
{
FMC->ISPCTL |= FMC_ISPCTL_ISPEN_Msk;
}
/**
* @brief Read a word from specified flash address.
* @param[in] u32Addr Flash word address. Must be a word aligned address.
* @return The word data stored in the flash address "u32Addr".
*/
uint32_t FMC_Read(uint32_t u32Addr)
{
FMC->ISPCMD = FMC_ISPCMD_READ;
FMC->ISPADDR = u32Addr;
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) ;
return FMC->ISPDAT;
}
/**
* @brief Read company ID.
* @return The company ID.
*/
uint32_t FMC_ReadCID(void)
{
FMC->ISPCMD = FMC_ISPCMD_READ_CID;
FMC->ISPADDR = 0x0;
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) ;
return FMC->ISPDAT;
}
/**
* @brief Read product ID.
* @return The product ID.
*/
uint32_t FMC_ReadPID(void)
{
FMC->ISPCMD = FMC_ISPCMD_READ_PID;
FMC->ISPADDR = 0x04;
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) ;
return FMC->ISPDAT;
}
/**
* @brief This function reads one of the four UCID.
* @param[in] u32Index index of the UCID to read. u32Index must be 0, 1, 2, or 3.
* @return The UCID.
*/
uint32_t FMC_ReadUCID(uint32_t u32Index)
{
FMC->ISPCMD = FMC_ISPCMD_READ_UID;
FMC->ISPADDR = (0x04 * u32Index) + 0x10;
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) ;
return FMC->ISPDAT;
}
/**
* @brief This function reads one of the three UID.
* @param[in] u32Index Index of the UID to read. u32Index must be 0, 1, or 2.
* @return The UID.
*/
uint32_t FMC_ReadUID(uint32_t u32Index)
{
FMC->ISPCMD = FMC_ISPCMD_READ_UID;
FMC->ISPADDR = 0x04 * u32Index;
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) ;
return FMC->ISPDAT;
}
/**
* @brief Get the base address of Data Flash if enabled.
* @return The base address of Data Flash
*/
uint32_t FMC_ReadDataFlashBaseAddr(void)
{
return FMC->DFBA;
}
/**
* @brief This function will force re-map assigned flash page to CPU address 0x0.
* @param[in] u32PageAddr Address of the page to be mapped to CPU address 0x0.
* @return None
*/
void FMC_SetVectorPageAddr(uint32_t u32PageAddr)
{
FMC->ISPCMD = FMC_ISPCMD_VECMAP;
FMC->ISPADDR = u32PageAddr;
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) ;
}
/**
* @brief Obtain the current vector page address setting.
* @return The vector page address.
*/
uint32_t FMC_GetVectorPageAddr(void)
{
return (FMC->ISPSTS & 0x0FFFFF00ul);
}
/**
* @brief Writes a word data to specified flash address.
* @param[in] u32Addr Destination address
* @param[in] u32Data Word data to be written
* @return None
*/
void FMC_Write(uint32_t u32Addr, uint32_t u32Data)
{
FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
FMC->ISPADDR = u32Addr;
FMC->ISPDAT = u32Data;
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) ;
}
/**
* @brief Read the User Configuration words.
* @param[in] u32Config The word array to store data.
* @param[in] u32Count Maximum length of "u32Config".
* @retval 0 Success
* @retval -1 Failed
*/
int32_t FMC_ReadConfig(uint32_t *u32Config, uint32_t u32Count)
{
if (u32Count < 1)
return 0;
u32Config[0] = FMC_Read(FMC_CONFIG_BASE);
if (u32Count < 2)
return 0;
u32Config[1] = FMC_Read(FMC_CONFIG_BASE+4);
return 0;
}
/**
* @brief Write User Configuration
* @param[in] u32Config The word array to store data.
* @param[in] u32Count Maximum length of "u32Config".
* @retval 0 Success
* @retval -1 Failed
*/
int32_t FMC_WriteConfig(uint32_t *u32Config, uint32_t u32Count)
{
if (u32Count < 1)
return 0;
FMC_ENABLE_CFG_UPDATE();
FMC_Erase(FMC_CONFIG_BASE);
FMC_Write(FMC_CONFIG_BASE, u32Config[0]);
if (u32Count < 2)
return 0;
FMC_Write(FMC_CONFIG_BASE+4, u32Config[1]);
FMC_DISABLE_CFG_UPDATE();
return 0;
}
/**
* @brief Calculate and read the CRC32 checksum of a specified flash area.
* @param[in] addr Start address of the flash area to be executed CRC32 checksum calculation.
* @param[in] count Number of bytes to be calculated.
* @param[out] chksum If success, it will contain the result of CRC32 checksum calculation.
* @retval 0 Success
* @retval -1 Invalid parameter.
*/
int32_t FMC_GetCRC32Sum(uint32_t addr, uint32_t count, uint32_t *chksum)
{
FMC->ISPCMD = FMC_ISPCMD_CAL_CRC32;
FMC->ISPADDR = addr;
FMC->ISPDAT = count;
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) ;
if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk) {
FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
return -1;
}
FMC->ISPCMD = FMC_ISPCMD_READ_CRC32;
FMC->ISPADDR = addr;
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) ;
if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk) {
FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
return -1;
}
*chksum = FMC->ISPDAT;
return 0;
}
/*@}*/ /* end of group Mini58_FMC_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_FMC_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,101 @@
/**************************************************************************//**
* @file gpio.c
* @version V1.00
* $Revision: 1 $
* $Date: 15/02/02 3:19p $
* @brief Mini58 series GPIO driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "Mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_GPIO_Driver GPIO Driver
@{
*/
/** @addtogroup Mini58_GPIO_EXPORTED_FUNCTIONS GPIO Exported Functions
@{
*/
/**
* @brief Set GPIO operation mode
*
* @param[in] gpio GPIO port. It could be \ref P0, \ref P1, \ref P2, \ref P3, \ref P4 or \ref P5.
* @param[in] u32PinMask The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
* @param[in] u32Mode Operation mode.
* - \ref GPIO_MODE_INPUT,
* - \ref GPIO_MODE_OUTPUT,
* - \ref GPIO_MODE_OPEN_DRAIN,
* - \ref GPIO_MODE_QUASI
*
* @return None
*
* @details This function is used to set specified GPIO operation mode.
*/
void GPIO_SetMode(GPIO_T *gpio, uint32_t u32PinMask, uint32_t u32Mode)
{
uint32_t i;
for (i=0; i<GPIO_PIN_MAX; i++) {
if (u32PinMask & (1 << i)) {
gpio->MODE = (gpio->MODE & ~(0x3 << (i << 1))) | (u32Mode << (i << 1));
}
}
}
/**
* @brief Enable GPIO interrupt
*
* @param[in] gpio GPIO port. It could be \ref P0, \ref P1, \ref P2, \ref P3, \ref P4 or \ref P5.
* @param[in] u32Pin The pin of specified GPIO port. It could be 0 ~ 7.
* @param[in] u32IntAttribs The interrupt attribute of specified GPIO pin. It could be \n
* - \ref GPIO_INT_RISING,
* - \ref GPIO_INT_FALLING,
* - \ref GPIO_INT_BOTH_EDGE,
* - \ref GPIO_INT_HIGH,
* - \ref GPIO_INT_LOW.
*
* @return None
*
* @details This function is used to enable specified GPIO pin interrupt.
*/
void GPIO_EnableInt(GPIO_T *gpio, uint32_t u32Pin, uint32_t u32IntAttribs)
{
gpio->INTTYPE |= (((u32IntAttribs >> 24) & 0xFFUL) << u32Pin);
gpio->INTEN |= ((u32IntAttribs & 0xFFFFFFUL) << u32Pin);
}
/**
* @brief Disable GPIO interrupt
*
* @param[in] gpio GPIO port. It could be \ref P0, \ref P1, \ref P2, \ref P3, \ref P4 or \ref P5.
* @param[in] u32Pin The pin of specified GPIO port. It could be 0 ~ 7.
*
* @return None
*
* @details This function is used to enable specified GPIO pin interrupt.
*/
void GPIO_DisableInt(GPIO_T *gpio, uint32_t u32Pin)
{
gpio->INTTYPE &= ~(1UL << u32Pin);
gpio->INTEN &= ~((0x00010001UL) << u32Pin);
}
/*@}*/ /* end of group Mini58_GPIO_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_GPIO_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,300 @@
/**************************************************************************//**
* @file i2c.c
* @version V1.00
* $Revision: 5 $
* $Date: 15/05/26 4:24p $
* @brief Mini58 series I2C driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "Mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_I2C_Driver I2C Driver
@{
*/
/** @addtogroup Mini58_I2C_EXPORTED_FUNCTIONS I2C Exported Functions
@{
*/
/**
* @brief This function make I2C module be ready and set the wanted bus clock.
* @param[in] i2c is the base address of I2C module.
* @param[in] u32BusClock is the target bus speed of I2C module.
* @return Actual I2C bus clock frequency.
*/
uint32_t I2C_Open(I2C_T *i2c, uint32_t u32BusClock)
{
uint32_t u32Div;
u32Div = (uint32_t) (((SystemCoreClock * 10)/(u32BusClock * 4) + 5) / 10 - 1); /* Compute proper divider for I2C clock */
i2c->CLKDIV = u32Div;
/* Enable I2C */
i2c->CTL |= I2C_CTL_I2CEN_Msk;
return ( SystemCoreClock / ((u32Div+1)<<2) );
}
/**
* @brief This function closes the I2C module.
* @param[in] i2c is the base address of I2C module.
* @return none
*/
void I2C_Close(I2C_T *i2c)
{
/* Reset SPI */
if(i2c == I2C0) {
SYS->IPRST1 |= SYS_IPRST1_I2C0RST_Msk;
SYS->IPRST1 &= ~SYS_IPRST1_I2C0RST_Msk;
} else {
SYS->IPRST1 |= SYS_IPRST1_I2C1RST_Msk;
SYS->IPRST1 &= ~SYS_IPRST1_I2C1RST_Msk;
}
/* Disable I2C */
i2c->CTL &= ~I2C_CTL_I2CEN_Msk;
}
/**
* @brief This function clears the timeout flag.
* @param[in] i2c is the base address of I2C module.
* @return none
*/
void I2C_ClearTimeoutFlag(I2C_T *i2c)
{
i2c->TOCTL |= I2C_TOCTL_TOIF_Msk;
}
/**
* @brief This function sets the control bit of the I2C module.
* @param[in] i2c is the base address of I2C module.
* @param[in] u8Start sets START bit to I2C module.
* @param[in] u8Stop sets STOP bit to I2C module.
* @param[in] u8Si sets SI bit to I2C module.
* @param[in] u8Ack sets ACK bit to I2C module.
* @return none
*/
void I2C_Trigger(I2C_T *i2c, uint8_t u8Start, uint8_t u8Stop, uint8_t u8Si, uint8_t u8Ack)
{
uint32_t u32Reg = 0;
if (u8Start)
u32Reg |= I2C_STA;
if (u8Stop)
u32Reg |= I2C_STO;
if (u8Si)
u32Reg |= I2C_SI;
if (u8Ack)
u32Reg |= I2C_AA;
i2c->CTL = (i2c->CTL & ~0x3C) | u32Reg;
}
/**
* @brief This function disables the interrupt (EI bit) of I2C module.
* @param[in] i2c is the base address of I2C module.
* @return none
*/
void I2C_DisableInt(I2C_T *i2c)
{
i2c->CTL &= ~I2C_CTL_INTEN_Msk;
}
/**
* @brief This function enables the interrupt (EI bit) of I2C module.
* @param[in] i2c is the base address of I2C module.
* @return none
*/
void I2C_EnableInt(I2C_T *i2c)
{
i2c->CTL |= I2C_CTL_INTEN_Msk;
}
/**
* @brief This function returns the real bus clock of I2C module.
* @param[in] i2c is the base address of I2C module.
* @return Actual I2C bus clock frequency.
*/
uint32_t I2C_GetBusClockFreq(I2C_T *i2c)
{
uint32_t u32Divider = i2c->CLKDIV;
return ( SystemCoreClock / ((u32Divider+1)<<2) );
}
/**
* @brief This function enables the interrupt (EI bit) of I2C module.
* @param[in] i2c is the base address of I2C module.
* @param[in] u32BusClock is the target bus speed of I2C module.
* @return Actual I2C bus clock frequency.
*/
uint32_t I2C_SetBusClockFreq(I2C_T *i2c, uint32_t u32BusClock)
{
uint32_t u32Div;
u32Div = (uint32_t) (((SystemCoreClock * 10)/(u32BusClock * 4) + 5) / 10 - 1); /* Compute proper divider for I2C clock */
i2c->CLKDIV = u32Div;
return ( SystemCoreClock / ((u32Div+1)<<2) );
}
/**
* @brief This function gets the interrupt flag (SI bit) of I2C module.
* @param[in] i2c is the base address of I2C module.
* @return Interrupt flag.
* @retval 0 Flag is not set.
* @retval 1 Flag is set.
*/
uint32_t I2C_GetIntFlag(I2C_T *i2c)
{
return ( (i2c->CTL & I2C_CTL_SI_Msk) == I2C_CTL_SI_Msk ? 1:0 );
}
/**
* @brief This function returns the status of I2C module.
* @param[in] i2c is the base address of I2C module.
* @return Status.
*/
uint32_t I2C_GetStatus(I2C_T *i2c)
{
return ( i2c->STATUS );
}
/**
* @brief This function returns the data stored in data register of I2C module.
* @param[in] i2c is the base address of I2C module.
* @return Data.
*/
uint32_t I2C_GetData(I2C_T *i2c)
{
return ( i2c->DAT );
}
/**
* @brief This function writes the data to data register of I2C module.
* @param[in] i2c is the base address of I2C module.
* @param[in] u8Data is the data which will be write to data register of I2C module.
* @return none
*/
void I2C_SetData(I2C_T *i2c, uint8_t u8Data)
{
i2c->DAT = u8Data;
}
/**
* @brief Configure slave address and enable GC mode.
* @param[in] i2c is the base address of I2C module.
* @param[in] u8SlaveNo is the set number of salve address.
* @param[in] u8SlaveAddr is the slave address.
* @param[in] u8GCMode enable GC mode.
* @return none
*/
void I2C_SetSlaveAddr(I2C_T *i2c, uint8_t u8SlaveNo, uint8_t u8SlaveAddr, uint8_t u8GCMode)
{
switch (u8SlaveNo) {
case 0:
i2c->ADDR0 = (u8SlaveAddr << 1) | u8GCMode;
break;
case 1:
i2c->ADDR1 = (u8SlaveAddr << 1) | u8GCMode;
break;
case 2:
i2c->ADDR2 = (u8SlaveAddr << 1) | u8GCMode;
break;
case 3:
i2c->ADDR3 = (u8SlaveAddr << 1) | u8GCMode;
break;
default:
i2c->ADDR0 = (u8SlaveAddr << 1) | u8GCMode;
}
}
/**
* @brief Configure the mask of slave address. The corresponding address bit is "Don't Care".
* @param[in] i2c is the base address of I2C module.
* @param[in] u8SlaveNo is the set number of salve address.
* @param[in] u8SlaveAddrMask is the slave address mask.
* @return none
*/
void I2C_SetSlaveAddrMask(I2C_T *i2c, uint8_t u8SlaveNo, uint8_t u8SlaveAddrMask)
{
switch (u8SlaveNo) {
case 0:
i2c->ADDRMSK0 = u8SlaveAddrMask << 1;
break;
case 1:
i2c->ADDRMSK1 = u8SlaveAddrMask << 1;
break;
case 2:
i2c->ADDRMSK2 = u8SlaveAddrMask << 1;
break;
case 3:
i2c->ADDRMSK3 = u8SlaveAddrMask << 1;
break;
default:
i2c->ADDRMSK0 = u8SlaveAddrMask << 1;
}
}
/**
* @brief This function enables timeout function and configures DIV4 function to support long timeout.
* @param[in] i2c is the base address of I2C module.
* @param[in] u8LongTimeout Enable timeout counter input clock is divide by 4.
* @return none.
*/
void I2C_EnableTimeout(I2C_T *i2c, uint8_t u8LongTimeout)
{
if(u8LongTimeout)
i2c->TOCTL |= I2C_TOCTL_TOCURIEN_Msk;
else
i2c->TOCTL &= ~I2C_TOCTL_TOCURIEN_Msk;
i2c->TOCTL |= I2C_TOCTL_TOCEN_Msk;
}
/**
* @brief This function disables timeout function.
* @param[in] i2c is the base address of I2C module.
* @return none.
*/
void I2C_DisableTimeout(I2C_T *i2c)
{
i2c->TOCTL &= ~I2C_TOCTL_TOCEN_Msk;
}
/**
* @brief This function enables the wakeup function of I2C module.
* @param[in] i2c is the base address of I2C module.
* @return none.
*/
void I2C_EnableWakeup(I2C_T *i2c)
{
if(i2c == I2C0) //only support for port0
i2c->CTL1 |= I2C_CTL1_WKEN_Msk;
}
/**
* @brief This function disables the wakeup function of I2C module.
* @param[in] i2c is the base address of I2C module.
* @return none.
*/
void I2C_DisableWakeup(I2C_T *i2c)
{
if(i2c == I2C0) //only support for port0
i2c->CTL1 &= ~I2C_CTL1_WKEN_Msk;
}
/*@}*/ /* end of group Mini58_I2C_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_I2C_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,573 @@
/**************************************************************************//**
* @file PWM.c
* @version V1.00
* $Revision: 4 $
* $Date: 15/06/05 1:43p $
* @brief Mini58 series PWM driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "Mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_PWM_Driver PWM Driver
@{
*/
/** @addtogroup Mini58_PWM_EXPORTED_FUNCTIONS PWM Exported Functions
@{
*/
/**
* @brief This function config PWM generator and get the nearest frequency in edge aligned auto-reload mode
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @param[in] u32Frequency Target generator frequency
* @param[in] u32DutyCycle Target generator duty cycle percentage. Valid range are between 0 ~ 100. 10 means 10%, 20 means 20%...
* @return Nearest frequency clock in nano second
* @note Since every two channels, (0 & 1), (2 & 3), (4 & 5), shares a prescaler. Call this API to configure PWM frequency may affect
* existing frequency of other channel.
*/
uint32_t PWM_ConfigOutputChannel (PWM_T *pwm,
uint32_t u32ChannelNum,
uint32_t u32Frequency,
uint32_t u32DutyCycle)
{
uint32_t i = SystemCoreClock / u32Frequency;
uint8_t u8Divider = 1, u8Prescale = 0xFF;
uint16_t u16CNR = 0xFFFF;
for(; u8Divider < 17; u8Divider <<= 1) { // clk divider could only be 1, 2, 4, 8, 16
i = (SystemCoreClock / u32Frequency) / u8Divider;
// If target value is larger than CNR * prescale, need to use a larger divider
if(i > (0x10000 * 0x100))
continue;
// CNR = 0xFFFF + 1, get a prescaler that CNR value is below 0xFFFF
u8Prescale = (i + 0xFFFF)/ 0x10000;
// u8Prescale must at least be 2, otherwise the output stop
if(u8Prescale < 3)
u8Prescale = 2;
i /= u8Prescale;
if(i <= 0x10000) {
if(i == 1)
u16CNR = 1; // Too fast, and PWM cannot generate expected frequency...
else
u16CNR = i;
break;
}
}
// Store return value here 'cos we're gonna change u8Divider & u8Prescale & u16CNR to the real value to fill into register
i = SystemCoreClock / (u8Prescale * u8Divider * u16CNR);
u8Prescale -= 1;
u16CNR -= 1;
// convert to real register value
if(u8Divider == 1)
u8Divider = 4;
else if (u8Divider == 2)
u8Divider = 0;
else if (u8Divider == 4)
u8Divider = 1;
else if (u8Divider == 8)
u8Divider = 2;
else // 16
u8Divider = 3;
// every two channels share a prescaler
PWM->CLKPSC = (PWM->CLKPSC & ~(PWM_CLKPSC_CLKPSC01_Msk << ((u32ChannelNum >> 1) * 8))) | (u8Prescale << ((u32ChannelNum >> 1) * 8));
PWM->CLKDIV = (PWM->CLKDIV & ~(PWM_CLKDIV_CLKDIV0_Msk << (4 * u32ChannelNum))) | (u8Divider << (4 * u32ChannelNum));
PWM->CTL = (PWM->CTL & ~PWM_CTL_CNTTYPE_Msk) | (PWM_CTL_CNTMODE0_Msk << ((4 * u32ChannelNum)));
if(u32DutyCycle == 0)
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CMPDAT0)) + u32ChannelNum * 4))) = 0;
else
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CMPDAT0)) + u32ChannelNum * 4))) = u32DutyCycle * (u16CNR + 1) / 100 - 1;
*((__IO uint32_t *)((((uint32_t) & ((pwm)->PERIOD0)) + (u32ChannelNum) * 4))) = u16CNR;
return(i);
}
/**
* @brief This function start PWM module
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Bit 0 is channel 0, bit 1 is channel 1...
* @return None
*/
void PWM_Start (PWM_T *pwm, uint32_t u32ChannelMask)
{
uint32_t u32Mask = 0, i;
for(i = 0; i < PWM_CHANNEL_NUM; i ++) {
if(u32ChannelMask & (1 << i)) {
u32Mask |= (PWM_CTL_CNTEN0_Msk << (i * 4));
}
}
PWM->CTL |= u32Mask;
}
/**
* @brief This function stop PWM module
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Bit 0 is channel 0, bit 1 is channel 1...
* @return None
*/
void PWM_Stop (PWM_T *pwm, uint32_t u32ChannelMask)
{
uint32_t i;
for(i = 0; i < PWM_CHANNEL_NUM; i ++) {
if(u32ChannelMask & (1 << i)) {
*((__IO uint32_t *)((((uint32_t) & ((pwm)->PERIOD0)) + (i) * 4))) = 0;
}
}
}
/**
* @brief This function stop PWM generation immediately by clear channel enable bit
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Bit 0 is channel 0, bit 1 is channel 1...
* @return None
*/
void PWM_ForceStop (PWM_T *pwm, uint32_t u32ChannelMask)
{
uint32_t u32Mask = 0, i;
for(i = 0; i < PWM_CHANNEL_NUM; i ++) {
if(u32ChannelMask & (1 << i)) {
u32Mask |= (PWM_CTL_CNTEN0_Msk << (i * 4));
}
}
PWM->CTL &= ~u32Mask;
}
/**
* @brief This function enable selected channel to trigger ADC
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @param[in] u32Condition The condition to trigger ADC. Combination of following conditions:
* - \ref PWM_TRIGGER_ADC_CNTR_IS_0
* - \ref PWM_TRIGGER_ADC_CNTR_IS_CMR_D
* - \ref PWM_TRIGGER_ADC_CNTR_IS_CNR
* - \ref PWM_TRIGGER_ADC_CNTR_IS_CMR_U
* @return None
*/
void PWM_EnableADCTrigger (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Condition)
{
if(u32ChannelNum < 4) {
PWM->ADCTCTL0 = (PWM->ADCTCTL0 & ~((PWM_TRIGGER_ADC_CNTR_IS_0 |
PWM_TRIGGER_ADC_CNTR_IS_CMR_D |
PWM_TRIGGER_ADC_CNTR_IS_CNR |
PWM_TRIGGER_ADC_CNTR_IS_CMR_U ) << (8 * u32ChannelNum))) | (u32Condition << (8 * u32ChannelNum));
} else {
PWM->ADCTCTL1 = (PWM->ADCTCTL1 & ~((PWM_TRIGGER_ADC_CNTR_IS_0 |
PWM_TRIGGER_ADC_CNTR_IS_CMR_D |
PWM_TRIGGER_ADC_CNTR_IS_CNR |
PWM_TRIGGER_ADC_CNTR_IS_CMR_U ) << (8 * (u32ChannelNum - 4)))) | (u32Condition << (8 * (u32ChannelNum - 4)));
}
}
/**
* @brief This function disable selected channel to trigger ADC
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_DisableADCTrigger (PWM_T *pwm, uint32_t u32ChannelNum)
{
if(u32ChannelNum < 4) {
PWM->ADCTCTL0 = (PWM->ADCTCTL0 & ~((PWM_TRIGGER_ADC_CNTR_IS_0 |
PWM_TRIGGER_ADC_CNTR_IS_CMR_D |
PWM_TRIGGER_ADC_CNTR_IS_CNR |
PWM_TRIGGER_ADC_CNTR_IS_CMR_U ) << (8 * u32ChannelNum)));
} else {
PWM->ADCTCTL1 = (PWM->ADCTCTL1 & ~((PWM_TRIGGER_ADC_CNTR_IS_0 |
PWM_TRIGGER_ADC_CNTR_IS_CMR_D |
PWM_TRIGGER_ADC_CNTR_IS_CNR |
PWM_TRIGGER_ADC_CNTR_IS_CMR_U ) << (8 * (u32ChannelNum - 4))));
}
}
/**
* @brief This function clear selected channel trigger ADC flag
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @param[in] u32Condition PWM triggered ADC flag to be cleared.
* @return None
*/
void PWM_ClearADCTriggerFlag (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Condition)
{
if(u32ChannelNum < 4) {
PWM->ADCTSTS0 |= (u32Condition << (8 * u32ChannelNum));
} else {
PWM->ADCTSTS1 |= (u32Condition << (8 * (u32ChannelNum - 4)));
}
}
/**
* @brief This function get selected channel trigger ADC flag
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @param[in] u32Condition PWM triggered ADC flag to be selected.
* @return Get status of the selected channel trigger ADC
*/
uint32_t PWM_GetADCTriggerFlag (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Condition)
{
if(u32ChannelNum < 4) {
return(PWM->ADCTSTS0 & (u32Condition << (8 * u32ChannelNum)) ? 1 : 0);
} else {
return(PWM->ADCTSTS1 & (u32Condition << (8 * (u32ChannelNum - 4))) ? 1 : 0);
}
}
/**
* @brief This function enable fault brake of selected channels
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelMask This parameter is not used
* @param[in] u32LevelMask Output high or low while fault brake occurs, each bit represent the level of a channel
* while fault brake occur. Bit 0 represents channel 0, bit 1 represents channel 1...
* , bit 6 represent D6, and bit 7 represents D7
* @param[in] u32BrakeSource Fault brake source, could be one of following source
* - \ref PWM_FB0_EINT0
* - \ref PWM_FB0_ACMP1
* - \ref PWM_FB1_EINT1
* - \ref PWM_FB1_ACMP0
* @return None
*/
void PWM_EnableFaultBrake (PWM_T *pwm,
uint32_t u32ChannelMask,
uint32_t u32LevelMask,
uint32_t u32BrakeSource)
{
PWM->BRKCTL = (u32LevelMask << PWM_BRKCTL_BKOD0_Pos) | u32BrakeSource;
}
/**
* @brief This function clear fault brake flag
* @param[in] pwm The base address of PWM module
* @param[in] u32BrakeSource This parameter is not used
* @return None
* @note After fault brake occurred, application must clear fault brake source before re-enable PWM output
*/
void PWM_ClearFaultBrakeFlag (PWM_T *pwm, uint32_t u32BrakeSource)
{
PWM->BRKCTL = PWM_BRKCTL_BRKSTS_Msk;
}
/**
* @brief This function enables PWM output generation of selected channels
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Set bit 0 to 1 enables channel 0 output, set bit 1 to 1 enables channel 1 output...
* @return None
*/
void PWM_EnableOutput (PWM_T *pwm, uint32_t u32ChannelMask)
{
PWM->POEN |= u32ChannelMask;
}
/**
* @brief This function disables PWM output generation of selected channels
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel
* Set bit 0 to 1 disables channel 0 output, set bit 1 to 1 disables channel 1 output...
* @return None
*/
void PWM_DisableOutput (PWM_T *pwm, uint32_t u32ChannelMask)
{
PWM->POEN &= ~u32ChannelMask;
}
/**
* @brief This function enable Dead zone of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @param[in] u32Duration Dead Zone length in PWM clock count, valid values are between 0~0xFF, but 0 means there is no
* dead zone.
* @return None
*/
void PWM_EnableDeadZone (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Duration)
{
// every two channels shares the same setting
u32ChannelNum >>= 1;
// set duration
PWM->DTCTL = (PWM->DTCTL & ~(PWM_DTCTL_DTI01_Msk << (8 * u32ChannelNum))) | (u32Duration << (8 * u32ChannelNum));
// enable dead zone
PWM->CTL |= (PWM_CTL_DTCNT01_Msk << u32ChannelNum);
}
/**
* @brief This function disable Dead zone of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_DisableDeadZone (PWM_T *pwm, uint32_t u32ChannelNum)
{
// every two channels shares the same setting
u32ChannelNum >>= 1;
// enable dead zone
PWM->CTL &= ~(PWM_CTL_DTCNT01_Msk << u32ChannelNum);
}
/**
* @brief This function enable duty interrupt of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @param[in] u32IntDutyType This parameter is not used
* @return None
*/
void PWM_EnableDutyInt (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32IntDutyType)
{
(pwm)->INTEN |= ((1 << PWM_INTEN_CMPDIEN0_Pos) << u32ChannelNum);
}
/**
* @brief This function disable duty interrupt of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_DisableDutyInt (PWM_T *pwm, uint32_t u32ChannelNum)
{
(pwm)->INTEN &= ~((1 << PWM_INTEN_CMPDIEN0_Pos) << u32ChannelNum);
}
/**
* @brief This function clears duty interrupt flag of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_ClearDutyIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
{
PWM->INTSTS = (PWM_INTSTS_CMPDIF0_Msk << u32ChannelNum);
}
/**
* @brief This function get duty interrupt flag of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return Duty interrupt flag of specified channel
* @retval 0 Duty interrupt did not occurred
* @retval 1 Duty interrupt occurred
*/
uint32_t PWM_GetDutyIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
{
return(PWM->INTSTS & (PWM_INTSTS_CMPDIF0_Msk << u32ChannelNum) ? 1 : 0);
}
/**
* @brief This function enable Period interrupt of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_EnablePeriodInt (PWM_T *pwm, uint32_t u32ChannelNum)
{
(pwm)->INTEN |= ((1 << PWM_INTEN_ZIEN0_Pos) << u32ChannelNum);
}
/**
* @brief This function disable Period interrupt of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_DisablePeriodInt (PWM_T *pwm, uint32_t u32ChannelNum)
{
(pwm)->INTEN &= ~((1 << PWM_INTEN_ZIEN0_Pos) << u32ChannelNum);
}
/**
* @brief This function clears Period interrupt flag of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_ClearPeriodIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
{
PWM->INTSTS = (PWM_INTSTS_ZIF0_Msk << u32ChannelNum);
}
/**
* @brief This function get Period interrupt flag of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return Period interrupt flag of specified channel
* @retval 0 Period interrupt did not occurred
* @retval 1 Period interrupt occurred
*/
uint32_t PWM_GetPeriodIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
{
return(PWM->INTSTS & (PWM_INTSTS_ZIF0_Msk << u32ChannelNum) ? 1 : 0);
}
/**
* @brief This function enable Rise interrupt of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_EnableRiseInt (PWM_T *pwm, uint32_t u32ChannelNum)
{
(pwm)->INTEN |= ((1 << PWM_INTEN_CMPUIEN0_Pos) << u32ChannelNum);
}
/**
* @brief This function disable Rise interrupt of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_DisableRiseInt (PWM_T *pwm, uint32_t u32ChannelNum)
{
(pwm)->INTEN &= ~((1 << PWM_INTEN_CMPUIEN0_Pos) << u32ChannelNum);
}
/**
* @brief This function clears Rise interrupt flag of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_ClearRiseIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
{
PWM->INTSTS = (PWM_INTSTS_CMPUIF0_Msk << u32ChannelNum);
}
/**
* @brief This function get Rise interrupt flag of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return Rise interrupt flag of specified channel
* @retval 0 Rise interrupt did not occurred
* @retval 1 Rise interrupt occurred
*/
uint32_t PWM_GetRiseIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
{
return(PWM->INTSTS & (PWM_INTSTS_CMPUIF0_Msk << u32ChannelNum) ? 1 : 0);
}
/**
* @brief This function enable fault brake interrupt
* @param[in] pwm The base address of PWM module
* @param[in] u32BrakeSource This parameter is not used
* @return None
*/
void PWM_EnableFaultBrakeInt (PWM_T *pwm, uint32_t u32BrakeSource)
{
PWM->INTEN |= PWM_INTEN_BRKIEN_Msk;
}
/**
* @brief This function disable fault brake interrupt
* @param[in] pwm The base address of PWM module
* @param[in] u32BrakeSource This parameter is not used
* @return None
*/
void PWM_DisableFaultBrakeInt (PWM_T *pwm, uint32_t u32BrakeSource)
{
PWM->INTEN &= ~PWM_INTEN_BRKIEN_Msk;
}
/**
* @brief This function clear fault brake interrupt of selected source
* @param[in] pwm The base address of PWM module
* @param[in] u32BrakeSource Fault brake source, could be either
* - \ref PWM_INTSTS_BRKIF0_Msk, or
* - \ref PWM_INTSTS_BRKIF1_Msk
* @return None
*/
void PWM_ClearFaultBrakeIntFlag (PWM_T *pwm, uint32_t u32BrakeSource)
{
PWM->INTSTS = u32BrakeSource;
}
/**
* @brief This function get fault brake interrupt of selected source
* @param[in] pwm The base address of PWM module
* @param[in] u32BrakeSource Fault brake source, could be either
* - \ref PWM_INTSTS_BRKIF0_Msk, or
* - \ref PWM_INTSTS_BRKIF1_Msk
* @return Fault brake interrupt flag of specified source
* @retval 0 Fault brake interrupt did not occurred
* @retval 1 Fault brake interrupt occurred
*/
uint32_t PWM_GetFaultBrakeIntFlag (PWM_T *pwm, uint32_t u32BrakeSource)
{
return (PWM->INTSTS & u32BrakeSource ? 1 : 0);
}
/**
* @brief This function enable Central interrupt of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @param[in] u32IntPeriodType Period interrupt type, could be either
* - \ref PWM_PERIOD_INT_UNDERFLOW
* - \ref PWM_PERIOD_INT_MATCH_CNR
* @return None
* @note All channels share the same Central interrupt type setting.
*/
void PWM_EnableCenterInt (PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32IntPeriodType)
{
PWM->INTEN = (PWM->INTEN & ~PWM_INTEN_PINTTYPE_Msk & ~(PWM_INTEN_PIEN0_Msk << u32ChannelNum)) | (PWM_INTEN_PIEN0_Msk << u32ChannelNum) | u32IntPeriodType;
}
/**
* @brief This function disable Central interrupt of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_DisableCenterInt (PWM_T *pwm, uint32_t u32ChannelNum)
{
PWM->INTEN &= ~(PWM_INTEN_PIEN0_Msk << u32ChannelNum);
}
/**
* @brief This function clear Central interrupt of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return None
*/
void PWM_ClearCenterIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
{
PWM->INTSTS = (PWM_INTSTS_PIF0_Msk << u32ChannelNum);
}
/**
* @brief This function get Central interrupt of selected channel
* @param[in] pwm The base address of PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~5
* @return Central interrupt flag of specified channel
* @retval 0 Central interrupt did not occurred
* @retval 1 Central interrupt occurred
*/
uint32_t PWM_GetCenterIntFlag (PWM_T *pwm, uint32_t u32ChannelNum)
{
return(PWM->INTSTS & (PWM_INTSTS_PIF0_Msk << u32ChannelNum) ? 1 : 0);
}
/*@}*/ /* end of group Mini58_PWM_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_PWM_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,493 @@
/**************************************************************************//**
* @file retarget.c
* @version V1.00
* $Revision: 4 $
* $Date: 15/11/02 2:11p $
* @brief Mini58 series retarget source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include "Mini58Series.h"
#if defined ( __CC_ARM )
#if (__ARMCC_VERSION < 400000)
#else
/* Insist on keeping widthprec, to avoid X propagation by benign code in C-lib */
#pragma import _printf_widthprec
#endif
#endif
#ifdef DEBUG_ENABLE_UART1
#define DEBUG_PORT UART1
#else
#define DEBUG_PORT UART0
#endif
/* Un-comment this line to disable all printf and getchar. getchar() will always return 0x00*/
//#define DISABLE_UART
#if defined(DEBUG_ENABLE_SEMIHOST)
#ifndef DISABLE_UART
#define DISABLE_UART
#endif
#endif
/*---------------------------------------------------------------------------------------------------------*/
/* Global variables */
/*---------------------------------------------------------------------------------------------------------*/
#if !(defined(__ICCARM__) && (__VER__ >= 6010000))
struct __FILE { int handle; /* Add whatever you need here */ };
#endif
FILE __stdout;
FILE __stdin;
enum { r0, r1, r2, r3, r12, lr, pc, psr};
void stackDump(uint32_t stack[])
{
printf("r0 = 0x%x\n", stack[r0]);
printf("r1 = 0x%x\n", stack[r1]);
printf("r2 = 0x%x\n", stack[r2]);
printf("r3 = 0x%x\n", stack[r3]);
printf("r12 = 0x%x\n", stack[r12]);
printf("lr = 0x%x\n", stack[lr]);
printf("pc = 0x%x\n", stack[pc]);
printf("psr = 0x%x\n", stack[psr]);
}
void Hard_Fault_Handler(uint32_t stack[])
{
printf("In Hard Fault Handler\n");
stackDump(stack);
//Chip Reset
//SYS_UnlockReg();
//SYS->IPRSTC1 |= SYS_IPRSTC1_CHIP_RST_Msk;
while(1);
}
#if defined(DEBUG_ENABLE_SEMIHOST)
/* The static buffer is used to speed up the semihost */
static char g_buf[16];
static char g_buf_len = 0;
# if defined(__ICCARM__)
/**
* @brief This HardFault handler is implemented to support semihost
*
* @param None
*
* @returns None
*
* @details This function is implement to support semihost message print.
*
*/
void HardFault_Handler(void)
{
asm("MOV R0, lr \n"
"LSLS R0, #29 \n" //; Check bit 2
"BMI SP_is_PSP \n" //; previous stack is PSP
"MRS R0, MSP \n" //; previous stack is MSP, read MSP
"B SP_Read_Ready \n"
"SP_is_PSP: \n"
"MRS R0, PSP \n" //; Read PSP
"SP_Read_Ready: \n"
"LDR R1, [R0, #24] \n" //; Get previous PC
"LDRH R3, [R1] \n" //; Get instruction
"LDR R2, [pc, #8] \n" //; The special BKPT instruction
"CMP R3, R2 \n" //; Test if the instruction at previous PC is BKPT
"BNE HardFault_Handler_Ret\n" //; Not BKPT
"ADDS R1, #4 \n" //; Skip BKPT and next line
"STR R1, [R0, #24] \n" //; Save previous PC
"BX lr \n" //; Return
"DCD 0xBEAB \n" //; BKPT instruction code
"HardFault_Handler_Ret:\n"
"MOVS r0, #4 \n"
"MOV r1, LR \n"
"TST r0, r1 \n"
"BEQ Stack_Use_MSP \n"
"MRS R0, PSP \n" //; stack use PSP
"B Get_LR_and_Branch \n"
"Stack_Use_MSP: \n"
"MRS R0, MSP \n" //; stack use MSP
"Get_LR_and_Branch: \n"
"MOV R1, LR \n" //; LR current value
"B Hard_Fault_Handler \n"
);
while(1);
}
/**
*
* @brief The function to process semihosted command
* @param[in] n32In_R0 : semihost register 0
* @param[in] n32In_R1 : semihost register 1
* @param[out] pn32Out_R0: semihost register 0
* @retval 0: No ICE debug
* @retval 1: ICE debug
*
*/
int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
{
asm("BKPT 0xAB \n" //; This instruction will cause ICE trap or system HardFault
"B SH_ICE \n"
"SH_HardFault: \n" //; Captured by HardFault
"MOVS R0, #0 \n" //; Set return value to 0
"BX lr \n" //; Return
"SH_ICE: \n" //; Captured by ICE
"CMP R2, #0 \n"
"BEQ SH_End \n"
"STR R0, [R2]\n" //; Save the return value to *pn32Out_R0
"SH_End: \n");
return 1; //; Return 1 when it is trap by ICE
}
# else
/**
* @brief This HardFault handler is implemented to support semihost
*
* @param None
*
* @returns None
*
* @details This function is implement to support semihost message print.
*
*/
__asm int32_t HardFault_Handler(void)
{
MOV R0, LR
LSLS R0, #29 //; Check bit 2
BMI SP_is_PSP //; previous stack is PSP
MRS R0, MSP //; previous stack is MSP, read MSP
B SP_Read_Ready
SP_is_PSP
MRS R0, PSP //; Read PSP
SP_Read_Ready
LDR R1, [R0, #24] //; Get previous PC
LDRH R3, [R1] //; Get instruction
LDR R2, =0xBEAB //; The special BKPT instruction
CMP R3, R2 //; Test if the instruction at previous PC is BKPT
BNE HardFault_Handler_Ret //; Not BKPT
ADDS R1, #4 //; Skip BKPT and next line
STR R1, [R0, #24] //; Save previous PC
BX LR //; Return
HardFault_Handler_Ret
/* TODO: Implement your own hard fault handler here. */
MOVS r0, #4
MOV r1, LR
TST r0, r1
BEQ Stack_Use_MSP
MRS R0, PSP ;stack use PSP
B Get_LR_and_Branch
Stack_Use_MSP
MRS R0, MSP ; stack use MSP
Get_LR_and_Branch
MOV R1, LR ; LR current value
LDR R2,=__cpp(Hard_Fault_Handler)
BX R2
B .
ALIGN
}
/**
*
* @brief The function to process semihosted command
* @param[in] n32In_R0 : semihost register 0
* @param[in] n32In_R1 : semihost register 1
* @param[out] pn32Out_R0: semihost register 0
* @retval 0: No ICE debug
* @retval 1: ICE debug
*
*/
__asm int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
{
BKPT 0xAB //; Wait ICE or HardFault
//; ICE will step over BKPT directly
//; HardFault will step BKPT and the next line
B SH_ICE
SH_HardFault //; Captured by HardFault
MOVS R0, #0 //; Set return value to 0
BX lr //; Return
SH_ICE //; Captured by ICE
//; Save return value
CMP R2, #0
BEQ SH_End
STR R0, [R2] //; Save the return value to *pn32Out_R0
SH_End
MOVS R0, #1 //; Set return value to 1
BX lr //; Return
}
#endif
#else
# if defined(__ICCARM__)
/**
* @brief This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
*
* @param None
*
* @returns None
*
* @details This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
*
*/
void HardFault_Handler(void)
{
asm("MOVS r0, #4 \n"
"MOV r1, LR \n"
"TST r0, r1 \n"
"BEQ Stack_Use_MSP \n"
"MRS R0, PSP \n" //; stack use PSP
"B Get_LR_and_Branch \n"
"Stack_Use_MSP: \n"
"MRS R0, MSP \n" //; stack use MSP
"Get_LR_and_Branch: \n"
"MOV R1, LR \n" //; LR current value
"B Hard_Fault_Handler \n"
);
while(1);
}
# else
/**
* @brief This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
*
* @param None
*
* @returns None
*
* @details This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr
*
*/
__asm int32_t HardFault_Handler(void)
{
MOVS r0, #4
MOV r1, LR
TST r0, r1
BEQ Stack_Use_MSP
MRS R0, PSP ;stack use PSP
B Get_LR_and_Branch
Stack_Use_MSP
MRS R0, MSP ; stack use MSP
Get_LR_and_Branch
MOV R1, LR ; LR current value
LDR R2,=__cpp(Hard_Fault_Handler)
BX R2
}
#endif
#endif
/**
* @brief Write a char to UART.
* @param ch The character sent to UART.
* @return None
*/
void SendChar_ToUART(int ch)
{
#ifndef DISABLE_UART
while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
DEBUG_PORT->DAT = ch;
if(ch == '\n'){
while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
DEBUG_PORT->DAT = '\r';
}
#endif
}
/**
* @brief Write a char to debug console.
* @param ch The character sent to debug console
* @return None
*/
void SendChar(int ch)
{
#if defined(DEBUG_ENABLE_SEMIHOST)
g_buf[g_buf_len++] = ch;
g_buf[g_buf_len] = '\0';
if(g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0')
{
/* Send the char */
if(SH_DoCommand(0x04, (int)g_buf, NULL) != 0)
{
g_buf_len = 0;
return;
}
else
{
int i;
for(i=0;i<g_buf_len;i++)
SendChar_ToUART(g_buf[i]);
g_buf_len = 0;
}
}
#else
SendChar_ToUART(ch);
#endif
}
/**
* @brief Read a char from debug console.
* @param None
* @return Received character from debug console
* @note This API waits until UART debug port or semihost input a character
*/
char GetChar(void)
{
#if defined(DEBUG_ENABLE_SEMIHOST)
# if defined ( __CC_ARM )
int nRet;
while(SH_DoCommand(0x101, 0, &nRet) != 0)
{
if(nRet != 0)
{
SH_DoCommand(0x07, 0, &nRet);
return (char)nRet;
}
}
# else
int nRet;
while(SH_DoCommand(0x7, 0, &nRet) != 0)
{
if(nRet != 0)
return (char)nRet;
}
# endif
#endif
#ifndef DISABLE_UART
while (1){
if(!(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk))
{
return (DEBUG_PORT->DAT);
}
}
#else
return(0);
#endif
}
/**
* @brief Check whether UART receive FIFO is empty or not.
* @param None
* @return UART Rx FIFO empty status
* @retval 1 Indicates at least one character is available in UART Rx FIFO
* @retval 0 UART Rx FIFO is empty
*/
int kbhit(void)
{
#ifndef DISABLE_UART
return !(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk);
#else
return(0);
#endif
}
/**
* @brief Check whether UART transmit FIFO is empty or not.
* @param None
* @return UART Tx FIFO empty status
* @retval 1 UART Tx FIFO is empty
* @retval 0 UART Tx FIFO is not empty
*/
int IsDebugFifoEmpty(void)
{
#ifndef DISABLE_UART
return (DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXEMPTYF_Msk) ? 1 : 0;
#else
return(1);
#endif
}
/*---------------------------------------------------------------------------------------------------------*/
/* C library retargetting */
/*---------------------------------------------------------------------------------------------------------*/
void _ttywrch(int ch)
{
SendChar(ch);
return;
}
int fputc(int ch, FILE *f)
{
SendChar(ch);
return ch;
}
int fgetc(FILE *f) {
return (GetChar());
}
int ferror(FILE *f) {
return EOF;
}
#ifdef DEBUG_ENABLE_SEMIHOST
# ifdef __ICCARM__
void __exit(int return_code) {
/* Check if link with ICE */
if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
{
/* Make sure all message is print out */
while(IsDebugFifoEmpty() == 0);
}
label: goto label; /* endless loop */
}
# else
void _sys_exit(int return_code) {
/* Check if link with ICE */
if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
{
/* Make sure all message is print out */
while(IsDebugFifoEmpty() == 0);
}
label: goto label; /* endless loop */
}
# endif
#endif
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,260 @@
/**************************************************************************//**
* @file spi.c
* @version V1.00
* $Revision: 7 $
* $Date: 15/05/28 1:47p $
* @brief Mini58 series SPI driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "Mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_SPI_Driver SPI Driver
@{
*/
/** @addtogroup Mini58_SPI_EXPORTED_FUNCTIONS SPI Exported Functions
@{
*/
/**
* @brief This function make SPI module be ready to transfer.
* By default, the SPI transfer sequence is MSB first and
* the automatic slave select function is disabled. In
* Slave mode, the u32BusClock must be NULL and the SPI clock
* divider setting will be 0.
* @param[in] spi is the base address of SPI module.
* @param[in] u32MasterSlave decides the SPI module is operating in master mode or in slave mode. ( \ref SPI_SLAVE, \ref SPI_MASTER)
* @param[in] u32SPIMode decides the transfer timing. ( \ref SPI_MODE_0, \ref SPI_MODE_1, \ref SPI_MODE_2, \ref SPI_MODE_3)
* @param[in] u32DataWidth decides the data width of a SPI transaction.
* @param[in] u32BusClock is the expected frequency of SPI bus clock in Hz.
* @return Actual frequency of SPI peripheral clock.
*/
uint32_t SPI_Open(SPI_T *spi,
uint32_t u32MasterSlave,
uint32_t u32SPIMode,
uint32_t u32DataWidth,
uint32_t u32BusClock)
{
if(u32DataWidth == 32)
u32DataWidth = 0;
spi->CTL = u32MasterSlave | (u32DataWidth << SPI_CTL_DWIDTH_Pos) | (u32SPIMode);
if(u32MasterSlave == SPI_SLAVE)
spi->SSCTL = SPI_SSCTL_SSLTEN_Msk;
return ( SPI_SetBusClock(spi, u32BusClock) );
}
/**
* @brief Reset SPI module and disable SPI peripheral clock.
* @param[in] spi is the base address of SPI module.
* @return none
*/
void SPI_Close(SPI_T *spi)
{
/* Reset SPI */
SYS->IPRST1 |= SYS_IPRST1_SPI0RST_Msk;
SYS->IPRST1 &= ~SYS_IPRST1_SPI0RST_Msk;
}
/**
* @brief Clear Rx FIFO buffer.
* @param[in] spi is the base address of SPI module.
* @return none
*/
void SPI_ClearRxFIFO(SPI_T *spi)
{
spi->FIFOCTL |= SPI_FIFOCTL_RXRST_Msk;
}
/**
* @brief Clear Tx FIFO buffer.
* @param[in] spi is the base address of SPI module.
* @return none
*/
void SPI_ClearTxFIFO(SPI_T *spi)
{
spi->FIFOCTL |= SPI_FIFOCTL_TXRST_Msk;
}
/**
* @brief Disable the automatic slave select function.
* @param[in] spi is the base address of SPI module.
* @return none
*/
void SPI_DisableAutoSS(SPI_T *spi)
{
spi->SSCTL &= ~SPI_SSCTL_AUTOSS_Msk;
}
/**
* @brief Enable the automatic slave select function. Only available in Master mode.
* @param[in] spi is the base address of SPI module.
* @param[in] u32SSPinMask specifies slave select pins. ( \ref SPI_SS)
* @param[in] u32ActiveLevel specifies the active level of slave select signal. ( \ref SPI_SS_ACTIVE_HIGH, \ref SPI_SS_ACTIVE_LOW)
* @return none
*/
void SPI_EnableAutoSS(SPI_T *spi, uint32_t u32SSPinMask, uint32_t u32ActiveLevel)
{
spi->SSCTL = (spi->SSCTL & ~(SPI_SSCTL_SSACTPOL_Msk | SPI_SSCTL_SS_Msk)) | (u32SSPinMask | u32ActiveLevel) | SPI_SSCTL_AUTOSS_Msk;
}
/**
* @brief Set the SPI bus clock. Only available in Master mode.
* @param[in] spi is the base address of SPI module.
* @param[in] u32BusClock is the expected frequency of SPI bus clock.
* @return Actual frequency of SPI peripheral clock.
*/
uint32_t SPI_SetBusClock(SPI_T *spi, uint32_t u32BusClock)
{
uint32_t u32Div = 0;
uint32_t u32ClkSrc;
if((CLK->CLKSEL1 & CLK_CLKSEL1_SPISEL_Msk) == CLK_CLKSEL1_SPISEL_XTAL) {
if((u32ClkSrc = CLK_GetHXTFreq()) == 0)
u32ClkSrc = CLK_GetLXTFreq();
} else if((CLK->CLKSEL1 & CLK_CLKSEL1_SPISEL_Msk) == CLK_CLKSEL1_SPISEL_PLL)
u32ClkSrc = CLK_GetPLLClockFreq();
else
u32ClkSrc = CLK_GetHCLKFreq();
if(u32BusClock > u32ClkSrc)
u32BusClock = u32ClkSrc;
if(u32BusClock != 0) {
u32Div = (((u32ClkSrc / u32BusClock) + 1) >> 1) - 1;
if(u32Div > SPI_CLKDIV_DIVIDER_Msk)
u32Div = SPI_CLKDIV_DIVIDER_Msk;
} else
return 0;
spi->CLKDIV = (spi->CLKDIV & ~SPI_CLKDIV_DIVIDER_Msk) | u32Div;
return ( u32ClkSrc / ((u32Div+1)*2) );
}
/**
* @brief Enable FIFO mode with user-specified Tx FIFO threshold and Rx FIFO threshold configurations.
* @param[in] spi is the base address of SPI module.
* @param[in] u32TxThreshold decides the Tx FIFO threshold.
* @param[in] u32RxThreshold decides the Rx FIFO threshold.
* @return none
*/
void SPI_EnableFIFO(SPI_T *spi, uint32_t u32TxThreshold, uint32_t u32RxThreshold)
{
spi->FIFOCTL = (spi->FIFOCTL & ~(SPI_FIFOCTL_TXTH_Msk | SPI_FIFOCTL_RXTH_Msk) |
(u32TxThreshold << SPI_FIFOCTL_TXTH_Pos) |
(u32RxThreshold << SPI_FIFOCTL_RXTH_Pos));
spi->CTL |= SPI_CTL_FIFOEN_Msk;
}
/**
* @brief Disable FIFO mode.
* @param[in] spi is the base address of SPI module.
* @return none
*/
void SPI_DisableFIFO(SPI_T *spi)
{
spi->CTL &= ~SPI_CTL_FIFOEN_Msk;
}
/**
* @brief Get the actual frequency of SPI bus clock. Only available in Master mode.
* @param[in] spi is the base address of SPI module.
* @return Actual SPI bus clock frequency.
*/
uint32_t SPI_GetBusClock(SPI_T *spi)
{
uint32_t u32Div;
uint32_t u32ClkSrc;
if((CLK->CLKSEL1 & CLK_CLKSEL1_SPISEL_Msk) == CLK_CLKSEL1_SPISEL_XTAL) {
if((u32ClkSrc = CLK_GetHXTFreq()) == 0)
u32ClkSrc = CLK_GetLXTFreq();
} else if((CLK->CLKSEL1 & CLK_CLKSEL1_SPISEL_Msk) == CLK_CLKSEL1_SPISEL_PLL)
u32ClkSrc = CLK_GetPLLClockFreq();
else
u32ClkSrc = CLK_GetHCLKFreq();
u32Div = spi->CLKDIV & SPI_CLKDIV_DIVIDER_Msk;
return ( u32ClkSrc / ((u32Div + 1)*2) );
}
/**
* @brief Enable FIFO related interrupts specified by u32Mask parameter.
* @param[in] spi is the base address of SPI module.
* @param[in] u32Mask is the combination of all related interrupt enable bits.
* Each bit corresponds to a interrupt bit.
* This parameter decides which interrupts will be enabled.
* ( \ref SPI_IE_MASK, \ref SPI_SSTA_INTEN_MASK, \ref SPI_FIFO_TX_INTEN_MASK,
* \ref SPI_FIFO_RX_INTEN_MASK, \ref SPI_FIFO_RXOV_INTEN_MASK, \ref SPI_FIFO_TIMEOUT_INTEN_MASK)
* @return none
*/
void SPI_EnableInt(SPI_T *spi, uint32_t u32Mask)
{
if((u32Mask & SPI_IE_MASK) == SPI_IE_MASK)
spi->CTL |= SPI_CTL_UNITIEN_Msk;
if((u32Mask & SPI_SSTA_INTEN_MASK) == SPI_SSTA_INTEN_MASK)
spi->SLVCTL |= SPI_SLVCTL_SLVSTIEN_Msk;
if((u32Mask & SPI_FIFO_TX_INTEN_MASK) == SPI_FIFO_TX_INTEN_MASK)
spi->FIFOCTL |= SPI_FIFOCTL_TXTHIEN_Msk;
if((u32Mask & SPI_FIFO_RX_INTEN_MASK) == SPI_FIFO_RX_INTEN_MASK)
spi->FIFOCTL |= SPI_FIFOCTL_RXTHIEN_Msk;
if((u32Mask & SPI_FIFO_RXOV_INTEN_MASK) == SPI_FIFO_RXOV_INTEN_MASK)
spi->FIFOCTL |= SPI_FIFOCTL_RXOVIEN_Msk;
if((u32Mask & SPI_FIFO_TIMEOUT_INTEN_MASK) == SPI_FIFO_TIMEOUT_INTEN_MASK)
spi->FIFOCTL |= SPI_FIFOCTL_RXTOIEN_Msk;
}
/**
* @brief Disable FIFO related interrupts specified by u32Mask parameter.
* @param[in] spi is the base address of SPI module.
* @param[in] u32Mask is the combination of all related interrupt enable bits.
* Each bit corresponds to a interrupt bit.
* This parameter decides which interrupts will be disabled.
* ( \ref SPI_IE_MASK, \ref SPI_SSTA_INTEN_MASK, \ref SPI_FIFO_TX_INTEN_MASK,
* \ref SPI_FIFO_RX_INTEN_MASK, \ref SPI_FIFO_RXOV_INTEN_MASK, \ref SPI_FIFO_TIMEOUT_INTEN_MASK)
* @return none
*/
void SPI_DisableInt(SPI_T *spi, uint32_t u32Mask)
{
if((u32Mask & SPI_IE_MASK) == SPI_IE_MASK)
spi->CTL &= ~SPI_CTL_UNITIEN_Msk;
if((u32Mask & SPI_SSTA_INTEN_MASK) == SPI_SSTA_INTEN_MASK)
spi->SLVCTL &= ~SPI_SLVCTL_SLVSTIEN_Msk;
if((u32Mask & SPI_FIFO_TX_INTEN_MASK) == SPI_FIFO_TX_INTEN_MASK)
spi->FIFOCTL &= ~SPI_FIFOCTL_TXTHIEN_Msk;
if((u32Mask & SPI_FIFO_RX_INTEN_MASK) == SPI_FIFO_RX_INTEN_MASK)
spi->FIFOCTL &= ~SPI_FIFOCTL_RXTHIEN_Msk;
if((u32Mask & SPI_FIFO_RXOV_INTEN_MASK) == SPI_FIFO_RXOV_INTEN_MASK)
spi->FIFOCTL &= ~SPI_FIFOCTL_RXOVIEN_Msk;
if((u32Mask & SPI_FIFO_TIMEOUT_INTEN_MASK) == SPI_FIFO_TIMEOUT_INTEN_MASK)
spi->FIFOCTL &= ~SPI_FIFOCTL_RXTOIEN_Msk;
}
/*@}*/ /* end of group Mini58_SPI_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_SPI_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,153 @@
/**************************************************************************//**
* @file sys.c
* @version V1.00
* $Revision: 9 $
* $Date: 15/06/05 1:13p $
* @brief Mini58 series SYS driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "Mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_SYS_Driver SYS Driver
@{
*/
/** @addtogroup Mini58_SYS_EXPORTED_FUNCTIONS SYS Exported Functions
@{
*/
/**
* @brief This function clear the selected system reset source
* @param[in] u32Src is system reset source
* @return None
*/
void SYS_ClearResetSrc(uint32_t u32Src)
{
SYS->RSTSTS |= u32Src;
}
/**
* @brief This function get Brown-out detector output status
* @return 0: System voltage is higher than BOD_VL setting or BOD_EN is 0.
* 1: System voltage is lower than BOD_VL setting.
* Note : If the BOD_EN is 0, this function always return 0.
*/
uint32_t SYS_GetBODStatus(void)
{
return (SYS->BODCTL & SYS_BODCTL_BODOUT_Msk)?1:0;
}
/**
* @brief This function get the system reset source register value
* @return Reset source
*/
uint32_t SYS_GetResetSrc(void)
{
return (SYS->RSTSTS);
}
/**
* @brief This function check register write-protection bit setting
* @return 0: Write-protection function is disabled.
* 1: Write-protection function is enabled.
*/
uint32_t SYS_IsRegLocked(void)
{
return !(SYS->REGLCTL & SYS_REGLCTL_REGLCTL_Msk);
}
/**
* @brief This function get product ID.
* @return Product ID
*/
uint32_t SYS_ReadPDID(void)
{
return SYS->PDID;
}
/**
* @brief This function reset chip.
* @return None
*/
void SYS_ResetChip(void)
{
SYS->IPRST0 |= SYS_IPRST0_CHIPRST_Msk;
}
/**
* @brief This function reset CPU.
* @return None
*/
void SYS_ResetCPU(void)
{
SYS->IPRST0 |= SYS_IPRST0_CPURST_Msk;
}
/**
* @brief This function reset selected modules.
* @param[in] u32ModuleIndex is module index. Including :
* - \ref ADC_RST
* - \ref ACMP_RST
* - \ref PWM0_RST
* - \ref UART0_RST
* - \ref UART1_RST
* - \ref SPI0_RST
* - \ref I2C0_RST
* - \ref I2C1_RST
* - \ref TMR1_RST
* - \ref TMR0_RST
* - \ref GPIO_RST
* @return None
*/
void SYS_ResetModule(uint32_t u32ModuleIndex)
{
*(volatile uint32_t *)(&(SYS->IPRST0) + (u32ModuleIndex>>24)) |= 1<<(u32ModuleIndex & 0x00ffffff);
*(volatile uint32_t *)(&(SYS->IPRST0) + (u32ModuleIndex>>24)) &= ~(1<<(u32ModuleIndex & 0x00ffffff));
}
/**
* @brief This function configure BOD function.
* Configure BOD reset or interrupt mode and set Brown-out voltage level.
* Enable Brown-out function
* @param[in] i32Mode is reset or interrupt mode. Including :
* - \ref SYS_BODCTL_BOD_RST_EN
* - \ref SYS_BODCTL_BOD_INTERRUPT_EN
* @param[in] u32BODLevel is Brown-out voltage level. Including :
* - \ref SYS_BODCTL_BODVL_4_4V
* - \ref SYS_BODCTL_BODVL_3_7V
* - \ref SYS_BODCTL_BODVL_2_7V
* - \ref SYS_BODCTL_BODVL_2_2V
* @return None
*/
void SYS_EnableBOD(int32_t i32Mode, uint32_t u32BODLevel)
{
SYS->BODCTL |= SYS_BODCTL_BODEN_Msk;
SYS->BODCTL = (SYS->BODCTL & ~SYS_BODCTL_BODRSTEN_Msk) | i32Mode;
SYS->BODCTL = (SYS->BODCTL & ~SYS_BODCTL_BODVL_Msk) | u32BODLevel;
}
/**
* @brief This function disable BOD function.
* @return None
*/
void SYS_DisableBOD(void)
{
SYS->BODCTL &= ~SYS_BODCTL_BODEN_Msk;
SYS->BODCTL = (SYS->BODCTL & ~SYS_BODCTL_BODVL_Msk) | SYS_BODCTL_BODVL_Msk ;
}
/*@}*/ /* end of group Mini58_SYS_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_SYS_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,217 @@
/**************************************************************************//**
* @file timer.c
* @version V1.00
* $Revision: 3 $
* $Date: 15/05/27 11:56a $
* @brief Mini58 series TIMER driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "Mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_TIMER_Driver TIMER Driver
@{
*/
/** @addtogroup Mini58_TIMER_EXPORTED_FUNCTIONS TIMER Exported Functions
@{
*/
/**
* @brief This API is used to configure timer to operate in specified mode
* and frequency. If timer cannot work in target frequency, a closest
* frequency will be chose and returned.
* @param[in] timer The base address of Timer module
* @param[in] u32Mode Operation mode. Possible options are
* - \ref TIMER_ONESHOT_MODE
* - \ref TIMER_PERIODIC_MODE
* - \ref TIMER_TOGGLE_MODE
* - \ref TIMER_CONTINUOUS_MODE
* @param[in] u32Freq Target working frequency
* @return Real Timer working frequency
* @note After calling this API, Timer is \b NOT running yet. But could start timer running be calling
* \ref TIMER_Start macro or program registers directly
*/
uint32_t TIMER_Open(TIMER_T *timer, uint32_t u32Mode, uint32_t u32Freq)
{
uint32_t u32Clk = TIMER_GetModuleClock(timer);
uint32_t u32Cmpr = 0, u32Prescale = 0;
// Fastest possible timer working freq is u32Clk / 2. While cmpr = 2, pre-scale = 0
if(u32Freq > (u32Clk / 2)) {
u32Cmpr = 2;
} else {
if(u32Clk >= 0x2000000) {
u32Prescale = 3; // real prescaler value is 4
u32Clk >>= 2;
} else if(u32Clk >= 0x1000000) {
u32Prescale = 1; // real prescaler value is 2
u32Clk >>= 1;
}
u32Cmpr = u32Clk / u32Freq;
}
timer->CTL = u32Mode | u32Prescale;
timer->CMP = u32Cmpr;
return(u32Clk / (u32Cmpr * (u32Prescale + 1)));
}
/**
* @brief This API stops Timer counting and disable the Timer interrupt function
* @param[in] timer The base address of Timer module
* @return None
*/
void TIMER_Close(TIMER_T *timer)
{
timer->CTL = 0;
timer->EXTCTL = 0;
}
/**
* @brief This API is used to create a delay loop for u32usec micro seconds
* @param[in] timer The base address of Timer module
* @param[in] u32Usec Delay period in micro seconds with 10 usec every step. Valid values are between 10~1000000 (10 micro second ~ 1 second)
* @return None
* @note This API overwrites the register setting of the timer used to count the delay time.
* @note This API use polling mode. So there is no need to enable interrupt for the timer module used to generate delay
*/
void TIMER_Delay(TIMER_T *timer, uint32_t u32Usec)
{
uint32_t u32Clk = TIMER_GetModuleClock(timer);
uint32_t u32Prescale = 0, delay = SystemCoreClock / u32Clk;
float fCmpr;
// Clear current timer configuration
timer->CTL = 0;
timer->EXTCTL = 0;
if(u32Clk == 10000) { // min delay is 100us if timer clock source is LIRC 10k
u32Usec = ((u32Usec + 99) / 100) * 100;
} else { // 10 usec every step
u32Usec = ((u32Usec + 9) / 10) * 10;
}
if(u32Clk >= 0x2000000) {
u32Prescale = 3; // real prescaler value is 4
u32Clk >>= 2;
} else if(u32Clk >= 0x1000000) {
u32Prescale = 1; // real prescaler value is 2
u32Clk >>= 1;
}
// u32Usec * u32Clk might overflow if using uint32_t
fCmpr = ((float)u32Usec * (float)u32Clk) / 1000000.0;
timer->CMP = (uint32_t)fCmpr;
timer->CTL = TIMER_CTL_CNTEN_Msk | u32Prescale; // one shot mode
// When system clock is faster than timer clock, it is possible timer active bit cannot set in time while we check it.
// And the while loop below return immediately, so put a tiny delay here allowing timer start counting and raise active flag.
for(; delay > 0; delay--) {
__NOP();
}
while(timer->CTL & TIMER_CTL_ACTSTS_Msk);
}
/**
* @brief This API is used to enable timer capture function with specified mode and capture edge
* @param[in] timer The base address of Timer module
* @param[in] u32CapMode Timer capture mode. Could be
* - \ref TIMER_CAPTURE_FREE_COUNTING_MODE
* - \ref TIMER_CAPTURE_TRIGGER_COUNTING_MODE
* - \ref TIMER_CAPTURE_COUNTER_RESET_MODE
* @param[in] u32Edge Timer capture edge. Possible values are
* - \ref TIMER_CAPTURE_FALLING_EDGE
* - \ref TIMER_CAPTURE_RISING_EDGE
* - \ref TIMER_CAPTURE_FALLING_THEN_RISING_EDGE
* - \ref TIMER_CAPTURE_RISING_THEN_FALLING_EDGE
* @return None
* @note Timer frequency should be configured separately by using \ref TIMER_Open API, or program registers directly
*/
void TIMER_EnableCapture(TIMER_T *timer, uint32_t u32CapMode, uint32_t u32Edge)
{
timer->EXTCTL = (timer->EXTCTL & ~(TIMER_EXTCTL_CAPSEL_Msk |
TIMER_EXTCTL_CAPFUNCS_Msk |
TIMER_EXTCTL_CAPEDGE_Msk)) |
u32CapMode | u32Edge | TIMER_EXTCTL_CAPEN_Msk;
}
/**
* @brief This API is used to disable the Timer capture function
* @param[in] timer The base address of Timer module
* @return None
*/
void TIMER_DisableCapture(TIMER_T *timer)
{
timer->EXTCTL &= ~TIMER_EXTCTL_CAPEN_Msk;
}
/**
* @brief This function is used to enable the Timer counter function with specify detection edge
* @param[in] timer The base address of Timer module
* @param[in] u32Edge Detection edge of counter pin. Could be ether
* - \ref TIMER_COUNTER_RISING_EDGE, or
* - \ref TIMER_COUNTER_FALLING_EDGE
* @return None
* @note Timer compare value should be configured separately by using \ref TIMER_SET_CMP_VALUE macro or program registers directly
*/
void TIMER_EnableEventCounter(TIMER_T *timer, uint32_t u32Edge)
{
timer->EXTCTL = (timer->EXTCTL & ~TIMER_EXTCTL_CNTPHASE_Msk) | u32Edge;
timer->CTL |= TIMER_CTL_EXTCNTEN_Msk;
}
/**
* @brief This API is used to disable the Timer event counter function.
* @param[in] timer The base address of Timer module
* @return None
*/
void TIMER_DisableEventCounter(TIMER_T *timer)
{
timer->CTL &= ~TIMER_CTL_EXTCNTEN_Msk;
}
/**
* @brief This API is used to get the clock frequency of Timer
* @param[in] timer The base address of Timer module
* @return Timer clock frequency
* @note This API cannot return correct clock rate if timer source is external clock input.
*/
uint32_t TIMER_GetModuleClock(TIMER_T *timer)
{
uint32_t u32Src;
if(timer == TIMER0)
u32Src = (CLK->CLKSEL1 & CLK_CLKSEL1_TMR0SEL_Msk) >> CLK_CLKSEL1_TMR0SEL_Pos;
else
u32Src = (CLK->CLKSEL1 & CLK_CLKSEL1_TMR1SEL_Msk) >> CLK_CLKSEL1_TMR1SEL_Pos;
if(u32Src == 0)
return((CLK->PWRCTL & CLK_PWRCTL_XTLEN_Msk) == 1 ? __XTAL12M : __XTAL32K);
else if(u32Src == 1)
return __IRC10K;
else if(u32Src == 2)
return SystemCoreClock;
else
return __HSI;
}
/*@}*/ /* end of group Mini58_TIMER_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_TIMER_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,364 @@
/**************************************************************************//**
* @file uart.c
* @version V1.00
* $Revision: 3 $
* $Date: 15/05/28 4:34p $
* @brief Mini58 series UART driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include "Mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_UART_Driver UART Driver
@{
*/
/** @addtogroup Mini58_UART_EXPORTED_FUNCTIONS UART Exported Functions
@{
*/
/**
* @brief The function is used to clear UART specified interrupt flag.
*
* @param[in] uart The base address of UART module.
* @param[in] u32InterruptFlag The specified interrupt of UART module.
*
* @return None
*/
void UART_ClearIntFlag(UART_T* uart , uint32_t u32InterruptFlag)
{
if(u32InterruptFlag & UART_INTSTS_RLSINT_Msk) { /* clear Receive Line Status Interrupt */
uart->FIFOSTS = UART_FIFOSTS_BIF_Msk | UART_FIFOSTS_FEF_Msk | UART_FIFOSTS_FEF_Msk;
uart->FIFOSTS = UART_FIFOSTS_ADDRDETF_Msk;
}
if(u32InterruptFlag & UART_INTSTS_MODEMINT_Msk) /* clear Modem Interrupt */
uart->MODEMSTS = UART_MODEMSTS_CTSDETF_Msk;
if(u32InterruptFlag & UART_INTSTS_BUFERRINT_Msk) { /* clear Buffer Error Interrupt */
uart->FIFOSTS = UART_FIFOSTS_RXOVIF_Msk | UART_FIFOSTS_TXOVIF_Msk;
}
if(u32InterruptFlag & UART_INTSTS_RXTOINT_Msk) /* clear Modem Interrupt */
uart->INTSTS = UART_INTSTS_RXTOIF_Msk;
}
/**
* @brief The function is used to disable UART.
*
* @param[in] uart The base address of UART module.
*
* @return None
*/
void UART_Close(UART_T* uart)
{
uart->INTEN = 0;
}
/**
* @brief The function is used to disable UART auto flow control.
*
* @param[in] uart The base address of UART module.
*
* @return None
*/
void UART_DisableFlowCtrl(UART_T* uart)
{
uart->INTEN &= ~(UART_INTEN_ATORTSEN_Msk | UART_INTEN_ATOCTSEN_Msk);
}
/**
* @brief The function is used to disable UART specified interrupt and disable NVIC UART IRQ.
*
* @param[in] uart The base address of UART module.
* @param[in] u32InterruptFlag The specified interrupt of UART module.
* - \ref UART_INTEN_TOCNTEN_Msk : Rx Time Out interrupt
* - \ref UART_INTEN_WKCTSIEN_Msk : Wakeup interrupt
* - \ref UART_INTEN_BUFERRIEN_Msk : Buffer Error interrupt
* - \ref UART_INTEN_RXTOIEN_Msk : Rx time-out interrupt
* - \ref UART_INTEN_MODEMIEN_Msk : Modem interrupt
* - \ref UART_INTEN_RLSIEN_Msk : Rx Line status interrupt
* - \ref UART_INTEN_THREIEN_Msk : Tx empty interrupt
* - \ref UART_INTEN_RDAIEN_Msk : Rx ready interrupt
*
* @return None
*/
void UART_DisableInt(UART_T* uart, uint32_t u32InterruptFlag )
{
uart->INTEN &= ~ u32InterruptFlag;
}
/**
* @brief The function is used to Enable UART auto flow control.
*
* @param[in] uart The base address of UART module.
*
* @return None
*/
void UART_EnableFlowCtrl(UART_T* uart )
{
uart->MODEM |= UART_MODEM_RTSACTLV_Msk;
uart->MODEM &= ~UART_MODEM_RTS_Msk;
uart->MODEMSTS |= UART_MODEMSTS_CTSACTLV_Msk;
uart->INTEN |= UART_INTEN_ATORTSEN_Msk | UART_INTEN_ATOCTSEN_Msk;
}
/**
* @brief The function is used to enable UART specified interrupt and disable NVIC UART IRQ.
*
* @param[in] uart The base address of UART module.
* @param[in] u32InterruptFlag The specified interrupt of UART module:
* - \ref UART_INTEN_TOCNTEN_Msk : Rx Time Out interrupt
* - \ref UART_INTEN_WKCTSIEN_Msk : Wakeup interrupt
* - \ref UART_INTEN_BUFERRIEN_Msk : Buffer Error interrupt
* - \ref UART_INTEN_RXTOIEN_Msk : Rx time-out interrupt
* - \ref UART_INTEN_MODEMIEN_Msk : Modem interrupt
* - \ref UART_INTEN_RLSIEN_Msk : Rx Line status interrupt
* - \ref UART_INTEN_THREIEN_Msk : Tx empty interrupt
* - \ref UART_INTEN_RDAIEN_Msk : Rx ready interrupt
*
* @return None
*/
void UART_EnableInt(UART_T* uart, uint32_t u32InterruptFlag )
{
uart->INTEN |= u32InterruptFlag;
}
/**
* @brief This function use to enable UART function and set baud-rate.
*
* @param[in] uart The base address of UART module.
* @param[in] u32baudrate The baudrate of UART module.
*
* @return None
*/
void UART_Open(UART_T* uart, uint32_t u32baudrate)
{
uint8_t u8UartClkSrcSel;
uint32_t u32Clk = 0;
uint32_t u32ClkDiv = 0;
uint32_t u32Baud_Div;
u8UartClkSrcSel = (CLK->CLKSEL1 & CLK_CLKSEL1_UARTSEL_Msk) >> CLK_CLKSEL1_UARTSEL_Pos;
uart->FUNSEL = UART_FUNC_SEL_UART;
uart->LINE = UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1;
uart->FIFO = UART_FIFO_RFITL_1BYTE | UART_FIFO_RTSTRGLV_1BYTE;
if(u8UartClkSrcSel == 0)
u32Clk = __XTAL;
else if(u8UartClkSrcSel == 1)
u32Clk = CLK_GetPLLClockFreq();
else if(u8UartClkSrcSel >= 2)
u32Clk = __HSI;
u32ClkDiv = ( (CLK->CLKDIV & CLK_CLKDIV_UARTDIV_Msk) >> CLK_CLKDIV_UARTDIV_Pos );
u32Clk = u32Clk/(u32ClkDiv + 1);
if(u32baudrate != 0) {
u32Baud_Div = UART_BAUD_MODE2_DIVIDER(u32Clk, u32baudrate);
if(u32Baud_Div > 0xFFFF)
uart->BAUD = (UART_BAUD_MODE0 | UART_BAUD_MODE0_DIVIDER(u32Clk, u32baudrate));
else
uart->BAUD = (UART_BAUD_MODE2 | u32Baud_Div);
}
}
/**
* @brief The function is used to read Rx data from RX FIFO and the data will be stored in pu8RxBuf.
*
* @param[in] uart The base address of UART module.
* @param[in] pu8RxBuf The buffer to receive the data of receive FIFO.
* @param[in] u32ReadBytes The the read bytes number of data.
*
* @return u32Count: Receive byte count
*
*/
uint32_t UART_Read(UART_T* uart, uint8_t *pu8RxBuf, uint32_t u32ReadBytes)
{
uint32_t u32Count, u32delayno;
for(u32Count=0; u32Count < u32ReadBytes; u32Count++) {
u32delayno = 0;
while(uart->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) { /* Check RX empty => failed */
u32delayno++;
if( u32delayno >= 0x40000000 )
return FALSE;
}
pu8RxBuf[u32Count] = uart->DAT; /* Get Data from UART RX */
}
return u32Count;
}
/**
* @brief This function use to config UART line setting.
*
* @param[in] uart The base address of UART module.
* @param[in] u32baudrate The register value of baudrate of UART module.
* if u32baudrate = 0, UART baudrate will not change.
* @param[in] u32data_width The data length of UART module.
* @param[in] u32parity The parity setting (odd/even/none) of UART module.
* @param[in] u32stop_bits The stop bit length (1/1.5 bit) of UART module.
*
* @return None
*/
void UART_SetLine_Config(UART_T* uart, uint32_t u32baudrate, uint32_t u32data_width, uint32_t u32parity, uint32_t u32stop_bits)
{
uint8_t u8UartClkSrcSel;
uint32_t u32Clk = 0;
uint32_t u32ClkDiv = 0;
uint32_t u32Baud_Div = 0;
u8UartClkSrcSel = (CLK->CLKSEL1 & CLK_CLKSEL1_UARTSEL_Msk) >> CLK_CLKSEL1_UARTSEL_Pos;
if(u8UartClkSrcSel == 0)
u32Clk = __XTAL;
else if(u8UartClkSrcSel == 1)
u32Clk = CLK_GetPLLClockFreq();
else if(u8UartClkSrcSel >= 2)
u32Clk = __HSI;
u32ClkDiv = ( (CLK->CLKDIV & CLK_CLKDIV_UARTDIV_Msk) >> CLK_CLKDIV_UARTDIV_Pos );
u32Clk = u32Clk/(u32ClkDiv + 1);
if(u32baudrate != 0) {
u32Baud_Div = UART_BAUD_MODE2_DIVIDER(u32Clk, u32baudrate);
if(u32Baud_Div > 0xFFFF)
uart->BAUD = (UART_BAUD_MODE0 | UART_BAUD_MODE0_DIVIDER(u32Clk, u32baudrate));
else
uart->BAUD = (UART_BAUD_MODE2 | u32Baud_Div);
}
uart->LINE = u32data_width | u32parity | u32stop_bits;
}
/**
* @brief This function use to set Rx timeout count.
*
* @param[in] uart The base address of UART module.
* @param[in] u32TOC Rx timeout counter.
*
* @return None
*/
void UART_SetTimeoutCnt(UART_T* uart, uint32_t u32TOC)
{
uart->TOUT = (uart->TOUT & ~UART_TOUT_TOIC_Msk)| (u32TOC);
uart->INTEN |= UART_INTEN_TOCNTEN_Msk;
}
/**
* @brief The function is used to configure IrDA relative settings. It consists of TX or RX mode and baudrate.
*
* @param[in] uart The base address of UART module.
* @param[in] u32Buadrate The baudrate of UART module.
* @param[in] u32Direction The direction(transmit:1/receive:0) of UART module in IrDA mode.
*
* @return None
*/
void UART_SelectIrDAMode(UART_T* uart, uint32_t u32Buadrate, uint32_t u32Direction)
{
uint8_t u8UartClkSrcSel;
uint32_t u32Clk = 0;
uint32_t u32ClkDiv = 0;
u8UartClkSrcSel = (CLK->CLKSEL1 & CLK_CLKSEL1_UARTSEL_Msk) >> CLK_CLKSEL1_UARTSEL_Pos;
if(u8UartClkSrcSel == 0)
u32Clk = __XTAL;
else if(u8UartClkSrcSel == 1)
u32Clk = CLK_GetPLLClockFreq();
else if(u8UartClkSrcSel >= 2)
u32Clk = __HSI;
u32ClkDiv = ( (CLK->CLKDIV & CLK_CLKDIV_UARTDIV_Msk) >> CLK_CLKDIV_UARTDIV_Pos );
u32Clk = u32Clk/(u32ClkDiv + 1);
uart->BAUD = UART_BAUD_MODE0 | UART_BAUD_MODE0_DIVIDER(u32Clk, u32Buadrate);
uart->IRDA &= ~UART_IRDA_TXINV_Msk;
uart->IRDA |= UART_IRDA_RXINV_Msk;
uart->IRDA = u32Direction ? uart->IRDA | UART_IRDA_TXEN_Msk : uart->IRDA &~ UART_IRDA_TXEN_Msk;
uart->FUNSEL = (0x2 << UART_FUNSEL_FUN_SEL_Pos);
}
/**
* @brief The function is used to set RS485 relative setting.
*
* @param[in] uart The base address of UART module.
* @param[in] u32Mode The operation mode(NMM/AUD/AAD).
* @param[in] u32Addr The RS485 address.
*
* @return None
*/
void UART_SelectRS485Mode(UART_T* uart, uint32_t u32Mode, uint32_t u32Addr)
{
uart->FUNSEL = UART_FUNC_SEL_RS485;
uart->ALTCTL = 0;
uart->ALTCTL |= u32Mode | (u32Addr << UART_ALTCTL_ADDRMV_Pos);
}
/**
* @brief The function is to write data into TX buffer to transmit data by UART.
*
* @param[in] uart The base address of UART module.
* @param[in] pu8TxBuf The buffer to send the data to UART transmission FIFO.
* @param[in] u32WriteBytes The byte number of data.
*
* @return u32Count: transfer byte count
*/
uint32_t UART_Write(UART_T* uart,uint8_t *pu8TxBuf, uint32_t u32WriteBytes)
{
uint32_t u32Count, u32delayno;
for(u32Count=0; u32Count != u32WriteBytes; u32Count++) {
u32delayno = 0;
while((uart->FIFOSTS & UART_FIFOSTS_TXEMPTYF_Msk) == 0) { /* Wait Tx empty and Time-out manner */
u32delayno++;
if( u32delayno >= 0x40000000 )
return FALSE;
}
uart->DAT = pu8TxBuf[u32Count]; /* Send UART Data from buffer */
}
return u32Count;
}
/*@}*/ /* end of group Mini58_UART_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_UART_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2012 Nuvoton Technology Corp. ***/
@@ -0,0 +1,100 @@
/**************************************************************************//**
* @file wdt.c
* @version V1.00
* $Revision: 3 $
* $Date: 15/05/28 1:16p $
* @brief Mini58 series WDT driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "Mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_WDT_Driver WDT Driver
@{
*/
/** @addtogroup Mini58_WDT_EXPORTED_FUNCTIONS WDT Exported Functions
@{
*/
/**
* @brief This function make WDT module start counting with different time-out interval
* @param[in] u32TimeoutInterval Time-out interval period of WDT module. Valid values are:
* - \ref WDT_TIMEOUT_2POW4
* - \ref WDT_TIMEOUT_2POW6
* - \ref WDT_TIMEOUT_2POW8
* - \ref WDT_TIMEOUT_2POW10
* - \ref WDT_TIMEOUT_2POW12
* - \ref WDT_TIMEOUT_2POW14
* - \ref WDT_TIMEOUT_2POW16
* - \ref WDT_TIMEOUT_2POW18
* @param[in] u32ResetDelay Reset delay period while WDT time-out happened. Valid values are:
* - \ref WDT_RESET_DELAY_3CLK
* - \ref WDT_RESET_DELAY_18CLK
* - \ref WDT_RESET_DELAY_130CLK
* - \ref WDT_RESET_DELAY_1026CLK
* @param[in] u32EnableReset Enable WDT reset system function. Valid values are TRUE and FALSE
* @param[in] u32EnableWakeup Enable WDT wake-up system function. Valid values are TRUE and FALSE
* @return None
*/
void WDT_Open(uint32_t u32TimeoutInterval,
uint32_t u32ResetDelay,
uint32_t u32EnableReset,
uint32_t u32EnableWakeup)
{
WDT->CTL = u32TimeoutInterval | WDT_CTL_WDTEN_Msk |
(u32EnableReset << WDT_CTL_RSTEN_Pos) |
(u32EnableWakeup << WDT_CTL_WKEN_Pos);
WDT->ALTCTL = u32ResetDelay;
return;
}
/**
* @brief This function stops WDT counting and disable WDT module
* @param None
* @return None
*/
void WDT_Close(void)
{
WDT->CTL = 0;
return;
}
/**
* @brief This function enables the WDT time-out interrupt
* @param None
* @return None
*/
void WDT_EnableInt(void)
{
WDT->CTL = (WDT->CTL & ~(WDT_CTL_IF_Msk | WDT_CTL_WKF_Msk | WDT_CTL_RSTF_Msk)) | WDT_CTL_INTEN_Msk;
return;
}
/**
* @brief This function disables the WDT time-out interrupt
* @param None
* @return None
*/
void WDT_DisableInt(void)
{
WDT->CTL &= ~(WDT_CTL_IF_Msk | WDT_CTL_WKF_Msk | WDT_CTL_RSTF_Msk | WDT_CTL_INTEN_Msk);
return;
}
/*@}*/ /* end of group Mini58_WDT_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_WDT_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
@@ -0,0 +1,68 @@
/**************************************************************************//**
* @file wwdt.c
* @version V1.00
* $Revision: 1 $
* $Date: 15/02/02 3:19p $
* @brief Mini58 series WWDT driver source file
*
* @note
* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "mini58Series.h"
/** @addtogroup Mini58_Device_Driver Mini58 Device Driver
@{
*/
/** @addtogroup Mini58_WWDT_Driver WWDT Driver
@{
*/
/** @addtogroup Mini58_WWDT_EXPORTED_FUNCTIONS WWDT Exported Functions
@{
*/
/**
* @brief This function make WWDT module start counting with different counter period and compared window value
* @param[in] u32PreScale Prescale period for the WWDT counter period. Valid values are:
* - \ref WWDT_PRESCALER_1
* - \ref WWDT_PRESCALER_2
* - \ref WWDT_PRESCALER_4
* - \ref WWDT_PRESCALER_8
* - \ref WWDT_PRESCALER_16
* - \ref WWDT_PRESCALER_32
* - \ref WWDT_PRESCALER_64
* - \ref WWDT_PRESCALER_128
* - \ref WWDT_PRESCALER_192
* - \ref WWDT_PRESCALER_256
* - \ref WWDT_PRESCALER_384
* - \ref WWDT_PRESCALER_512
* - \ref WWDT_PRESCALER_768
* - \ref WWDT_PRESCALER_1024
* - \ref WWDT_PRESCALER_1536
* - \ref WWDT_PRESCALER_2048
* @param[in] u32CmpValue Window compared value. Valid values are between 0x0 to 0x3F
* @param[in] u32EnableInt Enable WWDT interrupt or not. Valid values are \ref TRUE and \ref FALSE
* @return None
* @note Application can call this function can only once after boot up
*/
void WWDT_Open(uint32_t u32PreScale, uint32_t u32CmpValue, uint32_t u32EnableInt)
{
WWDT->CTL = u32PreScale |
(u32CmpValue << WWDT_CTL_CMPDAT_Pos)|
WWDT_CTL_WWDTEN_Msk |
(u32EnableInt ? WWDT_CTL_INTEN_Msk : 0);
return;
}
/*@}*/ /* end of group Mini58_WWDT_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group Mini58_WWDT_Driver */
/*@}*/ /* end of group Mini58_Device_Driver */
/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/