0

I'm encountering an issue while testing a custom-designed DAC module that utilizes an MCP4922 chip as its primary processor. The vendor provided C language test code for ESP32-S3, but I intend to test the module on a Raspberry Pi 3B+ using Python.

I've installed the Python-RPi-MCP4922 library and executed the test code, but the output voltage consistently remains at 0.

To investigate, I've: Removed the MCP4922 chip from the module and connected it directly to a breadboard following the provided schematic. The chip functioned normally, with the output voltage fluctuating according to the code.

Reattached the MCP4922 chip to the module and ran the test code. The output voltage remained at 0.

Employed a VOM to directly measure the voltage at the VoutA pin of the MCP4922 on the module. The voltage at this pin also consistently remained at 0.

I suspect the issue may stem from: Faulty DAC module hardware. Modifications required in the Python code for compatibility with the module.

Questions:

In your opinion, what could be causing the output voltage to remain at 0 consistently?

What modifications are necessary to the Python code for the module to function properly?

Do you have any other suggestions for troubleshooting this issue?

Thank you for your time and consideration.

Additional Information:

Schematic of module DAC MCP4922: https://dientuagv.com/wp-content/upload ... apture.png

Python-RPi-MCP4922 Library: https://github.com/topics/mcp4922

Schematic connect with raspberry pi: https://github.com/mrwunderbar666/Pytho ... tch_bb.png, https://github.com/mrwunderbar666/Pytho ... tch_bb.png

C language test code for ESP32-S3:

//#define DA_SDI  51
//#define DA_SCK  52
//#define DA_CS   53
#define DA_SDI  5
#define DA_SCK  41
#define DA_CS   42
long int CNT_TIME1=0;
static unsigned char buf[2];
static unsigned char gain =2.5;
static unsigned char buffered  = 1;
static unsigned char shdn = 1;
long int cnt_value=0;
 bool        usesHardwareReset = false;

void convert_dac(unsigned char x)
{   // do chuc nang ghi dich 8 bit vao noi tiep ra song song
     // do do vong for duoi se cho dich 8 lan de du 8 chan dau ra cho vdk
 int i,tam;
 for(i=0;i<8;i++) // 8 lan dich de co 8 bit
 {
  tam=x;
  tam=tam&0x80;
  if(tam==0x80)  digitalWrite(DA_SDI, HIGH);
  else   digitalWrite(DA_SDI, LOW);
  x=x<<1;    // dich bit nhu sau
   digitalWrite(DA_SCK, HIGH);;
   
   digitalWrite(DA_SCK, LOW);
 }
}
void update_channels( unsigned int chA, unsigned int chB )
  {
  // write a value to channel A
    buf[0] = (0 << 7) | (buffered << 6) | (gain << 5) | (shdn << 4) | (chA >> 8);
    buf[1] = (chA & 0xff); 
    convert_dac( buf[0]);
    convert_dac( buf[1]);
    digitalWrite( DA_CS, HIGH);
    digitalWrite(DA_CS, LOW); 
   
  // write a value to channel B
  buf[0] = (1 << 7) | (buffered << 6) | (gain << 5) | (shdn << 4) | (chB >> 8);
  buf[1] = (chB & 0xff);
 convert_dac( buf[0]);
  convert_dac( buf[1]);
   digitalWrite( DA_CS, HIGH);
    digitalWrite(DA_CS, LOW); 
  // Update DAC output
 
}
void analogWrite(unsigned char odd, unsigned char buffered, unsigned char gain, unsigned char  active, unsigned int value) 
  {
  
 unsigned char configBits  ; 
  unsigned char firstByte ;
   unsigned char secondByte;
 configBits = odd << 3 | buffered << 2 | gain << 1 | active;
  // Compose the first byte to send to the DAC:
  // the 4 control bits, and the 4 most significant bits of the value
firstByte= configBits << 4 | (value & 0xF00) >> 8;
 // Second byte is the lower 8 bits of the value
 secondByte = value & 0xFF;
convert_dac(firstByte);
 convert_dac(secondByte);  
 digitalWrite( DA_CS, HIGH);
    digitalWrite(DA_CS, LOW); 
 
}

