Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: HardFault при записи/чтении в SDRAM на Core429i
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Sharf
Пытаюсь запустить SDRAM на Core429i в TrueStudio с помощью CubeMX. Цепи FMC настроил согласно схеме, но программа при записи/чтении в SDRAM вылетает в HardFault.
Уже и PD6 подтянул к питанию... Ничего не помогает...
Прерываний, ОСРВ и т.п. вещей, который могли бы влиять на роботу с SDRAM, нет.
Код
Код: if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
  {
    Error_Handler();
  }
- выполняется без входа в Error_Handler.

Ревизия МК - 3, т.е. проблем с FMC быть не должно. Может в кубе (прикрепляю файл проекта) что-то не так указал?

Что еще можно проверить?
amiller
1. Прочитать документацию на семейство контроллеров.
2. Разрешить тактирование задействованных портов.
3. Настроить нужные выводы на альтернативную функцию (FSMC).
4. Разрешить тактирование модуля FSMC.
5. Настроить режим работы, диапазон адресов, ширину шины и т.п.
6. Настроить тайминги обмена в соответствии с параметрами внешнего устройства (памяти).
7. Настроить секцию для размещения переменных во внешней памяти.
8. Провести тестирование чтения/записи данных.

или попытаться объяснить кубу задачу, чтобы всё это он сделал за вас.
Sharf
Цитата(amiller @ Oct 1 2016, 18:17) *
.


Судя по коду, который генерирует куб, он все это делает. Кроме тестирования чтения/записи, которое пытаюсь выполнить я.
x893
И даже примеры от waveshare не работают ?
http://www.waveshare.com/wiki/Core429I

Если нет - горелку и сжечь его
Sharf
Цитата(x893 @ Oct 1 2016, 19:06) *


Наверно придется использовать их (хотя код куба сравнивал как раз с этими примерами - не один в один, но очень похоже получается...).
Я думал, что куб позволит быстро проверить работоспособность озушки, т.к. прикручивать примеры у меня не быстро получается...
Очень похоже, что при настройке FMC для SDRAM я что-то упустил, т.к. отдельно SDIO (+fatfs), FMC для LCD работают без проблем. В прикрепленном проекте (в первом сообщении) только FMC для SDRAM, т.е. ничего на него влиять не должно.
jcxz
Цитата(Sharf @ Oct 1 2016, 21:55) *
Судя по коду, который генерирует куб, он все это делает. Кроме тестирования чтения/записи, которое пытаюсь выполнить я.

Он и документацию за Вас читает??? smile3046.gif
scifi
Цитата(jcxz @ Oct 1 2016, 19:53) *
Он и документацию за Вас читает??? smile3046.gif

Зачем сразу так? Куб - он же как раз для того, чтобы талмуд не листать. А если сразу не срослось - что ж, бывает...
Sharf
Цитата(scifi @ Oct 1 2016, 20:58) *
Зачем сразу так? Куб - он же как раз для того, чтобы талмуд не листать. А если сразу не срослось - что ж, бывает...


Поддерживаю.

Кто-нибудь смотрел файл проекта куба, прикрепленный к первому сообщению? Предполагаю, что именно там какая-то мелочь не дает работать с sdram...
x893
Никак не могу заставить разбираться в килотоннах букв.
Всегда проще пройти отладчиком и не заставлять людей мучиться.
К тому же (в случае с Cube) правильнее публиковать ioc файл, а не килостроки им сгенерированные.
Sharf
Цитата(x893 @ Oct 1 2016, 21:59) *
Никак не могу заставить разбираться в килотоннах букв.
Всегда проще пройти отладчиком и не заставлять людей мучиться.
К тому же (в случае с Cube) правильнее публиковать ioc файл, а не килостроки им сгенерированные.


Именно ioc и прикреплен, т.е. только один файл (я, наверно, некорректно его назвал в предыдущих сообщениях).

Отладчиком, естественно проходился - в hardfault стабильно входит на операции чтения/записи.
AVI-crak
Цитата(Sharf @ Oct 1 2016, 20:31) *
Что еще можно проверить?


