Вы находитесь на странице: 1из 42

Оглавление

Раздел 1. Программирование

Для более полного понимания будем создавать проект с нуля.


Для начала будем разбираться с симулятором, потом плавно
перейдём на эмулятор с записью программы в ОЗУ, а затем
научимся прошивать её во флеш-память. Чтобы всё заработало,
для версии 3.1. необходимо установить дополнительные модули:
C2000-3.1-SA-to-UA-TI-FLASH2X.EXE или подобный файл,
который можно найти на сайте TI, а также модуль поддержки
различных симуляторов/эмуляторов
setupCCSPlatinum_v30104C.ZIP, который можно найти на сайте
Spectrum Digital. Приступать к дальнейшей работе имеет смысл
после установки этих модулей.

1.1. Симулятор. Базовые сведения о языке программирования «C».

1.1.1. Конфигурирование среды разработки.

Прежде чем начать работу с Code Composer Studio – среда


разработки, необходимо сначала сконфигурировать её на
использование соответствующего симулятора или эмулятора. Для
этого находим на рабочем столе значок - Setup CCStudio v3.1
и запускаем конфигуратор. В панели My System необходимо
удалить всё, что там есть (при первом запуске там пусто) если это
не касается симулятора, который, как мы договорились, изучим в
первую очередь, так как нам не надо обращаться к «железкам» и
можно позаниматься дома в уютной обстановке без лишнего
хлама. После удаления необходимо мышью перетащить из вкладки
справа (Available Factory Boards) строку F2812 Device Simulator во

вкладку слева, чтобы получилось так: в левой


вкладке. После этого закрываем эту программу и в ответ на диалог
Restart CCS on exit новички отвечают «нет», продвинутые
пользователи – «да». Если ответили «нет» - то теперь идём на
рабочий стол (или в меню Пуск) и находим значок запуска самой
CCS: - кликнув на него, запускаем нашу среду разработки.
При её запуске в заголовке окна (в самом верху) должна быть
надпись, включающая слово Simulator.
1.1.2. Создание рабочего проекта.

Выбрать: Project -> New. Введите в поля имя проекта, начальный


каталог проекта (например, Temp), выбрать тип проекта
executable (будем создавать исполняемый файл), процессор
семейства TMS320F28XX. Имя проекта будет соответствовать
каталогу, созданному внутри начального каталога, что
непосредственно видно при вводе имени:

Жмём «Готово». В меню View (верхняя полоска с менюшками File,


Edit, View… активируется однократным нажатием на Alt) на
вкладке Project должна стоять галочка. Если её нет – то ставим. В
проводнике проекта, щёлкаем на плюсике MyProject.pjt (Debug) и
видим:

Вкладки, появившиеся в окне браузера проекта не являются


физическими (не папка, не каталог, не директория, не ещё что-
либо созданное руками CCS). То есть эти вкладки просто
предназначены для обозначения типов файлов, из которых
состоит проект. Именно: во вкладке Include будут отображены
заголовочные файлы, имеющие расширение *.h. Отметим, в этой
вкладке (Include) заголовочные файлы будут отображены только
после компиляции проекта (точнее в момент, когда анализом
файлов в проекте занимается сама CCS). Во вкладке Libraries –
будут отображены файлы библиотек (имеющие расширение *.lib),
которые мы будем использовать. Во вкладке Source – будут
отображены файлы реализации программного кода *.c и *.asm.
Теперь необходимо навести предварительный порядок. Верхним
уровнем структуризации (упорядочения) проекта, является
уровень разбивки проекта на каталоги, в которых затем будут
храниться файлы, необходимые для его построения. Стандартный
подход следующий: в каталог “src” помещаются исходные файлы
реализации программных модулей, имеющие расширение “c”,
иными словами, помещаются файлы, содержащие функции,
написанные на языке C, а также определения переменных
(локальных (статических) и глобальных). Также в этот каталог
будут помещены файлы, написанные на ассемблере, и имеющие
расширение *.asm. В каталог “include” помещаются заголовочные
файлы, имеющие расширение “h”. В этих файлах содержатся
объявления переменных, функций, определения структур и
констант. В каталог “cmd” помещаются файлы размещения
программных единиц в памяти процессора, эти файлы имеют
расширение “cmd”. В некоторых младших версиях CCS в окне
браузера проекта может иметься только один файл “cmd”, но это
легко обходится путём редактирования файла проекта, имеющего
расширение “pjt” и добавления в него новой строки с именем
других “cmd” файлов. Каталоги “src”, “include”, “cmd”, другие
каталоги, которые помогут вам сделать проект более понятным по
структуре должны находится в каталоге проекта – в каталоге с
именем, которое вы указали ранее (C:\Temp\MyProject). Чтобы
структурировать проект по папкам необходимо: Открыть FAR
Manager или проводник или ещё что-либо, и в папке
C:\Temp\MyProject создать каталоги: Include, Src, Cmd.
FAR: Проводник:

Создание необходимых исходных файлов. Важно обеспечить


нормальную общепринятую структуру файлов. Чтобы не путаться
в терминах объявление/определение, определимся раз и навсегда:
определение – это когда под определяемую сущность выделяется
память, объявление – это нечто абстрактное, ярлык, этикетка, под
объявление память не выделяется. В файлах с расширением “c”,
или ещё называемых файлами реализации, должно содержаться
следующее:

 определения функций
 определения локальных (статических) переменных
 определения глобальных переменных

При этом другие файлы не должны содержать определения


переменной с одним и тем же именем, иначе возникнет ошибка
линковки. Иногда при определении массивов это возможно, но это
– явный путь нарыва на неприятности. Делайте код попонятнее, а
не покруче. Объявление «локальных» макросов, если эти макросы
удобно использовать внутри этого файла, помогут внести
дополнительную ясность. Настоятельно рекомендуется заменять
числа в программе макросами во избежание становления этих
чисел «магическими». В заголовочных файлах, имеющих
расширение “h” должны содержаться:
- объявления сложных составных типов данных, именуемых
структурами,
- объявления глобальных переменных
- объявление макросов, которые будут использоваться во всех
файлах, которые подключают данный заголовочный файл
- стражи включения, которые помогают избежать ошибок при
множественных подключениях заголовочного файла.

В библиотеках TI используется объектный подход к


проектированию программного кода. Есть даже такая утилита,
называемая Algorithm Standard, которая помогает строить
программный код на основе этой методики. Работа с
периферийными устройствами на кристалле осуществляется с
помощью библиотеки, включающей заголовочные файлы и файлы
реализации для работы с периферийными устройствами.
Парадигма и стиль программирования очень важны, поэтому
рекомендуется изучить приёмы, предлагаемые TI.

Для дальнейшего продвижения проекта (замете, что до сих пор мы


не создали ни одного файла и ничего не помещали в проект – если
это не так, значит, вы лезете поперёк батьки в пекло или делаете
что-то не так) необходимо использование библиотеки
периферийных устройств на кристалле процессора. Для этого
надо:
1. Скачайте библиотеку с сайта TI: документ sprc097.zip.
2. Установите эту библиотеку в каталог по умолчанию: c:\tidcs.
Если библиотека установлена, то она должна проявить себя в виде
следующего пути: C:\tidcs\c28\dsp281x\v100, проврете, есть ли
такой путь. Документацию на библиотеку можно посмотреть в
папке doc по этому же пути (файл DSP281x_Readme_V100.pdf).
Кстати v100 – это версия этой библиотеки.

Теперь создадим файл MainFile.c в каталоге проекта в подкаталоге


Src, полный путь: C:\temp\MyProject\Src\MainFile.c. Здесь и далее
будем пользоваться краткими обозначениями этих подкаталогов:
Src, Include, Cmd – для обозначения каталогов, куда надо
поместить файлы. Создать файл можно не выходя из CCS: Меню
File->New->Source File. Прежде чем что либо писать в окно,
сохраним файл под именем MainFile.c. Сделать это можно двумя
способами: корявым и нормальным. Корявый способ:
Меню File->Save, в появившемся окне выбрать папку Src, в поле
имени файла указать MainFile.c, тип файла All Files (*.*), нажать
кнопку сохранить. Нормальный способ отличается от корявого в
том, что наблюдается минимум мышиной возни. Вместо лазанья
по меню просто нажмите Ctrl+S в активном окне файла, и будет
всё то же самое. Настоятельно рекомендуется пользоваться
горячими клавишами для облегчения работы. Далее даётся
небольшой перечень горячих клавиш необходимый в работе.
Сочетание клавиш Результат
Удерживая Shift жмём ← или Выделение фрагмента текста
или ↑ или ↓ или → относительно текущего
положения курсора, то есть
положения до нажатия
соответствующей комбинации
клавиш.
Ctrl+Ins или Ctrl+C при Копирование выделенного
выделенном тексте фрагмента текста в буфер
обмена
Shift+Ins или Ctrl+V Вставка фрагмента текста из
буфера обмена
При выделенном тексте Выделенный фрагмент
нажимается клавиша Tab смещается на 1 табуляцию
вправо. Попросту говоря –
делается отступ. Особенно
полезно для редактирования
«ступенчатого вида
программы».
При выделенном тексте Выделенный фрагмент
нажимается клавиша Shift+Tab смещается на 1 табуляцию
влево.
Ctrl+S Сохранение текущего
документа
Ctrl+← или или ↑ или ↓ или → Курсор прыгает на следующую
текстовую позицию, если текст
разделён не текстовыми
символами (точки, скобки,
запятые и т. д.)
Ctrl+Shift+← или или ↑ или ↓ То же что и выше, только при
или → этом ещё и текст выделяется.

Далее вставим получившийся файл в проект. Для этого


необходимо: меню Project -> Add Files to Project…либо правой
кнопкой мыши щёлкаем по рабочей области браузера проекта и
нажимаем также Add Files to Project. Появится меню:

Видно, что отправной каталог этого окна – это каталог проекта


именуемый MyProject. Тип файла в окне означает шаблон для
выбора типа файла. Ознакомимся с шаблонами в этом меню.
Вкладка Значение
All Files (*.*) Любые файлы
C Source Files (*.c,*.ccc) Исходные файлы реализации на
С
C++ Source Files (*.cpp,*.cc,*,cxx) Исходные файлы реализации на
языке С++
Asm Source Files (*.a,*.s*) Файлы реализации на
ассемблере
Object and Library Files (*.o*,*.l*) Объектные файлы и файлы
библиотек
Configuration file (*.cdb) Файл конфигурации оболочки
CCS
Documents (*.txt, *.doc, *.pdf) Документация на программу в
текстовом формате, в формате
Word, в формате Adobe Acrobat.
Data Files (*.dat, *.m) Файлы, содержащие большие
массивы чисел, которые
необходимо использовать в
программе.
Linker Command File (*.cmd,*.lcf) Файл размещения сегментов
программы в памяти. Файл
конфигурирования линкёра.
Теперь напишем нашу первую программу на С и запустим её на
выполнение. В окне файла MainFile.c пишем:
main ()
{
long a=144,b=0x50,c,d;
c=a+b;
}
☺ Любой файл в проекте можно открыть из браузера
проекта двойным щелчком мыши.
Теперь скомпилируем и отлинкуем программу путём нажатия на
следующую кнопку:
Компиляция (обведено овалом):

или заходом в меню Project -> Build, либо нажатием кнопки F7.
Сразу после этого появится окошко Build, в котором будет
следующий текст (здесь он разбит на строки так как не влезает):
[MainFile.c] "C:\CCStudio_v3.1\C2000\cgtools\bin\cl2000" -g
-fr"C:/temp/MyProject/Debug" -d"_DEBUG" -d"LARGE_MODEL" -ml -v28
-@"../Debug.lkf" "MainFile.c"
"MainFile.c", line 5: warning: last line of file ends without a
newline
"MainFile.c", line 3: warning: variable "c" was set but never used
"MainFile.c", line 3: warning: variable "d" was declared but never
referenced

Warning: The project has no cmd file while the Text Linker is
selected
[Linking...] "C:\CCStudio_v3.1\C2000\cgtools\bin\cl2000"
-@"Debug.lkf"
<Linking>
>> warning: entry point symbol _c_int00 undefined

Build Complete,
0 Errors, 5 Warnings, 0 Remarks.
Этот текст говорит следующее: в первой строчке окна Build
высвечивается аргумент утилиты cl2000 при компиляции файла.
Утилита cl2000 вызывается в фоновом режиме из командной
строки, являясь консольным приложением. cl2000 – это C-
компилятор. В следующей строчке будет предупреждение
(Warning) о том, что вы не поставили Enter при редактировании в
самом конце файла, то есть после последней закрывающей
фигурной скобки в нашем случае. Оно может не появиться, если в
конце файла имеется Enter. В следующей строчке даётся
предупреждение о том, что переменная «c» определена,
вычисляется (по выражению c=a+b), но нигде по ходу выполнения
не используется для дальнейшего ввода/вывода. В следующей
строке также есть предупреждение, что переменная «d»
объявлена, под неё, возможно, выделена ячейка памяти, но при
этом она в программе вообще нигде не используется. Следующая
строчка ключевая: в проекте нет cmd-файла, то есть линкёр не
знает, в какую область памяти размещать нашу программу, не
знает даже из какой точки её запускать! Чтобы всё хорошо
работало, необходимо воспользоваться стандартными файлами и
функциями. Для нашего проекта необходим лишь один файл
rts2800_ml.lib, находящийся в системной папке и не требующий
внесения никаких изменений и других неприятных вещей.
Вставим его в проект, этот файл находится по следующему пути:
C:\CCStudio_v3.1\C2000\cgtools\lib\rts2800_ml.lib, его тип: Object
and Library Files (*.o*,*.l*). В этом файле содержатся необходимые
системные функции для инициализации переменных в начальное
состояние и передача управления нашей функции main(). Теперь
необходимо немного «химии». Создадим cmd-файл, и назовём его
MyCmd. Как обычно: File->New->Source File (либо нажав Ctrl+N) и
сохраним его в папке Cmd с именем MyCmd и типом Linker
Command File (*.cmd,*.lcf). В этот файл забьем следующий код:

MEMORY
{
PAGE 0 :
RAMP_H0 : origin = 0x3F8000, length = 0x001000
RESET : origin = 0x3FFFC0, length = 0x000002
PAGE 1 :
RAM_M1 : origin = 0x000400, length = 0x000400
RAMD_H0 : origin = 0x3F9000, length = 0x001000
}

SECTIONS
{
.text : > RAMP_H0, PAGE = 0
.reset : > RESET, PAGE = 0
.cinit : > RAMD_H0, PAGE = 1
.ebss : > RAMD_H0, PAGE = 1
.stack : > RAM_M1, PAGE = 1
}
Остановимся подробнее.
MEMORY – означает, что внутри фигурных скобок будет объявлена
карта памяти. Карта памяти даётся производителем процессора и
выглядит так, как показано на следующем рисунке:

Из всего этого нас будет интересовать всего 3 области памяти: H0


SARAM (8K X 16) по адресу 0x3F8000, BROM Vector по адресу
0x3FF000, M1 SARAM (1K X 16) по адресу 0x00400. Число в
скобках (1K X 16) означает, что имеется 1024 ячейки памяти по 16
бит в каждой, иными словами, это память объёмом 1024∙2=2048
байт, так как в байте 8 бит.
Внутри фигурных скобок, мы разбили формально память на 2
страницы: PAGE0 и PAGE1. В странице PAGE0 располагается
исполняемый код – программа, в странице PAGE1 – данные, с
которыми работает программа.
Строка
RAMP_H0 : origin = 0x3F8000, length = 0x001000
означает, что будет просто введено имя RAMP_H0, которое будет
обозначать сегмент памяти с начальным адресом 0x3F8000 и
длиною в 0x1000=4096 слов, или 4К слов (напоминаем,1 слово=2
байта). И вообще, адресация в этом процессоре не байтов, а
именно слов. В этом сегменте, размещённому по указанному
адресу, будет размещена программа. Сегмент RESET – служебный,
и находится по адресу, куда переходит процессор в самом начале
работы (BROM), его величина – 2 слова. По этому адресу находится
всего лишь команда перехода на начальный код системного
загрузчика BootLoader. Формально, он должен быть указан для
выбранной библиотеки, которую мы поместили в проект. В
следующей странице PAGE1 выделим сегменты для данных 2
типов: помещаемых в память не с помощью стека и с помощью
стека. Для «нестековых» данных выделим сегмент по адресу
0x3f9000 длиною 0x1000 (1K слов) и назовём его RAMD_H0. Для
стековых данных выделим сегмент по адресу 0x000400 длиною
0x400 (512 слов). Адрес выбран не случайно, так как согласно
документации после включения указатель стека устанавливается
именно по адресу 0x000400. Длину выбрали согласно полной
длине сегмента M1: 0x400. Видно, что формально мы разбили
сегмент H0 пополам – в первой половинке находится программа,
во второй – данные. После объявления страниц и сегментов
следует объявление секций.

Теперь следует сделать следующее: для линкёра необходимо


выставить длину стека (чтобы данные не «заползли» на стек).
Процедура эта формальная, но её надо выполнить, чтобы не
возникало лишних предупреждений. Итак, меню Project->Build
Options->Linker. В поле Stack Size вбиваем 0x400.

Откомпилируем программу заново по F7 и загрузим программу в


память. Загрузка производится следующим образом.
Меню File->Load Program. Появится окошко ввода исполняемого
файла (тип *.out). Исполняемый файл находится в папке Debug и
имеет расширение *.out. Кстати говоря, эта папка появилась
автоматически и её имя даётся по умолчанию для заданной
конфигурации проекта.
Теперь откроем снова файл MainFile.c. Чтобы проверить, как
работает c=a+b сделаем следующее: двойным щелчком мыши
щёлкнем на серой полоске, находящейся слева от области
редактирования, так чтобы появилась красная точка напротив
последней закрывающейся скобки – точка остановки в режиме
отладки:

Это будет точка останова программы. Теперь запускаем


программу на выполнение либо через меню Debug->Run, либо по
нажатию F5. Напротив красной точки появится жёлтая стрелочка
– означающая, что в данный момент мы находимся в этом месте
по программе. Чтобы посмотреть переменные, необходимо их
внести в Watch Window – окно просмотра символьных величин.
Делаем так: меню View->Watch Window. Появится окошко с
вкладкой Watch Locals (просмотр локальных переменных).
Переменные называются локальными, если они находятся внутри
фигурных скобок. Видим, что результат нормальный:
144+0x50=224, так как шестнадцатеричное число 0x50 в
десятичной системе будет равно 80, а 80+144=224.

Если подвести мышью на букву «c», то можно увидеть


всплывающую подсказку – дескать, её значение и тип: long.
Щёлкнув на голубой параллелепипед (вытянутый кубик) мы
перейдём к объявлению этой переменной, а именно курсор
встанет в третьей строчке напротив переменной «c». Лучше
использовать Watch Window, так как в нём можно просматривать
сразу несколько переменных.

Арифметика.

Для начала рассмотрим формы представление чисел. Возьмём,


