一:设置NVIC组,使能 RTC irq,设置RTC优先级(抢占优先级和响应优先级)
void nvic_configuration(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
nvic_irq_enable(RTC_IRQn,1,0);
}
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
设置中断向量控制器组
这里设置为GROUP2 => NVIC_PRIGROUP_PRE2_SUB2
GROUP2意味着最高2位用于抢占式优先级,最低2位用于响应优先级,也就是说可以设置2^2 = 4个抢占式优先级,每个抢占式优先级中可以有2^2=4个响应优先级。其实通过不同的排列组合可以构成2^4 = 16个优先级
这些级别意味着什么呢?
抢占式优先级顾名思义是说定义了这些级别,是可以抢占其他优先级,当然是级别高的抢占级别低的了。
如果2个中断的抢占优先级相同呢?那响应优先级就用上了,2个中断抢占优先级相同,则响应优先级高的先响应了。
那要是两个中断设置了相同的抢占优先级和相同的响应优先级呢?同时中断的情况下,谁先响应呢?
答案:会先响应中断通道号低的中断处理函数(比如RTC的中断通道号是19,DMA0 Channel0的是27)
先响应RTC的
; /* external interrupts handler */
DCD WWDGT_IRQHandler ; 16:Window Watchdog Timer
DCD LVD_IRQHandler ; 17:LVD through EXTI Line detect
DCD TAMPER_IRQHandler ; 18:Tamper through EXTI Line detect
DCD RTC_IRQHandler ; 19:RTC through EXTI Line
DCD FMC_IRQHandler ; 20:FMC
DCD RCU_CTC_IRQHandler ; 21:RCU and CTC
DCD EXTI0_IRQHandler ; 22:EXTI Line 0
DCD EXTI1_IRQHandler ; 23:EXTI Line 1
DCD EXTI2_IRQHandler ; 24:EXTI Line 2
DCD EXTI3_IRQHandler ; 25:EXTI Line 3
DCD EXTI4_IRQHandler ; 26:EXTI Line 4
DCD DMA0_Channel0_IRQHandler ; 27:DMA0 Channel0
DCD DMA0_Channel1_IRQHandler ; 28:DMA0 Channel1
DCD DMA0_Channel2_IRQHandler ; 29:DMA0 Channel2
DCD DMA0_Channel3_IRQHandler ; 30:DMA0 Channel3
DCD DMA0_Channel4_IRQHandler ; 31:DMA0 Channel4
DCD DMA0_Channel5_IRQHandler ; 32:DMA0 Channel5
DCD DMA0_Channel6_IRQHandler ; 33:DMA0 Channel6
DCD ADC0_1_IRQHandler ; 34:ADC0 and ADC1
DCD CAN0_TX_IRQHandler ; 35:CAN0 TX
DCD CAN0_RX0_IRQHandler ; 36:CAN0 RX0
DCD CAN0_RX1_IRQHandler ; 37:CAN0 RX1
DCD CAN0_EWMC_IRQHandler ; 38:CAN0 EWMC
DCD EXTI5_9_IRQHandler ; 39:EXTI5 to EXTI9
DCD TIMER0_BRK_TIMER8_IRQHandler ; 40:TIMER0 Break and TIMER8
DCD TIMER0_UP_TIMER9_IRQHandler ; 41:TIMER0 Update and TIMER9
DCD TIMER0_TRG_CMT_TIMER10_IRQHandler ; 42:TIMER0 Trigger and Commutation and TIMER10
DCD TIMER0_Channel_IRQHandler ; 43:TIMER0 Channel Capture Compare
DCD TIMER1_IRQHandler ; 44:TIMER1
DCD TIMER2_IRQHandler ; 45:TIMER2
DCD TIMER3_IRQHandler ; 46:TIMER3
DCD I2C0_EV_IRQHandler ; 47:I2C0 Event
DCD I2C0_ER_IRQHandler ; 48:I2C0 Error
DCD I2C1_EV_IRQHandler ; 49:I2C1 Event
DCD I2C1_ER_IRQHandler ; 50:I2C1 Error
DCD SPI0_IRQHandler ; 51:SPI0
DCD SPI1_IRQHandler ; 52:SPI1
DCD USART0_IRQHandler ; 53:USART0
DCD USART1_IRQHandler ; 54:USART1
DCD USART2_IRQHandler ; 55:USART2
DCD EXTI10_15_IRQHandler ; 56:EXTI10 to EXTI15
DCD RTC_Alarm_IRQHandler ; 57:RTC Alarm
DCD USBFS_WKUP_IRQHandler ; 58:USBFS Wakeup
DCD TIMER7_BRK_TIMER11_IRQHandler ; 59:TIMER7 Break and TIMER11
DCD TIMER7_UP_TIMER12_IRQHandler ; 60:TIMER7 Update and TIMER12
DCD TIMER7_TRG_CMT_TIMER13_IRQHandler ; 61:TIMER7 Trigger and Commutation and TIMER13
DCD TIMER7_Channel_IRQHandler ; 62:TIMER7 Channel Capture Compare
DCD 0 ; 63:Reserved
DCD EXMC_IRQHandler ; 64:EXMC
DCD 0 ; 65:Reserved
DCD TIMER4_IRQHandler ; 66:TIMER4
DCD SPI2_IRQHandler ; 67:SPI2
DCD UART3_IRQHandler ; 68:UART3
DCD UART4_IRQHandler ; 69:UART4
DCD TIMER5_IRQHandler ; 70:TIMER5
DCD TIMER6_IRQHandler ; 71:TIMER6
DCD DMA1_Channel0_IRQHandler ; 72:DMA1 Channel0
DCD DMA1_Channel1_IRQHandler ; 73:DMA1 Channel1
DCD DMA1_Channel2_IRQHandler ; 74:DMA1 Channel2
DCD DMA1_Channel3_IRQHandler ; 75:DMA1 Channel3
DCD DMA1_Channel4_IRQHandler ; 76:DMA1 Channel4
DCD 0 ; 77:Reserved
DCD 0 ; 78:Reserved
DCD CAN1_TX_IRQHandler ; 79:CAN1 TX
DCD CAN1_RX0_IRQHandler ; 80:CAN1 RX0
DCD CAN1_RX1_IRQHandler ; 81:CAN1 RX1
DCD CAN1_EWMC_IRQHandler ; 82:CAN1 EWMC
DCD USBFS_IRQHandler ; 83:USBFS
nvic_irq_enable(RTC_IRQn,1,0);
这个就是设置中断号,和对应的抢占和响应优先级了。
贴下剩余的RTC设置
void rtc_configuration(void)
{
/* enable PMU and BKPI clocks */
rcu_periph_clock_enable(RCU_BKPI);
rcu_periph_clock_enable(RCU_PMU);
/* allow access to BKP domain */
pmu_backup_write_enable();
/* reset backup domain */
bkp_deinit();
/* enable LXTAL */
rcu_osci_on(RCU_LXTAL);
/* wait till LXTAL is ready */
rcu_osci_stab_wait(RCU_LXTAL);
/* select RCU_LXTAL as RTC clock source */
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
/* enable RTC Clock */
rcu_periph_clock_enable(RCU_RTC);
/* wait for RTC registers synchronization */
rtc_register_sync_wait();
/* wait until last write operation on RTC registers has finished */
rtc_lwoff_wait();
/* enable the RTC second and alarm interrupt*/
rtc_interrupt_enable(RTC_INT_SECOND);
rtc_interrupt_enable(RTC_INT_ALARM);
/* wait until last write operation on RTC registers has finished */
rtc_lwoff_wait();
/* set RTC prescaler: set RTC period to 1s */
rtc_prescaler_set(32767);
/* wait until last write operation on RTC registers has finished */
rtc_lwoff_wait();
}
rcu_periph_clock_enable(RCU_BKPI);
注释上说了,这是打开BKPI时钟。
这里说下BKPI
BKP位于备份域中的备份寄存器可以在Vdd电源关闭时候由Vbat供电,备份寄存器有42个16位(84字节)寄存器可用来存储并保护用户应用数据,从待机模式唤醒或系统复位也不会对这些寄存器造成影响
从上面就可以看出“PMU”对BKP的影响,所以代码中要做这样的设置
rcu_periph_clock_enable(RCU_PMU);
/* allow access to BKP domain */
pmu_backup_write_enable();
在操作BKP 之前要先做下复位动作,这个很容易想到,你要操作某组寄存器先要把它恢复到一个初始的状态
/* reset backup domain */
bkp_deinit();
接下来看RTC所用时钟的配置
/* enable LXTAL */
rcu_osci_on(RCU_LXTAL);
/* wait till LXTAL is ready */
rcu_osci_stab_wait(RCU_LXTAL);
/* select RCU_LXTAL as RTC clock source */
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
这里我们要实现RTC功能。。。。哦,不,不能这样说,不应该说要实现RTC功能。
是要实现系统能够准确的显示时间,或者说让我们的系统能知道当前的时间功能,我们需要借助RTC(real time clock)来做秒计数,要借助BKP来保存这个时间,
看
/* select RCU_LXTAL as RTC clock source */
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
void rcu_rtc_clock_config(uint32_t rtc_clock_source)
{
uint32_t reg;
reg = RCU_BDCTL;
/* reset the RTCSRC bits and set according to rtc_clock_source */
reg &= ~RCU_BDCTL_RTCSRC;
RCU_BDCTL = (reg | rtc_clock_source);
}
/* RTC clock entry selection */
#define BDCTL_RTCSRC(regval) (BITS(8,9) & ((uint32_t)(regval) << 8))
#define RCU_RTCSRC_NONE BDCTL_RTCSRC(0) /*!< no clock selected */
#define RCU_RTCSRC_LXTAL BDCTL_RTCSRC(1) /*!< RTC source clock select LXTAL */
#define RCU_RTCSRC_IRC40K BDCTL_RTCSRC(2) /*!< RTC source clock select IRC40K */
#define RCU_RTCSRC_HXTAL_DIV_128 BDCTL_RTCSRC(3) /*!< RTC source clock select HXTAL/128 */
上面的LXTAL,IRC40K,HXTAL_DIV 分别是1,2,3从clock tree上就可以看出来
提供给CK_RTC 的有三路选择,11 就是HXTAL的128分频
01就是直接32.768K,10就是 IRC40K
/* RTC clock entry selection */
#define BDCTL_RTCSRC(regval) (BITS(8,9) & ((uint32_t)(regval) << 8))
/* wait for RTC registers synchronization */
rtc_register_sync_wait();
/* wait until last write operation on RTC registers has finished */
rtc_lwoff_wait();
等待RTC寄存器写操作完成
/* enable the RTC second and alarm interrupt*/
rtc_interrupt_enable(RTC_INT_SECOND);
rtc_interrupt_enable(RTC_INT_ALARM);
使能秒中断和闹钟中断
/* set RTC prescaler: set RTC period to 1s */
rtc_prescaler_set(32767);
设置RTC预分频的值32767
初始化的工作做完了。
之后就可以在RTC寄存器中设置时间值了。
/*!
\brief set RTC counter value
\param[in] cnt: RTC counter value
\param[out] none
\retval none
*/
void rtc_counter_set(uint32_t cnt)
{
rtc_configuration_mode_enter();
/* set the RTC counter high bits */
RTC_CNTH = (cnt >> RTC_HIGH_BITS_OFFSET);
/* set the RTC counter low bits */
RTC_CNTL = (cnt & RTC_LOW_BITS_MASK);
rtc_configuration_mode_exit();
}
RTC_CNTH 和 RTC_CNTL就对应前面的SPEC