Skip navigation

FPGA Group

5 Posts authored by: Jan Cumps Top Member
Jan Cumps

XuLA2 FPGA - Up the Clock

Posted by Jan Cumps Top Member Feb 4, 2017

The XuLA2 standard runs on a 12 MHz clock. That's plenty for many things, but not enough for some designs.

In my PWM with DeadBand  project, for instance, the effective signal frequency that the module outputs is halved for each bit of precision of the duty cycle register.

If you want to have 256 steps between 0 and 100% duty cycle, you need 8-bit precision and your maximum PWM output frequency is 47 kHz. When you need higher PWM frequency with the same duty cycle granularity, you can use a Digital Clock Manager to generate a (much!) faster clock signal for the PWM module.


I need a minimum 1 MHz output for the GaN half-bridge that I'm driving (an LMG5200). The deadband should be a in the range of 8 - 10 ns.

Let's assume that we allow for 2 ns steps (we can then set a deadband of 10 ns by skipping 5 ticks.

2ns means that our input frequency has to be 500 MHz. We can't do that - its beyond the capabilities of the Digital Clock Manager of the Spartan-6.

4ns is doable but a stretch. It'll require an up-sample to 250 MHz.

 

Only 12 MHz! Now what

That's the title of the Xess VHDL Tutorial chapter that covers this concept. Look there for the explanation.

I'll focus on a practical application.

 

 

library UNISIM;
use UNISIM.VComponents.all;
-- ...
architecture Behavioral of Rotary_Pwm is
-- ...
  signal clk_fast     : std_logic;
begin

   DCM_SP_inst : DCM_SP
   generic map (
      CLKFX_DIVIDE => 1,                     -- Divide value on CLKFX outputs - D - (1-32)
      CLKFX_MULTIPLY => 22                    -- Multiply value on CLKFX outputs - M - (2-32)
   )
   port map (
      CLKFX => clk_fast,    -- 1-bit output: Digital Frequency Synthesizer output (DFS)
      CLKIN => clk_i,       -- 1-bit input: Clock input
      RST => '0'            -- 1-bit input: Active high reset input
   );

  u0 : PwmDeadBand
    port map (
      clk_i => clk_fast,
  duty_i => accumulator_s,
  band_i => 64,
      pwmA_o => pwmA_o,
      pwmB_o => pwmB_o
      );
-- ...

 

 

The DCM_SP_inst is an instance of the Spartan-specific DCM_SP primitive. It's not a standard VHDL construct.

At this point, our design becomes device dependent. You can't just port it to another FPGA.

 

I've used the following design decisions:

To get the 4ns step rate the minimum frequency is 1/4ns = 250 MHz.

Our output frequency is going to be that frequency divided by 256, so we're just under our   MHz output goal.

We'll have to up it to at least 256 MHz.

With a 12 MHz clock as input, we'll need to multiply that clock with 22 and get 264 MHz.

Each step will have a period of 3.8 ns - close enough to the 4 ns we're aiming for.

 

We only have to pass that fast clock to the PWM module.

There's no reason to route it to the rotary encoder, it can keep running on the 12 MHz clacker.

 

 

photo: Bart Simpson looks over a wall

 

In the capture above, I've set a deadband of 64 clock ticks (to have something measurable on the scope).

The signal frequency is 1.03127 MHz (theoretical 12 MHz * 22 / 256 = 1.031250 MHz)

The time between the cursors is 244 ns for 64 dead band ticks. So the measured granularity of our deadband is 244ns / 64 = 3.8125 ns.

 

Here's a capture with 8 clock ticks.

 

My GaN board will run with 2 or 3 ticks - I'd have to use different probe technique to show that.

Good captures in the neighbourhood of 8 ns (that's the deadband that I'll try to achieve) are hard on a 50 MHz scope

 

 

XuLA2 FPGA - First Impressions of the Development Tools
XuLA2 FPGA - SD Card Read and Write
XuLA2 FPGA - Rotary Encoder and VHDL
XuLA2 FPGA - PWM with Dead Band in VHDL
XuLA2 FPGA - Up the Clock

A PWM module for FPGAs that supports dead band.

xessdeadband.gif

A VHDL project that generates two opposite PWM signals with a dead band. You can change the duty cycle with a rotary encoder.


When you drive half-bridge designs, you need a control signal for both transistors in the circuit.

These signals need to be each other's opposite, because you close one transistor when you drive the other.

At the switching time, you introduce a tiny bit of dead time, to allow one transistor to properly shut before the other opens.