например число 15. Обычное число. Что же в нём
примечательного? Примечательно то, что это число можно
представить следующим образом: |||||||||||||||.
Представляете, сколько палочек нам нужно, чтобы таким образом
представить число 1500?
☺ Кстати говоря, вся математика базируется на трёх
фундаментальнеших вещах: натуральных числах, операции
сложения и алгоритмах. В реальном мире присутствуют
исключительно натуральные числа – всё остальное, лишь
наша фантазия, позволяющая нам абстрагироваться от
конкретных вещей. Какие бы мы не выводили крутые
интегралы, матрицы и тензоры, всё равно в конечном итоге
всё упрётся к банальной операции сложения над
натуральными числами и алгоритмам. Допустим, знак в
отрицательных числах – это тоже число, просто оно имеет
особое место и обрабатывается по определённым правилам.
Натуральное число + атрибуты, являющиеся тоже числом, +
правила (алгоритмы) над атрибутами. Математика должна
давать какой-то конкретный, осмысленный и осмысляемый
простым людом результат в амперах, вольтах, метрах, а не в
интегралах и дифференциальных формах. Математика – есть
отображение самой себя на множество натуральных чисел +
алгоритмы их обработки. Даже символические вычисления –
тоже проводятся с использованием чисел в системах
компьютерной алгебры (CAS). Единственное, что пока что не
представлено в виде алгоритмов и чисел – это интеллект.
Интеллект породил чёрные дни для студентов в виде
комплексных чисел (которые просто представляют собой
массивчик из 2-х чисел с правилами его обработки) и другие
непонятные вещи. Так что пока не разработаны интуитивные
языки программирования с нейросетевой системой
разработки, будем мучиться с тем, что сами и придумали.

Поэтому ещё древние математики выкрутились следующим


образом. Представили любое вещественное число в десятичной
системе в виде:
 ...  ni  10i  ...  n1  101  n0  100  n1  101  ...  n f  10 f  ...
В формуле приняты следующие обозначения: ± - обозначает знак
числа, n - цифры (разряды) числа: n=0,1,2,3,4,5,6,7,8,9. Точка «.»
отделяет целую часть от дробной в вещественном числе. Индекс у
цифры «n» обозначает её позицию относительно дробной точки.
Число 1500 в такой форме записи представится следующим
образом :
1500  ...  0 10i  ...  1 103  5  102  0 101  0 100  0  101  ...  0 10 f  ...
При записи формул и мы предположили бесконечное количество
разрядов числа, о чём говорит знак троеточия «…» в начале и в
конце формулы. Если записываемое число имеет конечное
количество разрядов, то неиспользуемые разряды просто
становятся нулями, то есть наше число 1500 можно записать и
так: 01500., и так: 1500.00, и даже так: 001500.000.
Ограниченная разрядность позволяет делать хитрые вещи, о
которых мы сейчас и поговорим. Компьютер, который мы в
дальнейшем будем использовать, является целочисленным, то есть
базовые арифметические операции (сложение, вычитание,
умножение, деление) он выполняет с целыми числами. Однако,
вещественное число можно представить в виде целого с
некоторыми ограничениями. Допустим, мы имеем десятичный
компьютер, у которого разрядность равна 6. Число 15.21 можно
записать как 0015.21 в шестиразрядном формате: жирная точка,
которую мы поставили, является формальной, фиктивной, так
как реальный компьютер с целочисленной арифметикой о ней
ничего не знает! Здесь и далее жирной точкой будем обозначать
нашу «виртуальную» дробную часть в целом числе. Поэтому запись
0015.21 просто обозначает целое число 001521. В компьютере это
число можно представить также в виде значения 015.210 (=
015210) – как нам удобно, главное, чтобы оно вместилось в
разряды целиком, либо с как можно большим количеством
значащих цифр. При сложении чисел, принятое нами положение
десятичной точки ни на что не влияет. Иными словами,
целочисленные выражения в 000200+000210=000410 и
000020+000021=000041 для компьютера безразличны, сложение
он выполнит правильно, наше дело – для себя поставить
десятичную точку «.» в том разряде, в котором нам необходимо:
0000.20+0000.21=0000.41, или так: 0002.00+0002.10=0004.10. По-
обычному эти выражения запишутся как 0.2+0.21=0.41 и
2+2.1=4.1 соответственно. Иное дело обстоит с операцией
умножения. Здесь приходится маленько иначе интерпретировать
результат. Допустим, число 15.21 мы представили в нашем
компьютере в виде числа 001521. Формальную десятичную
запятую мы расположили для нас как нам нужно: между первым и
вторым разрядом (0015.21). Важное замечание: нумерация
разрядов начинается с нуля и идёт справа налево. Теперь мы
хотим число 15.21 умножить на число 5.6. Следуя нашему правилу
расстановки десятичной запятой, расположим число 5.6 в
компьютере так: 000560 (для нас: 0005.60). Теперь заставим
компьютер перемножить эти числа:
001521·000560=000000851760. Остановимся на этом моменте
подробнее. Результатом перемножения чисел с ограниченной
одинаковой разрядностью является число с удвоенной
разрядностью. Если перемножаются числа с разным количеством
разрядностей «a» и «b», то итоговое число имеет разрядность «c»,
равную сумме исходных разрядностей «с=a+b». Поэтому, если
например, процессор имеет разрядность регистров
перемножаемых чисел 16 бит, то регистр результата имеет
разрядность 32 бита. Значит, наш компьютер должен иметь
специальный регистр, равный 12 разрядам для команды
умножения, поэтому мы и записали результат в виде 12-ти
разрядного числа: 000000851760. Теперь остаётся правильно
поставить десятичную точку: зная ответ, 15.21·5.6=85.176,
поставим точку в нужном месте: 00000085.1760 (пока мы
действуем от результата, подгонкой). Как же теперь работать с
результатом? Если мы захотим его ещё умножить это число на что-
либо, нам придётся раздувать регистры на 6 разрядов, и так до
бесконечности? Конечно, нет. Придется чем-то жертвовать, а
именно – точностью результата. Чтобы результат был 6 разрядов в
том формате, который мы выбрали для десятичной запятой, а
именно, чтобы она располагалась между первым и вторым
разрядом, необходимо чтобы результат 85.176 был представлен в
компьютере так: 008517, для нас это 0085.17. Видно, что была
отброшена часть результата: а именно, цифра 6. В этом случае,
мы имеем погрешность, связанную с отсечением. Как правило,
регистр результата в компьютере разбит на 2 части: старшую и
младшую. Это сделано для упрощения последующей обработки
результата. Так же и мы разобьем наше 12-ти разрядное число на
2 части: 000000|851760. Чтобы получить «правильный» при
нашей расстановки десятичной точки результат 008517 в старшей
части, нам необходимо сдвинуть получившееся значение в 12-ти
разрядном числе на 4 позиции влево, причём сдвиг нужно
выполнять над всем 12-ти разрядным числом:
Нет сдвига: 000000|851760
1 сдвиг: 000008|517600
2 сдвига: 000085|176000
3 сдвига: 000851|760000
4 сдвига: 008517|600000
При сдвиге влево, появляющиеся свободные разряды справа
заполняются нулями. Количество сдвигов, естественно зависит от
положения точки в исходных числах. Теперь, в старшей части мы
имеем приближённое значение нашего результата (008517).
Младшую часть теперь можно забыть, если она нам не нужна.
Кстати говоря, если теперь младшую часть интерпретировать с
точки зрения расположения нашей точки, то получим число
6000.00 = 6000, которое является своеобразным остатком от
деления. Рассмотрим целое число 85176 (что соответствует при
нашей расстановки запятой числу 851.76), запишем его в
старшую часть 12-ти разрядного числа: 085176|00000, а затем
сдвинем вправо на 1 разряд, то получим число 008517|600000.
Видно, что старшая часть 008517 приближённо меньше в 10 раз
от исходного числа из-за отсечения. Младшая же часть
представляет собой остаток от деления числа 85176 на 10 (0.6),
умноженный на 10000 (6000), при нашей интерпретации
положения запятой. Чтобы получить «правильный» остаток с точки
зрения выбранного положения десятичной точки, необходимо
число 600000 сдвинуть на 4 позиции вправо: 000060, в нашем
представлении это 0000.60 = 0.6. Остановимся подробнее на
сдвигах. Возьмём число 16. Если его сдвинуть относительно
дробной точки влево, то получим число 160. Если сдвинуть
относительно дробной точки вправо, то получим число 1.6. Отсюда
правило: Сдвиг влево означает умножение на основание системы
исчисления, в нашем случае на 10, а сдвиг вправо – деление на 10.
Здесь надо быть крайне осторожным по следующей причине,
которая в вкратце была описана выше. Возьмём число 1.35 и
представим его в виде 6-ти разрядного числа следующим образом:
013500 или 01.3500 (формальную запятую расположили после 4-го
разряда). Теперь сдвинем это число влево: 13.5000, согласно
расположению нашей формальной запятой, получили правильный
результат: 13.5, равный умножению исходного числа 1.35 на 10.
Теперь сдвинем ещё раз влево: 35.0000 – вот тут нас ждёт
сюрприз:
Исходное : 01.3500
1 сдвиг : 13.5000 – цифры не теряем, результат точный
2 сдвига : 35.0000 – потеряли цифру, результат не точный
Стоп, получили так называемое переполнение! Получили
катастрофически неправильный результат. Поэтому при сдвиге
влево надо быть 100% уверенным в том, что при этом сдвиге не
произойдёт переполнение. Если нет переполнения, то при сдвиге
влево всегда получаем точный результат. В нашем случае это
очевидно, так как при умножении на 10 десятичного числа с
ограниченной разрядностью, оставшиеся при сдвиге разряды
заполняются нулями: 1.35, 13.5, 135, 1350 – если нет
переполнения, получаем точный результат умножения на 10.
Теперь рассмотрим сдвиг вправо. Запишем наше подопытное
число и начнём сдвигать вправо:
Исходное : 01.3500
1 сдвиг : 00.1350 – цифры не теряем, результат точный
2 сдвига : 00.0135 – цифры не теряем, результат точны
3 сдвига : 00.0013 – потеряли цифру, результат неточный
Стоп! На третьем разе получили приближённый результат, из-за
отсечения, так как разрядность у нас ограничена шестью.
Поэтому вытекает простое правило: деление при сдвигах будет
происходить точно до тех пор, пока в последнем разряде не
появится цифра, не равная нулю. Кстати говоря, при сдвиге
вправо (делении) если происходит отсечение, то мы получаем
приближённый результат, который, однако, можно впоследствии
использовать. От точного значения он отличается на 1/10·n где n
– отсечённая цифра. А при сдвиге влево (умножении) если
происходит переполнение, мы получаем какой попало результат,
отличающейся очень сильно от точного значения, а именно в 10·n
раз, где n-отсечённая цифра.
Положение «жирной» точки мы можем выбирать, как
заблагорассудится, поэтому необходимо ввести более строгий
термин, чем «жирная точка», который поможет нам в дальнейшем.
Введём IQ формат вещественного числа: IQXX(вещественное
число), в скобках указывается преобразуемое в данный формат
число. XX обозначает разряд, после которого расположена
формальная дробная точка «.» в целочисленном представлении.
Например, IQ1(15.21) означает, что нам необходимо расположить
формальную точку после первого разряда в целочисленном
представлении, то есть число 15.21 мы должны сдвинуть влево на
1 разряд и отбросить (либо округлить) дробную часть:
Было: 15.21
Сдвигаем: 152.1
Отбрасываем дробную часть: 152
Результат: 15.2 в формате IQ1. Формат IQXX – это просто
положение позиции нашей формальной жирной точки.
Формат IQ0 соответствует исходному числу, с отброшенной
дробной частью: IQ0(2.24)=2., IQ0(0.3)=0..
Теперь перейдём к рассмотрению представления вещественных
чисел в двоичной системе.
Вещественное число в двоичном представлении образуется
аналогично десятичному по формуле :
 ...  ni  2i  ...  n1  21  n0  20  n1  21  ...  n f  2 f  ...
