Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Making sense of SPI with MCP4922 DAC


  • Please log in to reply
17 replies to this topic

#1 Pete Brown

Pete Brown

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationAnne Arundel County, MD

Posted 23 January 2011 - 04:34 AM

Hi All

I'm having a bear of a time trying to work with the MCP4922 12 bit DAC (data sheet) but I have no idea if the problem is how I wired it, or the SPI implementation or something else.

I don't have a logic analyzer yet, but I do have on order the one Chris recommended in a different thread.

1. Does anyone have an example of using the MCP4921 or MCP4922 DAC with the netduino?
2. If not, any suggestions on how to test to see where the fault is?

I've been coding for decades, but electronics is still pretty new to me. The test equipment I have right now is a BK Precision 2709B meter and a Rigol DS1052E scope. I don't see anything on the scope, even in the clock output (I thought I'd see something there at a minimum).

Code:
namespace NetduinoDacTest
{
    enum Dac
    {
        DacA = 0,
        DacB = 1
    }

    public class Program
    {
        public static void Main()
        {
            OutputPort ldacPin = new OutputPort(Pins.GPIO_PIN_D9, true);
            OutputPort shutdownPin = new OutputPort(Pins.GPIO_PIN_D8, true);

            SPI.Configuration config = new SPI.Configuration(
                Pins.GPIO_PIN_D10,  // chip select is D10
                false,              // active is low, according to DAC spec
                0,                  // setup time
                0,                  // hold time
                false,              // clock idle state is low
                true,               // data is sampled on rising clock edge
                100,                // clock rate in KHZ
                SPI.SPI_module.SPI1);

            SPI dacSpi = new SPI(config);

            // output samples
            ushort sample;
            ushort message;

            Random rnd = new Random();

            while (true)
            {
                sample = (ushort)rnd.Next(4095);    // random noise for now

                message = BuildSingleSpiMessage(sample, Dac.DacA);

                // need to set LDAC to high in case I wanted to output to both DACs at once (stereo)
                ldacPin.Write(true);

                dacSpi.Write(new ushort[] { message });

                // need to set LDAC to low
                ldacPin.Write(false);
            }
        }


        

        // assumes that the sample value provided is only 12 bits (0-4095)
        private static ushort BuildSingleSpiMessage(ushort sample, Dac selectedDac)
        {
            // bits 0-11 are sample
            ushort message = sample;

            // bit 12: output power down control. Set to 1 to allow output
            message = (ushort)(message | 0x1000);

            // bit 13: output gain. We'll allow a set to 1 to have normal 1:1 output
            message = (ushort)(message | 0x2000);

            // bit 14: Vref Buffer. We'll assume unbuffered, so zero
            message = (ushort)(message & 0x4000);

            // bit 15: dac A or Dac B. Zero is A, 1 is B.
            if (selectedDac == Dac.DacA)
                message = (ushort)(message & 0x8000);
            else
                message = (ushort)(message | 0x8000);


            return message;

        }

    }
}


DAC Pins:
1. Vdd -> Netduino 3.3v, with a .1uf cap as recommended
2. NC (empty)
3. CS -> Netduino D10
4. SCK -> Netduino D13
5. SDI -> Netduino D12
6. NC (empty)
7. NC (empty)
8. LDAC -> Netduino D9 (for synchronization of the two DACs when I end up finally using B)
9. SHDN -> Netduino D8 (not sure if I need this wiring and logic)
10. VOUTB -> empty for now
11. VREFB -> empty for now
12. AVss -> Netduino Ground
13 VREFA -> Netduino 3.3v
14. VOUTA -> Scope

Pete
Pete Brown - http://10rem.net (NETMF, C++, Windows, C64, and general geekery) Twitter: @pete_brown
I work for Microsoft. Opinions expressed here are my own and do not necessarily reflect those of my employer,our partners or customers.

#2 Fabien Royer

Fabien Royer

    Advanced Member

  • Members
  • PipPipPip
  • 406 posts
  • LocationRedmond, WA

Posted 23 January 2011 - 06:41 AM


Hey Pete,

At first glance, SDI should be connected to Netduino D11 (SPI MOSI), not D12.
Also, if you want to send 12 bit values to the DAC, you should take a a look at the ExtendedSPIConfiguration class: http://forums.netdui...ch__1#entry6888



Another thought: the clock rate can be much higher than 100 kHz according to the datasheet (up to 20 Mhz).

Cheers,
-Fabien.


#3 Pete Brown

Pete Brown

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationAnne Arundel County, MD

Posted 23 January 2011 - 07:29 AM


Hey Pete,

At first glance, SDI should be connected to Netduino D11 (SPI MOSI), not D12.
Also, if you want to send 12 bit values to the DAC, you should take a a look at the ExtendedSPIConfiguration class: http://forums.netdui...ch__1#entry6888



Another thought: the clock rate can be much higher than 100 kHz according to the datasheet (up to 20 Mhz).

Cheers,
-Fabien.



Thanks, especially for the MOSI/MISO Pin. I was reading the last letter and thinking that was the I/O. I just looked up the definitions of the terms :)

