MKR Vidor 4000 interface between FPGA and SAMD21 using JTAG

Hi,

i have an Arduino MKR Vidor 4000 running a completely self-built CNC mill with true servo motors with incremental encoders. For this i am using a custom bitstream on the fpga. Right now i have an interface between the fpga and the cpu: 4 pins are used in a protocol similar to SPI, where the cpu is the master and the fpga the slave. The CPU repeatedly send and receives 512 bits at the same time, which means at every transfer 16 32-bit values are sent from the cpu to the fpga and vice-versa. This works flawlessly and is able to send numbers back and forth for hours at a frequency of 100Hz without any errors.

However, pins are rare on the vidor 4000 and i need every single one: that is 4 pins i can’t use anymore.

And now to my question: Is there a way to establish a reliable runtime communication between the fpga and the cpu without using an external pin?

I have been looking for documentations about pin schematics, but i was not able to find anything helpful. However, there must be a connection between the two chips that is not broken out: The JTAG pins!

As far as i have found out, there are four JTAG pins connecting the two chips, via which the fpga bitstream is uploaded when the program starts. In the Arduino variants.cpp i was even able to find the exact SAMD21 pin numbers for those pins, which means i can simply write to them. I have also found the JTAG pins in the Intel Quartus pin assignment for the vidor 4000, but these pins seem to be unconnected or unaccessable from an fpga program.

Can i somehow use these JTAG pins to receive data from the cpu?

Another question: How does the standard vidorPeripherals bitstream communicate?

When using the standard library there is obviously a communication to the cpu, which is not interferring with any external pins, but how can i use that myself?

Hope someone can help me here or give me any hints…

To communicate between MCU and FPGA you can use the JTAG pins like .... JTAG!

Altera / Intel has defined 2 registers (IR) of the JTAG on its FPGA to simulate a virtual JTAG usable by the hardware synthesized in the FPGA.

This mode is used by libraries to create the Message Box to send requests to the FPGA.

Also in my TiledScreen library I used this interface to read / write to the SDRAM and set the registers of the video controller.

Search for virtual JTAG in the Intel documentation and find all the explanations.

In the ip catalog of my quartus project i have 4 ip cores about jtag:

  • JTAG to Avalon Master Bridge
    -Altera Soft Core JTAG IO
    -Altera Virtual JTAG
    -ipTronix JTAG Bridge

Can i use any of those predefined ip cores and which one should i try?

Thanks for your time!

Altera Virtual JTAG

You should read this document: ug_virtualjtag.pdf

Very interesting, I didn't realize before this opportunity!
What library for the CPU?

Thanks.

I used the functions present in the jtag_host.cpp and jtag_host.h files of the VidorGraphics repository.

They are convenient because you can switch between using BitBang and SPI mode based on the bit length of the data to be transferred.

The functions I wrote are specific to a single instance Virtual JTAG with 16 registers, but I think it is a mode that adapts to several situations.

At the moment I do not use all 16 registers, but since in any case you cannot use less than 4 bits in the field in which to send the DR, you might as well use them all.

If you want to have a look at it, you can find the functions in the TiledScreen library that I published in the past few days.

Thanks for your help so far!

I managed to get tck, tdi and tms signals into my fpga program, as well as all state signals. This means, i can change the controller state using your JTAG_Walk function and receive data in the fpga, however i can not send anything back...

I connected a blinking clock to tdo, the output pin of the fpga jtag module, as well as an external pin. Then on the cpu i either do a digitalRead or TDO_READ and the external pin blinks like expected, but the tdo pin remains high.

Also, i found the primitive module sld_virtual_jtag, which has the exact same pins as Altera virtual JTAG with primitive signals enabled, but looks a lot cleaner. Nevertheless, both behave exactly the same with having the tck, tdi and tms signals working, but seemingly blocking the tdo pin.

Do i need to be in a specific state for the tdo data to pass through?

Edit: I realised this may also be due to having initialised several instances of jtag stuff, where inputs still work, but outputs are interferring, can i somehow make sure only the currently used instance has access?

If you do not receive data, I think that you have forgotten to close the loop: you must assign the value of the least significant bit of the selected shift register to the tdo signal.

In my code it is this:

