/**
  ******************************************************************************
  * @file    main.c
  *
  * @brief   Пример чтения и записи во внешнею ОЗУ размером 1МБ.
  *
  *          Используются 2 штуки 4Мбит памяти CY7C1041DV33-10ZSXI, образующие
  *          общее адресное пространство в 1МБ. Для управления сигналами Cen
  *          используется маскирование по 19 биту адреса внешней памяти. Сигналы
  *          Cen и Oen используются для каждой ОЗУ свой (MEM_Cen0, MEM_Oen0 и
  *          MEM_Cen1, MEM_Oen1).
  *          Шина данных и адреса подключены к обоим ОЗУ идентично. Для
  *          адреса используется шина MEM_ADDR[18:1]. Шина данных используется
  *          полностью.
  *
  *          Обе ОЗУ подключенны к первой альтернативной функции интерфейса
  *          внешней памяти. Исключением является сигнал MEM_Wen, который
  *          используется на третей альтернативной функции вывода B[0].
  *          Следовательно, для отладки и прошивки мк можно использовать только
  *          SWD интерфейс (B[0]-JTAG_TDI).
  *
  *          Компилятор: GCC ARM 4.9.3
  *          Среда: Qt Creator 3.4.2
  *
  * @author  НИИЭТ
  *             - Богдан Колбов (bkolbov), kolbov@niiet.ru
  * @date    07.12.2015
  *
  ******************************************************************************
  * @attention
  *
  * ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО
  * ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ
  * ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ
  * НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
  * ПРЕДНАЗНАЧЕНО ДЛЯ ОЗНАКОМИТЕЛЬНЫХ ЦЕЛЕЙ И НАПРАВЛЕНО ТОЛЬКО НА
  * ПРЕДОСТАВЛЕНИЕ ДОПОЛНИТЕЛЬНОЙ ИНФОРМАЦИИ О ПРОДУКТЕ, С ЦЕЛЬЮ СОХРАНИТЬ ВРЕМЯ
  * ПОТРЕБИТЕЛЮ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ
  * ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ, ЗА ПРЯМОЙ ИЛИ КОСВЕННЫЙ УЩЕРБ, ИЛИ
  * ПО ИНЫМ ТРЕБО ВАНИЯМ, ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ
  * ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
  *
  * <h2><center>&copy; 2015 ОАО "НИИЭТ"</center></h2>
  ******************************************************************************
  */

#include "niietcm4.h"
#include "retarget.h"

// Доступ по относительным адресам к каждой из ОЗУ
#define EXTRAM0(ADDR)       *(volatile uint32_t*)(0x40000000 + (uint32_t)ADDR)
#define EXTRAM1(ADDR)       *(volatile uint32_t*)(0x40080000 + (uint32_t)ADDR)

// Доступ к общему 1МБ пространству, используя абсолютные адреса внешней памяти:
// 0x40000000 - 0x400FFFFF общее пространство
// 0x40000000 - 0x4007FFFF RAM0
// 0x40080000 - 0x400FFFFF RAM1
#define EXTRAM(ADDR)        *(volatile uint32_t*)((uint32_t)ADDR)

void SystemInit()
{
    // инициализация шин внешней памяти
    GPIO_Init_TypeDef GPIO_InitStruct;
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_AltFunc = GPIO_AltFunc_1;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AltFunc;
    GPIO_InitStruct.GPIO_Out = GPIO_Out_En;

    // A[15:8] = MEM_ADDR[7:0]
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8_15;
    GPIO_Init(NT_GPIOA, &GPIO_InitStruct);

    // B[15] = MEM_DATA[0], B[14:4] = MEM_ADDR[18:8]
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4  |
                               GPIO_Pin_5  |
                               GPIO_Pin_6  |
                               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(NT_GPIOB, &GPIO_InitStruct);

    // C[15:6] = MEM_DATA[10:1]
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6  |
                               GPIO_Pin_7  |
                               GPIO_Pin_8_15;
    GPIO_Init(NT_GPIOC, &GPIO_InitStruct);

    // D[15:12] = MEM_DATA[14:11]
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12_15;
    GPIO_Init(NT_GPIOD, &GPIO_InitStruct);

    // E[14] = MEM_Oen0, E[15] = MEM_Oen1, E[12] = MEM_DATA[15]
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_14 | GPIO_Pin_12;
    GPIO_Init(NT_GPIOE, &GPIO_InitStruct);

    // F[9] = MEM_Ubn, F[8] = MEM_Lbn, F[7] = MEM_Cen1, F[6] = MEM_Cen0}
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 |
                               GPIO_Pin_7 |
                               GPIO_Pin_8 |
                               GPIO_Pin_9;
    GPIO_Init(NT_GPIOF, &GPIO_InitStruct);

    // B[0] = MEM_Wen
    GPIO_AltFuncConfig(NT_GPIOE, GPIO_Pin_13, GPIO_AltFunc_2); // хак, чтобы было возможно активировать порт с 3-ей функцией
    GPIO_InitStruct.GPIO_AltFunc = GPIO_AltFunc_3;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(NT_GPIOB, &GPIO_InitStruct);

    // инициализация контроллера внешней памяти
    EXTMEM_Init_TypeDef EXTMEM_InitStruct;
    EXTMEM_StructInit(&EXTMEM_InitStruct);
    EXTMEM_InitStruct.CEMask = EXTMEM_CEMask_Addr_19;
    EXTMEM_InitStruct.EXTMEM_Width = EXTMEM_Width_16bit;
    EXTMEM_InitStruct.EXTMEM_RWWaitState = EXTMEM_RWWaitState_1;
    EXTMEM_InitStruct.EXTMEM_ReadWaitState = EXTMEM_ReadWaitState_1;
    EXTMEM_InitStruct.EXTMEM_WriteWaitState = EXTMEM_WriteWaitState_1;
    EXTMEM_Init(&EXTMEM_InitStruct);

    // инициализация printf
    retarget_init();
}

int main()
{
    uint32_t temp;

    printf("Start!\n");

    // Пишем и читаем ОЗУ0
    printf("Write to ext. RAM0:\n");
    for (uint32_t i = 0; i < 8; i++)
    {
        temp = 0x5324648 + i*0x64;
        EXTRAM0(i*0x4) = temp;
        printf("    %d: 0x%x - 0x%x\n", i, i*0x4, temp);
    }
    printf("Read from ext. RAM0:\n");
    for (uint32_t i = 0; i < 8; i++)
    {
        temp = EXTRAM0(i*0x4);
        printf("    %d: 0x%x - 0x%x\n", i, i*0x4, temp);
    }

    // Пишем и читаем ОЗУ1
    printf("Write to ext. RAM1:\n");
    for (uint32_t i = 0; i < 8; i++)
    {
        temp = 0x1ACDF48 + i*0x2A;
        EXTRAM1(i*0x4) = temp;
        printf("    %d: 0x%x - 0x%x\n", i, i*0x4, temp);
    }
    printf("Read from ext. RAM1:\n");
    for (uint32_t i = 0; i < 8; i++)
    {
        temp = EXTRAM1(i*0x4);
        printf("    %d: 0x%x - 0x%x\n", i, i*0x4, temp);
    }

    printf("The end!\n");
    while(1);
}