Additionl info:

The DAC is 12 bits, but the messages are 16 bits (4 config bits plus 12 data bits), so I should be good with the default SPI class.

I just tried it at 100khz, 1mhz, 5mhz, 10mhz and 20mhz (assuming the Netduino actually sends clocks that high). FWIW, I don't even see a clock signal coming from the netduino when I hook the scope up to D13. Maybe I'm reading it incorrectly or something. I'm pretty new to the hardware side of things.

I tried this both on my regular netduino (now flashed with latest firmware) and my netduino plus with the latest 4.1.1.0 alpha.

Am I missing something really dumb? Does SPI need to be turned "on" or something?

Pete
Pete Brown - http://10rem.net (NETMF, C++, Windows, C64, and general geekery) Twitter: @pete_brown
I work for Microsoft. Opinions expressed here are my own and do not necessarily reflect those of my employer,our partners or customers.

#4 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 23 January 2011 - 07:38 AM

Hi Pete, Could you please try this with the v4.1.0.5 firmware? It may be a glitch in the alpha 5 firmware (which we just fixed and will be posting soon). Chris

#5 Pete Brown

Pete Brown

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationAnne Arundel County, MD

Posted 23 January 2011 - 07:53 AM

Hi Pete,

Could you please try this with the v4.1.0.5 firmware? It may be a glitch in the alpha 5 firmware (which we just fixed and will be posting soon).

Chris


My regular netduino had 4.1.0.5, but I just flashed the Plus I'm working with now to be sure. This is what I now have on the board:

SolutionReleaseInfo.solutionVersion: 4.1.0.5
SolutionReleaseInfo.solutionVendorInfo: Netduino Plus by Secret Labs LLC
SoftwareVersion.BuildDate: Nov 7 2010
SoftwareVersion.CompilerVersion: 400771

No dice on getting SPI and the DAC to work.

When I hook the scope up to the SCLK on the netduino, I expect to see a pulse, but I get nothing. (Tried a different wire to, just to be sure <g>)

Pete
Pete Brown - http://10rem.net (NETMF, C++, Windows, C64, and general geekery) Twitter: @pete_brown
I work for Microsoft. Opinions expressed here are my own and do not necessarily reflect those of my employer,our partners or customers.

#6 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 23 January 2011 - 08:09 AM

Pete, How are you triggering your scope? Are you triggering on the first level change? The clock will only run while data is being transmitted... You may want to trigger on the chip select line, if your oscilloscope will capture a long enough signal. Chris

#7 Pete Brown

Pete Brown

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationAnne Arundel County, MD

Posted 23 January 2011 - 08:11 AM