assign tdo = (ir_in == VIR_CTRL)    ? sh_CTRL[0]
           : (ir_in == VIR_0OUTPUT) ? sh_0OUTPUT[0]
           : (ir_in == VIR_0INPUT)  ? sh_0INPUT[0]
           : (ir_in == VIR_FWADDR)  ? sh_FWADDR[0]
           : (ir_in == VIR_FWDATA)  ? sh_FWDATA[0]
           : (ir_in == VIR_GEOM)    ? sh_GEOM[0]
           : (ir_in == VIR_BKCOLOR) ? sh_BKCOLOR[0]
           : (ir_in == VIR_PALETTE) ? sh_PALETTE[0]
           : (ir_in == VIR_DEBUG)   ? sh_DEBUG[0]
           : sh_BYPASS;

But without seeing the code it's hard to say ...

Ok, things just changed…

attached is an image of my fpga program, note it’s stiched together from separate screenshots. There’s just a clock signal driving tdo and oENABLE_Z, which is digital pin 0 and the fat line is from my already working communication (u[17] is pulled high so i see where relevant data starts).

Here’s a snippet of code on the cpu transferring jtag stuff:

    TDI_WRITE((millis() / 50) % 2 == 0);

    jtag_host_pulse_tck(0);

    message("TDO: ", TDO_READ());
    message("ENZ: ", digitalRead(0));
    delay(60);

While all this code is running the controller is in the state shift_ir. And now to the interesting stuff: TDI is toggling at a high frequency, while the fpga clock is toggling at a low frequency. tdi in the fpga program is confirmed by the existing communication to toggle at the expected high frequency, while the D0 pin is confirmed to toggle at the expected low frequency. However, tdo should also toggle at the same low frequency like D0, but is doesn’t, it toggles at the high frequency of tdi with a slight offset.

I understand that this offset is due to a shift register shifting all bits through, but when all bits shifted in are also shifted back out, how is the fpga supposed to add information, or what effect does the tdo pin in the fpga have? Do i need to be in a different state for the tdo pin to have an effect?

I think you misunderstood how virtual JTAG works.

The TDI and TDO signals present on the virtual JTAG interface are not directly connected to the TDI and TDO pins of the physical JTAG interface. So you can't use them to send any signal. They can only be used through the JTAG protocol.

The signals are all synchronized with the TCK clock, therefore also the status of the TDO signal is read only during the rising edges of TCK.

I am aware that I need to apply the JTAG interface to be able to send data back. This is the code I am using now on the cpu:

void uploadStart() {
  enableFpgaClock();
  jtag_host_setup();

  walk(5, 0b11111);
  pinMode(0, INPUT);  // ENABLE_Z on the FPGA
}


void walk(uint8_t numticks, uint16_t path)
{ for(int i=0; i<numticks; i++, path >>= 1) jtag_host_pulse_tck(path & 0x0001);
}


void uploadData() {
  // Send instruction 100
  uint16_t instr = 100;
  walk(10, 0x0DF);
  uint16_t result = jtag_host_pulse_tdio(10, instr);
  message("Sent instruction: ", instr);
  message("Instruction return: ", result);

  // Send data 12345678
  walk(5, 0x07);
  uint32_t value = 12345678;
  uint32_t got = jtag_host_pulse_tdio(32, value);
  message("Sent Value: ", value);
  message("Got  Value: ", got);

  // Info
  message("TDO: ", TDO_READ());
  message("ENZ: ", digitalRead(0));
  delay(60);
}

(See attachments)
As you can see, i am sending instruction 100 and i receive back 0b0101010101 (decimal 341), which according to the bsdl files of the cyclone 10 means that the instruction was captured successfully. This not only tells me that the instruction was successful, but also that reading with jtag_host_pulse_tdio() is generally working. Additionally, using jtag_host_pulse_tdio() and jtag_host_pulse_tdio_instruction() does not make a difference.

When sending the data however, i do not receive the content of the attached shift register or the clock which is sending all ones and some time later all zeroes. No matter what i attach to tdo, i always get twice the value I sent beforehands (shifted left by one bit because of the bypass register).

Now, when looking at the state signals the primitive state signal jtag_state_sdr (bit 11) is active, but the virtual state signal virtual_state_sdr (bit 23) is not. This gives me the impression that the virtual instance did not realise the state was changed and therefore does not switch from the bypass register to using user-defined shift registers connected to tdo.

Also, what instruction do i have to send?
When sending some specific instructions below 16 and then sending some data the fpga gets bricked until the bitstream is reuploaded, so this part is also generally working.
My thinking is that i have to send an instruction which is not used by the hardware, then read this instruction from the virtual instance and then attach the corresponding shift register to tdo.
Is this assumption correct?

JTAG_states.png