# 6. Specific Registers for ADC In ATmega328p

### 6.1 ADMUX — ADC Multiplexer Selection Register

**ADMUX** is an 8-bit register that handles the basic ADC configuration: reference voltage source, data storage format, and which analog input channel to read.

![image](https://hackmd.io/_uploads/B1Dn5h_3bx.png)

**Functions of each field:**

**a) REFS1:REFS0 — Reference Selection**

Selects the ADC reference voltage source:

| REFS1 | REFS0 | Reference Voltage |
| :--- | :--- | :--- |
| 0 | 0 | AREF Pin (external) |
| 0 | 1 | AVcc (supply voltage, typically 5V) |
| 1 | 0 | Unused |
| 1 | 1 | Internal 2.56V |

**b) ADLAR — ADC Left Adjust Result**

Determines the storage position of the 10-bit result within the two 8-bit registers (ADCH + ADCL):

| ADLAR | ADCH (8-bit) | ADCL (8-bit) |
| :--- | :--- | :--- |
| **1** (Left-justified) | D9 D8 D7 D6 D5 D4 D3 D2 | D1 D0 (unused 6-bit) |
| **0** (Right-justified) | (unused 6-bit) D9 D8 | D7 D6 D5 D4 D3 D2 D1 D0 |

- **Right-justified (ADLAR=0)**: ADCL stores the bottom 8 bits, and ADCH stores the top 2 bits. Typically used for reading the full 10-bit value.
- **Left-justified (ADLAR=1)**: ADCH stores the top 8 bits of the result. Useful when only 8-bit precision is needed (just read ADCH).

**c) MUX3:MUX0 — Analog Channel Selection**

Selects which analog input pin will be converted:

| MUX3 | MUX2 | MUX1 | MUX0 | Analog Pin |
| :--- | :--- | :--- | :--- | :--- |
| 0 | 0 | 0 | 0 | ADC0 / A0 |
| 0 | 0 | 0 | 1 | ADC1 / A1 |
| 0 | 0 | 1 | 0 | ADC2 / A2 |
| 0 | 0 | 1 | 1 | ADC3 / A3 |
| 0 | 1 | 0 | 0 | ADC4 / A4 |
| 0 | 1 | 0 | 1 | ADC5 / A5 |
| 0 | 1 | 1 | 0 | ADC6 / A6 |
| 0 | 1 | 1 | 1 | ADC7 / A7 |

---

### 6.2 ADCSRA — ADC Control and Status Register A

**ADCSRA** is an 8-bit register that serves as the command center for controlling and monitoring the ADC process status.

![image](https://hackmd.io/_uploads/HJGpo2_h-l.png)

**Functions of each bit:**

| Bit | Name | Function |
| :--- | :--- | :--- |
| **ADEN** ![image](https://hackmd.io/_uploads/rJGHi2O3-l.png) | ADC Enable | Set to **1** to enable the ADC. If 0, the ADC will not run and analog pins won't be converted. |
| **ADSC** | ADC Start Conversion | Set to **1** to start a single conversion cycle. This bit stays at 1 while conversion is in progress, then automatically returns to 0. |
| **ADATE** | ADC Auto Trigger Enable | If **1**, conversion starts automatically triggered by a specific event (e.g., timer overflow, external pin change). |
| **ADIF** | ADC Interrupt Flag | Set to **1** by hardware when conversion is complete (_End of Conversion_). Reset by manually writing a 1 to this bit. |
| **ADIE** | ADC Interrupt Enable | If **1**, the program will jump to an ISR (Interrupt Service Routine) when conversion is complete. Useful so the CPU doesn't have to wait (polling). |
| **ADPS2:ADPS0** | ADC Prescaler Select | 3 bits that determine the clock divider for the ADC (see the prescaler table above). |

---

### 6.3 ADCL and ADCH — ADC Data Registers

**ADCL** and **ADCH** are two 8-bit registers where the 10-bit ADC conversion result is stored after conversion is complete.

Since the ATmega328p uses a 10-bit ADC, the result (0–1023) cannot fit into a single 8-bit register, so it's split across two registers:

![image](https://hackmd.io/_uploads/SyH13hO3bg.png)

> **IMPORTANT:** ADCL **must be read first** before ADCH. Reading ADCL locks ADCH to prevent it from changing until ADCH is read, ensuring data consistency.

**How to read the full 10-bit ADC value (right-justified):**

```c
// In C:
uint16_t adc_value = ADC;  // or:
uint8_t  low  = ADCL;
uint8_t  high = ADCH;
uint16_t adc_value = (high << 8) | low;
```

```asm
; In Assembly:
LDS R18, ADCL    ; read low-byte first
LDS R19, ADCH    ; then read high-byte
```