Overview
The Microchip Technology Inc. MCP492X are 2.7 – 5.5V, low-power, low DNL, 12-Bit Digital-to-Analog Converters (DACs) with optional 2x buffered output and SPI interface.
The MCP492X are DACs that provide high accuracy and low noise performance for industrial applications where calibration or compensation of signals (such as temperature, pressure and humidity) are required. The MCP492X are available in the extended temperature range and PDIP, SOIC, MSOP and TSSOP packages.
| MCP4921 and MCP4922 DIP Chip |
This chip has a DIP version that is very user-friendly for DIY electronics prototyping. The MCP4921 has only one output DAC while the MCP4922 has two output DAC. DAC selection is set in software.
These two versions of chip function almost the same except the number of output DAC.
| PIN FUNCTION TABLE
|
This 12-bit DAC yield different 4096 step. Using a typical +5.0VDC supply voltage we can double its output voltage level to 2X via its gain control bit.
| Output Voltage Calculation |
The SPI interface of this chip is one direction (write only). One SPI data frame is 16-bit (two byte) that contain DAC setting and 12-bit DAC value.
| WRITE COMMAND REGISTER |
The Chip Select (CS) is active low. So the master MCU keeps this pin low for two bytes of data transmission.
| Write Command |
Using a dedicates SPI interface of an MCU offers a high speed data transmission.
ATMega644P SPI and MCP4921 Single DAC
The MCP4921 is a simple 8-bit DAC chip with single output. Here the ATMega644P send any DAC voltage to this chip with the lowest and the highest voltage level.
| Schematic |
I use its 2X gain feature that give a maximum output voltage up to 10VDC from a 5.0VDC supply voltage.
- /*
- * 12-spi_mcp4921.c
- *
- * Created: 2/23/2026 2:55:53 PM
- * Author : Admin
- */
- #include <avr/io.h>
- #include <util/delay.h>
- #define F_CPU 16000000UL
- #define DDR_SPI DDRB
- #define PRT_SPI PORTB
- #define DD_SS 4
- #define DD_MOSI 5
- #define DD_MISO 6
- #define DD_SCK 7
- #define BUF 14
- #define G1X 13
- #define ACTIVE 12
- void SPI_MasterInit(void)
- {
- /* Set MOSI and SCK output, all others input */
- DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
- /* Enable SPI, Master, set clock rate fck/16 */
- SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
- }
- void SPI_MasterTransmit(char cData)
- {
- /* Start transmission */
- SPDR = cData;
- /* Wait for transmission complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- }
- void SPI_SlaveInit(void)
- {
- /* Set MISO output, all others input */
- DDR_SPI = (1<<DD_MISO);
- /* Enable SPI */
- SPCR = (1<<SPE);
- }
- char SPI_SlaveReceive(void)
- {
- /* Wait for reception complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- /* Return Data Register */
- return SPDR;
- }
- void mcp4921_send(unsigned int value){
- unsigned int mcp4922_data,dac_12;
- mcp4922_data=(1<<BUF)|(1<<ACTIVE);
- dac_12=value;
- mcp4922_data|=dac_12&0x0FFF;
- PRT_SPI&=~(1<<DD_SS);
- SPI_MasterTransmit(mcp4922_data>>8);
- SPI_MasterTransmit(mcp4922_data&0x00FF);
- PRT_SPI|=(1<<DD_SS);
- }
- int main(void)
- {
- /* Replace with your application code */
- SPI_MasterInit();
- while (1)
- {
- mcp4921_send(0x0000);
- _delay_ms(1000);
- mcp4921_send(0x0FFF);
- _delay_ms(1000);
- }
- }
The 12-bit DAC data is masked with the MCP4921 control bits.
Now let create a sine wave output using a DAC data table. This output sine wave doesn't have zero cross.
| Sine Wave Generating |
| Output DAC Signal |
Its frequency is around 120Hz.
- /*
- * sine_wave.c
- *
- * Created: 2/23/2026 7:41:55 PM
- * Author : Admin
- */
- #include <avr/io.h>
- #include <util/delay.h>
- #define F_CPU 16000000UL
- #define DDR_SPI DDRB
- #define PRT_SPI PORTB
- #define DD_SS 4
- #define DD_MOSI 5
- #define DD_MISO 6
- #define DD_SCK 7
- #define BUF 14
- #define G1X 13
- #define ACTIVE 12
- static unsigned int sine_table[50] =
- {
- 512, 576, 639, 700, 759, 813, 862, 907, 944, 975,
- 999, 1015, 1023, 1023, 1015, 999, 975, 944, 907, 862,
- 813, 759, 700, 639, 576, 512, 448, 385, 324, 265,
- 211, 162, 117, 80, 49, 25, 9, 1, 1, 9,
- 25, 49, 80, 117, 162, 211, 265, 324, 385, 448
- };
- void SPI_MasterInit(void)
- {
- /* Set MOSI and SCK output, all others input */
- DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
- /* Enable SPI, Master, set clock rate fck/16 */
- SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
- }
- void SPI_MasterTransmit(char cData)
- {
- /* Start transmission */
- SPDR = cData;
- /* Wait for transmission complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- }
- void SPI_SlaveInit(void)
- {
- /* Set MISO output, all others input */
- DDR_SPI = (1<<DD_MISO);
- /* Enable SPI */
- SPCR = (1<<SPE);
- }
- char SPI_SlaveReceive(void)
- {
- /* Wait for reception complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- /* Return Data Register */
- return SPDR;
- }
- void mcp4921_send(unsigned int value){
- unsigned int mcp4922_data,dac_12;
- mcp4922_data=(1<<BUF)|(1<<ACTIVE);
- dac_12=value;
- mcp4922_data|=dac_12&0x0FFF;
- PRT_SPI&=~(1<<DD_SS);
- SPI_MasterTransmit(mcp4922_data>>8);
- SPI_MasterTransmit(mcp4922_data&0x00FF);
- PRT_SPI|=(1<<DD_SS);
- }
- int main(void)
- {
- /* Replace with your application code */
- SPI_MasterInit();
- char i=0;
- while (1)
- {
- mcp4921_send(4*sine_table[i]);
- //_delay_ms(10);
- i++;
- if(i>49) i=0;
- }
- }
ATMega644P SPI and MCP4921 Single DAC
The MCP4922 has two output DAC but doubled in footprint. However these two chips are identical in functions. This example show how to write DAC values to this chip.
| Schematic |
The master MCU just send the DAC values once and it keep in the buffer of the MCP4922 (buffer enabled).
- /*
- * 12-spi_mcp4922.c
- *
- * Created: 2/22/2026 8:01:15 PM
- * Author : Admin
- */
- #include <avr/io.h>
- #include <util/delay.h>
- #define F_CPU 16000000UL
- #define DDR_SPI DDRB
- #define PRT_SPI PORTB
- #define DD_SS 4
- #define DD_MOSI 5
- #define DD_MISO 6
- #define DD_SCK 7
- #define DAC_B 15
- #define BUF 14
- #define G1X 13
- #define ACTIVE 12
- void SPI_MasterInit(void)
- {
- /* Set MOSI and SCK output, all others input */
- DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
- /* Enable SPI, Master, set clock rate fck/16 */
- SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
- }
- void SPI_MasterTransmit(char cData)
- {
- /* Start transmission */
- SPDR = cData;
- /* Wait for transmission complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- }
- void SPI_SlaveInit(void)
- {
- /* Set MISO output, all others input */
- DDR_SPI = (1<<DD_MISO);
- /* Enable SPI */
- SPCR = (1<<SPE);
- }
- char SPI_SlaveReceive(void)
- {
- /* Wait for reception complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- /* Return Data Register */
- return SPDR;
- }
- int main(void)
- {
- /* Replace with your application code */
- SPI_MasterInit();
- unsigned int mcp4922_data,dac_12;
- mcp4922_data=(1<<DAC_B)|(1<<BUF)|(1<<ACTIVE);
- dac_12=3000;
- mcp4922_data|=dac_12&0x0FFF;
- PRT_SPI&=~(1<<DD_SS);
- SPI_MasterTransmit(mcp4922_data>>8);
- SPI_MasterTransmit(mcp4922_data&0x00FF);
- PRT_SPI|=(1<<DD_SS);
- mcp4922_data=(1<<BUF)|(1<<ACTIVE);
- dac_12=2048;
- mcp4922_data|=dac_12&0x0FFF;
- PRT_SPI&=~(1<<DD_SS);
- SPI_MasterTransmit(mcp4922_data>>8);
- SPI_MasterTransmit(mcp4922_data&0x00FF);
- PRT_SPI|=(1<<DD_SS);
- while (1)
- {
- }
- }
Now I added one ADC input to adjust the output DAC values.
| Schematic |
- /*
- * adc_dac.c
- *
- * Created: 2/23/2026 9:54:28 PM
- * Author : Admin
- */
- #include <avr/io.h>
- #include <util/delay.h>
- #define F_CPU 16000000UL
- #define DDR_SPI DDRB
- #define PRT_SPI PORTB
- #define DD_SS 4
- #define DD_MOSI 5
- #define DD_MISO 6
- #define DD_SCK 7
- #define DAC_B 15
- #define BUF 14
- #define G1X 13
- #define ACTIVE 12
- void SPI_MasterInit(void)
- {
- /* Set MOSI and SCK output, all others input */
- DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
- /* Enable SPI, Master, set clock rate fck/16 */
- SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
- }
- void SPI_MasterTransmit(char cData)
- {
- /* Start transmission */
- SPDR = cData;
- /* Wait for transmission complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- }
- void SPI_SlaveInit(void)
- {
- /* Set MISO output, all others input */
- DDR_SPI = (1<<DD_MISO);
- /* Enable SPI */
- SPCR = (1<<SPE);
- }
- char SPI_SlaveReceive(void)
- {
- /* Wait for reception complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- /* Return Data Register */
- return SPDR;
- }
- void dac_write(char dac, char gain, unsigned int dac_value){
- unsigned int mcp4922_data,dac_12,temp;
- if(gain==2) temp=0;
- else temp=1;
- if((dac=='B')||(dac==2)||(dac=='b')||(dac=='2'))
- mcp4922_data=(1<<DAC_B)|(1<<BUF)|(temp<<G1X)|(1<<ACTIVE);
- else if(dac=='A'||(dac==1)|(dac=='a')||(dac=='1'))
- mcp4922_data=(1<<BUF)|(temp<<G1X)|(1<<ACTIVE);
- else
- mcp4922_data=(1<<BUF)|(temp<<G1X)|(1<<ACTIVE);
- mcp4922_data|=dac_value&0x0FFF;
- PRT_SPI&=~(1<<DD_SS);
- SPI_MasterTransmit(mcp4922_data>>8);
- SPI_MasterTransmit(mcp4922_data&0x00FF);
- PRT_SPI|=(1<<DD_SS);
- }
- int main(void)
- {
- /* Replace with your application code */
- SPI_MasterInit();
- DDRB=0xFF;
- //PA0 or ADC0 as an analog input
- DDRA=0;
- //Turn on the ADC module
- ADCSRA=(1<<ADEN);
- uint16_t temp;
- ADMUX=0;
- dac_write(1, 2, 0x0FF);
- dac_write(2, 1, 0x0FFF);
- _delay_ms(5000);
- while (1)
- {
- //Start the conversion
- ADCSRA|=(1<<ADSC);
- //Wait for the completion
- while((ADCSRA&(1<<ADSC))==1);
- //Read the result
- temp=ADCL+(ADCH<<8);
- dac_write('A',2,temp*4);
- dac_write('B',2,0x0FFF-(temp*4));
- _delay_ms(100);
- }
- }
No comments:
Post a Comment