728x90

Showing posts with label DAC. Show all posts
Showing posts with label DAC. Show all posts

Monday, February 23, 2026

ATMega644P SPI and MCP492X 12-bit ADC

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.

ATMega644P SPI and MCP492X 12-bit ADC
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.

ATMega644P SPI and MCP492X 12-bit ADC 

These two versions of chip function almost the same except the number of output DAC.

ATMega644P SPI and MCP492X 12-bit ADC
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.

ATMega644P SPI and MCP492X 12-bit ADC
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.

ATMega644P SPI and MCP492X 12-bit ADC
WRITE COMMAND REGISTER

The Chip Select (CS) is active low. So the master MCU keeps this pin low for two bytes of data transmission.

ATMega644P SPI and MCP492X 12-bit ADC
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.

ATMega644P SPI and MCP492X 12-bit ADC
Schematic

 I use its 2X gain feature that give a maximum output voltage up to 10VDC from a 5.0VDC supply voltage.

  1. /*
  2. * 12-spi_mcp4921.c
  3. *
  4. * Created: 2/23/2026 2:55:53 PM
  5. * Author : Admin
  6. */

  7. #include <avr/io.h>
  8. #include <util/delay.h>
  9. #define F_CPU 16000000UL

  10. #define DDR_SPI DDRB
  11. #define PRT_SPI PORTB

  12. #define DD_SS 4
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7

  16. #define BUF 14
  17. #define G1X 13
  18. #define ACTIVE 12

  19. void SPI_MasterInit(void)
  20. {
  21. /* Set MOSI and SCK output, all others input */
  22. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  23. /* Enable SPI, Master, set clock rate fck/16 */
  24. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  25. }

  26. void SPI_MasterTransmit(char cData)
  27. {
  28. /* Start transmission */
  29. SPDR = cData;
  30. /* Wait for transmission complete */
  31. while(!(SPSR & (1<<SPIF)))
  32. ;
  33. }

  34. void SPI_SlaveInit(void)
  35. {
  36. /* Set MISO output, all others input */
  37. DDR_SPI = (1<<DD_MISO);
  38. /* Enable SPI */
  39. SPCR = (1<<SPE);
  40. }
  41. char SPI_SlaveReceive(void)
  42. {
  43. /* Wait for reception complete */
  44. while(!(SPSR & (1<<SPIF)))
  45. ;
  46. /* Return Data Register */
  47. return SPDR;
  48. }

  49. void mcp4921_send(unsigned int value){
  50. unsigned int mcp4922_data,dac_12;
  51. mcp4922_data=(1<<BUF)|(1<<ACTIVE);
  52. dac_12=value;
  53. mcp4922_data|=dac_12&0x0FFF;
  54. PRT_SPI&=~(1<<DD_SS);
  55. SPI_MasterTransmit(mcp4922_data>>8);
  56. SPI_MasterTransmit(mcp4922_data&0x00FF);
  57. PRT_SPI|=(1<<DD_SS);
  58. }

  59. int main(void)
  60. {
  61. /* Replace with your application code */
  62. SPI_MasterInit();
  63. while (1)
  64. {
  65. mcp4921_send(0x0000);
  66. _delay_ms(1000);
  67. mcp4921_send(0x0FFF);
  68. _delay_ms(1000);
  69. }
  70. }




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.

ATMega644P SPI and MCP492X 12-bit ADC
Sine Wave Generating

 

ATMega644P SPI and MCP492X 12-bit ADC
Output DAC Signal

