В процессе серийного производства электронных устройств следующим этапом после монтажа печатных плат является стенд серийной прошивки и тестирования. На нем производится прошивка микроконтроллера/микропроцессора, запуск платы и ее проверка в том или ином объеме. Естественно, как и монтаж плат, работа стенда также должна быть мах автоматизирована. В крайнем случае, ручные операции, от которых не удалось избавиться, должны быть предельно просты, интуитивно понятны и монотонны. В статье описывается процесс разработки подобного стенда под микропроцессор IMX6ULL.

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

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

Среди прочих требований к плате нужно продумать решение трех вопросов:

  1. где будет храниться образ ядра Linux (прошивка, image): SPI флеш, NAND флеш, microSD карта или еще что-либо;

  2. как эта прошивка будет поставляться в серийно выпускаемые изделия;

  3. как будет задаваться загрузочный интерфейс процессора;

Варианты ответов на каждый вопрос:

  1. Проще всего использовать microSD карту. В этом случае вам нужно лишь подготовить N-ное количество microSD карт с образом ядра вставить их во все изготовленные устройства. Но такой способ может не подойти, если:

  • необходимо разработать устройство в индустриальном исполнении (рабочие температуры от -40 С);

  • вы хотите осложнить доступ к прошивке устройства;

  • устройство может подвергаться вибрациям;

  • у вас есть строгие ограничения по себестоимости конечного изделия и каждый цент на счету (microSD карта + разъем заведомо дороже, чем микросхема флеш-памяти распаянная на плате);

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

Если microSD-карта не подходит, - остается выбор между NOR и NAND памятью. В целом, при выборе типа памяти нужно отталкиваться от размера финальной прошивки. Если до 32 Мб, - то лучше выбрать микросхему памяти NOR (цена - меньше, ресурс - выше), если больше 32 Мб - то остается NAND.

  1. Если выбор пал на микросхему памяти, распаянную на плате, то есть два варианта:

  • образ ядра прошивается в микросхему до распайки на плате. В этом случае микросхемы по-очередно извлекаются из катушки, устанавливаются в программатор (наподобие такого), затем упаковываются обратно в катушку. Очень трудоемкий и не технологичный процесс.

  • образ ядра прошивается в микросхему после распайки на плате с помощью микропроцессора. Процессор нужно каким-либо образом запустить (при этом загрузочная микросхема флеш памяти пуста!), доставить ему образ прошивки, которую процессор и загрузит в м/сх памяти. Звучит как нечто, что очень сложное в реализации, зато это снижает количество ручных операций в процессе производства. Забегая вперед скажу, что мы выбрали именно этот вариант и нам удалось его автоматизировать.

  1. При работе с отладочными платами вы почти наверняка встречали нечто подобное:

переключатель, задающий загрузочный режим. Дело в том, что процессоры, как правило, поддерживают несколько различных вариантов загрузки, таких как SPI, QSPI, SDHC, UART и пр. Какой-именно вариант загрузки использовать определяется фьюз-битами. Процессор может вычитать фьюз-биты из регистров, либо определив состояние определенных GPIO. Какой именно способ процессору использовать, в свою очередь, задается состоянием двух других ножек (BOOT_MODE0 и BOOT_MODE1).

Также можно встретить вариант одного-единственного варианта загрузки, заданного резисторами:

Если габариты позволяют и не жалко несколько ножек процессора, то лучше выбрать один из этих вариантов (переключатель или резисторы).

В случае же, если вы ограничены в габаритах (наш случай) или нужно высвободить ножки процессора под другие задачи, то остается только третий вариант, - "прожигать" фьюз-биты.

Итак, в нашем случае, ответы на три озвученных ранее вопроса были такими:

  1. Образ хранится в микросхеме памяти. SPI NOR флешка.

  2. Флешка прошивается уже будучи распаянной на плате.

  3. "Прожиг" фьюз битов.

Стенд

Решением задачи при такой постановке вопроса стал разработанный стенд серийной прошивки и первоначального тестирования.

Устройство, под которое был разработан стенд:

SoM-модуль, на борту стандартный для SoM-модулей набор: Процессор, память RAM, память flash, физика ethernet, физика wi-fi. По всем четырем граням расположены контактные площадки в форме полу-отверстий с шагом 1.5мм.

А вот и собственно сам стенд:

