Обзор отечественного одноплатного компьютера MB 77.07: От распаковки и прошивки, до написания первой DSP программы

    В наше время рынок SBC (Single Board Computer) сильно разросся, и появилось огромное количество одноплатных компьютеров на самых различных процессорах, от старых и всем известных, до совсем новых и специализированных. Недавно ко мне попал Module MB 77.07 – одноплатный компьютер от НТЦ «Модуль» на процессоре отечественного производства К1879ХБ1Я, про который на хабре уже однажды оставили небольшую заметку люди из компании Promwad. С момента того поста плату стали продавать всем желающим и было выложено ПО на официальный github компании – http://github.com/RC-MODULE

    В статье будет дано описание железа и софта, от распаковки и прошивки, до написания простого примера – аудио-эффекта эха на встроенном в используемый процессор DSP ядре NeuroMatrix.

    Комплектация


    Плата поставляется в цветной фирменной коробочке. Внутри находятся:

    • плата MB 77.07
    • Ethernet патчкорд
    • 5V/2A блок питания
    • USB-UART для тех, кто знакомится с embedded миром впервые

    Тут можно поспорить, нужно ли всё это или хватило бы обычной OEM поставки в виде антистатического пакетика с платой. Думаю, новичкам будет полезно сразу получить USB-UART, будет меньше желающих загуглить, получить стандартный вредный совет «соедини с COM портом, ничего не будет» и спалить плату в первый же день после покупки.









    Железо


    Теперь стоит рассмотреть саму плату. На борту платы находится ARM1176, такое же ядро используется в Raspberry Pi. Можно запускать заточенные под r-pi дистрибутивы, естественно с оговоркой на то, что нужно будет подсунуть драйвера для местных IP core, использованных в процессоре. Для облегчения этой задачи, разработчик процессора, НТЦ «Модуль», предоставляет готовые образы Debian Jessie и Raspbian Wheezy, пакеты периодически обновляются.

    Рядом с самим К1879ХБ1Я распаяно два чипа DDR2 оперативной памяти по 128MB, 1GB NAND памяти, USB-hub на 4 порта, Ethernet PHY и обвязка.

    На пинах, расположенных по двум сторонам платы разместились различные внешние интерфейсы:

    Правая сторона:

    • JTAG
    • 2xUSB – pinout точно такой же как и на материнских платах, доставайте планки из ящиков
    • UART с boot консолью

    Левая сторона, длинный разъем напоминающий IDE:

    • 8x GPIO
    • 1x Transport Stream Interface (очень подробно здесь)
    • 1x I2C
    • 1x SPI
    • 1x I2S
    • 1x SPDIF
    • 1x External Interrupt
    • 1.5x UART – один UART полный, второй только RX
    • 1x RESET
    • 5V
    • 3.3V — за данный канал отвечает выделенный канал импульсного источника питания, выдающий 800мА, реально зная современные китайские компоненты, я бы не стал вешать сюда больше 500мА

    Подробная распиновка доступна по ссылке: http://www.module.ru/mb7707/doc/MB77.07-X9-pinout.pdf

    Рассмотрим GPIO подробнее, так как это самое первое место, которое захочется пощупать самому. GPIO здесь два разных типа. Первый тип, это те, что выведены на гребенку, их подцепляет драйвер gpio-pl061 (IP core ARM PrimeCell™ General Purpose Input/Output PL061). Эти GPIO могут дергать прерывания к ARM ядру, что иногда бывает полезным. Кроме того, если вам не нужен Transport Stream, то его _D[0-7] пины можно мультиплексировать в GPIO, итого, можно получить 16 управляемых ножек.

    Нумерация GPIO ног в sysfs есть в документах выше по ссылке, и при желании можно подергать их через sysfs:

    # перейдем в sysfs, в директорию, где лежат классы gpio
    cd /sys/class/gpio
    # экспортируем 23-тий пин
    echo 23 > export
    # переключим его направление в out
    echo out > gpio23/direction
    # установим высокий уровень
    echo 1 > gpio23/value
    

    Второй тип GPIO – более упрощенные, управляемые другим IP core, они не могут дергать прерывания. На эти GPIO заведены два наплатных светодиода, один из них регистрируется через LED framework ядра Linux как heartbeat и показывает Load Average. Полезно при дебаге визуально видеть, не зависло ли всё.

    Отдельное место на плате занимают два пина для джампера boot.

    Загрузка сделана просто и надежно: когда джампера нет – происходит загрузка из NAND памяти, когда джампер надет – плата ожидает загрузки через JTAG или EDCL. Положение джампера считывается при ресете платы. О последнем режиме стоит рассказать подробнее, так как возможно, вы с ним не сталкивались.

    EDCL


    EDCL или Ethernet Debug Communications Link – это аппаратная функция, встроенная в Ethernet контроллер, которая позволяет писать и читать физическую память, отправляя правильно сформированные Ethernet пакеты. Данная функция шла в комплекте с IP Core используемого Ethernet контроллера – greth. Сам по себе EDCL достаточно удобен, но если оставить его включенным в продакшене – получится очень большая дыра в безопасности (интересно, сколько процессоров с таким же Ethernet контроллером работают с включенным EDCL в продакшене?).

    Поверх EDCL работает любопытный инструмент edcltool, который дает со стороны хоста lua API к edcl. Данная технология используется для анбрика и прошивки плат. Сам edcltool изначально предназначен для Linux, в отличие от популярных производителей SoC-ов, предоставляющих вам какой-нибудь livesuit/phoenixsuit или rkbatch.

    Есть версия для Windows, но она эксперементальна, собрана на скорую руку через mingw и требует установки WinPCAP. Кроме того, работает довольно медленно.

    Linux версия ставится стандартными ./bootstrap && ./configure --prefix=/usr && make && sudo make install и просит лишь lua5.1-dev или lua5.2-dev и libelf. Последний нужен если требуется работа с NeuroMatrix DSP, о котором речь пойдет ниже.

    Сам edcltool исполняет edcl скрипты, которые на самом деле – обычные lua скрипты, выглядят очень просто и читаемо. Например, вот так выглядит скрипт, запускающий код на голом ARM:

    fw = require("fw");
    edcl_init();
    fw.run_code("mboot-uemd.bin");
    

    Далее, вот так выглядит прошивка загрузчика mboot:

    fw = require("fw");
    edcl_init();
    fw.run_code("mboot-uemd.bin", true); -- start in slave mode
    fw.write_bootloader("mboot-signed.bin")
    

    Создание таблицы разделов в NAND, запись ядра, dtb и корневой файловой системы:

    fw = require("fw");
    edcl_init();
    fw.run_code("mboot-uemd.bin",true); -- start in slave mode
    fw.write_bootloader("mboot-signed.bin") -- save signed loader in NAND
    -- all sizes are in bytes
    partition_table = {
       { "kernel", 4*1024*1024 }, 
       { "rootfs", "-" }, 
    }
    fw.partition(partition_table);
    -- prepare and erase all nand 
    fw.mboot_cmd("parterase kernel y y")
    fw.mboot_cmd("parterase rootfs y y")
    fw.flash_part("kernel", "uImage", false);
    fw.flash_part("dtb", "mb77.07.dtb", false);
    fw.flash_part("rootfs", "filesystem.ubifs", false);
    fw.mboot_cmd("setenv bootargs console=ttyS0,38400n8 earlyprintk=serial   ubi.mtd=4,2048 root=ubi0:rootfs rootfstype=ubifs");
    fw.mboot_cmd("setenv bootfdt 1")
    fw.mboot_cmd("save");
    

    Вот так выглядит запуск кода на голом NeuroMatrix (сокращенно – NMC):

    nmc = require("easynmc");
    nmc.debug = true;
    edcl_init();
    nmc.init_core("ipl-K1879-nmc-debug.abs");
    entry = nmc.upload("myfile.abs");
    nmc.run(entry);
    -- Warning: nmc stdio, arguments and return code are NOT yet supported 
    -- when running nmc prog via edcltool.  Use linux libeasynmc.
    -- Expect these implemented in future updates. Sorry.
    

    Запуск самих скриптов очень прост:

    edcltool -f script.edcl -i имя_интерфейса
    

    Если забыть имя интерфейса, edcltool будет использовать eth0 (на Windows – 0-вой интерфейс). Полезной может оказаться команда edcltool –l перечисляющая доступные интерфейсы, особенно полезно на Windows, где может быть не очень понятно в панели управления, какой интерфейс под каким номером зарегистрирован в системе.

    Кроме вышеперечисленных, в комплекте идут другие скрипты для DSP, фактически для разработки DSP кода можно не загружать Linux. Для написания своих скриптов в архиве с edcltool лежит файлик SCRIPTING.TXT, в котором подробно описаны доступные из edcl окружения функции.

    Прошивки


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

    Подробная инструкция о текущем комплекте прошивки идет в каждом архиве, но цитировать её нет смысла, так как всё сводится к одному:

    • замкнуть джампер boot
    • нажать ресет на плате
    • запустить edcltool –f eupgrade.edcl
    • попить чаю 7-10 минут
    • снять джампер и нажать ресет

    Окружение


    Для полноценной работы с платой, нам потребуется окружение для сборки софта под процессор платы и его DSP – Модуль предоставляет уже собранные тулчейны и под Linux, и под Windows. Установка их достаточно проста, например, предположим что тулчейны хранятся в знакомом многим месте под названием ~/x-tools. Далее нужно положить туда скачанный тулчейн от Модуля и не забыть прописать очередной bin в свой PATH:

    export PATH=$PATH:~/x-tools/arm-module-linux-gnueabi/bin
    

    Дистрибутивы


    Производитель процессора придерживается минимализма при сборке своих дистрибутивов и по умолчанию, Debian и Raspbian идут в минимальной комплектации с поддержкой сети и ssh. X11 на 324MHz как-то медленно работает, плюс, загрузчик не умеет ничего рисовать на экран. Главным способом связи с платой является её serial console, ради которой в комлпект поставки и был положен UART. По умолчанию сеть дистрибутивами от производителя поднимается с адресом платы 192.168.0.7, логин root, пароль 12345678.

    Репозитории производителя выставляются следующим образом в sources.list:

    # RC Module's repository with MB77.07 packages
    deb http://www.module.ru/mb7707/ stable updates
    

    Загрузка системы


    Теперь немного о том, как система грузится с NAND. Первым исполняется IPL загрузчик и проверяет положение джампера boot и:

    • ждет по волшебному адресу 0x00100000 (начальный адрес первого SRAM банка памяти IM0) от edcl/jtag 32-битного адреса куда прыгнуть, если джампер установлен
    • загружает из NAND загрузчик в IM0, проверяет md5 и начинает его исполнение, если джампер не установлен

    Первым стартует загрузчик mboot. Это форк u-boot, немного отрефакторенный. Работает из SRAM памяти, которой на процессоре на удивление много: 4 банка, под названиями IM[0-3]. Каждый банк по 256 килобайт. Как удалось выяснить, предназначение каждой следующее:

    • IM0 – память, откуда работает загрузчик, после загрузки не используется и простаивает, можно использовать для своих корыстных целей.
    • IM1, IM3 – память NeuroMatrix, откуда предполагается запускать NMC код, NMC имеет приоритет при обращении к ней.
    • IM2 – используется декодером h264. Если декодер не используется – можно использовать для своих нужд

    К слову, старую версию mboot можно найти в google, лежит она на github аккаунте Сергея Миронова, ссылка для сокращения времени поиска: github.com/ierton/mboot, так же там можно найти overlay для Gentoo, но он не обновлялся довольно продолжительное время, так что вряд ли он кому-то пригодится.

    Последнее, что можно сказать о загрузчике, это то, что кроме команды pmgr есть еще пара команд для апдейта – fwupgrade и eupgrade, предназначены для прошивки по tftp образов, которые могут быть больше чем размер доступной на плате DDR памяти, такое тоже случается. В остальном, это обычный u-boot, к которому многие привыкли. Из загрузчика доступна сеть, работа с NAND, SPI Flash (которого на MB77.07, к сожалению, не положили) и немного usb, без поддержки файловых систем.

    Вернемся к памяти, в адресном пространстве сразу после IM0 идет IM1, а потом сразу IM3, это стоит помнить при написании низкоуровневого кода, работающего с SRAM, так же при написании подобного кода стоит помнить, что тут действительно много SRAM памяти, на каком-нибудь старом добром AT91RM9200 накристальной памяти было всего 4К. Именно по этой причине, загрузчик здесь работает напрямую в SRAM, без SPL. Такой подход очень полезен, так как в отличие от DDR, что у ARM, что у NeuroMatrix время доступа будет всего пару тактов. Другими словами – код оттуда будет работать очень и очень быстро. Более того, если код для NMC будет работать только из IM1/IM3, не обращаясь никак к DDR – на NMC можно будет крутить какую-нибудь очень жесткую realtime часть.

    Далее, стоит рассмотреть NAND подробнее, он разбит на разделы, первыми идут boot, env и dtb. Они жестко забиты и изменять их размеры нельзя. В первом лежит загрузчик, во втором его окружение, в третьем скомпилированный Device Tree Blob. Остальное разбивается интерактивно командой загрузчика pmgr, либо автоматом при прошивке образа из edcl скрипта. Заданные разделы загрузчик передает ядру, дописывая в cmdline стандартные mtdparts.

    С NAND вообще ожидалось увидеть что-нибудь станное. По опыту работы с linux-sunxi и linux-rockchip, NAND и там, и там был в ужасающем состоянии. Allwinner сделали из NAND свой собственный block device с частично закрытым FTL (flash translation layer), с своими накостылеными алгоритмами wear-leveling’а и прочего. Rockchip вообще предоставляет NAND только в виде закрытого модуля rknand.ko, исходников которого не дают даже под NDA партнерам компании, как мне рассказали в #linux-rockhip@freenode. Здесь же NAND представляет собой обычный standalone mtd device, поверх которого используется ставший уже стандартом UBIFS, что не может не радовать.

    Теперь собственно о самой загрузке. Думаю, многим было бы интересно посмотреть на dmesg:
    Загрузка системы
    MBOOT (K1879 and friends): Version mboot-00063-g9302e24-dirty (Built Thu Aug 21 17:10:13 MSK 2014)
    OTP info: boot_source 2 jtag_stop 0 words_len 1024
    Maximum bank size: 0x10000000 bytes
    Detected 134217728 bytes of EM0 memory
    MEMORY: 40000000 -> 48000000
    Memory layout
            0x00100010  early
            0x001001C8  text
            0x0011E9BC  data
            0x00127D40  signature
            0x00127D44  bss_start
            0x00135EB4  stack_start
            0x00137FF8^ stack_ptr
            0x00138000  malloc
            0x0017F000  env
    mnand_read_id: flash id 0xD3
    mnand_read_id: flash ext_id 0x95
    mnand_read_id: CS0 NAND 1GiB 3,3V 8-bit size(1024) writesize(2048) oobsize(64) erasesize(131072)
    mnand_read_id: flash id 0x00
    mnand_read_id: WARNING: Unknown flash ID. Using default (0xF1)
    mnand_read_id: flash ext_id 0x00
    mnand: Chip configurations differ, ignoring CS1
    greth: Setting GRETH base addr to 0x20034000
    greth: Found GRETH at 0x20034000, irq 255
    greth: Resetting GRETH
    greth: greth: 'phyaddr' not set, fall back to built-in table
    greth: greth: using preset PHY addr: 1f
    greth: Resetting the PHY
    greth: write_mii: 0x20034010 < 0xF809F801 [p:31 a:0 d:0xF809]
    greth: write_mii: 0x20034010 < 0x0000F801 [p:31 a:0 d:0x0000]
    greth: 10/100 GRETH Ethermac at [0x20034000] irq 255. Running 10 Mbps half duplex
    PHY info not available
    greth: greth_init
    greth: greth_init: enabling receiver
    ETH new device: name GRETH_10/100 
    greth: GRETH: New MAC address: 02:00:f7:00:27:0f
    USB thresholds: in 0x20 out 0x7e
    Is there an EDCL emergency? Nope
    edcl: Ethernet debug disabled by environment
    MTD Partition:       boot @ 0x00000000 size 0x00040000
    MTD Partition:        env @ 0x00040000 size 0x00020000
    MTD Partition:        dtb @ 0x00060000 size 0x00020000
    MTD Partition:     kernel @ 0x00080000 size 0x00400000
    MTD Partition:     rootfs @ 0x00480000 size 0x3FB80000
    Hit any key (in 2 sec) to skip autoload...
    Running autoload command 'tftp;bootm;'
    TFTP Using GRETH_10/100 device
    TFTP params: server 192.168.0.1 our_ip 192.168.0.7
    TFTP params: filename 'uImage-3' load_address 0x40100000
    TFTP Loading: T #################################################################
            #################################################################
            #################################################################
            #################################################################
            #################################################################
            #################################################################
            #################################################################
            ################################
    TFTP done
    Linux preparing to boot the kernel: machid 0xcd1
    Using Flatterned Device Tree boot method
    IMG moving image: type 2 from 0x40100040 to 0x40008000
    HINT: To optimize boot time adjust loadaddr to: 0x40007fc0
    Linux entry 0x40008000
    USB thresholds: in 0x20 out 0x7e
    Uncompressing Linux... done, booting the kernel.
    [    0.000000] Booting Linux on physical CPU 0x0
    [    0.000000] Linux version 3.10.28-shadow1-00032-gb8b1a50 (necromant@sylwer) (gcc version 4.8.1 (crosstool-NG 1.19.0) ) #141 Thu Aug 21 14:23:26 MSK 2014
    [    0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
    [    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
    [    0.000000] Machine: Module MB77.07, model: Module MB77.07
    [    0.000000] bootconsole [earlycon0] enabled
    [    0.000000] Memory policy: ECC disabled, Data cache writeback
    [    0.000000] On node 0 totalpages: 24128
    [    0.000000] free_area_init_node: node 0, pgdat c050df84, node_mem_map c0596000
    [    0.000000]   Normal zone: 288 pages used for memmap
    [    0.000000]   Normal zone: 0 pages reserved
    [    0.000000]   Normal zone: 24128 pages, LIFO batch:3
    [    0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
    [    0.000000] pcpu-alloc: [0] 0 
    [    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 23840
    [    0.000000] Kernel command line: debug console=ttyS0,38400n8 earlyprintk=serial  ubi.mtd=4,2048 root=ubi0:rootfs rootfstype=ubifs mtdparts=mnand:0x40000@0x0(boot),0x20000@0x40000(env),0x20000@0x60000(dtb),0x400000@0x80000(kernel),0x3FB8000)
    [    0.000000] PID hash table entries: 512 (order: -1, 2048 bytes)
    [    0.000000] Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
    [    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
    [    0.000000] Memory: 94MB 0MB = 94MB total
    [    0.000000] Memory: 89208k/89208k available, 41864k reserved, 0K highmem
    [    0.000000] Virtual kernel memory layout:
    [    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    [    0.000000]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
    [    0.000000]     vmalloc : 0xc8800000 - 0xff000000   ( 872 MB)
    [    0.000000]     lowmem  : 0xc0000000 - 0xc8000000   ( 128 MB)
    [    0.000000]     modules : 0xbf000000 - 0xc0000000   (  16 MB)
    [    0.000000]       .text : 0xc0008000 - 0xc04af9cc   (4767 kB)
    [    0.000000]       .init : 0xc04b0000 - 0xc04d31d4   ( 141 kB)
    [    0.000000]       .data : 0xc04d4000 - 0xc0515d50   ( 264 kB)
    [    0.000000]        .bss : 0xc0515d50 - 0xc0595990   ( 512 kB)
    [    0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
    [    0.000000] NR_IRQS:128
    [    0.000000] regs = 0xf8000000, irq_start = 0
    [    0.000000] VIC @f8000000: id 0x00041192, vendor 0x41
    [    0.000000] regs = 0xf8010000, irq_start = 32
    [    0.000000] VIC @f8010000: id 0x00041192, vendor 0x41
    [    0.000000] UEMD: Firing up timer system
    [    0.000000] Clocksource: rate 54000000 mult 19418074 shift 20
    [    0.000000] Clockevent: rate 54000000 mult 231928233 shift 32
    [    0.000000] sched_clock: 32 bits at 100 Hz, resolution 10000000ns, wraps every 4294967286ms
    [    0.000000] Console: colour dummy device 80x30
    [    0.020000] Calibrating delay loop... 215.04 BogoMIPS (lpj=1075200)
    [    0.100000] pid_max: default: 32768 minimum: 301
    [    0.110000] Mount-cache hash table entries: 512
    [    0.120000] CPU: Testing write buffer coherency: ok
    [    0.130000] Setting up static identity map for 0xc03417b8 - 0xc03417f0
    [    0.150000] devtmpfs: initialized
    [    0.160000] NET: Registered protocol family 16
    [    0.170000] DMA: preallocated 256 KiB pool for atomic coherent allocations
    [    0.240000] OTP ROM is not flashed
    [    0.250000] msvdhd: configuring memory
    [    0.260000] hw-breakpoint: found 6 breakpoint and 1 watchpoint registers.
    [    0.270000] hw-breakpoint: maximum watchpoint size is 4 bytes.
    [    0.410000] bio: create slab <bio-0> at 0
    [    0.430000] SCSI subsystem initialized
    [    0.440000] ssp-pl022 2002e000.ssp: ARM PL022 driver, device ID: 0x00041022
    [    0.450000] ssp-pl022 2002e000.ssp: BUSNO: 0
    [    0.460000] pl022: mapped registers from 0x2002e000 to f802e000
    [    0.470000] ssp-pl022 2002e000.ssp: registered master spi0
    [    0.480000] spi spi0.0: allocated memory for controller's runtime state
    [    0.490000] ssp-pl022 2002e000.ssp: SSP Target Frequency is: 25000000, Effective Frequency is 13500000
    [    0.500000] ssp-pl022 2002e000.ssp: SSP cpsdvsr = 2, scr = 1
    [    0.510000] spi spi0.0: 4 <= n <=8 bits per word
    [    0.520000] spi spi0.0: DMA mode NOT set in controller state
    [    0.530000] spi spi0.0: setup mode 1, 8 bits/w, 25000000 Hz max --> 0
    [    0.540000] ssp-pl022 2002e000.ssp: registered child spi0.0
    [    0.550000] ssp-pl022 2002e000.ssp: probe succeeded
    [    0.570000] usbcore: registered new interface driver usbfs
    [    0.580000] usbcore: registered new interface driver hub
    [    0.590000] usbcore: registered new device driver usb
    [    0.600000] media: Linux media interface: v0.10
    [    0.610000] Linux video capture interface: v2.00
    [    0.620000] Advanced Linux Sound Architecture Driver Initialized.
    [    0.630000] Switching to clocksource uemd_timer1
    [    0.730000] NET: Registered protocol family 2
    [    0.740000] TCP established hash table entries: 1024 (order: 1, 8192 bytes)
    [    0.750000] TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
    [    0.760000] TCP: Hash tables configured (established 1024 bind 1024)
    [    0.780000] TCP: reno registered
    [    0.790000] UDP hash table entries: 256 (order: 0, 4096 bytes)
    [    0.800000] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
    [    0.810000] NET: Registered protocol family 1
    [    0.820000] RPC: Registered named UNIX socket transport module.
    [    0.830000] RPC: Registered udp transport module.
    [    0.840000] RPC: Registered tcp transport module.
    [    0.850000] RPC: Registered tcp NFSv4.1 backchannel transport module.
    [    0.930000] squashfs: version 4.0 (2009/01/31) Phillip Lougher
    [    0.950000] NFS: Registering the id_resolver key type
    [    0.960000] Key type id_resolver registered
    [    0.970000] Key type id_legacy registered
    [    0.980000] msgmni has been set to 174
    [    1.000000] alg: No test for stdrng (krng)
    [    1.010000] io scheduler noop registered (default)
    [    1.020000] fj_gpio: Added 32 gpio lines at base -981095888
    [    1.040000] module_vdu 80173000.vdu: found VDU device at 80173000, id <ebebab01>
    [    1.070000] Console: switching to colour frame buffer device 90x36
    [    1.090000] fb0: Module VDU frame buffer device
    [    1.140000] Serial: 8250/16550 driver, 3 ports, IRQ sharing disabled
    [    1.150000] 2002b000.uart: ttyS0 at MMIO 0x2002b000 (irq = 7) is a 8250
    [    1.160000] console [ttyS0] enabled, bootconsole disabled
    [    1.160000] console [ttyS0] enabled, bootconsole disabled
    [    1.170000] 20022000.uart: ttyS1 at MMIO 0x20022000 (irq = 9) is a 8250
    [    1.180000] 2002c000.uart: ttyS2 at MMIO 0x2002c000 (irq = 8) is a 8250
    [    1.200000] [drm] Initialized drm 1.1.0 20060810
    [    1.240000] loop: module loaded
    [    1.250000] msvdhd 80180000.video_decoder: found device at 0x80180000, id 0x0025300b
    [    1.300000] EasyNMC Unified DSP Framework. (c) RC Module 2014
    [    1.310000] easynmc-nmc3: imem at phys 0x140000 virt 0xc8900000 size 0x80000 bytes
    [    1.320000] easynmc-nmc3: HP IRQ 14 LP IRQ 15
    [    1.330000] easynmc: registering core K1879-nmc (nmc3) with id 0
    [    1.350000] flash ext_id 0x95
    [    1.360000] mnand CS0 Samsung size(1024) writesize(2048) oobsize(64) erasesize(131072)
    [    1.370000] mnand: Bad chip id or no chip at CS1
    [    1.380000] mnand: Detected 1073741824 bytes of NAND
    [    1.390000] 5 cmdlinepart partitions found on MTD device mnand
    [    1.400000] Creating 5 MTD partitions on "mnand":
    [    1.410000] 0x000000000000-0x000000040000 : "boot"
    [    1.430000] 0x000000040000-0x000000060000 : "env"
    [    1.450000] 0x000000060000-0x000000080000 : "dtb"
    [    1.470000] 0x000000080000-0x000000480000 : "kernel"
    [    1.510000] 0x000000480000-0x000040000000 : "rootfs"
    [    6.500000] libphy: greth-mdio: probed
    [    9.590000] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
    [    9.600000] uemd-ehci 10040000.ehci: UEMD EHCI
    [    9.610000] uemd-ehci 10040000.ehci: new USB bus registered, assigned bus number 1
    [    9.630000] uemd-ehci 10040000.ehci: irq 35, io mem 0x10040000
    [    9.660000] uemd-ehci 10040000.ehci: USB 2.0 started, EHCI 1.00
    [    9.680000] hub 1-0:1.0: USB hub found
    [    9.690000] hub 1-0:1.0: 2 ports detected
    [    9.700000] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
    [    9.710000] usbcore: registered new interface driver usb-storage
    [    9.720000] usbcore: registered new interface driver usbserial
    [    9.730000] mousedev: PS/2 mouse device common for all mice
    [    9.740000] i2c /dev entries driver
    [    9.770000] module_hdmi: module_hdmi: Device ID: 0x9132
    [    9.780000] usbcore: registered new interface driver i2c-tiny-usb
    [    9.800000] ledtrig-cpu: registered to indicate activity on CPUs
    [    9.850000] usbcore: registered new interface driver usbhid
    [    9.860000] usbhid: USB HID core driver
    [    9.900000] TCP: cubic registered
    [    9.910000] Key type dns_resolver registered
    [    9.920000] VFP support v0.3: implementor 41 architecture 1 part 20 variant b rev 5
    [    9.950000] UBI: attaching mtd4 to ubi0
    [   10.020000] usb 1-1: new high-speed USB device number 2 using uemd-ehci
    [   10.180000] hub 1-1:1.0: USB hub found
    [   10.190000] hub 1-1:1.0: 4 ports detected
    [   25.560000] UBI: scanning is finished
    [   25.640000] UBI: attached mtd4 (name "rootfs", size 1019 MiB) to ubi0
    [   25.650000] UBI: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
    [   25.660000] UBI: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
    [   25.670000] UBI: VID header offset: 2048 (aligned 2048), data offset: 4096
    [   25.680000] UBI: good PEBs: 8141, bad PEBs: 15, corrupted PEBs: 0
    [   25.690000] UBI: user volume: 1, internal volumes: 1, max. volumes count: 128
    [   25.700000] UBI: max/mean erase counter: 4/1, WL threshold: 4096, image sequence number: 23379108
    [   25.710000] UBI: available PEBs: 0, total reserved PEBs: 8141, PEBs reserved for bad PEB handling: 145
    [   25.720000] mvdu: will allocate buffers
    [   25.730000] mvdu: did allocate buffers cc000000
    [   25.740000] UBI: background thread "ubi_bgt0d" started, PID 620
    [   25.750000] ALSA device list:
    [   25.760000]   #0: Module MB7707
    [   25.860000] UBIFS: recovery needed
    [   26.940000] UBIFS: recovery deferred
    [   26.950000] UBIFS: mounted UBI device 0, volume 0, name "rootfs", R/O mode
    [   26.960000] UBIFS: LEB size: 126976 bytes (124 KiB), min./max. I/O unit sizes: 2048 bytes/2048 bytes
    [   26.970000] UBIFS: FS size: 1013395456 bytes (966 MiB, 7981 LEBs), journal size 9023488 bytes (8 MiB, 72 LEBs)
    [   26.980000] UBIFS: reserved for root: 0 bytes (0 KiB)
    [   26.990000] UBIFS: media format: w4/r0 (latest is w4/r0), UUID D7B60B07-E5DE-408F-886D-5EACF67535FC, small LPT model
    [   27.010000] VFS: Mounted root (ubifs filesystem) readonly on device 0:11.
    [   27.020000] devtmpfs: mounted
    [   27.030000] Freeing unused kernel memory: 140K (c04b0000 - c04d3000)
    Mount failed for selinuxfs on /sys/fs/selinux:  No such file or directory
    INIT: version 2.88 booting
    [info] Using makefile-style concurrent boot in runlevel S.
    [info] Setting the system clock.
    head: cannot open '/etc/adjtime' for reading: No such file or directory
    hwclock: Cannot access the Hardware Clock via any known method.
    hwclock: Use the --debug option to see the details of our search for an access method.
    [....] Unable to set System Clock to: Thu Jan 1 00:00:33 UTC 1970 ... (warning).
    [....] Activating swap...done.
    [   33.700000] UBIFS: completing deferred recovery
    [   33.830000] UBIFS: background thread "ubifs_bgt0_0" started, PID 870
    [   33.850000] UBIFS: deferred recovery completed
    [....] Activating lvm and md swap...done.
    [....] Checking file systems...fsck from util-linux 2.20.1
    done.
    [....] Cleaning up temporary files... /tmp. ok 
    [....] Mounting local filesystems...done.
    [....] Activating swapfile swap...done.
    [....] Cleaning up temporary files.... ok 
    [....] Setting kernel variables ...done.
    [....] Configuring network interfaces...done.
    [....] Cleaning up temporary files.... ok 
    INIT: Entering runlevel: 2
    [info] Using makefile-style concurrent boot in runlevel 2.
    [....] Starting OpenBSD Secure Shell server: sshd. ok 
    
    Debian GNU/Linux jessie/sid shadow ttyS0
    
    shadow login: root
    Password: 
    Last login: Thu Jan  1 00:16:23 UTC 1970 from 192.168.0.1 on pts/0
    Linux shadow 3.10.28-shadow1-00032-gb8b1a50 #141 Thu Aug 21 14:23:26 MSK 2014 armv6l
    
    The programs included with the Debian GNU/Linux system are free software;
    the exact distribution terms for each program are described in the
    individual files in /usr/share/doc/*/copyright.
    
    Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
    permitted by applicable law.
    root@shadow:~# uname -a
    Linux shadow 3.10.28-shadow1-00032-gb8b1a50 #141 Thu Aug 21 14:23:26 MSK 2014 armv6l GNU/Linux
    root@shadow:~#
    


    Первое, что привлекает внимание это строчка «EasyNMC DSP Framework © RC Module 2014». Далее в лог пишется, сколько NMC ядер найдено и исходя из этого, можно предположить, что драйвера и утилиты заточены на то, что ядер NMC когда-нибудь будет много. В процессоре на этой плате ядро NMC только одно.

    Следующим многим было бы интересно узнать, как NMC взаимодействует с Linux. У разработчиков была выпытана следующая информация: к NMC от ARM идет три прерывания. Немаскируемое NMI, HP (High Priority) и LP (Low Priority). В обратную сторону так же HP и LP. Для запуска DSP ядра необходимо подать начальный сброс и дернуть NMI. Так запускается IPL код NeuroMatrix. После первого запуска, NMC крутится в этом начальном коде, который обрабатывает NMI прерывание. Через этот начальный код организуется перезапуск приложения. Все довольно просто.

    Время для DSP


    В половине статьи постоянно упоминается DSP, теперь пришло время подробно рассмотреть, как же с ним работать. Для работы с ним есть пакет nmc-utils, состоит из двух утилит и библиотеки:

    • nmctl
    • nmrun
    • libeasynmc (используется самими утилитами)

    В дереве исходников так же нашлись исходники IPL для NeuroMatrix, примеры и libeasynmc-nmc (выполняемая на nmc часть этой библиотеки). Бинарных блобов в ходе раскопок найдено не было, тайные агенты Free Software Foundation могут спать спокойно.

    nmctl


    Начнем с утилит. Первая это nmctl. Она умеет загружать начальный код, запускать, останавливать, мониторить события, отправлять прерывания и еще кучу всего.
    Помощь по nmctl
    root@shadow:~# nmctl --help
    nmctl — The EasyNMC control utility
    © 2014 RC Module | Andrew 'Necromant' Andrianov <andrew@ncrmnt.org>
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    License: LGPLv2
    Usage: ./nmctl [options] [actions] — operate on core 0 (default)
    ./nmctl --core=n [options] — operate on selected core
    ./nmctl --core=all [options] — operate all cores
    Valid options are:
    --core=id — Select a core to operate on (--core=all selects all cores)
    --list — list available nmc cores in this system and their state
    --help — Show this help
    --force — Disable internal seatbelts (DANGEROUS!)
    --nostdio — Do not auto-attach stdio
    --debug — print lots of debugging info (nmctl)
    --debug-lib — print lots of debugging info (libeasynmc)
    Valid actions are:
    --boot — Load initcode and boot a core (all cores)
    --reset-stats — Reset driver statistics for core (all cores)
    --load=file.abs — Load abs file to core internal memory
    --start=file.abs — Load abs file to core internal memory and start it
    --irq=[nmi,lp,hp] — Send an interrupt to NMC
    --kill — Abort nmc program execution
    --mon — Monitor IRQs from NMC
    --dump-ldr-regs — Dump init code memory registers

    ProTIP(tm): You can supply init code file to use via NMC_STARTUPCODE env var
    When no env is set nmctl will search a set of predefined paths

    Одна из главных функций, вывод информации о количестве ядер NMC в системе:
    nmctl --list
    root@shadow:~# ./nmctl --list
    0. name: K1879-nmc type: nmc3 (cold)
    IRQs Recv: HP: 0 LP: 0
    IRQs Sent: NMI: 0 HP: 0 LP: 0

    nmrun


    Далее рассмотрим nmrun.
    Помощь по nmrun
    root@shadow:~# ./nmrun --help
    nmrun — The EasyNMC app runner wrapper
    © 2014 RC Module | Andrew 'Necromant' Andrianov <andrew@ncrmnt.org>
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    License: LGPLv2
    Usage: ./nmrun [options] myapp.abs [arguments] — operate on core 0 (default)
    Valid options are:
    --help — Show this help
    --core=id — Select a core to operate on (Default — use first usused core)
    --force — Disable internal seatbelts (DANGEROUS!)
    --nostdio — Do not auto-attach stdio
    --nosigint — Do not catch SIGINT
    --detach — Run app in background (do not attach console)
    Debugging options:
    --debug — Print lots of debugging info (nmctl)
    --debug-lib — Print lots of debugging info (libeasynmc)

    Это враппер для DSP кода. Он запускает .abs файлы на NMC таким образом, что весь printf с NMC происходит в stdout этой обертки, а всё, что мы отправим на stdin – получает NMC. Есть поддержка передачи параметров, если после .abs файла перечислять параметры – они передадуться в NMC в виде аргументов argv. Return из main() выполняющегося на NMC передается nmrun, который он так же возвращает в систему в виде обычного return кода. Всё это моментально превращает сложную DSP программу в обычную command line утилиту, с которой справится даже новичок в DSP. Порог вхождения снижается в разы, ничего ненужно перешивать или специально обрабатывать.

    Попробуем запустить простейший пример:

    root@shadow:~# nmrun /usr/share/examples/easynmc-0.1/arguments.abs hello world
    Application now started, hit CTRL+C to stop it
    Hello world! I am the NMC blinking ledz!
    I have been given 3 arguments
    Argument 0 is nmrun
    Argument 1 is hello
    Argument 2 is world
    App terminated with result 3, exiting
    root@shadow:~# echo $?
    3
    

    Сами ядра NMC присутствуют в системе в виде /dev/nmc0io и /dev/nmc0mem, где:

    • /dev/nmc0mem – память NMC, те самые банки SRAM – IM1 + IM3, о которых речь велась выше. Просто выполнив cat /dev/nmc0mem > dump.bin можно снять дамп памяти DSP
    • /dev/nmc0io – виртуальный последовательный порт, можно писать и читать stdio, в том числе и в неблокирующем виде через poll/epoll

    Для всех остальных операций – ioctl, одинаковые для обоих устройств, их использует libeasynmc.

    Сами утилиты построенны на этой библиотеке, исходники так же полностью открыты под LGPLv2. Беглый осмотр показывает, что внутри кроется достаточно простой и понятный синхронный API. Казалось бы, зачем нам синхронный API во времена node.js? Оказалось, драйвера DSP поддерживают epoll/select не только для stdio, все события от NMC (прерывания, факт отправки NMI другим процессом) можно получать через poll/epoll. Соответственно, этот дескриптор можно подсунуть любимым libevent, libuv и т.д.

    Action


    Теперь, вооружившись этими зананиями, попробуем развернуть окружение для разработки и собрать чего-нибудь для NMC. Допустим, в MB77.07 мы прошили Raspbian, установили тулчейны.

    Начнем с nmc-utils.

    git clone github.com/RC-MODULE/nmc-utils.git 
    cd nmc-utils
    

    Осмотримся в том что мы склонировали с github:

    • в корне лежат исходники libeasynmc, их не особенно много, так как библиотека предельно простая. Исходный код nmctl можно использовать как простой пример работы с libeasynmc во всех его вариантах
    • в libeasynmc-nmc лежат исходники NMC части библиотеки, которую мы будем подключать к нашим NMC проектам
    • в doc/ есть подробное описание порядка работы с библиотекой и того, как комплировать. Особенно полезным будет на начальных этапах возможность статической сборки nm* утилит
    • в ipl/ лежат исходники начального кода, который крутится на NMC
    • в examples/ есть пачка простых примеров

    Кросс-сборка сводится к следующей магии:

    GNU_TARGET_NAME=arm-module-linux-gnueabihf make
    

    Если необходимо собрать все утилиты (nmctl, mnrun) статически:

    GNU_TARGET_NAME=arm-module-linux-gnueabihf make STATIC=y
    

    Если плата загружена по NFS и корень доступен где-то рядом, то можно установить все в него запустив следующее:

    DESTDIR=/srv/rootfs/mb7707/ make install
    

    Далее, при желании, на .deb based системах, можно собрать пачку deb-пакетов:

    GNU_TARGET_NAME=arm-module-linux-gnueabihf ARCH=armhf make deb
    

    При сборке deb пакетов требуется наличие в системе dpkg-deb и надо указывать deb-архитектуру, которая будет фигурировать в пакете: armhf для Raspbian, armel для Debian. На выходе получим файлы:

    • nmc-utils-abs-0.1-armhf.deb — Бинарники примеров, ставятся в /usr/share/examples/easynmc-0.1
    • nmc-utils-bin-0.1-armhf.deb — nmctl, nmrun и сама библиотека libeasynmc.so
    • nmc-utils-dev-0.1-armhf.deb — Заголовочные файлы, pkg-config .pc файл и прочее
    • nmc-utils-doc-0.1-armhf.deb — README и все содержимое doc/
    • nmc-utils-ipl-0.1-armhf.deb — IPL, ставится в /usr/share/easynmc-0.1/ipl/

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

    Для первой своей программы на NMC было решено поиграться со звуком и сделать нечто, что будет в реальном времени на NMC добавлять эффект эхо. Можно использовать следующий pipeline:
    arecord | nmrun ./echo.abs | aplay
    

    Где arecord будет записывать данные с микрофона и передавать прямиком на наш DSP, который будет добавлять эхо и выдавать сэмплы на выход, далее передаем их на воспроизведение в aplay. Для захвата звука была использована дешевая китайская USB звуковая карта, валявшаяся годами на полке. В данном примере использовать libeasynmc не потребуется, хватит обычного nmrun.

    Прежде чем продолжить, нужно сделать отступление и рассказать кое что о производительности такого решения. stdin/stdout хоть и являются самым простым способом обмена данными, но все же достаточно медленны. Они используют два кольцевых буфера, каждый байт должен быть сначала записан ARM ядром в кольцевой буфер, потом считан оттуда в другой буфер NMC ядром, обработан, результат записан в другой кольцевой буфер, откуда в свою очередь будет скопирован опять ARM. Мягко говоря, это не очень быстро, хоть кольцевые буферы и лежат в SRAM памяти. По этому, если нужна будет максимальная производительность, то придется все же забыть про stdio и командную строку и использовать libeasynmc.

    При разработке на C/С++ под NeuroMatrix надо учитывать несколько особенностей, которые могут повергнуть многих, кто никогда ничего не писал под DSP процессоре, в культурный шок. Далее собран список граблей, на которые можно наступить:

    • Отсутствует байтовая адресация. sizeof(char) == 1, sizeof(short) == 1. Указатель в случае NMC указывает на 32-х битные ячейки памяти. Соответственно адрес в пространстве NMC можно получить сдвигом на два бита вправо
    • Из за предыдущего пункта все ASCII представляют собой массив uint32_t[] в младшем байте каждого нужный нам символ, в старших нули
    • nmrun по умолчанию говорит драйверу делать переформатирование строк туда и обратно для stdin и stdout (можно отключить)
    • NMC не имеет MMU и адресует физическую память. Потому, просто передать указатель на буфер с данными из приложения мы не можем
    • Если использовать NMC ядром какую-нибудь периферию напрямую, то лучше выгрузить соответствующие драйвера со стороны Linux. Ни один драйвер не ожидает, что с его регистрами будет работать кто-то еще, кроме него самого
    • В чипе есть некоторые блоки (несколько таймеров, например) доступные только со стороны NMC. API можно посмотреть в nc_int_soc.h из состава тулчейна
    • Библиотека языка С достаточно спартанская
    • Так как NeuroMatrix имеет доступ ко всему адресному пространству, ошибка в коде для него может легко завалить всю систему и вызвать необходимость перезапуска
    • Исходя из предыдущего, если выставить плату в интернет, то удаленный атакующий получив доступ к NMC, может потенциально заставить его пропатчить память ядра для поднятия прав в системе. Соответственно права на /dev/nmc надо выставлять очень аккуратно. Иначе получится как в прошлый раз у Samsung с /dev/exynos-mem
    • NeuroMatrix состоит из RISC части и векторного ядра. Все, что пишется на C, исполняется на не особенно быстрой RISC части, от которой не следует ожидать чудес производительности. Исполняя код на DSP вы не делаете его по взмаху волшебной палочки идеально быстрым. Реальный выигрыш можно получить только задействовав векторное ядро, на ассемблере. Не все алгоритмы хорошо ложаться на то, что может сделать векторное ядро

    Эхо будем делать на C. Для простоты сэмплы пойдут на NMC 8-битные, соответственно с включенным переформатированием мы получим их на DSP в виде 32-х битных чисел.
    Начнем с того, что возьмем пример проекта hello world и ознакомимся с содержимым:

    • Makefile – основной мейкфайл
    • colorizer.mk – инклюдится в Makefile, тут лежит вся расцветка вывода. Расцветка реализована переносимо для Windows/Linux/Mac, потому выглядит весьма хакерски. Под Windows она использует cecho
    • easyconf.asm – ассемблерный файл с конфигурацией io/args. Содержит всего пару макросов, задающих размер области для argc/argv и размер кольцевых буферов для stdio.
    • K1879.cfg – конфигурационный файл линковщика (о нем ниже)
    • main.c – собственно наш файл с main()

    Рассмотрим Makefile. Он более-менее общий и предельно прост. Единственное, что нам требуется поменять – это EASYNMC_DIR, путь к каталогу libeasynmc-nmc где находится NMC часть библиотеки libeasynmc. Если необходимо будет подключить какие-то еще библиотеки, то их надо будет указать в libs.

    Makefile
    #
    # This is a basic Makefile template for a Neuromatrix DSP project 
    # to be run on Module MB77.07. To compile it you need: 
    # * Latest NMSDK installed with utilities in your $PATH
    # * NEURO environment variable pointing to NMSDK directory
    # * Host GCC (Since nmcpp doesn't support generating deps, 
    #              we use gcc for that) 
    #
    # For verbose build run 'make VERBOSE=y'
    #
    
    -include colorizer.mk
    -include *.dep
    
    .SUFFIXES:
    
    OBJECTS :=  \
            main.o \
            easyconf.o
    
    TARGET=helloworld
    
    # Set this to libeasynmc-nmc dir. Relative or absolute. 
    # Make sure you build it prior to building the actual project. 
    
    EASYNMC_DIR     = ../../libeasynmc-nmc
    
    CROSS_COMPILE   =
    NMCPP_FLAGS     = -DNEURO -OPT2 -inline -I$(EASYNMC_DIR)/include
    ASM_FLAGS       = -soc -Sc -Stmp -X-q -I$(EASYNMC_DIR)/include
    C2ASM_FLAGS     = -soc -q 
    
    #BIG FAT WARNING: easynmc.lib MUST go BEFORE libc
    #BIG FAT WARNING: Otherwise argc/argv won't work 
    
    LIBS            = easynmc.lib libc05.lib
    
    BUILDER_FLAGS   = -cK1879.cfg -m -heap=0 -heap1=0 -heap2=0 -heap3=0 -stack=20000 \
                      -full_names
    IDIRS           = -I. -I"$(NEURO)/include" 
    LIBDIR          = -l"$(NEURO)/lib" -l"$(EASYNMC_DIR)"
    
    .DEFAULT_GOAL=all
    
    all: $(TARGET).abs
    
    %.asmx: %.cpp
            $(SILENT_DEP)gcc -E -MM $(<) -o$(@).dep
            $(SILENT_NMCPP)$(CROSS_COMPILE)nmcpp -Tp $(NMCPP_FLAGS) $(<) -O$(@) $(IDIRS) 
    
    %.asmx: %.c
            $(SILENT_DEP)gcc -E -MM $(<) -o$(@).dep
            $(SILENT_NMCPP)$(CROSS_COMPILE)nmcpp -Tc99 $(NMCPP_FLAGS) $(<) -O$(@) $(IDIRS) 
    
    %.o: %.asmx
            $(SILENT_ASM)$(CROSS_COMPILE)asm $(C2ASM_FLAGS) $(<) -o$(@)
    
    %.o: %.asm
            $(SILENT_DEP)gcc -E -MM -xassembler-with-cpp $(<) -o$(@).dep
            $(SILENT_ASM)$(CROSS_COMPILE)nmcc $(ASM_FLAGS) $(<) -o$(@)
    
    $(TARGET).lib: $(OBJECTS)
            -$(SILENT_LIBRARIAN)$(CROSS_COMPILE)libr -c $(@) $(^) > /dev/null
    
    $(TARGET).abs: $(OBJECTS)
            -$(SILENT_LINKER)$(CROSS_COMPILE)linker  $(BUILDER_FLAGS) -o$(@) $(^) $(LIBS) $(LIBDIR)
    
    $(TARGET).dump: $(TARGET).abs
            -$(SILENT_NMDUMP)$(CROSS_COMPILE)nmdump -f $(^) > $(@)
    
    run: $(TARGET).abs
            edcltool -f run_nmc_code.edcl -i eth1
    
    clean:
            -$(SILENT_CLEAN)rm -f *.asmx; rm -f *.o; rm -f $(TARGET).abs $(TARGET).dump *.dep \
            *.ac *.map *~ *.abs *.lib
    


    Обращаю внимание на путь к библиотекек easynmc.lib – без нее у нас не заработают stdin/stdout, argc/argv и код возврата, так же в документации указано, что она должна идти перед библиотекой языка C.

    Второй по значимости файл – mb7707brd.cfg, для компилятора NeuroMatrix выполняет ту же роль, что для gcc LD скрипт. Здесь можно разложить секции по разным местам в памяти. Значения по умолчанию вполне вменяемы и можно их спокойно использовать:
    .cfg
    MEMORY
    {
            //-------------- NMC ---------------------------------------
            LOADERMEM:              at  0x00000000,         len = 0x00000200; 
            IM1:                    at  0x00000200,         len = 0x0000fe00; 
            IM3:                    at  0x00010000,         len = 0x00010000; 
            //------------- ARM ----------------------------------------
            INTERNAL_MEMORY0:       at      0x00040000,     len = 0x00010000;       // 256K-IM0 ARM         (ARM:0x00100000 0x0013ffff      0x4000(256kB))
            INTERNAL_MEMORY2:       at      0x20040000,     len = 0x00010000;       // 256K-IM2 ARM         (ARM:0x80100000 0x8013ffff      0x4000(256kB))
            //------------- DDR ----------------------------------------
            EXTERNAL_MEMORY0:       at      0x10000000,     len = 0x10000000;       // 16MB-EM0-DDR         (ARM:0x40000000 0x7fffffff) 
            EXTERNAL_MEMORY1:       at      0x30000000,     len = 0x10000000;       // 16MB-EM1-DDR         (ARM:0xc0000000 0xffffffff) 
    }
    
    
    SEGMENTS
    {
            code            : in IM3;
            data            : in IM1;
    }
    
    SECTIONS
    {
            .text                           : in code;
            .init                           : in code;
            .fini                           : in code;
            .data                           : in code;
            .bss                            : in code;
            .stack                          : in code;
            .heap                           : in code;
            .heap1                          : in code;
            .heap2                          : in code;
            .heap3                          : in code;
    }
    


    К слову о memory map – её можно взять на http://www.module.ru/mb7707/doc/K1879-memory-map.pdf

    После сборки командой make на выходе получаются два файла – hello.abs и hello.dump. abs файл – ELF с абсолютными адресами в адресном пространстве NMC. Его можно загрузить в банки IM1 или IM3, когда работаем из Linux на плате, так как за всю остальную память отвечает ядро Linux, в то время как при работе с edcl правила легче, и мы можем раскладывать секции по всему адресному пространству. dump – это дизассемблированный листинг, который может быть полезен тому, кто знает ассемблер под NMC.

    Движемся дальше, к проекту подключается один ассемблерный файл – easyconf.asm. Ассемблер здесь достаточно навороченный, с макросами и прочими радостями жизни. В easyconf лежит настройка stdio и аргументов, что делается буквально двумя макросами:
    .asm
    import from "easynmc/easynmc.mlb";
    /* Declare 2 circular buffers for stdio */
    const EASYNMC_IOBUFLEN = 128;
    EASYNMC_CBUF(".easynmc_stdin",  _easynmc_stdin_hdr,  _easynmc_stdin_data,  EASYNMC_IOBUFLEN);
    EASYNMC_CBUF(".easynmc_stdout", _easynmc_stdout_hdr, _easynmc_stdout_data, EASYNMC_IOBUFLEN);
    /* Reserve 128 32-bit words for arguments */
    EASYNMC_ARGS(128);
    


    Этот код резервирует место в abs файле для аргументов и кольцевых буферов, можно заметить, что на stdio выдается 128 байт, как и на аргументы. Если nmrun при запуске этой программы передать аргументов больше, чем 128 символов – nmrun выдаст ошибку.

    Наконец, рассмотрим main.c, который выглядит довольно просто:
    main.c
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <easynmc/easynmc.h>
    int main(int argc, char** argv)
    {
            printf("Hello world from NeuroMatrix! I am the NMC printf'ing to you!\n");
            return 0; 
    } 
    


    Это был стандартный проект hello world, теперь пришло время его модифицировать под нашу задачу. Поступим следующим образом, размер буфера задержки дадим где-то 200мс, с частотой дискретизации это будет около 1600 сэмплов. Округляем до ближайшего значения степени двойки и получаем 2048. Так как в плавающей точке NMC скорее всего не силен (хотя компилятор кушает float’ы), то сделаем все в целых числах, затухание сделаем битовым сдвигом.

    Получится что-то в духе этого:
    main.c
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <easynmc/easynmc.h>
    #define SIZE 2048
    static unsigned int delaybuf[SIZE];
    static unsigned int pos; 
    
    int main()
    {
    	while(1) { 
    		unsigned int in = getc();
    		unsigned int out = in + (delaybuf[pos] >> 2); 
    		if (out >255)
    			out = 255;
    		delaybuf[pos++] = in;
    		pos &= (SIZE -1);
    		putc(out);
    	}
    }
    


    Собираем, копируем abs на плату. По умолчанию у платы есть только одно ALSA устройство – HDMI. Мы же хотим вывод/ввод использовать от USB звуковой карты. Необходимо её название в ALSA, делается это достаточно просто, с помощью -L к arecord или aplay. В итоге должно получиться вот так:

    arecord -D default:CARD=Device | nmrun echo.abs | aplay -D default:CARD=Device
    

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

    Заключение


    Пожалуй, это всё на сегодня. Осталось сделать выводы. MB77.07 оставляет положительное впечатление, если, конечно, закрыть глаза на довольно слабоватый ARM. Перечислим общие плюсы и минусы:

    + Официально открытые исходники всего, что только можно, от загрузчика до IPL кода DSP процессора. На github от производителя чипа. Из других производителей такое существует разве что у Freescale и у Qualcomm (Code Aurora). Обычно все вываливают в лучшем случае в виде GPL source-drop в виде запакованных в rar tar’ов на ftp сервера, разгребать потом это – отдельное удовольствие. Еще, бывает, скидывают все огромной папкой вместе .git индексом.

    + DSP ядро, компилятор и инструментарий для него. Изначально продуман так, что бы новичку было работать очень просто, для старта хватит прочитанного по диагонали K&R. Особенно учитывая, что NMC в такой конфигурации может легко обеспечить жесткий realtime – для робототехников и станочников это просто находка.

    + Драйвера. Нельзя сказать, что идеал, но откровенной жути как у Allwinner (libnand), Rockchip (rk_fb, rknand), Mediatek (вообще всё) и им подобным замеченно не было. Везде стараются использовать стандартные подсистемы ядра. При наличии сообщества или желания разработчиков, большая часть может без проблем попасть в mainline. Проприетарные блобы в ядре отсутствуют.

    + Версия ядра. Сейчас есть 3.10 LTS, осенью разработчики пообщелаи подумать насчет следующего LTS. Для сравнения, в linux-sunxi коммьюнити ядро – 3.4, а в upstream практически нет мультимедиа. Rockchip только недавно выдавил из себя 3.10.x с очень большим скрипом и только для rk3288. Все попытки завести это дело популярном rk3188 провалилсь – не работает MMC контроллер. HardKernel ODROID сидит на 3.8.y linux-stable + ubuntu merge, хотя есть и движение в сторону поддержки в mainline.

    + Неубиваемость. Даже если физически убить NAND или отпаять, MB77.07 можно будет оживить и загрузить по EDCL. По этому, такая плата может оказаться полезной новичкам, желающим узнать, как на голом железе поднять загрузчик, операционную систему и т.д. Можно не бояться убить плату. Коротить ноги NAND в случае косяков как на RK3188 для перепрошивки загрузчика здесь не потребуется никогда.

    + deb-пакеты, репозитории и прочее. Многое сделано не дожидаясь появления коммьюнити, многое еще предстоит сделать.

    + Интересно разведено, все разъемы на одной стороне, намного удобнее чем на r-pi.

    — Цена. Этот факт, конечно, малину портит (pun intended)

    — Нет RTC. Для многих проектов может оказаться неважно, но может потребоваться. Плюс в системе первым приходится поднимать ntp.

    — Производительность. Да, 324MHz ARM1176 это не особенно весело. Отчасти компенсируется тем, что как ARM, так и NMC могут выполнять свой код из накристальной памяти, откуда работают просто реактивно, но тем не менее. Будем надеятся что дальше будет интереснее и Модуль не бросит OpenSource и мы увидим следующие их проекты, уже на более производительных решениях.

    — Сложность заказа. Тут уже чисто вопрос удобства и скорее вопрос к маркетингу, чем к инженерам. На сайте Модуля нехватает огромной жирной кнопки «купить» в полэкрана и моментальной оплаты через qiwi.

    Ссылки


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

    Подробнее
    Реклама
    Комментарии 53
    • +2
      Всегда было интересно узнать, по каким «алгоритмам» маркируют микросхемы, вот что например означают цифры/буквы в К1879ХБ1Я?
      • +5
        Вот подробное описание. Впрочем, индекса ХБ там нет, подозреваю, что тогда не было такого класса микросхем.
        • 0
          Я на аналогичный вопрос отвечал так же в их прошлой статье )). Смотрю автор статьи другой, но похоже из одной компании.
          • 0
            Нашёл тут, что «ХБ — для радио, телевидения, магнитофонов, дисплеев».
            • +1
              процессор на котором построена плата как раз предназначен для построения коробочек в духе этой www.module.ru/catalog/micro/dvb__tt2_fta/
              я не разработчик процессоров, по этому номенклатуру не могу подсказать.
            • +3
              И куда вы смотрите? мы не из одной компании, я вам даже более скажу, в данный момент — я свободен. Пожалуйста, перед голословными выражениями старайтесь хотя бы гуглить или открывать профили пользователей.
        • 0
          А по сравнению с чем цена кусается?

          И можно ли сказать что это изделие полностью сделанно на территории России, российскими фирмами? Я имею ввиду остальные части платы: ethernet карта, uart и прочее?
          • +6
            Плата стоит три тысячи рублей, за эту цену можно купить более производительные аналоги.

            Естественно что изделие не сделано полностью на территории РФ. Но отлажено и разработано — у нас, как раз это и важно. В случае какой Errata или другого ужаса есть кого пинать поименно. В случае с китайцами вас просто заигнорят (говорю это как работавший с китайцами).

            Я не очень хочу поддерживать никуда не ведущий разговор «мы все потеряли, наша электроника застряла в 80-тых», если вы ведете к нему. Эта плата — живой пример того как наши инженеры могут использовать как и зарубежные IP core (ARM ядро и т.д.), так и свои (DSP, DVB-*) и при этом все это вместе складывать и синтезировать в работающий процессор, который даже можно купить простым смертным.
            • 0
              Да при чем тут «мы все потеряли», я оцениваю для себя, это действительно Российская разработка или компановка запчастей.
              Для меня эта информация важна т.к. я думаю стоит ли тратить деньги или нет.
              На Российскую разработку я потрачу деньги, пусть она даже и будет сильно уступать аналогам. На компановку запчастей нет — этого добра у меня на работе хватает.
              • +1
                из обвяза здесь — пассивные компоненты, различные LDOшки и прочее питание, Ethernet от SMSC (теперь от Microchip, он их пару лет назад купил), ESD защита на HDMI порте с детекцией, DDR2 память. думаю, ответ очевиден, что без этих зарубежных компонентов — не взлетит.

                все таки это первый такой продукт, если у нас научатся производить вышеперечисленное — тогда да, возможно можно будет решить головную боль с зарубежными поставщиками.
                • +1
                  Ну вот есть у вас проект на QT, когда вы его реализуете — это будет Российская разработка?

                  Тут примерно аналогичная ситуация.
                  • –2
                    Не аналогичная.
                    Qt — это Open Source.
                    Если бы эта железка была бы так же основана на Open Source схемах и произведена полностью в России для меня это была бы так же полностью отечественной разработкой.
                    • +3
                      Ээ, связи открытости и Российскости ну уловил но ОК.

                      Вы пишите приложение под Windows. Это будет отечественной разработкой?

                      Не подумайте, что я пытаюсь тролить — просто достаточно смешно от людей, далеких от электроники слышать один и тот же вопрос.
                      Я думаю что не ошибусь, если скажу, что ни одно устройство в мире сложнее утюга не производится только на базе Open Source разработок и наработок одной нации/страны мира(разработка, производства, исходные компоненты).

                      ПС: вообще у всей российской электроники есть фатальный недостаток — она основывается на транзисторах, изобретенных на Загнивающем Западе.

              • 0
                ИМХО тут даже проц какой-то перемаркированный. Тут дело в том что компания российская = разработано в РФ = поддержка российская, а не в сделано/собрано в России.
                • 0
                  интересно, зачем тогда Модуль заказывал Promwad поддержку BSP? В общем — вы не правы как минимум по тому, что NeuroMatrix DSP разрабатывается уже пару лет точно, в данном процессоре его синтезировали. Еще из остальных своих IP core — кажется NAND контроллер полностью местный, плюс bootpath (IPL и прочее). Остальное, очевидно — покупные IP core (всякие ARM PL0xx в основном), из которых собирается процессор. Про то, насколько покупная, например, DVB часть — не знаю, для меня в данный момент это темный лес, но думаю что своя.

                  [sarcasm] Если вам интересно далее — позвоните в Модуль и спросите сколько ARM лицензий они купили и на какие именно ядра :)[/sarcasm]
                  • +2
                    А вы прежде чем язвить и обвинять в пятой колонне, лучше перечитайте:
                    Разработано в РФ, а не в сделано/собрано в России.

                    Ведь проц, понятно, тут сделали, но делают его по нашим маскам все равно в китае, как и плату. Потому для коммерческой компании самоубийственно тут делать, эта бы плата была золотой.
                    • +4
                      да я особенно и не язвлю по пятой колонне, ладно.

                      95% людей почему-то считают подход «разработал — напечатал в Китае» — это жутчайше плохо и вообще. не понимая, что альтернативы нету, совсем.

                      вполне очевидно, что все сделано именно так, процессор синтезирован здесь, испечен/запакован где-то в Азии, про плату не знаю, не спрашивал, возможно и у нас сделана, сейчас производителей плат расплодилось, и всё это запаковано в коробочки и поддерживается у нас. ASIC часть поддерживается Модулем, программная часть — Promwad и частично тоже Модулем.
                  • 0
                    Откуда вы взяли это свое IMHO? Никогда не пробовали интересоваться вопросом, но решили, что своего процессора в России разработать не могут?
                    «Модуль» делает процессоры давно и успешно, только не совсем для коммерческого рынка. Очень хорошо, что они и на него наконец вышли.
                    И предположение, что делают в Китае, может быть очень далеко от истины. Во-первых, такой процессор вполне можно изготовить в России, во-вторых, с не меньшей, чем Китай вероятностью, это могут быть Тайвань, Сингапур, Малайзия, Израиль или Германия.
                • 0
                  Объясните мне, попроще, что такого страшного в загрузчике, что существует такая необходимость в таких 'палках в колеса'?
                  Rockchip вообще предоставляет NAND только в виде закрытого модуля rknand.ko, исходников которого не дают даже под NDA партнерам компании

                  Из адекватных причин мне на ум приходит только — 'в загрузчиках в оборудовании этих поставщиков массово встраивается софт, который не хотят никому показывать, потому как оно сильно не понравится этому большинству'.
                  • +4
                    или «там все написано настолько через Ж, что если мы вам покажем исходники, вы у нас больше ничего не купите никогда из страха что оно и аппаратно такое же»
                    • +4
                      Если верить тому, что я слышал, то под NDA, чаще всего, могут предоставить данные, которые являются некой коммерческой/конкурентной тайной, типа ноу-хау всяких, а вот если не дают даже под NDA, то очень часто причина куда прозаичнее — там есть «позаимствованный» код, который используется без какой-либо лицензии, в итоге никто это рискует давать даже под NDA чтобы «как бы чего не случилось».
                    • 0
                      вы удивитесь, но раньше libnand у allwinner был открытым, и код там конечно та еще помойка — но он работал и его даже чуть-чуть подрихтовали в самых ужасных местах, а потом в следующей версии ядра allwinner закрыл исходники и распространяет только .ko или .o для линковки. анализ этих файлов показывает, что изменилось там практически ничего, но зачем-то код закрыли.
                    • +3
                      Отсутствует байтовая адресация. sizeof(char) == 4

                      Так не бывает, вы где-то ошиблись. Возможно, там char — 32-битный, но sizeof(char) == 1 с точки зрения языка С всегда на любой платформе.
                      • 0
                        Может быть формулировка sizeof(char) не совсем корректная, но суть которую хотел донести автор:
                        char* ptr = 0x00000004;
                        ptr++;
                        printf("%x", ptr);
                        Вывод будет 0x00000008
                        Впрочем не удивляюсь если компилятор явно имеет минимальный размер типа 4 байта.
                        • +2
                          дойду до платы, сделаю printf(sizeof()) что бы было понятнее.
                          • 0
                            см ниже.
                          • +2
                            действительно ошибся.

                            root@shadow:~# nmrun ./helloworld.abs 
                            Application now started, hit CTRL+C to stop it
                            Hello world from NeuroMatrix! I am the NMC printf'ing to you!
                            sizeof(char)  == 1
                            sizeof(short) == 1
                            sizeof(int)   == 1
                            

                            printf("Hello world from NeuroMatrix! I am the NMC printf'ing to you!\n");
                            printf("sizeof(char)  == %d\n", sizeof(char));
                            printf("sizeof(short) == %d\n", sizeof(short));
                            printf("sizeof(int)   == %d\n", sizeof(int));
                            
                            • 0
                              Не хочу показаться занудой, но можно посмотреть еще вывод:
                              char* ptr = <тут можно выделение памяти в куче воткнуть>;
                              ptr++;
                              printf("%x", ptr);
                              


                              Just a curious…
                              • +1
                                char* t = malloc(128);
                                printf("==> %x\n", t);
                                t++;
                                printf("==> %x\n", t);
                                

                                довольно очевидно выводит:
                                ==> 19c80
                                ==> 19c81
                                


                                что бы malloc отработал, нужно в Makefile указать -heap размер кучи, в примерах он выставлен в 0.
                          • 0
                            Спасибо за статью. Прямо передо мной лежит МВ 77.07, все руки не дойдут поковырять…
                            • 0
                              У меня несколько вопросов:
                              1) Возможно ли использовать U-Boot?
                              2) Трудно ли подготовить ядро и root-fs для загрузки?
                              3) Возможна ли загрузка через nfs?
                              • 0
                                Вы, видимо, не слишком усидчиво статью читали.
                                1. Есть mboot, форк u-boot, который поддерживает все функции и несколько новых.
                                2. Я не автор статьи, но уверен, что проще, чем у других.
                                3. Почему бы и нет, если ядро настроите.

                                Вообще, я считаю, это что-то вроде прорыва, без преувеличения. Полный open-source, DSP без NDA, нормальные модули ядра. Правда, хотелось бы, все-таки, CPU поновее и пошустрее.
                                • 0
                                  Мне показалось прорывной часть с DSP доступным по cmdline, без хитрых хитростей с его использованием.
                                • 0
                                  1) зачем? mboot — тот же u-boot, такие же команды, только староват чуть-чуть. проблемы возникнут если вам захочется из загрузчика работать с чем-то, что добавили только в самых новых версиях u-boot.
                                  2) ядро стандартное до ужаса же — ничего не требуется готовить, только посмотреть как edcl скрипты работают
                                  3) см. выше, ядро стандартное. плюс, в моем dmesg как раз выполняется загрузка ядра по сети, rootfs в mtd. в общем — ничего не мешает.
                                • +1
                                  По ссылке на продукт при выключенном JS ничего не показывается. Как же Graceful degrade леать?

                                  ЦЕНА 3280 руб + НДС вроде бы нормальная, не миллионов тыщи.
                                  • 0
                                    Сайт кажется кому-то аутсорсят, внизу где-то плашка была от аутсорсера. Ругать туда.

                                    Цена нормальная, но другие более производительные платы в этот же ценовой диапазон входят, вот и получается конкуренция. Скинуть бы тысячу — вот тогда было бы просто отлично.
                                    • 0
                                      Когда я брал Neo Freerunner он стоил порядка 12 000р. Насколько я помню разошлись все коробки. А тут мало того что открытое так еще и относительно местное.
                                      • 0
                                        к сожалению, я не в курсе про количество коробок у Модуля с этой платой. Я взял одну из первых довольно давно, но в тот момент состояние софта было ужасным для продажи в руки. сейчас все допилили и залили на github.
                                    • 0
                                      3280 рублей как посмотреть. За те же деньги можно взять плату на i.MX5(6) даже отечественного (starterkit.ru) производства. С доставкой на руки. Открытость компонентов и их поддержка даже в mainline linux kernel на уровне не хуже чем у этой платы, местами даже лучше. Да дсп это круто и вообще кул, но ортогональность к существующим решениям (TI, AD) ставить под небольшое сомнение. Также минусом данных камней является сложность покупки частными лицами (сам году так в 2006 пробовал закупать у них партию на тогдашних первенцах — NM6403).

                                      Так что пока подобный SoC вызывает больше вопросов и сомнений чем ответов.
                                      • +1
                                        только не starterkit, совсем плохая у них репутация, по прошлым платам. это конечно же ИМХО и может быть сейчас все уже по-другому.
                                        imx сам люблю, много его дебажил.
                                        • 0
                                          совсем плохая у них репутация, по прошлым платам.
                                          Офф топик поэтому если можно то в личку. А так да.

                                          И забыл добавить если брать промышленный вариант для фрискейла/ти и модуля, лоб в лоб сравнивать по ценам то «камешки получаются просто золотые».
                                    • 0
                                      Для использования во встраиваемых системах в наших краях очень большое значение имеет возможность работы при пониженных температурах. Не подскажете случайно как у этой платы обстоят дела с температурным диапазоном работы?
                                      • +1
                                        в даташитах не вижу ответа на этот вопрос, напишите в Модуль с своим предполагаемым применением, ответят.
                                      • 0
                                        AT91RM9200 накристальной памяти было всего 4К
                                        не 4К а 16К, и этого хватало чтобы напрямую загружать ядро линукса с SD карты, а не только инициализировать периферию и озу.
                                        • +1
                                          Слова К1879ХБ1Я и HDMI на одной микросхеме разрывают мозг. Почему никак не отойдем от СССР-ких ГОСТов в пользу чего либо более благозвучного?
                                          • 0
                                            А смысл отходить от того что проверенно временем и что позволяет спокойно идентифицировать серию и тип?
                                            Лучше придерживаться одного стандарта, чем прыгать туда сюда.
                                            • +1
                                              Потому что основной заказчик российских микросхем — все еще госструктуры, которым такая номенклатура удобнее, а на благозвучность наплевать. Вот когда будут обычные пользователи покупать много, тогда и об их удобстве подумают.
                                              Хотя, с третьей стороны, посмотрите на названия микросхем Analog Devices или Texas Instruments — там точно такие же огромные цифровые индексы. Видимо все-таки удобнее видеть не красивое название, а цифро-буквенный код, который что-то говорит о функционале микросхемы.
                                              • 0
                                                Ну хотя бы не использовать буквы которых нет в латиннице, мне кажется было бы неплохой идеей. По аналогии с автомобильными номерами. Если бы кто-то из-за бугра хотя бы теоретически заинтересовался данной микросхемой, ему было бы проще пользоваться поиском. Хотя конечно все это хипстерской брюзжание. Только суровые ХБ1Я-бы, только лампы, только хардкор!
                                                • 0
                                                  У меня наверное странные представления о мире и взаимоотношениях, но мне кажется, что если иностранцам понадобится покупать этот продукт (или узнавать какую-либо другую информацию о нем), то пусть уж напрягутся, научатся и введут в поиск кириллицу, ведь это им нужно, а не нам. Зачем же нам заранее под них прогибаться? А нам удобна и привычна своя маркировка.
                                                • +1
                                                  Просто товарищ правил маркировки не знает вот и всё. HDMI и ARM это просто эмблемы и торговые марки которые размещаются на чипах определённых размеров по договорённости (подобное можно проследить на семействе STM32). А вот K1879ХБ1Я это как раз маркировка.

                                                  Вот к примеру у меня сейчас i.MX6 Duo — собственно это его название, а вот маркировка у него — MCIMX6D5EYM10AC. и это ещё короткая маркировка. Есть всякие пометки и ревизии.

                                                  А из неё можно узнать не только функционал но и условия эксплуатации, версию прошивки, багревизию и много чего полезного включая возраст микросхемы.
                                              • 0
                                                Бело-черная цветовая гамма текстолита красиво выглядит.
                                                • +2
                                                  Поправочка: начиная с версии v2014.07.0 barebox официально поддерживает плату MB 77.07 (см. lists.infradead.org/pipermail/barebox/2014-July/019871.html).

                                                  • 0
                                                    Сколько кушает этот товарищ никто не измерял?

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