Its frequency is around 120Hz.

  1. /*
  2. * sine_wave.c
  3. *
  4. * Created: 2/23/2026 7:41:55 PM
  5. * Author : Admin
  6. */

  7. #include <avr/io.h>
  8. #include <util/delay.h>
  9. #define F_CPU 16000000UL

  10. #define DDR_SPI DDRB
  11. #define PRT_SPI PORTB

  12. #define DD_SS 4
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7

  16. #define BUF 14
  17. #define G1X 13
  18. #define ACTIVE 12

  19. static unsigned int sine_table[50] =
  20. {
  21. 512, 576, 639, 700, 759, 813, 862, 907, 944, 975,
  22. 999, 1015, 1023, 1023, 1015, 999, 975, 944, 907, 862,
  23. 813, 759, 700, 639, 576, 512, 448, 385, 324, 265,
  24. 211, 162, 117, 80, 49, 25, 9, 1, 1, 9,
  25. 25, 49, 80, 117, 162, 211, 265, 324, 385, 448
  26. };

  27. void SPI_MasterInit(void)
  28. {
  29. /* Set MOSI and SCK output, all others input */
  30. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  31. /* Enable SPI, Master, set clock rate fck/16 */
  32. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  33. }

  34. void SPI_MasterTransmit(char cData)
  35. {
  36. /* Start transmission */
  37. SPDR = cData;
  38. /* Wait for transmission complete */
  39. while(!(SPSR & (1<<SPIF)))
  40. ;
  41. }

  42. void SPI_SlaveInit(void)
  43. {
  44. /* Set MISO output, all others input */
  45. DDR_SPI = (1<<DD_MISO);
  46. /* Enable SPI */
  47. SPCR = (1<<SPE);
  48. }
  49. char SPI_SlaveReceive(void)
  50. {
  51. /* Wait for reception complete */
  52. while(!(SPSR & (1<<SPIF)))
  53. ;
  54. /* Return Data Register */
  55. return SPDR;
  56. }

  57. void mcp4921_send(unsigned int value){
  58. unsigned int mcp4922_data,dac_12;
  59. mcp4922_data=(1<<BUF)|(1<<ACTIVE);
  60. dac_12=value;
  61. mcp4922_data|=dac_12&0x0FFF;
  62. PRT_SPI&=~(1<<DD_SS);
  63. SPI_MasterTransmit(mcp4922_data>>8);
  64. SPI_MasterTransmit(mcp4922_data&0x00FF);
  65. PRT_SPI|=(1<<DD_SS);
  66. }

  67. int main(void)
  68. {
  69. /* Replace with your application code */
  70. SPI_MasterInit();
  71. char i=0;
  72. while (1)
  73. {
  74. mcp4921_send(4*sine_table[i]);
  75. //_delay_ms(10);
  76. i++;
  77. if(i>49) i=0;
  78. }
  79. }





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.

ATMega644P SPI and MCP492X 12-bit ADC
Schematic

 The master MCU just send the DAC values once and it keep in the buffer of the MCP4922 (buffer enabled).

  1. /*
  2. * 12-spi_mcp4922.c
  3. *
  4. * Created: 2/22/2026 8:01:15 PM
  5. * Author : Admin
  6. */

  7. #include <avr/io.h>
  8. #include <util/delay.h>
  9. #define F_CPU 16000000UL

  10. #define DDR_SPI DDRB
  11. #define PRT_SPI PORTB

  12. #define DD_SS 4
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7

  16. #define DAC_B 15
  17. #define BUF 14
  18. #define G1X 13
  19. #define ACTIVE 12

  20. void SPI_MasterInit(void)
  21. {
  22. /* Set MOSI and SCK output, all others input */
  23. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  24. /* Enable SPI, Master, set clock rate fck/16 */
  25. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  26. }

  27. void SPI_MasterTransmit(char cData)
  28. {
  29. /* Start transmission */
  30. SPDR = cData;
  31. /* Wait for transmission complete */
  32. while(!(SPSR & (1<<SPIF)))
  33. ;
  34. }

  35. void SPI_SlaveInit(void)
  36. {
  37. /* Set MISO output, all others input */
  38. DDR_SPI = (1<<DD_MISO);
  39. /* Enable SPI */
  40. SPCR = (1<<SPE);
  41. }
  42. char SPI_SlaveReceive(void)
  43. {
  44. /* Wait for reception complete */
  45. while(!(SPSR & (1<<SPIF)))
  46. ;
  47. /* Return Data Register */
  48. return SPDR;
  49. }

  50. int main(void)
  51. {
  52. /* Replace with your application code */
  53. SPI_MasterInit();
  54. unsigned int mcp4922_data,dac_12;
  55. mcp4922_data=(1<<DAC_B)|(1<<BUF)|(1<<ACTIVE);
  56. dac_12=3000;
  57. mcp4922_data|=dac_12&0x0FFF;
  58. PRT_SPI&=~(1<<DD_SS);
  59. SPI_MasterTransmit(mcp4922_data>>8);
  60. SPI_MasterTransmit(mcp4922_data&0x00FF);
  61. PRT_SPI|=(1<<DD_SS);
  62. mcp4922_data=(1<<BUF)|(1<<ACTIVE);
  63. dac_12=2048;
  64. mcp4922_data|=dac_12&0x0FFF;
  65. PRT_SPI&=~(1<<DD_SS);
  66. SPI_MasterTransmit(mcp4922_data>>8);
  67. SPI_MasterTransmit(mcp4922_data&0x00FF);
  68. PRT_SPI|=(1<<DD_SS);
  69. while (1)
  70. {
  71. }
  72. }


Now I added one ADC input to adjust the output DAC values.

ATMega644P SPI and MCP492X 12-bit ADC
Schematic

 

  1. /*
  2. * adc_dac.c
  3. *
  4. * Created: 2/23/2026 9:54:28 PM
  5. * Author : Admin
  6. */

  7. #include <avr/io.h>
  8. #include <util/delay.h>
  9. #define F_CPU 16000000UL

  10. #define DDR_SPI DDRB
  11. #define PRT_SPI PORTB

  12. #define DD_SS 4
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7

  16. #define DAC_B 15
  17. #define BUF 14
  18. #define G1X 13
  19. #define ACTIVE 12

  20. void SPI_MasterInit(void)
  21. {
  22. /* Set MOSI and SCK output, all others input */
  23. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  24. /* Enable SPI, Master, set clock rate fck/16 */
  25. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  26. }

  27. void SPI_MasterTransmit(char cData)
  28. {
  29. /* Start transmission */
  30. SPDR = cData;
  31. /* Wait for transmission complete */
  32. while(!(SPSR & (1<<SPIF)))
  33. ;
  34. }

  35. void SPI_SlaveInit(void)
  36. {
  37. /* Set MISO output, all others input */
  38. DDR_SPI = (1<<DD_MISO);
  39. /* Enable SPI */
  40. SPCR = (1<<SPE);
  41. }
  42. char SPI_SlaveReceive(void)
  43. {
  44. /* Wait for reception complete */
  45. while(!(SPSR & (1<<SPIF)))
  46. ;
  47. /* Return Data Register */
  48. return SPDR;
  49. }

  50. void dac_write(char dac, char gain, unsigned int dac_value){
  51. unsigned int mcp4922_data,dac_12,temp;
  52. if(gain==2) temp=0;
  53. else temp=1;
  54. if((dac=='B')||(dac==2)||(dac=='b')||(dac=='2'))
  55. mcp4922_data=(1<<DAC_B)|(1<<BUF)|(temp<<G1X)|(1<<ACTIVE);
  56. else if(dac=='A'||(dac==1)|(dac=='a')||(dac=='1'))
  57. mcp4922_data=(1<<BUF)|(temp<<G1X)|(1<<ACTIVE);
  58. else
  59. mcp4922_data=(1<<BUF)|(temp<<G1X)|(1<<ACTIVE);
  60. mcp4922_data|=dac_value&0x0FFF;
  61. PRT_SPI&=~(1<<DD_SS);
  62. SPI_MasterTransmit(mcp4922_data>>8);
  63. SPI_MasterTransmit(mcp4922_data&0x00FF);
  64. PRT_SPI|=(1<<DD_SS);
  65. }

  66. int main(void)
  67. {
  68. /* Replace with your application code */
  69. SPI_MasterInit();
  70. DDRB=0xFF;
  71. //PA0 or ADC0 as an analog input
  72. DDRA=0;
  73. //Turn on the ADC module
  74. ADCSRA=(1<<ADEN);
  75. uint16_t temp;
  76. ADMUX=0;
  77. dac_write(1, 2, 0x0FF);
  78. dac_write(2, 1, 0x0FFF);
  79. _delay_ms(5000);
  80. while (1)
  81. {
  82. //Start the conversion
  83. ADCSRA|=(1<<ADSC);
  84. //Wait for the completion
  85. while((ADCSRA&(1<<ADSC))==1);
  86. //Read the result
  87. temp=ADCL+(ADCH<<8);
  88. dac_write('A',2,temp*4);
  89. dac_write('B',2,0x0FFF-(temp*4));
  90. _delay_ms(100);
  91. }
  92. }





 

 

 

 

 

 


 

 

 

