2018년 11월 29일 목요일

U-boot / Kernel build - powered by NanoPi NEO

AllWinner 사에서 만든 프로토타이핑 보드 NanoPi를 이용해 나만의 IoT 서버를 빌드해보자


준비물


  1. NanoPi NEO
    • https://www.friendlyarm.com/index.php?route=product/product&product_id=132
    • 세상에! 2만원도 안하는 가격에 (아두이노 정품 보드보다도 훨씬 싸다!) 무려 Quad core ARM 보드를 구할 수 있다.
    • 다양한 레퍼런스와 초보자 친화적인 개발환경이 목적이 아니라면 라즈베리파이보다 훨씬 좋은 솔루션이 될 수 있겠다. (HDMI 단자가 없는 것은 함정 :))
  2. Ubuntu 18.04
    • U-boot과 Linux Kernel을 빌드하기 위해서는 리눅스 환경이 필수적이다. 그 중에서도 설치가 가장 쉬운 Ubuntu 최신 버전으로 시작해보자.
  3. Cross-compiler
    • Pre-built compiler (특히 arm 계열의)는 수많은 종류가 있을테고, 취향에 따라서 컴파일러도 자신의 손으로 빌드해보는 재미(?)를 느껴보고 싶다면 옵션은 더욱 다양해진다. 하지만, 누군가가 추천해주신 pre-built compiler가 있다면 수많은 옵션을 테스트해보고 시행착오를 겪는 수고스러움을 건너 뛸 수 있다 :)
    • https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/
  4. 소스코드
    • 고맙게도 NanoPi 보드류는 BSP 지원이 굉장히 잘 되고 있는 편이다. Pre-built image도 잘 구비가 되어있고, 소스코드도 Vendor provided BSP 뿐만 아니라 *Mainline 에서도 잘 지원되고 있다.
    • [제조사 제공 소스코드 및 가이드]
      • http://wiki.friendlyarm.com/wiki/index.php/Building_U-boot_and_Linux_for_H5/H3/H2%2B
      • https://github.com/friendlyarm/u-boot
      • https://github.com/friendlyarm/linux
    • [Pre-built image]
      • http://download.friendlyarm.com/nanopineo


환경설정

  1. 이제 언제 봐도 생소한 linux를 설치했으니 빌드환경 부터 갖춰야겠다.
    • 한 줄 인스톨 환경 셋업 스크립트
    • sudo apt-get install build-essential flex bison swig python-dev python3-dev
    • 행복한 코딩을 위해 깨알같은 유틸리티 설치도 빼먹지 말자
    • sudo apt-get install vim wget
  2. 크로스컴파일러 툴체인을 설치한다.
  3. wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf.tar.xz
    tar xvf gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf.tar.xz
    sudo mkdir /opt/toolchains
    sudo mv gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf /opt/toolchains/arm-linux-gnueabihf
    echo export PATH=\$PATH:/opt/toolchains/arm-linux-gnueabihf/bin/ >> ~/.bashrc
    echo export ARCH=arm >> ~/.bashrc
    echo export CROSS_COMPILE=arm-linux-gnueabihf- >> ~/.bashrc
    
    • 위와 같이 입력하고 터미널을 다시 실행하면 번거로운 환경변수 작업이 다 적용되어 편하게 작업할 수 있다.