где n=0..1. Напомним, что индекс у «n» обозначает цифру в
соответствующем разряде, точка разделяет дробную и целую
части. Формула может непосредственно использоваться для
перевода из двоичной системы в десятичную. Например, запишем
вещественное число в двоичном виде:
1011.1012
Чтобы не путаться в системах, здесь и далее условимся нижним
индексом обозначать базу системы исчисления: 1433.1 10 - это
число 1433.1 в десятичной системе, 101.11 2 – это число 101.11 в
двоичной системе, 12A.B16 – число 12A.B в шестнадцатеричной
системе, и т. д.
Чтобы перевести число 1011.101 2 из двоичной системы в
десятичную, нужно просто воспользоваться формулой :
1011.1012  1  23  0  22  1  21  1  20  1  21  0  22  1  23  11.62510
Чтобы вручную перевести число из десятичной системы в
двоичную, можно исходное десятичное число делить на степени
двойки с выделением остатка по очевидному алгоритму:
11710 =
1 шаг: 117/2 =58, остаток 0.5 (есть) 1
2 шаг: 58/2 =29, остаток 0 (нет) 0
3 шаг: 29/2 =14, остаток 0.5 (есть) 1
4 шаг: 14/2 =7, остаток 0 (нет) 0
5 шаг: 7/2 =3, остаток 0.5 (есть) 1
6 шаг: 3/2 =1, остаток 0.5 (есть) 1
7 шаг: 1/2 =0, остаток 0.5 (есть) 1
Получили в конце деления ноль, останов.
В столбце справа, если смотреть снизу вверх, видим число – это и
есть ответ: 11101012. Отметим, что этот алгоритм для перевода
требует log2(N) операций, где N – преобразуемое число.
Интересным можно назвать перевод из двоичной системы в
шестнадцатеричную и обратно. Для начала, нарисуем таблицу
первых 16-ти значений чисел в двоичной, десятичной и
шестнадцатеричной системах (см. Табл. ).
Табл. Значения в двоичной, десятичной и шестнадцатеричной
системах.
Двоичная Десятичная Шестнадцатеричная
0000 00 0
0001 01 1
0010 02 2
0011 03 3
0100 04 4
0101 05 5
0110 06 6
0111 07 7
1000 08 8
1001 09 9
1010 10 A
1011 11 B
1100 12 C
1101 13 D
1110 14 E
1111 15 F
В таблице видно, как в двоичной системе чередуются числа в
разрядах: в нулевом: 010101…, в первом: 001100110011…, во
втором: 0000111100001111... – это помогает быстро вручную
составить таблицу этих чисел. В числе, представленном в
двоичной системе также можно выбросить нули перед первой
попавшейся единичкой: 00102 есть 102. Правило перевода из
двоичной системы в шестнадцатеричную и обратно.
Из двоичной в шестнадцатеричную:
Возьмём число, например, 10110100110110 2. Разбиваем это число
на 4 цифры, начиная с младшей:
10 1101 0011 0110, теперь получившиеся «тетрады» сопоставляем
по таблице со значениями в шестнадцатеричной системе, как
показано ниже:
10 1101 0011 0110
2 D 3 6
Итак, число 10110100110110 2 = 2D3616. Аналогично переводим
число из шестнадцатеричной системы в двоичную:
Берём число, например, 3A16, разбиваем побуквенно и просто по
таблице слева направо записываем результат в двоичной системе:
3 A
0011 1010
Итак, значение 3A16=1110102. Из-за этого удобства перевода, в
программах часто используется шестнадцатеричная система.
Мы до сих пор ничего не сказали о форме представления
шестнадцатеричных чисел. Шестнадцатеричное число
представляется в виде :
 ...  ni  16i  ...  n1  161  n0  160  n1  161  ...  n f  16 f  ...
где n=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15.
И вообще, как вы уже успели заметить, любое число в системе с
основанием b можно представить в виде :
 ...  ni  bi  ...  n1  b1  n0  b0  n1  b 1  ...  n f  b  f  ...
при этом цифра n=0..b-1. Используя формулы представления
чисел, можно переводить числа из одной системы в другую.

Двоичная арифметика. Для этой арифметики справедливо всё


вышесказанное, просто одинаковые числа отличаются
количеством разрядов, и в двоичной системе работать менее
привычно, чем десятичной. Также введём для двоичного формата
IQ-представление, или «жирную точку». Рассмотрим число
0101.102 , как и для десятичного формата, от лишних нулей
можно избавиться: 0101.102 =101.12. В десятичную систему это
число можно перевести по формуле :
Имеем: 101.12 = 5.510. Чтобы представить это число в
шестнадцатеричной системе, проделаем следующее. Будем делить
в столбик на 16, также как мы это делаем обычно в десятичной
системе, когда делим на 10.
5.510 | 1016
_3716 0.3716
3016
_7016
7016
016
Итак, проверяем:
Следует отметить, что любое вещественное число в двоичной
системе имеет конечное представление в десятичной системе, так
как деление на 2 не приводит к бесконечной дроби в десятичной
системе, обратное же не верно. Например, число 5.3 не имеет
конечного числа в двоичной системе.

Указатели.

Указатель – это переменная, содержащая адрес другой


переменной. Для работы, указатель должен быть определён, то
есть в него должен быть загружен конкретный адрес используемой
ячейки, иначе, произойдёт искажение данных или в худшем
случае, программный сбой при записи по неправильному адресу.
Также важен тип данных, на который указывает указатель,
указателей на отдельные биты не существует:
Существует специальный указатель, в котором содержится ноль
«0» (NULL pointer) – который ни на что не указывает. Как правило,
нулевое значение указателя используется для обхода массивов
указателей, то есть когда встретился указатель с нулевым
значением, обход массива прекращается. Переделаем нашу
программу следующим образом:
main () //1
{ //2
long a=144,b=0x50,c,*d,e; //3
c=a+b; //4
d=&a; //5
e=*d+b; //6
}
Изменения в программе выделены жирным шрифтом. Справа
даны комментарии, обозначаемые двумя наклонными черточками
«//» - всё, что расположено правее этих символов считается
комментарием и в программе не используется. В нашем случае
комментариями являются номера строк. Что мы получили?
Мы объявили указатель «d». Теперь имя переменной «d» имеет тип
не «long», а «long*» (читается: long со звёздочкой, указатель на long)
- указательный тип. То есть эту переменную мы можем
использовать только в качестве указателя. Для простоты
понимания можно сказать, что переменные «a,b,c,e» – содержат
значения, а переменная «d» содержит адрес. Нельзя путать
значения с адресами. По умолчанию, переменные «c,d,e» не
инициализированы, то есть в отличие от «a» и «b» им не присвоено
значение, и в них содержится «мусор» - то есть неопределённые
значения. Как мы выяснили ранее, указатель обязан быть
проинициализирован либо правильным адресом, либо нулём,
означающего неиспользуемый указатель. В нашем случае мы его
проинициализировали правильным адресом в строке 5, а именно,
адресом переменной «a»:
d=&a;
Теперь переменная-указатель «d» содержит адрес ячейки «a» и
указывает на переменную с типом «long». Мы использовали для
получения адреса ячейки операцию взятия адреса объекта «&»
(читается: амперсанд). Операция взятия адреса может
применяться только к символам, к выражениям её применять
нельзя, например нельзя получить адрес выражения «&(a+b)». В
следующей строке 6 мы с помощью операции «*» получаем
значение по адресу:
e=*d+b;
В этом выражении «d» указывает на переменную «a» поэтому
фактически мы имеем выражение «e=a+b». Отметим, что операция
«*» является обратной операции «&», то есть если «&» получает
адрес, то «*» берёт значение по этому адресу. Теперь рассмотрим
действия с указателями на практике. Записав эту программу,
откомпилируйте её и загрузите. Поставьте точку остановки так,
как показано на рисунке:

Запустите программу (F5). Жёлтая стрелочка остановится


напротив строчки с красной точкой. Добавьте переменные «d» и
«e» в Watch Window следующим способом: правой кнопкой мыши
щёлкаете на переменной «d» в тексте программы, в появившемся
окошке жмёте команду Add to Watch Window (3-я сверху).
Аналогично проделываете с переменной «e». Чтобы закрыть
неиспользуемое окошко Watch Window, как и впрочем, любое
другое, щелкните внутри окошка правой кнопкой и выберете
команду Close (2-я снизу). Должны получить следующее:

Видим, что появилась переменная «d», содержащая мусор, так как


строчка «d=&a» ещё не успела выполниться. Замете, что жёлтая
стрелочка указывает на строчку, которая будет выполняться.
Выполним текущую строчку (5) командой меню Debug->Step Over
или нажатием клавиши F10. Теперь переменная «d» примет
значение 0x0000040C. Остановимся здесь подробнее. Помните,
как мы инициализировали стек в области памяти RAM_M1 в .cmd-
файле:

RAM_M1 : origin = 0x000400, length = 0x000400

.stack : > RAM_M1, PAGE = 1

Эта область памяти имеет начальный адрес 0x400 и длину 0x400,
то есть адрес последней ячейки будет равен 0x7FF. Мы же видим
значение переменной «d» равное 0x40C, откуда следует вывод о
том, что переменная «a» размещается в стеке, так как её адрес
равен 0x40C (переменная «d», напомним получает адрес
переменной «a»). Нажмём на «+» в Watch Window напротив
переменной «d», увидим, что значение по этому адресу равно 144
(или 0x90 в шестнадцатеричном формате), то есть такое же, как и
у переменной «a». Видна также важная для нас подсказка в виде
(*d) – означающая, что берётся значение по адресу, размещённому
в этой переменной. Проделайте следующее: в третьей строчке
Watch Window, там, где расположен рисуночек дважды
щёлкните левой кнопкой и введите:
*d
получите то же самое.

☺ В столбце Radix левой кнопкой вы можете менять


формат вывода:
hex – шестнадцатеричный
dec – десятичный целый
bin – двоичный (нолики и единички)
oct – восьмеричный (0,1,2,3,4,5,6,7,8,10,11…)
char – символьный для текущей кодировки
float – с десятичной точкой
scientific – в форме мантиссы и экспоненты (1e10)
undigned – беззнаковый целый
auto – на усмотрение CCS
qvalue – в формате IQ

Отметим, что таким способом можно вручную вставлять


выражения и переменные в Watch Window. Вставьте вручную
также переменные «a» и «b». Снова нажмём F10 (выполнить
следующую строчку) и получим значение «e», равное 244.

Структуры.
Что такое структура? Структура – это данные, объединённые под
общим именем. Структура предназначена исключительно для
удобства. Всегда можно обойтись без структур, используя
массивы. Но это так не удобно, возиться с номерами, вместо имён.
Структура – дело абстрактное, то есть это просто соглашение
(контракт), по которому мы объединяем данные. Вообщем
встретили мы данные, и видим, что среди них возник кипишь.
Чтобы навести порядок, подходим к ним и заключаем договор, что
они объединяются под именем «Рога и Копыта». Затем на базе
этого договора мы можем создавать другие объединения с тем же
самым составом, а можем даже создать целый массив «Рогов и
Копыт». Переходим к делу. Структуры будем объявлять в
заголовочном файле, который имеет расширение *.h. Когда мы
объявляем структуру, память под неё не выделяется, и вообще,
как мы раньше договаривались, в h-файлах не должно быть
вещей, приводящих к выделению под них памяти. Имя
заголовочного файла должно отражать его содержимое, как
правило, это имя должно совпадать с именем главной структуры в
этом файле. Будем создавать комплексное число, используя
структуры. Прежде чем что либо делать, необходимо выделить
главные моменты задачи: типы данных и действия над этими
данными. Типы данных: комплексное число состоит из мнимой и
действительной частей. Пусть эти части у нас будут
целочисленного типа int. Какие операции должны выполняться
над комплексными числами? Ответ: всякие, но для обучения
выберем попроще: сложение и умножение. Создайте новый файл
(Ctrl+N), сохраните его (Ctrl+S) в папке проекта include под
именем complex.h. Напомниаем, что при сохранении необходимо
в поле имени написать complex.h, при этом выбрать тип файла All
(*.*), либо просто написать complex и выбрать тип файла Header
Files (*.h). Аналогично создадим файл complex.c, в который мы
будем помещать функции, которые работают со структурой из h-
файла.

Чтобы начать работу с библиотекой IQmath, необходимо сделать


следующее:
1. Скачайте sprc087.zip и установите в директорию по
умолчанию (C:\tidcs)
2. Поместить копию файла IQmathLib.h в Ваш проект:
Зайти в каталог C:\tidcs\c28\IQmath\cIQmath\include
Выбрать файл IQmathLib.h
Поместить его копию в каталог Мой_проект\Include

ЧАВО: Иногда бывает, когда устанавливаются другие


библиотеки, например, pmsm… - для управления двигателями, и
другие, возникает следующая проблема: в папке с заголовочными
файлами для данной библиотеки присутствует файл IQmathLib.h.
Это делает кучу предупреждений, так как этот файл уже включён
где-либо в проекте. При этом может возникнуть коллизия,
связанная с разным значением макроса
#define GLOBAL_Q 24
прописанного в IQmathLib.h в разных местах по разному,
например у вас записано другое значение:
#define GLOBAL_Q 27
и это несовпадение может дать нехороший результат. Поэтому,
необходимо проследить, чтобы в вашем проекте была
единственная копия файла IQmathLib.h. Просто надо пройтись по
путям поиска компилятором подключаемых заголовочных файлов:
Project -> Build Options -> вкладка Compiler -> категория
Preprocessor -> Include Search Path. Вообщем если пробежаться по
всем перечисленным там каталогам, вы можете встретить только
один экземпляр этого файла, в папке вашего проекта:
Мой_проект\Include.

3. В CCS (Code Composer Studio) проделать следующее:


Добавить в проект файлы: Project -> Add Files to Project... в окошке
указать тип Object and Library Files (*.o*, *.l*) и указать файл
C:\tidcs\c28\IQmath\cIQmath\lib\IQmath.lib.
Удостовериться, что в файле размещения секций памяти (*.cmd) в
Вашем проекте имеются строки, содержащие имена
IQmath и IQmathTables. IQmath – это секция, где будут размещены
функции IQmath, используемые в Вашем проекте, IQmathTables –
секция таблиц синуса, косинуса, арктангенса, квадратного корня.
Например, в разделе MEMORY могут содержаться следующие
строки для проекта с использованием ОЗУ:
BOOTROM (RW) : origin = 0x3ff000, length = 0x000fc0
RAMH0 (RW) : origin = 0x3f8000, length = 0x002000
а в разделе SECTIONS:
IQmathTables : load = BOOTROM, type = NOLOAD, PAGE = 0
IQmath : load = RAMH0, PAGE = 0.
Внимательно! Для устройств TMS320F2810 или TMS320F2812 в
секции IQmathTables тип памяти должен быть NOLOAD, так как
таблицы математических функций уже записаны в ПЗУ.

Теперь можно приступать к работе с библиотекой.


1. В файле IQmathLib.h, который находится в Вашем
проекте в каталоге Мой_проект\Include можно
выставлять диапазон переменных с типом _iq с
помощью макроса GLOBAL_Q.
2.

Ассемблер.
Команды умножения.
Команда QMPYL ACC,XT,loc32, где в качестве loc32 будем
использовать *XAR{N}, где N=0…7. В адресный регистры XAR{N}
необходимо предварительно занести адрес ячейки, в которой
находится число, которое затем умножим на содержимое регистра
XT. Регистр XT также должен быть проинициализирован. В
качестве примера рассмотрим следующий код.

Объявим и определим переменную на языке С:


Файл.h:
extern long MyVar1,MyVar2;
Файл.c:
long MyVar1 = 0.1*2147483648,
MyVar2 = 0.3*2147483648;

2147483648*X=2^31*X означает перевод из дробно-десятичного


представления числа X (-1≤X<1) в формат с фиксированной
точкой IQ31.

Ассемблер:
.ref _MyVar ;указание ассемблеру, что эта переменная
;описана в другом месте

MOVL XAR1,#_MyVar1 ; помещаем в XAR1 адрес MyVar1 (#)


MOVW DP,#_MyVar2 ; Загружаем указатель на
; переменную MyVar2 в Data Pointer
MOVL XT, @_MyVar2 ; загружаем XT значением _MyVar2
; указатель берётся из DP,
; @_MyVar2 будет заменено нулём,
; так как смещение относительно
; указателя в DP равно нулю.
; (1 смещение = 2 байта)
QMPYL ACC,XT,*XAR1 ; помещаем в ACC результат:
; ACC=XT*(*XAR1), где *XAR1
; означает взятие значения
; по адресу в XAR1
Значения регистров и памяти до выполнения QMPYL:
*XAR1 = 214748364 = _IQ31(0.1)
XT = 644245094 = _IQ31(0.3)
После выполнения QMPYL:
ACC = 32212254 = _IQ31(0.015) = IQ30(0.03)
Видно, что результат получается в 2 раза меньше, чем ожидается,
так как результат представляется в формате IQ30 а не в исходном
IQ31. Этот факт отражён и в документации spru430x.pdf. Поэтому
необходимо каждый раз вводить коррекцию сдвигом влево на
необходимое количество разрядов после умножения, либо
использовать смешанные форматы. Причём при умножении
разных форматов для любой команды умножения справедливо
следующее:
IQ(X)*IQ(Y)=IQ(X+Y-32), X+Y>32

Синусы и косинусы.
Таблица представляет собой значения синусов, начиная с адреса
0x3FF000. Значения синуса представлены в 32-х битном формате
(2 слова, 4 байта) в количестве 640 точек (2560 байт) в диапазоне
 5 
от 

0, 
2 
рад. в формате IQ30. Период равен 512 точкам,
последняя точка перед повторением периода: 511 (0x1FF).
Значение синуса Sm в точке m, где m – номер точки по таблице,
  m  

вычисляется по формуле Sm  round  2  sin 256   , где round – операция
30

  
округления до ближайшего целого.

Методика нахождения синуса и косинуса, когда есть


вышеописанная таблица синусов.

Для начала, определимся с рабочим форматом. Наиболее простой


и лёгкий в реализации будет формат IQ30, так как таблица
синусов дана в этом формате. Минимальное значение любая
переменная будет принимать равным -2, а максимальное: 2-2 -30 в
IQ формате это будет соответственно IQ(-1.0) и IQ(1.0)-1.
Пусть даны функции синуса и косинуса:
S (t )  sin( k  t )
C (t )  cos(k  t )
Пусть мы хотим теперь получить значения функций синуса и
косинуса, используя таблицу синусов, введённую ранее.
Переменная t может принимать некоторое значение в диапазоне
t   0,1 . Если t приняло своё максимальное значение tmax, то это
соответствует периоду. Поэтому можно записать условие для
нахождения коэффициента k:
k  t max  2 . Так как tmax очень близко к 1, положим tmax=1, тогда
получаем, что
k  2
Чтобы теперь воспользоваться таблицей, необходимо число t
представленное в формате IQ30 преобразовать в число,
записанное в формате IQ9. Чтобы пояснить суть преобразования,
проделаем следующие заключения:
Пусть t=0.98. В формате IQ30 это значение запишется так:
0.98∙230=(отсечение)1052266987=0x3EB851EB.
В формате IQ9 это число будет выглядеть так:
0.98∙230=(отсечение)=501=0x1F5.
Видно, что если подставить вместо 0.98 число, максимально
близкое к 1, то максимальное значение в формате IQ9 будет равно
511 (0x1FF), а это период табличной функции. Поэтому мы можем
исходное число просто сдвинуть на 30-9=21 разряд вправо, тем
самым, оставляя нужные первые 9 бит от исходного числа,
которые и будут являться индексом в таблице. Если сдвинуть
число 0x3EB851EB на 21 бит вправо в 32-х битном регистре,
получим число 0x1F5 и остаток 0xC28F58, который потеряется, но
он содержит некоторую важную информацию. Теперь проделаем
хитрую вещь: запишем число 0x3EB851EB в старшую часть 64-х
битного регистра и сдвинем число в этом регистре. В качестве
регистра 64 бита можно использовать пару ACC:P – аккумулятора
и регистра P. В этом случае проще реализовать сдвиг, так как
только для этой пары существуют 64-х битные команды сдвига.
До сдвига:
ACC : P
63 32 31 0
3 E B 8 5 1 E B 0 0 0 0 0 0 0 0
После сдвига
Индекс Остаток
0 0 0 0 0 1 F 5 C 2 8 F 5 8 0 0
В старшей части сразу получаем индекс в таблице, то есть
приближённое к реальному значению t значение tm.
Остаток в младшей части 64-х битного регистра есть не что иное,
как разница, умноженная на 232-21=211, между «истинным»
значением t1 и ближайшему к нему значению tm, используемого в
качестве индекса таблицы. Если теперь число 0x1F5 сдвинуть на
21 бит влево, то получим значение tm в исходном формате IQ30:
0x3EA00000. Разница между исходным t и tm (отметим, что
переменные для разницы или суммы должны быть в одинаковом
формате) равна 0x3EB851EB-0x3EA00000=0x1851EB. Если теперь
эту разницу умножить на 2048, то получим остаток в нашем 64-х
битном регистре: 0x1851EB*2048=0xC28F5800. Иначе говоря
разница в формате IQ30 равна t-tm=Число_в_регистре*1/2048.

Напомним, что шаг таблицы равен 1/512 от периода, поэтому,


получаемое значение синуса, взятое из таблицы по адресу
0x1F5+0x3FF000 является весьма приближённым. Для более
точного нахождения воспользуемся разложением Тейлора и схемой
Горнера, при этом необходимо использовать полученный остаток.
Разложим функции в окрестности точки tm, где tm – индекс в
таблице синусов:
ST (t )  sin  k  tm   k  t  tm  cos k  tm  
 k  t  tm   2 sin  k  t    k  t  tm   3 cos k  t 
m m
2 6

CT (t )  cos k  tm   k  t  tm  sin  k  tm  
 k  t  tm   cos k  t    k  t  tm   3 cos k  t 
2

m m
2 6
обозначим произведение разницы t-tm на коэффициент k как
k  t  tm   Dt m
Для дальнейших выкладок применим схему Горнера к :
  1 1  
ST (t )  sin k  tm    cos k  tm     sin k  tm   cos k  tm   k  t  t m    k  t  tm    k  t  tm 
  2 6  
  1 1  
CT (t )  cos k  t m     sin k  tm     cos k  t m   sin k  t m   k  t  t m    k  t  t m    k  t  t m 
  2 6  
Выражение под знаками синуса и косинуса мы получили, сами
значения синусов и косинусов легко получить из таблицы,
используя указатели и индексацию со смещением. Поэтому
положим
sin  k  tm   sin m , cos k  t m   cos m
Подставляя и в получаем :
  1 1  
ST (t )  sin m   cos m    sin m  cosm  Dtm   Dt m   Dt m
  2 6  
  1 1  
CT (t )  cos m    sin m    cos m  sin m  Dt m   Dtm   Dt m
  2 6  
Исходя из формулы умножения разных форматов
IQ(X)*IQ(Y)=IQ(X+Y-32), приходим к заключению, что для того,
чтобы при умножении синуса или косинуса, представленного в
формате IQ30, на Dtm, получить результат в формате IQ30,
необходимо, чтобы Dtm было в формате IQ32. Чтобы привести Dtm
к формату IQ32 необходимо рассмотреть следующее. Число-
остаток в регистре будет иметь формат IQ30, если его умножить
на 1/2048, как мы выяснили ранее. Чтобы число-остаток в
регистре имело формат IQ32 его надо умножить на 4 (2 сдвига
влево), поэтому число-остаток в регистре нужно умножить
коэффициент 1/512. Коэффицент k  2 , поэтому формула в
формате IQ32 Dtm32 (в программе обозначается как Dt[m]) будет
2 
равно Dtm32   reg 32   reg 32 , где reg32 – содержимое младшей
512 32 256 32
части 64-х битного регистра после сдвига. Здесь также был учтён
тот факт, что при умножении числа в формате IQ32 на IQ32
получаем число также в формате IQ32. Но с этим форматом
корректно может работать лишь команда умножения без знака
QMPYUL, при этом числа в IQ32 представляются, естественно, без
знака. Схему Горнера необходимо вычислять с «внутренних
скобок» в выражении .
Для вычисления преобразования abc->dq с использованием -β
координат, необходимо предварительное вычисление синуса и
косинуса аргумента.
Программа вычисления синуса-косинуса аргумента:
   
Для начала определим константу:   232   52707179  0x03243F6B
256 32  256 

Значение времени t помещается в поле Gamma следующей


структуры:
typedef struct tag_GAMSICO
{
_iq Gamma;
_iq Si;
_iq Co;
} GAMSICO;

Возвращаемые синус и косинус процедура кладёт в поля Si и Co


соответственно. Указатель на объект структуры записывается в
регистр XAR3.
Процедура написания кода такова:
В файле *.c создаётся и инициализируется объект этой структуры:
GAMSICO GAMSICOObj={0,0,0};
В файле *.h созданная переменная объявляется:
extern GAMSICO GAMSICOObj;
На ассемблере указывается ссылка на внешнюю переменную
(подобие extern на C):
.ref _GAMSICOObj
Далее приведён листинг программы вычисления синуса/косинуса
SETC OVM ; устанавливаем флаг
; защиты от переполнения при
; суммировании или нахождении
; противоположного числа
MOVL XAR6,#0x3FF100 ; указатель на таблицу косинусов
MOVL XAR7,#0x3FF000 ; указатель на таблицу синусов
MOVL XAR3,#_GAMSICOObj ; указатель на объект структуры,
; (базовое значение, смещение 0)
MOVL ACC,*XAR3++ ; загружаем аккумулятор значением
; аргумента и передвигаем
; указатель на след. элемент объекта
; структуры (синус)
CLRC TC ; очищаем флаг TC, он модифицируется
; следующей командой
ABSTC ACC ; находим модуль аргумента (без переполн.)
; и сохраняем знак в TC
MPYB P,T,#0 ; обнуляем P (метод умножения на 0)
ASR64 ACC:P,16 ; сдвигаем регистровую пару ACC:P
; на 21 позицию вправо (16+5)
ASR64 ACC:P,5 ;
AND AL,#0x01FF ; защищаем от результата большего
; чем 511 (0x1FF)
LSL AL,1 ; индексация в словах, а так как
; в таблице синусов значение равно
; 2 словам, поэтому необходимо
; увеличение получившегося индекса в
; 2 раза
MOVZ AR0,AL ; загружаем в регистр AR0 значение
; индекса

MOV AL,#0x3F6B ; заносим константу 0x03243F6B в ACC


MOV AH,#0x0324 ; ACC = 0x03243F6B = Pi/256 (IQ32)
MOVL XT,ACC ; XT=ACC
;
QMPYUL P,XT,P ; умножаем остаток на константу
; и получаем значение Dt[m]
MOVL XT,P ; загружаем XT значением Dt[m]
MOVL XAR4,*+XAR6[AR0] ; загружаем XAR4 табличным косинусом
MOVL XAR5,*+XAR7[AR0] ; загружаем XAR5 табличным синусом

