新唐M263KIAAE芯片
1,寄存器锁定控制(Register Lock Control)
一些系统控制寄存器需要被保护,以避免无意中写入和干扰芯片操作。这些系统控制寄存器在开机复位后受到保护,直到用户禁用寄存器保护。要让用户对这些受保护的寄存器进行编程,在寄存器保护禁用序列之后还需要进行一个特殊的编程。寄存器保护禁用序列是连续地将数据“59h”、“16h”“88h”写入0x4000_0100处的寄存器SYS_REGLCTL地址。在这三个数据写入过程中,任何不同的数据值、不同的序列或对其他地址的任何其他写入都将中止整个序列。
1.1,寄存器锁定控制寄存器(SYS_REGLCTL)
保护禁用后,用户可以检查地址0x4000_0100位0的保护禁用位,1表示保护禁用,0表示保护使能。然后,用户可以更新目标保护寄存器值,然后将任何数据写入地址“0x4000_0100”以启用寄存器保护。
写入该寄存器以禁用/启用寄存器保护,并读取REGLCTL状态。
寄存器锁定控制代码
某些寄存器具有写保护功能。写入这些寄存器必须通过将序列值“59h”、“16h”、“88h”写入该字段来禁用保护功能。此序列完成后,REGLCTL位将设置为1,写保护寄存器可以正常写入。
REGLCTL[0]
寄存器锁定控制禁用索引
0=为写入受保护寄存器启用写保护。对受保护寄存器的任何写入都将被忽略。
1=写保护寄存器禁用写保护。
以下为禁用保护功能子函数
/**
* @brief Disable register write-protection function
* @param None
* @return None
* @details This function disable register write-protection function.
* To unlock the protected register to allow write access.
*/
__STATIC_INLINE void SYS_UnlockReg(void)
{
do
{
SYS->REGLCTL = 0x59UL;
SYS->REGLCTL = 0x16UL;
SYS->REGLCTL = 0x88UL;
}
while(SYS->REGLCTL == 0UL);
}
启用保护功能:
/**
* @brief Enable register write-protection function
* @param None
* @return None
* @details This function is used to enable register write-protection function.
* To lock the protected register to forbid write access.
*/
__STATIC_INLINE void SYS_LockReg(void)
{
SYS->REGLCTL = 0UL;
}
应用示例:main.c 中的 SYS_Init子函数
void SYS_Init(void)
{
/* Unlock protected registers */
SYS_UnlockReg();//禁用保护功能
/* Enable HIRC clock (Internal RC 48MHz) */
CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);//参考注释1[^1]
/* Wait for HIRC clock ready */
CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);//参考注释2
/* Select HCLK clock source as HIRC and HCLK source divider as 1 */
CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_HIRC, CLK_CLKDIV0_HCLK(1));//参考注释3
/* Enable UART0 clock */
CLK_EnableModuleClock(UART0_MODULE);//参考注释4
/* Switch UART0 clock source to HIRC */
CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));参考注释5
/* Update System Core Clock */
SystemCoreClockUpdate();//参考注释6
/* Set PB multi-function pins for UART0 RXD=PB.12 and TXD=PB.13 */
SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk)) | \
(SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);//参考注释7
/* Lock protected registers */
SYS_LockReg();//启用保护功能
}
注释:
注释1,CLK_PWRCTL:系统断电控制寄存器(System Power-down Control Register)
CLK_PWRCTL_HIRCEN:
HIRC启用位(写保护)
HCLK默认时钟源来自HIRC,此位默认值为1。
0=12MHz内部高速RC振荡器(HIRC)已禁用。
1=12MHz内部高速RC振荡器(HIRC)启用。
注1:该位元受写入保护。请参考SYS_REGLCTL寄存器。
注2:如果启用了Flash访问周期自动调优功能,或从HIRC或PLL(来自HIRC的时钟源)中选择了HCLK时钟源,则不能禁用HIRC,并且HIRCEN将始终读取为1。可以通过设置FADIS(FMC_CYCCTL[8])来禁用快速访问周期自动调优功能。
CLK_PWRCTL_HIRCEN_Msk:
#define CLK_PWRCTL_HIRCEN_Pos (2) /*!< CLK_T::PWRCTL: HIRCEN Position */
#define CLK_PWRCTL_HIRCEN_Msk (0x1ul << CLK_PWRCTL_HIRCEN_Pos) /*!< CLK_T::PWRCTL: HIRCEN Mask */
简而言之,该句代码将CLK中的寄存器PWRCTL中的HIRCEN(PWRCTL[2])位设为1,即 12 kHz internal low speed RC oscillator (LIRC) Enabled。
注释2,CLK_STATUS
时钟状态监视器寄存器(CLK_STATUS)
该寄存器中的位元用于监控芯片时钟源是否稳定,以及时钟开关是否发生故障。
CLK_STATUS_HIRCSTB
HIRC时钟源稳定标志(只读)
0=12MHz内部高速RC振荡器(HIRC)时钟不稳定或禁用。
1=12MHz内部高速RC振荡器(HIRC)时钟稳定并启用。
CLK_WaitClockReady()函数:
/**
* @brief This function check selected clock source status
* @param[in] u32ClkMask is selected clock source. Including :
* - \ref CLK_STATUS_HXTSTB_Msk
* - \ref CLK_STATUS_LXTSTB_Msk
* - \ref CLK_STATUS_HIRCSTB_Msk
* - \ref CLK_STATUS_LIRCSTB_Msk
* - \ref CLK_STATUS_PLLSTB_Msk
* - \ref CLK_STATUS_HIRC48STB_Msk
* - \ref CLK_STATUS_EXTLXTSTB_Msk
* - \ref CLK_STATUS_LIRC32STB_Msk
* @retval 0 clock is not stable
* @retval 1 clock is stable
* @details To wait for clock ready by specified clock source stable flag or timeout (~300ms)
*/
uint32_t CLK_WaitClockReady(uint32_t u32ClkMask)
{
int32_t i32TimeOutCnt = 2400000;
uint32_t u32Ret = 1U;
while((CLK->STATUS & u32ClkMask) != u32ClkMask)
{
if(i32TimeOutCnt-- <= 0)
{
u32Ret = 0U;
break;
}
}
return u32Ret;
}
简而言之,该函数只是不断监测并等待参数<HIRC时钟源稳定标志>变为1,即启用。
注释3
(1)CLK_CLKSEL0: Clock Source Select Control Register 0
CLK_CLKSEL0_HCLKSEL:
HCLKSEL: HCLK时钟源选择(写入保护)
在进行时钟切换之前,必须打开相关的时钟源(包括预先选择和新选择)。
CLK_CLKSEL0_HCLKSEL_HIRC 定义:
#define CLK_CLKSEL0_HCLKSEL_HIRC (0x07UL<<CLK_CLKSEL0_HCLKSEL_Pos) /*!< Setting HCLK clock source as HIRC */
(2)CLK_CLKDIV0_HCLK(1)
#define CLK_CLKDIV0_HCLK(x) (((x)-1UL) << CLK_CLKDIV0_HCLKDIV_Pos) /*!< CLKDIV0 Setting for HCLK clock divider. It could be 1~16 */
该句代码为启用HIRC作为HCLK,且设置HCLK时钟分频器为1。
注释4
UART0_MODULE 为一些状态设置,这里不详细展开了。
CLK_EnableModuleClock():
/**
* @brief This function enable module clock
* @param[in] u32ModuleIdx is module index. Including :
* - \ref PDMA0_MODULE
* - \ref PDMA1_MODULE
* - \ref ISP_MODULE
* - \ref EBI_MODULE
* - \ref SDH0_MODULE
* - \ref CRC_MODULE
* - \ref CRPT_MODULE
* - \ref USBH_MODULE
* - \ref WDT_MODULE
* - \ref WWDT_MODULE
* - \ref RTC_MODULE
* - \ref TMR0_MODULE
* - \ref TMR1_MODULE
* - \ref TMR2_MODULE
* - \ref TMR3_MODULE
* - \ref CLKO_MODULE
* - \ref ACMP01_MODULE
* - \ref I2C0_MODULE
* - \ref I2C1_MODULE
* - \ref I2C2_MODULE
* - \ref QSPI0_MODULE
* - \ref SPI0_MODULE
* - \ref SPI1_MODULE
* - \ref SPI2_MODULE
* - \ref SPI3_MODULE
* - \ref UART0_MODULE
* - \ref UART1_MODULE
* - \ref UART2_MODULE
* - \ref UART3_MODULE
* - \ref UART4_MODULE
* - \ref UART5_MODULE
* - \ref CAN0_MODULE
* - \ref OTG_MODULE
* - \ref USBD_MODULE
* - \ref EADC_MODULE
* - \ref I2S0_MODULE
* - \ref SC0_MODULE
* - \ref SC1_MODULE
* - \ref SC2_MODULE
* - \ref USCI0_MODULE
* - \ref USCI1_MODULE
* - \ref DAC_MODULE
* - \ref EPWM0_MODULE
* - \ref EPWM1_MODULE
* - \ref BPWM0_MODULE
* - \ref BPWM1_MODULE
* - \ref QEI0_MODULE
* - \ref QEI1_MODULE
* - \ref QEI0_MODULE
* - \ref TRNG_MODULE
* - \ref ECAP0_MODULE
* - \ref ECAP1_MODULE
* @return None
* @details This function enable module clock.
*/
void CLK_EnableModuleClock(uint32_t u32ModuleIdx)
{
uint32_t u32TmpVal = 0UL, u32TmpAddr = 0UL;
u32TmpVal = (1UL << MODULE_IP_EN_Pos(u32ModuleIdx));
u32TmpAddr = (uint32_t)&CLK->AHBCLK;
u32TmpAddr += ((MODULE_APBCLK(u32ModuleIdx) * 4UL));
*(volatile uint32_t *)u32TmpAddr |= u32TmpVal;
}
所以该句是启用UART0 并为UART0设置一些初始化状态。
注释5
CLK_CLKSEL1_UART0SEL_HIRC:
CLK_CLKDIV0_UART0(1)
#define CLK_CLKDIV0_UART0(x) (((x)-1UL) << CLK_CLKDIV0_UART0DIV_Pos) /*!< CLKDIV0 Setting for UART0 clock divider. It could be 1~16 */
CLK_SetModuleClock()
This function set selected module clock source and module clock divider
注释6
SystemCoreClockUpdate()
/**
* @brief Update the Variable SystemCoreClock
*
* @param None
*
* @return None
*
* @details This function is used to update the variable SystemCoreClock
* and must be called whenever the core clock is changed.
*/
void SystemCoreClockUpdate(void)
{
/* Update PLL Clock */
PllClock = CLK_GetPLLClockFreq();
/* Update System Core Clock */
SystemCoreClock = CLK_GetCPUFreq();
/* Update Cycles per micro second */
CyclesPerUs = (SystemCoreClock + 500000UL) / 1000000UL;
}
其中PLL参考本文第4小节
注释7
首先列出括号里各变量定义:
#define SYS_GPB_MFPH_PB12MFP_Pos (16) /*!< SYS_T::GPB_MFPH: PB12MFP Position */
#define SYS_GPB_MFPH_PB12MFP_Msk (0xful << SYS_GPB_MFPH_PB12MFP_Pos) /*!< SYS_T::GPB_MFPH: PB12MFP Mask */
#define SYS_GPB_MFPH_PB13MFP_Pos (20) /*!< SYS_T::GPB_MFPH: PB13MFP Position */
#define SYS_GPB_MFPH_PB13MFP_Msk (0xful << SYS_GPB_MFPH_PB13MFP_Pos) /*!< SYS_T::GPB_MFPH: PB13MFP Mask */
#define SYS_GPB_MFPH_PB12MFP_UART0_RXD (0x06UL<<SYS_GPB_MFPH_PB12MFP_Pos)/*!< GPB_MFPH PB12 setting for UART0_RXD */ //注:0x06UL->下图中UART0_RXD中PB12引脚对应MFP6
#define SYS_GPB_MFPH_PB13MFP_UART0_TXD (0x06UL<<SYS_GPB_MFPH_PB13MFP_Pos)/*!< GPB_MFPH PB13 setting for UART0_TXD */
对于SYS_GPB_MFPH寄存器,有如下解释:
SYS_GPB_MFPH 即 GPIOB High Byte Multiple Function Control Register ,意为GPIOB高字节多功能控制寄存器
此外,对于UART0_RXD:
UART0_RXD:
2, 时钟控制器(Clock Controller)
2.1,概览
时钟控制器为整个芯片生成时钟,包括系统时钟和所有外围时钟。时钟控制器还通过单独时钟开/关控制、时钟源选择和时钟分频器实现电源控制功能。在CPU设置掉电使能位PTEN(CLK_PWRCTL[7])且CORE执行WFI指令之前,芯片不会进入掉电模式。之后,芯片进入掉电模式,等待被触发的唤醒中断源退出掉电模式。在掉电模式下,时钟控制器关闭4~24 MHz外部高速晶体(HXT)、48 MHz内部高速RC振荡器(HIRC 48)和12 MHz内部高速RC振荡器(HIRC),以降低整个系统的功耗。图2.1-1至图2.1-3显示时钟发生器和时钟源控制概述。1
2.2,时钟发生器
时钟发生器由6个时钟源组成,如下所示:
- 32.768 kHz外接低速晶体振荡器(LXT);
- 4~24 MHz外接高速晶体振荡器(HXT);
- 可编程锁相环输出时钟频率(PLLFOUT),锁相环源可以选择外部4 ~ 24 MHz外部高速晶体(HXT)或12 MHz内部高速振荡器(HIRC);
- 12 MHz内部高速RC振荡器(HIRC);
- 48 MHz内部高速RC振荡器(HIRC 48);
- 10 kHz内部低速RC振荡器(LIRC)
图2.2-1 时钟发生器框图
这些时钟源中的每一个都有一定的稳定时间来等待时钟以稳定的频率工作。当使能时钟源时,稳定计数器开始计数和启动相关时钟稳定索引。
即,HXTSTB(CLK_STATUS[0])、LXTSTB(CLK_STATUS[1])、PLLSTB(CLK_STATUS[2])、LIRCSTB(CLK_STATUS[3])、HIRCSTB(CLK_STATUS[4])、HIRC48STB(CLK_STATUS[6])、EXTLXTSTB(CLK_STATUS[8])和LIRC32STB(CLK_STATUS[9])在稳定计数器值达到定义值后置1。
仅当相关时钟稳定指数设置为1时,系统和外围设备才能将时钟用作其操作时钟。时钟稳定指数将在时钟源 (HXTEN (CLK_PWRCTL[0]), LXTEN (CLK_PWRCTL[1]), LIRC32KEN (RTC_LXTCTL[0]), HIRCEN (CLK_PWRCTL[2]), LIRCEN(CLK_PWRCTL[3]), HIRC48EN (CLK_PWRCTL[18]) and PD (CLK_PLLCTL[16]))被禁用时自动清除。
此外,当芯片进入掉电状态时,HXT、HIRC、HIRC48和PLL的时钟稳定指数将自动清零,如果启用相关时钟,时钟稳定计数器将在芯片唤醒后重新计数。
2.3,系统时钟和SysTick时钟
系统时钟具有6个时钟源,这些时钟源由时钟发生器模块产生。时钟源开关取决于寄存器HCLKSEL(CLK_CLKSEL0[2:0])。框图如图2.3-1所示。
图2.3-1 系统时钟块图
有两个时钟故障检测器来观察HXT和LXT时钟源,它们具有单独的使能和中断控制。当启用HXT探测器时,HIRC时钟将自动启用。当启用LXT检测器时,LIRC时钟将自动启用。
当启用HXT时钟检测器时,如果在以下情况下停止检测到HXT时钟,系统时钟将自动切换到HIRC:系统时钟源COM来自HXT,或者系统时钟源来自PLL,输入为HXT。如果检测到HXT时钟停止条件,则HXTFIF(CLK_CLKDSTS[0])被设置为1,并且如果HXTFIE(CLK_CLKDCTL[5])被设置为1,芯片将进入中断。如果在使用HXT故障检测器功能时HXT停止,则HXT时钟源稳定标志HXTSTB(CLK_STATUS[0])将被清除。用户可以通过禁用HXT并再次启用HXT来尝试恢复HXT,以检查时钟稳定位是否设置为1。如果HXT时钟稳定位设置为1,则意味着重新使能动作后HXT恢复振荡,用户可以再次将系统时钟切换到HXT。
HXT时钟停止检测和系统时钟切换到HIRC程序如图2.3-2所示。
图2.3-2 HXT停止保护程序
处理器内SysTick的时钟源可以使用CPU时钟或外部时钟(SYST_CTRL[2])。如果使用外部时钟,SysTick时钟(STCLK)有5个时钟源。时钟源开关取决于寄存器STCLKSEL(CLK_CLKSEL0[5:3])的设置。框图如图2.3-3所示。
图2.3-3 系统诊断时钟控制方框图
SysTick详解链接: 新唐M261M262M263系列芯片知识总结归纳(1).
2.4,外围设备时钟
每个外设时钟都有自己的时钟源选择。参考CLK_CLKSEL1、CLK_CLKSEL2和CLK_CLKSEL3寄存器。
2.5,掉电模式时钟
进入掉电模式时,系统时钟、某些时钟源和某些外设时钟被禁用。某些时钟源和外设时钟在掉电模式下仍处于活动状态。
以下列出了这些仍处于活动状态的时钟:
-
时钟发生器
–10 KHz内部低速RC振荡器时钟;
–32.768 KHz外部低速晶体振荡器时钟; -
外设时钟(当模块采用LXT或LIRC作为时钟源时)
2.6,时钟输出
该器件配备了一个2次方分频器,该分频器由16个链式除以2移位寄存器组成。由16对1多路复用器选择的16个移位寄存器输出中的一个反映到 CLKO 功能引脚。因此,有16种2次方分频时钟的选择,频率从Fin/21到Fin/216,其中Fin是时钟分频器的输入时钟频率。
输出公式为 Fout=Fin/2(N+1),其中 Fin 为输入时钟频率,Fout 为时钟分频器输出频率,N 为FREQSEL(CLK_CLKOCTL[3:0])中的4位值。将 1 写入CLKOEN(CLK_CLKOCT[4])时,链接计数器开始计数。将 0 写入CLKOEN(CLK_CLKOCTL[4])时,链式计数器持续运行,直到分频时钟达到低电平状态并保持在低电平状态。
如果DIV1EN(CLK_CLKOCTL[5])设为1,时钟输出时钟(CLKO_CLK)将绕过2次方分频器。输出分频器时钟将直接输出到CLKO引脚。进入掉电模式时,即使CKO时钟源为LXT,时钟输出也不会输出时钟。
图2.6-1 时钟输出框图
2.7,寄存器映射与寄存器描述
略,详见技术手册 P418-P467
3,HCLK
system clock (HCLK)
The Clock of Advanced High-Performance Bus
4,PLL
4.1,简介
时钟与振荡电路
在芯片中,最重要的是时钟。那时钟是怎么来的呢?时钟可以看成周期性的0与1信号变化,而这种周期性的变化可以看成振荡。因此,振荡电路成为了时钟的来源。
PLL与倍频
晶振由于其频率的稳定性,一般作为系统的外部时钟源。但是晶振的频率虽然稳定,但是频率无法做到很高(成本与工艺限制),因此芯片中高频时钟就需要一种叫做压控振荡器(Voltage Controlled Oscillator)的东西生成了(顾名思义,VCO就是根据电压来调整输出频率的不同)。可压控振荡器也有问题,其频率不够稳定,而且变化时很难快速稳定频率。为了将频率锁定在一个固定的期望值,锁相环PLL出现了!
PLL(Phase Locked Loop)为锁相环。FPGA中的锁相环通常由PFD(鉴频鉴相器)、CP(电荷泵)、LF(滤波器)、VCO(压控振荡器)组成。一般晶体振荡器由于工艺和成本原因达不到高频信号输出。高频电子线路中,需要外部信号与内部的振荡信号同步。一路输入时钟需要生成多路时钟信号。以上几种问题就需要通过PLL来实现
PLL的内部结构如下图所示:
参考链接:
链接: 1,PLL 锁相环原理介绍. 2,PLL详解.
4.2,PLL Control Register (CLK_PLLCTL)
PLL参考时钟输入来自4~24MHz外部高速晶体振荡器(HXT)时钟输入,或来自12MHz内部高速RC振荡器(HIRC)。该寄存器用于控制PLL输出频率和PLL工作模式。
编程这些位需要编写“59h”、“16h”和“88h”来解决0x4000_0100问题,以禁用寄存器保护。参考地址SYS_BA+0x100处的寄存器SYS_REGLCTL。
如果用户需要更改PLL的频率或时钟源,请先禁用PLL(CLK_PLLCTL[16])。
5,定时器和时钟中断
略,详见技术手册
参考链接:
1, 说说M451例程讲解之定时器 .
2, M0 M4之Timer初始化