В данной серии статей будут приведены примеры работы с периферией STM32L с помощью библиотеки, предоставляемой ST — StdPeriph. Перед использованием примеров не забывайте включать, соответствующие файлы библиотеки в проект.
- Порты GPIOx
- Прерывания
- Timer 6
- USART
- I2C
- SPI
- DMA
- Системный таймер
- EEPROM
- RTC
- Тактирование 32МГц с настройкой пропуска такта flash
RTC
Доступ к RTC
После сброса RTC регистры защищены от случайной записи. Разрешение доступа к регистру доступа к **RTC(я знаю звучит как тавтология, но это так — см. ReferenceManual):
- Включение тактирования power interface установкой PWREN в RCC_APB1ENR.
- Установка DBP бита в PWR_CR регистре (разрешает доступ к регистрам RTC)
- Выбираем источник тактирования RTC через RTCSEL[1:0] биты RCC_CSR регистра.
- Включение RTC тактирования, RTCEN бит в регистре RCC_CSR.
Тактирование RTC
RTC может тактироваться от LSE, LSI или **HSE. Для получения 1 Гц на RTC — используют 2 предделителя частоты(асинхронный 7 бит, простой 13/15 бит). Для изменения источника тактирования RTC необходимо установить RTCRST бит в RCCCSR регистре и сбросить его обратно в 0. Бит RTCEN в регистре RCCCSR включает/отключает тактирование RTC(кроме того данный бит сбрасывается установкой RTCRST — см. выше).
note: Для тактирования от 32.768 kHz — предделители должны быть настроены на 128 и 256(в регистрах 127 и 255). Частота после всех предделителей рассчитывается как F_rtcclk/ ((асинхронный предделитель + 1)x(простой предделитель + 1)).
Инициализация RTC
Вначале мы снимаем запрет на доступ к регистру доступа к RTC(описано выше).
- Снимаем защиту записи в регистры RTC. Для этого пишем 0xCA и 0x53 в RTC_WPR регистр.
- Устанавливаем INIT бит в RTC_ISR регистре для входа в режим инициализации. В этом режиме календарь остановлен и его значение может быть изменено.
- Ждем подтверждения входа в режим инициализации RTC. Для этого ждем установки INITF бита в регистре RTC_ISR. Это длится примерно два такта RTCCLK.
- Программируем предделители для получения 1 Гц.
- Заполняем календарь датой и временем в регистрах RTCTR и RTCDR. Настраиваем 12 или 24 часовой формат в RTC_CRрегистре.
- Выход из режима инициализации. Для этого очищаем INIT бит в RTC_ISR регистре.
- Устанавливаем защиту на запись в регистры. Для этого пишем 0xFF в RTC_WPR регистр.
Пример:
void RTC_init(void)
{
RTC_TimeTypeDef RTC_Time;
RTC_InitTypeDef RTCInit;
// разрешенме доступа к регистру доступа RTC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_RTCAccessCmd(ENABLE);
// настройка тактирования RTC
RCC_LSICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
// настройка предделителя и вкл. RTC
// все необходимыве настройки (описанные выше) в RTC_Init()
// 1 Hz = 37000 Hz / (127+1)x(288+1)
RTCInit.RTC_HourFormat = RTC_HourFormat_24;
RTCInit.RTC_AsynchPrediv = 127;
RTCInit.RTC_SynchPrediv = 288;
RTC_Init(&RTCInit);
//RTC_Time.RTC_H12 = RTC_H12_AM; // не важно т.к. RTC_HourFormat_24
RTC_Time.RTC_Hours = 0x01;
RTC_Time.RTC_Minutes = 0x00;
RTC_Time.RTC_Seconds = 0x00;
RTC_SetTime(RTC_Format_BIN, &RTC_Time);
}
Для получения данных из RTC:
RTC_TimeTypeDef RTC_Time;
RTC_GetTime(RTC_Format_BIN, &RTC_Time);
Настройка и использование RTC ALARM
RTC ALARM прерывание происходит когда календарь укажет на определенную (заданную вами) дату и время.
Настройка RTC ALARM:
void RTC_alarm_config(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
RTC_AlarmTypeDef RTC_AlarmStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RTC_AlarmCmd(RTC_Alarm_A, DISABLE);
EXTI_ClearITPendingBit(EXTI_Line17);
EXTI_InitStructure.EXTI_Line = EXTI_Line17;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// маска позволяет использовать не всю дату целиком, а только ее часть
// например в этом примере срабатывает каждый день (дата, день и число не проверяются)
RTC_AlarmStructure.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay;
RTC_AlarmStructure.RTC_AlarmTime.RTC_H12 = RTC_HourFormat_24;
RTC_AlarmStructure.RTC_AlarmTime.RTC_Hours = 15;
RTC_AlarmStructure.RTC_AlarmTime.RTC_Minutes = 0;
RTC_AlarmStructure.RTC_AlarmTime.RTC_Seconds = 5;
// следующие два параметра в нашем примере не имеют значения - см. маску
RTC_AlarmStructure.RTC_AlarmDateWeekDay = 1; // день недели или месяца
RTC_AlarmStructure.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_WeekDay; // неделя или месяц
RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A, &RTC_AlarmStructure);
//RTC_AlarmSubSecondConfig(RTC_Alarm_A, 0xFF, RTC_AlarmSubSecondMask_SS14_5);
// настраиваем вывод сигнала о срабатывание alarm на RTC_OUT (stm32l - RC13)
RTC_OutputConfig(RTC_Output_AlarmA, RTC_OutputPolarity_High);
RTC_OutputTypeConfig(RTC_OutputType_PushPull);
/* Enable AlarmA interrupt */
RTC_ITConfig(RTC_IT_ALRA, ENABLE);
RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
RTC_ClearITPendingBit(RTC_IT_ALRA);
}
Кроме того, если хотите, чтобы на RTC_OUT выводился сигнал о срабатывание RTC ALARM — надо настроить этот pin (PC13):
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //(_OUT, _AF, _AN)
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_400KHz; //(_2MHz, _10MHz, 40MHz)
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //(_NOPULL, _UP)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //(_0 ... _15)
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //(_PP - push/pull, _OD - open drain)
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource13, GPIO_AF_RTC_AF1);
И само прерывание:
void RTC_Alarm_IRQHandler()
{
if(RTC_GetITStatus(RTC_IT_ALRA) != RESET)
{
RTC_ClearITPendingBit(RTC_IT_ALRA);
EXTI_ClearITPendingBit(EXTI_Line17);
}
}