Skip to content

Commit

Permalink
Biasing finished in first iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
hpretl committed Jan 2, 2025
1 parent 48a2c75 commit a46bfcd
Show file tree
Hide file tree
Showing 7 changed files with 1,444 additions and 12 deletions.
43 changes: 35 additions & 8 deletions content/_sec_biasing.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -68,34 +68,61 @@ $$
V_\mathrm{ref} = V_\mathrm{g0}
$$ {#eq-bandgap-voltage}
remains. We thus have created an on-chip reference (called the "**bandgap reference**") which is absolutely constant with zero temperature coefficient. Of course, this is only true neglecting second-order effects, but nevertheless, reference accuracies of $\pm 1 \ldots 3\%$ without trimming are perfectly possible.
remains. We thus have created an on-chip reference (called the [*bandgap voltage reference*](https://en.wikipedia.org/wiki/Bandgap_voltage_reference)) which is almost independent of manufacturing tolerances with zero temperature coefficient. Of course, this is only true neglecting second-order effects, but nevertheless, reference accuracies of $\pm 1 \ldots 3\%$ without trimming are perfectly possible.
The originial implementation in [@Widlar_1971] uses NPN transistors. The question is, where do we find BJT in a CMOS process? Luckily, when looking at the typical implementations, we find that there is a layer sandwich of P-N-P available. While the PNPs constructed parasitically out of this available layers are available for free without extra processing cost, they are very slow, show unusually small $\beta < 10$, and the collector is tied to $\VSS$ as it is the substrate. Still, for bandgap references, they are very useful.
The original implementation in [@Widlar_1971] uses NPN transistors. The question is, where do we find BJT in a CMOS process? Luckily, when looking at the typical implementations, we find that there is a layer sandwich of P-N-P available. While the PNPs constructed parasitically out of this available layers are available for free without extra processing cost, they are very slow, show unusually small $\beta < 10$, and the collector is tied to $\VSS$ as it is the substrate. Still, for bandgap references, they are very useful.
A simple implemementation of a bandgap referece circuit is shown in @fig-bandgap-simple [@Gray_Meyer_5th_ed]. If we scale $R_1$ and $R_2$ correctly then we can achieve @eq-bandgap-voltage. Note that the output voltage is ca. $1.2\,\text{V}$, so operating this circuit on low supply voltages will be problematic.
A simple implementation of a bandgap reference circuit is shown in @fig-bandgap-simple [@Gray_Meyer_5th_ed]. If we scale $R_1$ and $R_2$ correctly then we can achieve @eq-bandgap-voltage. Note that the output voltage is ca. $1.2\,\text{V}$, so operating this circuit on low supply voltages will be problematic.
{{< include /figures/_fig_bandgap_reference_simple.qmd >}}
$M_1$ to $M_4$ are scaled in a way that in both branches the same bias current is flowing. Further, $M_1$ and $M_2$ ensure that there is the same potential at their sources. Since the PNP are scaled by the factor $n$ (thus the current density is different) so that the following voltage develops across $R_1$:
$$
\Delta \VBE = \frac{k T}{q} \ln n
\Delta \VBE = \frac{k T}{q} \ln m
$$
Hence, the bias current in all the branches is given by
$$
I_\mathrm{bias} = \frac{\Delta \VBE}{R_1} = \frac{1}{R_1} \frac{k T}{q} \ln n.
$$
I_\mathrm{bias} = \frac{\Delta \VBE}{R_1} = \frac{1}{R_1} \frac{k T}{q} \ln m.
$$ {#eq-bandgap-bias-current}
With $M_5$ we mirror this bias current into the output branch, and the output voltage $V_\mathrm{ref}$ is then given by
Inspecting @eq-bandgap-bias-current we see that $I_\mathrm{bias} = k_1 T$ is a linear function of temperature $T$, a property that is very useful and called **PTAT** (proportional to absolute temperature). With $M_5$ we mirror this bias current into the output branch, and the output voltage $V_\mathrm{ref}$ is then given by
$$
V_\mathrm{ref} = \VBE + \frac{R_2}{R_1} \frac{k T}{q} \ln n.
V_\mathrm{ref} = \VBE + \frac{R_2}{R_1} \frac{k T}{q} \ln m.
$$
By proper selection of $R_1$, $R_2$ and $n$ we can satisfy @eq-bandgap-voltage-with-temp to result in @eq-bandgap-voltage.
::: {.callout-note title="Improved Bandgap Reference"}
For an improved implementation of @fig-bandgap-simple, the current mirrors should be cascoded, and a startup circuit should be included to guarantee proper operation after enabling it. Further, @eq-vbe-vs-temp and @eq-delta-vbe-vs-temp build on the relationship $I_\mathrm{C} = f(\VBE)$, while we control $I_\mathrm{E}$ in this circuit. If $\beta$ is large then $I_\mathrm{C} \approx I_\mathrm{E}$, but this is not the case for the used PNPs.
:::
The circuit of @fig-bandgap-simple has been implemented in Xschem and is shown in @fig-bandgap-schematic. The current sources have been improved by using cascodes. No base current compensation is implemented, as it is assumed that the $\beta$ of the PNP is similar although they are operated at different emitter current densities. Note the addition of a startup branch with $M_\mathrm{startup}$ which is inactive during normal operation but will inject a startup current if no proper bias point has yet been found. There is no circuitry added for enabling/disabling the circuit, which would also be needed for a practical implementation.
![Simple bandgap reference circuit in Xschem.](./xschem/bandgap_simple.svg){#fig-bandgap-schematic}
The Xschem schematic is available [here](./xschem/bandgap_simple.sch) and the simulated reference voltage vs. temperature is shown in @fig-bandgap-sim-result.
```{python}
#| label: fig-bandgap-sim-result
#| echo: false
#| fig-cap: "Reference voltage from simulated bandgap circuit."
import numpy as np
import matplotlib.pyplot as plt
filename = "xschem/bandgap_simple.txt"
data = np.loadtxt(filename)
x = data[:, 0]
y = data[:, 1]
plt.ylim(1.105, 1.115)
plt.plot(x, y, linestyle='-', color='b')
plt.xlabel("Temperature (C)")
plt.ylabel("Vref (V)")
#plt.title("Reference Voltage of Bandgap")
plt.grid(True)
```
The circuit in @fig-bandgap-schematic works fine at $\VDD = 1.5\,\text{V}$, but would not work at $1.2\,\text{V}$ or lower. Improved circuit architectures for $<1\,\text{V}$ operation exist [@Banba_1999,@Eberlein_2018] but are outside the scope of this introductory course.
4 changes: 2 additions & 2 deletions figures/_fig_bandgap_reference_simple.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ with sd.Drawing(canvas='svg') as d:
elm.Line().down().length(1)
M2 = elm.AnalogNFet(offset_gate=False).anchor('drain').theta(0).reverse().label(r'$M_2$', ofst=-1.5)
R1 = elm.Resistor().down().label('$R_1$')
N2 = elm.BjtPnp().anchor('emitter').right().label('$n$')
N2 = elm.BjtPnp().anchor('emitter').right().label('$m$')
elm.Ground().at(N2.collector)
elm.Line().left().length(0.5).at(N2.base)
elm.Line().down().toy(N2.collector)
Expand Down Expand Up @@ -63,7 +63,7 @@ with sd.Drawing(canvas='svg') as d:
d.pop()
elm.Line().down().toy(M2.source)
R2 = elm.Resistor().down().label('$R_2$')
N2 = elm.BjtPnp().anchor('emitter').right().label('$n$')
N2 = elm.BjtPnp().anchor('emitter').right().label('$m$')
elm.Ground().at(N2.collector)
elm.Line().left().length(0.5).at(N2.base)
elm.Line().down().toy(N2.collector)
Expand Down
29 changes: 27 additions & 2 deletions references.bib
Original file line number Diff line number Diff line change
@@ -1,13 +1,39 @@
%% This BibTeX bibliography file was created using BibDesk.
%% https://bibdesk.sourceforge.io/
%% Created for Harald Pretl at 2025-01-02 10:21:08 +0100
%% Created for Harald Pretl at 2025-01-02 13:50:50 +0100
%% Saved with string encoding Unicode (UTF-8)
@article{Eberlein_2018,
author = {Eberlein, Matthias and Panagopoulos, Georgios and Pretl, Harald},
date-added = {2025-01-02 13:50:32 +0100},
date-modified = {2025-01-02 13:50:47 +0100},
doi = {10.1109/asscc.2018.8579306},
journal = {2018 IEEE Asian Solid-State Circuits Conference (A-SSCC)},
month = {11},
pages = {99--102},
title = {{A 40nW, Sub-IV Truly `Digital' Reverse Bandgap Reference Using Bulk-Diodes in 16nm FinFET}},
volume = {00},
year = {2018},
bdsk-url-1 = {https://doi.org/10.1109/asscc.2018.8579306}}

@article{Banba_1999,
author = {Banba, H. and Shiga, H. and Umezawa, A. and Miyaba, T. and Tanzawa, T. and Atsumi, S. and Sakui, K.},
date-added = {2025-01-02 13:48:37 +0100},
date-modified = {2025-01-02 13:49:07 +0100},
doi = {10.1109/4.760378},
journal = {IEEE Journal of Solid-State Circuits},
number = {5},
pages = {670-674},
title = {A {CMOS} bandgap reference circuit with {sub-1-V} operation},
volume = {34},
year = {1999},
bdsk-url-1 = {https://doi.org/10.1109/4.760378}}

@article{Widlar_1971,
author = {Widlar, R.J.},
date-added = {2025-01-02 10:20:16 +0100},
Expand All @@ -19,7 +45,6 @@ @article{Widlar_1971
pages = {2--7},
rating = {5},
title = {{New developments in IC voltage regulators}},
url = {http://ieeexplore.ieee.org/document/1050151/},
volume = {6},
year = {1971},
bdsk-url-1 = {https://doi.org/10.1109/jssc.1971.1050151}}
Expand Down
117 changes: 117 additions & 0 deletions sizing/sizing_bandgap_simple.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Sizing for Bandgap Reference \n",
"\n",
"**Copyright 2025 Harald Pretl**\n",
"\n",
"Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"you may not use this file except in compliance with the License.\n",
"You may obtain a copy of the License at\n",
"http://www.apache.org/licenses/LICENSE-2.0"
]
},
{
"cell_type": "code",
"execution_count": 99,
"metadata": {},
"outputs": [],
"source": [
"# read table data\n",
"from pygmid import Lookup as lk\n",
"import numpy as np\n",
"lv_nmos = lk('sg13_lv_nmos.mat')\n",
"lv_pmos = lk('sg13_lv_pmos.mat')\n",
"# list of parameters: VGS, VDS, VSB, L, W, NFING, ID, VT, GM, GMB, GDS, CGG, CGB, CGD, CGS, CDD, CSS, STH, SFL\n",
"# if not specified, minimum L, VDS=max(vgs)/2=0.9 and VSB=0 are used "
]
},
{
"cell_type": "code",
"execution_count": 100,
"metadata": {},
"outputs": [],
"source": [
"# define the given values\n",
"id_spec = 10e-6\n",
"gm_id_spec = 20\n",
"L_spec = 1"
]
},
{
"cell_type": "code",
"execution_count": 101,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"VGS of NMOS = 0.356 V\n",
"VGS of PMOS = 0.387 V\n"
]
}
],
"source": [
"# get the vgs for NMOS and PMOS\n",
"vgsn = lv_nmos.look_upVGS(GM_ID=gm_id_spec, L=L_spec, VDS=0.75, VSB=0.8)\n",
"vgsn = lv_nmos.look_upVGS(GM_ID=gm_id_spec, L=L_spec, VDS=vgsn, VSB=0.8)\n",
"\n",
"vgsp = lv_pmos.look_upVGS(GM_ID=gm_id_spec, L=L_spec, VDS=0.75, VSB=0.0)\n",
"vgsp = lv_pmos.look_upVGS(GM_ID=gm_id_spec, L=L_spec, VDS=vgsp, VSB=0.0)\n",
"\n",
"print('VGS of NMOS =', round(float(vgsn), 3), 'V')\n",
"print('VGS of PMOS =', round(float(vgsp), 3), 'V')"
]
},
{
"cell_type": "code",
"execution_count": 102,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"NMOS W = 14.45 um, rounded W = 14.5 um\n",
"PMOS W = 51.9 um, rounded W = 52.0 um\n"
]
}
],
"source": [
"# find the W of the transistors\n",
"idn_w = lv_nmos.lookup('ID_W', GM_ID=gm_id_spec, L=L_spec, VDS=vgsn, VSB=0)\n",
"wn = id_spec / idn_w\n",
"print('NMOS W =', round(wn, 2), 'um, rounded W =', round(wn*2)/2, 'um')\n",
"\n",
"idp_w = lv_pmos.lookup('ID_W', GM_ID=gm_id_spec, L=L_spec, VDS=vgsp, VSB=0)\n",
"wp = id_spec / idp_w\n",
"print('PMOS W =', round(wp, 2), 'um, rounded W =', round(wp*2)/2, 'um')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Loading

0 comments on commit a46bfcd

Please sign in to comment.