---
# System prepended metadata

title: Embedded Systems Lab 06

---

<h2 style='border: none'><center>Embedded Systems Lab 06</center></h2>

### <center>ADC & DAC</center>
###### Author: Mohammed Nafiz ALMadhoun
---

<p style='text-align: justify;'>
In this lab, we are going to talk about ADCs (Analog-to-Digital Converters), we will use the integrated ADC peripheral in the LPC111x to read some data from sensors, then we will talk a bit about DACs (Digital-to-Analog Converters), which unfortunately is not integrated into the LPC111x, but we could achieve a close result using a capacitor and PWM signal.
</p>

### **Analog-to-Digital Converter**
<p style='text-align: justify;'>
As the name states the purpose of this module or peripheral is to convert an analog signal to a digital quantity that we can easily read and manipulate.

As with any previous peripheral this peripheral needs setup, by following chapter 25 in the Datasheet, we should select a pin functionality as Analog Input, then we should enable the clock for the peripheral, finally, we should power up the peripheral using `PDRUNCFG` register.
</p>

#### **Setting Up the ADC**
<p style='text-align: justify;'>
In this section, we will learn about the peripheral itself, the configuration it has and the register that controllers the peripheral.

Starting from `AD0CR` which is ADC Zero Control Register, the register contains these values:
</p>

- `SEL` : Which selects the working channels (8 channels with one bit for each one).
- `CLKDIV` : Which is an 8-bit unsigned divisor for the clock
- `BURST` : Controls if the burst mode is enabled (Hardware scan mode).
- `CLKS` : Number of cycles for each conversion (Only in burst mode).
- `START` : Controls when the conversion should start.
- `EDGE` : If it starts in a single in which edge it should start. 

`AD0GDR` is ADC Zero General Data Register, which holds the data and contains:
- `V_VREF` : The value of the most reset conversion.
- `CHN` : Unsigned 3-bits indicates which channel.
- `OVERRUN` : Works in Brust mode if one or more values was overwritten.
- `DONE` : DONE!

You can learn about the reset of the registers from the Datasheet.

#### **Example**

In this example, we will setup the system clock to 12MHz, then we will use `displaylib.c`, which we've created in the previous labs.

```c=
#include <LPC11xx.h>
#include "displaylib.h"

void setup_adc () {
    LPC_IOCON->JTAG_TDI_PIO0_11 = 0x2;        // Setup PIO0_11 As AD0
    LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 13;     // Enable ADC CLock
    LPC_SYSCON->PDRUNCFG &= ~(1<<4);          // Power ADC UP
    // CR = 0x1 = Enable 1st channel, 0xFF is divisor.
    LPC_ADC->CR = 0x1 | (0xFF << 8);
}

int read_ad0 () {
    LPC_ADC->CR = 1 << 24;                    // Start ADC (Software start)
    while ((LPC_ADC->DR[0] & (1<<31)) == 0);  // Wait until Done = 1
    return (LPC_ADC->DR[0] >> 6) & 0x3FF;     // Mask the value and return.
}
```
Using these functions, it will be easy for us to setup the ADC, and Read a value from it.

```c=
int main (void)
{ 
    LPC_GPIO0->DIR |= 0b110;     // Enable output for RS, E
    LPC_GPIO2->DIR |= 0xFF;      // Enable output for display Data
    setup_display();             // Setup the display
    setup_adc();                 // Setup ADC
    char buff[20];               // Create a string buffer.
    while (1) {
        cursor_home();           // Set cursor home (at the start)
        int adc_0 = read_ad0();  // Read ADC Channel 0
        sprintf(buff, "POT: %d   ", adc_0 );  // Write the value to the buffer
        send_string(buff);                    // Display the string.
    }
    return 0;
}   
```

This code will read the value from adc channel 0, and write it to the display.
<center>

![Figure 1: Hardware Setup](https://i.imgur.com/LorImDK.png)
Figure 1: Simple hardware setup.
</center>

***Note:*** *`sprintf` will not work out of the box, you should declare `_sbrk`*


### **Digital-to-Analog Converter**

<p style='text-align: justify;'>
In this section, we will not write any software, but we will look at the concepts to integrate a simple DAC with our microcontroller, please return to the previous lab to output any PWM signal,
</p>

#### **Using a simple RC filter**
<p style='text-align: justify;'>
If you can output a PWM signal, then you can use this signal with the help of the capacitors to output a poor analog signal, which could be used later to drive some components (But you can use PWM directly most of the time).
</p>

<center>

![Figure 2: RC Filter](https://i.imgur.com/lK9ESMg.png =450x)
Figure 2: RC Filter[^1].
</center>

[^1]: [Accurate, Fast Settling Analog Voltages from Digital PWM Signals](https://www.analog.com/en/technical-articles/accurate-fast-settling-analog-voltages-from-digital-pwm-signals.html)

As you may notice, the value of the resistor and the capacitor will depend on the PWM clock.


#### **Using moduels and communication protocols**

<p style='text-align: justify;'>
If you need a more accurate result (You may want to output some audio or something?), you could use integrated modules, which comes in different specifications (e.g. the speed, the accuracy), then use mostly I2C to communicate with the module.
</p>

<center>

![Figure 3: MCP4725 Module](https://i.imgur.com/EnfPBAN.png =300x)
Figure 2: MCP4725[^2].
</center>

[^2]: [12-Bit Single Output DAC w/EEPROM and I2C](https://www.microchip.com/wwwproducts/en/MCP4725)


<center>

### END OF LAB 6</center>

<div style="display:none">

# Embedded Systems Lab 06

</div>
