Sprint Magic Box Serial Logs

Written 2019-03-23

The three pin header on the relay board has a 3.3v 115200 baud serial port. Sadly, it's using U-Boot Secure Boot.
U-Boot SPL 2015.10 (Jun 21 2017 - 15:40:14)

U-Boot 2015.10 (Jun 21 2017 - 15:40:14 +0100)

CPU:   Freescale i.MX6SX rev1.2 996 MHz (running at 792 MHz)
CPU:   Extended Commercial temperature grade (-20C to 105C) at 39C
Reset cause: POR
BoardId: 0005
       Watchdog enabled
I2C:   ready
DRAM:  1 GiB
PCI:   pcie phy link never came up
In:    serial
Out:   serial
Err:   serial
Exit emergency shutdown mode
Writing debounce period of 30 seconds to TI battery chip is OK.
SECURE BOOT running, Boot prompt is disabled
Net:   FEC [PRIME]
Hit any key to stop autoboot:  0 
Booting from MMC...
switch to partitions #0, OK
mmc0(part 0) is current device
externalconfig: banktoboot=0
externalconfig: runapp=1
externalconfig: bootattempts bank0=7
externalconfig: bootattempts bank1=0

WARNING - Bank 0 previously failed to boot. Attempting again (8/15)

fallbackcheck: banktoboot=0
fallbackcheck: bootattempts bank0=8
fallbackcheck: bootattempts bank1=0
37665 bytes read in 122 ms (300.8 KiB/s)
6588448 bytes read in 435 ms (14.4 MiB/s)
Kernel image @ 0x82000000 [ 0x000000 - 0x648820 ]
## Flattened Device Tree blob at 88000000
   Booting using the fdt blob at 0x88000000
   Loading Device Tree to bfc24000, end bfc30320 ... OK

Starting kernel ...

[    0.086684] reg_fixed_voltage_probe: skipped regulators:regulator@6 from setting HIGH 
[    0.142899] Inserting airspan_gpio module
[    0.147712] mxsfb-spi-it8951 spidisp@0: allocated fb @ paddr=0xAA080000, size=518400. yres[540], lineLen[960]
[    0.185820] imx6sx-pinctrl 20e0000.iomuxc: pin MX6SX_PAD_GPIO1_IO04 already requested by 2020000.serial; cannot claim for 22a0000.serial
[    0.198150] imx6sx-pinctrl 20e0000.iomuxc: pin-9 (22a0000.serial) status -22
[    0.205239] imx6sx-pinctrl 20e0000.iomuxc: could not request pin 9 (MX6SX_PAD_GPIO1_IO04) from group uart6wifiap  on device 20e0000.iomuxc
[    0.217713] imx-uart 22a0000.serial: Error applying setting, reverse things back
[    0.229848] Error: Driver 'imx-ipuv3' is already registered, aborting...
[    0.236728] DEBUG: SPIDEV Initialised! 0
[    0.242600] spidev spi2.0: buggy DT: spidev listed directly in DT
[    0.467514] my_cfb_imageblit() called
[    1.143218] caam_jr 2101000.jr0: 20000b11: CCB: desc idx 11: AES: Mode error.
[    1.150701] alg: aead: encryption failed on test 1 for rfc4106-gcm-aes-caam: ret=-536873745
[    1.159768] caam_jr 2101000.jr0: 20000c11: CCB: desc idx 12: AES: Mode error.
[    1.167011] alg: aead: encryption failed on test 1 for gcm-aes-caam: ret=-536874001
[    1.220880] snvs-secvio 20cc000.caam-snvs: can't get snvs clock
[    1.237143] cpu cpu0: dev_pm_opp_get_opp_count: device OPP not found (-19)
[    1.560270] imx6q-pcie 8ffc000.pcie: phy link never came up
[    1.566134] imx6q-pcie 8ffc000.pcie: failed to initialize host
[    1.595032] EXT4-fs (mmcblk0p2): couldn't mount as ext3 due to feature incompatibilities
[    1.603843] EXT4-fs (mmcblk0p2): couldn't mount as ext2 due to feature incompatibilities
INIT: version 2.88 booting
Starting udev
bootlogd: cannot allocate pseudo tty: No such file or directory
ALSA: Restoring mixer settings...
/usr/sbin/alsactl: load_state:1729: No soundcards found...
INIT: Entering runlevel: 3
Configuring network interfaces... [    3.917366] m25p80 spi1.0: unrecognized JEDEC id bytes: 00,  0,  0
Starting system message bus: dbus.
Starting OpenBSD Secure Shell server: sshd
Starting rpcbind daemon...done.
Starting advanced power management daemon: No APM support in kernel
Starting HOSTAP Daemon: Configuration file: /etc/hostapd.conf
Could not read interface wlan0 flags: No such device
nl80211: Driver does not support authentication/association or connect commands
nl80211: deinit ifname=wlan0 disabled_11b_rates=0
Could not read interface wlan0 flags: No such device
nl80211 driver initialization failed.
wlan0: interface state UNINITIALIZED->DISABLED
hostapd_free_hapd_data: Interface wlan0 wasn't started
Starting IrDA: irattach fail
Starting ntpd: done
Starting syslogd/klogd: done
[ ok ]rting Avahi mDNS/DNS-SD Daemon: avahi-daemon
Starting Telephony daemon
Starting Linux NFC daemon
Starting Lighttpd Web Server: lighttpd.

BoardId        = 0005
BoardId Name   = AU545
Image          = airunity
Kernel cmdline = root=/dev/mmcblk0p2 rootwait console=ttymxc0,115200 runapp=yes envoffset=0x48000 bootversion= raid=noautodetect pci=nomsi ahci_imx.hotplug=1 quiet

Start init SUCCESS.
Inserting module spi_it8951
[   14.884690] ALERT: Openning file handle on: /dev/spidev2.0
[   14.896978] Initialised it8951_init 1511
Initialising spi_it8951
[   15.450692] Initialised Device it8951_initdev 557

Warning: Old and New Firmware versions match: Airspan.v.0.18
INFO: Display Width: 960
INFO: Display Height: 540
INFO: Display FWVersion: Airspan.v.0.18
INFO: Display LUTVersion: 320_R117_AF8301_
[   15.532901] Error: IT8951 unable to open: /dev/mtd0ro it8951_read_epd_flash 417
[   15.540282] Error: EPD flash read failed
[   15.554171] Error: IT8951 unable to open: /dev/mtd0ro it8951_read_epd_flash 417
[   15.561553] Error: EPD flash read failed
file is not updated: file version [12] batt serial number[12]

Data Flash Parameters update not required.
Start init SUCCESS.
Inserting module tamperdetect
[   18.216668] Error: i2c_transfer: -5 tamperdetect_get_cmd 927
[   18.222385] Error: Failed to get fw version tamperdetect_get_fwver 1025
[   18.229034] Error: Invalid FW Version tamperdetect_initdev 716
[   18.234887] Error: Initialisation Failed: 3
Initialising tamperdetect
Error: tamperdetect Driver failed to initialise: Retry: 1
Module tamperdetect present - removing first
[   18.353840] Exited tamperdetect_exit 2549
Inserting module tamperdetect
[   18.374874] Error: i2c_transfer: -5 tamperdetect_get_cmd 927
[   18.380636] Error: Failed to get fw version tamperdetect_get_fwver 1025
[   18.387324] Error: Invalid FW Version tamperdetect_initdev 716
[   18.393213] Error: Initialisation Failed: 3
Initialising tamperdetect
Error: tamperdetect Driver failed to initialise: Retry: 2
Module tamperdetect present - removing first
[   18.502064] Exited tamperdetect_exit 2549
Inserting module tamperdetect
[   18.523182] Error: i2c_transfer: -5 tamperdetect_get_cmd 927
[   18.528935] Error: Failed to get fw version tamperdetect_get_fwver 1025
[   18.535619] Error: Invalid FW Version tamperdetect_initdev 716
[   18.541519] Error: Initialisation Failed: 3
Initialising tamperdetect
Error: tamperdetect Driver failed to initialise: Retry: 3
Module tamperdetect present - removing first
[   18.649968] Exited tamperdetect_exit 2549
Inserting module tamperdetect
[   18.670924] Error: i2c_transfer: -5 tamperdetect_get_cmd 927
[   18.676676] Error: Failed to get fw version tamperdetect_get_fwver 1025
[   18.683372] Error: Invalid FW Version tamperdetect_initdev 716
[   18.689262] Error: Initialisation Failed: 3
Initialising tamperdetect
Error: tamperdetect Driver init retry count exceeded!
Board type is AU545, eNB power driven by MAINS so keep eNB power turning ON