컴파일

  1. U-boot 소스코드를 받고 빌드해보자
  2. wget ftp://ftp.denx.de/pub/u-boot/u-boot-2018.11.tar.bz2
    tar xvf u-boot-2018.11.tar.bz2
    cd u-boot-2018.11
    make nanopi_neo_defconfig
    make
    
    • 읭? 끝났네? mainline의 위력을 실감하는 순간이다. 그런데... 너무 공부가 안되는건 함정.
    • 그래서 뭐? :( 뭐가 된건지 모르겠다. 나중에 정리해보자.
    • 모든 컴파일 작업이 완료되면 u-boot로 시작하는 여러 개의 파일이 생성되는데, 최종 결과물은 u-boot-sunxi-with-spl.bin 파일이다. 이걸 아래의 명령으로 SD 카드의 특정 위치에 기록하면 된다(고 한다).
  3. Kernel 소스코드를 받고 빌드해보자
  4. wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.3.tar.xz
    tar xvf linux-4.19.3.tar.xz
    cd linux-4.19.3
    make sunxi_defconfig
    make zImage dtbs
    
    • 아 살짝 당황했다. Kernel에는 neopi가 없다;; 그런데 친절한 friendly arm wiki를 보니 sunxi_defconfig를 사용하면 된다는구나.
    • *Device tree 라는 시스템 덕에 같은 CPU family라면 동일한 kernel image로 구동할 수 있다. 보드 마다 다른 설정은 모두 *.dtb라는 파일에 기록되어 있다. 따라서 kernel image는 CPU family에서 공통으로 사용하는 파일을 사용하며, 앞서 살펴본 u-boot image파일과 비슷한 이름의 .dtb 파일을 찾아서 함께 사용하면 된다.
    • 이것도 마찬가지로 간단하게 컴파일 작업이 완료(시간은 무척 오래걸린다...)


부팅디스크 만들기

  1. 우선 파티션을 나눠야한다. 파티션 툴은 아주 오래전 DOS 시절 부터 친숙한 fdisk를 이용한다. 그간 진화한 fdisk의 복잡한 기능을 보니 세월이 느껴진다.
  2. fdisk /dev/sdb
    
    • fdisk의 기능도 하나 하나 익혀보고 싶지만, 당장 필요한 d, n, t, w 기능만 알아보자.
      • d: 파티션을 지운다. 별 생각 없이 d <enter>만 하면 차례 대로 선택지를 보여준다.
      • n: 파티션을 생성한다. 마찬가지로 단계별 질의에 답하면 된다.
      • t: 파티션의 속성(type)을 변경한다. 많은 종류의 타입이 있지만, 우리가 사용할 속성은 6: FAT16 (boot 파티션 커널 이미지가 들어갈 자리) 83: Linux (rootfs, 즉 root file system이 들어갈 자리) 두 가지 뿐이다.
      • p: 파티션 구성을 보여준다.
      • w: 파티션 구성을 저장한다. (돌이킬 수 없다-)
    • TIP
      • First/last sector 위치를 물어보는데 하나의 섹터가 512byte이니, 원래 대로라면 원하는 사이즈를 만들기 위해서는 차분히 계산을 해 넣어야겠지만 +100M와 같이 단위와 + 를 조합해 넣어주면 복잡한 계산 없이 간단히 해결된다.
      • lsblk명령을 사용하면 나눠진 파티션을 일목요연하게 정리해 보여준다. 좀더 자세한 내용이 필요한 경우 fdisk -l 명령을 사용한다.
  3. 파티션을 나누고 나면 부트섹터에는 u-boot를, 첫번째 마스터 파티션에는 kernel을, 그리고 마지막 파티션에는 root file system을 차례로 올리면 된다.
    • 첫번째. u-boot
    • sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=1024 seek=8
      sudo sync && eject /dev/sdb
      • 여기에서는 system disk 하나만 설치되어 있고, 외장형 저장 장치도 MMC card reader 하나만 있을 때의 예를 들었다. 시스템 구성에 따라 /dev/sdc 위치에 설치해야할 수도 있다. MMC카드의 device path를 꼭 확인해보자
      • bs: block size, seek: # of blocks from origin -> 따라서 위 명령은 8k위치에서 부터 u-boot image를 기록하겠다는 뜻이다. CPU 구성에 따라 다르다고 하니 다른 시스템 구성에서 사용 할 경우에는 각각의 시스템에 맞는 위치에 기록해야한다.
    • 두번째. kernel
    • sudo mkfs.fat /dev/sdb1
      sudo mkdir /media/boot
      sudo mount /dev/sdb1 /media/boot
      sudo cp arch/arm/boot/zImage /media/boot/
      sudo cp arch/arm/boot/dts/sun8i-*-nanopi-*.dtb /media/boot/
      
      • Kernel의 경우 단순한 file system에 몇 개의 이미지 파일을 넣어두면 부트로더에서 읽어서 일련의 과정을 수행해주게 되어있다. FAT16 파일은 윈도우에서도 확인해볼 수 있는데, 어떤 환경에서건 그저 필요한 파일들을 복사해주면 된다. 이를 위해 mkfs.fat 등의 유틸리티를 사용해 포멧을 해주는 것을 잊지 말자.
      • 필요한 파일은 zImage (또는 uImage, Image 등의 kernel image file), *.btb 파일이다. 시스템에 맞는 파일만 복사해주면 된다.
      • 주)
    • 커널의 모듈 업데이트는 다음과 같이 root file system에 파일을 복사하면 된다. 이게 올바른 방법인지는 잘 모르겠다 :(
    • make modules
      make modules_install INSTALL_MOD_PATH=/media/rootfs/
      • 여기에서는 rootfs라는 볼륨이 있다고 가정했는데, 이것도 boot 볼륨과 마찬가지로 포멧하고, 필요한 파일을 적재하고 마운트도 해야한다.
    • 세번째. root file system
    • sudo dd if=rootfs.ext4 of=/dev/sdb2 bs=1M
      sudo sync && eject /dev/sdb
      • rootfs.ext4 라는 파일 이름으로 미리 구성된 root file system 이미지가 있다면 위와 같이 간단한 명령만으로 만들 수 있는데... 나만의 새로운 root file system 이미지를 만드는 방법은 다음 기회에 다시 알아보기로 한다.

완료

U-Boot SPL 2018.11 (Nov 29 2018 - 22:56:51 +0900)
DRAM: 256 MiB
Trying to boot from MMC1


U-Boot 2018.11 (Nov 29 2018 - 22:56:51 +0900) Allwinner Technology

CPU:   Allwinner H3 (SUN8I 1680)
Model: FriendlyARM NanoPi NEO
DRAM:  256 MiB
MMC:   SUNXI SD/MMC: 0
Loading Environment from FAT... *** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   phy interface0

Error: ethernet@1c30000 address not set.
eth-1: ethernet@1c30000
starting USB...
USB0:   USB EHCI 1.00
USB1:   USB OHCI 1.0
USB2:   USB EHCI 1.00
USB3:   USB OHCI 1.0
scanning bus 0 for devices... 1 USB Device(s) found
scanning bus 2 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
Hit any key to stop autoboot:  0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found /extlinux/extlinux.conf
Retrieving file: /extlinux/extlinux.conf
183 bytes read in 4 ms (43.9 KiB/s)
Boot menu
1:      Default
Enter choice: 1:        Default
Retrieving file: /zImage
4032528 bytes read in 190 ms (20.2 MiB/s)
append: root=/dev/mmcblk0p2 console=ttyS0,115200n8
Retrieving file: /sun8i-h3-nanopi-neo.dtb
18907 bytes read in 3 ms (6 MiB/s)
## Flattened Device Tree blob at 43000000
   Booting using the fdt blob at 0x43000000
EHCI failed to shut down host controller.
EHCI failed to shut down host controller.
   Loading Device Tree to 49ff8000, end 49fff9da ... OK

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.19.3 (wsahn@wsahn-vm) (gcc version 7.3.1 20180425 [linaro-7.3-2018.05 revision d29120a424ecfbc167ef90065c0eeb7f91977701] (Linaro GCC 7.3-2018.05)) #1 SMP Thu Nov 29 23:42:18 KST 2018
[    0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c5387d
[    0.000000] CPU: div instructions available: patching division code
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] OF: fdt: Machine model: FriendlyARM NanoPi NEO
[    0.000000] Memory policy: Data cache writealloc
[    0.000000] cma: Reserved 16 MiB at 0x4ec00000
[    0.000000] psci: probing for conduit method from DT.
[    0.000000] psci: Using PSCI v0.1 Function IDs from DT
[    0.000000] random: get_random_bytes called from start_kernel+0xa0/0x3f8 with crng_init=0
[    0.000000] percpu: Embedded 16 pages/cpu @(ptrval) s34572 r8192 d22772 u65536
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 65024
[    0.000000] Kernel command line: root=/dev/mmcblk0p2 console=ttyS0,115200n8
[    0.000000] Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
[    0.000000] Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
[    0.000000] Memory: 233228K/262144K available (6144K kernel code, 419K rwdata, 1520K rodata, 1024K init, 242K bss, 12532K reserved, 16384K cma-reserved, 0K highmem)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
[    0.000000]     vmalloc : 0xd0800000 - 0xff800000   ( 752 MB)
[    0.000000]     lowmem  : 0xc0000000 - 0xd0000000   ( 256 MB)
[    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)
[    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)
[    0.000000]       .text : 0x(ptrval) - 0x(ptrval)   (7136 kB)
[    0.000000]       .init : 0x(ptrval) - 0x(ptrval)   (1024 kB)
[    0.000000]       .data : 0x(ptrval) - 0x(ptrval)   ( 420 kB)
[    0.000000]        .bss : 0x(ptrval) - 0x(ptrval)   ( 243 kB)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
[    0.000000] rcu: Hierarchical RCU implementation.
[    0.000000] rcu:     RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.
[    0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
[    0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
[    0.000000] GIC: Using split EOI/Deactivate mode
[    0.000000] clocksource: timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
[    0.000000] arch_timer: cp15 timer(s) running at 24.00MHz (phys).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns
[    0.000007] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns
[    0.000018] Switching to timer-based delay loop, resolution 41ns
[    0.000180] Console: colour dummy device 80x30
[    0.000230] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=240000)
[    0.000243] pid_max: default: 32768 minimum: 301
[    0.000387] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    0.000400] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    0.001011] CPU: Testing write buffer coherency: ok
[    0.001423] /cpus/cpu@0 missing clock-frequency property
[    0.001445] /cpus/cpu@1 missing clock-frequency property
[    0.001464] /cpus/cpu@2 missing clock-frequency property
[    0.001483] /cpus/cpu@3 missing clock-frequency property
[    0.001496] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[    0.001986] Setting up static identity map for 0x40100000 - 0x40100060
[    0.002134] rcu: Hierarchical SRCU implementation.
[    0.002811] smp: Bringing up secondary CPUs ...
[    0.013543] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
[    0.024366] CPU2: thread -1, cpu 2, socket 0, mpidr 80000002
[    0.035096] CPU3: thread -1, cpu 3, socket 0, mpidr 80000003
[    0.035176] smp: Brought up 1 node, 4 CPUs
[    0.035198] SMP: Total of 4 processors activated (192.00 BogoMIPS).
[    0.035204] CPU: All CPU(s) started in HYP mode.
[    0.035210] CPU: Virtualization extensions available.
[    0.036036] devtmpfs: initialized
[    0.040169] VFP support v0.3: implementor 41 architecture 2 part 30 variant 7 rev 5
[    0.040381] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.040403] futex hash table entries: 1024 (order: 4, 65536 bytes)
[    0.041241] pinctrl core: initialized pinctrl subsystem
[    0.042143] NET: Registered protocol family 16
[    0.043481] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    0.044480] hw-breakpoint: found 5 (+1 reserved) breakpoint and 4 watchpoint registers.
[    0.044493] hw-breakpoint: maximum watchpoint size is 8 bytes.
[    0.056651] SCSI subsystem initialized
[    0.057143] usbcore: registered new interface driver usbfs
[    0.057188] usbcore: registered new interface driver hub
[    0.057252] usbcore: registered new device driver usb
[    0.057440] pps_core: LinuxPPS API ver. 1 registered
[    0.057448] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti 
[    0.057467] PTP clock support registered
[    0.057676] Advanced Linux Sound Architecture Driver Initialized.
[    0.058447] clocksource: Switched to clocksource arch_sys_counter
[    0.065647] NET: Registered protocol family 2
[    0.066146] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes)
[    0.066183] TCP established hash table entries: 2048 (order: 1, 8192 bytes)
[    0.066222] TCP bind hash table entries: 2048 (order: 2, 16384 bytes)
[    0.066258] TCP: Hash tables configured (established 2048 bind 2048)
[    0.066366] UDP hash table entries: 256 (order: 1, 8192 bytes)
[    0.066413] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
[    0.066600] NET: Registered protocol family 1
[    0.067089] RPC: Registered named UNIX socket transport module.
[    0.067101] RPC: Registered udp transport module.
[    0.067107] RPC: Registered tcp transport module.
[    0.067113] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    0.068813] workingset: timestamp_bits=30 max_order=16 bucket_order=0
[    0.075211] NFS: Registering the id_resolver key type
[    0.075251] Key type id_resolver registered
[    0.075258] Key type id_legacy registered
[    0.076230] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 248)
[    0.076245] io scheduler noop registered
[    0.076253] io scheduler deadline registered
[    0.076404] io scheduler cfq registered (default)
[    0.076413] io scheduler mq-deadline registered
[    0.076420] io scheduler kyber registered
[    0.077168] sun4i-usb-phy 1c19400.phy: Couldn't request ID GPIO
[    0.080857] sun8i-h3-pinctrl 1c20800.pinctrl: initialized sunXi PIO driver
[    0.082428] sun8i-h3-r-pinctrl 1f02c00.pinctrl: initialized sunXi PIO driver
[    0.130453] Serial: 8250/16550 driver, 8 ports, IRQ sharing disabled
[    0.132794] console [ttyS0] disabled
[    0.152956] 1c28000.serial: ttyS0 at MMIO 0x1c28000 (irq = 35, base_baud = 1500000) is a U6_16550A
[    0.796602] console [ttyS0] enabled
[    0.802999] libphy: Fixed MDIO Bus: probed
[    0.807101] CAN device driver interface
[    0.811443] dwmac-sun8i 1c30000.ethernet: PTP uses main clock
[    0.817217] dwmac-sun8i 1c30000.ethernet: No regulator found
[    0.823276] dwmac-sun8i 1c30000.ethernet: Current syscon value is not the default 148000 (expect 58000)
[    0.832708] dwmac-sun8i 1c30000.ethernet: No HW DMA feature register supported
[    0.839936] dwmac-sun8i 1c30000.ethernet: RX Checksum Offload Engine supported
[    0.847148] dwmac-sun8i 1c30000.ethernet: COE Type 2
[    0.852118] dwmac-sun8i 1c30000.ethernet: TX Checksum insertion supported
[    0.858910] dwmac-sun8i 1c30000.ethernet: Normal descriptors
[    0.864562] dwmac-sun8i 1c30000.ethernet: Chain mode enabled
[    0.870379] libphy: stmmac: probed
[    0.874265] dwmac-sun8i 1c30000.ethernet: Found internal PHY node
[    0.880486] libphy: mdio_mux: probed
[    0.884073] dwmac-sun8i 1c30000.ethernet: Switch mux to internal PHY
[    0.890458] dwmac-sun8i 1c30000.ethernet: Powering internal PHY
[    0.897370] libphy: mdio_mux: probed
[    0.901286] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    0.907806] ehci-platform: EHCI generic platform driver
[    0.913207] ehci-platform 1c1a000.usb: EHCI Host Controller
[    0.918812] ehci-platform 1c1a000.usb: new USB bus registered, assigned bus number 1
[    0.926870] ehci-platform 1c1a000.usb: irq 26, io mem 0x01c1a000
[    0.968437] ehci-platform 1c1a000.usb: USB 2.0 started, EHCI 1.00
[    0.975260] hub 1-0:1.0: USB hub found
[    0.979059] hub 1-0:1.0: 1 port detected
[    0.983600] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[    0.989815] ohci-platform: OHCI generic platform driver
[    0.995182] ohci-platform 1c1a400.usb: Generic Platform OHCI controller
[    1.001821] ohci-platform 1c1a400.usb: new USB bus registered, assigned bus number 2
[    1.009747] ohci-platform 1c1a400.usb: irq 27, io mem 0x01c1a400
[    1.083094] hub 2-0:1.0: USB hub found
[    1.086870] hub 2-0:1.0: 1 port detected
[    1.094516] sun6i-rtc 1f00000.rtc: rtc core: registered rtc-sun6i as rtc0
[    1.101326] sun6i-rtc 1f00000.rtc: RTC enabled
[    1.105922] i2c /dev entries driver
[    1.110343] sunxi-wdt 1c20ca0.watchdog: Watchdog enabled (timeout=16 sec, nowayout=0)
[    1.119628] sunxi-mmc 1c0f000.mmc: Linked as a consumer to regulator.2
[    1.126719] sunxi-mmc 1c0f000.mmc: Got CD GPIO
[    1.156525] sunxi-mmc 1c0f000.mmc: initialized, max. request size: 16384 KB
[    1.164723] usbcore: registered new interface driver usbhid
[    1.170322] usbhid: USB HID core driver
[    1.175392] NET: Registered protocol family 17
[    1.179879] can: controller area network core (rev 20170425 abi 9)
[    1.186141] NET: Registered protocol family 29
[    1.190596] can: raw protocol (rev 20170425)
[    1.194863] can: broadcast manager protocol (rev 20170425 t)
[    1.200536] can: netlink gateway (rev 20170425) max_hops=1
[    1.206231] Key type dns_resolver registered
[    1.210590] Registering SWP/SWPB emulation handler
[    1.224181] ehci-platform 1c1d000.usb: EHCI Host Controller
[    1.229847] ehci-platform 1c1d000.usb: new USB bus registered, assigned bus number 3
[    1.238044] ehci-platform 1c1d000.usb: irq 28, io mem 0x01c1d000
[    1.266176] mmc0: host does not support reading read-only switch, assuming write-enable
[    1.268438] ehci-platform 1c1d000.usb: USB 2.0 started, EHCI 1.00
[    1.279662] mmc0: new high speed SDHC card at address aaaa
[    1.281101] hub 3-0:1.0: USB hub found
[    1.286843] mmcblk0: mmc0:aaaa SU04G 3.69 GiB
[    1.289665] hub 3-0:1.0: 1 port detected
[    1.299097] ohci-platform 1c1d400.usb: Generic Platform OHCI controller
[    1.301341]  mmcblk0: p1 p2
[    1.305745] ohci-platform 1c1d400.usb: new USB bus registered, assigned bus number 4
[    1.316708] ohci-platform 1c1d400.usb: irq 29, io mem 0x01c1d400
[    1.393178] hub 4-0:1.0: USB hub found
[    1.396971] hub 4-0:1.0: 1 port detected
[    1.401783] usb_phy_generic usb_phy_generic.0.auto: usb_phy_generic.0.auto supply vcc not found, using dummy regulator
[    1.412607] usb_phy_generic usb_phy_generic.0.auto: Linked as a consumer to regulator.0
[    1.421270] sun6i-rtc 1f00000.rtc: setting system clock to 1970-01-01 00:00:09 UTC (9)
[    1.429492] vcc3v0: disabling
[    1.432464] vcc5v0: disabling
[    1.435430] ALSA device list:
[    1.438391]   No soundcards found.
[    1.450949] EXT4-fs (mmcblk0p2): INFO: recovery required on readonly filesystem
[    1.458257] EXT4-fs (mmcblk0p2): write access will be enabled during recovery
[    1.570369] random: fast init done
[    1.612361] EXT4-fs (mmcblk0p2): recovery complete
[    1.620771] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
[    1.628929] VFS: Mounted root (ext4 filesystem) readonly on device 179:2.
[    1.637633] devtmpfs: mounted
[    1.641765] Freeing unused kernel memory: 1024K
[    1.646442] Run /sbin/init as init process
[    1.758717] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
Starting logging: OK
Initializing random number generator... [    1.874008] random: dd: uninitialized urandom read (512 bytes read)
done.

Suprema Academy
s-academy login:

---

Mainline 이란?

  • 오픈소스 운영체제 개발 쪽에서는 메인스트림에 해당하는 오픈소스 브랜치를 메인라인이라고 부르는 듯 하다.
  • 코드가 굉장히 정리가 잘 되어 있고, 몇 가지 요건만 갖추면 오류없는 깨끗한 빌드 경험을 할 수 있다.
  •  [U-boot] http://linux-sunxi.org/Mainline_U-Boot
  •  [Kernel] http://linux-sunxi.org/Mainline_Kernel_Howto

zImage / Image / uImage ?

  • Kernel image는 타겟 이름에 따라 저장 속성이 정해진다. zImage는 압축된 것. 나머지는 차이를 모르겠...

dtb ?

  • Device tree blob: 과거의 kernel은 동일한 CPU에 대해 장치 드라이버는 공용으로 사용했지만, 보드마다 구성이 달라 새로운 보드를 개발하면 kernel을 항상 다시 컴파일해야하는 문제가 있었다. --CPU pin을 uart/gpio/spi/i2c 등 앞서 사용한 보드와 다른 목적으로 사용하려면 소스코드에 반영하고 빌드해야 함, 마찬가지 이유로 memory/static storage 증설 시 address mapping을 위해 다시 빌드-- Bootloader 또한 하드웨어에 맞게 다시 빌드해서 사용해야하며, bootloader가 kernel에 하드웨어 정보를 전달하는 데도 유연하지 못한 구조였다. 현대의 kernel system에서는 device tree라는 별도의 구조체를 정의하여 이런 문제를 해결하고자 한다.
    • DTB: Device tree blob
    • DTC: Device tree compiler
    • DTS: Device tree source(specification)
    • DTB = DTC(DTS)
  • 참고자료
    • https://en.wikipedia.org/wiki/Device_tree
    • https://elinux.org/images/f/f9/Petazzoni-device-tree-dummies_0.pdf
    • http://selfish-developer.com/entry/%EB%94%94%EB%B0%94%EC%9D%B4%EC%8A%A4%ED%8A%B8%EB%A6%ACDevice-Tree
    • http://blog.naver.com/PostView.nhn?blogId=ham9627&logNo=220561187536&parentCategoryNo=&categoryNo=30&viewDate=&isShowPopularPosts=true&from=search

