element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • 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
Forum Testing a VHDL LCD matrix display driver
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join FPGA to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • Replies 9 replies
  • Subscribers 550 subscribers
  • Views 5386 views
  • Users 0 members are here
  • 44780
  • hitachi
  • zynq
  • xilinx
  • vivado
  • vhdl
Related

Testing a VHDL LCD matrix display driver

Jan Cumps
Jan Cumps over 3 years ago

image

I'm going to try out a VHDL driver for the Hitachi HD44780 LCD driver.
I've ported it for several microcontrollers (TI Hercules, Maxim MAX32660) and a Linux device in the past.
I was going to write a VHDL driver, but found a few potential candidates online. I'm going to try Daniel Kampert's HD44780 LCD-Interface.

Current status:

  • VHDL code analysed
  • Block diagram made:
    image

  • Sign in to reply
  • Cancel

Top Replies

  • Jan Cumps
    Jan Cumps over 3 years ago in reply to Jan Cumps +7
    Success. I'm sending a stream of 'f'. I used f because that's binary '01100110', so if I keep sending '0110' values, it should generate all 'f's. Yay!
  • phoenixcomm
    phoenixcomm over 3 years ago +4
    looks like fun.
  • Jan Cumps
    Jan Cumps over 3 years ago in reply to Jan Cumps +4
    Some good news: it's not working, but it's trying: This is a capture of the startup procedure. If you look at E, you can spot the 3 longer init sequences, then 1 burst to set 4 bit mode, then 2 …