If you don't allow for this stabilisation period, your transistors will get hot and the magic smoke will eventually (sooner rather than later) escape.

 

I've made a VHDL module that generates these complementary signals, including a configurable deadband.

You decide in your design what the frequency and deadband is.

You can then freely change the duty cycle. The FPGA takes care that the dead time is guaranteed.

 

PWM VHDL module

 

My design is 100% based on the Xess XuLA2 PWM library. I've added the complementary signal and introduced that delay for rising edges of both outputs.

 

entity PwmDeadBand is
  port (
    clk_i  : in  std_logic;             -- Input clock.
    duty_i : in  std_logic_vector;      -- Duty-cycle input.
    band_i : in  natural;               -- number of clock-ticks to keep both signals low before rising edge
    pwmA_o  : out std_logic;            -- PWM output.
    pwmB_o  : out std_logic             -- PWM output inverse.
    );
end entity;

 

duty_i is a register that holds the desired duty cycle. It's configurable - I've set it to 8 bits.

 

Your clock speed is dependent on the size of this register.

The clock that you present on the clk_i input of the module will be divided by 2^(number of bits). In this case, 2^8 -> 256.

For the standard 12 MHz clock of the XuLA2, the PWM module will beat at 47 kHz.

There are ways to increase the clock frequency in the FPGA and the XuLA2 libs have support for that.

 

The dead band, in clock ticks, is passed via the band_i pin. The two complementary signals appear on pwmA_o and pwmB_o.

In the constraint file of your project, you assign that to physical Spartan-6 pins:

 

# PM1 connections for the pwm outputs
net pwmA_o      loc=m16;
net pwmB_o      loc=k16;

 

If you use a StickIt! motherboard, you get the signals at PM1, pin D4 and D6.

If you tap them from the XuLA2 directly, they are chan4 and chan6 on the expansion header.

 

The implementation is just an extension of what the original Xess library does.

We introduce an additional channel that's HI when the other is LO,, and vice versa.

And we hold off driving any of these channels high until we've waited duty_i clock ticks.

 

architecture arch of PwmDeadBand is
  constant MAX_DUTY_C : std_logic_vector(duty_i'range) := (duty_i'range => ONE);
  signal timer_r      : natural range 0 to 2**duty_i'length-1;

begin

  process(clk_i)
  begin
    if rising_edge(clk_i) then
    
      pwmA_o   <= LO;

      timer_r <= timer_r + 1;
      if timer_r >= band_i + TO_INTEGER(unsigned(duty_i)) then
  pwmB_o <= HI;
  end if;

      if timer_r < TO_INTEGER(unsigned(duty_i)) then
        pwmB_o <= LO;
        if timer_r >= band_i  then
  pwmA_o <= HI;
   end if;
      end if;
    end if;
  end process;
  
end architecture;

 

That's really all for the PWM module.

 

Rotary Encoder module

 

This section is very short: read the previous blog post.

 

Patching it together

 

Also easy. We just have to wire the register that holds the value of the Rotary Encoder to the one that's driving the PWM module.

I just use the same register. That's the simplest way to do this.

 

 

entity Rotary_Pwm is
    Port ( clk_i : in  STD_LOGIC;
           rotEncA_i   : in  std_logic;        -- Rotary encoder phase 1 output.
           rotEncB_i   : in  std_logic;        -- Rotary encoder phase 2 output.
           pwmA_o      : out  STD_LOGIC;
           pwmB_o      : out  STD_LOGIC  
   );
end Rotary_Pwm;

architecture Behavioral of Rotary_Pwm is

  signal accumulator_s : std_logic_vector(7 downto 0) := "01111111"; -- 50%

begin

  u0 : PwmDeadBand
    port map (
      clk_i => clk_i,
  duty_i => accumulator_s,
  band_i => 16,
      pwmA_o => pwmA_o,
      pwmB_o => pwmB_o
      );

  u1 : RotaryEncoderWithCounter
    generic map (ALLOW_ROLLOVER_G => true, INITIAL_CNT_G => 127)
    port map (
      clk_i => clk_i,
      a_i   => rotEncA_i,
      b_i   => rotEncB_i,
      cnt_o => accumulator_s
      );

end Behavioral;

 

So the handover point is the 8-bit register accumulator_s. When you turn the encoder, it changes the value of the register to reflect your action.

In real-time, the duty cycle of the PWM module adapts. There's not a single clock tick between event and action.

 

Connections

 

