The Base-16 Multiplier: What Hexadecimal Times Tables Actually Are
A hexadecimal times table is a base-16 multiplication matrix used to calculate the products of numbers represented by digits 0-9 and letters A-F, primarily for computing memory offsets, buffer sizes, and register values in embedded systems. While a physical wiring diagram doesn't care what base you use to count electrons, base-16 math fundamentally changes how you calculate Direct Memory Access (DMA) buffer boundaries, I2C sub-addresses, and LED matrix mapping in the firmware driving your circuit. When you are allocating memory on a microcontroller, the compiler and the hardware registers speak in hex and binary; doing the math in decimal and converting back introduces rounding errors and off-by-one bugs that crash your system.
Beginners commonly confuse hex multiplication by 0x10 with decimal multiplication by 10. In hex, multiplying by 0x10 is equivalent to a bitwise left-shift by 4 (which is multiplying by 16 in decimal). Confusing the two will immediately corrupt your memory pointers, causing hard faults or silent data overwrites on your microcontroller.
0x10 simply appends a zero to the end (e.g., 0x4A * 0x10 = 0x4A0). Multiplying by 0x100 appends two zeros. This is the exact base-16 equivalent of multiplying by 10 or 100 in the decimal system, and it is the most frequently used 'times table' shortcut in embedded C/C++.
Worked Example: Calculating an ESP32 DMA Buffer Offset
Let's look at a real-world scenario where pulling out a hexadecimal times table saves you from a memory allocation fault. You are configuring an ESP32-S3 to drive a 144-LED WS2812B addressable strip using the I2S peripheral in parallel mode via the ESP-IDF framework. The I2S driver requires you to define the DMA buffer size in the i2s_config_t struct, and the hardware mandates that the buffer length must be a multiple of 4 bytes for 32-bit alignment.
Each WS2812B LED requires 3 bytes of GRB color data. Therefore, the raw payload is 144 LEDs × 3 bytes. Let's do the math in hex to match the register expectations:
- 144 in decimal is 0x90 in hex.
- 3 in decimal is
0x03in hex. - Using the hex times table:
9 * 3 = 27(decimal). 27 in hex is0x1B. - Therefore,
0x90 * 0x03 = 0x1B0.
Converting 0x1B0 back to decimal to verify: (1 × 256) + (11 × 16) + 0 = 432 bytes. Since 432 is perfectly divisible by 4, our DMA buffer length is valid. If your custom protocol required adding a 16-byte (0x10) header to each DMA transfer, your new total offset calculation becomes 0x1B0 + 0x10 = 0x1C0. By keeping the math in hex, you align your thinking directly with the ESP-IDF I2S API documentation, which defines buffer constraints in hex-aligned memory blocks.
Where You Meet This in Practice
You won't see a hex times table printed on a jobsite wiring diagram, but you will use it constantly when writing firmware for hardware interfaces. Here are the three most common bench scenarios where base-16 multiplication is mandatory:
1. Memory-Mapped GPIO Registers
Microcontrollers map physical pins to memory addresses. On the ESP32, the GPIO base address is 0x3FF44000. Each pin's configuration register is spaced 4 bytes (0x04) apart. If you need to manually toggle the configuration register for GPIO Pin 5, you must calculate the offset: 5 * 0x04 = 0x14. The exact memory address you write to is 0x3FF44000 + 0x14 = 0x3FF44014. If you mistakenly multiplied 5 by 4 in decimal and treated the result as hex, you would write to the wrong register, potentially bricking the boot sequence.
2. I2C Multiplexer Channel Offsets
When using an I2C multiplexer like the TCA9548A to connect multiple identical sensors (e.g., eight BME280 environmental sensors) to a single Arduino or Raspberry Pi I2C bus, you send a control byte to switch channels. The control register uses bitmasks. If you are writing a loop to poll all sensors and need to calculate the bitmask shift, you are essentially multiplying channel indices by powers of 2, which translates directly to hex shifts. Understanding how 0x01 << channel maps to the TI TCA9548A datasheet control register requires fluent hex multiplication.
3. RGB LED Array Mapping and Color Math
When scaling a 12-bit ADC reading (0x000 to 0xFFF) down to an 8-bit PWM duty cycle (0x00 to 0xFF) for an LED, you divide by 16. In hex, dividing by 16 is a right-shift by 1 nibble (dividing by 0x10). Conversely, if you are expanding an 8-bit color value to a 12-bit DAC output for a high-fidelity audio or lighting project, you multiply by 0x10 (appending a zero) or use a hex times table to multiply by 0x11 to ensure smooth scaling across the entire dynamic range without clipping the top end.
Quick-Reference Hex Multiplication Grid
Memorizing a full 16x16 hex times table is unnecessary for 99% of electronics work. Instead, professional firmware engineers memorize the multipliers that correspond to bitwise shifts and common bus widths. Below is the high-utility subset of the hex times table you should keep on your bench reference card.
| Hex Value | x 0x02 (Shift Left 1) | x 0x04 (Shift Left 2) | x 0x08 (Shift Left 3) | x 0x0A (Decimal 10) | x 0x10 (Shift Left 4) |
|---|---|---|---|---|---|
| 0x01 | 0x02 | 0x04 | 0x08 | 0x0A | 0x10 |
| 0x02 | 0x04 | 0x08 | 0x10 | 0x14 | 0x20 |
| 0x03 | 0x06 | 0x0C | 0x18 | 0x1E | 0x30 |
| 0x04 | 0x08 | 0x10 | 0x20 | 0x28 | 0x40 |
| 0x05 | 0x0A | 0x14 | 0x28 | 0x32 | 0x50 |
| 0x08 | 0x10 | 0x20 | 0x40 | 0x50 | 0x80 |
| 0x0A | 0x14 | 0x28 | 0x50 | 0x64 | 0xA0 |
| 0x0F | 0x1E | 0x3C | 0x78 | 0x96 | 0xF0 |
Note: Multiplying by 0x0A (hex for decimal 10) is the most common trap. Notice that 0x05 * 0x0A = 0x32 (which is 50 in decimal), not 0x50. Always verify your decimal-to-hex conversions when mixing base-10 physical counts (like 50 LEDs) with base-16 memory addresses.
Frequently Asked Questions
How do I multiply hex numbers without a programmer calculator?
Convert the hex numbers to decimal, multiply them using standard base-10 math, and convert the result back to hex. For example, to multiply 0x1C by 0x03: convert 0x1C to 28, multiply 28 × 3 = 84, and convert 84 back to 0x54. Alternatively, break the hex number into nibbles and distribute the multiplication: 0x1C * 0x03 becomes (0x10 * 0x03) + (0x0C * 0x03), which is 0x30 + 0x24 = 0x54. This distributive method is faster once you memorize the single-digit hex times table (0x1 through 0xF).
Why do embedded programmers use hex times tables instead of decimal?
Microcontrollers organize memory in binary, and binary is difficult for humans to read in long strings (e.g., 10110000). Hexadecimal is a direct 1-to-1 mapping of binary nibbles (4 bits). One hex digit represents exactly four binary bits. When you multiply by 0x10 in hex, you are shifting the binary data exactly one nibble to the left. Using decimal math obscures this direct relationship to the underlying binary hardware registers, making it harder to spot alignment errors, bitmask overlaps, and buffer boundary faults.
What is the hex times table equivalent of multiplying by 10 in decimal?
The hex equivalent of the decimal number 10 is 0x0A. Therefore, multiplying by 10 in decimal is the same as multiplying by 0x0A in hex. However, if you are asking what hex operation mimics the 'append a zero' trick of decimal multiplication by 10, that operation is multiplying by 0x10 (which is 16 in decimal). This distinction is the most frequent source of bugs for developers transitioning from high-level web programming to bare-metal embedded C.