choice3, gpio_bank2, gpio_bin1, dir_val0, value1

gpioSetupPinMode 2:1 (1 <= bank =< 8, 0 <= bin <= 31)
gpioRegisterBankPin 2:1 (1 <= bank =< 8, 0 <= bin <= 31)
registerGpioBankPin: 2:1 pin is registered
choice3, gpio_bank7, gpio_bin3, dir_val0, value0

gpioSetupPinMode 7:3 (1 <= bank =< 8, 0 <= bin <= 31)
gpioRegisterBankPin 7:3 (1 <= bank =< 8, 0 <= bin <= 31)
registerGpioBankPin: 7:3 pin is registered
choice3, gpio_bank4, gpio_bin23, dir_val0, value1

gpioSetupPinMode 4:23 (1 <= bank =< 8, 0 <= bin <= 31)
gpioRegisterBankPin 4:23 (1 <= bank =< 8, 0 <= bin <= 31)
registerGpioBankPin: 4:23 pin is registeredChoosing the image
airspan: RUNAPP = yes
Mount /config, /calibration and /archive partitions
Showing Sprint Logo
/dev/emmc1 has journal
/dev/emmc2 has journal
/dev/emmc3 has journal
Synchronising authentication credentials
Backup file not found
Reboot reason: Power-cycle (WDOG1_WRSR=0x0010: POR bit=1)
Starting background process to kick watchdog for 5 minutes (10s kick) until procmgr takes over
Starting hardware watchdog loop for 30 iterations with 10000000 usec delay...

X.Org X Server 1.14.4
Release Date: 2013-10-31
X Protocol Version 11, Revision 0
Build Operating System: Linux 3.13.0-110-generic x86_64 
Current Operating System: Linux airunity 4.1.15 #1 SMP Fri Jun 30 18:16:40 BST 2017 armv7l
Kernel command line: root=/dev/mmcblk0p2 rootwait console=ttymxc0,115200 runapp=yes envoffset=0x48000 bootversion= raid=noautodetect pci=nomsi ahci_imx.hotplug=1 quiet
Build Date: 02 March 2017[   21.011314] my_cfb_fillrect() called
Current version of pixman: 0.32.6
        Before reporting problems, check http://wiki.x.org
        to make sure that you have the latest version.
Markers: (--) probed, (**) from config file, (==) default setting,
        (++) from command line, (!!) notice, (II) informational,
        (WW) warning, (EE) error, (NI) not implemented, (??) unknown.
(==) Log file: "/var/log/Xorg.0.log", Time: Sat Mar 16 21:45:05 2019
(==) Using config file: "/etc/X11/xorg.conf"
(==) Using system config directory "/usr/share/X11/xorg.conf.d"
Initializing built-in extension Generic Event Extension
Initializing built-in extension SHAPE
Initializing built-in extension MIT-SHM
Initializing built-in extension XInputExtension
Initializing built-in extension XTEST
Initializing built-in extension BIG-REQUESTS
Initializing built-in extension SYNC
Initializing built-in extension XKEYBOARD
Initializing built-in extension XC-MISC
Initializing built-in extension XFIXES
Initializing built-in extension RENDER
Initializing built-in extension RANDR
Initializing built-in extension COMPOSITE
Initializing built-in extension DAMAGE
Initializing built-in extension MIT-SCREEN-SAVER
Initializing built-in extension DOUBLE-BUFFER
Initializing built-in extension DPMS
Initializing built-in extension X-Resource
Initializing built-in extension XVideo
Initializing built-in extension XVideo-MotionCompensation
Initializing built-in extension XFree86-VidModeExtension
Initializing built-in extension XFree86-DGA
Initializing built-in extension XFree86-DRI
Initializing built-in extension DRI2
Loading extension GLX
App Param =, 9093, 9092, /bs/font/, 0005, /bs/images/, yes, 960, 540, yes
2019-03-16 21:45:15 DEBUG ScreenView - /bs/images/animatable/network
2019-03-16 21:45:17 INFO  ViewNotification - addViewNotificationListener called
2019-03-16 21:45:18 INFO  CommNotification - addCommNotificationListener called
Comms Param =, 9093, 9092, /bs/font/, 0005, /bs/images/, yes, 960, 540, yes
2019-03-16 21:45:19 DEBUG UdpServer - UDPServer listening on port 9093
2019-03-16 21:45:19 DEBUG UpdateDisplay - UDP server socket open on port 9093

2019-03-16 21:45:19 DEBUG AirUnityServiceImpl - irelayCommClient created
2019-03-16 21:45:19 DEBUG UpdateDisplay - UDP client socket connected to on port 9092

2019-03-16 21:45:19 DEBUG StatusIndicationSender - New Status Indication scheduling being used

Opening Your Sprint Magic Box

Written 2019-03-23

This thing is a pain to take apart. The photos are after I already got it open.

Goal, remove the top cover so that 4 screws can be pulled.

Sprint Magic Box

Step one, crack open the sides starting from the botton.

Sprint Magic Box

Step two, reach up from the bottom/sides with a lever to pop the clips holding the top cover down. Clips visible at left and right sides here:

Sprint Magic Box

Once the top is popped, four screws can be removed to enable pulling off the sides.

Be careful, as the display should not be disconnected, as it may be part of the tamper detection circuitry.

Caldwell Ballistic Precision Chronograph Theory of Operation and Signal Path

Written 2018-12-04

Tags:Caldwell Chronograph 

Inside my chronograph, we find this simple PCB. With only two chips and a handful of passive components, this device can measure speeds from 5 to nearly 10000 feet per second. Here is how it works. The chronograph waits for an object to pass the first light-gate, starts a timer, waits for the object to pass the second light gate, records the finish time, and divides the distance between light gates by the time, and converts to appropriate human-readable units for display.

Caldwell Chronograph


Caldwell Precision Ballistic Chronograph Teardown


At each end of the device we see a large, black sensor module.

Caldwell Precision Ballistic Chronograph Teardown

Due to the presence of three wires running to each pod, it is likely either a phototransistor, or a photodiode with a bias circuit to help return a signal over the long wires.

Sensor Amplifier

Connected to the sensors is a TI LM324 quad operational amplifier. This common component adds a lot of flexibility in the analog domain, but its general purpose is to amplify the signal coming from the sensors over a range of frequencies.

Approach 1: Analog to Digital Converter - ADC

Connected to the output of the LM324 is the Silicon Labs C8051F380 microcontroller. From the datasheet we can see that the ADC is 10-bit resolution, up to 500kilosamples per second.


This is a pretty simple, basic ADC design. The window-compare feature may be used to allow the 8051 core to sleep while waiting for a signal pulse to arrive, but given that the chrono does nothing else, it may not be utilized. One nice thing about this ADC is that it features differential inputs. This means that instead of attempting to read the signals from both sensors we can instead subtract one from the other and feed it into the single ADC channel(this may also be done with the OpAmp).

I frankly have no idea what the signal of an arrow or bullet passing over a phototransistor when amplified by an unknown amplifier, but we can figure out some basic requirements from the device specifications, but we know a few thing:

This is a problem, because the ADC can only run at 0.5MHz. What does that mean? With a sample-rate of 500kHz, we can work out the error over speed like so:


This means that either the device doesn't operate quite as it appears to, or Battenfeld Technologies / Caldwell cheated a little on their specifications. Not that anyone would notice - no bullet travels anywhere near 10000 feet per second, rare bullets travel approximately 5000 feet per second, but most are much, much lower than that. A 220 Swift might be 4000 feet per second, and the chrono would be around 0.8 percent accurate. Sadly, 0.25 percent accuracy is achieved only for 1000 feet per second and slower velocities. If the vendor is not fudging their specs, we can assume they are not using the ADC.

Approach 2: OpAmp as Digital Comparator

Assuming we use the quad-op-amp as two channels of amplifier-followed-by-hysteresis-controlled-op-amp, we can receive a digital pulse either with the two INT pins or using the GATE functionallity of the microcontroller timer unit, which enables counting only while a signal is high. With this configuration, the accuracy is limited by the speed and accuracy of the timer, which can run at up to 12MHz. Assuming 12MHz, and the same 100us vs 100.25us from above, a 12MHz timer can measure 100us, 100.083us, 100.167us, or 100.25us. Assuming the clock is accurate, this leads to an error of at most 0.09%, far better than the ADC-approach, and quite a bit better than the vendor's own estimate.

Other Error Sources

Clock Accuracy and Temperature

With any event-timer based system, the overall accuracy is goverened by the accuracy of the timer. Coincidentally, the C8051F380 main clock is only accurate to 0.25%. Given that the PCB does not have an external oscillator to enable high precision, the unit is limited to 0.25% accuracy, assuming there is no post-assembly calibration completed, which would have to be completed over the operating temperature range, and using the on-board temp sensor to calibrate it out.

Shot Alignment With Chronograph

All of the above discussion assumes the bullet takes the shortest path between the sensors. However, without rigidly mounting the gun barrel and chronograph together to something like a table, alignment will be sub-optimal. As the bullet path angle changes from straight through the chronograph, the path length changes with 1/cosine(angle). We can plot this error easily enough:


Although a 20 degree misalignment is pretty difficult to do by accident, it is easier to accumulate a 1% error at only 8 degrees of misalignment, and 4 degrees of misalignment add 0.25% error, as much as the chronograph has already. If you do not plan to rigidly mount the chrono and firearm, you are unlikely to achieve the published accuracy.

Taking Apart the Caldwell Ballistic Precision Chronograph

Written 2018-12-04

Tags:Caldwell Chronograph 

Caldwell Chronograph

First we pull four massive screws out

Caldwell Precision Ballistic Chronograph Teardown

Flip over the whole assembly and remove the top cover

Caldwell Precision Ballistic Chronograph Teardown

On the top of the PCB we see a Silicon Labs 8051

Caldwell Precision Ballistic Chronograph Teardown

And an LM324 Quad OpAmp

Caldwell Precision Ballistic Chronograph Teardown

Unaligned Access on Cortex-M: Loads vs Stores, M4 vs M7

Written 2018-11-24

Tags:Cortex-M Memory ARM Cortex 

Unaligned Accesses

Anytime a processor attempts to load or store to memory at an address modulo the size of the transfer not equal to zero, it is considered unaligned. For example, loading 4 bytes from address 1 is unaligned. There are two common ways a processor can react to this, fixing up the load to make it work, or faulting so a programmer can fix the error(weirdly, ARMv5 would treat unaligned loads as a Load+Rotate, and was generally considered a bad idea to implement this behaviour).

Unaligned Loads on Cortex-M3/4

On Cortex-M3/4, the core breaks up unaligned loads into the smallest usable loads. For a 4 byte load at example address we can use the following table:

Address Modulo 4How DonePenalty Cycles

Generally, this is considered a pretty good deal as it is faster than constructing the data in registers using loads and shifts

Reference: Cortex-M4 Technical Reference Manual

Unaligned Loads on Cortex-M7

Another approach to unaligned loads is to always load two 32-bit words. This gives a more deterministic timing with 1 memory penalty cycle for all unaligned loads, however it is slower in the event that the memory pointed to is accessed by a 16-bit or 8-bit bus, as is common for slower external RAMs.

Address Modulo 4How DonePenalty Cycles

Reference: Cortex-M7 Technical Reference Manual

A word about the store buffer

On Cortex-M3/4 stores are handed off to a unit known as the store-buffer. It allows program execution to continue with the store instruction consuming seeming only a single cycle, but in reality the store buffer defers it until memory is ready to accept the change. However, if too many stores are issued too quickly and memory is unable to keep up, the core may become blocked on the store buffer.

Unaligned Stores on Cortex-M3/4/7

When an unaligned store occurs, the processor pushes it into the store buffer and continues on as it does for all stores. Beneath the store buffer, the following occurs:

Address Modulo 4How DonePenalty Cycles
For unaligned accesses, ARM states "A STR or STRH cannot delay the processor because of the store buffer." That's not entirely true - again if memory is slower than the processor, or there's just a lot of stores in the instruction stream, the penalty cycles caused by unaligned accesses can bubble up and eventually stall the processor.

How this affects embedded developers

Rarely, when benchmarking performance-critical code, I'll have strange, hard-to-explain results. A memset to one location might run slower than another, even though they're both in the same fixed-wait-state memory. Or, a graphical operation might run slower depending on the coordinates used, even though the number of pixels is the same from run to run. The cause is often unaligned memory accesses and the good news is that it can often be at least partially optimized, usually by aligning

Optimizations for memset

For a write-only, memset-like function, it's simple enough to eliminate all unaligned accesses by hand-aligning the head and tail of the operation, and if the operation is large enough, it's almost always worth it.

Check out newlib's memset() for an example. Note that Newlib is portable to platforms where unaligned accesses are undefined(trap), so it must eliminate them, but in doing so, this makes for a fast portable memset.

Optimizations for memcpy

For a read-write, memcpy-like function, it's sometimes impossible to possible to align both ends of the copy. In this case, it's best to align either source or destination, then use a mix of unaligned loads and aligned stores, or aligned loads and unaligned stores to carry out the bulk of the work.

ARM authored Newlib's memcpy, and it has an excellent example of aligning at least one pointer, then proceeding even if the other isn't aligned.

Optimizations for stream-mixing

For a read-read-write function, things are even more complicated. One example of this is mixing two 8-bit audio streams four samples at a time using LDR(streamA), LDR(streamB), QADD8, STR(StreamOut). In this case, you usually want to hand-align so that the largest number of streams are aligned, which could end up being anywhere from 1 to 3, potentially starting with 0 aligned streams.

Considerations for different memory subsystems

So far, the above writings haven't really touched on different memory architectures and how they affect unaligned accesses. For example, many Cortex-M processors are equipped with Flash ROM with a prefetcher. This means that the consecutive accesses caused by unaligned accesses cost only the penalty cycles. However, a slow, cacheless RAM may take many CPU cycles to complete a memory cycle, and now an unaligned access requires up to 3! Stranger yet are stores to SDRAMs, where the store buffer can cover up entire DRAM refreshes; however refreshes stall loads immediately. Finally, only rarely does a memory exist in a system with only a CPU - there are often other things contending for memory access to the same RAMs, often DMAs, GPUs, display controllers, and more. Keep in mind that on Cortex-M, the store-buffer is the only way to hide memory latency, and if you're doing a lot of stores, it may quickly become a bottleneck, doubly-to-tripply so if left unaligned.