Например адреса чтения/записи - у вас кстати второй банк 0xD0000000 ++.
Соответствие выставленных таймингов с тактовой и временем из доки на память. В доке большая часть параметров привязана к времени а не к тактовой. А у вас тактовая памяти получается 80мгц !!! - ниже некуда.
Первый PLL не может корректно умножать пограничные частоты в 1мгц и в 2мгц - середина умножается корректно и гладко, 1,5мгц - идеально.
Кубик игнорирует установку подтяжки на используемые ноги, а делать это ручным способом весьма утомительно.
Дата в землю, адрес без подтяжки, управление: sdclk, nbl0, nbl1 - в землю, - остальное в плюс. После чего становится доступным спящий режим.
Забыл: ноги нужно лочить, чтоб не слетали при дальнейшем неаккуратном инсталле.

Ну и наверное главное, хотя уже упомянули создание раздела в линковщике - забыли напомнить про копирование инициализированных переменных из флеша. Сделать эту операцию корректно из С кода - весьма проблематично. А в случае применения хала - практически не реально.
Так-шта в выигрыше старый добрый SystemInit запускаемый до копирования в sdram кучи переменных, с таким расчётом чтоб майн запустить на всём готовом.
Sharf
Цитата(AVI-crak @ Oct 1 2016, 23:41) *
Например адреса чтения/записи - у вас кстати второй банк 0xD0000000 ++.
Соответствие выставленных таймингов с тактовой и временем из доки на память. В доке большая часть параметров привязана к времени а не к тактовой. А у вас тактовая памяти получается 80мгц !!! - ниже некуда.
Первый PLL не может корректно умножать пограничные частоты в 1мгц и в 2мгц - середина умножается корректно и гладко, 1,5мгц - идеально.
Кубик игнорирует установку подтяжки на используемые ноги, а делать это ручным способом весьма утомительно.
Дата в землю, адрес без подтяжки, управление: sdclk, nbl0, nbl1 - в землю, - остальное в плюс. После чего становится доступным спящий режим.
Забыл: ноги нужно лочить, чтоб не слетали при дальнейшем неаккуратном инсталле.

Ну и наверное главное, хотя уже упомянули создание раздела в линковщике - забыли напомнить про копирование инициализированных переменных из флеша. Сделать эту операцию корректно из С кода - весьма проблематично. А в случае применения хала - практически не реально.
Так-шта в выигрыше старый добрый SystemInit запускаемый до копирования в sdram кучи переменных, с таким расчётом чтоб майн запустить на всём готовом.


//Например адреса чтения/записи - у вас кстати второй банк 0xD0000000 ++.

да, именно такой адрес у SDRAM_BASE. Уходит в hardfault внутри:

status = HAL_SDRAM_Read_16b(&hsdram1, (uint32_t*)SDRAM_BASE, buf, SDRAM_SIZE);

на строчке *pDstBuffer = *(__IO uint16_t *)pSdramAddress;

дизассемблер: ldrh.w r4, [r1], #2

при этом pDstBuffer = 0x2002fff0 (т.е. буфер из внутреннего ОЗУ МК),
pSdramAddress = 0xd0000000
SDRAM_SIZE = 4 (чисто для проверки)

//Соответствие выставленных таймингов с тактовой и временем из доки на память

- это еще смотрю

//Дата в землю, адрес без подтяжки, управление: sdclk, nbl0, nbl1 - в землю, - остальное в плюс. После чего становится доступным спящий режим.

сделал, не помогает

//Забыл: ноги нужно лочить, чтоб не слетали при дальнейшем неаккуратном инсталле.

- это есть в ioc

//Ну и наверное главное, хотя уже упомянули создание раздела в линковщике - забыли напомнить про копирование инициализированных переменных из флеша.
//Сделать эту операцию корректно из С кода - весьма проблематично. А в случае применения хала - практически не реально.
//Так-шта в выигрыше старый добрый SystemInit запускаемый до копирования в sdram кучи переменных, с таким расчётом чтоб майн запустить на всём готовом.

Можно тут подробнее? Пока во внешнем ОЗУ я ничего не храню и не планирую хранить.

AVI-crak
Код инстала для stm32f439, с небольшими исправлениями кочует из проекта в проект.

