Перейти к содержанию
    

Нужно добавить часы в проект на STM32.

Использую библиотеки ST и пример RTCCalendar.

При инициализации на RTC_WaitForLastTask() программа виснет.

В пошаговом режиме чаще проходит.

Может кто подскажет в чем может быть проблема.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Делал часы реального времени на основе примеров от ST. Все четко работает. Так что код в студию.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

void RTC_Config(void) {
 u16 WaitForOscSource;
  if (BKP_ReadBackupRegister(BKP_DR1) != CONF_DONE) 
 {
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
 PWR_BackupAccessCmd(ENABLE);
  BKP_DeInit();
 RCC_LSEConfig(RCC_LSE_ON);
 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
 {}
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
  RCC_RTCCLKCmd(ENABLE);
 RTC_WaitForSynchro();
  RTC_WaitForLastTask();
  RTC_SetPrescaler(32767); 
  RTC_WaitForLastTask();
 DateVar.Month = DEFAULT_MOUNT;
 DateVar.Day = DEFAULT_DAY;
 DateVar.Year = DEFAULT_YEAR;
 TimeVar.Sec = DEFAULT_SEC;
 TimeVar.Min = DEFAULT_MIN;
 TimeVar.Hour = DEFAULT_HOUR;
 SummerTimeCorrect =OCTOBER_FLAG_SET;
 BKP_WriteBackupRegister(BKP_DR1,CONF_DONE);
 RTC_DataWrite();
    }
 else
 {
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
   RTC_WaitForSynchro();
   RTC_WaitForLastTask();
} 
}

Изменено пользователем IgorKossak
[codebox]

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да

 

 

Тогда может Вам стоит проверить конкретно биты в регистрах, почему не устанавливаються флаги?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Использую библиотеки ST и пример RTCCalendar.

При инициализации на RTC_WaitForLastTask() программа виснет.

В пошаговом режиме чаще проходит.

Может кто подскажет в чем может быть проблема.

 

Генератор часов раскачивается полминуты в моем случае, потом, после первой инициализации все нормально, пока батарейку не выдернешь. Советую посмотреть, правильные ли нагрузочные емкости к Вашему кварцу?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

void RTC_Config(void) {...}

Что-то здесь не так с последовательностью инициализации (хотя вдумчиво не смотрел). Посмотрите как у меня сделано.

//******************************************************************************
// RTC_DRV_CPP
// DESCRIPTION:
// Драйвер аппаратного RTC.
// При совпадении текущего времени с заданными временами,
// вызывается пользовательский обработчик (из прерывания).
//
//******************************************************************************

#include "rtc_drv.h"
#include "platform_config.h"
#include "stm32f10x.h"
#include "helper.h"

//------------------------------------------------------------------------------
// T Y P E S and D E F I N I T I O N S
//------------------------------------------------------------------------------

namespace
{
const Time zero_time = {0,0,0};
const uint32_t sec_per_day = 0x00015180; // = 24*60*60
enum {nch = 2}; // Кол-во каналов для сравнения.
const uint16_t key = 0xA5A5;
} // ns

//------------------------------------------------------------------------------
// G L O B A L V A R I A B L E S
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// L O C A L S
//------------------------------------------------------------------------------
namespace
{
// Prototypes.
void enable_bkp();    
bool rtc_config();
void set_time(const Time& tm);
uint32_t time2int(Time tm);
Time int2time(uint32_t u);

// Variables.
rtc_drv::Cmp_callback callback;
uint32_t cmp_time[nch];
} // ns


//==============================================================================
// I M P L E M E N T A T I O N
//==============================================================================

namespace rtc_drv
{
//------------------------------------------------------------------------------
// Инициализация и запуск "железа".
// Возврат 0 - ошибок нет; 1 - кварц не запустился; 2 - восстановление по
// умолчанию (следствие разряда батареи).
uint8_t init()
{
   uint8_t res = 0;
   NVIC_InitTypeDef NVIC_InitStructure;

   // Enable the RTC Interrupt.
   NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = RTC_PRIORITY;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = RTC_SUBPRIORITY;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);

