======Создаем проект для 1901ВЦ1Т====== Миландр представляет хорошую поддержку в SPL для микропроцессоров 1986ВЕ1Т и семейства 1986ВЕ9х. Но помимо этого производитель выпускает достаточно много других интересных микропроцессоров, поддержка которых пока реализована слабо. В этой статье мы рассмотрим, как создать проект для одного из таких МК - 1901ВЦ1Т. Микропроцессор 1901ВЦ1Т состоит из двух ядер - RISC и DSP. Первое RISC ядро аналогично ядру семейства 1986ВЕ9х и разработано на базе //ARM Cortex M3//. Поэтому все, что мы напишем для 1986ВЕ9х, должно более-менее прижиться и в 1901ВЦ1Т. Работать с этим ядром мы будет в том же //Keil//. DSP ядро является аналогом TMS320C546 и для его программирования необходима среда //"Code Composer Studio"// версий 2 или 3.3. Собранный с помощью данной среды //hex// файл можно загрузить через RISC ядро в DSP. Также, на сколько я знаю, среда разработки //"CodeMaster-ARM"// позволяет производить компиляцию и отладку для обоих ядер сразу. Это наверное очень удобно, но в моем случае пока недоступно. Поэтому мы пойдем по первому пути и попробуем когда-нибудь реализовать вариант с загрузкой DSP через RISC ядро. Сейчас же создадим первый проект, который будет собираться и загружаться в 1901ВЦ1Т. Дополнение: //Pack с поддержкой 1901ВЦ1Т теперь можно взять из этого проекта - [[https://startmilandr.ru/doku.php/prog:sd:sdio_vc1#pack_%D0%B4%D0%BB%D1%8F_1901%D0%B2%D1%861%D1%82|ссылка]]. С ним проекты для 1901ВЦ1Т собираются стандартным образом, как и для прочих микроконтроллеров. Поэтому статья становится не вполне актуальна, но показывает способ собрать проект под микроконтроллер, для которого нет поддержки.// =====Создаем проект===== //(Для сборки проекта необходимо установить [[http://www2.keil.com/mdk5/legacy|Legacy support for ARM Cortex-M devices]]. Если этого не сделать, то файлы поддержки ядра, такие как core_cm3.h, core_cmFunc.h, ... необходимо будет подключить вручную из пака для микроконтроллеров 1986ВЕ9х.)// Итак, нажимаем создать новый проект, выбираем папку и название проекта. Назовем его "HelloWorld_1901". После этого нам открывается окно с выбором микроконтроллера. Можно раскрыть дерево "Milandr" и убедиться, что наш процессор не поддерживается в PACK от производителя. Надеюсь вскоре это исправят. Раскрываем дерево //"ARM"//, выбираем //"ARM Cortex M3"// и там присутствует всего один шаблон //"ARMCM3"// - выбираем его, жмем "ОК". {{prog:spec:1901_cortexm3.png}} Далее открывается окно //"Manage Run-Time Environment"//, ничего выбирать тут не нужно, просто жмем "ОК". Создался пустой проект, папку для кода //"Source Group 1"// мы лаконично переименуем в //"user"//. Добавим файл "main.c": * Правой клавишей на //"user"// * "Add New Item to Group user ..." * Выбираем тип файла и вбиваем имя main * Add. В группе проекта появился файл "main.c". Давайте сразу реализуем в нем пустую функцию main. {{prog:spec:1901_mainerr.png}} Запускаем компиляцию и видим по ошибкам внизу, что нашему проекту много чего не хватает, и в первую очередь, таблицы векторов прерываний. Таблица векторов прерываний обычно находится в файле с расширением "*.s", ищем такой файл для нашего процессора в папке PACK от Миландр и находим его по такому пути: \\ C:\Keil_v5\ARM\PACK\Keil\MDR1986BExx\1.4\Libraries\CMSIS\CM3\DeviceSupport\MDR1901VC1T\ inc\ MDR1901VC1T.h startup\arm\ startup_MDR1901VC1T.s system_MDR1901VC1T.c system_MDR1901VC1T.h Здесь я сразу представил дерево путей и все файлы, которые нам потребуются для компиляции проекта. Эти файлы защищены от записи, а нам потребуется внести некоторые изменения. Кроме этого, эти файлы потенциально могут быть обновлены при апдейте Pack. Поэтому скопируем их в директорию нашего проекта, для этого заведем в ней отдельную папку - "lib". Затем снимем защиту от записи: * Выделить все файлы * Правая клавиша мыши - свойства * Снять галочку Read Only. {{prog:spec:1901_readonlyoff.png}} Подключаем файл с таблицей векторов прерываний - //"startup_MDR1901VC1T.s"//: * В дереве проектов жмем правой клавишей на //"user"// * Кликаем на "Add Existing Files to Group user" * Выбираем папку lib * Меняем в диалоговом окне тип отображаемых файлов на //"All files"// * Выбираем нужный файл * Жмем Add и закрываем диалог Close. Пытаемся скомпилировать проект, и возникает следующая ошибка: {{prog:spec:1901_startuperr.png}} По сообщению компилятора понятно, что объектному файлу скомпилированному из файла //"startup_MDR1901VC1T.s"// требуется внешняя (из другого объектного файла) функция //SystemInit//. Если поискать, то такая функция реализована в файле //"system_MDR1901VC1T.c"//. Подключаем его к проекту аналогично тому, как подключали файл //"startup_MDR1901VC1T.s"//. Пытаемся скомпилировать: {{prog:spec:1901_systemerr.png}} Опять ошибка, требуется подключить еще один файл - //"MDR32F9Qx_config.h"//, он располагается в //C:\Keil_v5\ARM\PACK\Keil\MDR1986BExx\1.4\Config//. Скопируем его так-же к себе в проект к остальным библиотечным файлам, в папку "lib" и подключим. Теперь при попытке сборки, возникает аналогичная ошибка, но с указанием, что требуется файл //"MDR32F9Qx_lib.h"//. Находим его в //C:\Keil_v5\ARM\PACK\Keil\MDR1986BExx\1.4\Libraries\MDR32F9Qx_StdPeriph_Driver\inc// и подключаем. Запускаем сборку и видим, что проект успешно собрался. =====Настройки проекта===== Проект компилируется, теперь необходимо указать специфику микропроцессора в опциях проекта. В микропроцессоре 1901ВЦ1Т используется RISC ядро аналогичное 1986ВЕ92У, поэтому все настройки необходимо выставить как в статье - [[prog:start:project_options_9x|"Настройки проекта для 1986ВЕ9х"]], за исключением вкладки //"Device"//. =====Пишем "Hello World"===== Если сравнить спецификации на 1901ВЦ1Т и 1986ВЕ9х, то видно, что порты ввода вывода располагаются в одинаковых адресах и с одинаковыми смещениями (раздел "Описание регистров портов ввода-вывода"). Также наблюдаем полную аналогию в тактировании для CPU_CLK (раздел "Сигналы тактовой частоты" - схема тактирования и описание регистров). По этой причине наш пример [[PROG:Start:HelloWord|"Hello World - светодиод"]] не требует никаких дополнительных доработок. Тактирование и переключение вывода порта будут работать и в данном микроконтроллере 1901ВЦ1Т. Копируем наш код из примера в текущий файл //"main.c"// Для работы примера требуется два файла - //MDR32F9Qx_port.c// и //MDR32F9Qx_rst_clk.c//. Они должны быть скомпилированы средой Keil, поэтому подключаем их к нашему проекту. Файлы эти находятся по следующему пути: \\ //C:\Keil_v5\ARM\PACK\Keil\MDR1986BExx\1.4\Libraries\MDR32F9Qx_StdPeriph_Driver\src// Окно проекта у нас теперь выглядит так, здесь подключены все необходимые файлы: {{opt:1901_projlist.png}} Для того чтобы компиляция прошла успешно, необходимо указать среде, где следует искать заголовочные файлы. - В опциях проекта идем в закладку //С/С++//. - Находим внизу строку //"Include Paths"//, нажимаем кнопку с многоточием. - В открывшемся окне создаем новую строку пути. - В этой строке нажимаем кнопку с многоточием и в открывшемся диалоге выбираем папку, где Keil будет искать требуемые для компиляции файлы. - Создаем две строки с путями согласно скриншоту. {{opt:includepaths.png}} На данном этапе проект компилируется с многочисленными ошибками. Для их устранения требуется зайти в файл MDR32F9Qx_config.h и сделать макроопределение под наш микропроцессор. #ifndef __MDR32F9Qx_CONFIG_H #define __MDR32F9Qx_CONFIG_H #define USE_MDR1901VC1T /* - Это макроопределение указывает используемый МК*/ .... .... #endif /* __MDR32F9Qx_CONFIG_H */ Теперь проект снова успешно собирается. Осталось проверить, какой вывод и от какого порта разведен на один из светодиодов на демоплате. На плате, рядом с микросхемой памяти DD1, виден целый ряд перемычек к каждому светодиоду. Если присмотреться, то на плате указана маркировка, какой порт используется на каждом светодиоде. Давайте выберем крайний светодиод, он подписан на плате РВ11. Модифицируем код [[PROG:Start:HelloWord|"Hello World - светодиод"]] для мигания этим светодиодом. Для того чтобы оставить рабочим старый вариант, вынесем все определения, зависящие от конкретного МК, в макроопределения. Итоговый код получился таким: #include #include // Прототип функции задержки, реализованной ниже void Delay(int waitTicks); #define _test1901 // Выбираем секцию 1901ВЦ1Т для компиляции #ifdef _testBE9x // Определения для 1986ВЕ9х - неактивна при выбранном ключе _test1901 #define PORT_LedClock RST_CLK_PCLK_PORTC #define PORT_Led MDR_PORTC #define PORT_LedPin PORT_Pin_0 #define DELAY_Ticks 1000000 #endif #ifdef _test1901 // Определения для 1901ВЦ1Т - активна #define PORT_LedClock RST_CLK_PCLK_PORTB #define PORT_Led MDR_PORTB #define PORT_LedPin PORT_Pin_11 #define DELAY_Ticks 1000000 #endif // Точка входа, отсюда начинается исполнение программы int main() { // Заводим структуру конфигурации вывода(-ов) порта GPIO PORT_InitTypeDef GPIOInitStruct; // Включаем тактирование порта C RST_CLK_PCLKcmd (PORT_LedClock, ENABLE); // Инициализируем структуру конфигурации вывода(-ов) порта значениями по умолчанию PORT_StructInit(&GPIOInitStruct); // Изменяем значения по умолчанию на необходимые нам настройки GPIOInitStruct.PORT_Pin = PORT_LedPin; GPIOInitStruct.PORT_OE = PORT_OE_OUT; GPIOInitStruct.PORT_SPEED = PORT_SPEED_SLOW; GPIOInitStruct.PORT_MODE = PORT_MODE_DIGITAL; // Применяем заполненную нами структуру для PORTC. PORT_Init(PORT_Led, &GPIOInitStruct); // Запускаем бесконечный цикл обработки - Основной цикл while (1) { // Считываем состояние вода PC0 // Если на выводе логический "0", то выставляем вывод в логическую "1" if (PORT_ReadInputDataBit (PORT_Led, PORT_LedPin) == 0) { PORT_SetBits(PORT_Led, PORT_LedPin); // LED } // Задержка Delay(DELAY_Ticks); // Считываем состояние вода PC0 // Если на выводе = "1", то выставляем "0" if (PORT_ReadInputDataBit (PORT_Led, PORT_LedPin) == 1) { PORT_ResetBits(PORT_Led, PORT_LedPin); }; // Задержка Delay(DELAY_Ticks); } } // Простейшая функция задержки, позднее мы заменим ее на реализацию через таймер void Delay(int waitTicks) { int i; for (i = 0; i < waitTicks; i++) { __NOP(); } } Далее все просто - компилируем, прошиваем программу и наблюдаем мигание на выбранном нами светодиоде. Значит наш проект собрался и запустился успешно. Подобным образом можно реализовывать управление прочей периферией RISC ядра 1901ВЦ1Т, схожей по реализации с 1986ВЕ9х.