С аппаратной точки зрения, все довольно тривиально: по центру набор пружинных контактов под тестируемый SoM, который прижимается сверху вертикальным зажимом. Из подведенной к модулю периферии: UART, JTAG, Ethernet. Ну и питание.

Алгоритм работы стенда

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

  1. Тестируемое устройство устанавливается в стенд

  2. подключается usb-uart переходник, программатор JLink, Ethernet-кабель, подается питание.

  3. Запускается openocd сервер (openocd.exe);

  4. Производится подключение к openocd серверу по telnet (openocd клиент);

  5. Открывается COM-порт, назначенный USB-UART переходнику;

  6. Сброс процессора (через консоль openocd-клиента):

reset init; arm core_state arm; halt;
  1. Грузим образ u-boot (через консоль openocd-клиента):

load_image u-boot.imx 0x877ff400
  1. Грузим образ ядра linux (через консоль openocd-клиента):

load_image openwrt-imx6ull-cortexa7-video-squashfs.mtd-factory.bin 0x82000000
  1. Запускаем работу процессора (через консоль openocd-клиента):

resume 0x87800000

В это время должен стартануть u-boot и в консоли com-порта появятся логи загрузки. Нажимаем enter, чтобы остаться в консоли u-boot.

  1. Определите флешку (консоль COM-порта):

=> sf probe 
  1. И прошейте флешку (консоль COM-порта):

=> sf update 0x82000000 0x1000 0x8000
  1. Прожгите фьюз-биты (консоль COM-порта):

=> fuse prog -y 0 5 0x0a000030
=> fuse prog -y 0 6 0x00000010
  1. Ребутните процессор (консоль COM-порта):

=> reset

После этого процессор должен ребутнуться и загрузить ядро линукс с флешки без помощи программатора.

Автоматизируй это

Естественно, шаги с 3-его по 13-й можно автоматизировать. По-питонячьи это выглядит так:

# 1. Init OpenOCD server
device_state = Queue()
p_openocd = Process(target=run_openocd_server, args=(device_state,))
p_openocd.start()
check_state(device_state, STATE_JTAG_DEVICE_DETECTED)

# 2. Init. Connect to OpenOCD server via Telnet
telnet_socket_write_queue = Queue()
p_telnet = Process(target=run_telnet_client, args=(telnet_socket_write_queue,))
p_telnet.start()
check_state(device_state, STATE_TELNET_CLIENT_CONNECTED)

# 3. Init. Open COM port.
device_state_com = Queue()
com_port_write_queue = Queue()
p_com_port = Process(target=run_com_port_handler, args=(device_state_com,com_port_write_queue,CFG_COM_PORT,))
p_com_port.start()

# 4. Reset CPU
telnet_socket_write_queue.put((TELNET_CMD_RESTART_CPU + "\r\n").encode())
check_state(device_state, STATE_CPU_RESET_COMPLETED)

# 5. Load u-boot image
telnet_socket_write_queue.put((TELNET_CMD_LOAD_U_BOOT_IMAGE + "\r\n").encode())
check_state(device_state, STATE_IMAGE_LOADED, 30)

# 6. Load kernel image
telnet_socket_write_queue.put((TELNET_CMD_LOAD_KERNEL_IMAGE + "\r\n").encode())
check_state(device_state, STATE_IMAGE_LOADED, 600)

# 7. Start U-boot execution
telnet_socket_write_queue.put((TELNET_CMD_START_U_BOOT + "\r\n").encode())
check_state(device_state_com, STATE_U_BOOT_CONSOLE_ACCESSED)

# 8. Check flash IC available
com_port_write_queue.put(COM_CMD_CHECK_FLASH + "\r")
check_state(device_state_com, STATE_FLASH_IC_DETECTED)

# 9. Flash firmware to IC
com_port_write_queue.put(COM_CMD_WRITE_FIRMWARE_TO_FLASH + "\r")
check_state(device_state_com, STATE_FIRMWARE_FLASHED_TO_IC, 300)

# 10. Burn fuse bit (ECSPI3 programming 0x450 = 0x0a000030)
com_port_write_queue.put(COM_CMD_BURN_FUSE_BITS_1 + "\r")
check_state(device_state_com, STATE_FUSE_BITS_BURNED)