; вычисление синуса
MOVB ACC,#0 ; обнуляем аккумулятор
SUBL ACC,XAR5 ; ACC=-sin
ASR64 ACC:P,1 ; команда корректно работает
; со знаком (без участия SXM),
; без дополнительных регистров
; ACC=-1/2*sin
QMPYL P,XT,XAR4 ; P=cos*Dt[m]
MPY P,PH,#10922 ; P=1/6*cos*Dt[m]
SUBL ACC,P ; ACC=-1/2*sin-1/6*cos*Dt[m]
QMPYL ACC,XT,ACC ; ACC=(-1/2*sin-1/6*cos*Dt[m])*Dt[m]
ADDL ACC,XAR4 ; ACC=(-1/2*sin-1/6*cos*Dt[m])*Dt[m]+
; +cos
QMPYL ACC,XT,ACC ; ACC=((-1/2*sin-1/6*cos*Dt[m])*Dt[m]+
; +cos)*Dt[m]
ADDL ACC,XAR5 ; ACC=((-1/2*sin-1/6*cos*Dt[m])*Dt[m]+
; +cos)*Dt[m]+sin
NEGTC ACC ; восстанавливаем знак
;
MOVL *XAR3++,ACC ; сохраняем значение синуса в
; структуре и передвигаем указатель
; на след. элемент объекта структуры
; (косинус)

; вычисление косинуса
MOVB ACC,#0 ; обнуляем аккумулятор
SUBL ACC,XAR4 ; ACC=-cos
ASR64 ACC:P,1 ; команда корректно работает
; со знаком (без участия SXM),
; без дополнительных регистров
; ACC=-1/2*cos
QMPYL P,XT,XAR5 ; P=sin*Dt[m]
MPY P,PH,#10922 ; P=1/6*sin*Dt[m]
ADDL ACC,P ; ACC=-1/2*cos+1/6*sin*Dt[m]
QMPYL ACC,XT,ACC ; ACC=(-1/2*sin-1/6*cos*Dt[m])*Dt[m]
SUBL ACC,XAR5 ; ACC=(-1/2*sin-1/6*cos*Dt[m])*Dt[m]-
; -sin
QMPYL ACC,XT,ACC ; ACC=((-1/2*sin-1/6*cos*Dt[m])*Dt[m]-
; -sin)*Dt[m]
ADDL ACC,XAR4 ; ACC=((-1/2*sin-1/6*cos*Dt[m])*Dt[m]-
; -sin)*Dt[m]+cos
MOVL *XAR3,ACC ; сохраняем значение косинуса в
; объекте структуры

Вычисление D-Q преобразования производится с помощью


формул:

2
A
 B  C  ,
 
3 2 
1
  B  C ,
3
D    cos      sin    ,
Q    sin       cos   ,
1
Z   A  B  C
3

Обратные преобразования имеют вид:


  d  cos    q  sin    ,
  d  sin     q  cos   ,
A  Z ,
1

B  Z    3 ,
2

1
C  Z    3
2
 

При работе в симуляторе, убрать Memory Mapping, чтобы иметь


возможность записывать в ROM таблицы IQMath.

Загрузка модуля ШИМ значением в формате IQ30.


Для начала нарисуем рис .

Рис. Значение счётчика TxCNT от времени T.

На этом рис. показано изменение значения счётчика TxCNT в


зависимости от количества тактируемых импульсов, поданных на
этот счётчик. Длительность тактирующего импульса определяется
значением частоты модуля ФАПЧ (SYSCLKOUT) и делителем этой
частоты (HSPCLK). В нашем случае имеем тактовую частоту
модуля ШИМ равной частоте ядра, равной 135МГц. Значение,
закладываемое в TxPR равно половине периода (в тактах). Общее
количество тактов на период определяется по формуле:
FCLK
N  , Где FCLK – тактовая частота модуля ШИМ, FPWM – частота
FPWM
опорного сигнала (частота пилы). Для FCLK = 135МГц и FPWM =
135 106
20кГц получаем N   7500 . Значение TxPR должно быть равно
20 103
половине от этой величины (при заданной форме пилы), то есть
TxPR=7500/2=3750. Нулевая величина глубины модуляции будет
соответствовать значению регистра сравнения CMPRx = TxPR/2. В
нашем случае это будет равно CMPRx=3750/2=1875. При этом на
выходе будет наблюдаться меандр, с частотою 20кГц,
скважностью 0.5, естественно, если при этом отключён блок
формирования мёртвого времени (DEADTIME). Глубине модуляции
IQ30(-1.0) будет соответствовать значение регистра CMPRx=0,
максимальной глубине модуляции IQ30(1.0)-1 (0x3FFFFFF) будет
соответствовать значение регистра CMPRx=3749. Полярность
выходных импульсов задаётся в соответствующих регистрах.
Формально нам необходимо сделать преобразование:
_IQ30(1.0) -> 3750, соответствует M=1
_IQ30(-1.0) -> 0, соответствует M=-1
Запишем это математически в общем виде в виде системы
уравнений:
k 1.0  b  TxPR,
k    1.0   b  0
TxPR TxPR
решая эту простую систему получаем: k
2
,b 
2
. Выражение
для глубины модуляции на выходе ШИМ запишется следующим
TxPR TxPR
образом: CMPRx  k  M  b 
2
M 
2
. Теперь осталось записать это в
соответствующем формате:
 TxPR   TxPR 
CMPRxIQ15     M IQ15   
 2  IQ15  2  IQ15
Почему выбран формат IQ15? Потому, что регистры CMPRx и
TxPR имеют разрядность 16 бит – во первых, а во вторых, число M
– со знаком, а регистры CMPRx и TxPR – работают с беззнаковыми
числами, и поэтому чтобы не возникало проблем с работой с
числами со знаком и для более понятного кода мы пожертвовали
последним битом, и приняли значение этих регистров как
значения со знаком, то есть в формате IQ15. Спешу успокоить:
выход на отрицательные числа (появление бита в старшем разряде
ведёт к плачевным результатам в виде прыжка периода и
непредсказуемой глубине модуляции) не предвидится из-за
арифметики. Формулу удобнее переписать следующим образом:
CMPRx IQ15 
1
TxPRIQ15  M IQ15  TxPRIQ15 
2
Формула имеет на 1 умножение меньше (2 шт), чем формула (3
шт) (деление на 2 – это умножение на ½, или сдвиг вправо на 1
разряд, причём не забываем учитывать знак при сдвиге).
Следующий шаг: выбор операций процессора для реализации .

Синтез алгоритма осциллографа.


Осциллограф состоит из следующих управляющих флагов и
переменных:
Управляющие флаги:
- флаг включения синхронизации,
- флаг полярности синхронизации.
Управляющие переменные целого типа:
- номер канала
- величина прореживания
Управляющие переменные вещественного типа:
- уровень синхронизации

Работу осциллографа удобно представить в виде диаграммы


состояний. Программа имеет фоновую часть, и части,
оформленные в виде прерываний от модуля SCI, а также
прерывания от таймера ШИМ. Прерывание от таймера является
основным для проведения измерений. Прерывания от SCI
отвечают за приём/передачу информации. Главными данными
для модуля осциллографа является массив снятых значений.
Работу осциллографа удобно представить в виде формального
языка описания диаграмм состояний:

Создание аппаратного проекта.

Создание проекта можно разделить на следующие шаги.

1. Выяснение, чего хотим добиться от процессора.


2. Составление небольшого плана примерно такого содержания:
какие модули на кристалле нам понадобятся для работы,
какие программные модули, иметь представление о внешней
обвязке процессора.
3. Добываем необходимый материал: Программные библиотеки,
если необходимо поэкспериментировать – то добываем
процессор и его внешнюю обвязку. Если новичок – то
покупаем отладочник и пишем “Hello World” на его
светодиоде.
4. Изучаем английский, так как придется иметь дело с морем
англоязычной документацией.
Разделим наш проект на 2 относительно независимые части:
программная реализация и аппаратная. Можно отдельно написать
программу, создать “out”-файл (наподобие “exe”) и выполнить его
на процессоре не важно как – будь то отладочный модуль от
EzDSP (www.spectrumdigital.com), или самодельная плата с
программированием как через JTAG так и через RS-232 (см. схему
на рис .)

Рис. Схема простейшего интерфейса преобразующего обычные


цифровые сигналы 3.3В или 5В в сигналы RS-232, как впрочем, и
наоборот.

На схеме рис. имеются следующие сигналы: GND – общий (земля,


минус), +5V – питание, SCITXDA – сигнал, идущий от процессора,
SCIRXDA – сигнал, идущий к процессору. Имена сигналов,
изображённых на этой схеме совпадают с именами
соответствующих выводов процессора: SCITXDA (155) и SCIRXDA
(157). Конденсатор C5 располагается рядом с корпусом
микросхемы DD1 и паяется к стандартным выводам земли и
питания: 8 вывод – это GND, 16 вывод – это VCC, иначе говоря,
питание +5V. Расшифровка имён сигналов и не сигналов проста:
SCI – serial communication interface (интерфейс последовательной
передачи данных), TX – transmitter (передатчик), RX – receiver
(приёмник), буква A – означает, что этот интерфейс с именем A
(SCIA), так как на кристалле имеется ещё один интерфейс с
именем B (SCIB). Следует отметить, что только с периферийным
модулем A работает BootLoader – программа загрузки из внешней
периферии.

ЧАВО: что происходит с процессором при запуске?


Сразу после прохождения сигнала RESETа, формируемого
супервизором, начинает выполняться BootLoader. Он анализирует
выводы, которые даны в следующей таблице

GPIOF4 GPIOF12 GPIOF3 GPIOF2 Обозначения вывода GPIO