2018년 11월 14일 수요일

YOLO 설치 및 경험해보기

딥러닝의 강력한 툴 중에 하나인 YOLO를 경험해 보면서 겪었던 trouble에 대해서 정리해 보기로 한다. 리눅스 환경에 익수한 사용자라면 darknet에 나온 설명만 따라하면 쉽게 시작할 수 있겠지만, 나와같이 리눅스 문외한을 위해 또 나의 부족한 기억력을 위해 YOLO 설치 과정을 정리하기로 한다.



1. 시작하며


YOLO를 실행시키기 위해서는 Darknet이 필요하다. Darknet은 Joseph Redmon이 독자 개발한 신경망 프레임워크(neural network framework)로서 dnn(deep neural network)들을 학습시키고 실행시킬 수 있는 프레임워크다. Darknet을 이용하면 기존 정통 주류의 dnn 모델, 예를 들어, AlexNet, VGG-16, Resnet, Densenet 등 들도 돌려 볼 수 있다. YOLO 역시 Darknet을 통해 학습된 신경망 중 하나이다.



2. YOLO 설치 및 실행


앞서 말했듯이, YOLO를 설치하기 위해서는 Darknet을 먼저 설치해야한다. Darknet은 아래와 같이 git에서 다운받을 수 있다. 다운로드가 완료되면 darknet 폴더로 이동 후, make 명령어를 입력하여 코드를 Compile한다. 컴파일이 완료되면 폴더에 darknet이라는 실행파일이 만들어진다.

     git clone https://github.com/pjreddie/darknet.git
     cd darknet
     make


2.1 설치 옵션


make 명령어 실행 전, 아래와 같이 Makefile을 수정하여 설치 옵션을 변경할 수 있다.


  • CUDA를 설치 했다면, GPU=1
  • OpenCV를 설치 했다면, OPENCV=1
  • 둘 다 설치 안된 경우에는 OPENCV=0, GPU=0으로 설정


2.2 YOLO 실행


위 과정까지 마무리 되었다면 Darknet 및 YOLO의 설치는 끝났다. git에서 다운받은 Darknet에는 예제로 주어진 딥러닝 모델과 weight들이 제공되고 있어 쉽게 YOLO의 동작을 검증해볼 수 있다. 그 예는 Darknet 홈페이지(https://pjreddie.com/darknet/install/)를 참조하면 쉽게 시도해볼 수 있다.




3. YOLO 윈도우즈 버전


git은 없는 소스코드 빼고 필요한 모든 소스코드가 제공되는 것 같다. 나와같이 Windows-friendly한 사람을 위한 YOLO 윈도우즈 버전 설치방법을 안내한다.


3.1 소스코드 다운받기


YOLO 윈도우즈 버전은 아래 git에서 다운받을 수 있다. 이 버전은 YOLO 윈도우즈 버전 뿐만 아니라 리눅스 버전을 포함하며, 현재(2018.11.15) 기준 Yolo-v3와 Yolo-v2를 모두 지원한다.

  • YOLO 윈도우 버전: https://github.com/AlexeyAB/darknet/

3.2 소스코드 빌드하기

위에서 언급한 git에 접속하면 windows와 linux에서 build하는 방법을 자세하게 설명하고 있다. windows 설치 방법은 아래 사이트를 참조하면 쉽게 이해할 것이다.

  • YOLO windows 버전 설치 안내: https://github.com/AlexeyAB/darknet/#how-to-compile-on-windows

[Windows build 환경]


Windows 환경에서 YOLO를 빌드하기 위해서는 MSVS2015와 OpenCV 3.4.0 이전 버전 (3.4.1버전에서는 버그 발생)이 기본적으로 설치되어 있어야 한다. 빌드 환경은 x64, release mode이다. 본인 PC에서는 OpenCV 3.0.0을 사용하였다.


  • CUDA9.1, cuDNN7.0이 설치된 경우

MSVS2015에서 build\darknet\darknet.sln 파일을  열고 빌드한다. 만약, CUDA9.1 버전이 아닌 경우에는 build\darknet\darknet.vcxproj 파일을 열어서 "CUDA 9.1"로 되어 있는 곳을  현재 Winodws에 설치된 "CUDA version"으로 수정하면 된다. 본인의 PC에는 CUDA 9.0, cuDNN7.3.0이 설치되었고, 빌드도 성공하였다.


  • GPU가 없는 경우

MSVS2015에서 build\darknet\darknet_no_gpu.sln 파일을  열고 빌드한다. 이 경우, CPU만으로 YOLO가 실행되어 속도가 느리지만 실행하는데에는 문제가 없다.




이상, 나의 기억력을 불신하여 리눅스 및 Windows 환경에서 YOLO를 설치하고 실행하는 예제를 정리한 글을 마칩니다.

2018년 11월 1일 목요일

Keras 소개

앞으로의 딥러닝 과제에서는 Keras를 이용해서 알고리즘을 구현하려고 합니다. 이에, Keras에 주요 특징들에 대해 간략하게 소개합니다. 이 내용은 아래 블로그를 요약/정리한 것으로, 자세한 내용은 아래 링크를 참고하세요.





Abstract


Keras는 구글 엔지니어인 프랑소와 쏠레(François Chollet)가 개발한 파이썬 기반의 딥러닝 라이브러리입니다. 딥러닝 비전문가라도 각자 분야에서 손쉽게 딥러닝 모델을 개발하고 활용할 수 있도록 Keras는 직관적인 API를 제공하고 있습니다.

내부적으로는 텐서플로우(TensorFlow), 티아노(Theano), CNTK 등의 딥러닝 전용 엔진이 구동되지만, Keras 사용자는 복잡한 내부 엔진을 알 필요는 없습니다. 직관적인 API로 쉽게 다층퍼셉트론 모델, 컨볼루션 신경망 모델, 순환 신경망 모델 또는 이를 조합한 모델은 물론 다중 입력 또는 다중 출력 등 다양한 구성을 할 수 있습니다.



Keras의 주요 특징

1. 모듈화 (Modularity)

Keras에서 제공하는 모듈은 독립적이고 설정 가능하며, 가능한 최소한의 제약사항으로 서로 연결할 수 있습니다. 모델은 시퀀스 또는 그래프로 이러한 모듈들을 구성한 것입니다.
특히, 신경망 층, 비용함수, 최적화기, 초기화기법, 활성화함수, 정규화기법은 모두 독립적인 모듈이며, 새로운 모델을 만들기 위해 이러한 모듈을 조합할 수 있습니다.


2. 최소주의 (Minimalism)

각 모듈은 짥고 간결합니다. 모든 코드는 한 번 훑어보는 것으로도 이해가능해야 합니다. 단, 반복 속도와 혁신성에는 다소 떨어질 수가 있습니다. (재사용성이 높은 노드 구성 vs. 효율적인 노드 구성  / 간결성 vs. 설계 유연성 - commented by wsahn)


3. 쉬운 확장성

새로운 클래스나 함수로 모듈을 아주 쉽게 추가할 수 있습니다. 따라서 고급 연구에 필요한 다양한 표현을 할 수 있습니다.


4. 파이썬 기반

Caffe 처럼 별도의 모델 설정 파일이 필요없으며 파이썬 코드로 모델들이 정의됩니다.



Keras 기본 개념


Keras의 가장 핵심적인 데이터 구조는 바로 모델입니다. Keras에서 제공하는 시퀀스 모델로 원하는 레이어를 쉽게 순차적으로 쌓을 수 있습니다. 다중 출력이 필요하는 등 좀 더 복잡한 모델을 구성하려면 Keras 함수 API를 사용하면 됩니다. Keras로 딥러닝 모델을 만들 때는 다음과 같은 순서로 작성합니다. 다른 딥러닝 라이브러리와 비슷한 순서이지만 훨씬 직관적이고 간결합니다.

1.데이터셋 생성하기

  • 원본 데이터를 불러오거나 시뮬레이션을 통해 데이터를 생성합니다. 
  • 데이터로부터 훈련셋, 검증셋, 시험셋을 생성합니다.
  • 이 때 딥러닝 모델의 학습 및 평가를 할 수 있도록 포맷 변환을 합니다.


2.모델 구성하기

  • 시퀀스 모델을 생성한 뒤 필요한 레이어를 추가하여 구성합니다.
  • 좀 더 복잡한 모델이 필요할 때는 케라스 함수 API를 사용합니다.

3. 모델 학습과정 설정하기

  • 학습하기 전에 학습에 대한 설정을 수행합니다.
  • 손실 함수 및 최적화 방법을 정의합니다.
  • 케라스에서는 compile() 함수를 사용합니다.

4. 모델 학습시키기

  • 훈련셋을 이용하여 구성한 모델로 학습시킵니다.
  • 케라스에서는 fit() 함수를 사용합니다.

5. 학습과정 살펴보기

  • 모델 학습 시 훈련셋, 검증셋의 손실 및 정확도를 측정합니다.
  • 반복횟수에 따른 손실 및 정확도 추이를 보면서 학습 상황을 판단합니다.

6. 모델 평가하기

  • 준비된 시험셋으로 학습한 모델을 평가합니다.
  • 케라스에서는 evaluate() 함수를 사용합니다.

7. 모델 사용하기

  • 임의의 입력으로 모델의 출력을 얻습니다.
  • 케라스에서는 predict() 함수를 사용합니다.

[Scrap] Zero to Hero: Guide to Object Detection using Deep Learning: Faster R-CNN,YOLO,SSD

Zero to Hero: Guide to Object Detection using Deep Learning: Faster R-CNN,YOLO,SSD https://cv-tricks.com/object-detection/faster-r-cnn-yo...