CODE
///Install SDRAM stm32f439
FMC_Bank5_6 -> SDCR[0] = FMC_SDCR1_NC_9bits
|FMC_SDCR1_NR_13bits
|FMC_SDCR1_MWID_16bits
|FMC_SDCR1_NB_4banks
|FMC_SDCR1_CAS_2cycle
//|FMC_SDCR1_SDCLK_3x
|FMC_SDCR1_SDCLK_2x
|FMC_SDCR2_RBURST
|FMC_SDCR1_WP
|FMC_SDCR1_RPIPE_1delay; //FMC_SDCR1_RPIPE_1delay FMC_SDCR1_RPIPE_3delay

FMC_Bank5_6->SDTR[0] = (0x00000001) /// TMRD время между записью в MODE-REGISTER и ACTIVATE/1 /2
|(0x00000005 << 4) /// TXSR время между SELF-REFRESHING и ACTIVATE (exit self-refresh mode)/5 /7
|(0x00000002 << 8) /// TRAS минимальное время между SELF-REFRESH/2 /4
|(0x00000006 << 12) /// TRC время между двумя командами REFRESH/5 /7
|(0x00000003 << 16) /// TWR задержка между командой WRITE и вызовом PRECHARGE/1 /2
|(0x00000001 << 20) /// TRP время между командой PRECHARGE и любой другой командой/1 /1
|(0x00000002 << 24); /// TRCD время между подачей команды ACTIVATE и появлением данных на шинеС/1 /2
///TWR >= TRAS - TRCD and TWR >= TRC - TRCD - TRP
FMC_Bank5_6->SDCMR = FMC_SDCMR_CTB1 | FMC_SDCMR_MODE_Config_Enable;
tmp = FMC_Bank5_6->SDSR & 0x00000020;
timeout = 0xFFFF;
while((tmp != 0) && (timeout-- > 0))
{
tmp = FMC_Bank5_6->SDSR & 0x00000020;
}

delay(10000);
/// PALL command
FMC_Bank5_6->SDCMR = FMC_SDCMR_CTB1 | FMC_SDCMR_MODE_PALL;
timeout = 0xFFFF; tmp = 10;
while((tmp != 0) && (timeout-- > 0))
{
tmp = FMC_Bank5_6->SDSR & 0x00000020;
}
/// Auto refresh command
FMC_Bank5_6->SDCMR = (0x00000003 << 5) | FMC_SDCMR_CTB1 | FMC_SDCMR_MODE_Self_refresh;
/// Количество рефлеш минимум 2
timeout = 0xFFFF; tmp = 10;
while((tmp != 0) && (timeout-- > 0))
{
tmp = FMC_Bank5_6->SDSR & 0x00000020;
}
// MRD register program
tmp = (((((HSE_gz / (((RCC->PLLCFGR)<<26)>>26))*(((RCC->PLLCFGR)<<17)>>23))/(((((RCC->PLLCFGR)<<14)>>30)<<1)+2))/2000)*64)/8192;
FMC_Bank5_6->SDCMR = (tmp << 9) | FMC_SDCMR_CTB1 | FMC_SDCMR_MODE_Load_Mode;
/// 64mc/(размер блока Row Addresses(8192)) * (тактовая частота чипа)
timeout = 0xFFFF; tmp = 10;
while((tmp != 0) && (timeout-- > 0))
{
tmp = FMC_Bank5_6->SDSR & 0x00000020;
}
tmp = (((((((HSE_gz / (((RCC->PLLCFGR)<<26)>>26))*(((RCC->PLLCFGR)<<17)>>23))/(((((RCC->PLLCFGR)<<14)>>30)<<1)+2))/2000)*64)/8192)<<1) | FMC_Bank5_6->SDRTR;
FMC_Bank5_6->SDRTR = (tmp | (0x000002C5<<1)) | 1<<14; // время регена + вкл регена
/// Refresh rate = (COUNT) * SDRAM clock frequency
/// SDRAM refresh period = 64 mc
/// COUNT = (SDRAM refresh period / Number of rows )
/// Refresh rate = 0.064 / (8192rows + 4) ) * 84000000 , ~ 656 ( 0x290 )

FMC_Bank5_6->SDCR[0] &= (~FMC_SDCR1_WP);// снятие защиты от записи
// timeout =0;
for(tmp = 0xc0000000; tmp < 0xC1FFFFFC; tmp += 4) ///32Mb 0.873 ms
{
*((volatile uint32_t *)tmp) = 0x00000000;// timeout;
}