# 11. Burn fuse bit (BT_FUSE_SEL programming 0x460 = 0x00000010)
com_port_write_queue.put(COM_CMD_BURN_FUSE_BITS_2 + "\r")
check_state(device_state_com, STATE_FUSE_BITS_BURNED)

# 12. Reset device
com_port_write_queue.put(COM_CMD_RESET_DEVICE + "\r")

Исходники можно найти тут. Скрипт может быть относительно легко адаптирован под другие семейства процессоров с архитектурой ARM (семейства IMX компании NXP, по крайней мере).

TO-DO

В планах - замена шага №6 (загрузка factory образа по JTAG занимает очень много времени) на загрузку с TFTP-сервера с помощью u-boot утилиты tftp.

Комментарии (23)


  1. osmanpasha
    24.01.2022 17:39
    +2

    А по USB оно умеет загружаться? Мы с am335x от TI пробовали такой вариант: встроенный загрузчик грузит по USB специально собранный uboot, uboot грузится и создаёт поверх USB сетевой интерфейс и запускает TFTP-сервер, а потом ПК на этот сервер шлёт прошивку, которая записывается uboot-ом во флэш. Всё по одному интерфейсу. Правда, фьюзы мы не прожигали


    1. almaz1c Автор
      24.01.2022 17:44
      +1

      Перебирали разные варианты, в том числе, загрузку по usb в recovery режиме. Видимо, с jtag я дружу больше, чем с usb)


  1. VT100
    24.01.2022 21:22
    +1

    И не забыть предусмотреть направляющие или рамку для позиционирования SoM на стенде.


    1. almaz1c Автор
      24.01.2022 21:29

      От такого форм-фактора вообще решили отказаться. Переходим на разъемы. Из тех же самых соображений о технологичности.


  1. fk0
    25.01.2022 03:29

    Зачем мучения с пружинными контактами и сложной приспособой к ним, когда проще для программирования и отладки добавить один дешевый коннектор (1.27mm double row pin header) который может быть подключен вручную (это проще...) На который вывести:

    • сигналы для программирования (JTAG, SWD, etc...);

    • питание от внешнего источника;

    • контрольные точки (измерение напряжений вторичных источников питания размещённых на плате, частоты опорного генератора и т.п.);

    • последовательный порт, USB или сеть (настройка, вывод диагностической информации от процедуры самотестирования).

    Если речь о тестировании, то проще реализовать самотестирование путём прошивки отдельной программы или чем-то вроде, а не путём подключения к исключительно сложному внешнему стенду (причем еще разному для каждой новой версии или варианта изделия...) И для чего ещё на этапе разработки электронной схемы предусмотреть механизмы самотестирования.

    Причём это может быть даже не разъём, а контакты с краю печатной платы наподобии PCI-ex ламелей и включаться может в какой-либо подходящий ламельный разъём. Соответственно можно сделать "материнскую плату" для программирования и тестирования разом десятка дочерних плат.

    Или что-то вроде tag-connect, который может быть как в виде отверстий и контактов на плате (занимает площадь), так и в виде краевых контактов (плата сложней).

    Разумеется нужна минимальная защита от дурака, вроде того, что коннектор должен быть или симметричным, или не позволять неправильное включение. И контакты "земли" должны быть продублированы со всех возможных сторон, чтоб питание не осуществлялось через сигнальные цели и защитные диоды при включении "на горячую".

    Лучше конечно, чтоб после замыкания контакта и выдержки паузы в полсекунды просто автоматически включалось питание и запускалось программирование, чтоб на компе ничего нажимать не надо было.


    1. almaz1c Автор
      25.01.2022 11:31

      проще для программирования и отладки добавить один дешевый коннектор (1.27mm double row pin header)

      Предлагаете тестируемое устройство габаритами 42 х 43 х 3 мм превратить в устройство габаритами 42 х 49 х 7 мм ?

      Если речь о тестировании, то проще реализовать самотестирование путём прошивки отдельной программы или чем-то вроде, а не путём подключения к исключительно сложному внешнему стенду

      Каким образом прошивка протестирует работу аудио, видео, LoRaWAN, 2 езернета, 2 юсб и пр без стенда, к которому подключена вся эта периферия?

      а контакты с краю печатной платы наподобии PCI-ex ламелей

      http://suddendocs.samtec.com/catalog_english/pcie.pdf

      PCI Express разъем на 98 пинов (количество пинов в нашем SoM-модуле) имеет длину 56 мм. Предлагаете устройство габаритами 42 х 43 х 3 мм превратить в устройство габаритами 42 х 56 х 3 мм?

      Соответственно можно сделать "материнскую плату" для программирования и тестирования разом десятка дочерних плат

      десяток JTAG программаторов, десяток USB-UART адаптеров, два десятка USB-портов на ПК, десяток подключенных аудио-модулей, десяток подключенных видео-модулей, ....


  1. AlexVRud
    25.01.2022 12:42
    +1

    А вариант вывести MicroSD и пару boot битов на контакты SoM-а не рассматривали? Тогда на стенде, за счёт переподтяжки boot битов, можно было бы грузиться с MicroSD и прошивать без программатора. А через нескольких GPIO контролировать результат.


    1. almaz1c Автор
      25.01.2022 12:50

      Опять же все в габариты упирается. Размеры SoM-модуля 42 х 43 мм. Разместить на нем разъем для microSD карты не представляется возможным. Плюс, если посмотрите на SoM-модули таких известных производителей, как variscite, например, то SD-карту все-таки выносят на платы расширения.


      1. AlexVRud
        25.01.2022 13:39

        то SD-карту все-таки выносят на платы расширения.

        Так я об этом и говорю.


        1. almaz1c Автор
          25.01.2022 15:35

          Аа, понял)

          Даже не думали. JTAG нас в принципе устраивает. Видимо, у любой задачи может быть несколько решений.


        1. Sawko88
          25.01.2022 15:39

          Есть ещё вот такой способ подключения разъема программирования и тестирования (https://www.amazon.de/-/en/Tag-Connect-TC2050-IDC-NL-Cable/dp/B018H0UAXQ). Он более компактный  чем 1.27mm double row pin header, но нужны дополнительные сквоздные отверстия для направляющих разъема. Разъем на плате не нужен. Контакты у кабеля подпружинены. Используем такой в LCC модуле.
          Есть ещё вот такой способ подключения разъема программирования и тестирования (https://www.amazon.de/-/en/Tag-Connect-TC2050-IDC-NL-Cable/dp/B018H0UAXQ). Он более компактный чем 1.27mm double row pin header, но нужны дополнительные сквоздные отверстия для направляющих разъема. Разъем на плате не нужен. Контакты у кабеля подпружинены. Используем такой в LCC модуле.


          1. almaz1c Автор
            25.01.2022 15:41

            Доводилось работать с похожим. Если я правильно понял, то его нужно удерживать руками во время обновления прошивки и тестирования? Автоматизация тут не светит.


            1. Sawko88
              25.01.2022 15:49

              Да, все верно, держать руками нужно, вопрос лишь только в том , сколько времени занимает весь процес программирования и тестирования , если в течении 1 минуты , то вполне рабочий вариант, если дольше , то тут уже все будет зависеть от выносливости работника, который подготавливает оборудование =) . Но в вашем случае, тоже ведь нужно , чтобы кто-то менял модуль после программирования и тестирования ? =) а могу ещё поинтересоваться , где вы достали подпружиненные контакты ?


              1. Sawko88
                25.01.2022 15:50

                Извиняюсь, нашел ссылку на контакты в статье


              1. almaz1c Автор
                25.01.2022 15:57

                Да, модуль сменил, запустил скрипт и 5 минут (время работы скрипта) я свободен)

                А сидеть неподвижно, затаив дыхание, в течении 5 минут, - нет спасибо)

                Пружинные контакты


                1. Sawko88
                  25.01.2022 15:59

                  Согласне , что этим Ваш вариант лучше, что можно раслабляться во время тестирования =)


                1. fk0
                  26.01.2022 03:01
                  +1

                  Вот поэтому я и предлагал материнскую плату на N изделий разом. Логика в том, чтобы экономить время человека. Так получается эти самые 5 минут всё равно человек нужен и за рабочую смену не выпустить более 96 изделий, реально раза в два меньше, и не может работник ничем заниматься ещё.

                  Вот если бы можно было те же самые 96 плат подключить, условно, за полтора часа, а потом на три часа идти чем-то другим заниматься -- совершенно другое дело было бы. Чтоб потом только где-то на той же матьплате красными диодиками, или на компе, отображались прошедшие тест и неисправные изделия.

                  Иметь 96 программаторов для этого не нужно. Нужен какой-то коммутатор, мультиплексор, переключающий единственный программатор и всё прочее ко всем приборам по-очереди. Я понимаю, что в случае USB это уже не просто... И в данном случае может быть практически не применимо (много слишком разнотипных сигналов). Но в общем случае такая идея может быть стоящая.

                  Конечно это зависит от объёмов, зарплат и всего прочего... Если, условно, лишняя сотня рублей в себестоимости производства важна. Или если тест не дай бог не пять минут, а все два часа (с прожаркой в духовке для куры гриль).

                  PS: честно говоря пост прочитал по диагонали в первый раз и подумалось, что ваш стенд и есть ваше изделие, потому такой странный на ваш взгляд комментарий и написал изначально. Да, в в случае мелкого модуля ваш вариант вполне оптимален...


                  1. almaz1c Автор
                    26.01.2022 12:52

                    Наверное я еще по объемам не дорос - 8-ми часовой полноценно загруженной смены нет и в помине.

                    Наверное, в ближайшее время придем к подобному стенду - на miniPCIe разъемы переходим прямо сейчас. Не соображу пока, как 5-6 пинов JTAG мультиплексировать на N модулей, - но и это решаемо наверное.

                    А производительность можно ускорить и без распараллеливания. Достаточно скрипт довести до ума, - заменить JTAG на ethernet при обновлении прошивки. В этом случае вполне реально снизить время работы скрипта с 5-ти до 2-х минут.


            1. fk0
              26.01.2022 02:45
              +1

  1. hooperer
    26.01.2022 11:34

    Бывают ещё "летающие контакты".

    Мы вот поджимаем "иголками" при тестировании и прошивки ( используем VAR Som Solo).

    Да, SD карточка на материнской плате, да с тестированием одновременным и её и usb. Да, сотнями приборов.

    Считается хорошим тоном всё таки посмотреть после прошивки, по Ethernet версию того, что зашилось. Мы так вообще ставим в usb на стенде прошички и тестирования wifi и отдельно проверяем трафик с него в эзернет порт.


    1. almaz1c Автор
      26.01.2022 12:33

      А зачем тестировать/прошивать готовый SoM-модуль? Он же почти наверняка тестировался производителем и к вам приходят заведомо исправные модули с уже прожжеными фьюзами и прошитой прошивкой, которую можно обновить стандартными средствами (sysupgrade, например)?


      1. hooperer
        26.01.2022 17:53
        +1

        Вопрос:

        "А зачем тестировать/прошивать готовый SoM-модуль? Он же почти наверняка тестировался производителем и к вам приходят заведомо исправные модули с уже прожжеными фьюзами и прошитой прошивкой, которую можно обновить стандартными средствами (sysupgrade, например)? "

        Первая часть ответа : Для того чтобы обеспечить надёжность в соответствии со стандартом надёжности в компании. Типичный пример для нас - прибор 15-и летней давности достают из за фальш потолка, сдувают пыль, обновляют прошивку и ставят работать дальше.

        Вторая часть Вопроса "Он же почти наверняка тестировался производителем и к вам приходят заведомо исправные модули с уже прожжеными фьюзами и прошитой прошивкой, которую можно обновить стандартными средствами (sysupgrade, например)? "

        Ответ делиться тоже на две части. Первая часть говорит о том, что мы делаем ВСЮ прошивку Сами. и фьюзы и секьюр область шьём сами, свои номера.

        Вторая часть ответа на этот вопрос заключается в том, что до этого я работал в компании Овен. и мы делали похожие SOM модули, только на ситаре. Они до сих пор используются в плк110[m02]. И как бы маштаб производства достаточно большой, и при этом мы накушались Внезапных проблемм на SOM модулях. И предпочитаю надёжность в тестировании и прошивке проблемам по возврату дорогих модулей от Потребителя.

        Тем более что если модуль сторонний - стоит понимать его Гарантийный срок в соотнесении с Гарантийным сроком Вашего изделия. А он зачастую исчисляется временем попадания на Ваш склад. А в текущих реалиях, я думаю Вы можете прикинуть когда возникшая у Потребителя проблема может вернуться, относительно уже истёкшего гарантийного срока к Вам, и темболее поставщику модулей.


  1. srg27y
    27.01.2022 14:46

    pogo-pin в помощь

    можно не ставить в ряд как разъем, а в удобных местах по плате раскидать