Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ATSAM3S4B flash wait states
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Genadi Zawidowski
Поставил чип ATSM3S4B взамен AT91SAM7S64.
Обнаружилось, что при запуске холодного устрйства иногда происходит зависание (не выяснял, что стряслось).
ВЫлечилось установкой значения 3 в качестве wait states для FLASH (хотя, такое рекомендуется при частоте 64 МГц только при питании 1.65 вольта). У меня же - 1.8 от внутреннего стабилизатора (китайский тестер показывает 1.75 - но это скорее всего заниженно).
Или установкой 32 МГц (и 2 wait states).

Вот инициализация (некоторые комментарии про частоты устарели).

CODE
// Clock Source Selection
static void program_mckr_css(unsigned long cssvalue)
{
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~ PMC_MCKR_CSS_Msk) | (cssvalue & PMC_MCKR_CSS_Msk);
// Wiat MCLK ready
while ((PMC->PMC_SR & PMC_SR_MCKRDY) == 0)
;
}
// CPU prescaler
static void program_mckr_pres(unsigned long presvalue)
{
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~ PMC_MCKR_PRES_Msk) | (presvalue & PMC_MCKR_PRES_Msk);
// Wiat MCLK ready
while ((PMC->PMC_SR & PMC_SR_MCKRDY) == 0)
;
}

// If a new value for CSS field corresponds to PLL Clock,
static void program_mckr_switchtopll_a(void)
{
program_mckr_pres(PMC_MCKR_PRES_CLK_2); // with /2 divider
program_mckr_css(PMC_MCKR_CSS_PLLA_CLK);
}

// If a new value for CSS field corresponds to Main Clock
static void program_mckr_switchtomain(void)
{
program_mckr_css(PMC_MCKR_CSS_MAIN_CLK);
#ifdef PMC_MCKR_PRES_CLK_1
program_mckr_pres(PMC_MCKR_PRES_CLK_1); // w/o divider
#else
program_mckr_pres(PMC_MCKR_PRES_CLK); // w/o divider
#endif
}

static void program_use_xtal(
int useXtalFlag /* 0 - использование RC генератора, не-0 - использование кварцевого генератора */
)
{
// бит CKGR_MOR_MOSCSEL - источник MAINCK это кварцевый генератор
const unsigned long mor = PMC->CKGR_MOR & ~ CKGR_MOR_KEY_Msk;
if (((mor & CKGR_MOR_MOSCSEL) != 0) == (useXtalFlag != 0))
return; // переключение не требуется

if (useXtalFlag != 0)
PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | (mor | CKGR_MOR_MOSCSEL);
else
PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | (mor & ~ CKGR_MOR_MOSCSEL);

// ожидание переключения кварцевого генератора
while ((PMC->PMC_SR & PMC_SR_MOSCSELS) == 0)
;
}

// Enable on-chip RC oscillator
static void program_enable_RC_12MHz(void)
{
#ifdef CKGR_MOR_MOSCRCF_12_MHz
PMC->CKGR_MOR = (PMC->CKGR_MOR & ~ (CKGR_MOR_MOSCRCF_Msk | CKGR_MOR_KEY_Msk)) | // остальные биты не трогаем
CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCRCF_12_MHz;
#else
PMC->CKGR_MOR = (PMC->CKGR_MOR & ~ (CKGR_MOR_MOSCRCF_Msk | CKGR_MOR_KEY_Msk)) | // остальные биты не трогаем
CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCRCF_12MHZ;
#endif
// ожидание запуска RC генератора
while ((PMC->PMC_SR & PMC_SR_MOSCRCS) == 0)
;
}

static void program_disable_rc(void)
{
const unsigned long mor = PMC->CKGR_MOR & ~ (CKGR_MOR_KEY_Msk | CKGR_MOR_MOSCRCEN);
PMC->CKGR_MOR = mor | CKGR_MOR_KEY(0x37);
}

static void program_disable_xtal(void)
{
const unsigned long mor = PMC->CKGR_MOR & ~ (CKGR_MOR_KEY_Msk | CKGR_MOR_MOSCXTEN);
PMC->CKGR_MOR = mor | CKGR_MOR_KEY(0x37);
}

