This article describes the working principle of a 2-channel 12-Bit Digital-to-Analog converter module that works with MCP4922 IC with the MicroPython of the ml4m board via the SPI bus to output the analog signal in the triangular waveform. Squares as shown in Figures 6 and 7 of the example in this article.
Equipment
The equipment in this article includes:
- ET-mini MCP4922 or MCP4922 as show in Figure 2.
- esp32
MCP4922
Feature
- It has the resolution to convert digital values to analog signals in size 12 bits.
- There are two analog signal output channels via OUT_A and OUT_B.
- The maximum speed of communication via SPI bus is 20MHz.
- It takes approximately 45nsec to convert the voltage level or analog signal.
- Work with DC voltage at a voltage level of 2V7 to 5V5.
- Configurable signal amplification between x1 and x2.
Connection diagram
The connection between MCP4922 and esp32 is as shown in Figure 2.
- MCP4922’s SCK connected to esp32’s IO18
- MCP4922’s SDI connected to esp32’s IO23
- MCP4922’s CS connected to esp32’s IO27
Pin arrangment
The IC MCP4922 that we use is a 14-pin IC with the pin arrangement as shown in Figure 3.
From Figure 3
- The SDI pin is used to receive data from the microcontroller.
- CS pin for receiving CS signal.
- VOUTA pin for output voltage from channel A.
- VOUTB pin for output voltage from channel B.
- LDAC pin for sending pulse to output data from buffer to VOUTA or VOUTB.
- SHDN pin to enable or disable the IC.
- VREFA and VREFB pins for channel A and B reference voltage.
Flowchart
The working flow diagram is shown in Figure 4, the pin for controlling the operation is the pin SHDN which when set to 0 will cause the module MCP4922 to stop working and if it is 1, it will be activated. You can also enable or disable this function from the following commands. Additionally, the MCP4922 supports 1x (x1) and 2x (x2) voltage boosts determined by the Gain Logic, which is also configured from the instruction bit.
The output voltage level of VOUTA and VOUTB can be set by setting the voltage level from the VREFA and VREFB pins.
Timing chart
The timing diagram of the MCP4922 IC is shown in Figure 5. The operation uses the instruction appended to the first 4 bits of data sent to the MOSI pin, which will be discussed in the next section.
From Figure 5, it has a relationship of working commands: before starting pins CS and LDAC it has a status of 1 and when the module works, it has to change the state of CS to 0. After that, it sends data via SI or MOSI pin of the microcontroller. Runs from the top byte to the last bit of the lowest byte then raises the CS pin back to 1. Now programmers can direct data from the buffer to OUT_A or OUT_B by sending a pulse. 1->0->1 from the LDAC pin or set the LDAC pin to 0 all the time for automatic removal as well.
Commands
Executing the MCP4922 module requires instruction of the upper 4 bits, the upper byte or the 8th to 15th bits to be configured as follows.
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 |
Description | Channel | Buffer | Gain or voltage | IC on/off | 11st bit | 10th bit | 9th bit | 8th bit |
value | 0 is ch A 1 is ch B | 0 no buffer 1 buffer | 0 voltage x2 1 voltage x1 | 0 turn off 1 turn on | ||||
and for the lower byte or bits 0 to 7 is as follows
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Description | 7th bit | 6th bit | 5th bit | 4th bit | 3rd bit | 2nd bit | 1st bit | 0th bit |
Example Code
Example of a program to send a triangle wave or start from 0 to 4095 and decrease from 4094 to 0. Write the code as follows.
######################################################################
#
# MCP4922 12-bit ADC with SPI Interface
#
# (C) 2021, JarutEx
# https://www.jarutex.com
######################################################################
from machine import SPI, Pin, ADC
import time
pinCS = Pin(27, Pin.OUT)
pinCS.on()
spi = SPI(1,baudrate=20000000,sck=Pin(18,Pin.OUT),mosi=Pin(23,Pin.OUT),miso=Pin(19,Pin.IN))
try:
dacData = 0
dacDir = 0
while True:
x2 = 0b0111000000000000
x2 |= (dacData & 0b0000111111111111)
buffer = x2.to_bytes(2,'big')
pinCS.off()
spi.write(buffer)
pinCS.on()
if (dacDir):
dacData -= 1
if (dacData < 0):
dacData = 1
dacDir = 0
else:
dacData += 1
if (dacData > 4095):
dacData = 4094
dacDir = 1
time.sleep_us(10)
except KeyboardInterrupt:
pass
tmr0.deinit()
spi.deinit()
An example of the result is as shown in Figure 6.
The next example is to create a square wave as shown in Figure 7.
######################################################################
#
# MCP4922 12-bit ADC with SPI Interface
#
# (C) 2021, JarutEx
# https://www.jarutex.com
######################################################################
from machine import SPI, Pin, ADC
import time
spi = SPI(1,baudrate=20000000,sck=Pin(18,Pin.OUT),mosi=Pin(23,Pin.OUT),miso=Pin(19,Pin.IN))
pinCS = Pin(27, Pin.OUT)
pinCS.on()
try:
dacData = 0
dacDir = 0
while True:
dacData = 4000
x2 = ((dacData & 0b0000111111111111) | 0b0111000000000000)
buffer = x2.to_bytes(2,'big')
pinCS.off()
spi.write(buffer)
pinCS.on()
time.sleep_ms(500)
dacData = 100
x2 = ((dacData & 0b0000111111111111) | 0b0111000000000000)
buffer = x2.to_bytes(2,'big')
pinCS.off()
spi.write(buffer)
pinCS.on()
time.sleep_ms(500)
except KeyboardInterrupt:
pass
tmr0.deinit()
spi.deinit()
Conclusion
Through this article, our team hopes that readers will be able to apply DAC modules to microcontroller boards in the future. You will find it easy to operate as the MCP4922 provides a simple operation method by configuring the first 4 bits of data sent in the SPI bus to select the channel. Buffering, gaining, and activating or deactivating the channel and have fun with programming.
If you want to talk with us, feel free to leave comments below!!
References
(C) 2020-2021, By Jarut Busarathid and Danai Jedsadathitikul
Updated 2021-12-03