Ok, for a sanity check, I just ported my code to the FEZ Panda (I love .NET!), and got the same non-results. That likely means one of the following: 1. Wiring is wrong (doesn't explain clock issue, though) 2. My program logic is wrong 3. My testing procedure is wrong and I'm looking at the wrong thing or at it the wrong way So, my first question: With the above code, if I hook a scope up to SCLK on the netduino, should I see a pulse at the specified clock frequency? What is the voltage range of the clock pulse? Is it 0.0 to 3.3 or 0.0 to 2.0 or something else? Pete
Pete Brown - http://10rem.net (NETMF, C++, Windows, C64, and general geekery) Twitter: @pete_brown
I work for Microsoft. Opinions expressed here are my own and do not necessarily reflect those of my employer,our partners or customers.

#8 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 23 January 2011 - 08:24 AM

So, my first question: With the above code, if I hook a scope up to SCLK on the netduino, should I see a pulse at the specified clock frequency? What is the voltage range of the clock pulse? Is it 0.0 to 3.3 or 0.0 to 2.0 or something else?


Hi Pete,

Yes, but only while data is being sent. The CLK signal will be 0 to 3.3V.

Chris

#9 Innovactive

Innovactive

    Member

  • Members
  • PipPip
  • 29 posts

Posted 23 January 2011 - 09:14 AM

Hi Pete.

We use a MCP4822 DAC on our (amazing) Enhanced Driving Experience prototype.

Looking at datasheets it seems that SPI communication protocol should be the same of DAC you're using.

Our DAC driver is simply:

 public class MCP4822_DAC
    {
        // SPI bus reference
        SPI _spi = null;

        // ctor requires a pre-initialized SPI bus
        public MCP4822_DAC(SPI spi)
        {
            _spi = spi;
        }

        public void SetOut(OutputChannelEnum Channel, ushort Value)
        {
            Debug.Print("DAC SetOut: " + Channel + "," + Value);

            if (Value > 4095) throw new ArgumentException("Out of range (0-4095)", "Value");

            ushort[] tx = new ushort[1] {Value};

            if (Channel == OutputChannelEnum.ChannelB) tx[0] |= (1 << 15);

            tx[0] |= (1 << 12);

            _spi.Write(tx);
        }
    }

    public enum OutputChannelEnum
    {
        ChannelA,
        ChannelB
    }

We initialize the driver as following:

SPI.Configuration spiConfig = new SPI.Configuration(
            (Cpu.Pin)FEZ_Pin.Digital.UEXT6,    // CS Pin
            false,              // CS active when LOW
            0,                  // CS setup time
            0,                  // CS hold time
            false,              // SCK idle when LOW
            true,               // MISO/MOSI sampling on rising edge of SCK
            250,                // 250 KHz
            SPI.SPI_module.SPI2);

// SPI bus
SPI spi = new SPI(spiConfig);

MCP4822_DAC dac = new MCP4822_DAC(spi);


Hope this can help you ;)

#10 Pete Brown

Pete Brown

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationAnne Arundel County, MD

Posted 24 January 2011 - 07:53 AM

@Innovactive Thanks. The code is similar. I removed some of the extra statements in mine to make it more like what you have. Can you share your pinout? (awesome car setup, btw) Pete
Pete Brown - http://10rem.net (NETMF, C++, Windows, C64, and general geekery) Twitter: @pete_brown
I work for Microsoft. Opinions expressed here are my own and do not necessarily reflect those of my employer,our partners or customers.

#11 Pete Brown

Pete Brown

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationAnne Arundel County, MD

Posted 24 January 2011 - 08:05 AM

Pete,

How are you triggering your scope? Are you triggering on the first level change? The clock will only run while data is being transmitted...

You may want to trigger on the chip select line, if your oscilloscope will capture a long enough signal.

Chris


Thanks Christ.

I hooked the scope up to CS and got nothing. Maybe I'm just using it wrong. :P #noob

