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

Нужно добавить часы в проект на STM32.
Использую библиотеки ST и пример RTCCalendar.
При инициализации на RTC_WaitForLastTask() программа виснет.
В пошаговом режиме чаще проходит.
Может кто подскажет в чем может быть проблема.

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


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

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


Ссылка на сообщение
Поделиться на другие сайты
CODE
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]

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(ЛеонидК @ Nov 20 2010, 21:20) <{POST_SNAPBACK}>
Да



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

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(ЛеонидК @ Nov 20 2010, 12:58) <{POST_SNAPBACK}>
Использую библиотеки ST и пример RTCCalendar.
При инициализации на RTC_WaitForLastTask() программа виснет.
В пошаговом режиме чаще проходит.
Может кто подскажет в чем может быть проблема.


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

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


Ссылка на сообщение
Поделиться на другие сайты
Цитата(ЛеонидК @ Nov 20 2010, 18:03) <{POST_SNAPBACK}>
void RTC_Config(void) {...}

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

//******************************************************************************
// 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() не проходит.
И прерываний у меня нет. Я хочу смотреть часы, когда хочу, а не во время измерения.

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


Ссылка на сообщение
Поделиться на другие сайты
Вероятно, произошло вот что:

Привожу выдержку из мануала 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 на кварц. Впаял перемычку вместо него, ничего не изменилось.

Вот код инициализации часов:
CODE
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;

}


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

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


Ссылка на сообщение
Поделиться на другие сайты
Пришлось поменять микроконтроллер и все заработало....

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


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

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация