A Visit to Huaqiangbei Market by an Embedded Systems Engineer

After reading about the world’s largest electronics market in Shenzhen several years ago, I finally had a chance to visit it in early 2018 during an engineering trip to the region. I had two afternoons and a weekend to explore its offerings, and I am sure I missed plenty.

h/t to Goodians for the map

Huaqiangbei (“Huaqiang North” or “HQB”) is a 16+ city block area plus outlier buildings which house representatives of numerous Chinese semiconductor and electronics manufacturing companies located in Shenzhen.

Continue reading A Visit to Huaqiangbei Market by an Embedded Systems Engineer

Wiping Out An SSD

I had a really old solid-state disk in need of wiping. It’s one of Samsung’s very first OEM models and I’m not even sure what machines they were originally installed into with their super-uncommon uSATA connector.

Photo of Samsung uSATA SSD

There’s no way to completely wipe out an SSD without resorting to specialized software from the manufacturer (Samsung Magician, for instance, if it supports the drive), or grinding it up in a shredder or smashing it to pieces.

But you can get somewhat close by writing all 1’s to the flash cells, which also resets them to their default electrically-erased state and can improve later writes.

Here’s how to do that (based on this and this):

$ tr '\0' '\377' 

The first erasure is slower than the second, even though I'm not sure this drive has TRIM support. CrystalDiskInfo says it doesn't. Samsung's Magician software says it does. The second and third erasures exhibit identical write speeds.

CrystalDiskInfo for Samsung uSATA SSD

Samsung Magician for Samsung uSATA SSD

It's a weird drive anyways, but might still be useful as a relatively-quick portable hard disk, depending on the workload.

It is only useful for sequential writes. Its 4K and random write scores are pretty atrocious.

Before the wipe (drive filled with OS, data, etc.):

Samsung 120GB uSATA SSD (before full erase)

After the wipe (drive cleared with all 1s):

Under Ubuntu, the SATA drive information looks as follows:

$ sudo hdparm -I /dev/sda

/dev/sda:

ATA device, with non-removable media
	Model Number:       SAMSUNG SSD Thin uSATA 128GB M
	Serial Number:      DFFC30S912SE912A6439
	Firmware Revision:  VAM05D1Q
Standards:
	Used: ATA/ATAPI-7 T13 1532D revision 1
	Supported: 7 6 5 4
Configuration:
	Logical		max	current
	cylinders	16383	16383
	heads		16	16
	sectors/track	63	63
	--
	CHS current addressable sectors:    16514064
	LBA    user addressable sectors:   250069680
	LBA48  user addressable sectors:   250069680
	Logical/Physical Sector size:           512 bytes
	device size with M = 1024*1024:      122104 MBytes
	device size with M = 1000*1000:      128035 MBytes (128 GB)
	cache/buffer size  = unknown
	Nominal Media Rotation Rate: Solid State Device
Capabilities:
	LBA, IORDY(can be disabled)
	Standby timer values: spec'd by Standard, no device specific minimum
	R/W multiple sector transfer: Max = 16	Current = 16
	Recommended acoustic management value: 128, current value: 0
	DMA: mdma0 mdma1 mdma2 udma0 udma1 udma2 udma3 udma4 *udma5 
	     Cycle time: min=120ns recommended=120ns
	PIO: pio0 pio1 pio2 pio3 pio4 
	     Cycle time: no flow control=120ns  IORDY flow control=120ns
Commands/features:
	Enabled	Supported:
	   *	SMART feature set
	    	Security Mode feature set
	   *	Power Management feature set
	   *	Write cache
	   *	Look-ahead
	   *	Host Protected Area feature set
	   *	WRITE_BUFFER command
	   *	READ_BUFFER command
	   *	NOP cmd
	   *	DOWNLOAD_MICROCODE
	    	SET_MAX security extension
	    	Automatic Acoustic Management feature set
	   *	48-bit Address feature set
	   *	Device Configuration Overlay feature set
	   *	Mandatory FLUSH_CACHE
	   *	FLUSH_CACHE_EXT
	   *	SMART error logging
	   *	SMART self-test
	   *	General Purpose Logging feature set
	   *	WRITE_{DMA|MULTIPLE}_FUA_EXT
	   *	64-bit World wide name
	   *	WRITE_UNCORRECTABLE_EXT command
	   *	Segmented DOWNLOAD_MICROCODE
	   *	Gen1 signaling speed (1.5Gb/s)
	   *ssssss	Gen2 signaling speed (3.0Gb/s)
	   *	Host-initiated interface power management
	   *	Phy event counters
	    	Device-initiated interface power management
	   *	Software settings preservation
Security: 
	Master password revision code = 65534
		supported
	not	enabled
	not	locked
	not	frozen
	not	expired: security count
		supported: enhanced erase
	6min for SECURITY ERASE UNIT. 6min for ENHANCED SECURITY ERASE UNIT.
Logical Unit WWN Device Identifier: 50000f0056414431
	NAA		: 5
	IEEE OUI	: 0000f0
	Unique ID	: 056414431
Checksum: correct

Also under Ubuntu, the SMART information for the drive looks as follows, note the relatively large number of Power On Hours, this drive had a very heavy service life:

$ sudo smartctl -a /dev/sda
smartctl 6.6 2016-05-31 r4324 [x86_64-linux-4.13.0-21-generic] (local build)
Copyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org

=== START OF INFORMATION SECTION ===
Device Model:     SAMSUNG SSD Thin uSATA 128GB M
Serial Number:    DFFC30S912SE912A6439
LU WWN Device Id: 5 0000f0 056414431
Firmware Version: VAM05D1Q
User Capacity:    128,035,676,160 bytes [128 GB]
Sector Size:      512 bytes logical/physical
Rotation Rate:    Solid State Device
Device is:        Not in smartctl database [for details use: -P showall]
ATA Version is:   ATA/ATAPI-7 T13/1532D revision 1
Local Time is:    Wed Dec 27 13:51:49 2017 CET
SMART support is: Available - device has SMART capability.
SMART support is: Enabled

=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED

General SMART Values:
Offline data collection status:  (0x02)	Offline data collection activity
					was completed without error.
					Auto Offline Data Collection: Disabled.
Self-test execution status:      (  40)	The self-test routine was interrupted
					by the host with a hard or soft reset.
Total time to complete Offline 
data collection: 		(  360) seconds.
Offline data collection
capabilities: 			 (0x53) SMART execute Offline immediate.
					Auto Offline data collection on/off support.
					Suspend Offline collection upon new
					command.
					No Offline surface scan supported.
					Self-test supported.
					No Conveyance Self-test supported.
					Selective Self-test supported.
SMART capabilities:            (0x0003)	Saves SMART data before entering
					power-saving mode.
					Supports SMART auto save timer.
Error logging capability:        (0x01)	Error logging supported.
					General Purpose Logging supported.
Short self-test routine 
recommended polling time: 	 (   6) minutes.
Extended self-test routine
recommended polling time: 	 (  36) minutes.

SMART Attributes Data Structure revision number: 1
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE
  9 Power_On_Hours          0x0032   096   096   000    Old_age   Always       -       18948
 12 Power_Cycle_Count       0x0032   098   098   000    Old_age   Always       -       1962
175 Program_Fail_Count_Chip 0x0032   100   100   011    Old_age   Always       -       0
176 Erase_Fail_Count_Chip   0x0032   100   100   011    Old_age   Always       -       0
177 Wear_Leveling_Count     0x0013   100   100   023    Pre-fail  Always       -       0
178 Used_Rsvd_Blk_Cnt_Chip  0x0013   095   095   011    Pre-fail  Always       -       5
179 Used_Rsvd_Blk_Cnt_Tot   0x0013   099   099   010    Pre-fail  Always       -       26
180 Unused_Rsvd_Blk_Cnt_Tot 0x0013   099   099   010    Pre-fail  Always       -       3878
181 Program_Fail_Cnt_Total  0x0032   099   099   010    Old_age   Always       -       1
182 Erase_Fail_Count_Total  0x0032   100   100   010    Old_age   Always       -       0
183 Runtime_Bad_Block       0x0013   099   099   010    Pre-fail  Always       -       1
187 Reported_Uncorrect      0x0033   100   100   000    Pre-fail  Always       -       0
195 Hardware_ECC_Recovered  0x001a   200   200   000    Old_age   Always       -       0
198 Offline_Uncorrectable   0x0030   100   100   000    Old_age   Offline      -       0
199 UDMA_CRC_Error_Count    0x003e   253   253   000    Old_age   Always       -       255
232 Available_Reservd_Space 0x0013   095   095   011    Pre-fail  Always       -       117
233 Media_Wearout_Indicator 0x0032   071   071   000    Old_age   Always       -       1232987101

SMART Error Log Version: 1
No Errors Logged

SMART Self-test log structure revision number 1
Num  Test_Description    Status                  Remaining  LifeTime(hours)  LBA_of_first_error
# 1  Short offline       Interrupted (host reset)      80%     18456         -
# 2  Short offline       Interrupted (host reset)      90%     18456         -
# 3  Short offline       Completed without error       00%     12752         -
# 4  Short offline       Completed without error       00%         5         -
# 5  Short offline       Completed without error       00%         3         -

SMART Selective self-test log data structure revision number 1
 SPAN  MIN_LBA  MAX_LBA  CURRENT_TEST_STATUS
    1        0        0  Not_testing
    2        0        0  Not_testing
    3        0        0  Not_testing
    4        0        0  Not_testing
    5        0        0  Not_testing
Selective self-test flags (0x0):
  After scanning selected spans, do NOT read-scan remainder of disk.
If Selective self-test is pending on power-up, resume after 0 minute delay.

This drive is a piece of junk, it is "just enough" SSD, which is why it came "free" as part of the selling points for a used laptop I bought off of eBay, and which is why I replaced it shortly thereafter with a proper Samsung EVO-series drive.

Comparing Microcontroller Package Sizes

When building electronic hardware prototypes, one major source of frustration for circuit designers is the difference in chip package sizes, even when they are identically named.

Each integrated-circuit manufacturer usually has slightly different specifications for their version of SO-8, TSSOP-20, QFN32, LQFP-64, and so on.

To get some clarity on the topic, and to see how each manufacturer’s dimensions could differ, I compiled together a bunch of excerpts from various publicly-available packaging datasheets.

I wanted to put these excerpts all in one place, so that I could visually and numerically check the differences (something humans are still good at, take that machines!)

So without further ado, please find the results of the survey at this Github repo, and please feel to either comment here or in the issues there if you have any suggestions. Pull requests are also always welcome.

Embedded C++11 FTW

This is a rant.

Need Moar C++11 In Embedded Software

We really need to embrace the use of C++11 in embedded software development with proper, type-safe, interrupt-driven events and callbacks, and we need to do this as natively as possible.

Since IAR finally released a C++11-compatible compiler this year, it should be the goal to actually make use of C++11 now that all of the “Big 3” (IAR, Keil, and GCC) support it.

(Shame on you, IAR, for taking this long to make this possible.)

I’d really like to see a clean C++ API on embedded chips taking advantage of C++11 features, running as close to the metal as possible.

mbed is close, but I’ve definitely seen many odd behaviors where it wraps the low level APIs provided by vendors and ends up blocking, crashing, or doing other stupid things that aren’t anticipated in the mbed API.

Which leads me to my next point.

Procedural, Embedded C With Blocking APIs Needs To Die

We should stop writing procedural C APIs for microcontrollers. Apple’s IOKit object-oriented driver architecture shows us a better way, and it was invented decades ago, even if not that many people ended up using it.

We should also stop using blocking APIs on as many microcontrollers as possible.

The bare-metal HALs and SDKs that offer these types of code examples should remove them because they tend to encourage bad programming practices, even when an RTOS is in use (because most microcontroller RTOSes don’t tend to properly handle event-driven wakeup on I/O and leave this to the user anyways).

I’ve seen too many examples of code where reading a serial port involves:

  1. Setting up the serial port read.
  2. Running a while() loop.
  3. Waiting until the serial port indicates that a single byte of data is available.
  4. Exiting the loop and reading the byte.
  5. Going back to step 1.

Think about this: In one millisecond, a 12MHz processor can run 12000 instructions, more or less. Let’s say it takes the unskilled program 20 instructions to set up the registers to receive a byte on the serial port and enter a while loop.

The processor will busy-wait for 11980 cycles, consuming 100% power. This is idiotic.

The primary benefit of thinking in events and callbacks is power-related, we really should avoid sleeps that are not real sleeps.

It kills me to see people still using superloops without proper sleep / WFI / WFE calls. Pretty much all Arduino code falls into this category.

My experience with mbed is also that its power consumption is quite atrocious. It insanely does not yet have a tickless scheduler as part of its RTX RTOS codebase, making it essentially useless for battery-powered devices.

Goals Hardware Manufacturers Should Pursue

Every hardware manufacturer has something that slightly odd about its software offerings. I never understood this. NXP has LPCOpen, which is a set of C SDKs for their LPC microcontrollers, but each chip has its own SDK ZIPfile blob which may or may not have a consistent API with other LPC microcontrollers. STM has its STMCube software which is in a similar position. Atmel and Atmel Studio is pretty good, but their chips often seem to be pretty expensive and they just automate away some of these issues via clever IDE wizards. Cypress and TI have decent hardware, but the PSoC C APIs never seemed all that easy to get around and I have no idea who pays for Code Composer Studio.

NXP has a decent set of development tools, STM does not make its own (seriously, WTF), neither does Nordic Semiconductor (who just leaves you to puzzle through their horrendously-architected nRF5 SDK and fight multiple times with various not-well-documented headers just to get printf with RTT working and to struggle with integrating multiple projects together to get the various types of hardware working together).

Silicon Labs has a fantastic development environment, with amazing debug, energy measurement (AEM is amazing), and low-power state management (setup EM4!) but no one really uses them. So sad.

But at the end of the day, I feel like I’m always porting, even between chips in the same family, from the same company.

So here’s what I wish these damned hardware manufacturers would actually do:

  • No more crappy SDKs with slight differences in APIs and implementations per chip.
  • No more wrapping crappy, blocking C APIs.
  • No more always needing to pass a pointer to a C struct as the first parameter of an API call.
  • No more writing delay loops that are while(delay) { NOP() }.
  • No more abusing the C preprocessor to generate or to validate code.
  • No more needing to copy and paste source files with minor modifications to use a second instance of hardware.
  • No more violations of Don’t Repeat Yourself (DRY), where a chip feature is controlled by a preprocessor flag in an sdk_config.h file, and by a statically-defined variable, and by a variable in a configuration struct pointer somewhere. (I’m looking at you, Nordic Semiconductor.)
  • No more writing code without measuring power consumption in your labs.
  • Use decent, modern, C++11 with Dependency Injection and well-architected objects that receive base addresses as parameters from your CMSIS microprocessor definitions to represent the peripherals in your microcontrollers. No more hard-to-change dependencies on your company’s CMSIS definitions, please!

Why is this so hard to get right? Baseline functionality should have me doing less plumbing and more coding on my own application and it is high time, in 2017, to get this right.

The rest of the programming world moved to object orientation years ago, and the resources available on today’s microcontrollers should allow us to place greater value on programmer time and programmer effectiveness.

We need to stop chasing the smallest possible firmware and start chasing the most bang-per-line-of-code and bang-per-minute-of-programmer-time.

Postscript

Whenever I see the code example:

I want to punch someone at Arduino for wasting so much electricity.