Зачем язык Verilog программисту микроконтроллеров

    image

    Несколько раз начинал писать эту статью и бросал. Бросал потому, что тема, как мне кажется, несколько спорная. Изобретенный мною велосипед может кому-то показаться смешным и нелепым и вообще не совсем корректным. Тем не менее…

    Вообще, мне кажется, что в области разработки электронных устройств существует как бы несколько мало пересекающихся миров. Например, существует разработка устройств на базе микроконтроллеров и параллельно существует разработка устройств на базе ПЛИС. Принципы работы этим микросхем принципиально отличаются и точно так же отличаются принципы и методы разработки, используемые языки программирования и отладки. Конечно, выбор элементной базы сильно зависит от поставленной задачи. Однако и так понятно, что эти миры, мир микроконтроллеров и мир ПЛИСов почти не пересекаются. Может быть на стыке технологий что-то есть?

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

    Дело в том, что несмотря на заключенный договор о разработке устройства и несмотря на наличие более-менее согласованного ТЗ на устройство так получилось, что каждую неделю заказчик приходил с новыми идеями, требованиями, мыслями и пожеланиями. Можно было бы конечно, послать их куда подальше, но мы решили, что постараемся быть терпеливыми и все же будем выполнять проект.

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

    Вот такой пример. В режиме ожидания, когда контроллер просто ждет нажатия кнопки «Пуск», наш контроллер должен раз в сутки включать насос, прокачивающий жидкость, на 10 секунд. Это типа защита от закисания сальников насоса. Когда я спрашиваю; «вы как будете эту функцию проверять» – отвечают, что «никак». Лично я в шоке. Мы, конечно, стараемся писать программы «без ошибок», но думаю принимающая сторона то же как-то должна делить ответственность, проводить свои испытания и т.д…

    Далее перейду собственно к технической стороне дела.

    Мы решили, что нам нужны свои какие-то тесты программного обеспечения микроконтроллера.

    Обычно в мире ПО есть такое понятие юнит-тестирование. И в принципе, эта методика в какой-то мере подходит и для программ микроконтроллера. В настоящее время программы для микроконтроллеров зачастую пишутся на обычном языке Си, так что с юнит тестами, в общем, проблем быть не должно. Хотя… не все можно легко проверить юнит тестами в микроконтроллере.

    Все что связано с программированием внутренних аппаратных устройств вроде таймеров, каналов DMA, последовательных портов, прерываний и так далее – с этим есть проблемы. Тут для отладки в пору брать осциллограф и смотреть какие сигналы микроконтроллера получаются на входах-выходах. И вообще померить сколько по времени идет обработка прерывания – дело не лишнее. И это правильно.

    Есть еще один нюанс с юнит тестами. Как мне кажется, обычное юнит-тестирование ПО ориентированно на данные. Ну то есть обычно программа юнит-тест подает разные предполагаемые данные на вход проверяемой функции и далее проверяет, что обработанные выходные данные соответствуют требованиям. Все.

    Для электронного устройства, которое выступает как обработчик входных сигналов принципиально важно понятие «течение времени». Ну то есть требования обычно такие: при возникновении нештатной ситуации и срабатывании аварийного датчика A последовательно с интервалом в N1 секунд выключить исполнительные устройства B, C, а устройство D выключить не позже N2 секунд но не раньше N3 секунд, Что-то вроде этого.

    Понятно, что для проверки алгоритма управления программными средствами хорошо бы использовать какой-то симулятор сигналов с учетом течения времени. И такие средства есть в арсенале… у разработчиков систем на ПЛИС.

    Разработчик электронных устройств на базе ПЛИС как правило использует язык описания аппаратуры Verilog или VHDL. При этом, кроме кода для ПЛИС пишутся так называемые testbench – это и есть что-то вроде unit-test для обычного программиста на Си.

    Я использую Verilog HDL.
    Программу тестбенч пишет сам программист и при этом старается симулировать все возможные входные воздействия на микросхему ПЛИС. Выходные сигналы анализируются самим тестбенчем и проверяются в соответствии с ожидаемыми.
    При этом, сам симулятор Verilog следит за течением времени в системе.

    Рассмотрим простой и совершенно абстрактный пример, что делает программист ПЛИС.
    Например, вот модуль, который описывает простой двоичный счетчик с асинхронным сбросом (sample.v):

    module sample(
    	input wire reset,
    	input wire clk,
    	output reg [3:0]cnt
    );
    
    always @(posedge clk or posedge reset)
      if(reset)
    	cnt <= 0;
      else
    	cnt <= cnt + 1;
    
    endmodule
    


    Думаю такой код поймет любой программист, даже и не знающий языка Verilog HDL. Есть два входных сигнала reset и clk. И есть выходной четырехбитный сигнал [3:0]cnt. Всегда по фронту тактового сигнала значение в счетчике увеличивается. И всегда при появлении единицы на reset счетчик обнуляется.

    Этот модуль синтезируемый, то есть его планируется откомпилировать и зашить в ПЛИС.

    Теперь, например, программист хочет проверить работоспособность своего модуля. Он пишет программу на Verilog, тестбенч, который будет имитировать входные сигналы для микросхемы (testbench.v):

    `timescale 1ms / 1 ms
    
    module testbench();
    
    reg tb_rst, tb_clk;
    wire [3:0]value;
    
    always
    	#5 tb_clk = ~tb_clk;
    
    initial
    begin
    	$dumpfile("waves.vcd");
    	$dumpvars(0,testbench);
    
    	$display("starting testbench!!!!");
    	tb_rst = 1;
    	tb_clk = 0;
    	#10;
    	tb_rst = 0;
    	
    	#73;
    	tb_rst = 1;
    	#11;
    	tb_rst = 0;
    
    	#134;
    	tb_rst = 1;
    	#57;
    	tb_rst = 0;
    	#200;
    	$display("finished OK!");
    	$finish;
    end
    
    sample my_sample_inst(
    	.reset(tb_rst),
    	.clk(tb_clk),
    	.cnt( value )
    );
    
    wire fail;
    assign fail = (tb_rst & value!=0 );
    
    endmodule
    


    Этот модуль не синтезируемый, его нельзя откомпилировать и зашить в ПЛИС, но он нужен для симуляции проекта. Обратите внимание на строки

    sample my_sample_inst(
    	.reset(tb_rst),
    	.clk(tb_clk),
    	.cnt( value )
    );
    


    Это в тестбенч вставлен исследуемый экземпляр модуля sample. Получается вот так:

    image

    Очень возможно, что у нас есть критерий работоспособности проекта. Нам нужно, чтобы во время сигнала reset выходные сигналы счетчика были всегда в нуле. То есть мы можем в тестбенче определить сигнал ошибки:

    wire fail;
    assign fail = (tb_rst & value!=0 );
    


    Этот сигнал можно программно мониторить или просто посмотреть глазами на выходных временных диаграммах.

    Я часто использую простой свободный симулятор VerilogHDL IcarusVerilog. Его просто установить и работать с ним. Компилирую и запускаю симулятор:

    image

    Мой тестбенч благодаря строкам программы $dumpfile(«waves.vcd»); и $dumpvars(0,testbench); создает файл с временными диаграммами waves.vcd. И эти временные диаграммы можно посмотреть с помощью другого замечательного свободного инструмента GtkWave:

    image

    Таким образом, самое простое, что может сделать программист ПЛИС – это написать к тестируемому модулю тестбенч и сгенерировать файлы получившихся временных диаграмм и рассматривать их, смотреть правильный ли отклик идет от ПЛИС.

    Теперь расскажу, как можно похожую технологию тестирования применить к микроконтроллерам.

    Если обратите внимание еще раз на Verilog тестбенч, то заметите там некоторые системные функции вроде $display(..).

    Так вот. Оказывается, для симулятора Verilog HDL можно самому дописывать нужные нам системные функции на языке Си. А раз появляется место для языка Си, то появляется место, где код Verilog тестбенча может взаимодействовать с Сишным кодом для микроконтроллера.

    Вообще, интерфейс симулятора Verilog к языку Си называется Verilog Procedural Interface (VPI). Рассказывать про него можно долго, это большая отдельная тема. Можно больше почитать, например, вот здесь.

    Я же хочу просто схематично проиллюстрировать, как это может быть использовано.
    Проект для микроконтроллера может состоять из многих файлов. Наша задача отделить собственно алгоритм управления от аппаратных особенностей конкретного микроконтроллера.

    Предположим, проект для микроконтроллера состоит из файлов:

    Main.c
    Dma.c
    Serial.c
    Interrupts.c
    ….
    Algorithm.c
    


    Обработчики прерываний от входных линий микроконтроллера описаны в файле Interrupts.c. Они представляют из себя что-то вроде этого:

    void EXTI9_5_IRQHandler(void)
    {
      Int val;
      disableGlobalInterrupts();
      EXTI_ClearITPendingBit(EXTI_Line6);
      val = GPIO_ReadInputDataBit(MY_PORT, MY_SIGNAL);
           Algo_set_value( val );
      enableGlobalInterrupts();
    }
    


    Когда сигнал на входной линии микроконтроллера меняется, то происходит прерывание, в нем производится чтение значения на линии и это значение передается функцией Algo_set_val() алгоритму обработки. Весь алгоритм управления описан в файле Algorithm.c.

    Файл Algorithm.c одновременно участвует в проекте для микроконтроллера и в проекте для VPI модуля Verilog.

    image

    Таким образом, разрабатывая «алгоритм управления» мы в основном компилируем VPI модуль вместе с Algorithm.c для Verilog симулятора. Вызывая в тестбенче Verilog нами определенную новую системную функцию $int() мы имитируем возникновение прерывания микроконтроллера в некоторый момент времени. Точно так же, внутренние переменные алгоритма можно читать и передавать тестбенчу Verilog с помощью новой нами определенной системной функции $getpin(..). Получается, что наш Verilog тестбенч может имитировать входные воздействия и течение времени для алгоритма управления микроконтроллера.

    Примечательно, что мы получаем в свое распоряжение временные диаграммы входных воздействий и откликов. Их можно показать заказчику с целью ознакомления – для их просмотра используется программа GtkWave. Заказчик своими глазами сможет увидеть, как входные воздействия от различных датчиков будут откликаться его алгоритмом управления. Заказчик должен увидеть все возможные комбинации воздействий от входных сигналов и все отклики «черного ящика» под названием микроконтроллер.

    По крайней мере, на временных диаграммах можно увидеть, как виртуально включается насос на 10 секунд каждые сутки…

    Последний этап – перестаем компилировать VPI модуль для Verilog симулятора (фиолетовый блок) и начинаем компилировать проект микроконтроллера (оранжевый блок).

    Теперь функции алгоритма будут вызываться не из виртуальных воздействий симулятора Verilog, а из физических прерываний от входных линий и таймеров.

    На всякий случай еще раз замечу, что с помощью нашего Verilog тестбенча мы конечно не проверяем правильность программирования регистров периферийных устройств вроде DMA или таймеров или GPIO. Мы тестируем только «алгоритм управления». На мой взгляд и это очень и очень важно.

    Ну вот как-то так.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 16

      0
      Заголовок вызывает как минимум недоумение.
      Всё же программист МК работает на Си с библиотекой, предоставляемой через VPI и по-хорошему для него FPGA-side это BlackBox, с которым он взаимодействует через вызовы $get/&set и проч.
        +2
        Подход интересный для того, чтобы «показать заказчику». Простите, но не более того.
        К примеру, Вы не можете учесть того, что происходит в обработчиках прерываний и того, как, к примеру настроены таймеры. В свою очередь, это оказывает влияние на временные параметры. Для насоса, который включается раз в сутки, это не существенно. А вот на более коротких промежутках времени могут возникнуть проблемы.

        «как бы несколько мало пересекающихся миров». С этим Вы погорячились. Например, посмотрите в сторону SoC/softprocessors: Xilinx Microblaze тому подтверждение, да и практически у каждого вендора FPGA есть подобные решения. При таком подходе Вы можете разрабатывать high-level части на C/C++, а критичный low-level на VHDL/Verilog.
          0
          Хотел возразить про Xilinx Microblaze, но вы опередили)
          У меня сейчас проект например, я делаю всю обвязку прошивки с процессором на VHDL, а программист на C/C++ успешно программу для процессора отлаживает. Иногда друг к другу «лазить» приходится)
          +1
          Дело в том, что несмотря на заключенный договор о разработке устройства и несмотря на наличие более-менее согласованного ТЗ на устройство так получилось, что каждую неделю заказчик приходил с новыми идеями, требованиями, мыслями и пожеланиями.

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

          Иногда ко мне обращаются друзья с просьбой «помочь сделать сайт». Фактические сайт сделать надо. Заказчик не знает с какой стороны к нему подступаться и что хочет получить в конце. ТЗ худо-бедно согласованное. Разработка, дизайна. Куча правок. Верстка. Куча правок. Вообщем сайт как-то рождается. Ну и этот итерационный процесс воспринимается как-то нормально, несмотря на то что в конце получается всегда не так как в первоначальном ТЗ (то то не нравится, то другое, то третье, то озарение, то прояснение, то протрезвление т.д. и т.п. — короче, рабочий процесс).

          Но такой же подход к разработке электроники. Жесть! Я сам занимаюсь разработкой на ПЛИС. Это моя основная работа. Тружусь я в неочень частной конторе. С ТЗ у нас нормально в том плане, что оно мне спускается от спецов такого же уровня компетентности что и я или выше. И то, когда через пару месяцев выясняется что в ТЗ что-то подвинули, то начинаются небольшие перебранки. Да даже если в протоколе какие-то изменения — это надо переделывать интерфейсные модули в прошивке, на ответной части приемник корректировать, проверять, тесты менять. А если такое каждую неделю — да я б повесился!!! )))
          С другой стороны, такой подход имеет место быть — это техсогласование с целью написания ТЗ. Но у вас уже вроде ТЗ было какое-то… И вот так по нему людей напрягать, а потом оказывается не так, а потом не то… Это потом проще заново сделать, т.к. общий дизайн прошивки поломается и уже не будет так красив как изначально задумывалось, т.к. будет куча костылей. Да и модули отдельные переделывать постоянно тоже не лучшее решение, т.к. все равно когда-то что-то упустишь и будешь потом долго отлаживать)

          Кстати, с марсоходом дело имел, но было так себе — от нечего делать) Проект интересный, на его базе хотели даже кружок сделать, но незадалось, к сожалению.
            –1
            По моему мнению и опыту, который я имею — FPGA это либо для тех у кого не будет продукта(студенты, экспериментаторы), либо для тех кто делает реальный чип и отлаживается на FPGA(для ASIC), либо для тех кто ни те и ни те, и последних я боюсь больше всего, они обычно и используют МК + FPGA.
              +2
              Да, только если требуется специфичный контроллер, который должен выдерживать строгую времянку, и при этом серия производства конечной аппаратуры мала, то CPU + FPGA очень даже годное решение. Чаще всего можно обойтись только FPGA, используя тот же MicroBlaze внутри ПЛИС. Сейчас же производители FPGA предлагают более вкусный вариант, в котором совмещены CPU и FPGA (например, ZYNQ от Xilinx).
                +4
                Хех. Да как сказать. Весь космос и добрых 3/4 авиации сидят именно на ПЛИСах.
                А куда деваться, если вам нужно изготовить, например, с 10ок плат с кучей периферии и требованием делать быстрые вычисления, да еще и независимые по разным каналам? Большое количесвто I/O, возможность параллелльных операций без ущерба производительности, да еще и возможность переконфигурирования в случае доработок — ПЛИС самое то. Продукт же есть и вполне реален. ASIC просто не нужен, т.к. получится дорого и это экономически просто неоправдано. У американцев вон — марсоходы на Virtex4 по Марсу ездят и ничего )))
                Причем в некоторых проектах не обязательно же FPGA использовать, иногда достаточно CPLDшек понаставить.

                МК + FPGA — да, я теперь по своему опыту скажу гемора там немеряно. Пока отладишься порой много нового узнаешь))) Но иногда деваться некуда. Ибо лучше сделать часть периферии независимой (да и надежнее — вдруг из-за ошибки ПО это процесссор повиснет?), но скоростной. А в процессоре же своя программа крутится, которую гораздо проще менять (а порой и интуитивнее), чем на более низком уровне перекапывать модули на VHDL/Verilog…
                0
                  +2
                  Да, в нынешней ситуации с отладкой микроконтроллеров можно желать много лучшего. Но я лучше расскажу о своем опыте отладки программ на МК. Все начиналось еще в конце 90х, и инструментальные средства были не в пример нынешним.

                  Ну, во-первых, симулятор. Проблем у симуляторов две. Первая — их недоделанность. То есть симулируется МК не полностью, некоторая аппаратура не поддерживается. Вторая проблема — взаимодействие МК с внешним миром. Симулятор не симулирует внешних устройств, с которыми взаимодействует микроконтроллер, а эти устройства (например, другой МК) могут вести себя очень сложно, так что от симулятора в такой ситуации проку очень мало.

                  Что тут можно сделать? Отлаживать программу по частям. По маленьким частям. Проверяешь каждую функцию, исполняешь пошагово, контролируя все аспекты ее работы. При этом в прошивку добавляется много отладочных функций, веток и тестовых данных — фактически, симуляция взаимодействия с аппаратурой ведется средствами МК в той же прошивке. Используются доступные возможности симулятора по «подкидыванию» прошивке данных через внешние устройства и их съема и сохранения в файлы.

                  Если какое-то событие происходит редко — искусственно увеличиваешь частоту таких событий, чтобы было легче поймать событие и проверить правильность его отработки.

                  Когда достигнута безупречная работа в симуляторе — переходим к наладке в железе. Как правило, на этом этапе еще остаются ошибки. Чтобы облегчить себе жизнь, снова все упрощаем, используем генераторы простых данных, уменьшаем или увеличиваем скорость процессов. Процедуры, которые при штатной работе вызываются редко, вызываем в цикле, контролируя работу осциллографом.

                  На некотором этапе может потребоваться внутрисхемный отладчик. Я много лет обходился без него, и все получалось, но однажды пришлось налаживать алгоритм обработки сигнала (распознавание DTMF на аналоговом входе). На тестовых данных все работало, а на реальном сигнале — нет. Нужно было остановить программу в железе в процессе работы и посмотреть ее состояние. Это может только внутрисхемный отладчик. Но обращаться к отладчику рано, если перед этим не были использованы все возможности симулятора. Отладчик медленнее отзывается на команды пользователя, чем симулятор; иногда остановленную программу нельзя продолжить из-за того, что она «проспала» какой-то физический процесс.

                  И наконец, после испытаний и тщательного анализа всех, каких только можно, частей программы, можно постепенно выбрасывать из нее заглушки и настраивать все на штатные режимы. В процессе по возможности тоже все контролировать. Если вся разработка прошла в описанном выше режиме — то готовый продукт получается очень надежным.
                    +1
                    Хотел бы похвалить компилятор Icarus Verilog. Как-то нужно было промоделировать небольшой проект с применением VPI, а ставить тяжеловесные коммерческие решения не хотелось, и Икарус показал себя с очень хорошей стороны: простота, удобство, какая-никакая документация. Не имея в тот момент практически никакого опыта с Verilog и VPI, за вечер разобрался. Пример хорошего open-source решения.
                      0
                      Попытка использовать любимый инструмент в непрофильной для него сфере удалась) Все, я думаю, понимают, что для отладки МК недостаточно картины «Вход/Выход».
                        0
                        Несмотря на велосипедность, статья понравилась. Единственный совет в вашем случае, который уже давали выше — это использовать либо ПЛИСы с хардовыми процами либо брать RTL процов (благо RTL того же Microblaze кажется опубликован под свободной лицензией ) и зашивать в ПЛИС. В этом случае вы сможите не только алгоритм работы проца просимулировать но и сам проц непосредственно. Удачи.
                          0
                          Что-то я не понял — какая часть из вот этого:

                          Main.c
                          Dma.c
                          Serial.c
                          Interrupts.c
                          ….
                          Algorithm.c

                          в итоге будет протестирована при помощи тестбенча на Verilog?
                            0
                            только Algorithm.c
                              0
                              То есть отделяем алгоритм от аппаратной части (уже плюс!) и при помощи Verilog создаем жестко привязанный ко времени сценарий тестирования — так?
                                0
                                в общем, да, это то, что я хотел сказать своей возможно сумбурной статьей.

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                          Самое читаемое