The ArmSom Forge1

With all that’s been happening over the past couple of months, it’s been hard to keep a steady pace of hardware reviews, so this is going to be a short one.

Disclaimer: ArmSom supplied me with a Forge1 board completely free of charge (for which I thank them), and as usual this article follows .

The Forge1 is a “pure” industrial board, meaning you don’t even get an HDMI display output. You do get a MIPI DSI port, but since I don’t have bare LCD displays lying around, I wasn’t able to take advantage of that or its LVGL support. I’ve been dabbling with LVGL on MCUs, and that’s something I find quite appealing to tinker with, so if I ever find the time it will be fun to play around with it on this kind of board.

Hardware

Forge1 board with Rockchip RK3506J SoC
Forge1 board with Rockchip RK3506J SoC

The board follows the ubiquitous Raspberry Pi form factor, with the single USB port where you’d find HDMI and two Fast Ethernet ports.

As to specs, they are somewhat minimalist:

  • Three-core RockChip RK3506J (Cortex-A7)
  • 512MB DDR3 RAM
  • Two 100Mbps Ethernet ports
  • 1xMIPI video/LCD panel port
  • 1xUSB 2.0
  • TRS audio jack
  • Power via USB-C or 12V Jack
  • 40-pin GPIO with the usual set of features (UART/SPI/I2C/I2S/PWM)

However, this is not a board for hobbyists, and it is not meant to be used as a desktop replacement or even a media player. It is designed to be used in industrial applications, and it shows.

Software

ArmSom is only supplying a buildroot image for this, which was a big reason why it took me this long to get around to reviewing it. To use RKDevTool you need a Windows machine, and finding the time and patience to dig out, set up my and flash the newest OS image ended up taking many weeks.

RKDevTool on Windows, flashing firmware
RKDevTool on Windows, flashing firmware

That and having to find the right USB-to-TTL adapter to talk to the serial console was also a bit of a drag. I had a rough time trying to use minicom to connect to it, since the Wiki instructions didn’t work for me, but putty worked fine on the after I disabled XON/XOFF, so I did a little exploration.

Here’s U-Boot and a few choice bits of the kernel booting:

DDR 0ac6b06a19 typ 24/11/13-17:22:47,fwver: v1.04
tREFI:4x, sr_idle:93, pd_idle:13
PHY drv:clk:40,ca:48,DQ:40,odt:240
vrefinner:50%, vrefout:50%
dram drv:40,odt:120
sr_dq:0, sr_ca:0, sr_clk:0
rg:0xf-0x1-0x2, 0x6-0x1-0x2,status:a007
rdtrn:0x13-0x2d-0x47(0x34)
wrtrn:0x0-0x21-0x42(0x42)
DDR3, 750MHz
BW=16 Col=10 Bk=8 CS0 Row=15 CS=1 Size=512MB
out
U-Boot SPL board init
U-Boot SPL 2017.09 (May 15 2025 - 13:59:20)
sfc cmd=03H(6BH-x4)
SPI Nand ID ef aa 23
unrecognized JEDEC id bytes: ff, ef, aa
Trying to boot from MTD1
Trying fit image at 0x2000 sector
## Verified-boot: 0
## Checking optee 0x00001000 ... sha256(690eb8a14d...) + OK
Trying kernel at 0xba00 sector from 'boot' part
## Checking fdt 0x00063000 ... sha256(9698f73155...) + OK
## Checking kernel 0x01100000 ... sha256(422383f3a3...) + OK
Jumping to Kernel(0x01100000) via OP-TEE(0x00001000)
Total: 241.253/286.957 ms

I/TC:
I/TC: Status: cluster=0xc00, core=0xe100, bootcpu=0
I/TC: Next entry point address: 0x01100000
I/TC: OP-TEE version: 3.13.0-894-g0e7e5b3c7ff #chenjh (gcc version 10.2.1 20201103 (GNU Toolchain for the A-profile Architecture 10.2-2020.11 (arm-10.16))) #2 Tue Nov 12 09:21:23 CST 2024 arm, fwver: v1.25
I/TC: OP-TEE memory: TEEOS 0x5e000 TA 0x1000 SHM 0x1000
I/TC: Primary CPU initializing
E/TC:0 0 rk_otp_sbpi_read:353 otp_check_ecc fail! parity=0x20
E/TC:0 0 rk_otp_read:789 ---OTP---sbpi read otp failed! addr: 0x1ff
E/TC:0 0 call_initcalls:24 Initcall __text_start + 0x0001a280 failed
I/TC: Primary CPU switching to normal world boot
[    0.384101] Booting Linux on physical CPU 0xf00
[    0.384123] Linux version 6.1.99 (lhd@armsom) (arm-none-linux-gnueabihf-gcc (GNU Toolchain for the A-profile Architecture 10.3-2021.07 (arm-10.29)) 10.3.1 20210621, GNU ld (GNU Toolchain for the A-profile Architecture 10.3-2021.07 (arm-10.29)) 2.36.1.20210621) #18 SMP PREEMPT Wed May  7 18:21:18 CST 2025
[    0.384134] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=50c5387d
[    0.384144] CPU: div instructions available: patching division code
[    0.384150] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.384412] OF: fdt: Machine model: Rockchip RK3506J(BGA) ArmSoM Forge1
[    0.386189] earlycon: uart8250 at MMIO32 0xff0a0000 (options '')
[    0.392130] printk: bootconsole [uart8250] enabled
[    0.392648] Memory policy: Data cache writealloc
[    0.393213] OF: fdt: Reserved memory: failed to reserve memory for node 'drm-logo@0': base 0x00000000, size 0 MiB
[    0.394229] Reserved memory: created CMA memory pool at 0x1ea00000, size 22 MiB
[    0.394904] OF: reserved mem: initialized node linux,cma, compatible id shared-dma-pool
[    0.396080] Zone ranges:
[    0.396340]   Normal   [mem 0x0000000000000000-0x000000001fffffff]
[    0.396915] Movable zone start for each node
[    0.397310] Early memory node ranges
[    0.397641]   node   0: [mem 0x0000000000000000-0x000000001fffffff]
[    0.398219] Initmem setup node 0 [mem 0x0000000000000000-0x000000001fffffff]
[    0.415583] psci: probing for conduit method from DT.
[    0.416075] psci: PSCIv1.0 detected in firmware.
[    0.416505] psci: Using standard PSCI v0.2 function IDs
[    0.416987] psci: MIGRATE_INFO_TYPE not supported.
[    0.417430] psci: SMC Calling Convention v1.1
[    0.417971] percpu: Embedded 11 pages/cpu s16212 r8192 d20652 u45056
[    0.418673] Built 1 zonelists, mobility grouping on.  Total pages: 130048
[    0.419308] Kernel command line: earlycon=uart8250,mmio32,0xff0a0000 console=ttyFIQ0 ubi.mtd=5 ubi.block=0,rootfs root=/dev/ubiblock0_0 rootfstype=squashfs rootwait snd_aloop.index=7 snd_aloop.use_raw_jiffies=1 mtdparts=spi-nand0:0x400000@0x400000(uboot),0x100000@0x800000(misc),0x40000@0x900000(vnvm),0xe00000@0x940000(recovery),0xa00000@0x1740000(boot),0x4000000@0x2140000(rootfs),0x1000000@0x6140000(oem),0x18e20000@0x7140000(userdata) user_debug=31
[    0.423401] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes, linear)
[    0.424175] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes, linear)
[    0.424878] mem auto-init: stack:off, heap alloc:off, heap free:off
[    0.437658] Memory: 490564K/524288K available (3225K kernel code, 367K rwdata, 1704K rodata, 172K init, 99K bss, 11196K reserved, 22528K cma-reserved)
[    0.439035] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=3, Nodes=1
[    0.439859] rcu: Preemptible hierarchical RCU implementation.
[    0.440397] rcu:     RCU event tracing is enabled.
[    0.440816] rcu:     RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=3.
[    0.441419] rcu: RCU calculated value of scheduler-enlistment delay is 30 jiffies.
[    0.442115] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=3
[    0.442759] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
[    0.444154] rcu: srcu_init: Setting srcu_struct sizes based on contention.
[    0.455300] arch_timer: cp15 timer(s) running at 24.00MHz (virt).
[    0.455898] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns
[    0.456898] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns
[    0.457641] Switching to timer-based delay loop, resolution 41ns
[    0.458589] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=80000)
[    0.459548] CPU: Testing write buffer coherency: ok
[    0.460049] pid_max: default: 4096 minimum: 301
[    0.460594] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.461282] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.462828] /cpus/cpu@f00 missing clock-frequency property
[    0.463375] /cpus/cpu@f01 missing clock-frequency property
[    0.463895] /cpus/cpu@f02 missing clock-frequency property
[    0.464408] CPU0: thread -1, cpu 0, socket 15, mpidr 80000f00
[    0.465802] Setting up static identity map for 0x108240 - 0x108294
[    0.466553] rcu: Hierarchical SRCU implementation.
[    0.467002] rcu:     Max phase no-delay instances is 1000.
[    0.468215] smp: Bringing up secondary CPUs ...
I/TC: Secondary CPU 1 initializing
I/TC: Secondary CPU 1 switching to normal world boot
I/TC: Secondary CPU 2 initializing
I/TC: Secondary CPU 2 switching to normal world boot
[    0.470133] CPU1: thread -1, cpu 1, socket 15, mpidr 80000f01
[    0.471725] CPU2: thread -1, cpu 2, socket 15, mpidr 80000f02
[    0.471852] smp: Brought up 1 node, 3 CPUs
[    0.473343] SMP: Total of 3 processors activated (144.00 BogoMIPS).
[    0.473924] CPU: All CPU(s) started in SVC mode.
...
[    0.535620] mc: Linux media interface: v0.10
[    0.535712] videodev: Linux video capture interface: v2.00
[    0.535760] pps_core: LinuxPPS API ver. 1 registered
[    0.535774] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <[email protected]>
[    0.535801] PTP clock support registered
[    0.537012] Advanced Linux Sound Architecture Driver Initialized.
[    0.537815] rockchip-cpuinfo cpuinfo: SoC            : 35060000
[    0.537852] rockchip-cpuinfo cpuinfo: Serial         : 75fe7c2e8b33b6c4
...
[    0.572184] Creating 8 MTD partitions on "spi-nand0":
[    0.572202] 0x000000400000-0x000000800000 : "uboot"
[    0.574398] 0x000000800000-0x000000900000 : "misc"
[    0.576455] 0x000000900000-0x000000940000 : "vnvm"
[    0.578661] 0x000000940000-0x000001740000 : "recovery"
[    0.580681] 0x000001740000-0x000002140000 : "boot"
[    0.582812] 0x000002140000-0x000006140000 : "rootfs"
[    0.585048] 0x000006140000-0x000007140000 : "oem"
[    0.587171] 0x000007140000-0x00001ff60000 : "userdata"
[    0.591283] CAN device driver interface
...
[   12.935924] rk_gmac-dwmac ff4c8000.ethernet eth0: Link is Up - 100Mbps/Full - flow control off
root@armsom:/# uname -a
Linux armsom 6.1.99 #18 SMP PREEMPT Wed May  7 18:21:18 CST 2025 armv7l GNU/Linux

…and quickly came to the conclusion that the buildroot image doesn’t have a lot of useful binaries installed:

root@armsom:/# find . -print | grep ssh
root@armsom:/#

Without ssh or any other way to log in to the system remotely, the limitations of the reference image made it a little awkward to try to use the board for anything useful. I was able to build a little Go executable for armv7l and fetch it from the board itself with the BusyBox version of wget (and of course it ran fine), but the whole point of this board is that you should use the SDK to build your own custom OS image and bundle your application with it.

Conclusion

The Forge1 is quite different when compared to , since it doesn’t try to cater to both hobbyists and the industrial market—it’s purely focused on industrial applications.

And that’s fine. Despite not shipping with the usual amenities of an HDMI port or a “nicer” OS, it is perfectly capable of running a 3D printer or any other kind of CNC equipment, acting as an OPC router, or filling in for the various sensor data collection and actuator control jobs you need in an industrial environment.

Loaded with a custom OS, and being a well-known quantity in terms of CPU architecture, it’s quite likely to find a lot more niches than I can currently think of. I think the fact that ArmSom is committed to manufacturing it until 2035 gives you an idea of the overall expectations for this kind of board. It’s going to disappear inside all sorts of machines and provide a cheap, familiar approach to controlling them.

And for that purpose, buildroot support and the open SDK will certainly be sufficient—after you set up your custom environment, you can just treat it as a build target and develop elsewhere.

This page is referenced in: