Модуль FSMC (Flexible static memory controller) предназначен для подключения внешних устройств с параллельным интерфейсом (оперативная память, дисплеи, NAND, NOR Flash и т. д.). Для этого у него есть 26 линий адреса, 16 линий данных и линии управляющих сигналов (запись, чтение, выбор кристалла и т. д.).

Свернутый текст

http://a.radikal.ru/a39/2005/26/954df082841d.png

Под модуль зарезервировано 1 ГБ в адресном пространстве МК (на рисунке выделено красной линией).

Свернутый текст

http://b.radikal.ru/b21/2005/cb/78b7f660cc0b.png

Доступная помять разделена на 4 банка по 256 МБ в каждом. При этом каждый банк разделен на 4 части по 64 МБ в каждой (линий адреса 26 и больше 64 МБ непосредственно адресовать не получится). Для доступа к частям банка есть специальные линии выбора кристалла NE1 - NE4. У каждого банка памяти свое назначение. Например 1 банк предназначен для NOR и SRAM памяти. Второй и третий для NAND памяти и т. д.

Свернутый текст

http://b.radikal.ru/b37/2005/eb/0775e1dc0d72.png

То есть при необходимости подключить оперативную память или дисплей следует выбирать банк 1. У него следующее разделение адресного пространства.

Код:
0x60000000 - 0x63FFFFFF - NE1
0x64000000 - 0x67FFFFFF - NE2
0x68000000 - 0x6BFFFFFF - NE3
0x6C000000 - 0x6FFFFFFF - NE4

Подключим память. Чтобы не изготавливать плату, можно купить китайскую с микроконтроллером STM32F407ZET6 или STM32F407ZGT6.

Свернутый текст

http://a.radikal.ru/a23/2005/82/85292addfc39.png

У нее на обратной стороне есть место для монтажа микросхемы статической оперативной памяти IS62WV51216BLL емкостью 1 МБ.

Свернутый текст

http://c.radikal.ru/c18/2005/03/1b32ca0f4815.png

Кроме микросхемы, нужно припаять резистор R29 с сопротивлением 10К.

Схема подключения памяти к микроконтроллеру.

Свернутый текст

http://b.radikal.ru/b15/2005/c2/e3573e9acf6a.png

Теперь рассмотрим программную часть. Настройка FSMC.

Код:
void FSMC_Init(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE |
                           RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG, ENABLE);
    {
        GPIO_InitTypeDef gpio;
        gpio.GPIO_Mode = GPIO_Mode_AF;
        gpio.GPIO_OType = GPIO_OType_PP;
        gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
        gpio.GPIO_Speed = GPIO_Speed_100MHz;

        gpio.GPIO_Pin = (GPIO_Pin_All) & ~(GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_7);
        GPIO_Init(GPIOD, &gpio);

        gpio.GPIO_Pin = (GPIO_Pin_All) & ~(GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6);
        GPIO_Init(GPIOE, &gpio);

        gpio.GPIO_Pin = (GPIO_Pin_All) & ~(GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11);
        GPIO_Init(GPIOF, &gpio);

        gpio.GPIO_Pin = (GPIO_Pin_All) & ~(GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
        GPIO_Init(GPIOG, &gpio);
    }

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource0,  GPIO_AF_FSMC); // D2
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource1,  GPIO_AF_FSMC); // D3
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource4,  GPIO_AF_FSMC); // NOE
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource5,  GPIO_AF_FSMC); // NWE
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource8,  GPIO_AF_FSMC); // D13
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource9,  GPIO_AF_FSMC); // D14
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FSMC); // D15
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource11, GPIO_AF_FSMC); // A16
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_FSMC); // A17
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_FSMC); // A18
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FSMC); // D0
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FSMC); // D1

    GPIO_PinAFConfig(GPIOE, GPIO_PinSource0,  GPIO_AF_FSMC); // NBLO
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource1,  GPIO_AF_FSMC); // NBL1
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource7,  GPIO_AF_FSMC); // D4
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource8,  GPIO_AF_FSMC); // D5
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource9,  GPIO_AF_FSMC); // D6
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FSMC); // D7
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_FSMC); // D8
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_FSMC); // D9
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_FSMC); // D10
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FSMC); // D11
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FSMC); // D12

    GPIO_PinAFConfig(GPIOF, GPIO_PinSource0,  GPIO_AF_FSMC); // A0
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource1,  GPIO_AF_FSMC); // A1
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource2,  GPIO_AF_FSMC); // A2
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource3,  GPIO_AF_FSMC); // A3
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource4,  GPIO_AF_FSMC); // A4
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource5,  GPIO_AF_FSMC); // A5
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource12, GPIO_AF_FSMC); // A6
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource13, GPIO_AF_FSMC); // A7
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource14, GPIO_AF_FSMC); // A8
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource15, GPIO_AF_FSMC); // A9

    GPIO_PinAFConfig(GPIOG, GPIO_PinSource0,  GPIO_AF_FSMC); // A10
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource1,  GPIO_AF_FSMC); // A11
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource2,  GPIO_AF_FSMC); // A12
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource3,  GPIO_AF_FSMC); // A13
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource4,  GPIO_AF_FSMC); // A14
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource5,  GPIO_AF_FSMC); // A15
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource10, GPIO_AF_FSMC); // NE3
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource12, GPIO_AF_FSMC); // NE4


    RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);

    {
        FSMC_NORSRAMInitTypeDef  s;
        FSMC_NORSRAMTimingInitTypeDef  p;

        p.FSMC_AddressSetupTime = 8;
        p.FSMC_AddressHoldTime = 2;
        p.FSMC_DataSetupTime = 8;
        p.FSMC_BusTurnAroundDuration = 0;
        p.FSMC_CLKDivision = 0;
        p.FSMC_DataLatency = 0;
        p.FSMC_AccessMode = FSMC_AccessMode_A;

        s.FSMC_Bank = FSMC_Bank1_NORSRAM3;
        s.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
        s.FSMC_MemoryType = FSMC_MemoryType_SRAM;
        s.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
        s.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
        s.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
        s.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
        s.FSMC_WrapMode = FSMC_WrapMode_Disable;
        s.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
        s.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
        s.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
        s.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
        s.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
        s.FSMC_ReadWriteTimingStruct = &p;
        s.FSMC_WriteTimingStruct = &p;

        FSMC_NORSRAMInit(&s);

        /* Enable FSMC Bank1_SRAM3 Bank */
        FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE);
    }

}

Большую часть кода заняла конфигурация выходов, а именно настройка их альтернативной функции работы. Выводов задействовано много, отсюда относительно большое число строк.
Согласно конфигурации FSMC используется 3 часть банка 1 (потому что вывод CE  памяти соединен с NE3 микроконтроллера), а значит диапазон доступной памяти 0x68000000 - 0x6BFFFFFF, но поскольку у микросхемы размер 1 МБ, диапазон составляет 0x68000000 - 0x680FFFFF.
Один из способов получить доступ к памяти создать секцию в файле линкера и задать начальный адрес 0x68000000 и размер обрасти памяти. Тогда компилятор будет распределять память.
Достаточно будет написать что-то типа

Код:
uint16_t x __attribute__((section(".ex_sram")));
uint32_t y __attribute__((section(".ex_sram")));

Для теста был создан массив на всю доступную память.

Код:
#define SizeArr (1024*1024/2)

static volatile uint16_t Arr[SizeArr] __attribute__((section(".ex_sram")));

А после заполнен данными.

Код:
    for (uint32_t i=0; i<SizeArr; i++)
    {
        Arr[i]=i; // Запись во внешнюю память.
    }

Содержимое памяти было проверено отладчиком. Ошибок нет.
Память была заполнена за 12.5 миллиона тактов, а учитывая что в секунде 168 миллионов тактов (ядро работает на частоте 168 МГц), память была заполнена за 78 миллисекунд.

Свернутый текст

http://b.radikal.ru/b27/2005/93/83b4c3122540.png

Файлы. http://pure-basic.narod.ru/forum_files/ … C_SRAM.zip


Теперь подключим дисплей с контроллером ILI9341.

Свернутый текст

http://a.radikal.ru/a26/2005/fb/3843ee154c88.png
http://a.radikal.ru/a17/2005/6e/16b5e34f09dd.png

Для него предусмотрен разъем TFT.
Схема подключения дисплея.

Свернутый текст