Parents
  • _david_
    _david_ over 3 years ago

    Good luck with the project!  I interfaced a similar lcd recently with lattice semi's MachXO3LF fpga.  It was a little weird because it had a SPI controller, but I ended up using 4-bit mode as well.  It's definitely a challenge getting it working but it's worth it in the end.  I used a C library project for reference which saved a lot of time with register configurations, but I never fleshed out all it's features (just clear display and printing text).  It'll be neat to see what you get working.  Looks like you're planning to control it with the PS which will make it far more useful than mine ever was since mine just read from a ROM file.  Also since you are using 4 data lanes without a SPI controller, it will almost certainly be faster than mine.  Look forward to more updates!

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

    Looks like you're planning to control it with the PS

    The goal is from both. It's pure VHDL so it can be used in the PL directly.
    I have a PYNQ board, so I currently connected it to the PS. It allows me to use data and control pins from Python.

    That said: the week-end is finished and it isn't working yet.
    Current status:
    VHDL ported from 8 to 4 data lines (I commented out 8-bit logic in the source of Daniel below)

    ----------------------------------------------------------------------------------
    -- Company:             https://www.kampis-elektroecke.de
    -- Engineer:            Daniel Kampert
    -- 
    -- Create Date:         24.01.2020 21:51:49
    -- Design Name: 
    -- Module Name:         LCD_Controller - LCD_Controller_Arch
    -- Target Devices: 		XC7Z010CLG400-1
    -- Tool Versions:   	Vivado 2020.1
    -- Description:         LCD interface for the HD44780 LCD-Interface tutorial from
    --                      https://www.kampis-elektroecke.de/fpga/hd44780-lcd-interface/
    -- 
    -- Dependencies: 
    -- 
    -- Revision:
    --  Revision            0.01 - File Created
    --
    -- Additional Comments:
    -- 
    ----------------------------------------------------------------------------------
    
    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    
    -- Uncomment the following library declaration if using
    -- arithmetic functions with Signed or Unsigned values
    --use IEEE.NUMERIC_STD.ALL;
    
    -- Uncomment the following library declaration if instantiating
    -- any Xilinx leaf cells in this code.
    --library UNISIM;
    --use UNISIM.VComponents.all;
    
    entity LCD_Controller is
        Generic (   CONFIG      : INTEGER := 0;                         -- Default configuration index.
                    CLOCK_FREQ  : INTEGER := 125                        -- Input clock frequency in MHz.
                    );
        Port (  Clock   : in STD_LOGIC;
                nReset  : in STD_LOGIC;
    
                -- Communication bus
    --          Data    : in STD_LOGIC_VECTOR(7 downto 0);
                Data    : in STD_LOGIC_VECTOR(3 downto 0);
                Ready   : out STD_LOGIC;                                -- Output to signal that the display controller is ready
                Valid   : in STD_LOGIC;                                 -- Input to signal valid data
    
                SendCommand : in STD_LOGIC;                             -- Handle the next data byte as command (High)
    
                -- LCD bus
                LCD_RS  : out STD_LOGIC;                                -- Command (High) / Data (Low)
                LCD_E   : out STD_LOGIC;                                -- Low-High Transition: Display read RW and RS
                                                                        -- High-Low Transition: Display read data from bus (RW Low)
                                                                        --                      Display put data on the bus (RW High)
                LCD_RW  : out STD_LOGIC;                                -- Read data (High) / Write data (Low)
    --          LCD_Data: inout STD_LOGIC_VECTOR(7 downto 0)            -- LCD data bus
                LCD_Data: inout STD_LOGIC_VECTOR(3 downto 0)            -- LCD data bus
                );
    end LCD_Controller;
    
    architecture LCD_Controller_Arch of LCD_Controller is
    
        type State_t is (Reset, Initialize, Idle, WaitBusy, Transmit);
    --  type Config_t is array(0 to 1, 0 to 5) of STD_LOGIC_VECTOR(7 downto 0);
        type Config_t is array(0 to 1, 0 to 11) of STD_LOGIC_VECTOR(3 downto 0);
    
        constant RESET_DELAY_1  : INTEGER   := 50000;                                                   -- Delay after power up in us
        constant RESET_DELAY_2  : INTEGER   := 4100;                                                    -- Delay after sending first initialization instruction in us
        constant RESET_DELAY_3  : INTEGER   := 100;                                                     -- Delay after sending second initialization instruction in us
        constant RESET_DELAY_4  : INTEGER   := 100;                                                     -- Delay after sending third initialization instruction in us
    
    --  constant Configs        : Config_t  := ((x"39", x"06", x"17", x"0F", x"01", x"02"),             -- Function set european character set
    --                                                                                                  -- Entry mode set increment cursor by 1 not shifting display
    --                                                                                                  -- Character mode and internal power on
    --                                                                                                  -- Clear the display
    --                                                                                                  -- Return cursor to home position
    --                                                                                                  -- Display and blinking cursor on
    --                                          (x"39", x"06", x"17", x"0C", x"01", x"02")              -- Function set european character set
    --                                                                                                  -- Entry mode set increment cursor by 1 not shifting display
    --                                                                                                  -- Character mode and internal power on
    --                                                                                                  -- Clear the display
    --                                                                                                  -- Return cursor to home position
    --                                                                                                  -- Display on
    --                                         );
        constant Configs        : Config_t  := (
        (x"2", x"9",
         x"0", x"6", 
         x"1", x"7", 
         x"0", x"F", 
         x"0", x"1", 
         x"0", x"2"),             
                                                                                                        -- Function set european character set
                                                                                                        -- Entry mode set increment cursor by 1 not shifting display
                                                                                                        -- Character mode and internal power on
                                                                                                        -- Clear the display
                                                                                                        -- Return cursor to home position
                                                                                                        -- Display and blinking cursor on
        (x"2", x"9",
         x"0", x"6", 
         x"1", x"7", 
         x"0", x"C", 
         x"0", x"1", 
         x"0", x"2")              
                                                                                                        -- Function set european character set
                                                                                                        -- Entry mode set increment cursor by 1 not shifting display
                                                                                                        -- Character mode and internal power on
                                                                                                        -- Clear the display
                                                                                                        -- Return cursor to home position
                                                                                                        -- Display on
                                               );
    
        constant RESET_DELAY    : INTEGER   := RESET_DELAY_2 + RESET_DELAY_3 + RESET_DELAY_4;           -- Full reset delay after the power up reset
    
        signal CurrentState     : State_t   := Reset;
    
    --  signal Data_Int         : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');
        signal Data_Int         : STD_LOGIC_VECTOR(3 downto 0) := (others => '0');
    
    begin
    
        process(Clock, nReset)
            -- Millisecond counter for state machine timing
            variable usCounter  : INTEGER := 0;
        begin
            if(nReset = '0') then
                usCounter := 0;
                Ready <= '0';
                LCD_E <= '0';
                LCD_RS <= '0';
                LCD_RW <= '0';
                LCD_Data <= (others => '0');
                Data_Int <= (others => '0');
                CurrentState <= Reset;
            elsif(rising_edge(Clock)) then
                case CurrentState is
    
                    -- The entry point for the state machine.
                    when Reset =>
                        usCounter := usCounter + 1;
    
                        if(usCounter < (RESET_DELAY_1 * CLOCK_FREQ)) then
                            CurrentState <= Reset;
                        else
                            usCounter := 0;
    --                      LCD_Data <= x"30";
                            LCD_Data <= x"3"; -- 4 bit
                            CurrentState <= Initialize;
                        end if;
    
                    -- Initialize the display controller with a default configuration.
                    when Initialize =>
                        usCounter := usCounter + 1;
    
    --                  -- Send three times 0x30 to put the LCD into 8-bit mode
                        -- Send three times 0x03 to put the LCD into 4-bit mode
                        if(usCounter < (RESET_DELAY_2 * CLOCK_FREQ)) then
                            LCD_E <= '1';
                        elsif(usCounter < ((RESET_DELAY_2 + 10) * CLOCK_FREQ)) then
                            LCD_E <= '0';
                        elsif(usCounter < ((RESET_DELAY_2 + RESET_DELAY_3 + 10) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                        elsif(usCounter < ((RESET_DELAY_2 + RESET_DELAY_3 + 20) * CLOCK_FREQ)) then
                            LCD_E <= '0';         
                        elsif(usCounter < ((RESET_DELAY_2 + RESET_DELAY_3 + RESET_DELAY_4 + 20) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                        elsif(usCounter < ((RESET_DELAY_3 + RESET_DELAY_3 + RESET_DELAY_4 + 30) * CLOCK_FREQ)) then
                            LCD_E <= '0';
                            
                        -- set 4 character mode
                        elsif(usCounter < ((RESET_DELAY + 40) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= x"2"; -- 4 bit
                        elsif(usCounter < ((RESET_DELAY + 50) * CLOCK_FREQ)) then
                            LCD_E <= '0';
                        
    
                        -- Send the display configuration
    --                  elsif(usCounter < ((RESET_DELAY + 40) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 60) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 0);
    --                  elsif(usCounter < ((RESET_DELAY + 50) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 70) * CLOCK_FREQ)) then
                            LCD_E <= '0';
    --                  elsif(usCounter < ((RESET_DELAY + 60) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 80) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 1);
    --                  elsif(usCounter < ((RESET_DELAY + 70) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 90) * CLOCK_FREQ)) then
                            LCD_E <= '0';
    --                  elsif(usCounter < ((RESET_DELAY + 80) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 100) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 2);
    --                  elsif(usCounter < ((RESET_DELAY + 90) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 110) * CLOCK_FREQ)) then
                            LCD_E <= '0';
    --                    elsif(usCounter < ((RESET_DELAY + 100) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 120) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 3);
    --                  elsif(usCounter < ((RESET_DELAY + 110) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 130) * CLOCK_FREQ)) then
                            LCD_E <= '0';
    --                  elsif(usCounter < ((RESET_DELAY + 120) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 140) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 4);
    --                  elsif(usCounter < ((RESET_DELAY + 130) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 150) * CLOCK_FREQ)) then
                            LCD_E <= '0';
    --                  elsif(usCounter < ((RESET_DELAY + 140) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 160) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 5);
    --                  elsif(usCounter < ((RESET_DELAY + 150) * CLOCK_FREQ)) then
                        elsif(usCounter < ((RESET_DELAY + 170) * CLOCK_FREQ)) then
                            LCD_E <= '0';
    
                        elsif(usCounter < ((RESET_DELAY + 180) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 6);
                        elsif(usCounter < ((RESET_DELAY + 190) * CLOCK_FREQ)) then
                            LCD_E <= '0';
                        elsif(usCounter < ((RESET_DELAY + 200) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 7);
                        elsif(usCounter < ((RESET_DELAY + 210) * CLOCK_FREQ)) then
                            LCD_E <= '0';
                        elsif(usCounter < ((RESET_DELAY + 220) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 8);
                        elsif(usCounter < ((RESET_DELAY + 230) * CLOCK_FREQ)) then
                            LCD_E <= '0';
                        elsif(usCounter < ((RESET_DELAY + 240) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 9);
                        elsif(usCounter < ((RESET_DELAY + 250) * CLOCK_FREQ)) then
                            LCD_E <= '0';
                        elsif(usCounter < ((RESET_DELAY + 260) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 10);
                        elsif(usCounter < ((RESET_DELAY + 270) * CLOCK_FREQ)) then
                            LCD_E <= '0';
                        elsif(usCounter < ((RESET_DELAY + 280) * CLOCK_FREQ)) then
                            LCD_E <= '1';
                            LCD_Data <= Configs(CONFIG, 11);
                        elsif(usCounter < ((RESET_DELAY + 290) * CLOCK_FREQ)) then
                            LCD_E <= '0';
    
                        -- Initialization complete. Wait for the display to become ready.
                        else
                            usCounter := 0;
                            CurrentState <= WaitBusy;
                        end if;
    
                    -- Read the BUSY-Flag from the display controller and check 
                    -- if the controller is ready.
                    when WaitBusy =>
                        usCounter := usCounter + 1;
    
                        if(usCounter < (10 * CLOCK_FREQ)) then
                            LCD_RS <= '0';
                            LCD_RW <= '1';
                            LCD_E <= '1';
                            LCD_Data <= (others => 'Z');
                        elsif(usCounter < (20 * CLOCK_FREQ)) then
                            LCD_E <= '0';
                        else
                            usCounter := 0;
    
                            -- Check if the BUSY-Flag is set
                            
    --                      if(LCD_Data(7) = '1') then
                            if(LCD_Data(3) = '1') then
                                Ready <= '0';
                                CurrentState <= WaitBusy;
                            else
                                Ready <= '1';
                                CurrentState <= Idle;
                            end if;
                        end if;
    
                    -- Wait for a new data transmission.
                    when Idle =>
                        if(Valid = '1') then
                            Ready <= '0';
                            Data_Int <= Data;
                            if(SendCommand = '1') then
                                LCD_RS <= '0';
                            else
                                LCD_RS <= '1';
                            end if;
    
                            CurrentState <= Transmit;
                        else
                            Ready <= '1';
                            CurrentState <= Idle;
                        end if;
    
                    -- Write the data into the display controller.
                    when Transmit =>
                        usCounter := usCounter + 1;
    
                        if(usCounter < (10 * CLOCK_FREQ)) then
                            LCD_RW <= '0';
                            LCD_E <= '1';
                            LCD_Data <= Data_Int;
                        elsif(usCounter < (20 * CLOCK_FREQ)) then
                            LCD_E <= '0';
                        else
                            usCounter := 0;
                            CurrentState <= WaitBusy;
                        end if;
    
                end case;
            end if;
        end process;
    end LCD_Controller_Arch;

    Wired up:

    image

    Raw Python test bed written:

    from pynq import Overlay
    ol = Overlay("LCD_Controller.bit")
    
    # ================================
    
    from pynq import GPIO
    
    gpio_sendCommand = GPIO(GPIO.get_gpio_pin(0), 'out')
    gpio_valid = GPIO(GPIO.get_gpio_pin(1), 'out')
    
    gpio_ready = GPIO(GPIO.get_gpio_pin(2), 'in')
    
    def isReady():
        result = gpio_ready.read()
        if result:
            return True
        return False
    
    # ================================
    
    from pynq import MMIO
    databus_address = ol.ip_dict['axi_gpio_databus']['phys_addr']
    RANGE = 4
    databus = MMIO(databus_address, RANGE)
    
    # ================================
    
    def databus_write(data):
        databus.write(0,data)
    
    # ================================
    
    # raw test set address
    
    print(isReady())
    
    gpio_valid.write(0)
    gpio_sendCommand.write(1)
    databus_write(0b1000)
    gpio_valid.write(1)
    
    print(isReady())
    
    gpio_valid.write(0)
    databus_write(0b0010)
    gpio_valid.write(1)
    gpio_valid.write(0)
    
    gpio_sendCommand.write(0)
    
    print(isReady())
    
    # ================================
    
    #raw test set character
    
    print(isReady())
    
    gpio_valid.write(0)
    gpio_sendCommand.write(0)
    databus_write(0b0100)
    gpio_valid.write(1)
    
    print(isReady())
    
    gpio_valid.write(0)
    databus_write(0b1000)
    gpio_valid.write(1)
    gpio_valid.write(0)
    
    gpio_sendCommand.write(0)
    
    print(isReady())
    
    # ================================

    The conversation happens, because the LCD driver sets the ready bit in its reply, each time I send 2 * 4 bits. 
    But the magic doesn't happen yet. No characters.

    This was supposed to be my entry for the Project14 Build a Present. Like javagoza, I tried to make a device driver as present.
    With the week-end finished, I guess that won't happen Blush.

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

    Some good news: it's not working, but it's trying:

    image

    This is a capture of the startup procedure. If you look at E, you can spot the 3 longer init sequences, then 1 burst to set 4 bit mode, then 2 * 6 4 bit bursts with the init settings.
    The first thing I see, is that R/~W is high. It should be low while writing....

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

    I found the reason for the failure of the R/~W:

    image

    I had set it to V12, pin 9 of PMODB. It should be W18, pin 9 of PMOD A:

    image

    checking:

    image

    That's better. I'll reconnect the LCD to the Pynq board and retry ...

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

    Partly success:

    image

    It's not correct, I sent a single 'a'. But it's better than before.

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

    Partly success:

    image

    It's not correct, I sent a single 'a'. But it's better than before.

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

    Success.

    image
    I'm sending a stream of 'f'. I used f because that's binary '01100110',
    so if I keep sending '0110' values, it should generate all 'f's. Yay!

    • Cancel
    • Vote Up +7 Vote Down
    • Sign in to reply
    • 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