EN | JP | Last update: 2025-12-26

Chapter 2: Spin Transfer Torque (STT)

Slonczewski-Berger Model and Magnetization Dynamics

Reading Time: 35-45 min Difficulty: Intermediate Code Examples: 7

Spin Transfer Torque (STT) is the torque exerted on magnetization by spin-polarized current flowing through a magnetic material. Theoretically predicted independently by Slonczewski and Berger in 1996, it forms the operating principle of modern STT-MRAM. In this chapter, we learn from the theoretical foundations of STT through magnetization switching dynamics to device design applications.


2.1 Physical Origin of Spin Transfer Torque

When spin-polarized current passes through a magnetic material, the spin angular momentum of electrons is transferred to the magnetization. This is the origin of spin transfer torque.

Conservation of Angular Momentum

When spin-polarized electrons enter a ferromagnet, their spins interact with the local magnetization $\mathbf{M}$ and change direction. By angular momentum conservation, the lost electron spin angular momentum is transferred to the magnetization:

$$ \frac{d\mathbf{S}_{\text{electron}}}{dt} + \frac{d\mathbf{S}_{\text{magnet}}}{dt} = 0 $$
flowchart LR subgraph Fixed Layer P[Pinned Layer
M_p fixed] end subgraph Spacer S[Non-magnetic Layer
Cu/MgO] end subgraph Free Layer F[Free Layer
M_f switchable] end P -->|Spin-polarized current| S S -->|Spin transfer| F style P fill:#e74c3c,stroke:#c0392b,color:#fff style S fill:#3498db,stroke:#2980b9,color:#fff style F fill:#2ecc71,stroke:#27ae60,color:#fff

Slonczewski Model

Slonczewski formulated STT in GMR/TMR devices. The spin transfer torque is expressed as:

$$ \boldsymbol{\tau}_{\text{STT}} = \frac{\hbar}{2e} \frac{I P}{A M_s t_F} g(\theta) \mathbf{m} \times (\mathbf{m} \times \mathbf{m}_p) $$

where:

Code Example 2.1: Angular Dependence of STT

"""
Angular dependence of Slonczewski STT
"""
import numpy as np
import matplotlib.pyplot as plt

def slonczewski_g(theta, P, Lambda=1.5):
    """
    Slonczewski angular factor

    Parameters:
    theta: Relative angle between free and pinned layers
    P: Spin polarization
    Lambda: Spin asymmetry parameter
    """
    cos_theta = np.cos(theta)
    g = P * Lambda**2 / (Lambda**2 + 1 + (Lambda**2 - 1) * cos_theta)
    return g

# Plot angular dependence
theta = np.linspace(0, np.pi, 200)
P_values = [0.3, 0.5, 0.7]

plt.figure(figsize=(10, 6))

for P in P_values:
    g = slonczewski_g(theta, P)
    plt.plot(np.degrees(theta), g, linewidth=2, label=f'P = {P}')

plt.xlabel('Relative Angle θ (degrees)', fontsize=12)
plt.ylabel('Slonczewski Factor g(θ)', fontsize=12)
plt.title('STT Angular Dependence (Slonczewski Model)', fontsize=14)
plt.legend()
plt.grid(True, alpha=0.3)
plt.xlim(0, 180)
plt.show()

print("θ=0° (parallel): STT minimum")
print("θ=180° (antiparallel): STT maximum")

2.2 LLG Equation with STT

Magnetization dynamics is described by the Landau-Lifshitz-Gilbert (LLG) equation. The LLG equation including STT is:

$$ \frac{d\mathbf{m}}{dt} = -\gamma \mathbf{m} \times \mathbf{H}_{\text{eff}} + \alpha \mathbf{m} \times \frac{d\mathbf{m}}{dt} + \boldsymbol{\tau}_{\text{STT}} $$

where $\gamma$ is the gyromagnetic ratio and $\alpha$ is the Gilbert damping constant.

Two Components of STT

STT can be decomposed into two orthogonal components:

$$ \boldsymbol{\tau}_{\text{STT}} = a_J \mathbf{m} \times (\mathbf{m} \times \mathbf{m}_p) + b_J \mathbf{m} \times \mathbf{m}_p $$

Code Example 2.2: Numerical Solution of LLG with STT

"""
Numerical simulation of LLG equation with STT
"""
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

def llg_with_stt(m, t, gamma, alpha, H_eff, a_J, m_p):
    """
    LLG equation with STT

    Parameters:
    m: Magnetization vector (normalized)
    gamma: Gyromagnetic ratio (rad/s/T)
    alpha: Gilbert damping
    H_eff: Effective field vector (T)
    a_J: STT strength
    m_p: Pinned layer magnetization direction
    """
    m = m / np.linalg.norm(m)  # Normalize

    # Precession term
    precession = -gamma * np.cross(m, H_eff)

    # Damping term
    damping = alpha * np.cross(m, precession)

    # STT damping-like torque
    stt = a_J * np.cross(m, np.cross(m, m_p))

    dmdt = precession + damping + stt
    return dmdt

# Parameters
gamma = 1.76e11  # rad/s/T
alpha = 0.01
H_eff = np.array([0, 0, 0.1])  # Anisotropy field in z-direction (T)
m_p = np.array([0, 0, 1])  # Pinned layer: +z direction

# Time settings
t_max = 5e-9  # 5 ns
t = np.linspace(0, t_max, 5000)

# Initial condition (slightly tilted from z-axis)
m0 = np.array([0.1, 0, 0.995])
m0 = m0 / np.linalg.norm(m0)

# Comparison for different STT strengths
a_J_values = [0, 5e10, 1e11, 2e11]

fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes = axes.flatten()

for ax, a_J in zip(axes, a_J_values):
    sol = odeint(llg_with_stt, m0, t, args=(gamma, alpha, H_eff, a_J, m_p))

    ax.plot(t*1e9, sol[:, 0], 'r-', label='$m_x$', linewidth=1.5)
    ax.plot(t*1e9, sol[:, 1], 'g-', label='$m_y$', linewidth=1.5)
    ax.plot(t*1e9, sol[:, 2], 'b-', label='$m_z$', linewidth=1.5)

    ax.set_xlabel('Time (ns)', fontsize=11)
    ax.set_ylabel('Magnetization Component', fontsize=11)
    ax.set_title(f'$a_J$ = {a_J:.0e} rad/s', fontsize=12)
    ax.legend()
    ax.grid(True, alpha=0.3)
    ax.set_ylim(-1.1, 1.1)

plt.suptitle('Magnetization Dynamics with STT', fontsize=14)
plt.tight_layout()
plt.show()

2.3 Critical Current Density

Magnetization switching by STT requires sufficient current to overcome the damping torque. This critical current density $J_c$ is:

$$ J_c = \frac{2e}{\hbar} \frac{\alpha M_s t_F}{\eta P} (H_k + 2\pi M_s) $$

where $H_k$ is the anisotropy field and $\eta$ is the spin transfer efficiency.

How to Reduce Critical Current Density

Code Example 2.3: Critical Current Density Calculation

"""
STT switching critical current density calculation
"""
import numpy as np
import matplotlib.pyplot as plt

def critical_current_density(alpha, M_s, t_F, H_k, P, eta=1.0):
    """
    STT critical current density

    Parameters:
    alpha: Gilbert damping
    M_s: Saturation magnetization (A/m)
    t_F: Free layer thickness (m)
    H_k: Anisotropy field (A/m)
    P: Spin polarization
    eta: Spin transfer efficiency
    """
    hbar = 1.055e-34
    e = 1.6e-19
    mu_0 = 4 * np.pi * 1e-7

    J_c = (2 * e / hbar) * (alpha * M_s * t_F) / (eta * P)
    J_c *= (H_k + 2 * np.pi * M_s) * mu_0
    return J_c

# Typical parameters (CoFeB)
alpha = 0.01
M_s = 1.2e6  # A/m
P = 0.56

# Film thickness dependence
t_F = np.linspace(0.5e-9, 3e-9, 50)
H_k_values = [0.1e6, 0.3e6, 0.5e6]  # A/m

plt.figure(figsize=(10, 6))

for H_k in H_k_values:
    J_c = critical_current_density(alpha, M_s, t_F, H_k, P)
    plt.plot(t_F * 1e9, J_c / 1e10, linewidth=2,
             label=f'$H_k$ = {H_k/1e6:.1f} MA/m')

plt.xlabel('Free Layer Thickness $t_F$ (nm)', fontsize=12)
plt.ylabel('Critical Current Density $J_c$ (×$10^{10}$ A/m²)', fontsize=12)
plt.title('STT Switching Critical Current Density', fontsize=14)
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

# Typical value
t_F_typ = 1.5e-9
H_k_typ = 0.3e6
J_c_typ = critical_current_density(alpha, M_s, t_F_typ, H_k_typ, P)
print(f"Typical STT-MRAM: J_c ≈ {J_c_typ/1e10:.1f} × 10¹⁰ A/m²")

2.4 Magnetization Switching Dynamics

Switching Time

The STT magnetization switching time $\tau_{sw}$ depends on current density $J$:

$$ \tau_{sw} \approx \frac{1 + \alpha^2}{\alpha \gamma \mu_0 M_s} \ln\left(\frac{\pi}{2\theta_0}\right) \frac{J_c}{J - J_c} $$

where $\theta_0$ is the initial angle.

Code Example 2.4: Switching Time Simulation

"""
Complete simulation of STT magnetization switching
"""
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

def llg_stt_pma(m, t, gamma, alpha, H_k, a_J, m_p):
    """
    STT-LLG equation with perpendicular magnetic anisotropy
    """
    m = m / np.linalg.norm(m)

    # Effective field (PMA)
    H_eff = np.array([0, 0, H_k * m[2]])

    # LLG + STT
    precession = -gamma * np.cross(m, H_eff)
    damping = alpha * np.cross(m, precession)
    stt = a_J * np.cross(m, np.cross(m, m_p))

    return precession + damping + stt

def find_switching_time(t, mz, threshold=-0.5):
    """Detect switching completion time"""
    idx = np.where(mz < threshold)[0]
    if len(idx) > 0:
        return t[idx[0]]
    return np.nan

# Parameters
gamma = 1.76e11
alpha = 0.01
H_k = 0.5  # Anisotropy equivalent to T
m_p = np.array([0, 0, -1])  # Switch to antiparallel direction

# Initial state (slightly tilted from +z)
m0 = np.array([0.01, 0, 0.99995])
m0 = m0 / np.linalg.norm(m0)

# Switching at different current strengths
t_max = 10e-9
t = np.linspace(0, t_max, 10000)

a_J_values = np.array([0.8, 1.0, 1.5, 2.0, 3.0]) * 1e11

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# Left: mz time evolution
colors = plt.cm.viridis(np.linspace(0, 0.9, len(a_J_values)))
switching_times = []

for a_J, color in zip(a_J_values, colors):
    sol = odeint(llg_stt_pma, m0, t, args=(gamma, alpha, H_k, a_J, m_p))
    mz = sol[:, 2]
    axes[0].plot(t*1e9, mz, color=color, linewidth=1.5,
                 label=f'$a_J$ = {a_J/1e11:.1f}×$10^{{11}}$')
    switching_times.append(find_switching_time(t, mz))

axes[0].axhline(y=0, color='k', linestyle='--', alpha=0.3)
axes[0].set_xlabel('Time (ns)', fontsize=12)
axes[0].set_ylabel('$m_z$', fontsize=12)
axes[0].set_title('STT Magnetization Switching', fontsize=14)
axes[0].legend(loc='right')
axes[0].grid(True, alpha=0.3)

# Right: Switching time vs current
axes[1].plot(a_J_values/1e11, np.array(switching_times)*1e9, 'bo-', linewidth=2, markersize=8)
axes[1].set_xlabel('STT Strength $a_J$ (×$10^{11}$ rad/s)', fontsize=12)
axes[1].set_ylabel('Switching Time (ns)', fontsize=12)
axes[1].set_title('Current Dependence', fontsize=14)
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

2.5 STT-MRAM

STT-MRAM (Spin Transfer Torque Magnetoresistive RAM) is non-volatile memory using STT for writing.

flowchart TD subgraph STT-MRAM Structure Cap[Cap Layer] FL[Free Layer
CoFeB 1-2nm] TB[Tunnel Barrier
MgO 1nm] PL[Reference Layer
CoFeB] SAF[SAF Structure] BE[Bottom Electrode] end Cap --> FL --> TB --> PL --> SAF --> BE style FL fill:#2ecc71,stroke:#27ae60,color:#fff style TB fill:#3498db,stroke:#2980b9,color:#fff style PL fill:#e74c3c,stroke:#c0392b,color:#fff

STT-MRAM Operation

Operation Current Direction Final State Resistance
Write "0" PL → FL Parallel Low ($R_P$)
Write "1" FL → PL Antiparallel High ($R_{AP}$)
Read Small current (No change) Detected by TMR

Code Example 2.5: STT-MRAM Parameter Design

"""
STT-MRAM design parameter calculations
"""
import numpy as np
import matplotlib.pyplot as plt

class STTMRAM:
    def __init__(self, diameter_nm, t_FL_nm, M_s, H_k, alpha, P, TMR):
        """
        STT-MRAM cell design

        Parameters:
        diameter_nm: MTJ diameter (nm)
        t_FL_nm: Free layer thickness (nm)
        M_s: Saturation magnetization (A/m)
        H_k: Anisotropy field (A/m)
        alpha: Gilbert damping
        P: Spin polarization
        TMR: TMR ratio
        """
        self.diameter = diameter_nm * 1e-9
        self.t_FL = t_FL_nm * 1e-9
        self.M_s = M_s
        self.H_k = H_k
        self.alpha = alpha
        self.P = P
        self.TMR = TMR

        self.area = np.pi * (self.diameter/2)**2
        self.volume = self.area * self.t_FL

    def thermal_stability(self, T=300):
        """Thermal stability factor Δ = E_b / k_B T"""
        k_B = 1.38e-23
        mu_0 = 4 * np.pi * 1e-7
        E_b = 0.5 * mu_0 * self.M_s * self.H_k * self.volume
        return E_b / (k_B * T)

    def critical_current(self):
        """Critical current"""
        hbar = 1.055e-34
        e = 1.6e-19
        mu_0 = 4 * np.pi * 1e-7
        eta = 1.0

        J_c = (2 * e / hbar) * (self.alpha * self.M_s * self.t_FL) / (eta * self.P)
        J_c *= (self.H_k + 2 * np.pi * self.M_s) * mu_0
        return J_c * self.area

    def switching_voltage(self, R_P=1000):
        """Switching voltage (referenced to R_P)"""
        return self.critical_current() * R_P

    def retention_time(self, T=300):
        """Data retention time (10 years target)"""
        delta = self.thermal_stability(T)
        f0 = 1e9  # Attempt frequency
        return np.exp(delta) / f0

# Design parameter scan
diameters = np.linspace(20, 100, 50)

# Typical parameters
M_s = 1.2e6
H_k = 0.4e6
alpha = 0.01
P = 0.56
TMR = 1.5

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

deltas = []
I_cs = []

for d in diameters:
    cell = STTMRAM(d, 1.5, M_s, H_k, alpha, P, TMR)
    deltas.append(cell.thermal_stability())
    I_cs.append(cell.critical_current() * 1e6)

# Thermal stability
axes[0].plot(diameters, deltas, 'b-', linewidth=2)
axes[0].axhline(y=60, color='r', linestyle='--', label='Target Δ=60')
axes[0].set_xlabel('MTJ Diameter (nm)', fontsize=11)
axes[0].set_ylabel('Thermal Stability Factor Δ', fontsize=11)
axes[0].set_title('Thermal Stability vs Size', fontsize=12)
axes[0].legend()
axes[0].grid(True, alpha=0.3)

# Critical current
axes[1].plot(diameters, I_cs, 'g-', linewidth=2)
axes[1].set_xlabel('MTJ Diameter (nm)', fontsize=11)
axes[1].set_ylabel('Critical Current $I_c$ (μA)', fontsize=11)
axes[1].set_title('Critical Current vs Size', fontsize=12)
axes[1].grid(True, alpha=0.3)

# Trade-off
axes[2].plot(deltas, I_cs, 'mo-', linewidth=2, markersize=4)
axes[2].axvline(x=60, color='r', linestyle='--', alpha=0.5)
axes[2].set_xlabel('Thermal Stability Factor Δ', fontsize=11)
axes[2].set_ylabel('Critical Current $I_c$ (μA)', fontsize=11)
axes[2].set_title('Δ - $I_c$ Trade-off', fontsize=12)
axes[2].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# Design example
cell = STTMRAM(50, 1.5, M_s, H_k, alpha, P, TMR)
print(f"50nm MTJ diameter design:")
print(f"  Thermal stability Δ = {cell.thermal_stability():.1f}")
print(f"  Critical current Ic = {cell.critical_current()*1e6:.1f} μA")

2.6 Precessional Switching and Pulse Optimization

For fast switching, precessional switching utilizing magnetization precession is effective.

Code Example 2.6: Optimal Pulse Width Search

"""
High-speed switching by STT pulse driving
"""
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

def llg_stt_pulse(m, t, gamma, alpha, H_k, a_J, m_p, t_pulse):
    """STT with pulse current"""
    m = m / np.linalg.norm(m)

    H_eff = np.array([0, 0, H_k * m[2]])

    precession = -gamma * np.cross(m, H_eff)
    damping = alpha * np.cross(m, precession)

    # Pulse control
    if t < t_pulse:
        stt = a_J * np.cross(m, np.cross(m, m_p))
    else:
        stt = np.zeros(3)

    return precession + damping + stt

# Parameters
gamma = 1.76e11
alpha = 0.01
H_k = 0.5
m_p = np.array([0, 0, -1])
a_J = 2e11

m0 = np.array([0.01, 0, 0.99995])
m0 = m0 / np.linalg.norm(m0)

t_max = 15e-9
t = np.linspace(0, t_max, 15000)

# Different pulse widths
pulse_widths = [1e-9, 2e-9, 3e-9, 5e-9, 8e-9]

fig, axes = plt.subplots(2, 3, figsize=(15, 8))
axes = axes.flatten()

for i, t_pulse in enumerate(pulse_widths):
    sol = odeint(llg_stt_pulse, m0, t, args=(gamma, alpha, H_k, a_J, m_p, t_pulse))

    ax = axes[i]
    ax.plot(t*1e9, sol[:, 2], 'b-', linewidth=1.5)
    ax.axvline(x=t_pulse*1e9, color='r', linestyle='--', alpha=0.5, label='Pulse end')
    ax.axhline(y=0, color='k', linestyle=':', alpha=0.3)
    ax.set_xlabel('Time (ns)', fontsize=10)
    ax.set_ylabel('$m_z$', fontsize=10)
    ax.set_title(f'Pulse Width = {t_pulse*1e9:.0f} ns', fontsize=11)
    ax.legend()
    ax.grid(True, alpha=0.3)
    ax.set_ylim(-1.2, 1.2)

# Summary
axes[5].axis('off')
axes[5].text(0.1, 0.7, 'Pulse Optimization Points:', fontsize=12, fontweight='bold')
axes[5].text(0.1, 0.5, '• Too short: Incomplete switching', fontsize=10)
axes[5].text(0.1, 0.35, '• Optimal: Reliable complete switching', fontsize=10)
axes[5].text(0.1, 0.2, '• Too long: Energy waste, temperature rise', fontsize=10)

plt.suptitle('STT Pulse-Driven Switching', fontsize=14)
plt.tight_layout()
plt.show()

2.7 Challenges and Solutions for STT-MRAM

Code Example 2.7: Error Rate Analysis

"""
STT-MRAM write error analysis
"""
import numpy as np
import matplotlib.pyplot as plt

def write_error_rate(delta, I_ratio, T=300):
    """
    Write error probability (thermal activation model)

    Parameters:
    delta: Thermal stability factor
    I_ratio: I/Ic ratio
    """
    if I_ratio <= 1:
        return 1.0  # Certain failure below critical current

    # Error due to thermal activation
    effective_delta = delta * (1 - 1/I_ratio)
    P_error = np.exp(-effective_delta)
    return P_error

# Parameter scan
delta_values = [40, 50, 60, 70, 80]
I_ratios = np.linspace(1.01, 3, 100)

plt.figure(figsize=(10, 6))

for delta in delta_values:
    P_errors = [write_error_rate(delta, I) for I in I_ratios]
    plt.semilogy(I_ratios, P_errors, linewidth=2, label=f'Δ = {delta}')

plt.axhline(y=1e-6, color='r', linestyle='--', label='Target BER < 10⁻⁶')
plt.xlabel('$I/I_c$ Ratio', fontsize=12)
plt.ylabel('Write Error Probability', fontsize=12)
plt.title('STT-MRAM Write Error Analysis', fontsize=14)
plt.legend()
plt.grid(True, alpha=0.3)
plt.ylim(1e-20, 1)
plt.show()

print("High thermal stability (Δ) and sufficient overdrive (I/Ic) required")
print("Δ=60, I/Ic=1.5 can achieve BER ≈ 10⁻¹⁰")

Main Challenges of STT-MRAM

To address these challenges, SOT-MRAM covered in the next chapter was developed.


Chapter Summary

What We Learned

Preparation for Next Chapter

In the next chapter, we learn about Spin-Orbit Torque (SOT), which overcomes STT-MRAM challenges. SOT separates read and write paths, enabling high speed and high endurance.


References

  1. Slonczewski, J. C. (1996). "Current-driven excitation of magnetic multilayers." J. Magn. Magn. Mater., 159, L1-L7.
  2. Berger, L. (1996). "Emission of spin waves by a magnetic multilayer traversed by a current." Phys. Rev. B, 54, 9353.
  3. Ralph, D. C., & Stiles, M. D. (2008). "Spin transfer torques." J. Magn. Magn. Mater., 320, 1190-1216.
  4. Apalkov, D., et al. (2016). "Magnetoresistive RAM: A new paradigm for memory." Proc. IEEE, 104(10), 1796-1830.