Для файла линкера нечто подобное (у меня иначе, возможны ошибки)
CODE
MEMORY
{
ROM (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 192K
SRAM (rwx) : ORIGIN = 0xD0000000, LENGTH = 64K
CCRAM (rwx) : ORIGIN = 0x10000000, LENGTH = 64K
SDRAM (rwx) : ORIGIN = 0xC0000000, LENGTH = 16384K
BKRAM (rw) : ORIGIN = 0x40024000, LENGTH = 4K
}

--------------
/* размещение констант в SDRAM */
_sicsdram = LOADADDR(.csdram);
.csdram :
{
. = ALIGN(4);
_scsdram = .; /* глобальный символ начала SDRAM */
*(.csdram)
*(.csdram*)
. = ALIGN(4);
_ecsdram = .; /* глобальный символ конца SDRAM */
} > SDRAM AT> FLASH

---------------
*.s файл

bl SystemInit

ldr r0, =_scsdram
ldr r1, =_sicsdram
ldr r2, =_ecsdram
LoopCopySdram:
cmp r0, r2
ittt ne
ldrne r3, [r1], #4
strne r3, [r0], #4
bne LoopCopySdram

bl main

---------

макрос
#define SDram __attribute__((section(".csdram")))
----------
глобальные переменные
SDram const uint16_t Font[размер] ={дата};


Таким образом можно объявить функции и даже часть данных что не могут физически уместиться во внутреннюю флеш чипа. В этом случае из асмы *.s вызывается функция чтения внешней флешки, например 25q64, и есно запись в sdram. Сделать это необходимо до входа в майн.
Естественно размещение дампа на внешней памяти - отдельный разговор, он станет актуальным после получения бинарного файла прошивки размером за 2 гигабайта.
Исправляется ситуация весьма оригинально, но это потом.
Sharf
Цитата(AVI-crak @ Oct 3 2016, 03:21) *
Код инстала для stm32f439, с небольшими исправлениями кочует из проекта в проект.

...

Таким образом можно объявить функции и даже часть данных что не могут физически уместиться во внутреннюю флеш чипа. В этом случае из асмы *.s вызывается функция чтения внешней флешки, например 25q64, и есно запись в sdram. Сделать это необходимо до входа в майн.
Естественно размещение дампа на внешней памяти - отдельный разговор, он станет актуальным после получения бинарного файла прошивки размером за 2 гигабайта.
Исправляется ситуация весьма оригинально, но это потом.


Спасибо большое за информацию! Проблема решилась - была ошибка при инициализации памяти (банальность - при копипасте тактирование не включилось sm.gif )

Не подскажете, для чего waveshare два раза посылает одну и ту же команду:
Код
/* Wait until the SDRAM controller is ready */
  while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
  {
  }
  /* Send the  first command */
  FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
  
  /* Wait until the SDRAM controller is ready */
  while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)
  {
  }
  /* Send the second command */
  FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);

Также Вы писали: А у вас тактовая памяти получается 80мгц !!! - ниже некуда.

Почему ниже некуда? В описании на SDRAM ограничения максимальные частоты/тайминги указаны. Т.е. теоретически можно работать и на более низких частотах
AVI-crak
SDRAM необходимо регенерировать каждые 64мс независимо от частоты клока. Выше частота - быстрее получается регенерация, остаётся больше времени на рабочее состояние.

Зачем в конструкциях хала одинаково повторяющиеся команды? а фиг его знает. После десятого рекурсивного дифлайна на хале - у меня теряется терпение. Да и зачем, если с прямым обращением в регистры - код получается намного проще и понятнее.
Sharf
Цитата(AVI-crak @ Oct 5 2016, 16:59) *
SDRAM необходимо регенерировать каждые 64мс независимо от частоты клока. Выше частота - быстрее получается регенерация, остаётся больше времени на рабочее состояние.

Зачем в конструкциях хала одинаково повторяющиеся команды? а фиг его знает. После десятого рекурсивного дифлайна на хале - у меня теряется терпение. Да и зачем, если с прямым обращением в регистры - код получается намного проще и понятнее.


Спасибо большое за всю Вашу информацию! Она была очень полезна!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.