   enable_bkp();

   // Наличие правильной настройки определяется по ключевому значению в 
   // регистре в BKP domain.
   if (key != BKP_ReadBackupRegister(BKP_DR1))
   {
       // Backup data register value is not correct or not yet programmed (when
       // the first time the program is executed).
       if (!rtc_config())
       {
           return 1;
       }
       set_time(zero_time);
       BKP_WriteBackupRegister(BKP_DR1, key);
       res = 2;
   }
   else
   {
       // Без основного питания может пройти не один день. Счетчик необходимо
       // привести в надлежащее состояние.

       // Wait for RTC registers synchronization.
       RTC_WaitForSynchro();
       uint32_t ticks = RTC_GetCounter();
       ticks = ticks % sec_per_day;
       set_time(int2time(ticks));
   }

   // Enable the RTC Second interrupt.
   RTC_WaitForSynchro();
   RTC_ITConfig(RTC_IT_SEC, ENABLE);
   RTC_WaitForLastTask();

   // RTC clock output.
   // Disable the Tamper Pin.
   // To output RTCCLK/64 on Tamper pin,
   // the tamper functionality must be disabled.
   BKP_TamperPinCmd(DISABLE); 
   // Enable RTC Clock Output on Tamper Pin.
   BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);

   return res;
}

//------------------------------------------------------------------------------
// Возврат текущего времени.
Time time()
{
   return int2time(RTC_GetCounter());
}

//------------------------------------------------------------------------------
// Установка текущего времени.
void time(const Time& tm)
{
   set_time( tm );
}

//------------------------------------------------------------------------------
// Устанавливает значение делителя для получения секундного интервала.
void set_divider(uint32_t div)
{
   if (div)
   {
       // Wait until last write operation on RTC registers has finished.
       RTC_WaitForLastTask();
       // Enable the RTC Second interrupt.
       // Set RTC prescaler: set RTC period to 1sec.
       RTC_SetPrescaler(div-1); // RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(div+1)
       // Wait until last write operation on RTC registers has finished.
       RTC_WaitForLastTask();
   }
}

//------------------------------------------------------------------------------
// Устанавливает обработчик.
// При вызове обработчика, ему передается номер канала, в котором было совпадение.
void set_callback(Cmp_callback cb)
{
   callback = cb;
}

//------------------------------------------------------------------------------
// Устанавливает время для сравнения.
// ch =[0,1] - канал совпадения.
void set_cmp_time(uint8_t ch, const Time& tm)
{
   if (ch < nch)
       cmp_time[ch] = time2int( tm );
}

} // namespace rtc_drv

//------------------------------------------------------------------------------
// Обработчик секундного прерывания.
extern "C"
void RTC_IRQHandler()
{
   if (RESET != RTC_GetITStatus(RTC_IT_SEC))
   {
       RTC_ClearITPendingBit(RTC_IT_SEC);
       RTC_WaitForLastTask();
       // Reset RTC Counter when Time is 23:59:59.
       uint32_t curr = RTC_GetCounter();
       if (sec_per_day == curr)
       {
           curr = 0;
           RTC_SetCounter(0);
           RTC_WaitForLastTask();
       }

       // Проверка на совпадение.
       for (uint_fast8_t i=0; i<nch; ++i)
       {
           if (curr == cmp_time[i] && callback)
               callback(i);
       }
   }
}


//==============================================================================
// Local functions.

