element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
FPGA
  • Technologies
  • More
FPGA
Blog VIDOR 4000: Servo Interface
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join FPGA to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: jc2048
  • Date Created: 29 Jul 2021 9:16 PM Date Created
  • Views 4766 views
  • Likes 13 likes
  • Comments 20 comments
  • intel
  • cyclone 10
  • vidor 4000
  • fpga
  • servo
  • jc2048
  • logic design
  • arduino
Related
Recommended

VIDOR 4000: Servo Interface

jc2048
jc2048
29 Jul 2021

Introduction

 

Now a little project: a servo interface. This will give me a chance to experiment with some very simple communication between the microcontroller and the FPGA on my VIDOR 4000 board.

 

image

 

I'm going to have 8 servo channels, which the FPGA will drive out on the D0 to D7 pins of the header, and the control will be via a simple, write-only SPI interface on the SCK and MOSI pins from the SAM processor [with A0 used as the SS chip select].

 

I'm sure, if I looked around, I could find an existing design, but I thought it would make for a more interesting blog if I did one for myself, from the ground up.

 

The Design

 

I don't know much at all about model servos, so I had to look at a few datasheets, the Wikipedia page [1], and a couple of websites to find out what the waveform I'm going to generate should be like.

 

It's a repetitive waveform, where the timing of the falling edge after the positive edge determines the servo angle. Like this:

 

image

 

Traditionally, the repetition rate was 50Hz (20ms period). I'll stick to that for this blog, though it wouldn't be too difficult to change it or even make it programmable.

 

Here's the waveform again as I drew it, annotated with the various counter values in a way that's probably totally confusing, but might begin to make some sense if you read the explanation below.

 

image

 

The neutral position (for the hobby servos I'm using, that will be the centre position, which I'll call 0 degrees) occurs when the falling edge is 1500us after the rising edge.

 

I had to make a decision as to the resolution I was going to work to. Since the total travel is 120 degrees, working with 8-bit data looked reasonable as a start. That gives half a degree per bit, which I believe is about the size of the deadband with cheap servos. Being a flexible design in an FPGA, I could always increase the resolution later if I didn't like the result.

 

Since -60 degrees is at 1000us and +60 degrees is at 2000u, we can quickly work out that this is 8.3333us per degree. For half degree resolution, I need half that, ie 4.1666us. I can obtain that by dividing the 48MHz FPGA clock by 200, so I'm going to have an 8-bit prescaler to generate an enable signal every 200 clocks for the servo stuff to run on.

 

So how about the other end? The processor interface.

 