// Enable high-frequency XTAL oscillator
static void program_enable_xtal(void)
{
const unsigned long mor = PMC->CKGR_MOR & ~ (CKGR_MOR_KEY_Msk | CKGR_MOR_MOSCXTST_Msk);
if ((mor & CKGR_MOR_MOSCXTEN) != 0)
return; // кварцевый генератор уже запущен

PMC->CKGR_MOR =
mor | // стврые значения битов
CKGR_MOR_KEY(0x37) |
CKGR_MOR_MOSCXTST(128) |
CKGR_MOR_MOSCXTEN;
// ожидание запуска кварцевого генератора
while ((PMC->PMC_SR & PMC_SR_MOSCXTS) == 0)
;
}

static void program_enable_plla(unsigned pllmul, unsigned plldiv)
{
#ifdef CKGR_PLLAR_ONE
/* Initialize PLLA */
PMC->CKGR_PLLAR =
(CKGR_PLLAR_ONE | // всегда должен быть установлен
((pllmul - 1) << CKGR_PLLAR_MULA_Pos) |
(0x4 << CKGR_PLLAR_PLLACOUNT_Pos) |
(plldiv << CKGR_PLLAR_DIVA_Pos));
#else
/* Initialize PLLA */
PMC->CKGR_PLLAR =
(CKGR_PLLAR_STUCKTO1 | // всегда должен быть установлен
((pllmul - 1) << CKGR_PLLAR_MULA_Pos) |
(0x4 << CKGR_PLLAR_PLLACOUNT_Pos) |
(plldiv << CKGR_PLLAR_DIVA_Pos));
#endif
// Ожидание запуска PLL A
while (!(PMC->PMC_SR & PMC_SR_LOCKA))
;
}

#if 0
// unused now.
static void program_enable_pllb(void)
{
//unsigned timer = 0xffffff;
//enum { osc_mul = 32, osc_div = 6 }; // 12 MHz / 6 * 32 = 64 MHz
enum { osc_mul = 8, osc_div = 1 }; // 12 MHz / 1 * 8 = 96 MHz
//enum { osc_mul = 32, osc_div = 3 }; // 12 MHz / 3 * 32 = 128 MHz

/* Initialize PLLA */
PMC->CKGR_PLLBR =
//CKGR_PLLBR_STUCKTO1 | // всегда должен быть установлен
((osc_mul - 1) << CKGR_PLLBR_MULB_Pos) |
(0x1 << CKGR_PLLBR_PLLBCOUNT_Pos) |
(osc_div << CKGR_PLLBR_DIVB_Pos);
//timeout = 0;
//while (!(PMC->PMC_SR & PMC_SR_LOCKA) && (timeout++ < CLOCK_TIMEOUT))
while ((PMC->PMC_SR & PMC_SR_LOCKB) == 0)
;
}


// If a new value for CSS field corresponds to Slow Clock,
static void program_mckr_switchtoslow(void)
{
program_mckr_css(PMC_MCKR_CSS_SLOW_CLK);
#ifdef PMC_MCKR_PRES_CLK_1
program_mckr_pres(PMC_MCKR_PRES_CLK_1); // w/o divider
#else
program_mckr_pres(PMC_MCKR_PRES_CLK); // w/o divider
#endif
}


#endif

/*
инициализация внутреннего умножителя частоты.
Вход - 12 МГц, внутренний RC генератор (12 МГц).
внутренняя тактовая - 48 МГц,
//частота генератора - 96 МГц
Частота сраавнения PLL = 12 МГц
*/
static void lowlevel_sam3s_init_pll_clock_12_RC12(void)
{
// Embedded Flash Wait State VDDCORE set at 1.80V
// FWS field = 0: up to 22 MHz
// FWS field = 1: up to 38 MHz
// FWS field = 2: up to 64 MHz
//EFC->EEFC_FMR = EEFC_FMR_FWS_Msk & (0U << EEFC_FMR_FWS_Pos);
EFC->EEFC_FMR = EEFC_FMR_FWS(3); // Flash Wait State

//program_mckr_switchtoslow(); // переключаем на внутренний генератор 32 кГц
program_mckr_switchtomain(); // выключить ФАПЧ, если была включена (проблема, если ранее был не ресет)
program_enable_RC_12MHz();
program_use_xtal(0);
program_disable_xtal();

EFC->EEFC_FMR = EEFC_FMR_FWS(0); // Flash Wait State
}