I've used PM1 on the StickIt! motherboard, and used these pins:

 

 

PM1 pin
XuLA2 pin
Spartan-6 pinpin namedirectionfunction
6 - +3V3+3.3V+3.3Voutpull-up power for encoder
5 - GNDGNDGNDoutground for PWM and Rotary Encoder
4 - D6CHAN6K16pwmB_ooutPWM complementary signal B
3 - D4CHAN4M16pwmA_ooutPWM complementary signal A
2 - D2CHAN2R16rotEncB_iinRotary Encoder pin B
1 - D0CHAN0R7rotEncA_iinRotary Encoder pin A

 

If you want to wire the encoder inputs or pwm outputs to other pins, you only have to change the constraint file.

 

 

deadband.png

 

The project is attached, together with the PWM library.

I'm going to use this to drive my GaN experiment board. You?

 

 

XuLA2 FPGA - First Impressions of the Development Tools
XuLA2 FPGA - SD Card Read and Write
XuLA2 FPGA - Rotary Encoder and VHDL
XuLA2 FPGA - PWM with Dead Band in VHDL
XuLA2 FPGA - Up the Clock

How to use a rotary encoder with the XuLA2 and the Spartan-6 FPGA.

Another real world example: I'm checking if the Xess Rotary Encoder library works with the encoder I use in a GaN half-bridge design.

TL;DR: yes it works


Xess has a plug-in board with a rotary encoder. I'm not using that module (called a StickIt!) - but I'm using the sample project that comes with it.

 

StickIt!

 

Hat Shield Cape Wing. All names were taken except the coolest one.

StickIt!s are tiny modules that work togethet with the XuLa.

A XuLA board is small. Still it manages to expose loads of FPGA pins. Plug the XuLA in a breadboard and you have access to them.

Alternatively,  you can go StickIt!.

 

To start using the StickIt! modules, there's a motherboard. You dock the XuLA onto it and the signals become available in a few ways:

  • as a Raspberry Pi Hat (it can be used as a Hat or you can plug hats onto it. Your call).
  • as StickIt! ports where you can you can plug StickIt! modules into. The motherboard can host three modules.

 

In this blog I'm attaching the rotary encoder contacts to StickIt! port PM1. I just use patch cables to make the connections between my GaN PCB and that connector.

If you don't have the motherboard, you can make the connections directly to the XuLA2. I've pasted the xref tables you need to find out the correct pins.

 

This is the schematic of my rotary encoder. It's identical to the Xess module - except that I've added debounce capacitors.

 

 

 

The encoder is a Panasonic EVQ-VVD00203B Square SMD Encoder.

That's not the same model as the one on the Xess board but it works the same. This one doesn't have a push-button built in.

 

 

I'm plugging it into the PM1 of the motherboard. The power comes from the XuLA board, so you have to populate the XuLA PWR jumper and remove all others.

On this image you can see where you have to insert the jumper wires coming from the encoder.

Pin 6, VCC, goes to the 3V3 of the encoder circuit.

Pin 5, GND, to the circuit's GND

Pin 1, DO, to one of the encoder's switch contacts

Pin 2, D2, to the other switch contact.

The table also shows the channel numbers. Use these if you work without the motherboard. They represent the XuLA2 pins.

 

 

 

In this table you can find the mapping between the channel number and the FPGA signal.

You'll use that to define the pins in your project's constraint file.

For the pins that I've used, this is the constraint info.

 

# PM1 connections for rotary encoder module.
net rotEncA_i   loc=r7;
net rotEncB_i   loc=r16;

 

Update your project's .ucf file to reflect that.

 

 

I haven't changed a single line of code. I just went trough the typical FPGA build steps and generated the bitfile.

 

> xsload --fpga rotaryencodertest.bit
Success: Bitstream in rotaryencodertest.bit downloaded to FPGA on XuLA2-LX25!

 

Then I used the Python test script that's part of the project. It checks the (defined in the VHDL project)  register that holds the accumulated value, and prints it to the command line.

To start the test, execute this command:

 

> rot_enc_test.py

 

Rotate the encoder like a madman and see the results on your command prompt:

 

If you don't have a rotary encoder, break open an old mouse. The scroll wheel is often an encoder.

 

 

XuLA2 FPGA - First Impressions of the Development Tools
XuLA2 FPGA - SD Card Read and Write
XuLA2 FPGA - Rotary Encoder and VHDL
XuLA2 FPGA - PWM with Dead Band in VHDL
XuLA2 FPGA - Up the Clock

