New FPGA convert here. I am trying to interface with a parallel ADC as part of a data acquisition project. The pins on the ADC are used for both input and output (not simultaneously). Therefore, I need to drive the pins when I want to write control data to the ADC and read data values from the ADC when it is done with conversion. What are the different ways to do that? (I have an FSM driving the write and read signals so I know they are not simultaneous.)

I am currently going with the first approach (from comments) of splitting the signals into input and output versions at the top level, but I am having no joy with it. Here is an excerpt of my code and the picture of the FPGA family's IO pin in bidirectional mode:

inout [11:0] adc_data_pin_top

assign adc_data_pin_top = ~write_adc_data_n ? written_data_temp : 12'bz;
assign data_from_adc = converted_datas;

always @ (posedge adc_clock) begin 
  converted_datas <= adc_data_pin_top; 
  written_data_temp <= written_data_adc; 

My problem is that I cant read the data from the ADC. My adc_data_pin_top lines 'hold' values from the previous write cycle and spit it right back to me during my read cycle. I tried to use two tri-state buffers as shown below to make sure the write values are not 'leaking' to the input ports during a read cycle but that didnt help much. I am not sure if the tri-state buffer has to be clocked or not(i.e. if I need to use a register or just wires). Also, what exact value is a tristate signal(High Z) synthesized as in hardware? 0V? 1.4V? 2V? 3.3V? In other words, what should I expect to read when I am neither in read nor write cycle? You can see a diagram of altera's IO diagram of the pin on Page 2 of the document listed below the code:

assign adc_data_pin_top = (write_adc_data_n) ? 12'bZ : written_data_temp;
assign  converted_datas = (read_adc_data_n) ? 12'bZ : adc_data_pin_top;


Newbie alert! Sorry for all the triple-posting.

Edit: Chris, thanks for your help! The page won't let me comment on your comment, lol. So, I'm just going to comment here. The read and write signals are low enable and should be named that way-I'll fix that right now. Adding that inverter to the condition is probably redundant as well-read somewhere that old altera tools had a preference. I see what you are saying about the second statement--any high Z assignment infers a tristate buffer and I would have to pass that tri-state buffer(converted_datas) to my inner module which defeats the purpose of a split.

Further edits: Actually, on second thought, that is a GREAT idea! I do have push-button switches on the dev-kit that I can use to model an external switch. That way I can verify my HDL structure at least. But I cant read out my output signals unless I finally breakout that HSMC connector

Edit3: Hey Chris, finally got around to running that experiment today. I am able to drive the LED when the bidirectional bus is not in tristate. But because I cannot drive an input into the FPGA(and bidirectional pin) to simulate a one-bit ADC input, I cant verify that the bidirectional port is in tristate/read mode. Any ideas on how to get an input into an FPGA board with no GPIOs(except an HSMC connector)? Thanks!

Update: Yhello! Finally figured out a way to drive a signal into the FPGA via HSMC connector and was able to run a modified version of Chris' experiment--that was awesome! Now that I know my HDL bidirectional construct works, its one less variable to worry about. I figure the data being "spat" back to me is just the bus-hold feature of the FPGA board doing it work at high frequency to prevent metastability. That narrowed the possible issue down to control signal timing as I was not seeing data. Slackening the deadlines for the controls solved the problem. I am ecstatic to report my ADC is up and running! Thanks, Chris!

  • 1
    \$\begingroup\$ In HDL, preserve separate signals and a drive enable in your inner modules, and in the outer one declare an inout signal and drive 'z' when you want it to be an input - the tools should then infer what you want and configure the hardware to match the HDL behavior. Or you can look up the actual bidirectional iobuf function of your chosen FPGA family and explicitly instantiate them on the data lines. \$\endgroup\$ Aug 25, 2014 at 15:37
  • \$\begingroup\$ Hmm..sounds good. Just so I am actually sure we are on the same page. You are suggesting two approaches here; One is to have a top file 'split' the bidirectional pin into input/output pins that are passed along to the inner modules, right? And the second is to use the actual primitives defined for a Cyclone III FPGA(that is what I am using) to instantiate my data lines(any material on this one as I am not familiar with using primitives) \$\endgroup\$
    – oluishere
    Aug 25, 2014 at 15:47
  • \$\begingroup\$ In either case you'd split it in the top module, the choice I was proposing was between a language construct of driving the output or z's depending on the enable signal, vs. explicitly instantiating an iobuf that does that. \$\endgroup\$ Aug 25, 2014 at 15:53
  • \$\begingroup\$ I am having trouble doing a new line without saving the text so i am going to double post here. I am currently going with the first approach but I am having no joy with it. Is there any way to implement a bidirectional pin in HDL without using tri-state buffers? To explain further, my testbenches work fine--but my synthesis results are not quite right. How do I post a picture of a screen shot? \$\endgroup\$
    – oluishere
    Aug 25, 2014 at 15:55
  • \$\begingroup\$ A high Z signal doesn't necessarily have a defined voltage if unconnected. Consider making a simple experiment with a one bit inout signal with can be either z or the state of an external switch input, and the output enable controlled by input from another external switch, and the internal signal routed back to an output driving an LED. You should be able to put it in high Z mode and control that LED by driving the input high or low through a several K resistor, or put it in internal drive mode and control the LED with the switch. \$\endgroup\$ Aug 25, 2014 at 21:13


Your Answer

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

Browse other questions tagged or ask your own question.