/*
инициализация внутреннего умножителя частоты.
Вход - 12 МГц, внутренний RC генератор (12 МГц).
внутренняя тактовая - 48 МГц,
//частота генератора - 96 МГц
Частота сраавнения PLL = 12 МГц
*/
static void lowlevel_sam3s_init_pll_clock_48_RC12(unsigned pllmul, unsigned plldiv, unsigned fws)
{
// Embedded Flash Wait State VDDCORE set at 1.80V
// FWS field = 0: up to 22 MHz
// FWS field = 1: up to 38 MHz
// FWS field = 2: up to 64 MHz
EFC->EEFC_FMR = EEFC_FMR_FWS(3); // Flash Wait State

//program_mckr_switchtoslow(); // переключаем на внутренний генератор 32 кГц
program_mckr_switchtomain(); // выключить ФАПЧ, если была включена
program_enable_RC_12MHz();
program_use_xtal(0);
program_disable_xtal();
program_enable_plla(pllmul, plldiv);
//program_enable_pllb();
program_mckr_switchtopll_a();

EFC->EEFC_FMR = EEFC_FMR_FWS(fws); // Flash Wait State
}

/*
инициализация внутреннего умножителя частоты.
Вход - 12 МГц, кварцевый резонатор
внутренняя тактовая - 64 МГц,
частота генератора - 12 МГц
Частота сраавнения PLL = 4 МГц
*/
static void
lowlevel_sam3s_init_pll_clock_48_xtal12(unsigned pllmul, unsigned plldiv, unsigned ws)
{
// Embedded Flash Wait State VDDCORE set at 1.80V
// FWS field = 0: up to 22 MHz
// FWS field = 1: up to 38 MHz
// FWS field = 2: up to 64 MHz
EFC->EEFC_FMR = EEFC_FMR_FWS(3); // Flash Wait State

//program_mckr_switchtoslow(); // переключаем на внутренний генератор 32 кГц
program_mckr_switchtomain(); // выключить ФАПЧ, если была включена
program_enable_xtal();
program_use_xtal(1);
program_disable_rc();
program_enable_plla(pllmul, plldiv);
//program_enable_pllb();
program_mckr_switchtopll_a();

EFC->EEFC_FMR = EEFC_FMR_FWS(ws); // Flash Wait State
}

/* функция вызывается из start-up до копирования всех "быстрых" функций и до инициализации переменных
*/
void
arm_cpu_initialize(void)
{
// Disable Watchdog
WDT->WDT_MR = WDT_MR_WDDIS;

// Embedded Flash Wait State VDDCORE set at 1.65V
// 17 MHz - 1 cycle = FWS = 0
// 30 MHz - 2 cycle = FWS = 1
// 54 MHz - 3 cycle = FWS = 2
// 64 MHz - 4 cycle = FWS = 3

// Embedded Flash Wait State VDDCORE set at 1.80V
// 32 MHz - 1 cycle = FWS = 0
// 38 MHz - 2 cicle = FWS = 1
// 64 MHz - 3 cycls = FWS = 2

#if CPU_FREQ == 64000000UL
enum { OSC_MUL = 32, OSC_DIV = 3, FWS = 3 }; // 12 MHz / 3 * 32 = 128 MHz
#elif CPU_FREQ == 48000000UL
enum { OSC_MUL = 8, OSC_DIV = 1, FWS = 2 }; // 12 MHz / 1 * 8 = 96 MHz
#elif CPU_FREQ == 32000000UL
enum { OSC_MUL = 16, OSC_DIV = 3, FWS = 1 }; // 12 MHz / 3 * 16 = 96 MHz
#else
#error Unsupported CPU_FREQ value
#endif

if (CPU_FREQ == 12000000UL)
{
// 12 МГц от внутреннего RC генератора
lowlevel_sam3s_init_pll_clock_12_RC12();
}
else if (0)
{
// умножение кварцевого генератора
lowlevel_sam3s_init_pll_clock_48_xtal12(OSC_MUL, OSC_DIV, FWS);
}
else if (1)
{
// умножение от внутреннего RC генератора
lowlevel_sam3s_init_pll_clock_48_RC12(OSC_MUL, OSC_DIV, FWS);
}
}


