
ADC Codes & Polarity: Straight, Offset-Binary, Two’s-Complement
Global electronic component supplier ERSAELECTRONICS: Rich inventory for one-stop shopping. Inquire easily, and receive fast, customized solutions and quotes.
ADC Codes & Polarity — Straight vs Offset-Binary vs Two’s-Complement
Code format equals signal polarity and sets what your MCU or DSP expects. Mapping it wrong leads to zero shifts or inverted signs. This page shows when to use each format, how to convert safely, and how to verify the setup with a two-minute ramp or sine test.

Within 48 hours you’ll receive three safe options with indicative lead time, price ranges, and short notes on front-end/Vref and polarity risks.
Unipolar vs Bipolar Basics
Signal polarity sets the right code format. Unipolar (0…Vref) maps cleanly with straight binary; bipolar (−FS…+FS) is best handled as two’s-complement, while offset-binary often bridges legacy interfaces. Use LSB = FS / 2n (where unipolar FS=Vref; bipolar FS=2·Vref), and treat +FS ≈ FS − 1 LSB.
Range | Zero location | Typical format | Common use |
---|---|---|---|
0…Vref (FS = Vref) | Left end (0 V) | Straight binary | Light/pressure sensors, current loop, single-ended signals |
−Vref…+Vref (FS = 2·Vref) | Mid-scale | Two’s-complement (offset-binary for legacy/bridge) | Bridge sensors with INAs, audio/vibration, signed DSP |
Note: LSB = FS / 2n. Endpoint conventions vary — +FS ≈ FS − 1 LSB.

If zero sits at mid-scale, you likely want two’s-complement; if it sits at 0 V, straight binary fits. Next: Formats · Conversions.
Related: ADC Types (SAR / ΔΣ / Pipeline / Flash), Resolution & ENOB (step size).
Need a quick shortlist? Submit your BOM (48h).
Formats Explained
Code format defines how numeric codes map to physical levels and zero. Pick the format that matches your signal polarity and your MCU/DSP expectations before you write any math or filters.
2.1 Straight Binary
Definition. Code ∈ [0, 2n−1] maps 0…FS (for unipolar, FS = Vref).
Formula. V = LSB × Code, with LSB = FS / 2n. Endpoint convention: +FS ≈ FS − 1 LSB.
- Unipolar sensors (light, pressure, gas) or current-loop/voltage outputs with a floor near 0 V.
- Simple scaling and display; no signed DSP needed.
- You want monotonic codes from left (zero) to right (full scale).
- Treating straight data as if mid-scale were zero (that’s offset/two’s behavior).
- Off-by-1 at full scale by ignoring +FS ≈ FS − 1 LSB.
- Feeding left/right-justified words into math without first aligning bits.

Example (n=12): Code 0 → 0 V; Code 4095 → FS − 1 LSB.
2.2 Offset-Binary
Definition. Mid-scale is zero; the MSB indicates sign polarity.
Formula. V = LSB × (Code − 2n−1).
- Interfacing with legacy/board-level systems that define zero at mid-scale.
- Your AFE/ADC defaults to offset-binary or can be register-configured this way.
- You want an easy bridge to two’s-complement via MSB inversion in firmware.
- Flipping all bits to get two’s-complement (correct fix: invert MSB only).
- Wrong bit-width/alignment so mid-code isn’t exactly 2n−1.
- Treating offset-binary as signed in downstream math, causing zero shift.

Example (n=12): Code 0x800 → 0; 0x000 → −FS; 0xFFF → +FS − 1 LSB.
2.3 Two’s-Complement
Definition. Interpret code as a signed integer S ∈ [−2n−1, 2n−1−1].
Formula. V = LSB × S (LSB and FS defined by your bipolar span).
- Bipolar signals (audio, vibration, acceleration) must feed signed DSP/filters.
- Fixed-point pipelines (FFT/control loops) benefit from native signed values.
- MCU/FPGA peripherals or drivers explicitly expect signed samples.
- Missing sign extension (reading 16-bit but treating as unsigned).
- Left-justified reads shifting the sign bit out of place — align before interpretation.
- Overflow/underflow without saturation or clipping strategy.

Example (n=16): 0x0000 → 0; 0x7FFF → +FS − 1 LSB; 0x8000 → −FS.
Related: ADC Types (SAR / ΔΣ / Pipeline / Flash), Resolution & ENOB.
Quick Formulas
Copy-ready formulas you can drop into firmware or analysis notebooks. Keep bit-width and alignment consistent before applying them.
V = LSB × Code
LSB = FS / 2^n
(for unipolar,FS = Vref
)Code ∈ [0, 2^n−1]
, monotonic map 0…FS- Endpoint: +FS ≈ FS − 1 LSB
V = LSB × (Code − 2^(n−1))
- Mid-scale is zero:
mid = 2^(n−1)
- MSB indicates sign; to Two’s, invert MSB only
- Ensure bit-width/alignment consistency
interpret Code as signed S; V = LSB × S
S ∈ [−2^(n−1), 2^(n−1)−1]
(do proper sign extension)- Best for ± signals and DSP/fixed-point pipelines
- Align left/right-justified words before interpreting
Reminder: LSB = FS / 2n; endpoint conventions vary (+FS ≈ FS − 1 LSB). Keep bit-width and alignment consistent first. Need exact mapping rules? See conversions · Seeing zero shifts or inverted signs? Check pitfalls.

Need help applying to your BOM? Submit your BOM (48h) .
3-bit Intuition Panel
Build intuition with a tiny n=3 example: where zero sits, how codes map, and what the endpoints mean. These 3-bit ADC codes tables show straight, offset-binary, and two’s-complement side by side. For n=3, LSB = FS / 23 = FS/8.
Unipolar map with zero at the left end; codes rise monotonically.
Code | Value (LSB) | Notes |
---|---|---|
000 | 0 | Zero at left |
001 | 1 | |
010 | 2 | |
011 | 3 | |
100 | 4 | |
101 | 5 | |
110 | 6 | |
111 | 7 | ≈ FS − 1 LSB |
Zero sits at mid-scale; invert MSB to bridge to two’s-complement.
Code | Value (LSB) | Notes |
---|---|---|
000 | −4 | |
001 | −3 | |
010 | −2 | |
011 | −1 | |
100 | 0 | Mid-code |
101 | +1 | |
110 | +2 | |
111 | +3 |
Signed integer representation; ideal for DSP pipelines and two’s-complement 3-bit examples.
Code | Signed S | Notes |
---|---|---|
000 | 0 | Zero at mid-scale |
001 | +1 | |
010 | +2 | |
011 | +3 | Max positive |
100 | −4 | Min (negative) |
101 | −3 | |
110 | −2 | |
111 | −1 |

Reminder: LSB = FS / 2n; endpoint conventions vary (+FS ≈ FS − 1 LSB). Keep bit-width and left/right justification consistent before you interpret format. Need exact mapping rules? See conversions. Want to verify quickly? Run the 2-minute test.
Keywords: 3-bit ADC codes, offset-binary 3-bit table, two’s-complement 3-bit examples.
Conversions That Matter
The most common mapping mistakes come from mixing formats or aligning bits incorrectly. Use the rules below and validate on a few boundary codes before you write filters or scalers.
twos = offset ^ (1 << (n-1))
Invert MSB only; keep the other bits. Always clamp to n bits: & ((1<<n)-1)
.
offset = (straight + 2^(n-1)) mod 2^n
Equivalent bit trick: offset = straight ^ (1 << (n-1))
(flip MSB). This moves zero from left end to mid-scale.
Left/right-justified is bit alignment, not a code format. Align to n valid bits first, then apply the format conversion and math.
Start (straight) | Straight → Offset | Offset → Two’s | Interpretation (signed S) |
---|---|---|---|
0x7FF (2047) | 0x7FF + 0x800 = 0xFFF (≡ 0x7FF ^ 0x800) | 0xFFF ^ 0x800 = 0x7FF | Two’s 0x7FF → +2047 (max positive) |
0x800 (2048) | 0x800 + 0x800 = 0x000 (mod 4096) | 0x000 ^ 0x800 = 0x800 | Two’s 0x800 → −2048 (min negative) |
0xFFF (4095) | 0xFFF + 0x800 = 0x7FF (mod 4096) | 0x7FF ^ 0x800 = 0xFFF | Two’s 0xFFF → −1 |
Notes: ^
is XOR; “mod 2n” equals keeping the low n bits (& ((1<<n)-1)
).
// n-bit align (e.g., 12-bit left-justified in 16-bit -> >> 4)
static inline uint16_t align_n(uint16_t raw16, int shift){ return raw16 >> shift; }
static inline uint16_t straight_to_offset(uint16_t x, int n){
return (x ^ (1u<<(n-1))) & ((1u<<n)-1);
}
static inline uint16_t offset_to_twos(uint16_t x, int n){
return (x ^ (1u<<(n-1))) & ((1u<<n)-1);
}
static inline int32_t twos_to_signed(uint16_t x, int n){
uint32_t m=(1u<<n)-1; x&=m;
return (x & (1u<<(n-1))) ? (int32_t)(x | ~m) : (int32_t)x; // sign-extend
}
def straight_to_offset(x,n): return (x ^ (1<<(n-1))) & ((1<<n)-1)
def offset_to_twos(x,n): return (x ^ (1<<(n-1))) & ((1<<n)-1)
def align_right(raw, n, word_bits=16, left_justified=True):
return (raw >> (word_bits-n)) if left_justified else (raw & ((1<<n)-1))



Next: Common pitfalls & quick fixes · Want to validate fast? 2-minute verification.
Choose the Right Format
Single-ended sensing (current loop / light / pressure)
- Signal: unipolar 0…Vref inputs (4–20 mA, 0–10 V after scaling, light/gas/pressure, etc.).
- Recommendation: Straight Binary (zero at the left end; simplest scaling/thresholds).
- Pitfalls: treating straight as offset; ignoring +FS ≈ FS − 1 LSB.
Immediate action: if the peripheral only outputs offset, convert in firmware: straight = offset ^ (1<<(n-1))
.
Bridge / instrumentation front-end (differential, strain, load cell)
- Signal: true ± with mid-scale zero, via INA/programmable gain into the ADC.
- Recommendation: Two’s-Complement (feeds signed DSP/filters directly).
- Pitfalls: reading offset-binary as two’s; misaligned left/right-justified words shifting the sign bit.
Immediate action: enable two’s mode; if only offset is available, invert MSB only: twos = offset ^ (1<<(n-1))
.
Audio / vibration → DSP
- Signal: acoustic/acceleration/vibration destined for frequency-domain processing (FFT/filters/control).
- Recommendation: Two’s-Complement (natural match for fixed-point libraries).
- Pitfalls: missing sign extension; using left-justified samples without aligning first.
Immediate action: align to n bits → interpret as two’s → convert LSB to physical units; add saturation/clipping in the ISR.

Remember: alignment ≠ format — align bits to n first, then interpret format. Need rules? See conversions · Seeing anomalies? Check pitfalls · Want a quick validation? 2-minute test.
Common Pitfalls & Debug
Most ADC headaches are polarity/format mixups or bit-alignment errors. Use this one-screen guide: Symptom → Likely cause → Quick fix.
Symptom | Likely cause | Quick fix |
---|---|---|
Zero at mid but readings are globally shifted | Offset-binary treated as two’s (or vice versa) | Verify mid-code = 2^(n−1) first, then convert with the MSB-only rule |
Sign looks inverted | Flipped all bits when converting offset ↔ two’s | Use twos = offset ^ (1 << (n-1)) (invert MSB only) |
Full-scale off by 1 LSB | Endpoint convention mismatch | Treat +FS ≈ FS − 1 LSB; adjust scaling/display |
DMA data looks “striped” or garbage | Left/right-justified misalignment | Align to n valid bits (shift/mask) before interpreting format |
Mid-code not exactly centered | Wrong bit-width or truncation; no masking | Clamp: code &= (1<<n) - 1 prior to math/sign-extension |

- Alignment ≠ format — shift/mask first, then interpret/convert.
- Always clamp to n bits before arithmetic or sign-extension.
- Validate on three boundary codes: mid (
2^(n−1)
), +FS−1 LSB, and −FS; or run the 2-minute ramp/sine test.
Need the exact mapping rules? See conversions.
Verification & Test Snippets
A two-minute sanity check to confirm both format and bit alignment before data hits filters or FFT. Use a ramp or a short sine capture, then validate mid-code, sign, endpoints, and alignment.
- Align & clamp:
code = (raw >> shift) & ((1<<n)-1)
to get n valid bits. - Mid-code: check if zero sits at
2^(n−1)
(offset/two’s path) or at the left end (straight). - Sign sanity: two’s should be symmetric around 0; offset symmetric around mid; straight has no negative side.
- Endpoints: observe 0 and
2^n−1
; treat +FS ≈ FS − 1 LSB. - Boundary probe: test three codes (e.g., n=12:
0x7FF
,0x800
,0xFFF
) and confirm expectations.
Method A — Ramp (monotone)
- Capture 2–4k samples while input ramps up or down.
- Straight: codes increase 0→
2^n−1
with zero at the left end. - Offset: a clear boundary at
mid = 2^(n−1)
; symmetry on both sides. - Two’s: when interpreted as signed, the sequence crosses 0 monotonically.
Method B — Sine code-density
- Capture 2–10k samples of a sine (no strict coherence required).
- Two’s: histogram centered at 0; negative and positive counts are similar.
- Offset: histogram centered at
mid
; nearly no “negative” notion. - Straight: distribution sits to the right (no negative half).
- Zero shift or sign inversion indicates a format/align mismatch.
// Align to n bits (e.g., 12-bit left-justified in 16-bit)
static inline uint16_t align_n(uint16_t raw16, int n, int left_justified){
int shift = left_justified ? (16 - n) : 0;
return (raw16 >> shift) & ((1u<<n) - 1);
}
// Offset <-> Two's (MSB only)
static inline uint16_t offset_to_twos(uint16_t x, int n){
return (x ^ (1u<<(n-1))) & ((1u<<n)-1);
}
static inline uint16_t straight_to_offset(uint16_t x, int n){
return (x ^ (1u<<(n-1))) & ((1u<<n)-1); // same as +2^(n-1) mod 2^n
}
// Two's to signed 32 (sign extension)
static inline int32_t twos_to_s32(uint16_t x, int n){
uint32_t m = (1u<<n) - 1; x &= m;
return (x & (1u<<(n-1))) ? (int32_t)(x | ~m) : (int32_t)x;
}
import numpy as np
raw = np.fromfile("samples_u16.bin", dtype=np.uint16) # or np.loadtxt("log.csv", dtype=np.uint16)
n, left_justified = 12, True
shift = (16 - n) if left_justified else 0
code = (raw >> shift) & ((1<<n)-1)
def offset_to_twos(x,n): return (x ^ (1<<(n-1))) & ((1<<n)-1)
def twos_to_s32(x,n):
m=(1<<n)-1; x = x & m; neg = (x & (1<<(n-1))) != 0
return np.where(neg, x | ~m, x).astype(np.int32)
mid = 1<<(n-1)
s_off = code - mid
s_twos = twos_to_s32(offset_to_twos(code, n), n)
print("mean(code)=", code.mean(), " mid=", mid, " mean(s_twos)=", s_twos.mean(),
" neg/pos=", (s_twos<0).sum(), (s_twos>=0).sum())
Plot two histograms: one centered at mid
(offset path) and one centered at 0
(two’s path). A shifted center suggests a wrong mapping or alignment.

- Alignment first, format second: shift/mask to n bits before conversion or sign extension.
- Confirm
mid = 2^(n−1)
and treat +FS ≈ FS − 1 LSB. - When in doubt, test the three boundary codes or run the ramp/sine density check.
Need exact conversion formulas? See conversions · Seeing odd symptoms? Check pitfalls.
FAQ — Codes & Polarity
When should I use straight vs offset-binary vs two’s-complement?
How do I convert offset-binary to two’s-complement safely?
Why do zero shifts or inverted signs appear?
MCU expects signed, but the ADC outputs offset—what now?
Do left-justified outputs change the code format?
Still unclear? Submit your BOM (48h).
Get a safe shortlist in 48h
Within 48 hours you’ll receive three safe options with indicative lead time, price ranges, and short notes on front-end/Vref and polarity risks.
