ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Четверг
4 июля
122270
Evgeny_CD, Архитектор (08.06.2008 19:56, просмотров: 15806)
Обобщенные драйвера: продолжение моих идей. Есть контроллер (UART, USB, Ethernet, ...). Можно работать с его регистрами напрямую "в лоб", но структурированность и переносимость такого кода нулевые. Можно написать драйвера, которые виртуализируют этот контроллер. И вместо обращения к регистрам происходит использование макросов и функций таких драйверов. Это хорошо, ибо можно написать симулятор контроллера, и отлаживать целевую программу на нем. Более того, симулятор может принимать команды для контроллера, передвать их по каналу связи на железяку с контроллером, и выполнять их там. Обратно можно передавать ответы реального контрололера. Это небыстро, но, зачастую, на начальном этапе освоения контроллера роль ошибок в документации и ошибок воприятия документаци куда важнее скорости. Лично я ненавижу такую процедуру: записал дрова, откомпилил, прошил, запустил, проверил - не алё. Написал чуть по другому, собрал, снова залили и т.д. Но накладных расходов никто не отменял! Если место проверки бита готовности в регистре я буду вызывать некую функцию, то где-то это может стать просто фатально. Мощность современых контроллеров растет, но все же не хочется закладывать принципиально избыточные решения. Можно пойти по пути макросов, но это сложно и не сильно универсально (макрос раскрывается либо в вызов симулятора, либо в набор операций с регистрами контроллера). Есть более изящный способ!!!! Берем кодогенератор типа Templarian http://sourceforge …et/projects/templarian В нем прописываем все "методы" объекта контроллера. Для разных вариантов - симулятор, "телепортация", "родное" исполнение кода. В нужных местах проекта вставляем "выход" такого кодогенератора - и вуаля! Автоматическая модификация текста под целевую платформу готова! Преимущества над макросами уже описал. Преимущества над #ifdef очевидны. Если я ничего не путаю, в методиках использования С++ это называется "отделение интерфейса от реализации". Снова я кусок С++ "изобрел" :) Продолжаем тему совершенствования работы с контроллерами. Самое тупое, что бывает при освоении нового контроллера - это чтение линейной PDF документации на него. Т.е. ты вначале парсиш моском 10м файл, затем, осознав, из чего же состоит твой контроллер, уже немного начинаешь ориентироваться в нем. Что касается самго процесса написания документации, то я так и вижу уходяшие к горизонту вереницы tecnical wrighters (надо полагать, прикованных за ногу к батарее), которые правят бесчисленные таблицы в документации какой-нибудь ATxmega. Хоть одна ошибка - и плеть надсмотрщика... Мы пойдем другим путем. Берем XML и строим иерархическую структуру типа: * контроллер * интерфейс контроллера * регистр * битовое поле * зачения этого поля Естественно, к каждой сущности приписано ее описание нормальным языком. (я не считаю XML правильным или неправильным, я привел его как пример иерархической организации данных. Реализация идеи может быть сделана любым другим способом.) Из этой структуры автоматически генерим "картинки с текстом" в виде графа сущностей контроллера. Так будет просто на порядки нагляднее линейнго описания. Теперь берем программистский редактор, который воспринимает наше описание как... DTD! Выглядит этот так: * жмем батон - хочу работать с периферией * далее выбираем : контроллер -> интерфейс -> регистр -> битовое поле -> значение На каждом шаге мне автоматически подсовывается список того, из чего я могу выбрать в данный момент. И все это оформляется как "вызов" кодогенератора! Букафф в исходнике будет гораздо больше, но скорость восприятия несопоставимо выше. Мне не надо держать в голове всю информацию о регистрах. Мне нужно примерно помнить, как устроен контроллер, а далее "говорящие названия" все мне скажут. Можно, конечно, наплодить аццких хидеров, которые отчасти будут использовать ту же идеологию, но: * аццкий хилер повышает время сборки проекта * аццкий хилер не гарантирует, что моя IDE всосет его аццкую структуру и так удобно, как я описал, мне все подскажет * переносимость всего этого аццкого хозяйства между компилерами неочевидна (битовые поля компилеры поддерживают, мягко говоря, по разному). В реальности регистры устройства состоят из многих полей, и, прежде чем проициализировать регистр я должен "синтезировать" все слово, записываемое в регистр. Т.е. в тексте у меня это будет выглядеть как-то так Обращение к кодогенератору (Ethernet.Control.Satate_Of_Chip_WR, PKT_LEN =1560, SPEED=100, FLOW_CONTROL=ON) что раскроется в выражение типа *((volatile unsigned int*)0xFFFF0000)=((0x618<<24)|(1<<2)|1)); Получается все сбалансированно - описание для кодогенератора совместимо с моском любого программера (и оно совершенно понятно без тщательного чтения доки на чип), а plain С строка совместима с любым С компилятором. Ну и в качестве вершины такого подхода можно предложить обобщенные методы. Например, у нас есть Ethernet_Init, которому в качестве параметров передается длина пакета, скорость, ну и много чего. А этот метод раскрывается в целый кусок кода: * сборка значений в регистры * запись в нужной поледовательности * проверка готовности * пр. Тогда этот самый Ethernet контроллер для внешнего мира выглядит как компактный набор методов, которые в реальности суть очень эффективный С код. Комбинация двух описанных выше подходов возволяет полностью исключить ручную низкоуровневую модификацию исходников при переходе от навороченного синтетического порта к, например, ATmega48, которая еще очень долго будет "натягивать" по потреблению все эти супернавороченные ARM'ы при работе от кварца 32768.