ps: Почему-то тэг CODEBLOCK не работает... кнопки нет, а название забыл. Модераторы, поправьте пожалуйста.
Genadi Zawidowski
Начал разбираться... Выяснил (благодара GDB), что это был не сбой. Что-то с инициализацией ADC - первый запуск как-будто не происходил, если команда давалась слишком быстро после инициализации. То, что не "сбой памяти" как он обычно выглядит, почти уверен.
upd: глюки переползают в другие места. В USART, в работу с PIO... где нечему сбоить. FWS=3 и никаких проблем...
aaarrr
Инициализация не из флеш выполняется случайно? Т.к. про EEFC_FMR сказано следующее:
Цитата
No Flash read should be done during change of this register.

На SAM3U изменение его содержимого при работе из флеш приводит к непредсказуемым глюкам.
Genadi Zawidowski
Да, это интересная строчка в даташите есть и в ATSAM3S.
Но, те же авторы демонстрационных программ атмела выполняют инициализацию из флеша (LowLevelInit), устанавливая вэитстэйты в значение
3 и не парятся вообще...
И нет никаких указаний на размещение функции SetFlashWaitState (boards\at91sam3u-ek\board_lowlevel.c(212)) в SRAM.
Опять же, значение после ресета там 0.

Ради проверки сделаю "честно" - переключение процессора на высокую скорость сделаю после копирования кода в ОЗУ - результат сообщу.

Интересно... пока характерных проявлений "сбоев" не обнаружил с
Код
    EFC->EEFC_FMR = EEFC_FMR_FWS(2);    // Flash Wait State
aaarrr
Цитата(Genadi Zawidowski @ Jun 24 2012, 21:40) *
Но, те же авторы демонстрационных программ атмела выполняют инициализацию из флеша (LowLevelInit), устанавливая вэитстэйты в значение
3 и не парятся вообще...

Ну, они в принципе не парятся.

Еще проверьте правильность настройки PLL: например, занижение входной частоты тоже приводит к интересным побочным эффектам.
Genadi Zawidowski
Правильнее было бы переключить на 12 МГц (не трогая EEFC_FMR), выполнить копирование а потом переключиться (из ОЗУ) на полную скорость... надо попробовать.

Цитата
Еще проверьте правильность настройки PLL: например, занижение входной частоты тоже приводит к интересным побочным эффектам.

Не зря я свой код сюда целиком выложил... 12 МГц кварц, делители/умножители приведены (на 3 делим, на 32 умножаем... про вычитание единичек не забыл). PLL программируется правильно, частоты на выходах померяны не один раз.

upd: сделал как хотел - переключение на 12 МГц RC osc (не трогая программирование вэйтстэйтов), копирование, переключение на 64 МГц от кварца на 12 МГц. Полёт нормальный.
Genadi Zawidowski
А вот интересно - что, только я один наткнулся на это (или все используют инициализацию из ASF с FWS=3)?
Немного ранее очень "по крупному" разбирался с инициализацией - результат разбирательств в первом сообщении этой темы - так как вариант от Атмела _иногда_ не работал - не инициализировал... благодара встроенным счётчикам на ожидании готовности оно конечно проходило start up - но частота была не та, что надо.

Или, все нормальные люди используют STM32?
aaarrr
Как видите, не Вы один.

Не холивара ради: из Cortex-M3 использовал TI(Luminary), Atmel, NXP, ST. На будущее принял решение ориентироваться на NXP. Периферия и документация на нее от ST вызывает стойкое неприятие.
andrewlekar
Тоже не ради холивара: сами пользуемся NXP, но с рыночной точки зрения наиболее перспективными кажутся ST.
topkin
Цитата(aaarrr @ Jun 25 2012, 01:04) *
Как видите, не Вы один.

Не холивара ради: из Cortex-M3 использовал TI(Luminary), Atmel, NXP, ST. На будущее принял решение ориентироваться на NXP. Периферия и документация на нее от ST вызывает стойкое неприятие.


Кому то нравится, кому то нет, к общему знаменателю мы не придем.
Я вот, например, к документацией NXP так и не сдружился в свое время, серия LPC23х в частности...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.