Let's try to do something real with the Xilinx Spartan-6 FPGA: write a set of data to an SD card.

 

To boost the FPGA skills, I'm refreshing theory and checking out some real designs.

For a standalone XuLA2 board, talking to SD cards is a good practical example.

 

There's  a Micro SD slot on the XuLA2 models. The only other component you need is a spare Micro SD card.

 

Don't use an SD card with your marriage photo shoot on it. You'll very likely loose that when you test this project.

 

The Xess XuLA2 github has two SD card projects. We'll use the SD Card Control Test example.

In this project, the FPGA has two main duties:

  • Read and Write SD data
  • Communicate with your PC over USB

A python script on your PC will generate test data and send it to the FPGA over USB.

The FPGA writes the data to your SD card. We're using low level protocol here, no filesystem.

When finished, it reads the data back off the SD card and verifies the results.

 

VHDL Libraries

 

Xess made a set of common VHDL libraries. The example uses several those libs.

The communication with the SD slot is via :

  • SDCard.vhd

Clocking is handled by these two:

  • ClkGen.vhd
  • SyncToClk.vhd

Talk to the PC over USB happens with this one (and the on-board PIC microcontroller):

  • HostIo.vhd

These libs are not only useful, but also a great source to learn reusable VHDL.

 

 

How it Works

 

The XESS blog explains the example in detail. It explains both the electrical connections and how the Micro SD protocol is handled.

The header comments of the SdCard.vhd source file document many implementation details.

Open that file by double-clicking the u3 - SdCardCtrl node in the Implementation view.

If you've ever tried to understand (or port) a microcontroller SDCard lib - maybe the one from Arduino - you'll recognise much of the logic.

 

Let's now synthesize the project and generate the programming file.

Insert the SD card, connect the XuLA2 with your laptop and load the bitstream:

 

xsload --fpga sdcardctrltest.bit

 

Once you've loaded the bitstream, your XuLA2 board sits idle. You need to tell it to read and write data.

There's a python scrip that does exactly that.

If you have retrieved the latest XuLA2 FPGA sources from GIT, you'll find a python file named SDcardTest.py in the project directory.

If you're using the examples that were installed by the XESS installer, you can retrieve the testbed from here:

https://raw.githubusercontent.com/xesscorp/XuLA2/master/FPGA/SdcardCtrlTest/SdcardTest.py

 

Run the script to write a random set of data to the SD card, read it back and check if everything is correct:

 

SDcardTest.py

 

 

The data is written using low level protocol. You will not be able to read the data when you insert the SD card into your PC.

The design doesn't use a filesystem or any other advanced disk management protocol. It's SD access for real blokes.

 

Windows 8 and Windows 10 with Xilinx ISE

 

If you are running WIndows 10 64-bit, you may encounter several ISE problems:

 

  • Pressing the Open Project button (and several other actions, like selecting the Preferences menu item) crashes ISE.
  • Running the Simulator results in a "failed to link the design" message and the simulator not starting.

 

Switching to the 32-bit version has solved most of them for me:

To switch,

  • alter the command in the ISE shortcut to
    "<DRIVE>:\Xilinx\14.7\ISE_DS\settings32.bat D:\Xilinx\14.7\ISE_DS\ISE\bin\nt\ise.exe"
  • in "<DRIVE>:\Xilinx\14.7\ISE_DS\ISE\bin\nt", rename fuse.exe to _fuse.exe, and copy the fuse.exe from the "..\nt64" directory over (got that from here)

 

After that, I still have one issue left: when in Simulator, the Relaunch functionality doesn't work. I have to close iSIM and restart it from within ISE.

 

I've also tested the design with a known defect card - one that's rejected by any known operating system and can't be formatted.

This test was successful. The test flagged that the FPGA wasn't able to write data, as expected:

 

 

The core of the example can be used in your own design as a persistent storage area.

If you want to use it as a data exchange mechanism, you'll have to find a way to read the raw data from the card. That can be done with an Arduino.

Another - advanced - option is to implement a supported file systems (fat32?) in HDL,

Whatever you do, make it a nice design and share your work.

 

 

 

XuLA2 FPGA - First Impressions of the Development Tools
XuLA2 FPGA - SD Card Read and Write
XuLA2 FPGA - Rotary Encoder and VHDL
XuLA2 FPGA - PWM with Dead Band in VHDL
XuLA2 FPGA - Up the Clock

I purchased a Xess XuLA2. It arrived this morning.