Pete
Pete Brown - http://10rem.net (NETMF, C++, Windows, C64, and general geekery) Twitter: @pete_brown
I work for Microsoft. Opinions expressed here are my own and do not necessarily reflect those of my employer,our partners or customers.

#12 Pete Brown

Pete Brown

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationAnne Arundel County, MD

Posted 24 January 2011 - 08:12 AM

Arrrgghh! OMG I'm an idiot. I'm almost too ashamed to post what I was doing, but I will anyway. I was connecting the wrong test lead to the signal. This is what happens when you let a noob play with cool toys :) Pete
Pete Brown - http://10rem.net (NETMF, C++, Windows, C64, and general geekery) Twitter: @pete_brown
I work for Microsoft. Opinions expressed here are my own and do not necessarily reflect those of my employer,our partners or customers.

#13 Pete Brown

Pete Brown

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationAnne Arundel County, MD

Posted 24 January 2011 - 08:25 AM

BTW, I still don't actually have any *output*, but at least I can see the clock and CS signals :)
Pete Brown - http://10rem.net (NETMF, C++, Windows, C64, and general geekery) Twitter: @pete_brown
I work for Microsoft. Opinions expressed here are my own and do not necessarily reflect those of my employer,our partners or customers.

#14 Pete Brown

Pete Brown

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationAnne Arundel County, MD

Posted 24 January 2011 - 08:48 AM

One last update on this part: Success!

Posted Image

My waveform isn't perfect (need to figure out what's up with the bottoming out), but it's definitely coming from code and running through the DAC :)

I had some code issues as well as just the dumb testing issue I mentioned above. Thanks everyone for the help

Pete
Pete Brown - http://10rem.net (NETMF, C++, Windows, C64, and general geekery) Twitter: @pete_brown
I work for Microsoft. Opinions expressed here are my own and do not necessarily reflect those of my employer,our partners or customers.

#15 light

light

    Member

  • Members
  • PipPip
  • 13 posts

Posted 27 January 2011 - 07:36 PM

How would this work if you had two DACs? The SPI config only takes one cs pin. I tried creating another SPI object with a different cs pin but that errored. Thanks Ron

#16 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 27 January 2011 - 09:49 PM

How would this work if you had two DACs? The SPI config only takes one cs pin. I tried creating another SPI object with a different cs pin but that errored.
Thanks
Ron


Hi Ron,

You might need to dispose of the first SPI object before creating the second one. I know...lots of GC action going on there.

Chris

#17 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 28 January 2011 - 07:21 AM

How would this work if you had two DACs? The SPI config only takes one cs pin. I tried creating another SPI object with a different cs pin but that errored.

You can use a general I/O pin (i.e. OutputPort) for custom-controlled CS pin. It is not necessary to use ChipSelect_Port in SPI.Configuration at all (pass Pin.GPIO_NONE).

The Neduino microcontroller directly supports up to 15 SPI peripheral devices (with decoding on four chip select lines, up to 4 without decoding), but unfortunately this feature is not accessible neither in the current .NET Micro Framework firmware (not implemented) nor on Netduino boards (pins not broken out). The SPI class represents the hardware interface module, so you can instantiate only one object (it is not per slave device). The microcontroller has two SPI interfaces, the second one is used internally for SD card on Netduino Plus.

#18 Pete Brown

Pete Brown

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationAnne Arundel County, MD

Posted 01 February 2011 - 05:25 PM

The managed code route won't work for sound synthesis. Once Chris has the source up on codeplex and I can do a custom firmware build, I'll try porting that part to native code. Here's as far as I got in managed code:

http://10rem.net/blo...th-the-netduino

Thanks all for the help.

Pete
Pete Brown - http://10rem.net (NETMF, C++, Windows, C64, and general geekery) Twitter: @pete_brown
I work for Microsoft. Opinions expressed here are my own and do not necessarily reflect those of my employer,our partners or customers.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.