Пример реализации загрузчика образа программного кода из EPCS.
Есть у альтеры пример расширенного копировщика, но он мне, во 1-ых не понравился, во 2-ых я с ним долго провозился — но так и не запустил. Если точно следовать пиндоской инструкции, то загрузчика для EPCS не получится. А чтоб отклонится от инструкции — нужно знать матчасть. Ну а если изучить матчасть, то ни какие инструкции не нужны. ИМХО. А не понравился он мне из-за того, что нужно указывать куда размещать образ программы в flash памяти и следить за тем чтоб не перекрыть конфигурацию. Причем это все делается ручками. А если вдруг придется подвинуть локацию образа программы, то нужно опять пересобирать загрузчик, пересобирать Quartus, перепиливать скрипты и т. д. Ад и израиль!
Исходные данные: имеется рабочий проект — конфигурация + программа.
Конфигурация в 2-х словах: Cyclon III + NIOS II + EPCS + SDRAM. Вектор сброса на контроллер EPCS. Вектор прерывания на SDRAM.
При включении питания загружается конфигурация и процессор сбрасывается. По сбросу выполняется код загрузчика по умолчанию, размещённого в начале адресного пространства контроллера EPCS. Этот загрузчик находит образ программы в EPCS и загружает исполняемый код из flash в SDRAM. После передает управление на точку входа основной программы. Если требуется во время загрузки что-то ещё сделать, то придется писать свой загрузчик. Например мне пришлось до загрузки основной программы в SDRAM сделать тест ОЗУ, т. е. проверить на залипухи/обрывы шины адреса/данных/управления.
Возможны 2 варианта загрузчика.
1 вариант: При включении запускается расширенный загрузчик из onchip-memory, загрузчик копирует код программы из образа flash- EPCS в SDRAM, переписывает вектор сброса. Теперь в векторе сброса стоит инструкция типа
jmp entry_point_in_SDRAM;
Далее загрузчик передает управление основной программе. После очередного сброса процессора программа начинает выполнятся с точки входа основной программы entry_point_in_SDRAM. Наш расширенный загрузчик больше не выполнится до выкл/вкл питания. Т. е. Исполняемый код основной программы заново не грузится из flash в SDRAM, а основная программа стартует незамедлительно.
2 вариант: При включении запускается расширенный загрузчик из onchip-memory, из образа flash в EPCS копирует код программы в SDRAM, и передает управление основной программе. После очередного сброса процессора программа начинает выполнятся, начиная с загрузчика, точно также, как после включения. Т. е. опять загрузчик из образа flash в EPCS копирует код программы в SDRAM и передает управление основной программе.
Размер копировщика не зависит от варианта и занимает примерно 6...7 Кбайт без выхлопа в JTAG_UART, и примерно 9 Кбайт с выводом в JTAG_UART.
Время работы загрузчика.... на глаз.... с выводом в jtag_uart 3-4 секунды, без вывода меньше секунды.
Загрузчик написан на С и состоит из 2-х файлов advanced_boot_copier.h и advanced_boot_copier.с
Вариант I
1. Добавим в SOPC память onchip-memory. RAM(Writable). Размер 12 Кбайт. Отметим галочку Initialize memory content. Остальное по умолчанию. Переименуем в bootRom.
2. Вектор сброса на bootRom, offset 0x0, вектор исключений на bootRom, offset 0x20
3. Собираем процессор.
4. Компилируем проект в Quartus-e.
5. Открываем Eclipse. Создаем новый проект: File->New->NIOS II Aplication and BSP from Template
6. В SOPC Information File name указываем свой процессор, у меня был D:\Work\Quartus\testBoot\cpuNew.sopcinfo
7. Задаем имя проекту, пусть будет bootLoader. Project template – Hello World. Жмём Finish
8. В проводнике идем в папку нашего загрузчика и удаляем файл hello_world.c. Добавляем в эту папку файлы: advanced_boot_copier.c и advanced_boot_copier.h
9. В Eclipse в Project Explorer правой кнопкой мыши по проекту bootLoader, в контекстном меню Refres.
10. В BSP редакторе указываем Uart для ввода/вывода jtag_uart. Отмечаем галочки как на рисунке.
Оптимизацию -Os. На вкладке Linker Script указать все регионы на bootRom
Жмём Generate, ждем окончания процесса и закрываем окно.
11. Если требуется дебажный вывод в uart то отмечаем в advanced_boot_copier.c
#define USING_JTAG_UART 1
иначе
#define USING_JTAG_UART 0
12. У меня в устройстве есть линейка светодиодов. На разных процессах загрузки я зажигаю разные диоды, тем самым контролирую процесс без терминала. Если у вас есть индикация, то замените вывод индикации на свой или закоментируйте строки
IOWR_ALTERA_AVALON_PIO_DATA(IOLED_BASE, 0x2);
13. Собираем проект bootLoader
14. Собираем *.hex. ПКМ по проекту в Project Explorer ->Make Targets->Build... Выбираем mem_init_install, жмём Build. Создастся *.hex с расширенным загрузчиком
15. Запускаем повторную компиляцию в Quartus-e. При этом наш hex с загрузчиком подцепится к *.sof файлу.
16. Программируем ПЛИС полученным *.sof файлом (через квартусовский программатор)
Теперь займёмся рихтовкой рабочей программы/проекта
17. В BSP Editore я ни чего не менял. Оставил всё, как было без расширенного загрузчика.
Жмём Generate, ждем окончания процесса и закрываем окно.
18. Собираем рабочий проект — на выходе *.elf
Ну вот собственно и всё. Осталось залить все это в EPCS
19. В Eclipse открываем флеш-программатор NIOS II->Flash Programmer Создаем/откываем сеттинг файл и программируем. Образ из *.elf должен лечь сразу за *.sof, без смещений.
20. Выключаем плис. Включаем.
21. Если вы указали USING_JTAG_UART 1 и после включения плис, как нинзя, успеть в шеле ввести команду nios2-terminal, то можно залицезреть выхлоп
После сброса процессора вывода в терминал не будет, т. к. код загрузчика больше не выполняется.
Вариант II
1. Добавим в SOPC память onchip-memory. RAM(Writable). Размер 4 Кбайт. Остальное по умолчанию. Снимим галочку Initialize memory content. Переименуем в onchip-memory.
2. Добавим в SOPC память onchip-memory. ROM(Read only). Размер 10 Кбайт. Отметим галочку Initialize memory content. Остальное по умолчанию. Переименуем в onchip-memory.
3. Вектор сброса на bootRom, offset 0x0, вектор исключений на onchip-memory, offset 0x0.
4. Собираем процессор.
5. Компилируем проект в Quartus-e.
6. Открываем Eclipse. Создаем новый проект: File->New->NIOS II Aplication and BSP from Template
7. В SOPC Information File name указываем свой про процессор, у меня был D:\Work\Quartus\testBoot\cpuNew.sopcinfo
8. Задаем имя проекту, пусть будет bootLoader. Project template – Hello World. Жмём Finish
9. В проводнике идем в папку нашего загрузчика и удаляем файл hello_world.c. Добавляем в эту папку файлы: advanced_boot_copier.c и advanced_boot_copier.h
10. В Eclipse в Project Explorer правой кнопкой мыши по проекту bootLoader, в контекстном меню Refres.
В BSP редакторе указываем Uart для ввода/вывода jtag_uart. Отмечаем галочки как на рисунке в п.10 варианта I.
Отметчаем enable_alt_load_copy_rodata
13. На вкладке Linker Script: .text на bootRom, остальные на onchip_memory.
Жмём Generate, ждем окончания процесса и закрываем окно.
13. Если требуется дебажный вывод в uart то отмечаем в advanced_boot_copier.c
#define USING_JTAG_UART 1
иначе
#define USING_JTAG_UART 0
14. У меня в устройстве есть линейка светодиодов. На разных процессах загрузки я зажигаю разные диоды, тем самым контролирую процесс без терминала. Если у вас есть индикация, то замените вывод индикации на свой или закоментируйте строки
IOWR_ALTERA_AVALON_PIO_DATA(IOLED_BASE, 0x2);
15. Собираем проект bootLoader
16. Собираем *.hex. ПКМ по проекту в Project Explorer ->Make Targets->Build... Выбираем mem_init_install, жмём Build. Создастся *.hex с расширенным загрузчиком
17. Запускаем повторную компиляцию в Quartus-e. При этом наш hex с загрузчиком подцепится к *.sof файлу.
18. Программируем ПЛИС полученным *.sof файлом (я делал через квартусовский программатор)
Теперь займёмся рихтовкой рабочей программы/проекта
19. В BSP Editore я ни чего не менял. Оставил всё, как было без расширенного загрузчика. (см рисунок п. 17 варианта 1)
Жмём Generate, ждем окончания процесса и закрываем окно.
20. Собираем рабочий проект — на выходе *.elf
Ну вот собственно и всё. Осталось залить все это в EPCS
21. В Eclipse открываем флеш-программатор NIOS II->Flash Programmer Создаем/откываем сеттинг файл и программируем. Образ из *.elf должен лечь сразу за *.sof, без смещений.
22. Выключаем плис. Включаем.
23. Если вы указали USING_JTAG_UART 1, то после включения плис, в терминале видим вывод.