This post is the story of my first steps

 

 

I have a little bit of experience with FPGAs. I learned digital electronics in the early-to-mid 80's.
My VHDL skills are beginner level and I've worked with the Xilinx Spartan 6 and development tools.

This is my experience to run a first design on the XuLA2 board

 

I have done training work with the Spartan 6 FPGA before. The Xilinx development environment is running on my laptop and works.

I can focus on getting the Xess tools working.

That's not difficult, but I had some issues with Python dependencies that I'll document here.

 

The USB Driver

Installing the device on a Windows10 laptop was easy. There's the typical 'signed driver' hurdle to jump.

When you plug in the XuLA, it's recognised by the OS, but in the Device Management screen there's a warning next to the device.

The typical Windows " invalid hash signature" warning.

 

The solution is known. You have to restart Windows in a special mode that allows to install unsigned drivers (use your google-fu to find the instructions for your version and language).

Once Windows is restarted in the 'allow unsigned drivers' mode, right-click on the device in the Device Manager and select Update Driver.

Windows will find the driver for you and install it. From then on, all is good.

 

The Loader Tool

The XuLA depends on external tools to synthesize your design into an upload file. I'm using the free Xilinx ISE toolset.

The Xess tools come into play when you want to load your designs to the FPGA.

They have command line and GUI applications. I'm testing the command line Loader tool here.

 

The command line tools are for Python 2.7 - I got synthax errors in the print() and other functions when trying it with 3.x.

The instructions to install the toolkit are here: https://xstools.readthedocs.io/en/python/installation.html.

Install went fine. But I ran into a dependency conflict.

The tools depend on a Python library called pubsub. The installer nicely reports that the minimum required version is pypubsub >= 3.1.2.

(I don't know anything about python - I learned the deep internals of it today while getting all of this working )

The bad thing is that the latest version of that library, 4.x, doesn't work (either with Python 2.7 or with the current Xess tools release - I don't know that).

So I had to force-replace pubsub 4 with pubsub3 (I've logged an issue on github).

 

I used these commands:

 

pip uninstall Pypubsub
pip install -Iv https://pypi.python.org/packages/95/5a/1801be1a63af9250e79b8941a37b88e3ca0d660b880b9862fe9016ae6a3a/PyPubSub-3.3.0.zip

 

Finding all of that out took me a half day - don't ask how I did that unless we're in a pub together and you're paying for the drinks.

Once done, all works.

 

C:\Python27>xstest
Success: XuLA2-LX25 passed diagnostic test!

 

 

Testing the XuLA2

I used the mandatory blinky project. I didn't use an LED though, but an oscilloscope.

 

The XuLA2 examples are available when you install the Xess XSTOOLS.

I've opened Examples/XuLA2/LX25/blinker in the Xilinx ISE, synthesised it and generated the programming file.

You can also make the project yourself by following the instructions in the Xess tutorial, chapter "Starting a Design in WebPACK"

 

Then I used the XSTOOLS Loader to beam it to the XuLA2:

 

xsload --fpga blinker.bit
Success: Bitstream in blinker.bit downloaded to FPGA on XuLA2-LX25!

 

 

With my scope attached to the CLK pin at the right lower corner of the PCB, I got the output:

 

 

The clock and output setting are defined in blinker.ucf:

 

net clk_i     loc=a9;  # 12 MHz input clock.
net blinker_o loc=t7 | IOSTANDARD=LVTTL | DRIVE=24 | SLEW=SLOW ;  # Blinker output to LED.

 

 

 

The downcount from 12 MHz clock to approx. 1Hz blink signal is done in the VHDL design:

 

entity blinker is
    Port ( clk_i : in  STD_LOGIC;
           blinker_o : out  STD_LOGIC);
end blinker;


architecture Behavioral of blinker is
signal cnt_r : std_logic_vector(22 downto 0) := (others=>'0');
begin


process(clk_i) is
begin
  if rising_edge(clk_i) then
    cnt_r <= cnt_r + 1;
  end if;  
end process;


blinker_o <= cnt_r(22);


end Behavioral;

 

(if only e14 had a VHDL syntax highlighter)

 

Summary

It works

 

 

 

XuLA2 FPGA - First Impressions of the Development Tools
XuLA2 FPGA - SD Card Read and Write
XuLA2 FPGA - Rotary Encoder and VHDL
XuLA2 FPGA - PWM with Dead Band in VHDL
XuLA2 FPGA - Up the Clock