在线时间589 小时
UID3469866
注册时间2018-4-19
NXP金币3176
TA的每日心情 | 慵懒 2024-2-8 09:39 |
---|
签到天数: 217 天 [LV.7]常住居民III
版主
- 积分
- 7749
- 最后登录
- 2024-4-30
|
首先吐槽一下MDK5.24a,老是闪退,而且调试不好使(可能因为中文路径),一气之下又换回了我的MDK5.22。还是原来的好使啊。
现在开始今天的正题,PIT这个PIT只有一个模块,但是里面有4个通道(独立计时),今天就以通道0为例。
首先在工程添加PIT.c,添加PIT.h
这个 BOARD_BootClockRUN();是用来配置外设时钟的
这里面最常出现的就是CLOCK_SetMux(),CLOCK_SetDiv()这两个函数。
先看看这两个函数是干啥的
/*!
* @brief Set CCM MUX node to certain value.
*
* @param mux Which mux node to set, see \ref clock_mux_t.
* @param value Clock mux value to set, different mux has different value range.
*/
static inline void CLOCK_SetMux(clock_mux_t mux, uint32_t value)
{
uint32_t busyShift;
busyShift = CCM_TUPLE_BUSY_SHIFT(mux);
CCM_TUPLE_REG(CCM, mux) = (CCM_TUPLE_REG(CCM, mux) & (~CCM_TUPLE_MASK(mux))) |
(((uint32_t)((value) << CCM_TUPLE_SHIFT(mux))) & CCM_TUPLE_MASK(mux));
assert(busyShift <= CCM_NO_BUSY_WAIT);
/* Clock switch need Handshake? */
if (CCM_NO_BUSY_WAIT != busyShift)
{
/* Wait until CCM internal handshake finish. */
while (CCM->CDHIPR & (1U << busyShift))
{
}
}
}
/*!
* @brief Set CCM DIV node to certain value.
*
* @param divider Which div node to set, see \ref clock_div_t.
* @param value Clock div value to set, different divider has different value range.
*/
static inline void CLOCK_SetDiv(clock_div_t divider, uint32_t value)
{
uint32_t busyShift;
busyShift = CCM_TUPLE_BUSY_SHIFT(divider);
CCM_TUPLE_REG(CCM, divider) = (CCM_TUPLE_REG(CCM, divider) & (~CCM_TUPLE_MASK(divider))) |
(((uint32_t)((value) << CCM_TUPLE_SHIFT(divider))) & CCM_TUPLE_MASK(divider));
assert(busyShift <= CCM_NO_BUSY_WAIT);
/* Clock switch need Handshake? */
if (CCM_NO_BUSY_WAIT != busyShift)
{
/* Wait until CCM internal handshake finish. */
while (CCM->CDHIPR & (1U << busyShift))
{
}
}
}
嗯,看起来很复杂,其实我们也没必要去完全理解每一步的原理,只需要安心调用库就好了,配合下面三张图和函数的解释看
可以基本猜到CLOCK_SetMux是选择时钟来源的,而CLOCK_SetDiv是设置时钟分频的。以pit的为例
可以找到应该去配置kCLOCK_PerclkMux和kCLOCK_PerclkDiv。
我们去看一下CSCMR1的对应位说明
那我们就先设置个比较简单的使用OSC时钟,分频为1(OSC时钟来源是外部震荡电路 频率为24MHz,具体以后再讨论)也就是PERCLK_CLK_
SEL配置为1,PERCLK_PODF配置为0;
CLOCK_SetMux(kCLOCK_PerclkMux, 1U);
CLOCK_SetDiv(kCLOCK_PerclkDiv, 0U);
这样外设时钟就配置好了。然后接着去看PIT_Init函数,void PIT_Init(PIT_Type *base, const pit_config_t *config);可以看到它有两个参数。第一个是选择配置哪个模块(话说PIT就一个模块),第二个是相关配置,我们可以去看一下pit_config_t
typedef struct _pit_config
{
bool enableRunInDebug; /*!< true: Timers run in debug mode; false: Timers stop in debug mode */
} pit_config_t;
(emmmmmm就一个。。。)这个是用来选择debug的时候定时器是否开启。我们就写一下
pit_config_t pitConfig;
pitConfig.enableRunInDebug = false;
PIT_Init(PIT, &pitConfig);
然后就是要设置定时时间和配置中断了,先上代码
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, MSEC_TO_COUNT(1000U, CLOCK_GetFreq(kCLOCK_OscClk)));//配置中断事件
PIT_EnableInterrupts(PIT, kPIT_Chnl_0, kPIT_TimerInterruptEnable);//使能对应模块中断
EnableIRQ(PIT_IRQn); //使能中断
PIT_StartTimer(PIT, kPIT_Chnl_0); //开始计时
先看PIT_SetTimerPeriod,他有三个参数,第一个是选择模块,第二个是选择通道,第三个是选择初始计数(PIT是减计数器,减到0重新配置初值)
在函数说明里给了一句提示
* @note Users can call the utility macros provided in fsl_common.h to convert to ticks.
(那当然要去看了)
/*! @name Timer utilities */
/* @{ */
/*! Macro to convert a microsecond period to raw count value */
#define USEC_TO_COUNT(us, clockFreqInHz) (uint64_t)((uint64_t)us * clockFreqInHz / 1000000U)
/*! Macro to convert a raw count value to microsecond */
#define COUNT_TO_USEC(count, clockFreqInHz) (uint64_t)((uint64_t)count * 1000000U / clockFreqInHz)
/*! Macro to convert a millisecond period to raw count value */
#define MSEC_TO_COUNT(ms, clockFreqInHz) (uint64_t)((uint64_t)ms * clockFreqInHz / 1000U)
/*! Macro to convert a raw count value to millisecond */
#define COUNT_TO_MSEC(count, clockFreqInHz) (uint64_t)((uint64_t)count * 1000U / clockFreqInHz)
/* @} */
可以看到提供了定时转计数和计数转定时的宏函数,不过要提供时钟频率(单位Hz)
接着看一下CLOCK_GetFreq函数
/*!
* @brief Gets the clock frequency for a specific clock name.
*
* This function checks the current clock configurations and then calculates
* the clock frequency for a specific clock name defined in clock_name_t.
*
* @param clockName Clock names defined in clock_name_t
* @return Clock frequency value in hertz
*/
uint32_t CLOCK_GetFreq(clock_name_t name);
可以看到,只要提供时钟名称,这个函数就能返回频率
里面可以选择的参数有
/*! @brief Clock name used to get clock frequency. */
typedef enum _clock_name
{
kCLOCK_CpuClk = 0x0U, /*!< CPU clock */
kCLOCK_AhbClk = 0x1U, /*!< AHB clock */
kCLOCK_SemcClk = 0x2U, /*!< SEMC clock */
kCLOCK_IpgClk = 0x3U, /*!< IPG clock */
kCLOCK_OscClk = 0x4U, /*!< OSC clock selected by PMU_LOWPWR_CTRL[OSC_SEL]. */
kCLOCK_RtcClk = 0x5U, /*!< RTC clock. (RTCCLK) */
kCLOCK_ArmPllClk = 0x6U, /*!< ARMPLLCLK. */
kCLOCK_Usb1PllClk = 0x7U, /*!< USB1PLLCLK. */
kCLOCK_Usb1PllPfd0Clk = 0x8U, /*!< USB1PLLPDF0CLK. */
kCLOCK_Usb1PllPfd1Clk = 0x9U, /*!< USB1PLLPFD1CLK. */
kCLOCK_Usb1PllPfd2Clk = 0xAU, /*!< USB1PLLPFD2CLK. */
kCLOCK_Usb1PllPfd3Clk = 0xBU, /*!< USB1PLLPFD3CLK. */
kCLOCK_Usb2PllClk = 0xCU, /*!< USB2PLLCLK. */
kCLOCK_SysPllClk = 0xDU, /*!< SYSPLLCLK. */
kCLOCK_SysPllPfd0Clk = 0xEU, /*!< SYSPLLPDF0CLK. */
kCLOCK_SysPllPfd1Clk = 0xFU, /*!< SYSPLLPFD1CLK. */
kCLOCK_SysPllPfd2Clk = 0x10U, /*!< SYSPLLPFD2CLK. */
kCLOCK_SysPllPfd3Clk = 0x11U, /*!< SYSPLLPFD3CLK. */
kCLOCK_EnetPll0Clk = 0x12U, /*!< Enet PLLCLK ref_enetpll0. */
kCLOCK_EnetPll1Clk = 0x13U, /*!< Enet PLLCLK ref_enetpll1. */
kCLOCK_AudioPllClk = 0x14U, /*!< Audio PLLCLK. */
kCLOCK_VideoPllClk = 0x15U, /*!< Video PLLCLK. */
} clock_name_t;
从中间找到我们需要的osc时钟。这样的话,就可以用MSEC_TO_COUNT(1000U, CLOCK_GetFreq(kCLOCK_OscClk))的到定时1s的计数值
然后开启有关中断
/*! @brief List of PIT interrupts */
typedef enum _pit_interrupt_enable
{
kPIT_TimerInterruptEnable = PIT_TCTRL_TIE_MASK, /*!< Timer interrupt enable*/
} pit_interrupt_enable_t;
(emmmmmmmm,也就一种)
配置好中断使能,最后就是开启计数,利用PIT_StartTimer。
编写中断回调函数
void PIT_IRQHandler(void)
{
if(PIT_GetStatusFlags(PIT, kPIT_Chnl_0) == kPIT_TimerFlag) //判断是不是对应中断
{
PIT_ClearStatusFlags(PIT, kPIT_Chnl_0, kPIT_TimerFlag);//清空中断标志位
LPUART_WriteByte(LPUART1, '1');
LPUART_WriteByte(LPUART1, '\r');
LPUART_WriteByte(LPUART1, '\n');
}
}
也没啥好说的。现象就是先打印 你好世界 然后每隔1S发送一个1
(注意为了便于观察实验结果,我开启了时间戳)
最后附上工程
MDK版本:5.22
pack:NXP.MIMXRT1052_DFP.10.0.1.pack
下载算法:飞凌嵌入式提供的 MIMXRT_QSPIFLASH.FLM
启动方式:spi flash启动
下载方式:STlink
4.pit.zip
(1.46 MB, 下载次数: 39)
|
|