namespace
{
//------------------------------------------------------------------------------
// Открывает доступ к регистрам из bkp domain.
void enable_bkp()
{
   // Enable PWR and BKP clocks.
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
   // Allow access to BKP Domain.
   PWR_BackupAccessCmd(ENABLE);
}

//------------------------------------------------------------------------------
// Настраивает и запускает аппаратный rtc.
// Возврат true, если ошибок нет.
bool rtc_config()
{
   BKP_DeInit();

   // Enable LSE.
   RCC_LSEConfig(RCC_LSE_ON);

   // Wait till LSE is ready (но не более 3 секунд).
   uint32_t i=0;
   while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET  && i<3000)
   {
       delay_us(1000);
       ++i;
   }
   if (i >= 3000) return false;

   // Select LSE as RTC Clock Source.
   RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
   // Enable RTC Clock.
   RCC_RTCCLKCmd(ENABLE);
   // Wait for RTC registers synchronization.
   RTC_WaitForSynchro();
   rtc_drv::set_divider(rtc_drv::divider_def);
   return true;
}

//------------------------------------------------------------------------------
// Устанавливает новое значение времени.
void set_time(const Time& tm)
{
   // Wait until last write operation on RTC registers has finished.
   RTC_WaitForLastTask();
   // Change the current time.
   RTC_SetCounter(time2int);
   // Wait until last write operation on RTC registers has finished.
   RTC_WaitForLastTask();
}

//------------------------------------------------------------------------------
// Преобразование времени в число и обратно.
uint32_t time2int(Time tm)
{
   return (tm.hour*3600 + tm.min*60 + tm.sec);
}

Time int2time(uint32_t u)
{
   Time tm = {u/3600, (u%3600)/60, (u%3600)%60};
   return tm;
}

} // ns

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так то оно так, только RTC_WaitForLastTask() не проходит.

И прерываний у меня нет. Я хочу смотреть часы, когда хочу, а не во время измерения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос снимается.

Удалил лишнее RTC_WaitForLastTask().

Правда четкого понимания нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вероятно, произошло вот что:

 

Привожу выдержку из мануала RM0008 стр 464:

 

To enable access to the Backup registers and the RTC, proceed as follows:

● enable the power and backup interface clocks by setting the PWREN and BKPEN bits

in the RCC_APB1ENR register

● set the DBP bit the Power Control Register (PWR_CR) to enable access to the Backup

registers and RTC.

 

Похоже, второй пункт у Вас не выполнен!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Еще вопрос по часам.

 

Плата stm32discovery не могу запустить часы от внешнего кварца. Смотрел осцилом - нет генерации на кварце. На OSC32_OUT просто 3 вольта. На OSC32_IN что то около нуля. Самое странное на плате не было резистора R15 который как раз идет с OSC32_OUT на кварц. Впаял перемычку вместо него, ничего не изменилось.

 

Вот код инициализации часов:

unsigned char  RtcInit  (void)
{
//разрешить тактирование модулей управления питанием и управлением резервной областью
 RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN;
 //разрешить доступ к области резервных данных
 PWR->CR |= PWR_CR_DBP;

 //если часы выключены - инициализировать их
 if ((RCC->BDCR & RCC_BDCR_RTCEN) != RCC_BDCR_RTCEN)
 {
   //выполнить сброс области резервных данных
   RCC->BDCR |=  RCC_BDCR_BDRST;
   RCC->BDCR &= ~RCC_BDCR_BDRST;


   //выбрать источником тактовых импульсов внешний кварц 32768 и подать тактирование
   RCC->BDCR |=  RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL_LSE;

   RTC->CRL  |=  RTC_CRL_CNF;
   RTC->PRLL  = 0x7FFF;         //регистр деления на 32768
   RTC->CRL  &=  ~RTC_CRL_CNF;

   //установить бит разрешения работы и дождаться установки бита готовности
   RCC->BDCR |= RCC_BDCR_LSEON;
   while ((RCC->BDCR & RCC_BDCR_LSERDY) != RCC_BDCR_LSERDY);

   RTC->CRL &= (uint16_t)~RTC_CRL_RSF;
   while((RTC->CRL & RTC_CRL_RSF) != RTC_CRL_RSF){}

   return 1;
 }
 return 0;

}

 

Что может быть?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...