Cours:De0NanoSoc : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
(compiler Qt)
(ov7670 et DDR)
 
(64 révisions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
=installation Linux=
+
=schema=
  
*créer la carte SD avec l'image :
+
[[Media:De0NanoTop.zip]]
https://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=167&No=941&PartNo=4
 
*modifier la partition racine
 
*installer debian 10
 
https://rcn-ee.com/rootfs/eewiki/minfs/
 
*installer debian 8
 
https://rocketboards.org/foswiki/pub/Projects/Debian/debian.img.gz
 
*ajouter la partition racine dans le fichier fstab
 
/dev/mmcblk0p2  /  auto  errors=remount-ro  0  1
 
*démarrer la de0 nano soc
 
**configurer le reseau
 
**bug :
 
ln -s /lib/systemd/system/getty@.service /etc/systemd/system/getty.target.wants/getty@ttyS0.service
 
  
==modifier sur la Debian==
+
=ov7670 et DDR=
===apt sources list===
 
  
modifier le fichier /etc/apt/sources.list avec :
+
[[Media:Ov7670.zip]]
<source lang=bash>
+
 
deb http://archive.debian.org/debian buster main contrib non-free
+
<source lang=vhdl>
#deb-src http://archive.debian.org/debian buster main contrib non-free
+
library ieee;
 +
use ieee.std_logic_1164.all;
 +
use ieee.numeric_std.all;
 +
 
 +
entity fpga_dma_rgb32_simple is
 +
    port (
 +
        -- ============================================================
 +
        -- Interface Système (Reliée à l'horloge du FPGA/HPS)
 +
        -- ============================================================
 +
        clk              : in  std_logic; -- 50 MHz
 +
        reset_n          : in  std_logic; -- Reset Actif Bas
 +
 
 +
        -- ============================================================
 +
        -- Interface Avalon-MM Master (Vers le HPS SDRAM Controller)
 +
        -- ============================================================
 +
        avm_address      : out std_logic_vector(31 downto 0);
 +
        avm_write        : out std_logic;
 +
        avm_writedata    : out std_logic_vector(31 downto 0);
 +
        avm_byteenable  : out std_logic_vector(3 downto 0);
 +
        avm_waitrequest  : in  std_logic;
 +
 
 +
        -- ============================================================
 +
        -- Interface Physique Caméra (Conduit vers les Pins)
 +
        -- ============================================================
 +
        cam_pclk        : in  std_logic; -- Pixel Clock (~24 MHz)
 +
        cam_href        : in  std_logic; -- Ligne valide
 +
        cam_vsync        : in  std_logic; -- Nouvelle image
 +
        cam_data        : in  std_logic_vector(7 downto 0); -- Données brutes
 +
 
 +
        -- Sortie horloge générée pour la caméra (25 MHz)
 +
        cam_xclk        : out std_logic
 +
    );
 +
end entity;
 +
 
 +
architecture rtl of fpga_dma_rgb32_simple is
 +
 
 +
    -- ========================================================================
 +
    -- 1. DECLARATION DES COMPOSANTS IP
 +
    -- ========================================================================
 +
 
 +
    -- PLL (Doit correspondre à ton fichier pll.vhd)
 +
    component pll is
 +
        port (
 +
            refclk  : in  std_logic;
 +
            rst      : in  std_logic;
 +
            outclk_0 : out std_logic;
 +
            locked  : out std_logic  -- Ajouté suite à ta correction
 +
        );
 +
    end component pll;
 +
 
 +
    -- FIFO (Doit correspondre à ton fichier camera_fifo.vhd)
 +
    component camera_fifo is
 +
        port (
 +
            data    : in  std_logic_vector(15 downto 0);
 +
            rdclk  : in  std_logic;
 +
            rdreq  : in  std_logic;
 +
            wrclk  : in  std_logic;
 +
            wrreq  : in  std_logic;
 +
            q      : out std_logic_vector(15 downto 0);
 +
            rdempty : out std_logic;
 +
            wrfull  : out std_logic
 +
        );
 +
    end component;
 +
 
 +
    -- ========================================================================
 +
    -- 2. SIGNAUX INTERNES
 +
    -- ========================================================================
 +
 
 +
    -- Configuration Mémoire
 +
    constant BASE_ADDRESS : unsigned(31 downto 0) := x"30000000"; -- Adresse de départ dans la DDR
 +
    -- QVGA (320x240) = 76,800 pixels. En 32 bits (4 octets) -> 307,200 octets.
 +
    -- VGA  (640x480) = 307,200 pixels. En 32 bits -> 1,228,800 octets.
 +
    constant MAX_OFFSET  : integer := 320 * 240 * 4;
  
deb http://archive.debian.org/debian-security buster/updates main contrib non-free
+
    -- Signaux Capture (Domaine PCLK)
#deb-src http://security.debian.org/debian-security buster/updates main contrib non-free
+
    signal cam_high_byte  : std_logic_vector(7 downto 0);
 +
    signal cam_toggle    : std_logic := '0';
 +
    signal fifo_data_in  : std_logic_vector(15 downto 0);
 +
    signal fifo_wr_req    : std_logic := '0';
  
deb http://archive.debian.org/debian buster-updates main contrib non-free
+
    -- Signaux DMA (Domaine CLK 50MHz)
#deb-src http://archive.debian.org/debian buster-updates main contrib non-free
+
    signal fifo_data_out  : std_logic_vector(15 downto 0);
 +
    signal fifo_rd_req    : std_logic;
 +
    signal fifo_empty    : std_logic;
  
#Kernel source (repos.rcn-ee.com) : https://github.com/RobertCNelson/linux-stable-rcn-ee
+
    signal dma_addr      : unsigned(31 downto 0) := BASE_ADDRESS;
#
+
    signal writing_active : std_logic := '0';
#git clone https://github.com/RobertCNelson/linux-stable-rcn-ee
 
#cd ./linux-stable-rcn-ee
 
#git checkout `uname -r` -b tmp
 
  
deb [arch=armhf signed-by=/usr/share/keyrings/rcn-ee-archive-keyring.gpg] http://repos.rcn-ee.com/debian/ buster main
+
    -- Synchro VSYNC (Passage de domaine PCLK -> CLK 50MHz)
#deb-src [arch=armhf signed-by=/usr/share/keyrings/rcn-ee-archive-keyring.gpg] http://repos.rcn-ee.com/debian/ buster main
+
    signal vsync_r1, vsync_r2 : std_logic;
</source>
+
    signal vsync_edge        : std_logic;
  
===installer===
+
    -- Reconstruction Pixel
*dpkg-reconfigure locales
+
    signal r, g, b : std_logic_vector(7 downto 0);
*apt install build-essential
 
*apt install zlib1g-dev libicu-dev libdouble-conversion-dev libpcre2-dev libzstd-dev libglib2.0-0 libglib2.0-dev libpng-dev libharfbuzz-dev
 
*apt install libssl-dev libkrb5-dev libudev-dev libfontconfig-dev libxkbcommon-dev
 
*libmd4c
 
wget http://ftp.fr.debian.org/debian/pool/main/m/md4c/libmd4c0_0.4.8-1_armhf.deb
 
wget http://ftp.fr.debian.org/debian/pool/main/m/md4c/libmd4c-dev_0.4.8-1_armhf.deb
 
dpkg -i *.deb
 
  
==chroot==
+
begin
  
<source lang=bash>
+
    -- ========================================================================
mount -t proc /proc /apps/de0NanoSoc/chroot/proc/
+
    -- 3. INSTANCIATION PLL (50MHz -> 25MHz)
mount --rbind /sys /apps/de0NanoSoc/chroot/sys/
+
    -- ========================================================================
mount --rbind /dev /apps/de0NanoSoc/chroot/dev/
+
    u_pll : component pll
chroot /apps/de0NanoSoc/chroot/
+
        port map (
umount /apps/de0NanoSoc/chroot/dev/
+
            refclk  => clk,
umount /apps/de0NanoSoc/chroot/sys/
+
            rst      => not reset_n, -- Le reset système est actif bas, la PLL attend actif haut
umount /apps/de0NanoSoc/chroot/proc/
+
            outclk_0 => cam_xclk,
</source>
+
            locked  => open        -- On laisse ouvert si on ne s'en sert pas pour une LED
 +
        );
  
=cross compilation=
+
    -- ========================================================================
 +
    -- 4. LOGIQUE DE CAPTURE (Domaine PCLK)
 +
    -- ========================================================================
 +
    process(cam_pclk)
 +
    begin
 +
        if rising_edge(cam_pclk) then
 +
            -- Si VSYNC actif ou pas de HREF, on reset la machine à états de capture
 +
            if cam_vsync = '1' or cam_href = '0' then
 +
                cam_toggle  <= '0';
 +
                fifo_wr_req <= '0';
 +
            else
 +
                -- Si ligne valide
 +
                if cam_href = '1' then
 +
                    cam_toggle <= not cam_toggle;
  
==sysroot==
+
                    if cam_toggle = '0' then
<source lang=bash>
+
                        -- Premier octet reçu (MSB du RGB565)
rep="monDossier"
+
                        cam_high_byte <= cam_data;
cd $rep
+
                        fifo_wr_req  <= '0';
rsync -av chroot/lib sysroot/
+
                    else
rsync -av chroot/usr/include sysroot/usr/
+
                        -- Deuxième octet reçu (LSB)
rsync -av chroot/usr/lib sysroot/usr/
+
                        -- On concatène pour former le pixel 16 bits
rsync -av chroot/usr/arm-linux-gnueabi rsync -av sysroot/usr/
+
                        fifo_data_in <= cam_high_byte & cam_data;
apt install symlinks
+
                        fifo_wr_req  <= '1'; -- On demande l'écriture dans la FIFO
symlinks -rc sysroot
+
                    end if;
 +
                end if;
 +
            end if;
 +
        end if;
 +
    end process;
  
cd sysroot/usr/include/
+
    -- ========================================================================
ln -s ../arm-linux-gnueabi/include/gnu ./
+
    -- 5. INSTANCIATION FIFO DUAL CLOCK
</source>
+
    -- ========================================================================
 +
    u_fifo : component camera_fifo
 +
        port map (
 +
            -- Coté Ecriture (Caméra)
 +
            wrclk  => cam_pclk,
 +
            data    => fifo_data_in,
 +
            wrreq  => fifo_wr_req,
 +
            wrfull  => open,
  
==compilateur arm 8==
+
            -- Coté Lecture (Système Avalon)
 +
            rdclk  => clk,
 +
            rdreq  => fifo_rd_req,
 +
            q      => fifo_data_out,
 +
            rdempty => fifo_empty
 +
        );
  
*ajouter au fichier /etc/apt/sources.list
+
    -- ========================================================================
http://archive.ubuntu.com/ubuntu focal main universe
+
    -- 6. LOGIQUE DMA & AVALON (Domaine CLK 50MHz)
http://archive.ubuntu.com/ubuntu focal main universe
+
    -- ========================================================================
  
 +
    -- Détection du VSYNC dans le domaine 50MHz (pour reset l'adresse mémoire)
 +
    process(clk)
 +
    begin
 +
        if rising_edge(clk) then
 +
            vsync_r1 <= cam_vsync;
 +
            vsync_r2 <= vsync_r1;
 +
        end if;
 +
    end process;
 +
    -- Détection front montant VSYNC
 +
    vsync_edge <= '1' when (vsync_r1 = '1' and vsync_r2 = '0') else '0';
  
<source lang=bash>
+
    -- Machine à états DMA
mkdir -p /apps/gcc/arm-8/
+
    process(clk, reset_n)
cp /apps/gcc/arm-8/
+
    begin
ln -s /usr/bin/arm-linux-gnueabihf-cpp-8 arm-linux-gnueabihf-cpp
+
        if reset_n = '0' then
ln -s /usr/bin/arm-linux-gnueabihf-g++-8 arm-linux-gnueabihf-g++
+
            dma_addr      <= BASE_ADDRESS;
ln -s /usr/bin/arm-linux-gnueabihf-gcc-8 arm-linux-gnueabihf-gcc
+
            writing_active <= '0';
ln -s /usr/bin/arm-linux-gnueabihf-gcc-ar-8 arm-linux-gnueabihf-ar
+
            fifo_rd_req    <= '0';
ln -s /usr/bin/arm-linux-gnueabihf-gcc-nm-8 arm-linux-gnueabihf-nm
 
ln -s /usr/bin/arm-linux-gnueabihf-gcc-ranlib-8 arm-linux-gnueabihf-ranlib
 
ln -s /usr/bin/arm-linux-gnueabihf-gcov-8 arm-linux-gnueabihf-gcov
 
ln -s /usr/bin/arm-linux-gnueabihf-gcov-dump-8 arm-linux-gnueabihf-gcov-dump
 
ln -s /usr/bin/arm-linux-gnueabihf-gcov-tool-8 arm-linux-gnueabihf-gcov-tool
 
ln -s /usr/bin/arm-linux-gnueabihf-lto-dump-8 arm-linux-gnueabihf-dump
 
</source>
 
  
 +
        elsif rising_edge(clk) then
  
PATH=/apps/gcc/arm-12:$PATH
+
            -- 1. Gestion du Reset Frame (VSYNC)
 +
            -- Si la caméra commence une nouvelle image, on remet l'adresse au début
 +
            if vsync_edge = '1' then
 +
                dma_addr <= BASE_ADDRESS;
 +
            end if;
  
 +
            -- 2. Gestion de la fin d'écriture Avalon
 +
            -- Si 'waitrequest' tombe à 0, l'écriture est validée par la DDR
 +
            if avm_waitrequest = '0' then
 +
                writing_active <= '0';
 +
            end if;
  
==compiler Qt==
+
            -- 3. Lancement d'une nouvelle écriture
 +
            -- Si on n'écrit pas ET que la FIFO n'est pas vide
 +
            if writing_active = '0' and fifo_empty = '0' then
 +
                fifo_rd_req    <= '1'; -- On "pop" un pixel de la FIFO
 +
                writing_active <= '1'; -- On lève le flag d'écriture pour Avalon
  
 +
                -- Calcul adresse suivante (4 octets par pixel 32 bits)
 +
                if dma_addr < (BASE_ADDRESS + MAX_OFFSET) then
 +
                    dma_addr <= dma_addr + 4;
 +
                else
 +
                    dma_addr <= BASE_ADDRESS; -- Sécurité (bouclage)
 +
                end if;
 +
            else
 +
                fifo_rd_req <= '0';
 +
            end if;
  
===get qtSource===
+
        end if;
<source lang=bash>
+
    end process;
rep="monDossier"
 
cd $rep
 
mkdir qt5Source
 
cd qt5Source
 
git clone https://code.qt.io/qt/qt5.git -b 5.15
 
cd qt5
 
./init-repository --module-subset=essential,qtserialport
 
git submodule foreach --recursive "git clean -dfx"
 
</source>
 
  
===créer le fichier "devices"===
+
    -- ========================================================================
 +
    -- 7. CONVERSION DE DONNEES (RGB565 -> RGB32)
 +
    -- ========================================================================
  
<source lang=bash>
+
    -- Sortie FIFO (16 bits) : R[15:11], G[10:5], B[4:0]
mkdir linux-cyclonev-g++
+
    -- Conversion vers 32 bits : Alpha(8) - R(8) - G(8) - B(8)
cd linux-cyclonev-g++
 
nano qmake.conf
 
//contenu
 
  
#include(../common/linux_device_pre.conf)
+
    -- On décale les bits et on remplit les LSB avec des 0
 +
    r <= fifo_data_out(15 downto 11) & "000";
 +
    g <= fifo_data_out(10 downto 5)  & "00";
 +
    b <= fifo_data_out(4 downto 0)  & "000";
  
#DISTRO_OPTS                  += arm
+
    -- Mappage des sorties Avalon
#COMPILER_FLAGS              += -march=armv7-a+fp -mfloat-abi=hard
+
    avm_address    <= std_logic_vector(dma_addr);
 +
    avm_byteenable <= "1111"; -- Ecriture sur 32 bits (4 octets)
 +
    avm_write      <= writing_active;
  
#DISTRO_OPTS += hard-float
+
    -- Données : Alpha (Full Opaque) | Red | Green | Blue
 +
    avm_writedata  <= x"FF" & r & g & b;
  
#CONFIG += incremental cross_compile qpa
+
end architecture;
#QT_QPA_DEFAULT_PLATFORM = linuxfb
+
</source>
  
 +
=Ecriture dans la DDR=
  
#include(../common/linux_arm_device_post.conf)
+
!!! ATTENTION : le bus avalon ne peut pas accéder à tout l'espace de la DDR
 +
à vérifier mais ne marche pas à l'@ 0x3f000000
 +
utiliser une zone mémoire à l'@ 0x30000000
  
 +
il faut autoriser l'accès avec :
 +
memtool mw -l 0xFFC25080 0x1F0
  
#-------------------------------------------------
 
# Qt mkspec for DE0-Nano-SoC (Cyclone V, ARMv7-A, hard-float)
 
# Cross-compilation using Linaro or Intel SoC EDS toolchain
 
#-------------------------------------------------
 
  
MAKEFILE_GENERATOR = UNIX
+
// a supprimer
CONFIG += incremental global_init_link_order
+
*dans uboot
CONFIG += cross_compile qpa
+
<source lang=bash>
 +
mw 0xFFC25080 0x1F0
 +
mw 0xFFC2505C 0xA
 +
</source>
  
# QPA platforms
+
*sur linux
QMAKE_QPA_PLATFORM = linuxfb eglfs
+
<source lang=cpp>
 +
memtool mw -l 0xFFC25080 0x1F0
 +
memtool mw -l 0xFFC2505C 0xA
 +
</source>
  
#-------------------------------------------------
 
# Toolchain
 
#-------------------------------------------------
 
QMAKE_CC        = $$CROSS_COMPILEgcc-12
 
QMAKE_CXX      = $$CROSS_COMPILEg++-12
 
QMAKE_LINK      = $$CROSS_COMPILEg++-12
 
QMAKE_LINK_SHLIB= $$CROSS_COMPILEg++-12
 
QMAKE_AR        = $$CROSS_COMPILEar cqs
 
QMAKE_OBJCOPY  = $$CROSS_COMPILEobjcopy
 
QMAKE_STRIP    = $$CROSS_COMPILEstrip
 
  
#-------------------------------------------------
+
https://www.reddit.com/r/FPGA/comments/12mg5su/having_issues_writing_data_from_fpga_to_hps_using/?tl=fr
# CPU architecture flags (Cyclone V = ARMv7-A + NEON)
 
#-------------------------------------------------
 
QMAKE_CFLAGS  += -march=armv7-a -mfloat-abi=hard -mfpu=neon
 
QMAKE_CXXFLAGS += -march=armv7-a -mfloat-abi=hard -mfpu=neon
 
  
#-------------------------------------------------
+
https://people.ece.cornell.edu/land/courses/ece5760/DE1_SOC/cv_5_HPS_tech_ref.pdf
# Sysroot
 
#-------------------------------------------------
 
  
QMAKE_INCDIR += \
+
*fpga
    $$[QT_SYSROOT]/usr/include \
 
    $$[QT_SYSROOT]/usr/include/arm-linux-gnueabihf \
 
    $$[QT_SYSROOT]/usr/arm-linux-gnueabi/include
 
  
QMAKE_LIBDIR += \
+
<source lang=vhdl>
    $$[QT_SYSROOT]/lib \
+
library ieee;
    $$[QT_SYSROOT]/lib/arm-linux-gnueabihf \
+
use ieee.std_logic_1164.all;
    $$[QT_SYSROOT]/usr/lib \
+
use ieee.numeric_std.all;
    $$[QT_SYSROOT]/usr/lib/arm-linux-gnueabihf
 
  
 +
entity fpga_dma_rgb32_simple is
 +
  port (
 +
    clk  : in  std_logic;
 +
    reset : in  std_logic;
  
QMAKE_LIBS += -ldl
+
    -- Avalon-MM master
QMAKE_LIBS_PRIVATE += -ldl
+
    avm_address    : out std_logic_vector(31 downto 0);
 +
    avm_write      : out std_logic;
 +
    avm_writedata  : out std_logic_vector(31 downto 0);
 +
    avm_waitrequest : in  std_logic
 +
  );
 +
end entity;
  
# Avoid RPATH for embedded targets
+
architecture rtl of fpga_dma_rgb32_simple is
QMAKE_LFLAGS_RPATH =
 
  
# Default QPA platform
+
  constant BASE_ADDR    : unsigned(31 downto 0) := x"3FB00000";
QT_QPA_DEFAULT_PLATFORM = linuxfb
+
  constant WIDTH        : integer := 640;
 +
  constant HEIGHT      : integer := 480;
 +
  constant TOTAL_PIXELS : integer := WIDTH * HEIGHT; -- 307200
  
# EGLFS backend (requires SGX drivers)
+
  signal pixel_index : integer range 0 to TOTAL_PIXELS-1 := 0;
EGLFS_DEVICE_INTEGRATION = eglfs
+
  signal addr        : unsigned(31 downto 0);
 +
  signal write_reg  : std_logic := '0';
  
#-------------------------------------------------
+
  -- Pattern RGB32 (XRGB8888)
# Common includes for embedded Linux
+
  signal r, g, b    : unsigned(7 downto 0);
#-------------------------------------------------
+
  signal pixel32    : unsigned(31 downto 0);
DISTRO_OPTS += hard-float
 
  
QT_CPU_FEATURES.arm = neon
+
begin
  
load(device_config)
+
  --------------------------------------------------------------------
include(../common/linux_device_pre.conf)
+
  -- Générateur simple de pattern
include(../common/linux_arm_device_post.conf)
+
  --------------------------------------------------------------------
load(qt_config)
+
  r <= to_unsigned((pixel_index mod WIDTH) * 255 / WIDTH, 8);
 +
  g <= to_unsigned((pixel_index / WIDTH) * 255 / HEIGHT, 8);
 +
  b <= to_unsigned(128, 8);
  
 +
--  pixel32 <= x"00" & r & g & b;  -- XRGB8888
 +
  pixel32 <= x"AAAAAAAA";  -- XRGB8888
  
nano qplatformdefs.h
+
  avm_writedata <= std_logic_vector(pixel32);
  
//contenu
+
  --------------------------------------------------------------------
/dev/mmcblk0p2  /  auto  errors=remount-ro  0  1
+
  -- Adresse courante
 +
  --------------------------------------------------------------------
 +
  addr <= BASE_ADDR + to_unsigned(pixel_index * 4, 32);
  
</source>
+
  avm_address <= std_logic_vector(addr);
 +
  avm_write  <= write_reg;
 +
  --------------------------------------------------------------------
 +
  -- FSM simple
 +
  --------------------------------------------------------------------
 +
  process(clk)
 +
  begin
 +
    if rising_edge(clk) then
 +
        if avm_waitrequest = '0' then
 +
          write_reg <= '1';
  
={{Rouge|Projet Quartus}}=
+
          pixel_index <= pixel_index + 1;
Device :
 
*Altera Cyclone®  V
 
*SE  Mainstream
 
*5CSEMA4U23C6 N
 
  
={{Rouge|positions}}=
+
          -- boucle image
 +
          if pixel_index = TOTAL_PIXELS-1 then
 +
            pixel_index <= 0;
 +
          end if;
 +
        else
 +
          write_reg <= '0';
 +
        end if;
 +
    end if;
 +
  end process;
  
{| class="wikitable"
+
end architecture;
|-
+
</source>
| Nom || Led7 || Led6 || Led5 || Led4 || Led3 || Led2 || Led1 || Led0
 
|-
 
| Broche || AA23 || Y16 || AE26 || AF26 || V15 || V16 || AA24 || W15
 
|}
 
  
{| class="wikitable"
+
=I2C=
|-
 
| Nom || SW3 || SW2 || SW1 || SW0
 
|-
 
| Broche || H5 || H6 || L9 || L10
 
|}
 
  
={{Rouge|Ressources}}=
+
[[Media:DE0-Nano-SoC_Schematic.pdf]]
  
*[https://eewiki.net/display/linuxonarm/DE0-Nano-SoC+Kit préparation de la carte SD avec debian]
+
*on utilisera le bus i2c1
*configuration du noyau
+
*la vitesse est de 100kHz
**device/fpga_config_support  .... altera
+
**dans le fichier device-tree
**device/gpio ... altera
+
**modifier speed-mode = <0x00>
 +
***0x00 = Standard mode (100 kHz)
 +
***0x01 = Fast mode (400 kHz)
 +
*broches
 +
**sur le connecteur LTC
 +
**ATTENTION : il faut mettre des résistances de Pull-Up !!!

Version actuelle datée du 4 février 2026 à 11:24

schema

Media:De0NanoTop.zip

ov7670 et DDR

Media:Ov7670.zip

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity fpga_dma_rgb32_simple is
    port (
        -- ============================================================
        -- Interface Système (Reliée à l'horloge du FPGA/HPS)
        -- ============================================================
        clk              : in  std_logic; -- 50 MHz
        reset_n          : in  std_logic; -- Reset Actif Bas

        -- ============================================================
        -- Interface Avalon-MM Master (Vers le HPS SDRAM Controller)
        -- ============================================================
        avm_address      : out std_logic_vector(31 downto 0);
        avm_write        : out std_logic;
        avm_writedata    : out std_logic_vector(31 downto 0);
        avm_byteenable   : out std_logic_vector(3 downto 0);
        avm_waitrequest  : in  std_logic;

        -- ============================================================
        -- Interface Physique Caméra (Conduit vers les Pins)
        -- ============================================================
        cam_pclk         : in  std_logic; -- Pixel Clock (~24 MHz)
        cam_href         : in  std_logic; -- Ligne valide
        cam_vsync        : in  std_logic; -- Nouvelle image
        cam_data         : in  std_logic_vector(7 downto 0); -- Données brutes

        -- Sortie horloge générée pour la caméra (25 MHz)
        cam_xclk         : out std_logic
    );
end entity;

architecture rtl of fpga_dma_rgb32_simple is

    -- ========================================================================
    -- 1. DECLARATION DES COMPOSANTS IP
    -- ========================================================================

    -- PLL (Doit correspondre à ton fichier pll.vhd)
    component pll is
        port (
            refclk   : in  std_logic;
            rst      : in  std_logic;
            outclk_0 : out std_logic;
            locked   : out std_logic  -- Ajouté suite à ta correction
        );
    end component pll;

    -- FIFO (Doit correspondre à ton fichier camera_fifo.vhd)
    component camera_fifo is
        port (
            data    : in  std_logic_vector(15 downto 0);
            rdclk   : in  std_logic;
            rdreq   : in  std_logic;
            wrclk   : in  std_logic;
            wrreq   : in  std_logic;
            q       : out std_logic_vector(15 downto 0);
            rdempty : out std_logic;
            wrfull  : out std_logic
        );
    end component;

    -- ========================================================================
    -- 2. SIGNAUX INTERNES
    -- ========================================================================

    -- Configuration Mémoire
    constant BASE_ADDRESS : unsigned(31 downto 0) := x"30000000"; -- Adresse de départ dans la DDR
    -- QVGA (320x240) = 76,800 pixels. En 32 bits (4 octets) -> 307,200 octets.
    -- VGA  (640x480) = 307,200 pixels. En 32 bits -> 1,228,800 octets.
    constant MAX_OFFSET   : integer := 320 * 240 * 4;

    -- Signaux Capture (Domaine PCLK)
    signal cam_high_byte  : std_logic_vector(7 downto 0);
    signal cam_toggle     : std_logic := '0';
    signal fifo_data_in   : std_logic_vector(15 downto 0);
    signal fifo_wr_req    : std_logic := '0';

    -- Signaux DMA (Domaine CLK 50MHz)
    signal fifo_data_out  : std_logic_vector(15 downto 0);
    signal fifo_rd_req    : std_logic;
    signal fifo_empty     : std_logic;

    signal dma_addr       : unsigned(31 downto 0) := BASE_ADDRESS;
    signal writing_active : std_logic := '0';

    -- Synchro VSYNC (Passage de domaine PCLK -> CLK 50MHz)
    signal vsync_r1, vsync_r2 : std_logic;
    signal vsync_edge         : std_logic;

    -- Reconstruction Pixel
    signal r, g, b : std_logic_vector(7 downto 0);

begin

    -- ========================================================================
    -- 3. INSTANCIATION PLL (50MHz -> 25MHz)
    -- ========================================================================
    u_pll : component pll
        port map (
            refclk   => clk,
            rst      => not reset_n, -- Le reset système est actif bas, la PLL attend actif haut
            outclk_0 => cam_xclk,
            locked   => open         -- On laisse ouvert si on ne s'en sert pas pour une LED
        );

    -- ========================================================================
    -- 4. LOGIQUE DE CAPTURE (Domaine PCLK)
    -- ========================================================================
    process(cam_pclk)
    begin
        if rising_edge(cam_pclk) then
            -- Si VSYNC actif ou pas de HREF, on reset la machine à états de capture
            if cam_vsync = '1' or cam_href = '0' then
                cam_toggle  <= '0';
                fifo_wr_req <= '0';
            else
                -- Si ligne valide
                if cam_href = '1' then
                    cam_toggle <= not cam_toggle;

                    if cam_toggle = '0' then
                        -- Premier octet reçu (MSB du RGB565)
                        cam_high_byte <= cam_data;
                        fifo_wr_req   <= '0';
                    else
                        -- Deuxième octet reçu (LSB)
                        -- On concatène pour former le pixel 16 bits
                        fifo_data_in <= cam_high_byte & cam_data;
                        fifo_wr_req  <= '1'; -- On demande l'écriture dans la FIFO
                    end if;
                end if;
            end if;
        end if;
    end process;

    -- ========================================================================
    -- 5. INSTANCIATION FIFO DUAL CLOCK
    -- ========================================================================
    u_fifo : component camera_fifo
        port map (
            -- Coté Ecriture (Caméra)
            wrclk   => cam_pclk,
            data    => fifo_data_in,
            wrreq   => fifo_wr_req,
            wrfull  => open,

            -- Coté Lecture (Système Avalon)
            rdclk   => clk,
            rdreq   => fifo_rd_req,
            q       => fifo_data_out,
            rdempty => fifo_empty
        );

    -- ========================================================================
    -- 6. LOGIQUE DMA & AVALON (Domaine CLK 50MHz)
    -- ========================================================================

    -- Détection du VSYNC dans le domaine 50MHz (pour reset l'adresse mémoire)
    process(clk)
    begin
        if rising_edge(clk) then
            vsync_r1 <= cam_vsync;
            vsync_r2 <= vsync_r1;
        end if;
    end process;
    -- Détection front montant VSYNC
    vsync_edge <= '1' when (vsync_r1 = '1' and vsync_r2 = '0') else '0';

    -- Machine à états DMA
    process(clk, reset_n)
    begin
        if reset_n = '0' then
            dma_addr       <= BASE_ADDRESS;
            writing_active <= '0';
            fifo_rd_req    <= '0';

        elsif rising_edge(clk) then

            -- 1. Gestion du Reset Frame (VSYNC)
            -- Si la caméra commence une nouvelle image, on remet l'adresse au début
            if vsync_edge = '1' then
                dma_addr <= BASE_ADDRESS;
            end if;

            -- 2. Gestion de la fin d'écriture Avalon
            -- Si 'waitrequest' tombe à 0, l'écriture est validée par la DDR
            if avm_waitrequest = '0' then
                writing_active <= '0';
            end if;

            -- 3. Lancement d'une nouvelle écriture
            -- Si on n'écrit pas ET que la FIFO n'est pas vide
            if writing_active = '0' and fifo_empty = '0' then
                fifo_rd_req    <= '1'; -- On "pop" un pixel de la FIFO
                writing_active <= '1'; -- On lève le flag d'écriture pour Avalon

                -- Calcul adresse suivante (4 octets par pixel 32 bits)
                if dma_addr < (BASE_ADDRESS + MAX_OFFSET) then
                    dma_addr <= dma_addr + 4;
                else
                    dma_addr <= BASE_ADDRESS; -- Sécurité (bouclage)
                end if;
            else
                fifo_rd_req <= '0';
            end if;

        end if;
    end process;

    -- ========================================================================
    -- 7. CONVERSION DE DONNEES (RGB565 -> RGB32)
    -- ========================================================================

    -- Sortie FIFO (16 bits) : R[15:11], G[10:5], B[4:0]
    -- Conversion vers 32 bits : Alpha(8) - R(8) - G(8) - B(8)

    -- On décale les bits et on remplit les LSB avec des 0
    r <= fifo_data_out(15 downto 11) & "000";
    g <= fifo_data_out(10 downto 5)  & "00";
    b <= fifo_data_out(4 downto 0)   & "000";

    -- Mappage des sorties Avalon
    avm_address    <= std_logic_vector(dma_addr);
    avm_byteenable <= "1111"; -- Ecriture sur 32 bits (4 octets)
    avm_write      <= writing_active;

    -- Données : Alpha (Full Opaque) | Red | Green | Blue
    avm_writedata  <= x"FF" & r & g & b;

end architecture;

Ecriture dans la DDR

!!! ATTENTION : le bus avalon ne peut pas accéder à tout l'espace de la DDR
à vérifier mais ne marche pas à l'@ 0x3f000000
utiliser une zone mémoire à l'@ 0x30000000
il faut autoriser l'accès avec :
memtool mw -l 0xFFC25080 0x1F0


// a supprimer

  • dans uboot
mw 0xFFC25080 0x1F0
mw 0xFFC2505C 0xA
  • sur linux
memtool mw -l 0xFFC25080 0x1F0
memtool mw -l 0xFFC2505C 0xA


https://www.reddit.com/r/FPGA/comments/12mg5su/having_issues_writing_data_from_fpga_to_hps_using/?tl=fr

https://people.ece.cornell.edu/land/courses/ece5760/DE1_SOC/cv_5_HPS_tech_ref.pdf

  • fpga
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity fpga_dma_rgb32_simple is
  port (
    clk   : in  std_logic;
    reset : in  std_logic;

    -- Avalon-MM master
    avm_address     : out std_logic_vector(31 downto 0);
    avm_write       : out std_logic;
    avm_writedata   : out std_logic_vector(31 downto 0);
    avm_waitrequest : in  std_logic
  );
end entity;

architecture rtl of fpga_dma_rgb32_simple is

  constant BASE_ADDR    : unsigned(31 downto 0) := x"3FB00000";
  constant WIDTH        : integer := 640;
  constant HEIGHT       : integer := 480;
  constant TOTAL_PIXELS : integer := WIDTH * HEIGHT; -- 307200

  signal pixel_index : integer range 0 to TOTAL_PIXELS-1 := 0;
  signal addr        : unsigned(31 downto 0);
  signal write_reg   : std_logic := '0';

  -- Pattern RGB32 (XRGB8888)
  signal r, g, b    : unsigned(7 downto 0);
  signal pixel32    : unsigned(31 downto 0);

begin

  --------------------------------------------------------------------
  -- Générateur simple de pattern
  --------------------------------------------------------------------
  r <= to_unsigned((pixel_index mod WIDTH) * 255 / WIDTH, 8);
  g <= to_unsigned((pixel_index / WIDTH) * 255 / HEIGHT, 8);
  b <= to_unsigned(128, 8);

--  pixel32 <= x"00" & r & g & b;  -- XRGB8888
  pixel32 <= x"AAAAAAAA";  -- XRGB8888

  avm_writedata <= std_logic_vector(pixel32);

  --------------------------------------------------------------------
  -- Adresse courante
  --------------------------------------------------------------------
  addr <= BASE_ADDR + to_unsigned(pixel_index * 4, 32);

  avm_address <= std_logic_vector(addr);
  avm_write   <= write_reg;
  --------------------------------------------------------------------
  -- FSM simple
  --------------------------------------------------------------------
  process(clk)
  begin
    if rising_edge(clk) then
        if avm_waitrequest = '0' then
          write_reg <= '1';

          pixel_index <= pixel_index + 1;

          -- boucle image
          if pixel_index = TOTAL_PIXELS-1 then
            pixel_index <= 0;
          end if;
        else
          write_reg <= '0';
        end if;
    end if;
  end process;

end architecture;

I2C

Media:DE0-Nano-SoC_Schematic.pdf

  • on utilisera le bus i2c1
  • la vitesse est de 100kHz
    • dans le fichier device-tree
    • modifier speed-mode = <0x00>
      • 0x00 = Standard mode (100 kHz)
      • 0x01 = Fast mode (400 kHz)
  • broches
    • sur le connecteur LTC
    • ATTENTION : il faut mettre des résistances de Pull-Up !!!