Saturday, July 18, 2020

Interfacing ATMega32 SPI to MCP4922 Dual 12-bit Digital To Analog Converter

Interfacing ATMega32 SPI to MCP4922 Dual 12-bit Digital To Analog Converter

Microchip MCP492X SPI Digital To Analog Converter

MCP492X is a 12-bit digital to analog converter (DAC) with SPI interface. MCP4921 is a single output DAC while MCP4922 has two configurable DAC. This SPI DAC could clock up to 20 MHz.

Interfacing ATMega32 SPI to MCP4922 Dual 12-bit Digital To Analog Converter DAC AVR ATMega Serial Peripheral Interface Microchip
A sample of this programming example


In this post I use MCP4922 I possess. I bought this chip from Futurlec on-line store a few years ago. It comes with an easy to prototype 14-bit DIP.


Interfacing ATMega32 SPI to MCP4922 Dual 12-bit Digital To Analog Converter
MCP4922 14-pin DIP Package

Interfacing ATMega32 SPI to MCP4922 Dual 12-bit Digital To Analog Converter
MCP4922 14-pin DIP pin diagram

These are the pins description of this IC:
  1. VDD  is positive supply voltage for internal device working (2.7 V to 5.5 V).
  2. NC - No Connection
  3. CS - Chip Select Input
  4. SCK - Serial Clock Input
  5. SDI - Serial Data Input
  6. NC - No Connection
  7. NC - No Connection
  8. LDAC - is active low. It transfers DAC setting from serial latches to output latches.
  9. SHDN - Hardware shut down input
  10. VOUTB - DAC_B Output
  11. VREFB - DAC_B Voltage Input (AVSS To VDD)
  12. AVSS - Analog ground
  13. VREFA - DAC_A Voltage Input (AVSS to VDD)
  14. VOUTA - DAC_A Output
The data format transfers to this device is 16-bit wide. One upper nibble is the DAC configuration bits while the remaining 12-bit is the DAC output value. The output value to DAC is up 4096 maximum.

DAC output voltage - VOUT lists as follow:
Interfacing ATMega32 SPI to MCP4922 Dual 12-bit Digital To Analog Converter
Where,
  • VREF is DAC voltage reference input. It could be DAC_A or DAC_B
  • G is output voltage gain, 1X or 2X.
  • DN is 12-bit DAC data input value
  • 2^N is the DAC resolution. In this case, the resolution is 12-bit yield the decimal value to 2^12 = 4046
The 16-bit SPI data representation lists below.

Interfacing ATMega32 SPI to MCP4922 Dual 12-bit Digital To Analog Converter
MCP4922 Write Command Register


Each bit functions as below.
  • Bit 15 - A/B - Write '0' for DAC_A, otherwise DAC_B
  • Bit 14 - BUF - Write '0' for Unbuffered, otherwise Buffered.
  • Bit 13 - GA - Write '0' 1x Gain, otherwise 2x Gain.
  • Bit 12 - SHDN - Write '0' to disable output buffer, otherwise enable the output buffer.
  • Bit 11:0 - D11:D0 - 12-bit digital data DAC output ranges from 0 to 4095 (4096 in total).
Data transfer to this device is 16-bit, we need to send 8-bit twice with only on latching pulse.

Interfacing ATMega32 SPI to MCP4922 Dual 12-bit Digital To Analog Converter
Writing the command to MCP4922. External wiring is not include here.

Interfacing And Programming With Atmel Studio 7 In C

In this example, I use both output DAC. Both DAC outputs the maximum 12-bit value, 0xFFF or 4096. With 2X gain, DAC A generate the output voltage nearest to 10 V. Similarly, using 1X gain, DAC B generate output the voltage nearest to 5 V. The sample of this program lists below. The reference voltage for both DAC is 5 V.

Interfacing ATMega32 SPI to MCP4922 Dual 12-bit Digital To Analog Converter DAC AVR ATMega Serial Peripheral Interface Microchip
A sample of this programming example

C source code:


Schematic Diagram

Interfacing ATMega32 SPI to MCP4922 Dual 12-bit Digital To Analog Converter
Schematic Diagram for simulation 



Search This Blog

Labels