(SCITXDA) (MDXA) (SPISTEA) (SPICLK) Имя периферийного устройства
155 22 35 34 Номер вывода
PU No PU No PU No PU Имеется ли резистор?
V '1' 'x' 'x' 'x' Выполнить из Flash по адресу 0x3F 7FF6
'0' '1' 'x' 'x' Грузить по SPI из внешней EEPROM
V '0' '0' '1' '1' Грузить из SCI, модуль A
'0' '0' '1' '0' Перейти в H0 SARAM по адресу 0x3F 8000
'0' '0' '0' '1' Перейти в OTP по адресу 0x3D 7800
'0' '0' '0' '0' Грузиться из GPIO Port B

и в зависимости от их состояния передаёт управление, как


написано справа от таблицы. «PU» – означает, что имеется
внутренний резистор, подвешанный к +3.3В (Pull-up), «No PU» –
что этого резистора нет, что вовсе не означает, что имеется
резистор, подвешивающий вывод к земле (Pull-down). Поэтому для
более надёжной работы, рекомендуется эти выводы соединять с
землёй/питанием через внешние резисторы в 10 кОм.

Работа с процессором TMS320F2812.


Краткие сведения о процессоре:
176 Выводов, корпус PGF LQFP.

Необходимую информацию по общему описанию


процессора можно найти в файле tms320f2812.pdf (см. ссылку).
Для более детальной справки, например, по периферийным
устройствам на кристалле, необходимо обращаться к отдельной
документации. Вся эта документация находится на сайте TI в
этом месте:
http://focus.ti.com/docs/prod/folders/print/tms320f2812.html.
Также там имеются библиотечные модули (в виде архивов),
которые также необходимы для работы (раздел Related Software).
Для наверняка полноценной работы с этим процессором
необходимо:

1. Купить процессор.

2. Купить внешние элементы «обвязки» процессора. Для


получения более подробной информации - смотреть схемы
от EzDSP. Обвязкой служат:

 2 Танталовых конденсатора по 10 мкФ для выводов ADCREFP


(11) и ADCREFM (10). При ручном монтаже будьте внимательны:
полоской на корпусе танталового конденсатора помечен его
плюс (+), в отличие от обычных алюминиевых оксидных
конденсаторов (электролитов), где полоской обозначается его
минус (-).
 Несколько (например, штук 20) фильтрующих конденсаторов.
Их количество (судя по документации) должно быть равно
количеству выводов питания (15 штук). Номинал: от 1нФ до
100нФ (или от 0.001мкФ до 0.1мкФ). Желательно, на каждую
шину питания, их поставить в последовательности от меньшего,
расположенного непосредственно «на выводе», к большему,
расположенного на шине питания, но также недалеко от
вывода.
 Резистор на 24.9 кОм ± 5% для вывода ADCRESEXT (16).
 Источник питания. Автор использовал 2 источника: TPS77533
для создания напряжения +3.3В, а также TPS77518 для
создания напряжения +1.8В. Питается оба этих источника от
+5В. Следует отметить следующее: для работы на 150 МГц
требуется источник напряжением 1.9В. При 1.8В тактовая
частота должна быть снижена до 135 МГц. Также существует
источник, который выдаёт оба этих напряжения, например,
TPS767D301, используемый в EzDSP. Но так как он
подстраиваемый, то для него должна быть внешняя обвязка в
виде прецизионного резистивного делителя. Также его нижняя
рабочая температура от –40 °С, в отличие от выбранных, где
она равна -55 °С. Отметим, что эти источники имеют внизу
корпуса микросхемы так называемый thermal pad – выведенная
наружу корпуса металлическая подложка. Её необходимо
припаивать к печатной плате, при этом под этот thermal pad
на плате делается медная лужёная площадка, как для обычного
вывода, и эта площадка имеет достаточную площадь для
охлаждения. Так как обычным паяльником это сделать
невозможно (прогреть микросхему с обратной стороны, которая
прижата к плате) эта технология реализуется в заводских
условиях в печке, либо инфракрасной пайкой. Поэтому
необходимо самостоятельно соорудить источник питания на 3.3
и 1.8В. Можно также обратиться к документу slva204.pdf, где
описаны некоторые решения по вопросу источников питания
для данного процессора. В любом случае, последовательность
включения/выключения должна быть обеспечена в правильном
порядке.

Обвязка источников питания и последовательность включеия.


Сигнал +1.8 В должен подаваться с задержкой минимум 10
мс по отношению к +3.3 В. Поэтому к выводу ~EN источника
питания +1.8 В подключается полевой транзистор, затвор
которого через делитель подключен к +3.3 В. Этот делитель
должен обеспечить: Как только сигнал +3.3 В пересечёт уровень
2.5 В, транзистор закрывается и на вывод ~EN подаётся лог. 0,
и происходит выдача напряжения питания +1.8 В. Более
подробно процесс подачи напряжений питания описан в
разделе «Power Sequencing Requirements» документа
tms320f2812.pdf. Продумайте этот пункт. Фильтрующие
ёмкости – как и в схемах от EzDSP. Будьте внимательны с
нумерацией выводов, так как легко запутаться и подать не то и
не туда.

3. Развести печатную плату либо купить специальную плату, на


которой уже есть посадочное место для процессора.
При разводке или макетировании на платке необходимо
тщательно подойти к разводке цепей земли и питания. Сделать
надо так, чтобы путь тока через цепь питание – фильтрующий
конденсатор – земля был минимальный.

4. Цепи земли и питания.


Прежде, чем впаивать процессор убедитесь мультиметром,
осциллографом, что питание подано правильно на
соответствующие выводы:
Питание ядра (1.8 В или 1.9 В):
Обозначение: VDD.
23, 37,
56, 75,
100, 112, 128,
143, 154.
Питание периферии (3.3 В):
Обозначение: VDDIO.
31,
64, 81,
114,
145.
Питание флэш-памяти (3.3 В):
Обозначение: VDD3VFL.
69.
Выводы питания АЦП (1.8 В или 1.9 В):
Обозначение: VDD1.
162.
Выводы питания АЦП (3.3 В):
Обозначение: AVDDREFBG.
13.
Обозначение: VDDA1, VDDA2.
14, 166.
Обозначение: VDDAIO.
1.

Задержку по питанию необходимо проверять уже при впаянном


процессоре – то есть под нагрузкой. Внимание! Выводы питания
АЦП должны быть запитаны «аналоговым питанием»! То есть через
индуктивный или иной другой фильтр, как показано в схемах от
EzDSP.

Земляные цепи. Разделите цифровую землю и аналоговую землю


на печатной плате, если она достаточно большая. Разделить – не
значить не соединить земли.

Так как сложность платы достаточно большая, желательно


перед впаиванием процессора омметром проверить, все ли земли
соединены с минусом источника питания:
Выводы земли для ядра и периферии:

Обозначение: VSS.
19, 32, 38,
52, 58, 70, 78, 86,
99, 105, 113, 120, 129,
142, 153.
Выводы земли АЦП:
Обозначение: AVSSREFBG.
12.
Обозначение: VSSA1, VSSA2, VSS1
15, 165, 163.
Обозначение: VSSAIO.
176.
Обозначение: ADCLO.
175.
Токи потребления процессора.
IDD IDDIO IDD3VFL IDDA
(ядро) (периферия) (питание (АЦП)
цифр. цифр. Flash) аналогов.
Типич. Макс. Типич. Макс. Типич. Макс. Типич. Макс.
195мA 230мA 15мA 30мA 40мA 45мA 40мA 50мA
См. далее.
Получаем суммарный макс. ток по напряжению 3.3В: 125 мА.
Pист=0.22 Вт.
По напряжению 1.8В: 280 мА. Pист = 0.9 Вт.

5. Хитрые выводы.
Вывод XF_~XPLLDIS (140). Сигнал с этого вывода блокирует ФАПЧ.
Его состояние считывается во время RESETа, то есть когда на
вывод ~XRS подана такая вот штука:
’X’ -> ‘0’ -> ‘1’ (X – не важно, что было. -> - знак последовательного
перехода). Если выводе XF_~XPLLDIS во время RESETа логический
‘0’, то что бы ни писали в значение периферийного регистра
PLLCR – тактовая частота ядра будет равна частоте, приходящей с
внешнего источника: либо резонатора, либо генератора. Регистр
PLLCR содержит значение коэффициента умножения системы
ФАПЧ, и, записывая туда соответствующее значение, можно
изменять тактовую частоту ядра. Чтобы система ФАПЧ
заработала, необходимо вывод XF_~XPLLDIS присоединить к +3.3
В через pull-up резистор сопротивлением 10 кОм. После того, как
RESET прошёл, этот вывод можно использовать по своему
усмотрению, например, в качестве GPIO14 – периферийного
вывода общего назначения. Подробности – в файле spru078*.pdf.

Вывод XMP/~MC (17). Сигнал на этом выводе определяет, в каком


режиме будет работать кристалл: микропроцессорном (‘1’) или
микрокомпьютерном (‘0’). Микропроцессорный режим – это режим
с использованием внешней памяти, соответствующим образом
подсоединённой к выводам внешнего интерфейса. Этот сигнал
считывается также сигналом RESETа. После RESETа сигналы на
этом выводе игнорируются. Микрокомпьютерный режим – это
когда внешняя память не используется, а используется
внутренняя память на кристалле. В обычном применении его надо
присоединить к земле. Полезно прочитать также о регистре
XINTCNF2.

Вывод TESTSEL (134) ОБЯЗАН быть на земле, несмотря на


встроенный pull-down. Если этого не сделать, то любая помеха
вызовет сбои в программе и процессор будет «глючить».
Прикосновение пинцетом к плате, или подключение осциллографа
к земле, или статические разряды от снимающейся юбки
помощницы начальника, могут вызвать сбой программы.

6. Внешний кварцевый генератор либо резонатор. Сразу


подводный камень: вход внешнего генератора должен быть
запитан с амплитудой не более 1.8В, то есть не более
напряжения питания ядра. Таким образом, если кварцевый
генератор на выходе даёт более 1.8В, необходимо применять
либо резистивный делитель, либо резистор с диодом, как
показано на схеме ниже.