Help with AD7991 code

Hey everyone. I tried implementing the ADC AD7991 Pmod Controller VHDL code provided in the “eewiki” with no avail. I am using a Nexys 3 board, and used two 2k2 pull-ups for both SDA and SCL lines. I edited the constant programmed in the ADC controller to define my system clock at 100MHz (operating frequency of the Spartan-6).

My program consists of the ADC controller and a PWM generator, the ADC reads the voltage from a potentiometer and passes that integer value as the duty cycle of the PWM generator working at 20kHz. Finally that PWM wave is outputted to an external LED. When I compile and run the program, the LED stays off and the error flag of the I2C slave acknowledge is always on. I can provide the code if needed.

Can anyone help me with this? Thank you very much!

Hi there. If you could provide your code and a picture of your setup (showing the I2C pull-up resistors), I will take a look.

Based on your description, I suspect the most likely source of the problem is a signal integrity issue on the I2C bus.

Regards,
Scott

Hey!

Thanks for the quick response. I’ve included some photos of the set-up (sorry if it’s a bit messy, if you have any doubts please ask). You can see that the potentiometer is on the bottom, in the middle the two 2k2 pull-up resistors of SCL and SDA, connected to F11 and E11 respectively on the Nexys 3, and on the top the LED that should be turning brighter or dimmer depending on the potentiometer. I’m including my code with the constraints file too (the top-level file is “noveno_ensayo.vhd” ).



noveno_ensayo.zip (513.2 KB)

On the Nexys3 board, isn’t the pmod connector that you are using JA (rather than JD)? So you are connected to FPGA pins N10 and P11, rather than F11 and E11?

Incorrect pin assignments for SDA and/or SCL would cause the I2C acknowledge error that you are seeing.

Thanks for pointing that out, I fixed the pin assignment for both SDA (P11) and SCL (N10) but I’m still having the same problem. The LED is always bright and the error flag is still high.

I still think you may likely have a signal integrity problem.

Do you have an o’scope?

Also, do you have any other pmods that use I2C by chance?

Yeah, I have an oscilloscope at the lab. And sadly I don’t own any other I2C Pmods, I was using the AD1 earlier but that one uses SPI.

One simple thing you could try first is changing the I2C bus speed. The AD7991 datasheet says it also supports standard mode. Slowing down the bus to standard mode could alleviate signal integrity problems somewhat.

Try changing the “bus_clk” generic to “100_000” when the I2C master is instantiated on line 79 of the pmod_adc_ad7991.vhd file.

Just tried that, still the same problem :pensive:.

If you look at SCL and SDA on your scope, I’m guessing they look pretty distorted…?

You could reduce the capacitance on the bus quite a bit by rewiring it to remove much of the wire length and eliminate some of the connections. Plug the pmod directly into the Nexys3’s pmod connector. The two rows are redundant, so you can plug the bottom row from the pmod into the top row on the Nexys3 connector. This will leave the top row of the pmod accessible above the Nexys3 connector. You can run your wires to the pull-up resistors from those exposed pins. Also use the VCC pin from the pmod for the other side of the pull-ups, rather than VCC from another connector. Also, if you have happen to have any shorter jumper wires… the shorter the better.

All of this should reduce the capacitance on the bus, improving the rise/fall times of the signals, improving the signal integrity.

I don’t have a Nexys3 kit available, but I just tried running your entire design on another board that I do have.

Everything works correctly, so the code itself should all be fine.

Hey Scott, I truly thank you for taking all this time to help me. I’m sorry I didn’t answer your scope question, I was at home and not in the lab with the tools to view the signals, and I didn’t see your edit afterwards.

I’m gonna try to reduce the capacitance with the methods you said and I’ll report back. Thanks again!

Well, I tried simplifying the wiring but I still have the same problem, bright LED and bright error acknowledge flag. I’m thinking it might be a breadboard problem. I’ll go to the lab tomorrow and come back with some SDA/SCL waveforms if I can. I’ll leave a pic of the setup here just in case.

So, I used the scope and the I2C master was working properly. The actual problem was that the adress was incorrect. Instead of using “0101000”, I used “0101001” and everything works now. Thank you very much for all the help!

So… just to clarify: you changed the address to “0101001” and now it works?

That’s interesting, because Digilent’s reference manual states to use “0101000”. That’s what works on mine.

There are multiple versions of the AD7991 with different addresses (see Table 8 on page 12 of the datasheet), so that would mean Digilent has produced this board with different versions. If so, that would be a very good thing to know, because it means other people will certainly have this problem as well.

I’m glad to hear that you got it working!

Exactly. I singled out signal integrity and I2C controller problems using a Digital Analyzer at the lab. Both SCL and SDA lines seemed fine, but the 64 bits of data that the ADC was supposed to output were all ones, so a friend pointed out that the address might be the problem, and he was totally correct! I reread the datasheet, tried the other address listed for the AD7991, and everything works fine now.

So if anyone else has the same problem and comes across this thread, definitely try changing the LSB in the address!

Below is an image of the scope with the ADC working, D1 is SCL and D0 is SDA.

Thanks for confirming that.

I will also update the ADC AD7991 Pmod Controller (VHDL) eewiki page to call this out, so hopefully anyone using the pmod controller can avoid the problem in the first place.

Can you suggest what changes must be made in the provided code to operate in high-speed mode?

Hi m.hitesh,

The author of this code is no longer available. However, looking through his documentation and the provided VHDL code, it does not look like there were provisions made for high-speed mode.

At first reading, I thought one could accommodate high-speed mode merely by changing the bus clock speed in the appropriate line of the pmod_adc_ad7991.vhd file – specifically changing the “bus_clk” generic to “xx_xxx_000” (where xx_xxx are MHz and kHz, respectively) on line 79. However, after reading through the documentation on page 25 of the AD7991 datasheet, it looks like going into high-speed mode involves first sending a command of “00001XXX” to all slave devices in “fast” mode, then issuing a “NO ACK”, and then switching the bus clock to “high-speed” mode. At this point one must issue another “start” followed by a device address and R/~W bit. Then the “high-speed” mode continues until the master issues a “stop” condition, at which time it switches back to “fast” mode.

It looks to me like you would have to modify the pmod_adc_ad7991.vhd file fairly significantly to allow for this mode. Specifically, you would need to add code to allow for the changing of the bus clock to high-speed and back again, as described in the process above.