http://c.radikal.ru/c24/2005/b8/c38828d8ebdc.png

С дисплеем соединен вывод NE4, а значит ему выделено адресное пространство 0x6C000000 - 0x6FFFFFFF. В FSMC нет понятия команд и данных и соответствующий вывод отсутствует, но можно использовать для этой цели любой вывод адреса. В данной плате использован вывод A6. Таким образом запись при 0 на A6 будет интерпретироваться дисплеем как команда, а при 1 на A6 как данные. Например запись по адресу 0x6C000000 это команда, а по 0x6C000080 данные. В виде кода это выглядит так.

Код:
// *********  Отправка КОМАНДЫ  ************//
static inline void ILI9341_SendCommand(uint16_t cmd)
{
    *(__IO uint16_t*)(0x6C000000) = cmd;
}

// *********  Отправка 1 байта ДАННЫХ ************//
static inline void ILI9341_SendData(uint16_t data)
{
    *(__IO uint16_t*)(0x6C000080) = data;
}

Настройка модуля FSMC.

Код:
static void FSMC_Init(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE |
                           RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG, ENABLE);
    {
        GPIO_InitTypeDef gpio;
        gpio.GPIO_Mode = GPIO_Mode_AF;
        gpio.GPIO_OType = GPIO_OType_PP;
        gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
        gpio.GPIO_Speed = GPIO_Speed_100MHz;

        gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_9 |
                        GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;
        GPIO_Init(GPIOD, &gpio);

        gpio.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 |
                        GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
        GPIO_Init(GPIOE, &gpio);

        gpio.GPIO_Pin = GPIO_Pin_12;
        GPIO_Init(GPIOF, &gpio);

        gpio.GPIO_Pin = GPIO_Pin_12;
        GPIO_Init(GPIOG, &gpio);
    }

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource0,  GPIO_AF_FSMC); // D2
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource1,  GPIO_AF_FSMC); // D3
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource4,  GPIO_AF_FSMC); // NOE
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource5,  GPIO_AF_FSMC); // NWE
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource8,  GPIO_AF_FSMC); // D13
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource9,  GPIO_AF_FSMC); // D14
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FSMC); // D15
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FSMC); // D0
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FSMC); // D1

    GPIO_PinAFConfig(GPIOE, GPIO_PinSource7,  GPIO_AF_FSMC); // D4
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource8,  GPIO_AF_FSMC); // D5
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource9,  GPIO_AF_FSMC); // D6
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FSMC); // D7
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_FSMC); // D8
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_FSMC); // D9
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_FSMC); // D10
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FSMC); // D11
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FSMC); // D12

    GPIO_PinAFConfig(GPIOF, GPIO_PinSource12, GPIO_AF_FSMC); // A6

    GPIO_PinAFConfig(GPIOG, GPIO_PinSource12, GPIO_AF_FSMC); // NE4


    RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);

    {
        FSMC_NORSRAMInitTypeDef  s;
        FSMC_NORSRAMTimingInitTypeDef  p;

        p.FSMC_AddressSetupTime = 2;
        p.FSMC_AddressHoldTime = 2;
        p.FSMC_DataSetupTime = 6;
        p.FSMC_BusTurnAroundDuration = 0;
        p.FSMC_CLKDivision = 0;
        p.FSMC_DataLatency = 0;
        p.FSMC_AccessMode = FSMC_AccessMode_A;

        s.FSMC_Bank = FSMC_Bank1_NORSRAM4;
        s.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
        s.FSMC_MemoryType = FSMC_MemoryType_SRAM;
        s.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
        s.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
        s.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
        s.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
        s.FSMC_WrapMode = FSMC_WrapMode_Disable;
        s.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
        s.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
        s.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
        s.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
        s.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
        s.FSMC_ReadWriteTimingStruct = &p;
        s.FSMC_WriteTimingStruct = &p;

        FSMC_NORSRAMInit(&s);

        /* Enable FSMC Bank1_SRAM2 Bank */
        FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);
    }

}

Кода немного меньше чем в случае с памятью в основном за счет того что используется меньше выводов.

Дисплей 320x240 заполняется цветом за 922 тысячи тактов что равно 5 миллисекунд.

Файлы. http://pure-basic.narod.ru/forum_files/ … LI9341.zip