void setup() {
  // put your setup code here, to run once:
 pinMode(DA_SDI, OUTPUT);
  pinMode(DA_SCK, OUTPUT);
   pinMode(DA_CS, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  CNT_TIME1++;
  switch(CNT_TIME1)
  {
    case 1000:cnt_value++;break;
    case 2000: update_channels(cnt_value,cnt_value);break;
    case 3000:CNT_TIME1=0;break;
    }


   if(cnt_value>4095) cnt_value=0;
  // delay(1);
}

Test code on Raspberry Pi 3B+ using Python:

#!/usr/bin/python

"""
Python Library for MCP4922 DAC using Raspberry Pi 3 Model B+
2 Channels, 12 Bit
Currently only supports Hardware SPI
Requires: RPi.GPIO & spidev libraries

Wiring:

MCP4922    =======>   Raspberry Pi

CS         ------->   GPIO08 Physical Pin 24 (SPI0 CE0) => Can be changed
SDI        ------->   GPIO10 Physical Pin 19 (SPI0 MOSI) => cannot be changed in hardware SPI MODE
SCK        ------->   GPIO11 Physical Pin 23 (SPI0 SCLK) => cannot be changed in hardware SPI MODE

MIT License

Copyright (c) 2017 mrwunderbar666

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

"""
import time
import sys
import RPi.GPIO as GPIO
import spidev


class MCP4922(object):
    """ Class for the Microchip MCP4922 digital to analog converter
    """
    spi = spidev.SpiDev()
    
    def __init__(self,
                 spibus=None,
                 spidevice=None,
                 cs=None
                 ):
        """ Initialize MCP4922 device with hardware SPI
            Chipselect default value is BCM Pin 8 (Physical Pin: 24)
            Select the bus and device number. Default values are:
            Bus = 0 ; Device = 1
            If you're not sure, just leave it default
        """
        mode = GPIO.getmode()
        if mode == GPIO.BOARD:
            default_cs = 24
        elif mode == GPIO.BCM:
            default_cs = 8
        else:
            raise ValueError(
                "You haven't selected a GPIO Mode? Use: e.g. GPIO.setmode(GPIO.BCM)")

        if cs is None:
            self.cs = default_cs
        else:
            self.cs = cs

        if spibus is None:
            self.spibus = 0
        else:
            self.spibus = spibus

        if spidevice is None:
            self.spidevice = 1
        else:
            self.spidevice = spidevice

        GPIO.setup(self.cs, GPIO.OUT)
        GPIO.output(self.cs, 1)
        # As soon as MCP4922 object is created spidev bus and device are opened
        # otherwise causes memory leak and creates Errno 24
        self.spi.open(self.spibus, self.spidevice)

    def setVoltage(self, channel, value):
        """
        Regular setVoltage Function
        Select your channel 0 or 1
        Select Voltage value 0 to 4095
        """
        if channel == 0:
            output = 0x3000 # 3 bit dau la bit dac biet de chon mode, 12 bit sau la du lieu 
        elif channel == 1:
            output = 0xb000 # 3 bit dau la bit dac biet de chon mode, 12 bit sau la du lieu 
        else:
            raise ValueError(
                'MCP4922 Says: Wrong Channel Selected! Chose either 0 or 1!')
        if value > 4095:
            value = 4095
        if value < 0:
            value = 0
        #self.spi.open(self.spibus, self.spidevice)
        output |= value # gan data value cho output
        buf0 = (output >> 8) & 0xff # tach 8 bit dau và sau
        buf1 = output & 0xff
        GPIO.output(self.cs, 0)
        self.spi.writebytes([buf0, buf1])
        GPIO.output(self.cs, 1)
        #self.spi.close
        return

    def setVoltage_gain(self, channel, value):
        """
        The MCP4922 has the ability to output the double of the reference Voltage
        Reference Voltage is measured by the MCP4922 at pin 13 (VrefA) for Channel A and pin 11 (VrefB) for Channel B
        Note that the output voltage cannot exceed the supply voltage from pin 1 (VDD)
        """
        if channel == 0:
            output = 0x1000 # 0111 0000 0000 0000
        elif channel == 1:
            output = 0x9000
        else:
            raise ValueError(
                'MCP4922 Says: Wrong Channel Selected! Chose either 0 or 1!')
        if value > 4095:
            value = 4095
        if value < 0:
            value = 0
        #self.spi.open(self.spibus, self.spidevice)
        output |= value
        buf0 = (output >> 8) & 0xff
        buf1 = output & 0xff
        GPIO.output(self.cs, 0)
        self.spi.writebytes([buf0, buf1])
        GPIO.output(self.cs, 1)
        #self.spi.close
        return

    def setVoltage_buffered(self, channel, value):
        """
        Using the buffer feature of the MCP4922,
        refer to the datasheet for details
        """
        if channel == 0:
            output = 0x7000
        elif channel == 1:
            output = 0xF000
        else:
            raise ValueError(
                'MCP4922 Says: Wrong Channel Selected! Chose either 0 or 1!')
        if value > 4095:
            value = 4095
        if value < 0:
            value = 0
        #self.spi.open(self.spibus, self.spidevice)
        output |= value
        buf0 = (output >> 8) & 0xff
        buf1 = output & 0xff
        GPIO.output(self.cs, 0)
        self.spi.writebytes([buf0, buf1])
        GPIO.output(self.cs, 1)
        #self.spi.close
        return

    def shutdown(self, channel):
        """
        Completely shutdown selected channel for power saving
        Sets the output of selected channel to 0 and 500K Ohms.
        Read Datasheet (SHDN) for details
        """
        if channel == 0:
            output = 0x2000
        elif channel == 1:
            output = 0xA000
        else:
            raise ValueError(
                'MCP4922 Says: Wrong Channel Selected! Chose either 0 or 1!')
        #self.spi.open(self.spibus, self.spidevice)
        buf0 = (output >> 8) & 0xff
        buf1 = output & 0xff
        GPIO.output(self.cs, 0)
        self.spi.writebytes([buf0, buf1])
        GPIO.output(self.cs, 1)
        #self.spi.close
        return

    def close(self):
        """
        Closes the device
        """
        self.spi.close
        return

    def open(self):
        """
        Manually Open the device
        """
        self.spi.open(self.spibus, self.spidevice)
        return


    
GPIO.setmode(GPIO.BCM)                 # use the Broadcom pin numbering
GPIO.setwarnings(False)             # disable warnings

if __name__ == '__main__':
    dac = MCP4922()
    try:
        while True:
            x = 0
            for i in range(0, 100):
                x = x + 40
                dac.setVoltage(0, x)
                dac.setVoltage(1, x)
                print(x)
                time.sleep(0.1)
            for i in range(0, 100):
                x = x - 40
                dac.setVoltage(0, x)
                dac.setVoltage(1, x)
                print(x)
                time.sleep(0.1)

    except KeyboardInterrupt:   # Press CTRL C to exit program
        dac.setVoltage(0, 0)
        dac.setVoltage(1, 0)
        dac.shutdown(0)
        dac.shutdown(1)
        GPIO.cleanup()
        sys.exit(0)
2
  • If possible, use an oscilloscope to monitor the SPI communication between the Raspberry Pi and the MCP4922 chip. This can help identify any anomalies or errors in the communication.
    – liaifat85
    Apr 3 at 10:07
  • You can cross-check your code and circuit with this video: youtube.com/watch?v=iwzXh2V1SP4
    – liaifat85
    Apr 6 at 11:33

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.