Урок 62
Часть 2
FMC SDRAM
В прошлой части нашего занятия мы познакомились с микросхемой памяти SDRAM MT48LC4M32B2 от компании Micron.
Также мы ознакомились с организацией данной памяти, как к ней обратиться, чтобы она начала запись и чтение.
Сегодня мы продолжим начатое дело.
Начнём мы данную часть с создания проекта.
Мы создадим новый проект в Cube MX, выберем контроллер (нажмите на картинку для увеличения размера)
Начнем настраивать проект.
Первым делом включим кварцевый резонатор
Затем настроим Clock Configuration на 200 МГц следующим образом (нажмите на картинку для увеличения изображения)
Включим ножку PI1, управляющую зелёным светодиодом, на выход.
Писать мы будем программу, которая будет сначала писать определённые данные. начиная с определённого адреса в SDRAM, а затем читать их оттуда же в массив. А смотреть считанные данные будем через USART.
Я думаю, многие знают, но не все. В плате F746-DISCO интерфейсом USART можно пользоваться прямо через порт программирования ST-Link, не подключая при этом никаких дополнительных переходников. Самое главное — правильно его сконфигурировать в Cube MX.
Включим там USART1
Посмотрим на картинке контроллера, какие же ножки нам автоматически подключил в качестве USART генератор Cube MX
Эти ножки — PB7 в качестве RX и PB6 в качестве TX.
Проверим на схеме, так ли это
Как мы видим, RX у нас правильный. а TX — нет. Поэтому переопределим его на PA9.
И такая вот ситуация сплошь и рядом. То же самое будет и при включении FMC и LTDC.
Ну, скорее всего, Cube MX и не обязан знать, на какие у нас контакты и что задействовано в схеме отладочной платы. Мы же выбрали не плату, а контроллер. Многие советуют выбирать плату, но мне это не нравится. Всё желтое и зелёное, свободных ножек нет вообще и, наоборот, начинаешь думаль, что же отключить. Поэтому лучше будем иногда поглядывать в схему.
Вообщем с USART разобрались
Теперь разберёмся с самим контроллером.
Зайдём в Configuration и откроем там CORTEX M7. Включим первым делом кэш
Далее регионы доступа
Теперь FMC.
Мы видим, что у нас включилось очень много ножек и очень много их согласно схеме также будет переопределено, поэтому, я напишу список, какие должы быть включены ножки для FMC и в каком качестве, а то мало ли, может к кого-то включатся вообще другие. Мы уже знаем какие ножки за что отвечают, поэтому нам уже проще будет понимать распиновку.
Также подсказкой будет служить таблица 10 в User Manual
Из неё мы всё и соберём
Pin | Pin Name | Signal or Label |
---|---|---|
A5 | PE1 | FMC_NBL1 |
A6 | PE0 | FMC_NBL0 |
B7 | PG15 | FMC_SDNCAS |
B12 | PD0 | FMC_D2 |
C12 | PD1 | FMC_D3 |
D2 | PF0 | FMC_A0 |
E2 | PF1 | FMC_A1 |
G2 | PF2 | FMC_A2 |
H2 | PF3 | FMC_A3 |
H14 | PG8 | FMC_SDCLK |
J2 | PF4 | FMC_A4 |
J3 | PH5 | FMC_SDNWE |
J4 | PH3 | FMC_SDNE0 |
K3 | PF5 | FMC_A5 |
K13 | PD15 | FMC_D1 |
K15 | PD10 | FMC_D15 |
L4 | PC3 | FMC_SDCKE0 |
L12 | PD14 | FMC_D0 |
L14 | PD9 | FMC_D14 |
L15 | PD8 | FMC_D13 |
M6 | PF12 | FMC_A6 |
M7 | PG1 | FMC_A11 |
M8 | PF15 | FMC_A9 |
N6 | PF13 | FMC_A7 |
N7 | PG0 | FMC_A10 |
N9 | PE8 | FMC_D5 |
N12 | PG4 | FMC_BA0 |
P6 | PF14 | FMC_A8 |
P8 | PF11 | FMC_SDNRAS |
P9 | PE9 | FMC_D6 |
P10 | PE11 | FMC_D8 |
P11 | PE14 | FMC_D11 |
R8 | PE7 | FMC_D4 |
R9 | PE10 | FMC_D7 |
R10 | PE12 | FMC_D9 |
R11 | PE15 | FMC_D12 |
R12 | PE13 | FMC_D10 |
Вот по такой схеме и переопределяем контакты.
Теперь настроим наш FMC на вкладке Configuration
Здесь всё согласно документации. Мы прибавили латентность на шину включении адресации колонки, добавили ещё один такт на команды, включили BRUST (режим пакетной передачи данных) на чтение, а также настроили тайминги.
Настроим проект, назвав его FMC_SDRAM, выбрав Keil 5 в качестве среды, а также увеличим в 10 раз стек и кучу
Вообщем-то с Cube MX пока всё.
Сгенерируем проект, откроем его в Keil, настроив программатор на авторезет.
Сначала напишем несложный тест в main() в бесконечном цикле, чтобы проверить зеленый светодиод
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_1, GPIO_PIN_SET);
HAL_Delay(500);
}
/* USER CODE END 3 */
Соберем код, прошьём контроллер, светодиод мигает.
Теперь проверим USART
Подключим файл в main.c
/* USER CODE BEGIN Includes */
#include «string.h»
В main() создадим небольшой строковый буфер
/* USER CODE BEGIN 1 */
char str1[20]={0};
/* USER CODE END 1 */
Добавим код в бесконечный цикл
HAL_Delay(500); }
sprintf(str1,»Ok!\r\n»);
HAL_UART_Transmit(&huart1, (uint8_t*)str1,strlen(str1),0x1000);
Запустим терминальную программу, настроим её на 115200 с одним стоповым битом и нажмем Connect.
Затем соберем код, прошьём контроллер и посмотрим в терминал
Всё нормально отправляестя.
Теперь займёмся памятью SDRAM.
Частично память у нас уже была инициализирована в Cube MX.
Продолжим инициализацию дальше.
Создадим два файла MT48LC4M32B2.c и MT48LC4M32B2.h обычным способом
Заголовочный файл подключим к main.c и к MT48LC4M32B2.c
/* USER CODE BEGIN Includes */
#include «MT48LC4M32B2.h»
#include «string.h»
#include «MT48LC4M32B2.h»
В данный заголовочный файл добавим макросы для конфигурирования и обращения к памяти SDRAM, взяв их из примера, ну и также подключим туда библиотеку HAL.
В результате файл будет таким
#ifndef __MT48LC4M32B2_H
#define __MT48LC4M32B2_H
//————————————————
#include «stm32f7xx_hal.h»
//————————————————
#define SDRAM_TIMEOUT ((uint32_t)0xFFFF)
#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
//————————————————
#endif /* __MT48LC4M32B2_H */
Соберём проект, прошьём контроллер и проверим, мигает ли у нас светодиод, то есть ту ли лапку порта мы используем
Светодиод у нас мигает как положено раз в секунду.
Дальнейшую работу с проектом мы отложим до следующей части нашего занятия.
Предыдущая часть Программирование МК STM32 Следующая часть
Техническая документация на микросхему SDRAM MT48LC4M32B2
Отладочную плату можно приобрести здесь 32F746G-DISCOVERY
Смотреть ВИДЕОУРОК (нажмите на картинку)
Подправте картинку с описаниемрегионов доступа, там указан неверный адрес начала региона
Ссылку убрал.
Необходимо исправить в таблице PF9 на PF0 (см. Pin № D2)
Готово!
Спасибо за внимательность. А мне минус за невнимательность.
Спасибо автору за статью, но не мог бы автор более подробно расписать настройку таймингов SDRAM? Откуда берутся магические цифры 2 6 4 6 2 2 2? Ясно, что из даташита, но из какой таблицы и как эти параметры там могут обзыватся? Заранее спасибо за ответ.
В принципе, в технической документации на любую память все эти тайминги есть. Я просто физически не смогу разжевать каждую циферку, уж простите великодушно. Поэтому, думаю, всё это несложно освоить самостоятельно.
Разве BURST_LENGTH_8 не должен быть 3, а не 4?
Ставил как в репозитории.
Исправте пожалуйста
sprintf(str1,»Ok!rn»);
на
sprintf(str1,»Ok!\r\n»);
Исправил, спасибо. Они там были, это всё происки вордпресса.
Здравствуйте! Расскажите,пожалуйста, как вы посчитали тайминги, в датащите на мироновскую память нет об этом данных. Спасибо
микроновскую * опечатка
ахха, уже разобрался, кому интересно:
в референс мануале на стм32ф746 (РМ0385 версии 8) страница 376/1724(раздел фмс-сдрам-регистры таймингов) запомните аббревиатуры. Те же аббревиатуры только в таблице 12 в датащите на микроновскую память на странице 20/79 указаны периоды в наносекундах и время одного тика.