|
|
  |
ATSAM3S4B flash wait states, Приходится ставить 3 |
|
|
|
Jun 10 2012, 11:42
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Поставил чип 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 не работает... кнопки нет, а название забыл. Модераторы, поправьте пожалуйста.
Сообщение отредактировал IgorKossak - Jun 10 2012, 14:05
Причина редактирования: [codebox] для простыней, пора бы запомнить!!!
|
|
|
|
|
Jun 24 2012, 17:52
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Да, это интересная строчка в даташите есть и в ATSAM3S. Но, те же авторы демонстрационных программ атмела выполняют инициализацию из флеша (LowLevelInit), устанавливая вэитстэйты в значение 3 и не парятся вообще... И нет никаких указаний на размещение функции SetFlashWaitState (boards\at91sam3u-ek\board_lowlevel.c(212)) в SRAM. Опять же, значение после ресета там 0. Ради проверки сделаю "честно" - переключение процессора на высокую скорость сделаю после копирования кода в ОЗУ - результат сообщу. Интересно... пока характерных проявлений "сбоев" не обнаружил с Код EFC->EEFC_FMR = EEFC_FMR_FWS(2); // Flash Wait State
Сообщение отредактировал Genadi Zawidowski - Jun 24 2012, 18:26
|
|
|
|
|
Jun 24 2012, 18:25
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Правильнее было бы переключить на 12 МГц (не трогая EEFC_FMR), выполнить копирование а потом переключиться (из ОЗУ) на полную скорость... надо попробовать. Цитата Еще проверьте правильность настройки PLL: например, занижение входной частоты тоже приводит к интересным побочным эффектам. Не зря я свой код сюда целиком выложил... 12 МГц кварц, делители/умножители приведены (на 3 делим, на 32 умножаем... про вычитание единичек не забыл). PLL программируется правильно, частоты на выходах померяны не один раз. upd: сделал как хотел - переключение на 12 МГц RC osc (не трогая программирование вэйтстэйтов), копирование, переключение на 64 МГц от кварца на 12 МГц. Полёт нормальный.
Сообщение отредактировал Genadi Zawidowski - Jun 24 2012, 19:01
|
|
|
|
|
Jun 28 2012, 07:08
|
Частый гость
 
Группа: Свой
Сообщений: 152
Регистрация: 21-12-05
Из: Москва
Пользователь №: 12 476

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