I've already mentioned that it's going to be SPI. That's because it's very simple to implement (it's even simpler with a cut-down, receive-only design like this), and there's also support for it on the SAM side of things, so it's very easy to use in the processor sketch. SPI data is bit-serial, so to receive it we'll need a shift register. In hardware terms, this is little more than a serial-data-in, parallel-data-out shift register.

 

I have a choice as to how fast I make the SPI clock when I set it up with the Arduino library. Quite arbitrarily, I'm going to set it to 1MHz. [The default on the VIDOR board seems to be 4MHz, as I discovered when I misunderstood that the SPI.beginTransaction function has to come after the SPI.begin, and not before.] That's quite fast enough for what I want to do here, but is slow enough that I won't have any problems at all with dealing with it on the FPGA. Although you might think I'd use something labelled 'clock' as a clock input to the FPGA, I'm not going to. Instead I'm going to treat it as data that I'll sample to find the positive-going edge that marks the time to pick up the data.

 

SPI is sent as a byte or multiples of a byte. I'm going to choose 2-bytes for each transaction, so my shift register will need to be 16 bits. The first byte will be the address for a channel, the next the data.

 

After the SPI interface, I need some holding registers to store the data for each channel. As well as the holding registers, I'm also going to have a working register for each channel. The transfer will occur at the start of the cycle, well out of the way of the comparisons that determine the falling edges.

 

Those stored values then get compared to a counter for generating the output waveforms. Although I could design the output stage and duplicate it eight times, with a counter for each channel, a little thought shows that the counter does exactly the same thing in each case and can be shared between all eight.

 

Putting all of that together then gives me something like this as a block diagram:

 

image

 

The VHDL

 

Here's the VHDL I ended up with. It's reasonably well commented, so you should be able to follow it and what it's doing. If anything doesn't make sense, ask in the comments.

 

---------------------------------------------------------------
--- Filename: servo.vhd                                     ---
--- Target device: 16CL016YU256C8G                          ---
---                                                         ---
--- 8-Channel Servo driver with output at 100Hz             ---
---                                                         ---
--- Interfaces to microcontroller with SPI [write only]     ---
--- 16-bit data, msb first, and mode (0,0) for the clock    ---
---                                                         ---
--- msb                                     lsb             ---
--- x x x x x A2 A1 A0  D7 D6 D5 D4 D3 D2 D1 D0             ---
---                                                         ---
--- where A is the channel address                          ---
--- D is two's complement setting in half degree increments ---
---                                                         ---
--- Jon Clift 18th July 2021                                ---
---                                                         ---
---------------------------------------------------------------
--- Rev    Date         Comments                            ---
--- 1.0    18-Jul-21                                        ---
---------------------------------------------------------------


library IEEE;
use IEEE.std_logic_1164.all;  
---use IEEE.numeric_std.all;  
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;


entity servo_top is port(


   --- system signals
   CLKi:             in std_logic;
   RESn:             in std_logic;
  
   --- MKR PINS
   MKR_D:            out std_logic_vector(7 downto 0);
MOSI:             in std_logic;
SCK:              in std_logic;
SS:               in std_logic;

   --- SDRAM
   SDRAM_CK:         out std_logic;
   SDRAM_CSn:        out std_logic;
   SDRAM_CKE:        out std_logic;
  
   --- NINA module
   WM10_RESn:        out std_logic

   );


end servo_top;


architecture arch_servo_top of servo_top is


signal prescaler: std_logic_vector(7 downto 0);
signal servo_en, servo_transfer_en: std_logic;
signal servo_counter: std_logic_vector(12 downto 0);
signal spi_clk_del1, spi_clk_del2, spi_en: std_logic;
signal spi_ss_del1, spi_ss_del2, spi_ss_end: std_logic;
signal spi_data_del1, spi_data_del2: std_logic;
signal spi_shift_register: std_logic_vector(15 downto 0);
signal servo_hold_0: std_logic_vector(7 downto 0);
signal servo_hold_1: std_logic_vector(7 downto 0);
signal servo_hold_2: std_logic_vector(7 downto 0);
signal servo_hold_3: std_logic_vector(7 downto 0);
signal servo_hold_4: std_logic_vector(7 downto 0);
signal servo_hold_5: std_logic_vector(7 downto 0);
signal servo_hold_6: std_logic_vector(7 downto 0);
signal servo_hold_7: std_logic_vector(7 downto 0);
signal servo_data_0: std_logic_vector(7 downto 0);
signal servo_data_1: std_logic_vector(7 downto 0);
signal servo_data_2: std_logic_vector(7 downto 0);
signal servo_data_3: std_logic_vector(7 downto 0);
signal servo_data_4: std_logic_vector(7 downto 0);
signal servo_data_5: std_logic_vector(7 downto 0);
signal servo_data_6: std_logic_vector(7 downto 0);
signal servo_data_7: std_logic_vector(7 downto 0);
signal servo_out: std_logic_vector(7 downto 0);


begin


   --- everything that runs from the 48MHz clock input on CLKi


    clocked_stuff: process (CLKi)
        begin
            if (CLKi'event and CLKi = '1') then

                --- prescaler down to 4.16666us period (divide by 200)
          
                if (prescaler(7 downto 0) = "00000000") then --- if reached 0
                    prescaler(7 downto 0) <= "11000111"; ---   preset to 199
                    servo_en <= '1'; ---   and set enable for one cycle
                else --- else count down
                    prescaler <= prescaler - 1;
                    servo_en <= '0'; ---   keeping enable low rest of time
                end if;


--- the servo counter counts every 4.16666us (equivalent to half a degree on the servo)
--- period is 4800 counts: 4.16666us x 4800 = 20ms (100Hz)

                if (servo_en = '1') then
  if (servo_counter(12 downto 0) = "1000111010111") then --- if reached 4567
servo_counter(12 downto 0) <= "1111100011000"; --- preset (skip ahead) to 7960 (-232)
servo_out(7 downto 0) <= "11111111"; --- and set all the servo outputs high
                     servo_transfer_en <= '1'; ---   
else --- else
servo_counter <= servo_counter + 1; --- count down
                     servo_transfer_en <= '0'; ---   
end if;
end if;


--- the SPI interface

spi_clk_del1 <= SCK;
spi_clk_del2 <= spi_clk_del1;

spi_ss_del1 <= SS;
spi_ss_del2 <= spi_ss_del1;

spi_data_del1 <= MOSI;
spi_data_del2 <= spi_data_del1;


if((spi_clk_del1 = '1') and (spi_clk_del2 = '0')) then
spi_en <= '1';
else
spi_en <= '0';
end if;


if((spi_ss_del1 = '1') and (spi_ss_del2 = '0')) then
spi_ss_end <= '1';
else
spi_ss_end <= '0';
end if;


if((spi_en = '1') and (spi_ss_del2 = '0')) then

spi_shift_register(15 downto 1) <= spi_shift_register(14 downto 0);
spi_shift_register(0) <= spi_data_del2;

end if;


--- at end of ss (SPI 'chip select' going high at end of transfer)
--- transfer data from spi shift register to the addressed 
--- servo data holding register
--- bit 7 is negated to convert 2's complement back to binary

if(spi_ss_end = '1') then

case (spi_shift_register(10 downto 8)) is
when "000" =>
servo_hold_0(6 downto 0) <= spi_shift_register(6 downto 0);
servo_hold_0(7) <= not spi_shift_register(7);
when "001" =>
servo_hold_1(6 downto 0) <= spi_shift_register(6 downto 0);
servo_hold_1(7) <= not spi_shift_register(7);
when "010" =>
servo_hold_2(6 downto 0) <= spi_shift_register(6 downto 0);
servo_hold_2(7) <= not spi_shift_register(7);
when "011" =>
servo_hold_3(6 downto 0) <= spi_shift_register(6 downto 0);
servo_hold_3(7) <= not spi_shift_register(7);
when "100" =>
servo_hold_4(6 downto 0) <= spi_shift_register(6 downto 0);
servo_hold_4(7) <= not spi_shift_register(7);
when "101" =>
servo_hold_5(6 downto 0) <= spi_shift_register(6 downto 0);
servo_hold_5(7) <= not spi_shift_register(7);
when "110" =>
servo_hold_6(6 downto 0) <= spi_shift_register(6 downto 0);
servo_hold_6(7) <= not spi_shift_register(7);
when "111" =>
servo_hold_7(6 downto 0) <= spi_shift_register(6 downto 0);
servo_hold_7(7) <= not spi_shift_register(7);
when others =>
end case;

end if;


--- update the data registers from the holding registers
--- do this at start of period, well before they get used

if(servo_transfer_en = '1') then

servo_data_0 <= servo_hold_0;
servo_data_1 <= servo_hold_1;
servo_data_2 <= servo_hold_2;
servo_data_3 <= servo_hold_3;
servo_data_4 <= servo_hold_4;
servo_data_5 <= servo_hold_5;
servo_data_6 <= servo_hold_6;
servo_data_7 <= servo_hold_7;
end if;

  --- set each servo output low at the appropriate time
--- (they were all set high at the same instant: see servo counter above)

                if ((servo_en = '1') and (servo_counter(10 downto 8) = "000")) then

if (servo_counter(7 downto 0) = servo_data_0(7 downto 0)) then --- if same
servo_out(0) <= '0'; --- set output low
end if;


if (servo_counter(7 downto 0) = servo_data_1(7 downto 0)) then
servo_out(1) <= '0';
end if;


if (servo_counter(7 downto 0) = servo_data_2(7 downto 0)) then
servo_out(2) <= '0';
end if;


if (servo_counter(7 downto 0) = servo_data_3(7 downto 0)) then
servo_out(3) <= '0';
end if;


if (servo_counter(7 downto 0) = servo_data_4(7 downto 0)) then
servo_out(4) <= '0';
end if;


if (servo_counter(7 downto 0) = servo_data_5(7 downto 0)) then
servo_out(5) <= '0';
end if;


if (servo_counter(7 downto 0) = servo_data_6(7 downto 0)) then
servo_out(6) <= '0';
end if;


if (servo_counter(7 downto 0) = servo_data_7(7 downto 0)) then
servo_out(7) <= '0';
end if;


end if;
         
end if;
              
end process clocked_stuff;


--- connect servo outs to the MKR pins

MKR_D <= servo_out;

--- hold some of the unused, board hardware components in inactive state
         
SDRAM_CK <= CLKI;
SDRAM_CSn <= '1';
SDRAM_CKE <= '1';
         
WM10_RESn <= '0';




end arch_servo_top;

 

(Sorry about the strange formatting. The original was fine. If I have the energy tomorrow, I'll try editing it.)

 

I haven't put a licence on this (I'm still unsure what the best way to licence something like this is). Effectively, you can do what you like with it, but there's no warranty, no claim of fitness for purpose, nor any obligation on me to support it in any way whatsoever.

 

The Sketch

 

For the sketch, I modified the template provided here [thank you, C Helmich]:

 

https://github.com/chelmich/vidor_template/tree/master/arduino/vidor_template

 

just adding in the SPI stuff for testing the interface from the processor to the FPGA.

 

Here's how the sketch part looked after I'd finished:

 

#include <wiring_private.h>
#include <SPI.h>
#include "jtag.h"
#include "defines.h"


__attribute__ ((used, section(".fpga_bitstream_signature")))
const unsigned char signatures[4096] = {
    #include "signature.h"
};


__attribute__ ((used, section(".fpga_bitstream")))
const unsigned char bitstream[] = {
    #include "app.h"
};


void FPGA_init (){
    // enable fpga clock
    pinPeripheral(30, PIO_AC_CLK);
    clockout(0, 1);


    // wait for clock to come up (unnecessary?)
    delay(1000);


    // send bitstream over jtag
    uint32_t ptr[1] = {3};
    jtagInit();
    mbPinSet();
    mbEveSend(ptr, 1);
    jtagDeinit();
}


void setup (){
    FPGA_init();


    delay(1000);


    // turn on built in LED
    pinMode(LED_BUILTIN, OUTPUT);


    // set A0 as output - this is SS (device select) for SPI
    pinMode(A0, OUTPUT);
    // start SPI
    SPI.begin();
}


void loop (){


unsigned char servoChannel;
signed char servoData[] = {-128,-120,-60,0,60,90,120,127};


SPI.beginTransaction(SPISettings(1000000,MSBFIRST,SPI_MODE0));


while(1){
  for(servoChannel=0;servoChannel<8;servoChannel++) {
    digitalWrite(A0, LOW);                  // SS low 
//    delayMicroseconds(2);
    SPI.transfer(servoChannel);             // send channel
    SPI.transfer(servoData[servoChannel]);  // send channel data
//    delayMicroseconds(2);
    digitalWrite(A0, HIGH);                 // SS high
//    servoData[servoChannel] = (signed char) random(256);  // pick new random value for next time through
    servoData[servoChannel]++;  // 
    delayMicroseconds(10);
    }
  delay(100);
  }
  
SPI.end();
}

 

 

My app.h came from my own VHDL design, and the jtag.c and jtag.h files were the same as the template.

[There's no mention of a licence, so I presume it's a generous 'do what you like with this' piece of code.]

 

The Servo Interface Working

 

Here are some oscilloscope traces from the working design. This is with the initialisation values from my code.

 

signed char servoData[] = {-128,-120,-60,0,60,90,120,127};

 

 

image

 

This first one shows the complete cycle. The logic-analyser section shows the MKR D0 to D7 outputs from the VIDOR headers. The one marked '0' is D0, and so on. The yellow, analogue trace is a duplicate of D0.

 

We can see the various pulse widths as they should be. This also shows that I've got the output frequency correct at 50Hz (give or take a little variation because of the jitter on the FPGA's clock).

 

Here it is again, in a bit more detail on a faster timebase:

 

image

 

The cursors I've placed at the 1000us and 2000us positions, which line up with values of -120 and +120 sent from the microcontroller [effectively, -60 and +60 degrees, the limits of my servos].

 

With this next one, I have the data for each of the channels incrementing 10 times a second. With the phosphor set to infinity, the analogue trace then shows all the possible positions for the falling edge [the analyser section doesn't persist in the same way as the analogue trace, so you only see the most recent trace there].

 

image

 

Finally, here's a quick look at the SPI. Trace '0' is the clock, '1' is the data, and '2' is the SS signal.

 

image

 

Conclusions

 

That didn't go too badly, and I've got the beginnings of a working design. It uses about 1.5% of the logic blocks of the FPGA, so there's plenty left for extending or elaborating the design, or for other uses entirely.

 

Later, I'll try wiring up some servos [if I can find them: I think I might have three, somewhere or other] and then I'll see if it works for real.

 

References

 

[1] https://en.wikipedia.org/wiki/Servo_(radio_control)

[2] VIDOR 4000: Johnson Counter

[3] VIDOR 4000: Clock Jitter

 

If you found this interesting and would like to see other blogs I've written, a list can be found here: jc2048 Blog Index

  • Sign in to reply

Top Comments

  • michaelkellett
    michaelkellett over 3 years ago +4
    Thanks for the blog. I'll offer a couple of suggestions re. the VHDL which I hope may be useful to you and others. LIBRARIES In your VHDL you have: library IEEE; use IEEE.std_logic_1164.all; ---use IEEE…
  • michaelkellett
    michaelkellett over 3 years ago in reply to jc2048 +4
    I have some nice little Chinese (cheap £16) boards with Cyclone 10LP and an SDRAM. I have some more on the way with a Xilinx Artix 35 and a DDRAM. I was looking for somehting interesting to do with them…
  • Jan Cumps
    Jan Cumps over 3 years ago +4
    The design works. Tested with an Sparkfun micro servo. www.youtube.com/watch I think that servo is the same as the blue ones you use, just older black housing.
  • Jan Cumps
    Jan Cumps over 3 years ago in reply to jc2048

    jc2048  wrote:

    ...

    But as shabaz  predicted, the timing is out. The last step is missing and the one prior to that is a short one, so the limit at that end of the travel is a good bit lower than the 'standard' 2000us I was working to.

    I have the same experience. Sparkfun says that they aren't actually 180° capable.

    Note: This servo is rated for 180° rotation, but in actuality it only hits ~160°.

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • jc2048
    jc2048 over 3 years ago

    Mine works with a servo, too. This is 15 degree steps from -60 to +60, and then go back and start again.

     

    You don't have permission to edit metadata of this video.
    Edit media
    x
    image
    Upload Preview
    image

     

     

    But as shabaz predicted, the timing is out. The last step is missing and the one prior to that is a short one, so the limit at that end of the travel is a good bit lower than the 'standard' 2000us I was working to.

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 3 years ago

    The design works.  Tested with an Sparkfun micro servo.

    You don't have permission to edit metadata of this video.
    Edit media
    x
    image
    Upload Preview
    image

     

    I think that servo is the same as the blue ones you use, just older black housing.

    • Cancel
    • Vote Up +4 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • michaelkellett
    michaelkellett over 3 years ago in reply to jc2048

    I have some nice little Chinese (cheap £16) boards with Cyclone 10LP and an SDRAM.

    I have some more on the way with a Xilinx Artix 35 and a DDRAM.

     

    I was looking for somehting interesting to do with them and your comment triggers a possibility.

     

    Both XIlinx and Altera/Intel tools can infer block ram.

    So it should be possible to write 'bog standard' VHDL which compiles on either and still uses block ram.

     

    (I almost always use the vendors IP blobs for block ram stuff - not portable but moving to different chips has never been a priority for my work.)

     

    I found this article:

    https://danstrother.com/2010/09/11/inferring-rams-in-fpgas/

     

    It's fairly old and some of the problems it mentions may be fixed by now.

     

    A rather old Altera document  suggests this:

    LIBRARY ieee;
    USE ieee.std_logic_1164.all;
    ENTITY single_clock_ram IS
    PORT (
    clock: IN STD_LOGIC;
    data: IN STD_LOGIC_VECTOR (2 DOWNTO 0);
    write_address: IN INTEGER RANGE 0 to 31;
    read_address: IN INTEGER RANGE 0 to 31;
    we: IN STD_LOGIC;
    q: OUT STD_LOGIC_VECTOR (2 DOWNTO 0)
    );
    END single_clock_ram;
    ARCHITECTURE rtl OF single_clock_ram IS
    TYPE MEM IS ARRAY(0 TO 31) OF STD_LOGIC_VECTOR(2 DOWNTO 0);
    SIGNAL ram_block: MEM;
    BEGIN
    PROCESS (clock)
    BEGIN
    IF (clock'event AND clock = '1') THEN
    IF (we = '1') THEN
    ram_block(write_address) <= data;
    END IF;
    q <= ram_block(read_address);
    -- VHDL semantics imply that q doesn't get data
    -- in this clock cycle
    END IF;
    END PROCESS;
    END rtl;

     

    (Time E14 added VHDL formatting to the options image)

    November 2013 Altera Corporation Quartus II Handbook Version 13.1

    Volume 1: Design and Synthesis

     

    Xilinx offer this:

    --
    -- Write-First Mode (template 1)
    --
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_unsigned.all;
    entity rams_02a is
    port (clk : in std_logic;
    we : in std_logic;
    en : in std_logic;
    addr : in std_logic_vector(5 downto 0);
    di : in std_logic_vector(15 downto 0);
    do : out std_logic_vector(15 downto 0));
    end rams_02a;
    architecture syn of rams_02a is
    type ram_type is array (63 downto 0)
    of std_logic_vector (15 downto 0);
    signal RAM : ram_type;
    begin
    process (clk)
    begin
    if clk'event and clk = '1' then
    if en = '1' then
    if we = '1' then
    RAM(conv_integer(addr)) <= di;
    do <= di;
    else
    do <= RAM( conv_integer(addr));
    end if;
    end if;
    end if;
    end process;
    end syn;

     

    XST User Guide 10.1

     

    So far I haven't found really up to date stuff from X or IA - but I'll go on looking.

     

    The code looks very similar - should work OK.

     

    I'll have a go at implmenting something on my Cyclone board and start a new blog about it.

     

     

    MK

    • Cancel
    • Vote Up +4 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • jc2048
    jc2048 over 3 years ago in reply to Jan Cumps

    Thanks for doing that. Good to see it works, but that's more down to Xilinx than to me. (Hooray for Xilinx!) This is 'bog standard' VHDL and should port to practically anything. It's when you start using vendor-specific hardware rather than just the fairly generic logic fabric that it gets messy (you wouldn't have found porting it so easy if I'd followed Michael's suggestion of using a block memory as a register file). I might try it with my Max CPLD board and an UNO if I get time.

     

    Can't help with the Python. My solution would be to look for a C compiler.

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube