Disabled external gits

This commit is contained in:
2022-04-07 18:54:11 +02:00
parent 15e7120d6d
commit 0fb3e365d4
376 changed files with 50840 additions and 0 deletions

169
cs309-psoc/lab_4_0/README Normal file
View File

@ -0,0 +1,169 @@
README
======
The file tree shown at the end of this README lists all the contents of the
provided template. In addition to the standard file hierarchy you have been
using for the previous labs, the template for this lab contains the VHDL files
and Linux kernel module of 2 new custom interfaces:
1) framebuffer device
2) VGA output
The hardware files are available under hw/hdl/displays/
The Linux kernel device tree is available under sw/hps/linux/device_tree/
The Linux kernel module is available under sw/hps/linux/driver/fbdev/
How to use the template
=======================
Background
==========
We need to re-create a linux system in this lab, but we cannot directly copy
and modify the one you created in the previous labs since some of the tools
used in the middle hard-code absolute paths in many generated files...
Therefore, we provide you with a shell script which performs all the steps
you did in lab 3.0 and 3.1 in order to get a bootable linux system. Namely
the script performs the following steps automatically:
1) Compiles the Quartus project.
2) Generates and compiles the Preloader.
3) Downloads and compiles U-Boot.
4) Downloads and compiles Linux.
5) Downloads and creates a Ubuntu 14.04.5 root filesystem.
6) Partitions the sdcard.
7) Writes all files to the sdcard.
BEFORE you start your mini-project
==================================
Follow the steps listed below in order to create a bootable sdcard
containing a Linux OS:
1) Replace all files indicated with the "OVERWRITE" label in the file
tree shown at the end of this README with the files you implemented
in the previous labs.
2) Plug in your sdcard into your Linux computer/VM and take note of the
identifier the OS assigned to it. This README assumes the identifier
assigned to the sdcard is "/dev/sdb".
WARNING : Be ABSOLUTELY SURE that you have the correct drive
identifier or else we will later accidentally format the
wrong drive!
3) Start an embedded command shell.
4) Execute the create_linux_system.sh script as follows:
$ ./create_linux_system.sh /dev/sdb
WARNING : Again, be absolutely sure that you have used the correct
drive identifier before running the command above!
The lower bound for the execution time of the script is around 25
minutes (the time it takes to compile all files). However, the script
also clones large git repositories, so the total execution time can
vary greatly depending on the download speed. Be patient :).
AFTER you start your mini-project
=================================
You can now follow the steps explained in the lab statement.
File tree
=========
lab_4_0_template/
├── create_hw_headers.sh
├── create_linux_system.sh
├── hw
│   ├── hdl
│   │   ├── DE0_Nano_SoC_PrSoC_extn_board_top_level.vhd
│   │   ├── displays
│   │   │   ├── framebuffer_manager
│   │   │   │   └── hdl
│   │   │   │   ├── dc_video_fifo.vhd
│   │   │   │   ├── framebuffer_manager_hw.tcl
│   │   │   │   └── framebuffer_manager.vhd
│   │   │   └── vga_sequencer
│   │   │   └── hdl
│   │   │   ├── vga_sequencer_hw.tcl
│   │   │   └── vga_sequencer.vhd
│   │   ├── joysticks
│   │   │   ├── hdl
│   │   │   │   ├── mcp3204_hw.tcl
│   │   │   │   ├── mcp3204_spi.vhd ------------------------> # OVERWRITE : Overwrite with your previous implementation.
│   │   │   │   └── mcp3204.vhd
│   │   │   └── tb
│   │   │   ├── tb_mcp3204_spi.vhd
│   │   │   └── tb_mcp3204.vhd
│   │   ├── lepton
│   │   │   ├── hdl
│   │   │   │   ├── avalon_st_spi_master.vhd
│   │   │   │   ├── byte2pix.vhd
│   │   │   │   ├── dual_ported_ram.vhd
│   │   │   │   ├── lepton_hw.tcl
│   │   │   │   ├── lepton_manager.vhd
│   │   │   │   ├── lepton_stats.vhd -----------------------> # OVERWRITE : Overwrite with your previous implementation.
│   │   │   │   ├── lepton.vhd
│   │   │   │   ├── level_adjuster.vhd ---------------------> # OVERWRITE : Overwrite with your previous implementation.
│   │   │   │   ├── lpm_divider.vhd
│   │   │   │   ├── ram_writer.vhd
│   │   │   │   └── utils.vhd
│   │   │   └── tb
│   │   │   └── lepton_tb.vhd
│   │   └── pantilt
│   │   ├── hdl
│   │   │   ├── pwm_constants.vhd ----------------------> # OVERWRITE : Overwrite with your previous implementation.
│   │   │   ├── pwm_hw.tcl
│   │   │   └── pwm.vhd --------------------------------> # OVERWRITE : Overwrite with your previous implementation.
│   │   └── tb
│   │   └── tb_pwm.vhd
│   ├── modelsim
│   └── quartus
│   ├── ip
│   │   └── components.ipx
│   ├── lab_4_0.qpf
│   ├── lab_4_0.qsf
│   ├── lab_4_0.sdc
│   └── soc_system.qsys
├── README
└── sw
└── hps
├── application
│   ├── hw_headers
│   └── lab_4_0
│   ├── app.c ----------------------------------> # TODO : Your lab_4_0 mini-project application code goes here.
│   ├── displays
│   │   ├── batman_320x240.jpg -----------------> # IMAGE : sample input images for "fbv" binary.
│   │   ├── batman_480x272.jpg -----------------> # IMAGE : sample input images for "fbv" binary.
│   │   ├── fb_multiple_buffering_example.c ----> # DEMO : how to use a framebuffer driver.
│   │   └── fbv --------------------------------> # BINARY : "framebuffer viewer" outputs an image to a framebuffer device (http://freecode.com/projects/fbv).
│   ├── io_custom.h
│   ├── joysticks
│   │   ├── joysticks.c ------------------------> # OVERWRITE : Overwrite with your previous implementation.
│   │   ├── joysticks.h ------------------------> # OVERWRITE : Overwrite with your previous implementation.
│   │   └── mcp3204
│   │   ├── mcp3204.c ----------------------> # OVERWRITE : Overwrite with your previous implementation.
│   │   ├── mcp3204.h ----------------------> # OVERWRITE : Overwrite with your previous implementation.
│   │   └── mcp3204_regs.h -----------------> # OVERWRITE : Overwrite with your previous implementation.
│   ├── lepton
│   │   ├── lepton.c ---------------------------> # OVERWRITE : Overwrite with your previous implementation.
│   │   ├── lepton.h ---------------------------> # OVERWRITE : Overwrite with your previous implementation.
│   │   └── lepton_regs.h ----------------------> # OVERWRITE : Overwrite with your previous implementation.
│   └── pantilt
│   ├── pantilt.c --------------------------> # OVERWRITE : Overwrite with your previous implementation.
│   ├── pantilt.h --------------------------> # OVERWRITE : Overwrite with your previous implementation.
│   └── pwm
│   ├── pwm.c --------------------------> # OVERWRITE : Overwrite with your previous implementation.
│   ├── pwm.h --------------------------> # OVERWRITE : Overwrite with your previous implementation.
│   └── pwm_regs.h ---------------------> # OVERWRITE : Overwrite with your previous implementation.
└── linux
├── device_tree
│   └── socfpga_cyclone5_de0_sockit_prsoc.dts --> # DEMO : source code of our custom device tree.
├── driver
│   └── fbdev
│   ├── Makefile ---------------------------> # DEMO : makefile of our custom framebuffer driver.
│   └── prsoc_fbdev.c ----------------------> # DEMO : source code of our custom framebuffer driver.
└── rootfs
├── config_post_install.sh
└── config_system.sh
35 directories, 59 files

View File

@ -0,0 +1,14 @@
#!/bin/bash -x
# make sure to be in the same directory as this script
script_dir_abs=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
cd "${script_dir_abs}"
rm -rf sw/hps/application/hw_headers
# create target directory if not present
mkdir -p sw/hps/application/hw_headers
sopc-create-header-files \
hw/quartus/soc_system.sopcinfo \
--output-dir sw/hps/application/hw_headers

View File

@ -0,0 +1,510 @@
#!/bin/bash -x
# ===================================================================================
# usage: create_linux_system.sh [sdcard_device]
#
# positional arguments:
# sdcard_device path to sdcard device file [ex: "/dev/sdb", "/dev/mmcblk0"]
# ===================================================================================
# make sure to be in the same directory as this script
script_dir_abs=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
cd "${script_dir_abs}"
# constants ####################################################################
quartus_dir="$(readlink -m "hw/quartus")"
quartus_project_name="$(basename "$(find "${quartus_dir}" -name "*.qpf")" .qpf)"
quartus_sof_file="$(readlink -m "${quartus_dir}/output_files/${quartus_project_name}.sof")"
fpga_device_part_number="5CSEMA4U23C6" # 5CSEMA5F31C6
preloader_dir="$(readlink -m "sw/hps/preloader")"
preloader_settings_dir="$(readlink -m "${quartus_dir}/hps_isw_handoff/soc_system_hps_0")"
preloader_settings_file="$(readlink -m "${preloader_dir}/settings.bsp")"
preloader_source_tgz_file="$(readlink -m "${SOCEDS_DEST_ROOT}/host_tools/altera/preloader/uboot-socfpga.tar.gz")"
preloader_bin_file="${preloader_dir}/preloader-mkpimage.bin"
uboot_src_dir="$(readlink -m "sw/hps/u-boot")"
uboot_src_git_repo="git://git.denx.de/u-boot.git"
uboot_src_git_checkout_commit="b104b3dc1dd90cdbf67ccf3c51b06e4f1592fe91"
uboot_src_make_config_file="socfpga_de0_nano_soc_defconfig" # socfpga_cyclone5_config
uboot_src_config_file="${uboot_src_dir}/include/configs/socfpga_de0_nano_soc.h" # socfpga_cyclone5_socdk.h
uboot_script_file="$(readlink -m "${uboot_src_dir}/u-boot.script")"
uboot_img_file="$(readlink -m "${uboot_src_dir}/u-boot.img")"
linux_dir="$(readlink -m "sw/hps/linux")"
linux_src_git_repo="https://github.com/altera-opensource/linux-socfpga.git"
linux_src_dir="$(readlink -m "${linux_dir}/source")"
linux_src_git_checkout_commit="9735a22799b9214d17d3c231fe377fc852f042e9"
linux_src_make_config_file="socfpga_defconfig"
linux_kernel_mem_arg="1024M"
linux_zImage_file="$(readlink -m "${linux_src_dir}/arch/arm/boot/zImage")"
linux_dtb_file="$(readlink -m "${linux_src_dir}/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dtb")" # socfpga_cyclone5_socdk.dtb
rootfs_dir="${linux_dir}/rootfs"
rootfs_chroot_dir="$(readlink -m ${rootfs_dir}/ubuntu-core-rootfs)"
rootfs_src_tgz_link="http://cdimage.ubuntu.com/ubuntu-base/releases/14.04.5/release/ubuntu-base-14.04.5-base-armhf.tar.gz"
rootfs_src_tgz_file="$(readlink -m "${rootfs_dir}/${rootfs_src_tgz_link##*/}")"
rootfs_system_config_script_file="${rootfs_dir}/config_system.sh"
rootfs_post_install_config_script_file="${rootfs_dir}/config_post_install.sh"
sdcard_fat32_dir="$(readlink -m "sdcard/fat32")"
sdcard_fat32_rbf_file="$(readlink -m "${sdcard_fat32_dir}/socfpga.rbf")"
sdcard_fat32_uboot_img_file="$(readlink -m "${sdcard_fat32_dir}/$(basename "${uboot_img_file}")")"
sdcard_fat32_uboot_scr_file="$(readlink -m "${sdcard_fat32_dir}/u-boot.scr")"
sdcard_fat32_zImage_file="$(readlink -m "${sdcard_fat32_dir}/zImage")"
sdcard_fat32_dtb_file="$(readlink -m "${sdcard_fat32_dir}/socfpga.dtb")"
sdcard_dev="$(readlink -m "${1}")"
sdcard_ext3_rootfs_tgz_file="$(readlink -m "sdcard/ext3_rootfs.tar.gz")"
sdcard_a2_dir="$(readlink -m "sdcard/a2")"
sdcard_a2_preloader_bin_file="$(readlink -m "${sdcard_a2_dir}/$(basename "${preloader_bin_file}")")"
sdcard_partition_size_fat32="32M"
sdcard_partition_size_linux="512M"
sdcard_partition_number_fat32="1"
sdcard_partition_number_ext3="2"
sdcard_partition_number_a2="3"
if [ "$(echo "${sdcard_dev}" | grep -P "/dev/sd\w.*$")" ]; then
sdcard_dev_fat32_id="${sdcard_partition_number_fat32}"
sdcard_dev_ext3_id="${sdcard_partition_number_ext3}"
sdcard_dev_a2_id="${sdcard_partition_number_a2}"
elif [ "$(echo "${sdcard_dev}" | grep -P "/dev/mmcblk\w.*$")" ]; then
sdcard_dev_fat32_id="p${sdcard_partition_number_fat32}"
sdcard_dev_ext3_id="p${sdcard_partition_number_ext3}"
sdcard_dev_a2_id="p${sdcard_partition_number_a2}"
fi
sdcard_dev_fat32="${sdcard_dev}${sdcard_dev_fat32_id}"
sdcard_dev_ext3="${sdcard_dev}${sdcard_dev_ext3_id}"
sdcard_dev_a2="${sdcard_dev}${sdcard_dev_a2_id}"
sdcard_dev_fat32_mount_point="$(readlink -m "sdcard/mount_point_fat32")"
sdcard_dev_ext3_mount_point="$(readlink -m "sdcard/mount_point_ext3")"
# compile_quartus_project() ####################################################
compile_quartus_project() {
# change working directory to quartus directory
pushd "${quartus_dir}"
# delete old artifacts
rm -rf "c5_pin_model_dump.txt" \
"db/" \
"hps_isw_handoff/" \
"hps_sdram_p0_all_pins.txt" \
"incremental_db/" \
"output_files/" \
"soc_system.sopcinfo" \
"soc_system/" \
"${quartus_project_name}.qws" \
"${sdcard_fat32_rbf_file}"
qsys-generate "soc_system.qsys" --synthesis=VHDL --output-directory="soc_system/" --part="${fpga_device_part_number}"
# Analysis and synthesis
quartus_map "${quartus_project_name}"
# Execute HPS DDR3 pin assignment TCL script
# it is normal for the following script to report an error, but it was
# sucessfully executed
ddr3_pin_assignment_script="$(find . -name "hps_sdram_p0_pin_assignments.tcl")"
quartus_sta -t "${ddr3_pin_assignment_script}" "${quartus_project_name}"
# Fitter
quartus_fit "${quartus_project_name}"
# Assembler
quartus_asm "${quartus_project_name}"
# convert .sof to .rbf in associated sdcard directory
quartus_cpf -c "${quartus_sof_file}" "${sdcard_fat32_rbf_file}"
# change working directory back to script directory
popd
}
# compile_preloader() ##########################################################
compile_preloader() {
# delete old artifacts
rm -rf "${preloader_dir}" \
"${sdcard_a2_preloader_bin_file}"
# create directory for preloader
mkdir -p "${preloader_dir}"
# change working directory to preloader directory
pushd "${preloader_dir}"
# create bsp settings file
bsp-create-settings \
--bsp-dir "${preloader_dir}" \
--preloader-settings-dir "${preloader_settings_dir}" \
--settings "${preloader_settings_file}" \
--type spl \
--set spl.CROSS_COMPILE "arm-altera-eabi-" \
--set spl.PRELOADER_TGZ "${preloader_source_tgz_file}" \
--set spl.boot.BOOTROM_HANDSHAKE_CFGIO "1" \
--set spl.boot.BOOT_FROM_NAND "0" \
--set spl.boot.BOOT_FROM_QSPI "0" \
--set spl.boot.BOOT_FROM_RAM "0" \
--set spl.boot.BOOT_FROM_SDMMC "1" \
--set spl.boot.CHECKSUM_NEXT_IMAGE "1" \
--set spl.boot.EXE_ON_FPGA "0" \
--set spl.boot.FAT_BOOT_PARTITION "1" \
--set spl.boot.FAT_LOAD_PAYLOAD_NAME "$(basename "${uboot_img_file}")" \
--set spl.boot.FAT_SUPPORT "1" \
--set spl.boot.FPGA_DATA_BASE "0xffff0000" \
--set spl.boot.FPGA_DATA_MAX_SIZE "0x10000" \
--set spl.boot.FPGA_MAX_SIZE "0x10000" \
--set spl.boot.NAND_NEXT_BOOT_IMAGE "0xc0000" \
--set spl.boot.QSPI_NEXT_BOOT_IMAGE "0x60000" \
--set spl.boot.RAMBOOT_PLLRESET "1" \
--set spl.boot.SDMMC_NEXT_BOOT_IMAGE "0x40000" \
--set spl.boot.SDRAM_SCRUBBING "0" \
--set spl.boot.SDRAM_SCRUB_BOOT_REGION_END "0x2000000" \
--set spl.boot.SDRAM_SCRUB_BOOT_REGION_START "0x1000000" \
--set spl.boot.SDRAM_SCRUB_REMAIN_REGION "1" \
--set spl.boot.STATE_REG_ENABLE "1" \
--set spl.boot.WARMRST_SKIP_CFGIO "1" \
--set spl.boot.WATCHDOG_ENABLE "1" \
--set spl.debug.DEBUG_MEMORY_ADDR "0xfffffd00" \
--set spl.debug.DEBUG_MEMORY_SIZE "0x200" \
--set spl.debug.DEBUG_MEMORY_WRITE "0" \
--set spl.debug.HARDWARE_DIAGNOSTIC "0" \
--set spl.debug.SEMIHOSTING "0" \
--set spl.debug.SKIP_SDRAM "0" \
--set spl.performance.SERIAL_SUPPORT "1" \
--set spl.reset_assert.DMA "0" \
--set spl.reset_assert.GPIO0 "0" \
--set spl.reset_assert.GPIO1 "0" \
--set spl.reset_assert.GPIO2 "0" \
--set spl.reset_assert.L4WD1 "0" \
--set spl.reset_assert.OSC1TIMER1 "0" \
--set spl.reset_assert.SDR "0" \
--set spl.reset_assert.SPTIMER0 "0" \
--set spl.reset_assert.SPTIMER1 "0" \
--set spl.warm_reset_handshake.ETR "1" \
--set spl.warm_reset_handshake.FPGA "1" \
--set spl.warm_reset_handshake.SDRAM "0"
# generate bsp
bsp-generate-files \
--bsp-dir "${preloader_dir}" \
--settings "${preloader_settings_file}"
# compile preloader
make -j4
# copy artifacts to associated sdcard directory
cp "${preloader_bin_file}" "${sdcard_a2_preloader_bin_file}"
# change working directory back to script directory
popd
}
# compile_uboot ################################################################
compile_uboot() {
# delete old artifacts
rm -rf "${sdcard_fat32_uboot_scr_file}" \
"${sdcard_fat32_uboot_img_file}"
# if uboot source tree doesn't exist, then download it
if [ ! -d "${uboot_src_dir}" ]; then
git clone "${uboot_src_git_repo}" "${uboot_src_dir}"
fi
# change working directory to uboot source tree directory
pushd "${uboot_src_dir}"
# use cross compiler instead of standard x86 version of gcc
export CROSS_COMPILE=arm-linux-gnueabihf-
# clean up source tree
make distclean
# checkout the following commit (tested and working):
git checkout "${uboot_src_git_checkout_commit}"
# configure uboot for socfpga_cyclone5 architecture
make "${uboot_src_make_config_file}"
## patch the uboot configuration file that describes environment variables
# replace value of CONFIG_BOOTCOMMAND macro (we will always use a script for configuring everything)
# result:
# #define CONFIG_BOOTCOMMAND "run callscript"
perl -pi -e 's/^(#define\s+CONFIG_BOOTCOMMAND)(.*)/$1\t"run callscript"/g' "${uboot_src_config_file}"
# replace value of CONFIG_EXTRA_ENV_SETTINGS macro
# result:
# #define CONFIG_EXTRA_ENV_SETTINGS \
# "scriptfile=u-boot.scr" "\0" \
# "fpgadata=0x2000000" "\0" \
# "callscript=fatload mmc 0:1 $fpgadata $scriptfile;" \
# "source $fpgadata" "\0"
perl -pi -e 'BEGIN{undef $/;} s/^(#define\s+CONFIG_EXTRA_ENV_SETTINGS)(.*)#include/$1\t"scriptfile=u-boot.scr\\0" "fpgadata=0x2000000\\0" "callscript=fatload mmc 0:1 \$fpgadata \$scriptfile; source \$fpgadata\\0"\n\n#include/smg' "${uboot_src_config_file}"
# compile uboot
make -j4
# create uboot script
cat <<EOF > "${uboot_script_file}"
################################################################################
echo --- Resetting Env variables ---
# reset environment variables to default
env default -a
echo --- Setting Env variables ---
# Set the kernel image
setenv bootimage $(basename ${sdcard_fat32_zImage_file});
# address to which the device tree will be loaded
setenv fdtaddr 0x00000100
# Set the devicetree image
setenv fdtimage $(basename ${sdcard_fat32_dtb_file});
# set kernel boot arguments, then boot the kernel
setenv mmcboot 'setenv bootargs mem=${linux_kernel_mem_arg} console=ttyS0,115200 root=\${mmcroot} rw rootwait; \
bootz \${loadaddr} - \${fdtaddr}';
# load linux kernel image and device tree to memory
setenv mmcload 'mmc rescan; \
\${mmcloadcmd} mmc 0:\${mmcloadpart} \${loadaddr} \${bootimage}; \
\${mmcloadcmd} mmc 0:\${mmcloadpart} \${fdtaddr} \${fdtimage}'
# command to be executed to read from sdcard
setenv mmcloadcmd fatload
# sdcard fat32 partition number
setenv mmcloadpart ${sdcard_partition_number_fat32}
# sdcard ext3 identifier
setenv mmcroot /dev/mmcblk0p${sdcard_partition_number_ext3}
# standard input/output
setenv stderr serial
setenv stdin serial
setenv stdout serial
# save environment to sdcard (not needed, but useful to avoid CRC errors on a new sdcard)
saveenv
################################################################################
echo --- Programming FPGA ---
# load rbf from FAT partition into memory
fatload mmc 0:1 \${fpgadata} $(basename ${sdcard_fat32_rbf_file});
# program FPGA
fpga load 0 \${fpgadata} \${filesize};
# enable HPS-to-FPGA, FPGA-to-HPS, LWHPS-to-FPGA bridges
bridge enable;
################################################################################
echo --- Booting Linux ---
# load linux kernel image and device tree to memory
run mmcload;
# set kernel boot arguments, then boot the kernel
run mmcboot;
EOF
# compile uboot script to binary form
mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "${quartus_project_name}" -d "${uboot_script_file}" "${sdcard_fat32_uboot_scr_file}"
# copy artifacts to associated sdcard directory
cp "${uboot_img_file}" "${sdcard_fat32_uboot_img_file}"
# change working directory back to script directory
popd
}
# compile_linux() ##############################################################
compile_linux() {
# if linux source tree doesn't exist, then download it
if [ ! -d "${linux_src_dir}" ]; then
git clone "${linux_src_git_repo}" "${linux_src_dir}"
fi
# change working directory to linux source tree directory
pushd "${linux_src_dir}"
# compile for the ARM architecture
export ARCH=arm
# use cross compiler instead of standard x86 version of gcc
export CROSS_COMPILE=arm-linux-gnueabihf-
# clean up source tree
make distclean
# checkout the following commit (tested and working):
git checkout "${linux_src_git_checkout_commit}"
# configure kernel for socfpga architecture
make "${linux_src_make_config_file}"
# compile zImage
make -j4 zImage
# compile device tree
make -j4 "$(basename "${linux_dtb_file}")"
# copy artifacts to associated sdcard directory
cp "${linux_zImage_file}" "${sdcard_fat32_zImage_file}"
cp "${linux_dtb_file}" "${sdcard_fat32_dtb_file}"
# change working directory back to script directory
popd
}
# create_rootfs() ##############################################################
create_rootfs() {
# if rootfs tarball doesn't exist, then download it
if [ ! -f "${rootfs_src_tgz_file}" ]; then
wget "${rootfs_src_tgz_link}" -O "${rootfs_src_tgz_file}"
fi
# delete old artifacts
sudo rm -rf "${rootfs_chroot_dir}" \
"${sdcard_ext3_rootfs_tgz_file}"
# create dir to extract rootfs
mkdir -p "${rootfs_chroot_dir}"
# extract ubuntu core rootfs
pushd "${rootfs_chroot_dir}"
sudo tar -xzpf "${rootfs_src_tgz_file}"
popd
# copy chroot SYSTEM configuration script to chroot directory
sudo cp "${rootfs_system_config_script_file}" "${rootfs_chroot_dir}"
# edit chroot environment's /etc/rc.local to execute the rootfs
# configuration script
sudo tee "${rootfs_chroot_dir}/etc/rc.local" > "/dev/null" <<EOF
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
/$(basename ${rootfs_system_config_script_file})
exit 0
EOF
# copy chroot POST-INSTALL configuration script to chroot directory
sudo cp "${rootfs_post_install_config_script_file}" "${rootfs_chroot_dir}"
# create archive of updated rootfs
pushd "${rootfs_chroot_dir}"
sudo tar -czpf "${sdcard_ext3_rootfs_tgz_file}" .
popd
}
# partition_sdcard() ###########################################################
partition_sdcard() {
# manually partitioning the sdcard
# sudo fdisk /dev/sdx
# use the following commands
# n p 3 <default> 4095 t a2 (2048 is default first sector)
# n p 1 <default> +32M t 1 b (4096 is default first sector)
# n p 2 <default> +512M t 2 83 (69632 is default first sector)
# w
# result
# Device Boot Start End Sectors Size Id Type
# /dev/sdb1 4096 69631 65536 32M b W95 FAT32
# /dev/sdb2 69632 1118207 1048576 512M 83 Linux
# /dev/sdb3 2048 4095 2048 1M a2 unknown
# note that you can choose any size for the FAT32 and Linux partitions,
# but the a2 partition must be 1M.
# automatically partitioning the sdcard
# wipe partition table
sudo dd if="/dev/zero" of="${sdcard_dev}" bs=512 count=1
# create partitions
# no need to specify the partition number for the first invocation of
# the "t" command in fdisk, because there is only 1 partition at this
# point
echo -e "n\np\n3\n\n4095\nt\na2\nn\np\n1\n\n+${sdcard_partition_size_fat32}\nt\n1\nb\nn\np\n2\n\n+${sdcard_partition_size_linux}\nt\n2\n83\nw\nq\n" | sudo fdisk "${sdcard_dev}"
# create filesystems
sudo mkfs.vfat "${sdcard_dev_fat32}"
sudo mkfs.ext3 -F "${sdcard_dev_ext3}"
}
# write_sdcard() ###############################################################
write_sdcard() {
# create mount point for sdcard
mkdir -p "${sdcard_dev_fat32_mount_point}"
mkdir -p "${sdcard_dev_ext3_mount_point}"
# mount sdcard partitions
sudo mount "${sdcard_dev_fat32}" "${sdcard_dev_fat32_mount_point}"
sudo mount "${sdcard_dev_ext3}" "${sdcard_dev_ext3_mount_point}"
# preloader
sudo dd if="${sdcard_a2_preloader_bin_file}" of="${sdcard_dev_a2}" bs=64K seek=0
# fpga .rbf, uboot .img, uboot .scr, linux zImage, linux .dtb
sudo cp "${sdcard_fat32_dir}"/* "${sdcard_dev_fat32_mount_point}"
# linux rootfs
pushd "${sdcard_dev_ext3_mount_point}"
sudo tar -xzf "${sdcard_ext3_rootfs_tgz_file}"
popd
# flush write buffers to target
sudo sync
# unmount sdcard partitions
sudo umount "${sdcard_dev_fat32_mount_point}"
sudo umount "${sdcard_dev_ext3_mount_point}"
# delete mount points for sdcard
rm -rf "${sdcard_dev_fat32_mount_point}"
rm -rf "${sdcard_dev_ext3_mount_point}"
}
# Script execution #############################################################
# Report script line number on any error (non-zero exit code).
trap 'echo "Error on line ${LINENO}" 1>&2' ERR
set -e
# Create sdcard output directories
mkdir -p "${sdcard_a2_dir}"
mkdir -p "${sdcard_fat32_dir}"
compile_quartus_project
compile_preloader
compile_uboot
compile_linux
create_rootfs
# Write sdcard if it exists
if [ -z "${sdcard_dev}" ]; then
echo "sdcard argument not provided => no sdcard written."
elif [ -b "${sdcard_dev}" ]; then
partition_sdcard
write_sdcard
fi
# Make sure MSEL = 000000

View File

@ -0,0 +1,347 @@
-- #############################################################################
-- DE0_Nano_SoC_PrSoC_extn_board_top_level.vhd
--
-- BOARD : PrSoC extension board for DE0-Nano-SoC
-- Author : Florian Depraz based on Sahand Kashani-Akhavan work
-- Revision : 1.1
-- Creation date : 06/02/2016
--
-- Syntax Rule : GROUP_NAME_N[bit]
--
-- GROUP : specify a particular interface (ex: SDR_)
-- NAME : signal name (ex: CONFIG, D, ...)
-- bit : signal index
-- _N : to specify an active-low signal
-- #############################################################################
library ieee;
use ieee.std_logic_1164.all;
entity DE0_Nano_SoC_PrSoC_extn_board_top_level is
port(
-------------------------------
-- Comment ALL unused ports. --
-------------------------------
-- CLOCK
FPGA_CLK1_50 : in std_logic;
-- FPGA_CLK2_50 : in std_logic;
-- FPGA_CLK3_50 : in std_logic;
-- KEY on DE0 Nano SoC
KEY_N : in std_logic_vector(1 downto 0);
-- LEDs on DE0 Nano SoC
-- LED : out std_logic_vector(7 downto 0);
-- SWITCHES on DE0 Nano SoC
-- SW : in std_logic_vector(3 downto 0);
-- Servomotors pwm
SERVO_0 : out std_logic;
SERVO_1 : out std_logic;
-- ADC Joysticks
J0_SPI_CS_n : out std_logic;
J0_SPI_MOSI : out std_logic;
J0_SPI_MISO : in std_logic;
J0_SPI_CLK : out std_logic;
-- Lepton
CAM_TH_SPI_CS_N : out std_logic;
CAM_TH_MISO : in std_logic;
CAM_TH_MOSI : out std_logic;
CAM_TH_CLK : out std_logic;
-- PCA9637
-- PIO_SCL : inout std_logic;
-- PIO_SDA : inout std_logic;
-- PIO_INT_N : in std_logic;
-- RESET_N : out std_logic;
-- OV7670
-- CAM_D : in std_logic_vector(9 downto 0);
-- CAM_PIX_CLK : in std_logic;
-- CAM_LV : in std_logic;
-- CAM_FV : in std_logic;
-- CAM_SYS_CLK : out std_logic;
-- VGA and LCD shared signals
VIDEO_CLK : out std_logic;
VIDEO_VSYNC : out std_logic;
VIDEO_HSYNC : out std_logic;
VIDEO_B : out std_logic_vector(7 downto 0);
VIDEO_G : out std_logic_vector(7 downto 0);
VIDEO_R : out std_logic_vector(7 downto 0);
-- LCD Specific signals
LCD_DE : out std_logic;
-- LCD_PIN_DAV_N : ? ?? std_logic;
LCD_DISPLAY_EN : out std_logic;
-- SPI_MISO : in std_logic;
-- SPI_ENA_N : out std_logic;
-- SPI_CLK : out std_logic;
-- SPI_MOSI : out std_logic;
-- SPI_DAT : inout std_logic;
-- I2C TOUCH SCREEN
-- TS_SCL : inout std_logic;
-- TS_SDA : inout std_logic;
-- BLUETOOTH (BLE)
-- BLT_TXD : in std_logic;
-- BLT_RXD : out std_logic;
-- I2C For VGA, PAL and OV7670 cameras
-- CAM_PAL_VGA_SDA : inout std_logic;
-- CAM_PAL_VGA_SCL : inout std_logic;
-- ONE WIRE
-- BOARD_ID : inout std_logic;
-- PAL Camera
-- PAL_VD_VD : in std_logic_vector(7 downto 0);
-- PAL_VD_VSO : in std_logic;
-- PAL_VD_HSO : in std_logic;
-- PAL_VD_CLKO : in std_logic;
-- PAL_PWDN : out std_logic;
-- WIFI
-- FROM_ESP_TXD : in std_logic;
-- TO_ESP_RXD : out std_logic;
-- LED RGB
-- LED_BGR : out std_logic;
-- HPS
HPS_CONV_USB_N : inout std_logic;
HPS_DDR3_ADDR : out std_logic_vector(14 downto 0);
HPS_DDR3_BA : out std_logic_vector(2 downto 0);
HPS_DDR3_CAS_N : out std_logic;
HPS_DDR3_CK_N : out std_logic;
HPS_DDR3_CK_P : out std_logic;
HPS_DDR3_CKE : out std_logic;
HPS_DDR3_CS_N : out std_logic;
HPS_DDR3_DM : out std_logic_vector(3 downto 0);
HPS_DDR3_DQ : inout std_logic_vector(31 downto 0);
HPS_DDR3_DQS_N : inout std_logic_vector(3 downto 0);
HPS_DDR3_DQS_P : inout std_logic_vector(3 downto 0);
HPS_DDR3_ODT : out std_logic;
HPS_DDR3_RAS_N : out std_logic;
HPS_DDR3_RESET_N : out std_logic;
HPS_DDR3_RZQ : in std_logic;
HPS_DDR3_WE_N : out std_logic;
HPS_ENET_GTX_CLK : out std_logic;
HPS_ENET_INT_N : inout std_logic;
HPS_ENET_MDC : out std_logic;
HPS_ENET_MDIO : inout std_logic;
HPS_ENET_RX_CLK : in std_logic;
HPS_ENET_RX_DATA : in std_logic_vector(3 downto 0);
HPS_ENET_RX_DV : in std_logic;
HPS_ENET_TX_DATA : out std_logic_vector(3 downto 0);
HPS_ENET_TX_EN : out std_logic;
HPS_GSENSOR_INT : inout std_logic;
HPS_I2C0_SCLK : inout std_logic;
HPS_I2C0_SDAT : inout std_logic;
HPS_I2C1_SCLK : inout std_logic;
HPS_I2C1_SDAT : inout std_logic;
HPS_KEY_N : inout std_logic;
HPS_LED : inout std_logic;
HPS_LTC_GPIO : inout std_logic;
HPS_SD_CLK : out std_logic;
HPS_SD_CMD : inout std_logic;
HPS_SD_DATA : inout std_logic_vector(3 downto 0);
HPS_SPIM_CLK : out std_logic;
HPS_SPIM_MISO : in std_logic;
HPS_SPIM_MOSI : out std_logic;
HPS_SPIM_SS : inout std_logic;
HPS_UART_RX : in std_logic;
HPS_UART_TX : out std_logic;
HPS_USB_CLKOUT : in std_logic;
HPS_USB_DATA : inout std_logic_vector(7 downto 0);
HPS_USB_DIR : in std_logic;
HPS_USB_NXT : in std_logic;
HPS_USB_STP : out std_logic
);
end entity DE0_Nano_SoC_PrSoC_extn_board_top_level;
architecture rtl of DE0_Nano_SoC_PrSoC_extn_board_top_level is
component soc_system is
port(
clk_clk : in std_logic := 'X';
reset_reset_n : in std_logic := 'X';
hps_0_ddr_mem_a : out std_logic_vector(14 downto 0);
hps_0_ddr_mem_ba : out std_logic_vector(2 downto 0);
hps_0_ddr_mem_ck : out std_logic;
hps_0_ddr_mem_ck_n : out std_logic;
hps_0_ddr_mem_cke : out std_logic;
hps_0_ddr_mem_cs_n : out std_logic;
hps_0_ddr_mem_ras_n : out std_logic;
hps_0_ddr_mem_cas_n : out std_logic;
hps_0_ddr_mem_we_n : out std_logic;
hps_0_ddr_mem_reset_n : out std_logic;
hps_0_ddr_mem_dq : inout std_logic_vector(31 downto 0) := (others => 'X');
hps_0_ddr_mem_dqs : inout std_logic_vector(3 downto 0) := (others => 'X');
hps_0_ddr_mem_dqs_n : inout std_logic_vector(3 downto 0) := (others => 'X');
hps_0_ddr_mem_odt : out std_logic;
hps_0_ddr_mem_dm : out std_logic_vector(3 downto 0);
hps_0_ddr_oct_rzqin : in std_logic := 'X';
hps_0_io_hps_io_emac1_inst_TX_CLK : out std_logic;
hps_0_io_hps_io_emac1_inst_TX_CTL : out std_logic;
hps_0_io_hps_io_emac1_inst_TXD0 : out std_logic;
hps_0_io_hps_io_emac1_inst_TXD1 : out std_logic;
hps_0_io_hps_io_emac1_inst_TXD2 : out std_logic;
hps_0_io_hps_io_emac1_inst_TXD3 : out std_logic;
hps_0_io_hps_io_emac1_inst_RX_CLK : in std_logic := 'X';
hps_0_io_hps_io_emac1_inst_RX_CTL : in std_logic := 'X';
hps_0_io_hps_io_emac1_inst_RXD0 : in std_logic := 'X';
hps_0_io_hps_io_emac1_inst_RXD1 : in std_logic := 'X';
hps_0_io_hps_io_emac1_inst_RXD2 : in std_logic := 'X';
hps_0_io_hps_io_emac1_inst_RXD3 : in std_logic := 'X';
hps_0_io_hps_io_emac1_inst_MDIO : inout std_logic := 'X';
hps_0_io_hps_io_emac1_inst_MDC : out std_logic;
hps_0_io_hps_io_sdio_inst_CLK : out std_logic;
hps_0_io_hps_io_sdio_inst_CMD : inout std_logic := 'X';
hps_0_io_hps_io_sdio_inst_D0 : inout std_logic := 'X';
hps_0_io_hps_io_sdio_inst_D1 : inout std_logic := 'X';
hps_0_io_hps_io_sdio_inst_D2 : inout std_logic := 'X';
hps_0_io_hps_io_sdio_inst_D3 : inout std_logic := 'X';
hps_0_io_hps_io_usb1_inst_CLK : in std_logic := 'X';
hps_0_io_hps_io_usb1_inst_STP : out std_logic;
hps_0_io_hps_io_usb1_inst_DIR : in std_logic := 'X';
hps_0_io_hps_io_usb1_inst_NXT : in std_logic := 'X';
hps_0_io_hps_io_usb1_inst_D0 : inout std_logic := 'X';
hps_0_io_hps_io_usb1_inst_D1 : inout std_logic := 'X';
hps_0_io_hps_io_usb1_inst_D2 : inout std_logic := 'X';
hps_0_io_hps_io_usb1_inst_D3 : inout std_logic := 'X';
hps_0_io_hps_io_usb1_inst_D4 : inout std_logic := 'X';
hps_0_io_hps_io_usb1_inst_D5 : inout std_logic := 'X';
hps_0_io_hps_io_usb1_inst_D6 : inout std_logic := 'X';
hps_0_io_hps_io_usb1_inst_D7 : inout std_logic := 'X';
hps_0_io_hps_io_spim1_inst_CLK : out std_logic;
hps_0_io_hps_io_spim1_inst_MOSI : out std_logic;
hps_0_io_hps_io_spim1_inst_MISO : in std_logic := 'X';
hps_0_io_hps_io_spim1_inst_SS0 : out std_logic;
hps_0_io_hps_io_uart0_inst_RX : in std_logic := 'X';
hps_0_io_hps_io_uart0_inst_TX : out std_logic;
hps_0_io_hps_io_i2c0_inst_SDA : inout std_logic := 'X';
hps_0_io_hps_io_i2c0_inst_SCL : inout std_logic := 'X';
hps_0_io_hps_io_i2c1_inst_SDA : inout std_logic := 'X';
hps_0_io_hps_io_i2c1_inst_SCL : inout std_logic := 'X';
hps_0_io_hps_io_gpio_inst_GPIO09 : inout std_logic := 'X';
hps_0_io_hps_io_gpio_inst_GPIO35 : inout std_logic := 'X';
hps_0_io_hps_io_gpio_inst_GPIO40 : inout std_logic := 'X';
hps_0_io_hps_io_gpio_inst_GPIO53 : inout std_logic := 'X';
hps_0_io_hps_io_gpio_inst_GPIO54 : inout std_logic := 'X';
hps_0_io_hps_io_gpio_inst_GPIO61 : inout std_logic := 'X';
pwm_0_conduit_end_pwm : out std_logic;
pwm_1_conduit_end_pwm : out std_logic;
mcp3204_0_conduit_end_cs_n : out std_logic;
mcp3204_0_conduit_end_mosi : out std_logic;
mcp3204_0_conduit_end_miso : in std_logic := 'X';
mcp3204_0_conduit_end_sclk : out std_logic;
lepton_0_spi_cs_n : out std_logic;
lepton_0_spi_mosi : out std_logic;
lepton_0_spi_miso : in std_logic := 'X';
lepton_0_spi_sclk : out std_logic;
pixclk_clk : out std_logic;
vga_hsync : out std_logic;
vga_vsync : out std_logic;
vga_r : out std_logic_vector(7 downto 0);
vga_g : out std_logic_vector(7 downto 0);
vga_b : out std_logic_vector(7 downto 0);
vga_de : out std_logic
);
end component soc_system;
begin
soc_system_inst : component soc_system
port map(
clk_clk => FPGA_CLK1_50,
reset_reset_n => KEY_N(0),
hps_0_ddr_mem_a => HPS_DDR3_ADDR,
hps_0_ddr_mem_ba => HPS_DDR3_BA,
hps_0_ddr_mem_ck => HPS_DDR3_CK_P,
hps_0_ddr_mem_ck_n => HPS_DDR3_CK_N,
hps_0_ddr_mem_cke => HPS_DDR3_CKE,
hps_0_ddr_mem_cs_n => HPS_DDR3_CS_N,
hps_0_ddr_mem_ras_n => HPS_DDR3_RAS_N,
hps_0_ddr_mem_cas_n => HPS_DDR3_CAS_N,
hps_0_ddr_mem_we_n => HPS_DDR3_WE_N,
hps_0_ddr_mem_reset_n => HPS_DDR3_RESET_N,
hps_0_ddr_mem_dq => HPS_DDR3_DQ,
hps_0_ddr_mem_dqs => HPS_DDR3_DQS_P,
hps_0_ddr_mem_dqs_n => HPS_DDR3_DQS_N,
hps_0_ddr_mem_odt => HPS_DDR3_ODT,
hps_0_ddr_mem_dm => HPS_DDR3_DM,
hps_0_ddr_oct_rzqin => HPS_DDR3_RZQ,
hps_0_io_hps_io_emac1_inst_TX_CLK => HPS_ENET_GTX_CLK,
hps_0_io_hps_io_emac1_inst_TX_CTL => HPS_ENET_TX_EN,
hps_0_io_hps_io_emac1_inst_TXD0 => HPS_ENET_TX_DATA(0),
hps_0_io_hps_io_emac1_inst_TXD1 => HPS_ENET_TX_DATA(1),
hps_0_io_hps_io_emac1_inst_TXD2 => HPS_ENET_TX_DATA(2),
hps_0_io_hps_io_emac1_inst_TXD3 => HPS_ENET_TX_DATA(3),
hps_0_io_hps_io_emac1_inst_RX_CLK => HPS_ENET_RX_CLK,
hps_0_io_hps_io_emac1_inst_RX_CTL => HPS_ENET_RX_DV,
hps_0_io_hps_io_emac1_inst_RXD0 => HPS_ENET_RX_DATA(0),
hps_0_io_hps_io_emac1_inst_RXD1 => HPS_ENET_RX_DATA(1),
hps_0_io_hps_io_emac1_inst_RXD2 => HPS_ENET_RX_DATA(2),
hps_0_io_hps_io_emac1_inst_RXD3 => HPS_ENET_RX_DATA(3),
hps_0_io_hps_io_emac1_inst_MDIO => HPS_ENET_MDIO,
hps_0_io_hps_io_emac1_inst_MDC => HPS_ENET_MDC,
hps_0_io_hps_io_sdio_inst_CLK => HPS_SD_CLK,
hps_0_io_hps_io_sdio_inst_CMD => HPS_SD_CMD,
hps_0_io_hps_io_sdio_inst_D0 => HPS_SD_DATA(0),
hps_0_io_hps_io_sdio_inst_D1 => HPS_SD_DATA(1),
hps_0_io_hps_io_sdio_inst_D2 => HPS_SD_DATA(2),
hps_0_io_hps_io_sdio_inst_D3 => HPS_SD_DATA(3),
hps_0_io_hps_io_usb1_inst_CLK => HPS_USB_CLKOUT,
hps_0_io_hps_io_usb1_inst_STP => HPS_USB_STP,
hps_0_io_hps_io_usb1_inst_DIR => HPS_USB_DIR,
hps_0_io_hps_io_usb1_inst_NXT => HPS_USB_NXT,
hps_0_io_hps_io_usb1_inst_D0 => HPS_USB_DATA(0),
hps_0_io_hps_io_usb1_inst_D1 => HPS_USB_DATA(1),
hps_0_io_hps_io_usb1_inst_D2 => HPS_USB_DATA(2),
hps_0_io_hps_io_usb1_inst_D3 => HPS_USB_DATA(3),
hps_0_io_hps_io_usb1_inst_D4 => HPS_USB_DATA(4),
hps_0_io_hps_io_usb1_inst_D5 => HPS_USB_DATA(5),
hps_0_io_hps_io_usb1_inst_D6 => HPS_USB_DATA(6),
hps_0_io_hps_io_usb1_inst_D7 => HPS_USB_DATA(7),
hps_0_io_hps_io_spim1_inst_CLK => HPS_SPIM_CLK,
hps_0_io_hps_io_spim1_inst_MOSI => HPS_SPIM_MOSI,
hps_0_io_hps_io_spim1_inst_MISO => HPS_SPIM_MISO,
hps_0_io_hps_io_spim1_inst_SS0 => HPS_SPIM_SS,
hps_0_io_hps_io_uart0_inst_RX => HPS_UART_RX,
hps_0_io_hps_io_uart0_inst_TX => HPS_UART_TX,
hps_0_io_hps_io_i2c0_inst_SDA => HPS_I2C0_SDAT,
hps_0_io_hps_io_i2c0_inst_SCL => HPS_I2C0_SCLK,
hps_0_io_hps_io_i2c1_inst_SDA => HPS_I2C1_SDAT,
hps_0_io_hps_io_i2c1_inst_SCL => HPS_I2C1_SCLK,
hps_0_io_hps_io_gpio_inst_GPIO09 => HPS_CONV_USB_N,
hps_0_io_hps_io_gpio_inst_GPIO35 => HPS_ENET_INT_N,
hps_0_io_hps_io_gpio_inst_GPIO40 => HPS_LTC_GPIO,
hps_0_io_hps_io_gpio_inst_GPIO53 => HPS_LED,
hps_0_io_hps_io_gpio_inst_GPIO54 => HPS_KEY_N,
hps_0_io_hps_io_gpio_inst_GPIO61 => HPS_GSENSOR_INT,
pwm_0_conduit_end_pwm => SERVO_0,
pwm_1_conduit_end_pwm => SERVO_1,
mcp3204_0_conduit_end_cs_n => J0_SPI_CS_n,
mcp3204_0_conduit_end_mosi => J0_SPI_MOSI,
mcp3204_0_conduit_end_miso => J0_SPI_MISO,
mcp3204_0_conduit_end_sclk => J0_SPI_CLK,
lepton_0_spi_cs_n => CAM_TH_SPI_CS_N,
lepton_0_spi_mosi => CAM_TH_MOSI,
lepton_0_spi_miso => CAM_TH_MISO,
lepton_0_spi_sclk => CAM_TH_CLK,
pixclk_clk => VIDEO_CLK,
vga_hsync => VIDEO_HSYNC,
vga_vsync => VIDEO_VSYNC,
vga_r => VIDEO_R,
vga_g => VIDEO_G,
vga_b => VIDEO_B,
vga_de => LCD_DE
);
LCD_DISPLAY_EN <= '1';
end;

View File

@ -0,0 +1,214 @@
-- megafunction wizard: %FIFO%
-- GENERATION: STANDARD
-- VERSION: WM1.0
-- MODULE: dcfifo_mixed_widths
-- ============================================================
-- File Name: dc_video_fifo.vhd
-- Megafunction Name(s):
-- dcfifo_mixed_widths
--
-- Simulation Library Files(s):
-- altera_mf
-- ============================================================
-- ************************************************************
-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
--
-- 15.1.0 Build 185 10/21/2015 SJ Lite Edition
-- ************************************************************
--Copyright (C) 1991-2015 Altera Corporation. All rights reserved.
--Your use of Altera Corporation's design tools, logic functions
--and other software and tools, and its AMPP partner logic
--functions, and any output files from any of the foregoing
--(including device programming or simulation files), and any
--associated documentation or information are expressly subject
--to the terms and conditions of the Altera Program License
--Subscription Agreement, the Altera Quartus Prime License Agreement,
--the Altera MegaCore Function License Agreement, or other
--applicable license agreement, including, without limitation,
--that your use is for the sole purpose of programming logic
--devices manufactured by Altera and sold by Altera or its
--authorized distributors. Please refer to the applicable
--agreement for further details.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.all;
ENTITY dc_video_fifo IS
PORT
(
aclr : IN STD_LOGIC := '0';
data : IN STD_LOGIC_VECTOR (95 DOWNTO 0);
rdclk : IN STD_LOGIC ;
rdreq : IN STD_LOGIC ;
wrclk : IN STD_LOGIC ;
wrreq : IN STD_LOGIC ;
q : OUT STD_LOGIC_VECTOR (23 DOWNTO 0);
rdempty : OUT STD_LOGIC ;
wrusedw : OUT STD_LOGIC_VECTOR (8 DOWNTO 0)
);
END dc_video_fifo;
ARCHITECTURE SYN OF dc_video_fifo IS
SIGNAL sub_wire0 : STD_LOGIC_VECTOR (23 DOWNTO 0);
SIGNAL sub_wire1 : STD_LOGIC ;
SIGNAL sub_wire2 : STD_LOGIC_VECTOR (8 DOWNTO 0);
COMPONENT dcfifo_mixed_widths
GENERIC (
add_usedw_msb_bit : STRING;
intended_device_family : STRING;
lpm_numwords : NATURAL;
lpm_showahead : STRING;
lpm_type : STRING;
lpm_width : NATURAL;
lpm_widthu : NATURAL;
lpm_widthu_r : NATURAL;
lpm_width_r : NATURAL;
overflow_checking : STRING;
rdsync_delaypipe : NATURAL;
read_aclr_synch : STRING;
underflow_checking : STRING;
use_eab : STRING;
write_aclr_synch : STRING;
wrsync_delaypipe : NATURAL
);
PORT (
aclr : IN STD_LOGIC ;
data : IN STD_LOGIC_VECTOR (95 DOWNTO 0);
rdclk : IN STD_LOGIC ;
rdreq : IN STD_LOGIC ;
wrclk : IN STD_LOGIC ;
wrreq : IN STD_LOGIC ;
q : OUT STD_LOGIC_VECTOR (23 DOWNTO 0);
rdempty : OUT STD_LOGIC ;
wrusedw : OUT STD_LOGIC_VECTOR (8 DOWNTO 0)
);
END COMPONENT;
BEGIN
q <= sub_wire0(23 DOWNTO 0);
rdempty <= sub_wire1;
wrusedw <= sub_wire2(8 DOWNTO 0);
dcfifo_mixed_widths_component : dcfifo_mixed_widths
GENERIC MAP (
add_usedw_msb_bit => "ON",
intended_device_family => "Cyclone V",
lpm_numwords => 256,
lpm_showahead => "ON",
lpm_type => "dcfifo_mixed_widths",
lpm_width => 96,
lpm_widthu => 9,
lpm_widthu_r => 11,
lpm_width_r => 24,
overflow_checking => "ON",
rdsync_delaypipe => 5,
read_aclr_synch => "OFF",
underflow_checking => "ON",
use_eab => "ON",
write_aclr_synch => "OFF",
wrsync_delaypipe => 5
)
PORT MAP (
aclr => aclr,
data => data,
rdclk => rdclk,
rdreq => rdreq,
wrclk => wrclk,
wrreq => wrreq,
q => sub_wire0,
rdempty => sub_wire1,
wrusedw => sub_wire2
);
END SYN;
-- ============================================================
-- CNX file retrieval info
-- ============================================================
-- Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0"
-- Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1"
-- Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
-- Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
-- Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
-- Retrieval info: PRIVATE: Clock NUMERIC "4"
-- Retrieval info: PRIVATE: Depth NUMERIC "256"
-- Retrieval info: PRIVATE: Empty NUMERIC "1"
-- Retrieval info: PRIVATE: Full NUMERIC "1"
-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
-- Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0"
-- Retrieval info: PRIVATE: LegacyRREQ NUMERIC "0"
-- Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0"
-- Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0"
-- Retrieval info: PRIVATE: Optimize NUMERIC "2"
-- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
-- Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
-- Retrieval info: PRIVATE: UsedW NUMERIC "1"
-- Retrieval info: PRIVATE: Width NUMERIC "96"
-- Retrieval info: PRIVATE: dc_aclr NUMERIC "1"
-- Retrieval info: PRIVATE: diff_widths NUMERIC "1"
-- Retrieval info: PRIVATE: msb_usedw NUMERIC "1"
-- Retrieval info: PRIVATE: output_width NUMERIC "24"
-- Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
-- Retrieval info: PRIVATE: rsFull NUMERIC "0"
-- Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
-- Retrieval info: PRIVATE: sc_aclr NUMERIC "0"
-- Retrieval info: PRIVATE: sc_sclr NUMERIC "0"
-- Retrieval info: PRIVATE: wsEmpty NUMERIC "0"
-- Retrieval info: PRIVATE: wsFull NUMERIC "0"
-- Retrieval info: PRIVATE: wsUsedW NUMERIC "1"
-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
-- Retrieval info: CONSTANT: ADD_USEDW_MSB_BIT STRING "ON"
-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
-- Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "256"
-- Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "ON"
-- Retrieval info: CONSTANT: LPM_TYPE STRING "dcfifo_mixed_widths"
-- Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "96"
-- Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "9"
-- Retrieval info: CONSTANT: LPM_WIDTHU_R NUMERIC "11"
-- Retrieval info: CONSTANT: LPM_WIDTH_R NUMERIC "24"
-- Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
-- Retrieval info: CONSTANT: RDSYNC_DELAYPIPE NUMERIC "5"
-- Retrieval info: CONSTANT: READ_ACLR_SYNCH STRING "OFF"
-- Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
-- Retrieval info: CONSTANT: USE_EAB STRING "ON"
-- Retrieval info: CONSTANT: WRITE_ACLR_SYNCH STRING "OFF"
-- Retrieval info: CONSTANT: WRSYNC_DELAYPIPE NUMERIC "5"
-- Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT GND "aclr"
-- Retrieval info: USED_PORT: data 0 0 96 0 INPUT NODEFVAL "data[95..0]"
-- Retrieval info: USED_PORT: q 0 0 24 0 OUTPUT NODEFVAL "q[23..0]"
-- Retrieval info: USED_PORT: rdclk 0 0 0 0 INPUT NODEFVAL "rdclk"
-- Retrieval info: USED_PORT: rdempty 0 0 0 0 OUTPUT NODEFVAL "rdempty"
-- Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL "rdreq"
-- Retrieval info: USED_PORT: wrclk 0 0 0 0 INPUT NODEFVAL "wrclk"
-- Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL "wrreq"
-- Retrieval info: USED_PORT: wrusedw 0 0 9 0 OUTPUT NODEFVAL "wrusedw[8..0]"
-- Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0
-- Retrieval info: CONNECT: @data 0 0 96 0 data 0 0 96 0
-- Retrieval info: CONNECT: @rdclk 0 0 0 0 rdclk 0 0 0 0
-- Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
-- Retrieval info: CONNECT: @wrclk 0 0 0 0 wrclk 0 0 0 0
-- Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
-- Retrieval info: CONNECT: q 0 0 24 0 @q 0 0 24 0
-- Retrieval info: CONNECT: rdempty 0 0 0 0 @rdempty 0 0 0 0
-- Retrieval info: CONNECT: wrusedw 0 0 9 0 @wrusedw 0 0 9 0
-- Retrieval info: GEN_FILE: TYPE_NORMAL dc_video_fifo.vhd TRUE
-- Retrieval info: GEN_FILE: TYPE_NORMAL dc_video_fifo.inc FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL dc_video_fifo.cmp FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL dc_video_fifo.bsf FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL dc_video_fifo_inst.vhd FALSE
-- Retrieval info: LIB_FILE: altera_mf

View File

@ -0,0 +1,363 @@
-------------------------------------------------------------------------------
-- Title : Frame Buffer Manager
-- Project : From FPGA to Linux: An embedded system exploration
-------------------------------------------------------------------------------
-- File : framebuffer_manager.vhd
-- Author : Philemon Orphee Favrod <philemon.favrod@epfl.ch>
-- Company :
-- Created : 2016-03-10
-- Last update: 2017-02-21
-- Platform :
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: DMA-capable unit that manages reads to a framebuffer.
-------------------------------------------------------------------------------
-- Copyright (c) 2016
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2016-03-10 1.0 P. Favrod Created
-- 2016-04-25 1.1 P. Favrod Debuged
-- 2016-05-23 1.2 P. Favrod Increased bandwidth + fifo sync @ VFP
-- 2016-05-29 1.3 P. Favrod Added MSB to FIFO + removed wrfull
-------------------------------------------------------------------------------
-- Register Memory Mapping
-- +-------+--------+-----+-----+-----+-----+----+-----------+
-- | Regno | Access | B31 | ... | B10 | ... | B1 | B0 |
-- +-------+--------+-----+-----+-----+-----+----+-----------+
-- | 0 | R/W | FRAME_START_ADDRESS |
-- +-------+--------+----------------------------------------+
-- | 1 | R/W | FRAME_PIXEL_PER_LINE |
-- +-------+--------+----------------------------------------+
-- | 2 | R/W | FRAME_LINES_PER_FRAME |
-- +-------+--------+----------------------------------------+
-- | 3 | R/W | FRAME_EOL_BYTE_OFFSET |
-- +-------+--------+----------------------------------------+
-- | 4 | WO | COMMAND_REGISTER |
-- +-------+--------+---------------------------+------------+
-- | 5 | R/W | | FB_BURST_COUNT |
-- +-------+--------+-----------+----------------------------+
--
-- Command register:
-- [0] Enable DMA loop
-- [1] Disable DMA loop
-- [2] Enable interrupts
-- [3] Disable interrupts
-- [4] Acknowledge IRQ
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity framebuffer_manager is
port(
clk : in std_logic;
pixclk : in std_logic;
reset : in std_logic;
-- Avalon-MM Slave Interface
as_address : in std_logic_vector(3 downto 0);
as_read : in std_logic;
as_readdata : out std_logic_vector(31 downto 0);
as_write : in std_logic;
as_writedata : in std_logic_vector(31 downto 0);
-- Avalon-MM Master Interface
am_address : out std_logic_vector(31 downto 0);
am_waitrequest : in std_logic;
am_burstcount : out std_logic_vector(10 downto 0);
am_read : out std_logic;
am_readdata : in std_logic_vector(127 downto 0);
am_readdatavalid : in std_logic;
frame_sync : in std_logic;
-- Interrupt Sender Interface
irq : out std_logic;
-- Avalon-ST Source Interface
src_data : out std_logic_vector(23 downto 0);
src_valid : out std_logic;
src_ready : in std_logic);
end framebuffer_manager;
architecture rtl of framebuffer_manager is
constant MAX_BURST_COUNT : integer := 1024;
constant FRAME_START_ADDRESS_REGNO : std_logic_vector(as_address'range) := std_logic_vector(to_unsigned(0, as_address'length));
constant FRAME_PIXEL_PER_LINE_REGNO : std_logic_vector(as_address'range) := std_logic_vector(to_unsigned(1, as_address'length));
constant FRAME_LINES_PER_FRAME_REGNO : std_logic_vector(as_address'range) := std_logic_vector(to_unsigned(2, as_address'length));
constant FRAME_EOL_BYTE_OFFSET_REGNO : std_logic_vector(as_address'range) := std_logic_vector(to_unsigned(3, as_address'length));
constant FB_COMMAND_REGNO : std_logic_vector(as_address'range) := std_logic_vector(to_unsigned(4, as_address'length));
constant FB_BURST_COUNT_REGNO : std_logic_vector(as_address'range) := std_logic_vector(to_unsigned(5, as_address'length));
signal start_address : integer;
signal current_address : integer;
signal pix_per_line, pix_per_line_copy : integer;
signal num_lines, num_lines_copy : integer;
signal eol_byte_offset, eol_byte_offset_copy : integer;
signal enabled : boolean;
signal burst_count, burst_count_copy : integer;
signal irq_enabled : boolean;
signal irq_acknowledged : boolean;
signal burst_counter : integer range 1 to MAX_BURST_COUNT;
signal pix_counter : integer;
signal line_counter : integer;
type state is (IDLE, MEMSTARTREAD, MEMRESTARTREAD, MEMREAD, FLUSHBURST, WAITSYNC);
signal current_state : state;
constant INTERNAL_FIFO_DEPTH : integer := 256;
signal fifo_clr : std_logic;
signal fifo_data_in : std_logic_vector(95 downto 0);
signal fifo_data_out : std_logic_vector(23 downto 0);
signal fifo_read : std_logic;
signal fifo_write : std_logic;
signal fifo_usedw : std_logic_vector(8 downto 0);
signal fifo_freew : integer range 0 to INTERNAL_FIFO_DEPTH;
signal fifo_empty : std_logic;
signal fifo_large_enough : boolean;
begin
dc_video_fifo_inst : entity work.dc_video_fifo port map (
aclr => fifo_clr,
data => fifo_data_in,
rdclk => pixclk,
rdreq => fifo_read,
wrclk => clk,
wrreq => fifo_write,
q => fifo_data_out,
rdempty => fifo_empty,
wrusedw => fifo_usedw);
fifo_write <= am_readdatavalid and not fifo_clr when current_state = MEMREAD else '0';
fifo_read <= src_ready and not fifo_empty;
fifo_clr <= '1' when current_state = IDLE else '0';
fifo_freew <= INTERNAL_FIFO_DEPTH - to_integer(unsigned(fifo_usedw));
fifo_large_enough <= fifo_freew >= burst_count_copy;
fifo_data_in <= am_readdata(119 downto 96) & am_readdata(87 downto 64) & am_readdata(55 downto 32) & am_readdata(23 downto 0);
src_data <= fifo_data_out when fifo_empty = '0' else X"ff0000";
src_valid <= not fifo_empty;
p_as_write : process (clk, reset)
begin
if reset = '1' then
start_address <= 0;
pix_per_line <= 0;
num_lines <= 0;
eol_byte_offset <= 0;
burst_count <= 4;
enabled <= false;
irq_enabled <= false;
irq_acknowledged <= false;
elsif rising_edge(clk) then
irq_acknowledged <= false;
if as_write = '1' then
case as_address is
when FRAME_START_ADDRESS_REGNO =>
start_address <= to_integer(unsigned(as_writedata));
when FRAME_PIXEL_PER_LINE_REGNO =>
pix_per_line <= to_integer(unsigned(as_writedata));
when FRAME_LINES_PER_FRAME_REGNO =>
num_lines <= to_integer(unsigned(as_writedata));
when FRAME_EOL_BYTE_OFFSET_REGNO =>
eol_byte_offset <= to_integer(unsigned(as_writedata));
when FB_COMMAND_REGNO =>
if as_writedata(0) = '1' then
enabled <= true;
end if;
if as_writedata(1) = '1' then
enabled <= false;
end if;
if as_writedata(2) = '1' then
irq_enabled <= true;
end if;
if as_writedata(3) = '1' then
irq_enabled <= false;
end if;
if as_writedata(4) = '1' then
irq_acknowledged <= true;
end if;
when FB_BURST_COUNT_REGNO =>
if unsigned(as_writedata) > MAX_BURST_COUNT then
burst_count <= MAX_BURST_COUNT;
else
burst_count <= to_integer(unsigned(as_writedata));
end if;
when others => null;
end case;
end if;
end if;
end process p_as_write;
p_as_read : process (clk, reset)
begin
if reset = '1' then
as_readdata <= (others => '0');
elsif rising_edge(clk) then
as_readdata <= (others => '0');
if as_read = '1' then
case as_address is
when FRAME_START_ADDRESS_REGNO =>
as_readdata <= std_logic_vector(to_unsigned(start_address, as_readdata'length));
when FRAME_PIXEL_PER_LINE_REGNO =>
as_readdata <= std_logic_vector(to_unsigned(pix_per_line, as_readdata'length));
when FRAME_LINES_PER_FRAME_REGNO =>
as_readdata <= std_logic_vector(to_unsigned(num_lines, as_readdata'length));
when FRAME_EOL_BYTE_OFFSET_REGNO =>
as_readdata <= std_logic_vector(to_unsigned(eol_byte_offset, as_readdata'length));
when FB_BURST_COUNT_REGNO =>
as_readdata <= std_logic_vector(to_unsigned(burst_count, as_readdata'length));
when others => null;
end case;
end if;
end if;
end process p_as_read;
p_fsm : process (clk, reset)
begin
if reset = '1' then
current_address <= 0;
pix_per_line_copy <= 0;
num_lines_copy <= 0;
eol_byte_offset_copy <= 0;
burst_count_copy <= 0;
burst_counter <= 1;
pix_counter <= 0;
line_counter <= 0;
current_state <= IDLE;
elsif rising_edge(clk) then
-- If the interrupts have been disabled or acknowledged
-- we deassert the interrupt request line.
if not irq_enabled or irq_acknowledged then
irq <= '0';
end if;
case current_state is
when IDLE =>
-- In IDLE state, wait for enabled to be high Then, save a copy of registers
-- in shadow registers and start reading memory.
if enabled then
current_address <= start_address;
pix_per_line_copy <= pix_per_line;
num_lines_copy <= num_lines;
eol_byte_offset_copy <= eol_byte_offset;
burst_count_copy <= burst_count;
current_state <= MEMSTARTREAD;
pix_counter <= 4 * burst_count; -- so that when pix_counter =
-- pix_per_line_copy we are done
line_counter <= 1;
end if;
-- wait state for the DC fifo signal to be updated
when MEMRESTARTREAD =>
current_state <= MEMSTARTREAD;
when MEMSTARTREAD =>
-- If there is room for a full burst in the FIFO and
-- no wait request on the bus, we start reading!
if fifo_large_enough and am_waitrequest = '0' then
burst_counter <= 1;
current_state <= MEMREAD;
end if;
when MEMREAD =>
-- If a valid data is received
if am_readdatavalid = '1' then
-- If in the middle of a burst, increment the burst counter
if burst_counter < burst_count_copy then
burst_counter <= burst_counter + 1;
else
-- If in the middle of a line, increment the pixel counter and the
-- address accordingly
if pix_counter < pix_per_line_copy then
pix_counter <= pix_counter + 4 * burst_count_copy;
current_address <= current_address + 16 * burst_count_copy;
current_state <= MEMRESTARTREAD;
-- If at the end of a line, increment the line counter and the
-- address accordingly. Reset pix_counter too!
elsif line_counter < num_lines_copy then
line_counter <= line_counter + 1;
pix_counter <= 4 * burst_count_copy;
current_address <= current_address + 16 * burst_count_copy + eol_byte_offset_copy;
current_state <= MEMRESTARTREAD;
-- If at the end of a frame, go back to WAITSYNC until blanking
else
current_state <= WAITSYNC;
-- End of frame => IRQ!
if irq_enabled then
irq <= '1';
end if;
end if;
end if;
end if;
if frame_sync = '1' then
current_state <= FLUSHBURST;
end if;
when FLUSHBURST =>
if burst_counter = burst_count_copy then
current_state <= IDLE;
elsif am_readdatavalid = '1' then
burst_counter <= burst_counter + 1;
end if;
when WAITSYNC =>
-- Wait for vertical blanking to occur to avoid filling the FIFO
-- just before it is cleared!
if frame_sync = '1' then
current_state <= IDLE;
end if;
when others => null;
end case;
end if;
end process p_fsm;
am_address <= std_logic_vector(to_unsigned(current_address, am_address'length));
am_read <= '1' when fifo_large_enough and current_state = MEMSTARTREAD else '0';
am_burstcount <= std_logic_vector(to_unsigned(burst_count_copy, am_burstcount'length));
end architecture;

View File

@ -0,0 +1,233 @@
# TCL File Generated by Component Editor 16.0
# Sun Feb 05 18:18:01 CET 2017
# DO NOT MODIFY
#
# framebuffer_manager "framebuffer_manager" v1.0
# 2017.02.05.18:18:01
#
#
#
# request TCL package from ACDS 16.0
#
package require -exact qsys 16.0
#
# module framebuffer_manager
#
set_module_property DESCRIPTION ""
set_module_property NAME framebuffer_manager
set_module_property VERSION 1.0
set_module_property INTERNAL false
set_module_property OPAQUE_ADDRESS_MAP true
set_module_property GROUP LCD
set_module_property AUTHOR "Philemon Favrod"
set_module_property DISPLAY_NAME framebuffer_manager
set_module_property INSTANTIATE_IN_SYSTEM_MODULE true
set_module_property EDITABLE true
set_module_property REPORT_TO_TALKBACK false
set_module_property ALLOW_GREYBOX_GENERATION false
set_module_property REPORT_HIERARCHY false
#
# file sets
#
add_fileset QUARTUS_SYNTH QUARTUS_SYNTH "" ""
set_fileset_property QUARTUS_SYNTH TOP_LEVEL framebuffer_manager
set_fileset_property QUARTUS_SYNTH ENABLE_RELATIVE_INCLUDE_PATHS false
set_fileset_property QUARTUS_SYNTH ENABLE_FILE_OVERWRITE_MODE false
add_fileset_file framebuffer_manager.vhd VHDL PATH framebuffer_manager.vhd TOP_LEVEL_FILE
add_fileset_file dc_video_fifo.vhd VHDL PATH dc_video_fifo.vhd
#
# parameters
#
#
# module assignments
#
set_module_assignment embeddedsw.dts.compatible prsoc,framebuffer-manager
set_module_assignment embeddedsw.dts.group any
set_module_assignment embeddedsw.dts.vendor prsoc
#
# display items
#
#
# connection point clock
#
add_interface clock clock end
set_interface_property clock clockRate 0
set_interface_property clock ENABLED true
set_interface_property clock EXPORT_OF ""
set_interface_property clock PORT_NAME_MAP ""
set_interface_property clock CMSIS_SVD_VARIABLES ""
set_interface_property clock SVD_ADDRESS_GROUP ""
add_interface_port clock clk clk Input 1
#
# connection point reset
#
add_interface reset reset end
set_interface_property reset associatedClock clock
set_interface_property reset synchronousEdges DEASSERT
set_interface_property reset ENABLED true
set_interface_property reset EXPORT_OF ""
set_interface_property reset PORT_NAME_MAP ""
set_interface_property reset CMSIS_SVD_VARIABLES ""
set_interface_property reset SVD_ADDRESS_GROUP ""
add_interface_port reset reset reset Input 1
#
# connection point interrupt_sender
#
add_interface interrupt_sender interrupt end
set_interface_property interrupt_sender associatedAddressablePoint ""
set_interface_property interrupt_sender associatedClock clock
set_interface_property interrupt_sender associatedReset reset
set_interface_property interrupt_sender bridgedReceiverOffset ""
set_interface_property interrupt_sender bridgesToReceiver ""
set_interface_property interrupt_sender ENABLED true
set_interface_property interrupt_sender EXPORT_OF ""
set_interface_property interrupt_sender PORT_NAME_MAP ""
set_interface_property interrupt_sender CMSIS_SVD_VARIABLES ""
set_interface_property interrupt_sender SVD_ADDRESS_GROUP ""
add_interface_port interrupt_sender irq irq Output 1
#
# connection point csr
#
add_interface csr avalon end
set_interface_property csr addressUnits WORDS
set_interface_property csr associatedClock clock
set_interface_property csr associatedReset reset
set_interface_property csr bitsPerSymbol 8
set_interface_property csr burstOnBurstBoundariesOnly false
set_interface_property csr burstcountUnits WORDS
set_interface_property csr explicitAddressSpan 0
set_interface_property csr holdTime 0
set_interface_property csr linewrapBursts false
set_interface_property csr maximumPendingReadTransactions 0
set_interface_property csr maximumPendingWriteTransactions 0
set_interface_property csr readLatency 0
set_interface_property csr readWaitTime 1
set_interface_property csr setupTime 0
set_interface_property csr timingUnits Cycles
set_interface_property csr writeWaitTime 0
set_interface_property csr ENABLED true
set_interface_property csr EXPORT_OF ""
set_interface_property csr PORT_NAME_MAP ""
set_interface_property csr CMSIS_SVD_VARIABLES ""
set_interface_property csr SVD_ADDRESS_GROUP ""
add_interface_port csr as_address address Input 4
add_interface_port csr as_read read Input 1
add_interface_port csr as_readdata readdata Output 32
add_interface_port csr as_write write Input 1
add_interface_port csr as_writedata writedata Input 32
set_interface_assignment csr embeddedsw.configuration.isFlash 0
set_interface_assignment csr embeddedsw.configuration.isMemoryDevice 0
set_interface_assignment csr embeddedsw.configuration.isNonVolatileStorage 0
set_interface_assignment csr embeddedsw.configuration.isPrintableDevice 0
#
# connection point dma
#
add_interface dma avalon start
set_interface_property dma addressUnits SYMBOLS
set_interface_property dma associatedClock clock
set_interface_property dma associatedReset reset
set_interface_property dma bitsPerSymbol 8
set_interface_property dma burstOnBurstBoundariesOnly false
set_interface_property dma burstcountUnits WORDS
set_interface_property dma doStreamReads false
set_interface_property dma doStreamWrites false
set_interface_property dma holdTime 0
set_interface_property dma linewrapBursts false
set_interface_property dma maximumPendingReadTransactions 0
set_interface_property dma maximumPendingWriteTransactions 0
set_interface_property dma readLatency 0
set_interface_property dma readWaitTime 1
set_interface_property dma setupTime 0
set_interface_property dma timingUnits Cycles
set_interface_property dma writeWaitTime 0
set_interface_property dma ENABLED true
set_interface_property dma EXPORT_OF ""
set_interface_property dma PORT_NAME_MAP ""
set_interface_property dma CMSIS_SVD_VARIABLES ""
set_interface_property dma SVD_ADDRESS_GROUP ""
add_interface_port dma am_address address Output 32
add_interface_port dma am_burstcount burstcount Output 11
add_interface_port dma am_read read Output 1
add_interface_port dma am_readdata readdata Input 128
add_interface_port dma am_readdatavalid readdatavalid Input 1
add_interface_port dma am_waitrequest waitrequest Input 1
#
# connection point video_out
#
add_interface video_out avalon_streaming start
set_interface_property video_out associatedClock pixclk
set_interface_property video_out associatedReset reset
set_interface_property video_out dataBitsPerSymbol 24
set_interface_property video_out errorDescriptor ""
set_interface_property video_out firstSymbolInHighOrderBits true
set_interface_property video_out maxChannel 0
set_interface_property video_out readyLatency 0
set_interface_property video_out ENABLED true
set_interface_property video_out EXPORT_OF ""
set_interface_property video_out PORT_NAME_MAP ""
set_interface_property video_out CMSIS_SVD_VARIABLES ""
set_interface_property video_out SVD_ADDRESS_GROUP ""
add_interface_port video_out src_data data Output 24
add_interface_port video_out src_valid valid Output 1
add_interface_port video_out src_ready ready Input 1
#
# connection point sync
#
add_interface sync conduit end
set_interface_property sync associatedClock clock
set_interface_property sync associatedReset ""
set_interface_property sync ENABLED true
set_interface_property sync EXPORT_OF ""
set_interface_property sync PORT_NAME_MAP ""
set_interface_property sync CMSIS_SVD_VARIABLES ""
set_interface_property sync SVD_ADDRESS_GROUP ""
add_interface_port sync frame_sync frame_sync Input 1
#
# connection point pixclk
#
add_interface pixclk clock end
set_interface_property pixclk clockRate 0
set_interface_property pixclk ENABLED true
set_interface_property pixclk EXPORT_OF ""
set_interface_property pixclk PORT_NAME_MAP ""
set_interface_property pixclk CMSIS_SVD_VARIABLES ""
set_interface_property pixclk SVD_ADDRESS_GROUP ""
add_interface_port pixclk pixclk clk Input 1

View File

@ -0,0 +1,358 @@
--+--------+------------+-------------------------------------------------------------------+
--| Offset | Name | Description |
--+--------+------------+-------------------------------------------------------------------+
--| 0x0 | CSR | [0] Enable/Disable |
--| 0x1 | HBP | [15..0] Horizontal Back Porch (in DCLK) |
--| 0x2 | HFP | [15..0] Horizontal Front Porch (in DCLK) |
--| 0x3 | VBP | [15..0] Vertical Back Porch (in # lines) |
--| 0x4 | VFP | [15..0] Vertical Front Porch (in # lines) |
--| 0x5 | HDATA | [15..0] Horizontal data (in DCLK) |
--| 0x6 | VDATA | [15..0] [15..0] Vertical data (in # lines) |
--| 0x7 | HSync | [15..0] HSync width (in DCLK) |
--| 0x8 | Vsync | [15..0] VSync width (in # lines) |
--+--------+------------+-------------------------------------------------------------------+
--
-- As usual, the horizontal timings are specified in number of data clock
-- cycles, and the vertical timings are specified in number of lines.
--
-- For naming conventions, please refer to the following diagram:
-- +----------------------------------------------------------------------------------------------+-----
-- | A | B | C | D | ...
-- +----------------------------------------------------------------------------------------------+-----
-- --+ +------------------------------------------------------------------------------------------+ +-
-- | | | |
-- +---+ +---+
--
-- A is the pulse width
-- B is the back porch
-- C is the valid data
-- D is the front porch
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity vga_sequencer is
generic (
HBP_DEFAULT : positive := 12;
HFP_DEFAULT : positive := 18;
VBP_DEFAULT : positive := 8;
VFP_DEFAULT : positive := 20;
HDATA_DEFAULT : positive := 240;
VDATA_DEFAULT : positive := 320;
HSYNC_DEFAULT : positive := 2;
VSYNC_DEFAULT : positive := 7);
port (
pixclk : in std_logic; -- A copy of the pixclk from the PLL
clk : in std_logic; -- The clock of the bus
reset : in std_logic;
-- Avalon-MM CSR Interface
address : in std_logic_vector(4 downto 0);
read, write : in std_logic;
readdata : out std_logic_vector(31 downto 0);
writedata : in std_logic_vector(31 downto 0);
-- Avalon-ST sink Interface
sink_data : in std_logic_vector(23 downto 0);
sink_valid : in std_logic;
sink_ready : out std_logic;
-- TFT Interface
r : out std_logic_vector(7 downto 0);
g : out std_logic_vector(7 downto 0);
b : out std_logic_vector(7 downto 0);
hsync : out std_logic;
vsync : out std_logic;
de : out std_logic;
-- Indicates when we enter the front porch of the vertical sync.
-- Used to flush the FIFO and restart reading the frame in memory.
frame_sync : out std_logic);
end entity vga_sequencer;
architecture rtl of vga_sequencer is
-- Both counters should be able to count up to the addition of any four 16-bit numbers.
signal horizontal_counter, horizontal_max : unsigned(19 downto 0);
constant HORIZONTAL_COUNTER_RESET : unsigned(horizontal_counter'range) := to_unsigned(1, horizontal_counter'length);
signal vertical_counter, vertical_max : unsigned(19 downto 0);
constant VERTICAL_COUNTER_RESET : unsigned(horizontal_counter'range) := to_unsigned(1, horizontal_counter'length);
-- Registers
signal hbp, hfp, vbp, vfp, hdata_width, vdata_width, hsync_width, vsync_width : unsigned(15 downto 0);
signal enabled : boolean;
-- Output registers
signal i_r : std_logic_vector(7 downto 0);
signal i_g : std_logic_vector(7 downto 0);
signal i_b : std_logic_vector(7 downto 0);
signal i_hsync : std_logic;
signal i_vsync : std_logic;
signal i_de : std_logic;
-- couting becomes true whenever enabled is true and sink_valid='1'
signal counting : boolean;
constant CSR_REG_OFST : unsigned(address'range) := to_unsigned(0, address'length);
constant HBP_REG_OFST : unsigned(address'range) := to_unsigned(1, address'length);
constant HFP_REG_OFST : unsigned(address'range) := to_unsigned(2, address'length);
constant VBP_REG_OFST : unsigned(address'range) := to_unsigned(3, address'length);
constant VFP_REG_OFST : unsigned(address'range) := to_unsigned(4, address'length);
constant HDATA_REG_OFST : unsigned(address'range) := to_unsigned(5, address'length);
constant VDATA_REG_OFST : unsigned(address'range) := to_unsigned(6, address'length);
constant HSYNC_REG_OFST : unsigned(address'range) := to_unsigned(7, address'length);
constant VSYNC_REG_OFST : unsigned(address'range) := to_unsigned(8, address'length);
begin
p_csr_write : process (clk, reset)
begin
if reset = '1' then
enabled <= false;
hbp <= to_unsigned(HBP_DEFAULT, hbp'length);
hfp <= to_unsigned(HFP_DEFAULT, hfp'length);
vbp <= to_unsigned(VBP_DEFAULT, vbp'length);
vfp <= to_unsigned(VFP_DEFAULT, vfp'length);
hdata_width <= to_unsigned(HDATA_DEFAULT, hdata_width'length);
vdata_width <= to_unsigned(VDATA_DEFAULT, vdata_width'length);
hsync_width <= to_unsigned(HSYNC_DEFAULT, hsync_width'length);
vsync_width <= to_unsigned(VSYNC_DEFAULT, vsync_width'length);
elsif rising_edge(clk) then
if write = '1' then
case unsigned(address) is
-- Status
when CSR_REG_OFST =>
if writedata(0) = '1' then
enabled <= true;
else
enabled <= false;
end if;
-- HBP
when HBP_REG_OFST =>
hbp <= unsigned(writedata(15 downto 0));
-- HFP
when HFP_REG_OFST =>
hfp <= unsigned(writedata(15 downto 0));
-- VBP
when VBP_REG_OFST =>
vbp <= unsigned(writedata(15 downto 0));
-- VFP
when VFP_REG_OFST =>
vfp <= unsigned(writedata(15 downto 0));
-- HDATA
when HDATA_REG_OFST =>
hdata_width <= unsigned(writedata(15 downto 0));
-- VDATA
when VDATA_REG_OFST =>
vdata_width <= unsigned(writedata(15 downto 0));
-- HSYNC
when HSYNC_REG_OFST =>
hsync_width <= unsigned(writedata(15 downto 0));
-- VSYNC
when VSYNC_REG_OFST =>
vsync_width <= unsigned(writedata(15 downto 0));
when others => null;
end case;
end if;
end if;
end process p_csr_write;
p_csr_read : process (clk, reset)
begin
if reset = '1' then
readdata <= (others => '0');
elsif rising_edge(clk) then
readdata <= (others => '0');
if read = '1' then
case unsigned(address) is
-- Status
when CSR_REG_OFST =>
readdata <= (others => '0');
if enabled then
readdata(0) <= '1';
end if;
-- HBP
when HBP_REG_OFST =>
readdata(15 downto 0) <= std_logic_vector(hbp);
-- HFP
when HFP_REG_OFST =>
readdata(15 downto 0) <= std_logic_vector(hfp);
-- VBP
when VBP_REG_OFST =>
readdata(15 downto 0) <= std_logic_vector(vbp);
-- VFP
when VFP_REG_OFST =>
readdata(15 downto 0) <= std_logic_vector(vfp);
-- HDATA
when HDATA_REG_OFST =>
readdata(15 downto 0) <= std_logic_vector(hdata_width);
-- VDATA
when VDATA_REG_OFST =>
readdata(15 downto 0) <= std_logic_vector(vdata_width);
-- HSYNC
when HSYNC_REG_OFST =>
readdata(15 downto 0) <= std_logic_vector(hsync_width);
-- VSYNC
when VSYNC_REG_OFST =>
readdata(15 downto 0) <= std_logic_vector(vsync_width);
when others => null;
end case;
end if;
end if;
end process p_csr_read;
horizontal_max <=
resize(hsync_width, horizontal_max 'length) +
resize(hbp, horizontal_max'length) +
resize(hdata_width, horizontal_max'length) +
resize(hfp, horizontal_max'length);
vertical_max <=
resize(vsync_width, horizontal_max 'length) +
resize(vbp, horizontal_max'length) +
resize(vdata_width, horizontal_max'length) +
resize(vfp, horizontal_max'length);
p_cnt_trigger : process (pixclk, reset)
begin
if reset = '1' then
counting <= false;
elsif rising_edge(pixclk) then
if enabled and sink_valid = '1' then
counting <= true;
elsif not enabled then
counting <= false;
end if;
end if;
end process p_cnt_trigger;
p_horizontal_count : process (pixclk, reset)
begin
if reset = '1' then
horizontal_counter <= HORIZONTAL_COUNTER_RESET;
elsif rising_edge(pixclk) then
horizontal_counter <= HORIZONTAL_COUNTER_RESET;
if counting and horizontal_counter < horizontal_max then
horizontal_counter <= horizontal_counter + 1;
end if;
end if;
end process p_horizontal_count;
p_vertical_count : process (pixclk, reset)
begin
if reset = '1' then
vertical_counter <= VERTICAL_COUNTER_RESET;
elsif rising_edge(pixclk) then
if counting then
if horizontal_counter = horizontal_max then
if vertical_counter < vertical_max then
vertical_counter <= vertical_counter + 1;
else
vertical_counter <= VERTICAL_COUNTER_RESET;
end if;
end if;
else
vertical_counter <= VERTICAL_COUNTER_RESET;
end if;
end if;
end process p_vertical_count;
p_hsync_vsync_gen : process (counting, horizontal_counter, hsync_width,
vertical_counter, vsync_width)
begin
-- HSYNC generation
i_hsync <= '1';
if horizontal_counter <= hsync_width then
i_hsync <= '0';
end if;
-- VSYNC generation
i_vsync <= '1';
if vertical_counter <= vsync_width then
i_vsync <= '0';
end if;
if not counting then
i_vsync <= '1';
i_hsync <= '1';
end if;
end process p_hsync_vsync_gen;
p_rgb_out : process (hbp, hdata_width, horizontal_counter, hsync_width,
sink_data, vbp, vdata_width, vertical_counter,
vsync_width)
begin
i_r <= (others => '0');
i_g <= (others => '0');
i_b <= (others => '0');
i_de <= '0';
sink_ready <= '0';
frame_sync <= '0';
if
vertical_counter > (resize(vsync_width, vertical_counter'length) + resize(vbp, vertical_counter'length)) and
vertical_counter <= (resize(vsync_width, vertical_counter'length) + resize(vbp, vertical_counter'length) + resize(vdata_width, vertical_counter'length)) and
horizontal_counter > (resize(hsync_width, horizontal_counter'length) + resize(hbp, horizontal_counter'length)) and
horizontal_counter <= (resize(hsync_width, horizontal_counter'length) + resize(hbp, horizontal_counter'length) + resize(hdata_width, horizontal_counter'length))
then
i_de <= '1';
i_r <= sink_data(23 downto 16);
i_g <= sink_data(15 downto 8);
i_b <= sink_data(7 downto 0);
sink_ready <= '1';
end if;
if
vertical_counter > (resize(vsync_width, vertical_counter'length) + resize(vbp, vertical_counter'length) + resize(vdata_width, vertical_counter'length))
then
frame_sync <= '1';
end if;
end process p_rgb_out;
p_output_reg : process (pixclk, reset)
begin
if reset = '1' then
r <= (others => '0');
g <= (others => '0');
b <= (others => '0');
de <= '0';
hsync <= '1';
vsync <= '1';
elsif rising_edge(pixclk) then
de <= i_de;
r <= i_r;
g <= i_g;
b <= i_b;
vsync <= i_vsync;
hsync <= i_hsync;
end if;
end process;
end architecture rtl;

View File

@ -0,0 +1,247 @@
# TCL File Generated by Component Editor 16.0
# Sun Feb 05 18:18:28 CET 2017
# DO NOT MODIFY
#
# vga_sequencer "vga_sequencer" v1.0
# 2017.02.05.18:18:28
#
#
#
# request TCL package from ACDS 16.0
#
package require -exact qsys 16.0
#
# module vga_sequencer
#
set_module_property DESCRIPTION ""
set_module_property NAME vga_sequencer
set_module_property VERSION 1.0
set_module_property INTERNAL false
set_module_property OPAQUE_ADDRESS_MAP true
set_module_property GROUP LCD
set_module_property AUTHOR "Philemon Favrod"
set_module_property DISPLAY_NAME vga_sequencer
set_module_property INSTANTIATE_IN_SYSTEM_MODULE true
set_module_property EDITABLE true
set_module_property REPORT_TO_TALKBACK false
set_module_property ALLOW_GREYBOX_GENERATION false
set_module_property REPORT_HIERARCHY false
#
# file sets
#
add_fileset QUARTUS_SYNTH QUARTUS_SYNTH "" ""
set_fileset_property QUARTUS_SYNTH TOP_LEVEL vga_sequencer
set_fileset_property QUARTUS_SYNTH ENABLE_RELATIVE_INCLUDE_PATHS false
set_fileset_property QUARTUS_SYNTH ENABLE_FILE_OVERWRITE_MODE false
add_fileset_file vga_sequencer.vhd VHDL PATH vga_sequencer.vhd TOP_LEVEL_FILE
#
# parameters
#
add_parameter HBP_DEFAULT POSITIVE 12
set_parameter_property HBP_DEFAULT DEFAULT_VALUE 12
set_parameter_property HBP_DEFAULT DISPLAY_NAME HBP_DEFAULT
set_parameter_property HBP_DEFAULT TYPE POSITIVE
set_parameter_property HBP_DEFAULT UNITS None
set_parameter_property HBP_DEFAULT ALLOWED_RANGES 1:2147483647
set_parameter_property HBP_DEFAULT HDL_PARAMETER true
add_parameter HFP_DEFAULT POSITIVE 18
set_parameter_property HFP_DEFAULT DEFAULT_VALUE 18
set_parameter_property HFP_DEFAULT DISPLAY_NAME HFP_DEFAULT
set_parameter_property HFP_DEFAULT TYPE POSITIVE
set_parameter_property HFP_DEFAULT UNITS None
set_parameter_property HFP_DEFAULT ALLOWED_RANGES 1:2147483647
set_parameter_property HFP_DEFAULT HDL_PARAMETER true
add_parameter VBP_DEFAULT POSITIVE 8
set_parameter_property VBP_DEFAULT DEFAULT_VALUE 8
set_parameter_property VBP_DEFAULT DISPLAY_NAME VBP_DEFAULT
set_parameter_property VBP_DEFAULT TYPE POSITIVE
set_parameter_property VBP_DEFAULT UNITS None
set_parameter_property VBP_DEFAULT ALLOWED_RANGES 1:2147483647
set_parameter_property VBP_DEFAULT HDL_PARAMETER true
add_parameter VFP_DEFAULT POSITIVE 20
set_parameter_property VFP_DEFAULT DEFAULT_VALUE 20
set_parameter_property VFP_DEFAULT DISPLAY_NAME VFP_DEFAULT
set_parameter_property VFP_DEFAULT TYPE POSITIVE
set_parameter_property VFP_DEFAULT UNITS None
set_parameter_property VFP_DEFAULT ALLOWED_RANGES 1:2147483647
set_parameter_property VFP_DEFAULT HDL_PARAMETER true
add_parameter HDATA_DEFAULT POSITIVE 240
set_parameter_property HDATA_DEFAULT DEFAULT_VALUE 240
set_parameter_property HDATA_DEFAULT DISPLAY_NAME HDATA_DEFAULT
set_parameter_property HDATA_DEFAULT TYPE POSITIVE
set_parameter_property HDATA_DEFAULT UNITS None
set_parameter_property HDATA_DEFAULT ALLOWED_RANGES 1:2147483647
set_parameter_property HDATA_DEFAULT HDL_PARAMETER true
add_parameter VDATA_DEFAULT POSITIVE 320
set_parameter_property VDATA_DEFAULT DEFAULT_VALUE 320
set_parameter_property VDATA_DEFAULT DISPLAY_NAME VDATA_DEFAULT
set_parameter_property VDATA_DEFAULT TYPE POSITIVE
set_parameter_property VDATA_DEFAULT UNITS None
set_parameter_property VDATA_DEFAULT ALLOWED_RANGES 1:2147483647
set_parameter_property VDATA_DEFAULT HDL_PARAMETER true
add_parameter HSYNC_DEFAULT POSITIVE 2
set_parameter_property HSYNC_DEFAULT DEFAULT_VALUE 2
set_parameter_property HSYNC_DEFAULT DISPLAY_NAME HSYNC_DEFAULT
set_parameter_property HSYNC_DEFAULT TYPE POSITIVE
set_parameter_property HSYNC_DEFAULT UNITS None
set_parameter_property HSYNC_DEFAULT ALLOWED_RANGES 1:2147483647
set_parameter_property HSYNC_DEFAULT HDL_PARAMETER true
add_parameter VSYNC_DEFAULT POSITIVE 7
set_parameter_property VSYNC_DEFAULT DEFAULT_VALUE 7
set_parameter_property VSYNC_DEFAULT DISPLAY_NAME VSYNC_DEFAULT
set_parameter_property VSYNC_DEFAULT TYPE POSITIVE
set_parameter_property VSYNC_DEFAULT UNITS None
set_parameter_property VSYNC_DEFAULT ALLOWED_RANGES 1:2147483647
set_parameter_property VSYNC_DEFAULT HDL_PARAMETER true
#
# display items
#
#
# connection point clock
#
add_interface clock clock end
set_interface_property clock clockRate 0
set_interface_property clock ENABLED true
set_interface_property clock EXPORT_OF ""
set_interface_property clock PORT_NAME_MAP ""
set_interface_property clock CMSIS_SVD_VARIABLES ""
set_interface_property clock SVD_ADDRESS_GROUP ""
add_interface_port clock clk clk Input 1
#
# connection point reset
#
add_interface reset reset end
set_interface_property reset associatedClock clock
set_interface_property reset synchronousEdges DEASSERT
set_interface_property reset ENABLED true
set_interface_property reset EXPORT_OF ""
set_interface_property reset PORT_NAME_MAP ""
set_interface_property reset CMSIS_SVD_VARIABLES ""
set_interface_property reset SVD_ADDRESS_GROUP ""
add_interface_port reset reset reset Input 1
#
# connection point csr
#
add_interface csr avalon end
set_interface_property csr addressUnits WORDS
set_interface_property csr associatedClock clock
set_interface_property csr associatedReset reset
set_interface_property csr bitsPerSymbol 8
set_interface_property csr burstOnBurstBoundariesOnly false
set_interface_property csr burstcountUnits WORDS
set_interface_property csr explicitAddressSpan 0
set_interface_property csr holdTime 0
set_interface_property csr linewrapBursts false
set_interface_property csr maximumPendingReadTransactions 0
set_interface_property csr maximumPendingWriteTransactions 0
set_interface_property csr readLatency 0
set_interface_property csr readWaitTime 1
set_interface_property csr setupTime 0
set_interface_property csr timingUnits Cycles
set_interface_property csr writeWaitTime 0
set_interface_property csr ENABLED true
set_interface_property csr EXPORT_OF ""
set_interface_property csr PORT_NAME_MAP ""
set_interface_property csr CMSIS_SVD_VARIABLES ""
set_interface_property csr SVD_ADDRESS_GROUP ""
add_interface_port csr address address Input 5
add_interface_port csr read read Input 1
add_interface_port csr write write Input 1
add_interface_port csr readdata readdata Output 32
add_interface_port csr writedata writedata Input 32
set_interface_assignment csr embeddedsw.configuration.isFlash 0
set_interface_assignment csr embeddedsw.configuration.isMemoryDevice 0
set_interface_assignment csr embeddedsw.configuration.isNonVolatileStorage 0
set_interface_assignment csr embeddedsw.configuration.isPrintableDevice 0
#
# connection point out
#
add_interface out conduit end
set_interface_property out associatedClock clock
set_interface_property out associatedReset ""
set_interface_property out ENABLED true
set_interface_property out EXPORT_OF ""
set_interface_property out PORT_NAME_MAP ""
set_interface_property out CMSIS_SVD_VARIABLES ""
set_interface_property out SVD_ADDRESS_GROUP ""
add_interface_port out hsync hsync Output 1
add_interface_port out g g Output 8
add_interface_port out b b Output 8
add_interface_port out de de Output 1
add_interface_port out vsync vsync Output 1
add_interface_port out r r Output 8
#
# connection point in
#
add_interface in avalon_streaming end
set_interface_property in associatedClock pixclk
set_interface_property in associatedReset reset
set_interface_property in dataBitsPerSymbol 24
set_interface_property in errorDescriptor ""
set_interface_property in firstSymbolInHighOrderBits true
set_interface_property in maxChannel 0
set_interface_property in readyLatency 0
set_interface_property in ENABLED true
set_interface_property in EXPORT_OF ""
set_interface_property in PORT_NAME_MAP ""
set_interface_property in CMSIS_SVD_VARIABLES ""
set_interface_property in SVD_ADDRESS_GROUP ""
add_interface_port in sink_ready ready Output 1
add_interface_port in sink_valid valid Input 1
add_interface_port in sink_data data Input 24
#
# connection point pixclk
#
add_interface pixclk clock end
set_interface_property pixclk clockRate 0
set_interface_property pixclk ENABLED true
set_interface_property pixclk EXPORT_OF ""
set_interface_property pixclk PORT_NAME_MAP ""
set_interface_property pixclk CMSIS_SVD_VARIABLES ""
set_interface_property pixclk SVD_ADDRESS_GROUP ""
add_interface_port pixclk pixclk clk Input 1
#
# connection point frame_sync
#
add_interface frame_sync conduit end
set_interface_property frame_sync associatedClock clock
set_interface_property frame_sync associatedReset ""
set_interface_property frame_sync ENABLED true
set_interface_property frame_sync EXPORT_OF ""
set_interface_property frame_sync PORT_NAME_MAP ""
set_interface_property frame_sync CMSIS_SVD_VARIABLES ""
set_interface_property frame_sync SVD_ADDRESS_GROUP ""
add_interface_port frame_sync frame_sync frame_sync Output 1

View File

@ -0,0 +1,138 @@
-- #############################################################################
-- mcp3204.vhd
-- ===========
-- MCP3204 Avalon-MM slave interface.
--
-- Register map
-- +-------+-----------+--------+------------------------------------+
-- | RegNo | Name | Access | Description |
-- +-------+-----------+--------+------------------------------------+
-- | 0 | CHANNEL_0 | RO | 12-bit digital value of channel 0. |
-- +-------+-----------+--------+------------------------------------+
-- | 1 | CHANNEL_1 | RO | 12-bit digital value of channel 1. |
-- +-------+-----------+--------+------------------------------------+
-- | 2 | CHANNEL_2 | RO | 12-bit digital value of channel 2. |
-- +-------+-----------+--------+------------------------------------+
-- | 3 | CHANNEL_3 | RO | 12-bit digital value of channel 3. |
-- +-------+-----------+--------+------------------------------------+
--
-- Author : Philémon Favrod [philemon.favrod@epfl.ch]
-- Author : Sahand Kashani-Akhavan [sahand.kashani-akhavan@epfl.ch]
-- Revision : 2
-- Last modified : 2018-03-06
-- #############################################################################
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity mcp3204 is
port(
-- Avalon Clock interface
clk : in std_logic;
-- Avalon Reset interface
reset : in std_logic;
-- Avalon-MM Slave interface
address : in std_logic_vector(1 downto 0);
read : in std_logic;
readdata : out std_logic_vector(31 downto 0);
-- Avalon Conduit interface
CS_N : out std_logic;
MOSI : out std_logic;
MISO : in std_logic;
SCLK : out std_logic
);
end entity;
architecture arch of mcp3204 is
constant NUM_CHANNELS : positive := 4;
constant CHANNEL_WIDTH : positive := integer(ceil(log2(real(NUM_CHANNELS))));
type data_array is array (NUM_CHANNELS - 1 downto 0) of std_logic_vector(readdata'range);
signal data_reg : data_array;
signal spi_busy, spi_start, spi_datavalid : std_logic;
signal spi_channel : std_logic_vector(1 downto 0);
signal spi_data : std_logic_vector(11 downto 0);
type state_t is (READY, INIT_READ_CHANNEL, WAIT_FOR_DATA);
signal state : state_t;
signal channel : unsigned(CHANNEL_WIDTH - 1 downto 0);
begin
SPI : entity work.mcp3204_spi
port map(
clk => clk,
reset => reset,
busy => spi_busy,
start => spi_start,
channel => spi_channel,
data_valid => spi_datavalid,
data => spi_data,
SCLK => SCLK,
CS_N => CS_N,
MOSI => MOSI,
MISO => MISO
);
-- FSM that dictates which channel is being read. The state of the component
-- should be thought as the pair (state, channel)
p_fsm : process(reset, clk)
begin
if reset = '1' then
state <= READY;
channel <= (others => '0');
elsif rising_edge(clk) then
case state is
when READY =>
if spi_busy = '0' then
state <= INIT_READ_CHANNEL;
end if;
when INIT_READ_CHANNEL =>
state <= WAIT_FOR_DATA;
when WAIT_FOR_DATA =>
if spi_datavalid = '1' then
state <= READY;
channel <= channel + 1;
end if;
end case;
end if;
end process p_fsm;
-- Updates the internal registers when a new data is available
p_data : process(reset, clk)
begin
if reset = '1' then
for i in 0 to NUM_CHANNELS - 1 loop
data_reg(i) <= (others => '0');
end loop;
elsif rising_edge(clk) then
if state = WAIT_FOR_DATA and spi_datavalid = '1' then
data_reg(to_integer(channel)) <= (31 downto 12 => '0') & spi_data;
end if;
end if;
end process p_data;
spi_start <= '1' when state = INIT_READ_CHANNEL else '0';
spi_channel <= std_logic_vector(channel);
-- Interface with the Avalon Switch Fabric
p_avalon_read : process(reset, clk)
begin
if reset = '1' then
readdata <= (others => '0');
elsif rising_edge(clk) then
if read = '1' then
readdata <= data_reg(to_integer(unsigned(address)));
end if;
end if;
end process p_avalon_read;
end architecture;

View File

@ -0,0 +1,137 @@
# TCL File Generated by Component Editor 16.0
# Sun Feb 05 18:14:06 CET 2017
# DO NOT MODIFY
#
# mcp3204 "mcp3204" v1.0
# Philemon Favrod & Sahand Kashani-Akhavan 2017.02.05.18:14:06
# 4-Channel 12-Bit A/D Converter with SPI Serial Interface
#
#
# request TCL package from ACDS 16.0
#
package require -exact qsys 16.0
#
# module mcp3204
#
set_module_property DESCRIPTION "4-Channel 12-Bit A/D Converter with SPI Serial Interface"
set_module_property NAME mcp3204
set_module_property VERSION 1.0
set_module_property INTERNAL false
set_module_property OPAQUE_ADDRESS_MAP true
set_module_property GROUP Joystick
set_module_property AUTHOR "Philemon Favrod & Sahand Kashani-Akhavan"
set_module_property DISPLAY_NAME mcp3204
set_module_property INSTANTIATE_IN_SYSTEM_MODULE true
set_module_property EDITABLE true
set_module_property REPORT_TO_TALKBACK false
set_module_property ALLOW_GREYBOX_GENERATION false
set_module_property REPORT_HIERARCHY false
#
# file sets
#
add_fileset QUARTUS_SYNTH QUARTUS_SYNTH "" ""
set_fileset_property QUARTUS_SYNTH TOP_LEVEL mcp3204
set_fileset_property QUARTUS_SYNTH ENABLE_RELATIVE_INCLUDE_PATHS false
set_fileset_property QUARTUS_SYNTH ENABLE_FILE_OVERWRITE_MODE false
add_fileset_file mcp3204.vhd VHDL PATH mcp3204.vhd TOP_LEVEL_FILE
add_fileset_file mcp3204_spi.vhd VHDL PATH mcp3204_spi.vhd
#
# parameters
#
#
# display items
#
#
# connection point clock
#
add_interface clock clock end
set_interface_property clock clockRate 0
set_interface_property clock ENABLED true
set_interface_property clock EXPORT_OF ""
set_interface_property clock PORT_NAME_MAP ""
set_interface_property clock CMSIS_SVD_VARIABLES ""
set_interface_property clock SVD_ADDRESS_GROUP ""
add_interface_port clock clk clk Input 1
#
# connection point reset
#
add_interface reset reset end
set_interface_property reset associatedClock clock
set_interface_property reset synchronousEdges DEASSERT
set_interface_property reset ENABLED true
set_interface_property reset EXPORT_OF ""
set_interface_property reset PORT_NAME_MAP ""
set_interface_property reset CMSIS_SVD_VARIABLES ""
set_interface_property reset SVD_ADDRESS_GROUP ""
add_interface_port reset reset reset Input 1
#
# connection point avalon_slave_0
#
add_interface avalon_slave_0 avalon end
set_interface_property avalon_slave_0 addressUnits WORDS
set_interface_property avalon_slave_0 associatedClock clock
set_interface_property avalon_slave_0 associatedReset reset
set_interface_property avalon_slave_0 bitsPerSymbol 8
set_interface_property avalon_slave_0 burstOnBurstBoundariesOnly false
set_interface_property avalon_slave_0 burstcountUnits WORDS
set_interface_property avalon_slave_0 explicitAddressSpan 0
set_interface_property avalon_slave_0 holdTime 0
set_interface_property avalon_slave_0 linewrapBursts false
set_interface_property avalon_slave_0 maximumPendingReadTransactions 0
set_interface_property avalon_slave_0 maximumPendingWriteTransactions 0
set_interface_property avalon_slave_0 readLatency 0
set_interface_property avalon_slave_0 readWaitTime 1
set_interface_property avalon_slave_0 setupTime 0
set_interface_property avalon_slave_0 timingUnits Cycles
set_interface_property avalon_slave_0 writeWaitTime 0
set_interface_property avalon_slave_0 ENABLED true
set_interface_property avalon_slave_0 EXPORT_OF ""
set_interface_property avalon_slave_0 PORT_NAME_MAP ""
set_interface_property avalon_slave_0 CMSIS_SVD_VARIABLES ""
set_interface_property avalon_slave_0 SVD_ADDRESS_GROUP ""
add_interface_port avalon_slave_0 address address Input 2
add_interface_port avalon_slave_0 read read Input 1
add_interface_port avalon_slave_0 readdata readdata Output 32
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isFlash 0
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isMemoryDevice 0
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isNonVolatileStorage 0
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isPrintableDevice 0
#
# connection point conduit_end
#
add_interface conduit_end conduit end
set_interface_property conduit_end associatedClock clock
set_interface_property conduit_end associatedReset ""
set_interface_property conduit_end ENABLED true
set_interface_property conduit_end EXPORT_OF ""
set_interface_property conduit_end PORT_NAME_MAP ""
set_interface_property conduit_end CMSIS_SVD_VARIABLES ""
set_interface_property conduit_end SVD_ADDRESS_GROUP ""
add_interface_port conduit_end CS_N cs_n Output 1
add_interface_port conduit_end MOSI mosi Output 1
add_interface_port conduit_end MISO miso Input 1
add_interface_port conduit_end SCLK sclk Output 1

View File

@ -0,0 +1,87 @@
-- #############################################################################
-- mcp3204_spi.vhd
-- ===============
-- MCP3204 SPI interface.
--
-- Author : Philémon Favrod [philemon.favrod@epfl.ch]
-- Author : Sahand Kashani-Akhavan [sahand.kashani-akhavan@epfl.ch]
-- Author : <insert your name> (<insert your e-mail address>)
-- Revision : 1
-- Last modified : <insert date>
-- #############################################################################
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mcp3204_spi is
port(
-- 50 MHz
clk : in std_logic;
reset : in std_logic;
busy : out std_logic;
start : in std_logic;
channel : in std_logic_vector(1 downto 0);
data_valid : out std_logic;
data : out std_logic_vector(11 downto 0);
-- 1 MHz
SCLK : out std_logic;
CS_N : out std_logic;
MOSI : out std_logic;
MISO : in std_logic
);
end mcp3204_spi;
architecture rtl of mcp3204_spi is
signal reg_clk_divider_counter : unsigned(4 downto 0) := (others => '0'); -- need to be able to count until 24
signal reg_spi_en : std_logic := '0'; -- pulses every 0.5 MHz
signal reg_rising_edge_sclk : std_logic := '0';
signal reg_falling_edge_sclk : std_logic := '0';
signal reg_sclk : std_logic := '0';
begin
clk_divider_generation : process(clk, reset)
begin
if reset = '1' then
reg_clk_divider_counter <= (others => '0');
elsif rising_edge(clk) then
reg_clk_divider_counter <= reg_clk_divider_counter + 1;
reg_spi_en <= '0';
reg_rising_edge_sclk <= '0';
reg_falling_edge_sclk <= '0';
if reg_clk_divider_counter = 24 then
reg_clk_divider_counter <= (others => '0');
reg_spi_en <= '1';
if reg_sclk = '0' then
reg_rising_edge_sclk <= '1';
elsif reg_sclk = '1' then
reg_falling_edge_sclk <= '1';
end if;
end if;
end if;
end process;
SCLK_generation : process(clk, reset)
begin
if reset = '1' then
reg_sclk <= '0';
elsif rising_edge(clk) then
if reg_spi_en = '1' then
reg_sclk <= not reg_sclk;
end if;
end if;
end process;
STATE_LOGIC : process(clk, reset)
begin
-- TODO: complete this process
if reset = '1' then
elsif rising_edge(clk) then
end if;
end process;
end architecture rtl;

View File

@ -0,0 +1,105 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library osvvm;
use osvvm.RandomPkg.all;
entity tb_mcp3204 is
end entity;
architecture rtl of tb_mcp3204 is
constant CLK_PERIOD : time := 20 ns;
signal clk : std_logic := '0';
signal reset : std_logic := '0';
signal sim_finished : boolean := false;
-- mcp3204 -----------------------------------------------------------------
signal address : std_logic_vector(1 downto 0) := (others => '0');
signal read : std_logic := '0';
signal readdata : std_logic_vector(31 downto 0) := (others => '0');
signal CS_N : std_logic := '0';
signal MOSI : std_logic := '0';
signal MISO : std_logic := '0';
signal SCLK : std_logic := '0';
begin
duv : entity work.mcp3204
port map(
clk => clk,
reset => reset,
address => address,
read => read,
readdata => readdata,
CS_N => CS_N,
MOSI => MOSI,
MISO => MISO,
SCLK => SCLK
);
clk <= not clk after CLK_PERIOD / 2 when not sim_finished;
MISO_generation : process
variable rand_gen : RandomPType;
variable rint : integer;
begin
rand_gen.InitSeed(rand_gen'instance_name);
rand_gen.SetRandomParm(UNIFORM);
while true loop
if not sim_finished then
wait until falling_edge(SCLK);
rint := rand_gen.RandInt(0, 1);
if rint = 0 then
MISO <= '0';
else
MISO <= '1';
end if;
else
wait;
end if;
end loop;
end process MISO_generation;
sim : process
procedure async_reset is
begin
wait until rising_edge(clk);
wait for CLK_PERIOD / 4;
reset <= '1';
wait for CLK_PERIOD / 2;
reset <= '0';
end procedure async_reset;
procedure read_register(constant channel_number : natural range 0 to 3) is
begin
wait until falling_edge(clk);
address <= std_logic_vector(to_unsigned(channel_number, address'length));
read <= '1';
wait until falling_edge(clk);
address <= (others => '0');
read <= '0';
wait until falling_edge(clk);
end procedure;
begin
async_reset;
wait for 10000 * CLK_PERIOD;
for i in 0 to 3 loop
read_register(i);
end loop;
sim_finished <= true;
wait;
end process sim;
end architecture rtl;

View File

@ -0,0 +1,103 @@
-- #############################################################################
-- tb_mcp3204_spi.vhd
-- ==================
-- Testbench for MCP3204 SPI interface.
--
-- Author : Sahand Kashani-Akhavan [sahand.kashani-akhavan@epfl.ch]
-- Revision : 1
-- Last modified : 2018-03-06
-- #############################################################################
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_mcp3204_spi is
end entity;
architecture rtl of tb_mcp3204_spi is
constant CLK_PERIOD : time := 20 ns;
signal clk : std_logic := '0';
signal reset : std_logic := '0';
signal sim_finished : boolean := false;
-- mcp3204_spi ------------------------------------------------------------
signal busy : std_logic := '0';
signal start : std_logic := '0';
signal channel : std_logic_vector(1 downto 0) := (others => '0');
signal data_valid : std_logic := '0';
signal data : std_logic_vector(11 downto 0) := (others => '0');
signal SCLK : std_logic := '0';
signal CS_N : std_logic := '1';
signal MOSI : std_logic := '0';
signal MISO : std_logic := '0';
begin
duv : entity work.mcp3204_spi
port map(
clk => clk,
reset => reset,
busy => busy,
start => start,
channel => channel,
data_valid => data_valid,
data => data,
SCLK => SCLK,
CS_N => CS_N,
MOSI => MOSI,
MISO => MISO
);
clk <= not clk after CLK_PERIOD / 2 when not sim_finished;
sim : process
procedure async_reset is
begin
wait until rising_edge(clk);
wait for CLK_PERIOD / 4;
reset <= '1';
wait for CLK_PERIOD / 2;
reset <= '0';
end procedure async_reset;
procedure spi_transfer(constant channel_number : natural range 0 to 3) is
begin
if busy = '1' then
wait until busy = '0';
else
wait until falling_edge(clk);
start <= '1';
channel <= std_logic_vector(to_unsigned(channel_number, channel'length));
wait until falling_edge(clk);
start <= '0';
channel <= (others => '0');
wait until rising_edge(data_valid);
wait until falling_edge(busy);
end if;
end procedure spi_transfer;
begin
async_reset;
MISO <= '1';
spi_transfer(0);
MISO <= '0';
spi_transfer(1);
MISO <= '1';
spi_transfer(2);
MISO <= '0';
spi_transfer(3);
sim_finished <= true;
wait;
end process sim;
end architecture rtl;

View File

@ -0,0 +1,139 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.utils.all;
entity avalon_st_spi_master is
generic(
INPUT_CLK_FREQ : integer := 50000000;
SPI_SCLK_FREQ : integer := 10000000;
CPOL : integer := 1;
CPHA : integer := 1
);
port(
-- Input clock
clk : in std_logic;
-- Reset
reset : in std_logic;
spi_cs_n : in std_logic;
-- Sink Avalon ST Interface
mosi_sink_data : in std_logic_vector(7 downto 0);
mosi_sink_valid : in std_logic;
mosi_sink_ready : out std_logic;
-- Source Avalon ST Interface
miso_src_data : out std_logic_vector(7 downto 0);
miso_src_valid : out std_logic;
-- SPI Master signals
SCLK : out std_logic;
MISO : in std_logic;
MOSI : out std_logic;
CS_n : out std_logic
);
end avalon_st_spi_master;
architecture rtl of avalon_st_spi_master is
constant SCLK_PRESCALER_MAX : integer := INPUT_CLK_FREQ / SPI_SCLK_FREQ / 2;
signal sclk_prescaler : unsigned(bitlength(SCLK_PRESCALER_MAX) downto 0);
signal sclk_toggle : std_logic;
signal new_sink_buffer, cur_sink_buffer : std_logic_vector(mosi_sink_data'range);
signal new_sink_buffer_busy, cur_sink_buffer_busy : std_logic;
signal miso_src_buffer : std_logic_vector(7 downto 0);
signal spi_done, i_sclk : std_logic;
signal spi_bit_index : unsigned(2 downto 0);
begin
CS_n <= spi_cs_n;
p_sclk_prescaler : process(clk, reset) is
begin
if reset = '1' then
sclk_prescaler <= to_unsigned(1, sclk_prescaler'length);
elsif rising_edge(clk) then
if sclk_prescaler = SCLK_PRESCALER_MAX then
sclk_prescaler <= to_unsigned(1, sclk_prescaler'length);
else
sclk_prescaler <= sclk_prescaler + 1;
end if;
end if;
end process p_sclk_prescaler;
sclk_toggle <= '1' when sclk_prescaler = SCLK_PRESCALER_MAX else '0';
p_avalon_st_sink : process(clk, reset) is
begin
if reset = '1' then
new_sink_buffer_busy <= '0';
new_sink_buffer <= (others => '0');
elsif rising_edge(clk) then
if mosi_sink_valid = '1' then
if new_sink_buffer_busy = '0' and cur_sink_buffer_busy = '1' then
new_sink_buffer <= mosi_sink_data;
new_sink_buffer_busy <= '1';
end if;
elsif new_sink_buffer_busy = '1' and cur_sink_buffer_busy = '0' then
new_sink_buffer_busy <= '0';
end if;
end if;
end process p_avalon_st_sink;
mosi_sink_ready <= not new_sink_buffer_busy;
p_cur_buffer : process(clk, reset) is
begin
if reset = '1' then
cur_sink_buffer <= (others => '0');
cur_sink_buffer_busy <= '0';
elsif rising_edge(clk) then
if mosi_sink_valid = '1' and cur_sink_buffer_busy = '0' then
cur_sink_buffer <= mosi_sink_data;
cur_sink_buffer_busy <= '1';
elsif cur_sink_buffer_busy = '0' and new_sink_buffer_busy = '1' then
cur_sink_buffer <= new_sink_buffer;
cur_sink_buffer_busy <= '1';
elsif cur_sink_buffer_busy = '1' and spi_done = '1' then
cur_sink_buffer_busy <= '0';
end if;
end if;
end process p_cur_buffer;
p_spi : process(clk, reset) is
begin
if reset = '1' then
spi_done <= '0';
i_sclk <= to_unsigned(CPOL, 1)(0);
spi_bit_index <= "000";
MOSI <= '0';
miso_src_data <= (others => '0');
miso_src_valid <= '0';
miso_src_buffer <= (others => '0');
elsif rising_edge(clk) then
spi_done <= '0';
miso_src_valid <= '0';
if cur_sink_buffer_busy = '1' and sclk_toggle = '1' then
if i_sclk /= to_unsigned(CPHA, 1)(0) then
if spi_bit_index = "111" then
spi_done <= '1';
spi_bit_index <= "000";
miso_src_valid <= '1';
miso_src_data <= miso_src_buffer(7 downto 1) & MISO;
else
MOSI <= cur_sink_buffer(7 - to_integer(spi_bit_index));
miso_src_buffer(7 - to_integer(spi_bit_index)) <= MISO;
spi_bit_index <= spi_bit_index + 1;
end if;
end if;
i_sclk <= not i_sclk;
end if;
end if;
end process p_spi;
SCLK <= i_sclk;
end rtl;

View File

@ -0,0 +1,87 @@
-------------------------------------------------------------------------------
-- Title : Byte stream to pixel converter for the Lepton Camera
-- Project : PrSoC
-------------------------------------------------------------------------------
-- File : byte2pix.vhd
-- Author : Philemon Orphee Favrod <pofavrod@lappc5.epfl.ch>
-- Company :
-- Created : 2016-03-21
-- Last update: 2017-03-19
-- Platform :
-- Standard : VHDL'87
-------------------------------------------------------------------------------
-- Description: Converts a byte stream to a 14-bit pixel stream.
-------------------------------------------------------------------------------
-- Copyright (c) 2016
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2016-03-21 1.0 pofavrod Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity byte2pix is
port(
clk, reset : in std_logic;
byte_data : in std_logic_vector(7 downto 0);
byte_valid : in std_logic;
byte_sof : in std_logic;
byte_eof : in std_logic;
pix_data : out std_logic_vector(13 downto 0);
pix_valid : out std_logic;
pix_sof : out std_logic;
pix_eof : out std_logic);
end byte2pix;
architecture rtl of byte2pix is
signal last_sof : std_logic;
signal msb : std_logic_vector(5 downto 0);
signal cnt : std_logic; -- used to skip msb sampling every other time
begin
process(clk, reset)
begin
if reset = '1' then
msb <= (others => '0');
cnt <= '0';
last_sof <= '0';
elsif rising_edge(clk) then
if byte_valid = '1' then
if cnt = '0' then
msb <= byte_data(5 downto 0);
last_sof <= byte_sof;
end if;
cnt <= not cnt;
end if;
end if;
end process;
process(clk, reset)
begin
if reset = '1' then
pix_data <= (others => '0');
pix_valid <= '0';
pix_sof <= '0';
pix_eof <= '0';
elsif rising_edge(clk) then
pix_data <= (others => '0');
pix_valid <= '0';
pix_sof <= '0';
pix_eof <= '0';
if byte_valid = '1' then
if cnt = '1' then
pix_data <= msb & byte_data;
pix_valid <= '1';
pix_sof <= last_sof;
pix_eof <= byte_eof;
end if;
end if;
end if;
end process;
end architecture rtl;

View File

@ -0,0 +1,192 @@
-- megafunction wizard: %RAM: 2-PORT%
-- GENERATION: STANDARD
-- VERSION: WM1.0
-- MODULE: altsyncram
-- ============================================================
-- File Name: dual_ported_ram.vhd
-- Megafunction Name(s):
-- altsyncram
--
-- Simulation Library Files(s):
-- altera_mf
-- ============================================================
-- ************************************************************
-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
--
-- 15.1.0 Build 185 10/21/2015 SJ Lite Edition
-- ************************************************************
--Copyright (C) 1991-2015 Altera Corporation. All rights reserved.
--Your use of Altera Corporation's design tools, logic functions
--and other software and tools, and its AMPP partner logic
--functions, and any output files from any of the foregoing
--(including device programming or simulation files), and any
--associated documentation or information are expressly subject
--to the terms and conditions of the Altera Program License
--Subscription Agreement, the Altera Quartus Prime License Agreement,
--the Altera MegaCore Function License Agreement, or other
--applicable license agreement, including, without limitation,
--that your use is for the sole purpose of programming logic
--devices manufactured by Altera and sold by Altera or its
--authorized distributors. Please refer to the applicable
--agreement for further details.
library ieee;
use ieee.std_logic_1164.all;
library altera_mf;
use altera_mf.altera_mf_components.all;
entity dual_ported_ram is
port(
clock : in std_logic := '1';
data : in std_logic_vector(15 downto 0);
rdaddress : in std_logic_vector(12 downto 0);
wraddress : in std_logic_vector(12 downto 0);
wren : in std_logic := '0';
q : out std_logic_vector(15 downto 0)
);
end dual_ported_ram;
architecture SYN of dual_ported_ram is
signal sub_wire0 : std_logic_vector(15 downto 0);
begin
q <= sub_wire0(15 downto 0);
altsyncram_component : altsyncram
generic map(
address_aclr_b => "NONE",
address_reg_b => "CLOCK0",
clock_enable_input_a => "BYPASS",
clock_enable_input_b => "BYPASS",
clock_enable_output_b => "BYPASS",
intended_device_family => "Cyclone V",
lpm_type => "altsyncram",
numwords_a => 8192,
numwords_b => 8192,
operation_mode => "DUAL_PORT",
outdata_aclr_b => "NONE",
outdata_reg_b => "CLOCK0",
power_up_uninitialized => "FALSE",
read_during_write_mode_mixed_ports => "DONT_CARE",
widthad_a => 13,
widthad_b => 13,
width_a => 16,
width_b => 16,
width_byteena_a => 1
)
port map(
address_a => wraddress,
address_b => rdaddress,
clock0 => clock,
data_a => data,
wren_a => wren,
q_b => sub_wire0
);
end SYN;
-- ============================================================
-- CNX file retrieval info
-- ============================================================
-- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0"
-- Retrieval info: PRIVATE: ADDRESSSTALL_B NUMERIC "0"
-- Retrieval info: PRIVATE: BYTEENA_ACLR_A NUMERIC "0"
-- Retrieval info: PRIVATE: BYTEENA_ACLR_B NUMERIC "0"
-- Retrieval info: PRIVATE: BYTE_ENABLE_A NUMERIC "0"
-- Retrieval info: PRIVATE: BYTE_ENABLE_B NUMERIC "0"
-- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8"
-- Retrieval info: PRIVATE: BlankMemory NUMERIC "1"
-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0"
-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_B NUMERIC "0"
-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0"
-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_B NUMERIC "0"
-- Retrieval info: PRIVATE: CLRdata NUMERIC "0"
-- Retrieval info: PRIVATE: CLRq NUMERIC "0"
-- Retrieval info: PRIVATE: CLRrdaddress NUMERIC "0"
-- Retrieval info: PRIVATE: CLRrren NUMERIC "0"
-- Retrieval info: PRIVATE: CLRwraddress NUMERIC "0"
-- Retrieval info: PRIVATE: CLRwren NUMERIC "0"
-- Retrieval info: PRIVATE: Clock NUMERIC "0"
-- Retrieval info: PRIVATE: Clock_A NUMERIC "0"
-- Retrieval info: PRIVATE: Clock_B NUMERIC "0"
-- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0"
-- Retrieval info: PRIVATE: INDATA_ACLR_B NUMERIC "0"
-- Retrieval info: PRIVATE: INDATA_REG_B NUMERIC "0"
-- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_B"
-- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0"
-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
-- Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0"
-- Retrieval info: PRIVATE: JTAG_ID STRING "NONE"
-- Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0"
-- Retrieval info: PRIVATE: MEMSIZE NUMERIC "131072"
-- Retrieval info: PRIVATE: MEM_IN_BITS NUMERIC "0"
-- Retrieval info: PRIVATE: MIFfilename STRING ""
-- Retrieval info: PRIVATE: OPERATION_MODE NUMERIC "2"
-- Retrieval info: PRIVATE: OUTDATA_ACLR_B NUMERIC "0"
-- Retrieval info: PRIVATE: OUTDATA_REG_B NUMERIC "1"
-- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_MIXED_PORTS NUMERIC "2"
-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3"
-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_B NUMERIC "3"
-- Retrieval info: PRIVATE: REGdata NUMERIC "1"
-- Retrieval info: PRIVATE: REGq NUMERIC "1"
-- Retrieval info: PRIVATE: REGrdaddress NUMERIC "1"
-- Retrieval info: PRIVATE: REGrren NUMERIC "1"
-- Retrieval info: PRIVATE: REGwraddress NUMERIC "1"
-- Retrieval info: PRIVATE: REGwren NUMERIC "1"
-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
-- Retrieval info: PRIVATE: USE_DIFF_CLKEN NUMERIC "0"
-- Retrieval info: PRIVATE: UseDPRAM NUMERIC "1"
-- Retrieval info: PRIVATE: VarWidth NUMERIC "0"
-- Retrieval info: PRIVATE: WIDTH_READ_A NUMERIC "16"
-- Retrieval info: PRIVATE: WIDTH_READ_B NUMERIC "16"
-- Retrieval info: PRIVATE: WIDTH_WRITE_A NUMERIC "16"
-- Retrieval info: PRIVATE: WIDTH_WRITE_B NUMERIC "16"
-- Retrieval info: PRIVATE: WRADDR_ACLR_B NUMERIC "0"
-- Retrieval info: PRIVATE: WRADDR_REG_B NUMERIC "0"
-- Retrieval info: PRIVATE: WRCTRL_ACLR_B NUMERIC "0"
-- Retrieval info: PRIVATE: enable NUMERIC "0"
-- Retrieval info: PRIVATE: rden NUMERIC "0"
-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
-- Retrieval info: CONSTANT: ADDRESS_ACLR_B STRING "NONE"
-- Retrieval info: CONSTANT: ADDRESS_REG_B STRING "CLOCK0"
-- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS"
-- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_B STRING "BYPASS"
-- Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_B STRING "BYPASS"
-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
-- Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram"
-- Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "8192"
-- Retrieval info: CONSTANT: NUMWORDS_B NUMERIC "8192"
-- Retrieval info: CONSTANT: OPERATION_MODE STRING "DUAL_PORT"
-- Retrieval info: CONSTANT: OUTDATA_ACLR_B STRING "NONE"
-- Retrieval info: CONSTANT: OUTDATA_REG_B STRING "CLOCK0"
-- Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE"
-- Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_MIXED_PORTS STRING "DONT_CARE"
-- Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "13"
-- Retrieval info: CONSTANT: WIDTHAD_B NUMERIC "13"
-- Retrieval info: CONSTANT: WIDTH_A NUMERIC "16"
-- Retrieval info: CONSTANT: WIDTH_B NUMERIC "16"
-- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1"
-- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock"
-- Retrieval info: USED_PORT: data 0 0 16 0 INPUT NODEFVAL "data[15..0]"
-- Retrieval info: USED_PORT: q 0 0 16 0 OUTPUT NODEFVAL "q[15..0]"
-- Retrieval info: USED_PORT: rdaddress 0 0 13 0 INPUT NODEFVAL "rdaddress[12..0]"
-- Retrieval info: USED_PORT: wraddress 0 0 13 0 INPUT NODEFVAL "wraddress[12..0]"
-- Retrieval info: USED_PORT: wren 0 0 0 0 INPUT GND "wren"
-- Retrieval info: CONNECT: @address_a 0 0 13 0 wraddress 0 0 13 0
-- Retrieval info: CONNECT: @address_b 0 0 13 0 rdaddress 0 0 13 0
-- Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0
-- Retrieval info: CONNECT: @data_a 0 0 16 0 data 0 0 16 0
-- Retrieval info: CONNECT: @wren_a 0 0 0 0 wren 0 0 0 0
-- Retrieval info: CONNECT: q 0 0 16 0 @q_b 0 0 16 0
-- Retrieval info: GEN_FILE: TYPE_NORMAL dual_ported_ram.vhd TRUE
-- Retrieval info: GEN_FILE: TYPE_NORMAL dual_ported_ram.inc FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL dual_ported_ram.cmp FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL dual_ported_ram.bsf FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL dual_ported_ram_inst.vhd FALSE
-- Retrieval info: LIB_FILE: altera_mf

View File

@ -0,0 +1,288 @@
-- Lepton Avalon Memory-Mapped Slave Interface
-- Author: Philémon Favrod (philemon.favrod@epfl.ch)
-- Modified by: Sahand Kashani-Akhavan (sahand.kashani-akhavan@epfl.ch)
-- Revision: 2
-- Register map
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | RegNo | Name | Access | Description |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 0 | COMMAND | WO | Command |
-- | | | | - Writing 1 starts capturing a frame & resets the |
-- | | | | ERROR bit (bit 1) in the STATUS register. |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 1 | STATUS | RO | Status |
-- | | | | - Bit 0: 0 --> no capture in progress. |
-- | | | | 1 --> capture in progress. |
-- | | | | - Bit 1: 0 --> previous capture successful. |
-- | | | | 1 --> error during previous capture. |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 2 | MIN | RO | Minimum pixel value in frame. |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 3 | MAX | RO | Maximum pixel value in frame. |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 4 | SUM_LSB | RO | Sum of all pixels in frame (low 16 bits). |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 5 | SUM_MSB | RO | Sum of all pixels in frame (high 16 bits). |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 6 | ROW_IDX | RO | Current line being captured (1 <= ROW_IDX <= 60). |
-- | | | | Available for debugging purposes. |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 7 | RESERVED | - | Reserved |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 8 - 4807 | RAW BUFFER | RO | View into RAW pixel buffer. |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 4808 - 8191 | RESERVED | - | Reserved |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 8192 - 12991 | ADJUSTED BUFFER | RO | View into adjusted (scaled) pixel buffer. |
-- | | | | Values are scaled between MIN and MAX. |
-- +---------------+-----------------+--------+---------------------------------------------------+
-- | 12992 - 16383 | RESERVED | - | Reserved |
-- +---------------+-----------------+--------+---------------------------------------------------+
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity lepton is
port(
clk : in std_logic;
reset : in std_logic;
address : in std_logic_vector(13 downto 0);
readdata : out std_logic_vector(15 downto 0);
writedata : in std_logic_vector(15 downto 0);
read : in std_logic;
write : in std_logic;
SCLK : out std_logic;
CSn : out std_logic;
MOSI : out std_logic;
MISO : in std_logic
);
end lepton;
architecture rtl of lepton is
signal spi_cs_n : std_logic;
signal spi_mosi_data : std_logic_vector(7 downto 0);
signal spi_mosi_valid : std_logic;
signal spi_mosi_ready : std_logic;
signal spi_miso_data : std_logic_vector(7 downto 0);
signal spi_miso_valid : std_logic;
signal lepton_manager_start : std_logic;
signal lepton_manager_error : std_logic;
signal byte_data : std_logic_vector(7 downto 0);
signal byte_valid : std_logic;
signal byte_sof : std_logic;
signal byte_eof : std_logic;
signal pix_data : std_logic_vector(13 downto 0);
signal pix_valid : std_logic;
signal pix_sof : std_logic;
signal pix_eof : std_logic;
signal stat_min : std_logic_vector(13 downto 0);
signal stat_max : std_logic_vector(13 downto 0);
signal stat_sum : std_logic_vector(26 downto 0);
signal stat_valid : std_logic;
signal ram_data : std_logic_vector(15 downto 0);
signal ram_wren : std_logic;
signal ram_wraddress : std_logic_vector(12 downto 0);
signal ram_rdaddress : std_logic_vector(12 downto 0);
signal ram_q : std_logic_vector(15 downto 0);
signal row_idx : std_logic_vector(5 downto 0);
signal raw_pixel : std_logic_vector(13 downto 0);
signal raw_max : std_logic_vector(13 downto 0);
signal raw_min : std_logic_vector(13 downto 0);
signal raw_sum : std_logic_vector(26 downto 0);
signal adjusted_pixel : std_logic_vector(13 downto 0);
constant COMMAND_REG_OFFSET : std_logic_vector(address'range) := "00000000000000";
constant STATUS_REG_OFFSET : std_logic_vector(address'range) := "00000000000001";
constant MIN_REG_OFFSET : std_logic_vector(address'range) := "00000000000010";
constant MAX_REG_OFFSET : std_logic_vector(address'range) := "00000000000011";
constant SUM_LSB_REG_OFFSET : std_logic_vector(address'range) := "00000000000100";
constant SUM_MSB_REG_OFFSET : std_logic_vector(address'range) := "00000000000101";
constant ROW_IDX_REG_OFFSET : std_logic_vector(address'range) := "00000000000110";
constant BUFFER_REG_OFFSET : unsigned(address'range) := "00000000001000";
constant ADJUSTED_BUFFER_REG_OFFSET : unsigned(address'range) := "10000000000000";
constant IMAGE_SIZE : integer := 80 * 60;
constant BUFFER_REG_LIMIT : unsigned(address'range) := unsigned(BUFFER_REG_OFFSET) + IMAGE_SIZE;
constant ADJUSTED_BUFFER_LIMIT : unsigned(address'range) := unsigned(ADJUSTED_BUFFER_REG_OFFSET) + IMAGE_SIZE;
signal max_reg : std_logic_vector(stat_max'range);
signal min_reg : std_logic_vector(stat_min'range);
signal sum_reg : std_logic_vector(stat_sum'range);
signal error_reg : std_logic;
begin
spi_controller0 : entity work.avalon_st_spi_master
port map(
clk => clk,
reset => reset,
spi_cs_n => spi_cs_n,
mosi_sink_data => spi_mosi_data,
mosi_sink_valid => spi_mosi_valid,
mosi_sink_ready => spi_mosi_ready,
miso_src_data => spi_miso_data,
miso_src_valid => spi_miso_valid,
SCLK => SCLK,
MISO => MISO,
MOSI => MOSI,
CS_n => CSn
);
lepton_manager0 : entity work.lepton_manager
port map(
clk => clk,
reset => reset,
spi_miso_sink_data => spi_miso_data,
spi_miso_sink_valid => spi_miso_valid,
spi_mosi_src_data => spi_mosi_data,
spi_mosi_src_valid => spi_mosi_valid,
spi_mosi_src_ready => spi_mosi_ready,
lepton_out_data => byte_data,
lepton_out_valid => byte_valid,
lepton_out_sof => byte_sof,
lepton_out_eof => byte_eof,
row_idx => row_idx,
error => lepton_manager_error,
start => lepton_manager_start,
spi_cs_n => spi_cs_n
);
byte2pix0 : entity work.byte2pix
port map(
clk => clk,
reset => reset,
byte_data => byte_data,
byte_valid => byte_valid,
byte_sof => byte_sof,
byte_eof => byte_eof,
pix_data => pix_data,
pix_valid => pix_valid,
pix_sof => pix_sof,
pix_eof => pix_eof
);
lepton_stats0 : entity work.lepton_stats
port map(
reset => reset,
clk => clk,
pix_data => pix_data,
pix_valid => pix_valid,
pix_sof => pix_sof,
pix_eof => pix_eof,
stat_min => stat_min,
stat_max => stat_max,
stat_sum => stat_sum,
stat_valid => stat_valid
);
ram_writer0 : entity work.ram_writer
port map(
clk => clk,
reset => reset,
pix_data => pix_data,
pix_valid => pix_valid,
pix_sof => pix_sof,
pix_eof => pix_eof,
ram_data => ram_data,
ram_wren => ram_wren,
ram_wraddress => ram_wraddress
);
dual_ported_ram0 : entity work.dual_ported_ram
port map(
clock => clk,
data => ram_data,
rdaddress => ram_rdaddress,
wraddress => ram_wraddress,
wren => ram_wren,
q => ram_q
);
level_adjuster0 : entity work.level_adjuster
port map(
clk => clk,
raw_pixel => ram_q(13 downto 0),
raw_max => max_reg,
raw_min => min_reg,
raw_sum => sum_reg,
adjusted_pixel => adjusted_pixel
);
p_lepton_start : process(clk, reset)
begin
if reset = '1' then
lepton_manager_start <= '0';
error_reg <= '0';
elsif rising_edge(clk) then
if write = '1' and address = COMMAND_REG_OFFSET then
lepton_manager_start <= writedata(0);
error_reg <= '0';
elsif pix_eof = '1' then
lepton_manager_start <= '0';
elsif lepton_manager_error = '1' then
error_reg <= '1';
end if;
end if;
end process p_lepton_start;
p_stat_reg : process(clk, reset)
begin
if reset = '1' then
min_reg <= (others => '0');
max_reg <= (others => '0');
sum_reg <= (others => '0');
elsif rising_edge(clk) then
if stat_valid = '1' then
min_reg <= stat_min;
max_reg <= stat_max;
sum_reg <= stat_sum;
end if;
end if;
end process p_stat_reg;
p_read : process(clk, reset)
begin
if reset = '1' then
readdata <= (others => '0');
ram_rdaddress <= (others => '0');
elsif rising_edge(clk) then
readdata <= (others => '0');
if read = '1' then
case address is
when STATUS_REG_OFFSET =>
readdata(1) <= error_reg;
readdata(0) <= lepton_manager_start;
when MIN_REG_OFFSET =>
readdata <= "00" & min_reg;
when MAX_REG_OFFSET =>
readdata <= "00" & max_reg;
when SUM_MSB_REG_OFFSET =>
readdata <= "00000" & sum_reg(26 downto 16);
when SUM_LSB_REG_OFFSET =>
readdata <= sum_reg(15 downto 0);
when ROW_IDX_REG_OFFSET =>
readdata(5 downto 0) <= row_idx;
when others =>
if unsigned(address) >= BUFFER_REG_OFFSET and unsigned(address) < BUFFER_REG_LIMIT then
ram_rdaddress <= std_logic_vector(resize(unsigned(address) - BUFFER_REG_OFFSET, ram_rdaddress'length));
readdata <= ram_q;
elsif unsigned(address) >= ADJUSTED_BUFFER_REG_OFFSET and unsigned(address) < ADJUSTED_BUFFER_LIMIT then
ram_rdaddress <= std_logic_vector(resize(unsigned(address) - ADJUSTED_BUFFER_REG_OFFSET, ram_rdaddress'length));
readdata <= "00" & adjusted_pixel;
end if;
end case;
end if;
end if;
end process p_read;
end rtl;

View File

@ -0,0 +1,148 @@
# TCL File Generated by Component Editor 16.0
# Sun Feb 05 19:05:24 CET 2017
# DO NOT MODIFY
#
# lepton "lepton" v1.0
# Philemon Favrod & Sahand Kashani-Akhavan 2017.02.05.19:05:24
# IR Camera 80x60
#
#
# request TCL package from ACDS 16.0
#
package require -exact qsys 16.0
#
# module lepton
#
set_module_property DESCRIPTION "IR Camera 80x60"
set_module_property NAME lepton
set_module_property VERSION 1.0
set_module_property INTERNAL false
set_module_property OPAQUE_ADDRESS_MAP true
set_module_property GROUP Camera
set_module_property AUTHOR "Philemon Favrod & Sahand Kashani-Akhavan"
set_module_property DISPLAY_NAME lepton
set_module_property INSTANTIATE_IN_SYSTEM_MODULE true
set_module_property EDITABLE true
set_module_property REPORT_TO_TALKBACK false
set_module_property ALLOW_GREYBOX_GENERATION false
set_module_property REPORT_HIERARCHY false
#
# file sets
#
add_fileset QUARTUS_SYNTH QUARTUS_SYNTH "" ""
set_fileset_property QUARTUS_SYNTH TOP_LEVEL lepton
set_fileset_property QUARTUS_SYNTH ENABLE_RELATIVE_INCLUDE_PATHS false
set_fileset_property QUARTUS_SYNTH ENABLE_FILE_OVERWRITE_MODE false
add_fileset_file avalon_st_spi_master.vhd VHDL PATH avalon_st_spi_master.vhd
add_fileset_file byte2pix.vhd VHDL PATH byte2pix.vhd
add_fileset_file dual_ported_ram.vhd VHDL PATH dual_ported_ram.vhd
add_fileset_file lepton.vhd VHDL PATH lepton.vhd TOP_LEVEL_FILE
add_fileset_file lepton_manager.vhd VHDL PATH lepton_manager.vhd
add_fileset_file lepton_stats.vhd VHDL PATH lepton_stats.vhd
add_fileset_file ram_writer.vhd VHDL PATH ram_writer.vhd
add_fileset_file utils.vhd VHDL PATH utils.vhd
add_fileset_file level_adjuster.vhd VHDL PATH level_adjuster.vhd
add_fileset_file lpm_divider.vhd VHDL PATH lpm_divider.vhd
#
# parameters
#
#
# display items
#
#
# connection point clock
#
add_interface clock clock end
set_interface_property clock clockRate 0
set_interface_property clock ENABLED true
set_interface_property clock EXPORT_OF ""
set_interface_property clock PORT_NAME_MAP ""
set_interface_property clock CMSIS_SVD_VARIABLES ""
set_interface_property clock SVD_ADDRESS_GROUP ""
add_interface_port clock clk clk Input 1
#
# connection point reset
#
add_interface reset reset end
set_interface_property reset associatedClock clock
set_interface_property reset synchronousEdges DEASSERT
set_interface_property reset ENABLED true
set_interface_property reset EXPORT_OF ""
set_interface_property reset PORT_NAME_MAP ""
set_interface_property reset CMSIS_SVD_VARIABLES ""
set_interface_property reset SVD_ADDRESS_GROUP ""
add_interface_port reset reset reset Input 1
#
# connection point avalon_slave_0
#
add_interface avalon_slave_0 avalon end
set_interface_property avalon_slave_0 addressUnits WORDS
set_interface_property avalon_slave_0 associatedClock clock
set_interface_property avalon_slave_0 associatedReset reset
set_interface_property avalon_slave_0 bitsPerSymbol 8
set_interface_property avalon_slave_0 burstOnBurstBoundariesOnly false
set_interface_property avalon_slave_0 burstcountUnits WORDS
set_interface_property avalon_slave_0 explicitAddressSpan 0
set_interface_property avalon_slave_0 holdTime 0
set_interface_property avalon_slave_0 linewrapBursts false
set_interface_property avalon_slave_0 maximumPendingReadTransactions 0
set_interface_property avalon_slave_0 maximumPendingWriteTransactions 0
set_interface_property avalon_slave_0 readLatency 0
set_interface_property avalon_slave_0 readWaitStates 9
set_interface_property avalon_slave_0 readWaitTime 9
set_interface_property avalon_slave_0 setupTime 0
set_interface_property avalon_slave_0 timingUnits Cycles
set_interface_property avalon_slave_0 writeWaitTime 0
set_interface_property avalon_slave_0 ENABLED true
set_interface_property avalon_slave_0 EXPORT_OF ""
set_interface_property avalon_slave_0 PORT_NAME_MAP ""
set_interface_property avalon_slave_0 CMSIS_SVD_VARIABLES ""
set_interface_property avalon_slave_0 SVD_ADDRESS_GROUP ""
add_interface_port avalon_slave_0 address address Input 14
add_interface_port avalon_slave_0 readdata readdata Output 16
add_interface_port avalon_slave_0 writedata writedata Input 16
add_interface_port avalon_slave_0 read read Input 1
add_interface_port avalon_slave_0 write write Input 1
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isFlash 0
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isMemoryDevice 0
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isNonVolatileStorage 0
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isPrintableDevice 0
#
# connection point spi
#
add_interface spi conduit end
set_interface_property spi associatedClock clock
set_interface_property spi associatedReset ""
set_interface_property spi ENABLED true
set_interface_property spi EXPORT_OF ""
set_interface_property spi PORT_NAME_MAP ""
set_interface_property spi CMSIS_SVD_VARIABLES ""
set_interface_property spi SVD_ADDRESS_GROUP ""
add_interface_port spi CSn cs_n Output 1
add_interface_port spi MISO miso Input 1
add_interface_port spi MOSI mosi Output 1
add_interface_port spi SCLK sclk Output 1

View File

@ -0,0 +1,235 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity lepton_manager is
generic(
INPUT_CLK_FREQ : integer := 50000000);
port(
clk : in std_logic := '0';
reset : in std_logic := '0';
-- Avalon ST Sink to receive SPI data
spi_miso_sink_data : in std_logic_vector(7 downto 0);
spi_miso_sink_valid : in std_logic;
-- Avalon ST Source to send SPI data
spi_mosi_src_data : out std_logic_vector(7 downto 0);
spi_mosi_src_valid : out std_logic;
spi_mosi_src_ready : in std_logic := '0';
-- Filtered output to retransmit cleaned data (without the discard packets, see Lepton Datasheet on page 31)
-- lepton_out_data is valid on rising edge when lepton_src_valid = '1'
lepton_out_data : out std_logic_vector(7 downto 0);
lepton_out_valid : out std_logic;
lepton_out_sof : out std_logic;
lepton_out_eof : out std_logic;
-- Some status
row_idx : out std_logic_vector(5 downto 0);
error : out std_logic;
-- Avalon MM Slave interface for configuration
start : in std_logic;
-- The SPI Chip Select (Active low !)
spi_cs_n : out std_logic := '0');
end entity lepton_manager;
architecture rtl of lepton_manager is
type state_t is (Idle, CSn, ReadHeader, ReadPayload, DiscardPayload, WaitBeforeIdle);
signal state, next_state : state_t;
signal header_3_last_nibbles : std_logic_vector(11 downto 0);
constant CLOCK_TICKS_PER_37_MS : integer := 37 * (INPUT_CLK_FREQ / 1e3); -- the timeout delay for a frame
constant CLOCK_TICKS_PER_200_MS : integer := 200 * (INPUT_CLK_FREQ / 1e3);
constant CLOCK_TICKS_PER_200_NS : integer := (200 * (INPUT_CLK_FREQ / 1e6)) / 1e3;
constant BYTES_PER_HEADER : integer := 4;
constant BYTES_PER_PAYLOAD : integer := 160;
constant NUMBER_OF_LINES_PER_FRAME : positive := 60;
signal counter, counter_max : integer range 1 to CLOCK_TICKS_PER_200_MS;
signal line_counter : integer range 1 to NUMBER_OF_LINES_PER_FRAME;
signal timeout_counter : integer range 1 to CLOCK_TICKS_PER_37_MS;
signal counter_enabled : boolean;
signal waited_long_enough : boolean;
signal header_end, payload_end : boolean;
begin
-- purpose: register for state
p_fsm : process(clk, reset)
begin
if reset = '1' then
state <= Idle;
elsif rising_edge(clk) then
state <= next_state;
end if;
end process p_fsm;
-- purpose: compute the next state
p_nsl : process(header_3_last_nibbles, header_end, payload_end, start, spi_miso_sink_valid, state, waited_long_enough, line_counter)
begin
next_state <= state;
case state is
when Idle =>
if waited_long_enough and start = '1' then
next_state <= CSn;
end if;
when CSn =>
if waited_long_enough then
next_state <= ReadHeader;
end if;
when ReadHeader =>
if header_end then
if header_3_last_nibbles(11 downto 8) = X"F" then
next_state <= DiscardPayload;
else
next_state <= ReadPayload;
end if;
end if;
when DiscardPayload | ReadPayload =>
if payload_end then
next_state <= ReadHeader;
if line_counter = NUMBER_OF_LINES_PER_FRAME then
next_state <= WaitBeforeIdle;
end if;
end if;
when WaitBeforeIdle =>
if spi_miso_sink_valid = '1' then
next_state <= Idle;
end if;
end case;
end process p_nsl;
p_counter : process(clk, reset)
begin
if reset = '1' then
counter <= 1;
line_counter <= 1;
elsif rising_edge(clk) then
if counter = counter_max and counter_enabled then
counter <= 1;
if state = ReadPayload then
if line_counter = NUMBER_OF_LINES_PER_FRAME then
line_counter <= 1;
else
line_counter <= line_counter + 1;
end if;
end if;
elsif counter_enabled then
counter <= counter + 1;
end if;
end if;
end process p_counter;
p_error : process(clk, reset)
begin
if reset = '1' then
error <= '0';
timeout_counter <= 1;
elsif rising_edge(clk) then
if state /= ReadHeader and state /= ReadPayload and state /= ReadHeader then
timeout_counter <= 1;
error <= '0';
else
if timeout_counter = CLOCK_TICKS_PER_37_MS then
error <= '1';
else
timeout_counter <= timeout_counter + 1;
end if;
end if;
if state = ReadPayload and header_3_last_nibbles /= std_logic_vector(to_unsigned(line_counter - 1, header_3_last_nibbles'length)) then
error <= '1';
end if;
end if;
end process p_error;
-- purpose: wire the datapath
p_datapath : process(counter, counter_enabled, counter_max, line_counter, spi_miso_sink_data, spi_miso_sink_valid, spi_mosi_src_ready, state)
variable counter_ended : boolean;
begin
counter_max <= 1;
counter_enabled <= true;
waited_long_enough <= false;
lepton_out_data <= (others => '0');
lepton_out_valid <= '0';
lepton_out_sof <= '0';
lepton_out_eof <= '0';
spi_mosi_src_valid <= '0';
spi_mosi_src_data <= (others => '0');
spi_cs_n <= '0';
header_end <= false;
payload_end <= false;
counter_ended := (counter = counter_max and counter_enabled);
case state is
when Idle =>
counter_max <= CLOCK_TICKS_PER_200_MS;
waited_long_enough <= counter_ended;
spi_cs_n <= '1';
when CSn =>
counter_max <= CLOCK_TICKS_PER_200_NS;
waited_long_enough <= counter_ended;
when ReadHeader =>
counter_max <= BYTES_PER_HEADER;
counter_enabled <= spi_miso_sink_valid = '1';
header_end <= counter_ended;
spi_mosi_src_valid <= spi_mosi_src_ready;
when ReadPayload =>
counter_max <= BYTES_PER_PAYLOAD;
counter_enabled <= spi_miso_sink_valid = '1';
lepton_out_data <= spi_miso_sink_data;
lepton_out_valid <= spi_miso_sink_valid;
payload_end <= counter_ended;
spi_mosi_src_valid <= spi_mosi_src_ready;
if spi_miso_sink_valid = '1' then
if counter = 1 and counter_enabled and line_counter = 1 then
lepton_out_sof <= '1';
elsif counter_ended and line_counter = NUMBER_OF_LINES_PER_FRAME then
lepton_out_eof <= '1';
end if;
end if;
when DiscardPayload =>
counter_max <= BYTES_PER_PAYLOAD;
counter_enabled <= spi_miso_sink_valid = '1';
payload_end <= counter_ended;
spi_mosi_src_valid <= spi_mosi_src_ready;
when others => null;
end case;
end process p_datapath;
p_capture_header : process(clk, reset)
begin
if reset = '1' then
header_3_last_nibbles <= X"000";
elsif rising_edge(clk) then
if state = ReadHeader and spi_miso_sink_valid = '1' then
if counter = 1 then
header_3_last_nibbles(11 downto 8) <= spi_miso_sink_data(3 downto 0);
elsif counter = 2 then
header_3_last_nibbles(7 downto 0) <= spi_miso_sink_data;
end if;
end if;
end if;
end process p_capture_header;
row_idx <= std_logic_vector(to_unsigned(line_counter, row_idx'length));
end architecture rtl;

View File

@ -0,0 +1,78 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity lepton_stats is
port(
clk : in std_logic;
reset : in std_logic;
pix_data : in std_logic_vector(13 downto 0);
pix_valid : in std_logic;
pix_sof : in std_logic;
pix_eof : in std_logic;
stat_min : out std_logic_vector(13 downto 0);
stat_max : out std_logic_vector(13 downto 0);
stat_sum : out std_logic_vector(26 downto 0);
stat_valid : out std_logic);
end lepton_stats;
architecture rtl of lepton_stats is
-- The accumulated sum, min and max of the pixel values
signal curr_min : unsigned(13 downto 0);
signal curr_max : unsigned(13 downto 0);
signal curr_sum : unsigned(26 downto 0);
-- The next value of the registers
signal next_min : unsigned(13 downto 0);
signal next_max : unsigned(13 downto 0);
signal next_sum : unsigned(26 downto 0);
begin
-- This is the synchronous transition logic
transition_logic : process(clk, reset)
begin
if reset = '1' then
curr_sum <= (others => '0');
curr_min <= (others => '0');
curr_max <= (others => '0');
elsif rising_edge(clk) then
curr_min <= next_min;
curr_max <= next_max;
curr_sum <= next_sum;
end if;
end process;
-- This is the combinatorial transition logic
next_min <=
curr_min when pix_valid = '0' else
unsigned(pix_data) when pix_sof = '1' else
curr_min when unsigned(pix_data) >= curr_min else
unsigned(pix_data);
next_max <=
curr_max when pix_valid = '0' else
unsigned(pix_data) when pix_sof = '1' else
curr_max when unsigned(pix_data) <= curr_max else
unsigned(pix_data);
next_sum <=
curr_sum when pix_valid = '0' else
unsigned((26 downto 14 => '0') & pix_data) when pix_sof = '1' else
curr_sum + unsigned((26 downto 14 => '0') & pix_data);
-- This is the synchronous output logic
output_logic : process(clk, reset)
begin
if rising_edge(clk) then
stat_valid <= pix_eof;
end if;
end process;
-- This is the combinatorial output logic
stat_min <= std_logic_vector(curr_min);
stat_max <= std_logic_vector(curr_max);
stat_sum <= std_logic_vector(curr_sum);
end rtl;

View File

@ -0,0 +1,50 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity level_adjuster is
port(
clk : in std_logic;
raw_pixel : in std_logic_vector(13 downto 0);
raw_max : in std_logic_vector(13 downto 0);
raw_min : in std_logic_vector(13 downto 0);
raw_sum : in std_logic_vector(26 downto 0);
adjusted_pixel : out std_logic_vector(13 downto 0));
end level_adjuster;
architecture rtl of level_adjuster is
component lpm_divider
port(
clock : in std_logic;
denom : in std_logic_vector(13 downto 0);
numer : in std_logic_vector(27 downto 0);
quotient : out std_logic_vector(27 downto 0);
remain : out std_logic_vector(13 downto 0));
end component;
-- Intermediate signals needed by the divider
signal numer : std_logic_vector(27 downto 0);
signal denom : std_logic_vector(13 downto 0);
signal quot : std_logic_vector(27 downto 0);
begin
-- Computation of the intermediate signals
numer <= std_logic_vector((13 downto 0 => '1') * (unsigned(raw_pixel) - unsigned(raw_min)));
denom <= std_logic_vector(unsigned(raw_max) - unsigned(raw_min));
-- We compute the remaineder of (x - min) / (max - min)
divider : lpm_divider port map(
clock => clk,
numer => numer,
denom => denom,
quotient => quot,
remain => open
);
-- And we only keep the LSB of the quotient (we know the MSB must be 0)
adjusted_pixel <=
(adjusted_pixel'range => '0') when denom = (denom'range => '0') else
quot(13 downto 0);
end rtl;

View File

@ -0,0 +1,133 @@
-- megafunction wizard: %LPM_DIVIDE%
-- GENERATION: STANDARD
-- VERSION: WM1.0
-- MODULE: LPM_DIVIDE
-- ============================================================
-- File Name: lpm_divider.vhd
-- Megafunction Name(s):
-- LPM_DIVIDE
--
-- Simulation Library Files(s):
-- lpm
-- ============================================================
-- ************************************************************
-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
--
-- 15.1.0 Build 185 10/21/2015 SJ Lite Edition
-- ************************************************************
--Copyright (C) 1991-2015 Altera Corporation. All rights reserved.
--Your use of Altera Corporation's design tools, logic functions
--and other software and tools, and its AMPP partner logic
--functions, and any output files from any of the foregoing
--(including device programming or simulation files), and any
--associated documentation or information are expressly subject
--to the terms and conditions of the Altera Program License
--Subscription Agreement, the Altera Quartus Prime License Agreement,
--the Altera MegaCore Function License Agreement, or other
--applicable license agreement, including, without limitation,
--that your use is for the sole purpose of programming logic
--devices manufactured by Altera and sold by Altera or its
--authorized distributors. Please refer to the applicable
--agreement for further details.
library ieee;
use ieee.std_logic_1164.all;
library lpm;
use lpm.all;
entity lpm_divider is
port(
clock : in std_logic;
denom : in std_logic_vector(13 downto 0);
numer : in std_logic_vector(27 downto 0);
quotient : out std_logic_vector(27 downto 0);
remain : out std_logic_vector(13 downto 0)
);
end lpm_divider;
architecture SYN of lpm_divider is
signal sub_wire0 : std_logic_vector(27 downto 0);
signal sub_wire1 : std_logic_vector(13 downto 0);
component lpm_divide
generic(
lpm_drepresentation : string;
lpm_hint : string;
lpm_nrepresentation : string;
lpm_pipeline : natural;
lpm_type : string;
lpm_widthd : natural;
lpm_widthn : natural
);
port(
clock : in std_logic;
denom : in std_logic_vector(13 downto 0);
numer : in std_logic_vector(27 downto 0);
quotient : out std_logic_vector(27 downto 0);
remain : out std_logic_vector(13 downto 0)
);
end component;
begin
quotient <= sub_wire0(27 downto 0);
remain <= sub_wire1(13 downto 0);
LPM_DIVIDE_component : LPM_DIVIDE
generic map(
lpm_drepresentation => "UNSIGNED",
lpm_hint => "LPM_REMAINDERPOSITIVE=TRUE",
lpm_nrepresentation => "UNSIGNED",
lpm_pipeline => 5,
lpm_type => "LPM_DIVIDE",
lpm_widthd => 14,
lpm_widthn => 28
)
port map(
clock => clock,
denom => denom,
numer => numer,
quotient => sub_wire0,
remain => sub_wire1
);
end SYN;
-- ============================================================
-- CNX file retrieval info
-- ============================================================
-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
-- Retrieval info: PRIVATE: PRIVATE_LPM_REMAINDERPOSITIVE STRING "TRUE"
-- Retrieval info: PRIVATE: PRIVATE_MAXIMIZE_SPEED NUMERIC "-1"
-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
-- Retrieval info: PRIVATE: USING_PIPELINE NUMERIC "1"
-- Retrieval info: PRIVATE: VERSION_NUMBER NUMERIC "2"
-- Retrieval info: PRIVATE: new_diagram STRING "1"
-- Retrieval info: LIBRARY: lpm lpm.lpm_components.all
-- Retrieval info: CONSTANT: LPM_DREPRESENTATION STRING "UNSIGNED"
-- Retrieval info: CONSTANT: LPM_HINT STRING "LPM_REMAINDERPOSITIVE=TRUE"
-- Retrieval info: CONSTANT: LPM_NREPRESENTATION STRING "UNSIGNED"
-- Retrieval info: CONSTANT: LPM_PIPELINE NUMERIC "5"
-- Retrieval info: CONSTANT: LPM_TYPE STRING "LPM_DIVIDE"
-- Retrieval info: CONSTANT: LPM_WIDTHD NUMERIC "14"
-- Retrieval info: CONSTANT: LPM_WIDTHN NUMERIC "28"
-- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL "clock"
-- Retrieval info: USED_PORT: denom 0 0 14 0 INPUT NODEFVAL "denom[13..0]"
-- Retrieval info: USED_PORT: numer 0 0 28 0 INPUT NODEFVAL "numer[27..0]"
-- Retrieval info: USED_PORT: quotient 0 0 28 0 OUTPUT NODEFVAL "quotient[27..0]"
-- Retrieval info: USED_PORT: remain 0 0 14 0 OUTPUT NODEFVAL "remain[13..0]"
-- Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0
-- Retrieval info: CONNECT: @denom 0 0 14 0 denom 0 0 14 0
-- Retrieval info: CONNECT: @numer 0 0 28 0 numer 0 0 28 0
-- Retrieval info: CONNECT: quotient 0 0 28 0 @quotient 0 0 28 0
-- Retrieval info: CONNECT: remain 0 0 14 0 @remain 0 0 14 0
-- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_divider.vhd TRUE
-- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_divider.inc FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_divider.cmp FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_divider.bsf FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_divider_inst.vhd FALSE
-- Retrieval info: LIB_FILE: lpm

View File

@ -0,0 +1,38 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ram_writer is
port(
clk, reset : in std_logic;
pix_data : in std_logic_vector(13 downto 0);
pix_valid : in std_logic;
pix_sof : in std_logic;
pix_eof : in std_logic;
ram_data : out std_logic_vector(15 downto 0);
ram_wren : out std_logic;
ram_wraddress : out std_logic_vector(12 downto 0));
end ram_writer;
architecture rtl of ram_writer is
signal wraddress_counter : unsigned(ram_wraddress'range);
begin
p_address_gen : process(clk, reset)
begin
if reset = '1' then
wraddress_counter <= (others => '0');
elsif rising_edge(clk) then
if pix_eof = '1' then
wraddress_counter <= (others => '0');
elsif pix_valid = '1' then
wraddress_counter <= wraddress_counter + 1;
end if;
end if;
end process p_address_gen;
ram_data <= "00" & pix_data;
ram_wren <= pix_valid;
ram_wraddress <= std_logic_vector(wraddress_counter);
end rtl;

View File

@ -0,0 +1,27 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package utils is
function bitlength(number : positive) return positive;
end package utils;
package body utils is
-- purpose: returns the minimum # of bits needed to represent the input number
function bitlength(number : positive) return positive is
variable acc : positive := 1;
variable i : natural := 0;
begin
while True loop
if acc > number then
return i;
end if;
acc := acc * 2;
i := i + 1;
end loop;
end function bitlength;
end package body utils;

View File

@ -0,0 +1,77 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity lepton_tb is
end lepton_tb;
architecture tb of lepton_tb is
signal clk : std_logic := '0';
signal reset : std_logic := '0';
signal address : std_logic_vector(13 downto 0) := (others => '0');
signal readdata : std_logic_vector(15 downto 0) := (others => '0');
signal writedata : std_logic_vector(15 downto 0) := (others => '0');
signal read : std_logic := '0';
signal write : std_logic := '0';
signal SCLK : std_logic := '0';
signal CSn : std_logic := '0';
signal MOSI : std_logic := '0';
signal MISO : std_logic := '1';
constant CLK_PERIOD : time := 20 ns;
signal sim_ended : boolean := false;
begin
dut : entity work.lepton
port map(
clk => clk,
reset => reset,
address => address,
readdata => readdata,
writedata => writedata,
read => read,
write => write,
SCLK => SCLK,
CSn => CSn,
MOSI => MOSI,
MISO => MISO
);
clk <= not clk after CLK_PERIOD / 2 when not sim_ended else '0';
miso_gen : process
variable seed1, seed2 : positive;
variable rand : real;
begin
if sim_ended then
wait;
else
uniform(seed1, seed2, rand);
wait until rising_edge(SCLK);
MISO <= to_unsigned(integer(rand), 1)(0);
end if;
end process;
stimuli : process
begin
reset <= '1';
write <= '0';
wait for 2 * CLK_PERIOD;
reset <= '0';
wait for CLK_PERIOD;
write <= '1';
writedata(0) <= '1';
wait for CLK_PERIOD;
write <= '0';
wait for 17 ms;
sim_ended <= true;
wait;
end process;
end tb;

View File

@ -0,0 +1,42 @@
-- #############################################################################
-- pwm.vhd
-- =======
-- PWM memory-mapped Avalon slave interface.
--
-- Author : <insert your name> (<insert your e-mail address>)
-- Author : <insert your name> (<insert your e-mail address>)
-- Revision : <insert revision>
-- Last modified : <insert date>
-- #############################################################################
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.pwm_constants.all;
entity pwm is
port(
-- Avalon Clock interface
clk : in std_logic;
-- Avalon Reset interface
reset : in std_logic;
-- Avalon-MM Slave interface
address : in std_logic_vector(1 downto 0);
read : in std_logic;
write : in std_logic;
readdata : out std_logic_vector(31 downto 0);
writedata : in std_logic_vector(31 downto 0);
-- Avalon Conduit interface
pwm_out : out std_logic
);
end pwm;
architecture rtl of pwm is
begin
end architecture rtl;

View File

@ -0,0 +1,61 @@
-- #############################################################################
-- pwm_constants.vhd
-- =================
-- This package contains constants used in the PWM design files.
--
-- Author : Sahand Kashani-Akhavan [sahand.kashani-akhavan@epfl.ch]
-- Revision : 2
-- Last modified : 2018-02-28
-- #############################################################################
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package pwm_constants is
-- Register map
-- +--------+------------+--------+------------------------------------------------------------------------------+
-- | RegNo | Name | Access | Description |
-- +--------+------------+--------+------------------------------------------------------------------------------+
-- | 0 | PERIOD | R/W | Period in clock cycles [2 <= period <= (2**32) - 1]. |
-- | | | | |
-- | | | | This value can be read/written while the unit is in the middle of an ongoing |
-- | | | | PWM pulse. To allow safe behaviour, one cannot modify the period of an |
-- | | | | ongoing pulse, so we adopt the following semantics for this register: |
-- | | | | |
-- | | | | >> WRITING a value in this register indicates the NEW period to apply to the |
-- | | | | next pulse. |
-- | | | | |
-- | | | | >> READING a value from this register indicates the CURRENT period of the |
-- | | | | ongoing pulse. |
-- +--------+------------+--------+------------------------------------------------------------------------------+
-- | 1 | DUTY_CYCLE | R/W | Duty cycle of the PWM [1 <= duty cycle <= period] |
-- | | | | |
-- | | | | This value can be read/written while the unit is in the middle of an ongoing |
-- | | | | PWM pulse. To allow safe behaviour, one cannot modify the duty cycle of an |
-- | | | | ongoing pulse, so we adopt the following semantics for this register: |
-- | | | | |
-- | | | | >> WRITING a value in this register indicates the NEW duty cycle to apply to |
-- | | | | the next pulse. |
-- | | | | |
-- | | | | >> READING a value from this register indicates the CURRENT duty cycle of |
-- | | | | the ongoing pulse. |
-- +--------+------------+--------+------------------------------------------------------------------------------+
-- | 2 | CTRL | WO | >> Writing 0 to this register stops the PWM once the ongoing pulse has ended.|
-- | | | | Writing 1 to this register starts the PWM. |
-- | | | | |
-- | | | | >> Reading this register always returns 0. |
-- +--------+------------+--------+------------------------------------------------------------------------------+
constant REG_PERIOD_OFST : std_logic_vector(1 downto 0) := "00";
constant REG_DUTY_CYCLE_OFST : std_logic_vector(1 downto 0) := "01";
constant REG_CTRL_OFST : std_logic_vector(1 downto 0) := "10";
-- Default values of registers after reset (BEFORE writing START to the CTRL
-- register with a new configuration)
constant DEFAULT_PERIOD : natural := 4;
constant DEFAULT_DUTY_CYCLE : natural := 2;
end package pwm_constants;
package body pwm_constants is
end package body pwm_constants;

View File

@ -0,0 +1,135 @@
# TCL File Generated by Component Editor 16.0
# Tue Feb 28 12:18:00 CET 2017
# DO NOT MODIFY
#
# pwm "pwm" v1.0
# 2017.02.28.12:18:00
# Pan-tilt
#
#
# request TCL package from ACDS 16.0
#
package require -exact qsys 16.0
#
# module pwm
#
set_module_property DESCRIPTION Pan-tilt
set_module_property NAME pwm
set_module_property VERSION 1.0
set_module_property INTERNAL false
set_module_property OPAQUE_ADDRESS_MAP true
set_module_property GROUP Pan-tilt
set_module_property AUTHOR ""
set_module_property DISPLAY_NAME pwm
set_module_property INSTANTIATE_IN_SYSTEM_MODULE true
set_module_property EDITABLE true
set_module_property REPORT_TO_TALKBACK false
set_module_property ALLOW_GREYBOX_GENERATION false
set_module_property REPORT_HIERARCHY false
#
# file sets
#
add_fileset QUARTUS_SYNTH QUARTUS_SYNTH "" ""
set_fileset_property QUARTUS_SYNTH TOP_LEVEL pwm
set_fileset_property QUARTUS_SYNTH ENABLE_RELATIVE_INCLUDE_PATHS false
set_fileset_property QUARTUS_SYNTH ENABLE_FILE_OVERWRITE_MODE false
add_fileset_file pwm.vhd VHDL PATH pwm.vhd TOP_LEVEL_FILE
add_fileset_file pwm_constants.vhd VHDL PATH pwm_constants.vhd
#
# parameters
#
#
# display items
#
#
# connection point clock
#
add_interface clock clock end
set_interface_property clock clockRate 0
set_interface_property clock ENABLED true
set_interface_property clock EXPORT_OF ""
set_interface_property clock PORT_NAME_MAP ""
set_interface_property clock CMSIS_SVD_VARIABLES ""
set_interface_property clock SVD_ADDRESS_GROUP ""
add_interface_port clock clk clk Input 1
#
# connection point reset
#
add_interface reset reset end
set_interface_property reset associatedClock clock
set_interface_property reset synchronousEdges DEASSERT
set_interface_property reset ENABLED true
set_interface_property reset EXPORT_OF ""
set_interface_property reset PORT_NAME_MAP ""
set_interface_property reset CMSIS_SVD_VARIABLES ""
set_interface_property reset SVD_ADDRESS_GROUP ""
add_interface_port reset reset reset Input 1
#
# connection point avalon_slave_0
#
add_interface avalon_slave_0 avalon end
set_interface_property avalon_slave_0 addressUnits WORDS
set_interface_property avalon_slave_0 associatedClock clock
set_interface_property avalon_slave_0 associatedReset reset
set_interface_property avalon_slave_0 bitsPerSymbol 8
set_interface_property avalon_slave_0 burstOnBurstBoundariesOnly false
set_interface_property avalon_slave_0 burstcountUnits WORDS
set_interface_property avalon_slave_0 explicitAddressSpan 0
set_interface_property avalon_slave_0 holdTime 0
set_interface_property avalon_slave_0 linewrapBursts false
set_interface_property avalon_slave_0 maximumPendingReadTransactions 0
set_interface_property avalon_slave_0 maximumPendingWriteTransactions 0
set_interface_property avalon_slave_0 readLatency 0
set_interface_property avalon_slave_0 readWaitTime 1
set_interface_property avalon_slave_0 setupTime 0
set_interface_property avalon_slave_0 timingUnits Cycles
set_interface_property avalon_slave_0 writeWaitTime 0
set_interface_property avalon_slave_0 ENABLED true
set_interface_property avalon_slave_0 EXPORT_OF ""
set_interface_property avalon_slave_0 PORT_NAME_MAP ""
set_interface_property avalon_slave_0 CMSIS_SVD_VARIABLES ""
set_interface_property avalon_slave_0 SVD_ADDRESS_GROUP ""
add_interface_port avalon_slave_0 address address Input 2
add_interface_port avalon_slave_0 read read Input 1
add_interface_port avalon_slave_0 write write Input 1
add_interface_port avalon_slave_0 readdata readdata Output 32
add_interface_port avalon_slave_0 writedata writedata Input 32
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isFlash 0
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isMemoryDevice 0
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isNonVolatileStorage 0
set_interface_assignment avalon_slave_0 embeddedsw.configuration.isPrintableDevice 0
#
# connection point conduit_end
#
add_interface conduit_end conduit end
set_interface_property conduit_end associatedClock clock
set_interface_property conduit_end associatedReset ""
set_interface_property conduit_end ENABLED true
set_interface_property conduit_end EXPORT_OF ""
set_interface_property conduit_end PORT_NAME_MAP ""
set_interface_property conduit_end CMSIS_SVD_VARIABLES ""
set_interface_property conduit_end SVD_ADDRESS_GROUP ""
add_interface_port conduit_end pwm_out pwm Output 1

View File

@ -0,0 +1,205 @@
-- #############################################################################
-- tb_pwm.vhd
-- ==========
-- Testbench for PWM memory-mapped Avalon slave interface.
--
-- Modified by : Sahand Kashani-Akhavan [sahand.kashani-akhavan@epfl.ch]
-- Revision : 2
-- Last modified : 2018-02-28
-- #############################################################################
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.pwm_constants.all;
entity tb_pwm is
end entity;
architecture rtl of tb_pwm is
-- 50 MHz clock
constant CLK_PERIOD : time := 20 ns;
-- Signal used to end simulator when we finished submitting our test cases
signal sim_finished : boolean := false;
-- PWM PORTS
signal clk : std_logic;
signal reset : std_logic;
signal address : std_logic_vector(1 downto 0);
signal read : std_logic;
signal write : std_logic;
signal readdata : std_logic_vector(31 downto 0);
signal writedata : std_logic_vector(31 downto 0);
signal pwm_out : std_logic;
-- Values of registers we are going to use to configure the PWM unit
constant CONFIG_PERIOD : natural := 100;
constant CONFIG_DUTY_CYCLE : natural := 20;
constant CONFIG_CTRL_START : natural := 1;
constant CONFIG_CTRL_STOP : natural := 0;
begin
-- Instantiate DUT
dut : entity work.pwm
port map(
clk => clk,
reset => reset,
address => address,
read => read,
write => write,
readdata => readdata,
writedata => writedata,
pwm_out => pwm_out
);
-- Generate clk signal
clk_generation : process
begin
if not sim_finished then
clk <= '1';
wait for CLK_PERIOD / 2;
clk <= '0';
wait for CLK_PERIOD / 2;
else
wait;
end if;
end process clk_generation;
-- Test PWM
simulation : process
procedure async_reset is
begin
wait until rising_edge(clk);
wait for CLK_PERIOD / 4;
reset <= '1';
wait for CLK_PERIOD / 2;
reset <= '0';
wait for CLK_PERIOD / 4;
end procedure async_reset;
procedure write_register(constant ofst : in std_logic_vector(1 downto 0);
constant val : in natural) is
begin
wait until rising_edge(clk);
address <= ofst;
write <= '1';
writedata <= std_logic_vector(to_unsigned(val, writedata'length));
wait until rising_edge(clk);
address <= (others => '0');
write <= '0';
writedata <= (others => '0');
wait until rising_edge(clk);
end procedure write_register;
procedure read_register(constant ofst : in std_logic_vector(1 downto 0)) is
begin
wait until rising_edge(clk);
address <= ofst;
read <= '1';
-- The read has a 1 cycle wait-state, so we need to keep the read
-- signal high for 2 clock cycles.
wait until rising_edge(clk);
wait until rising_edge(clk);
address <= (others => '0');
read <= '0';
wait until rising_edge(clk);
end procedure read_register;
procedure read_register_check(constant ofst : in std_logic_vector(1 downto 0);
constant expected_val : in natural) is
begin
read_register(ofst);
case ofst is
when REG_PERIOD_OFST =>
assert to_integer(unsigned(readdata)) = expected_val
report "Unexpected PERIOD: " &
"PERIOD = " & integer'image(to_integer(unsigned(readdata))) & "; " &
"PERIOD_expected = " & integer'image(expected_val)
severity error;
when REG_DUTY_CYCLE_OFST =>
assert to_integer(unsigned(readdata)) = expected_val
report "Unexpected DUTY_CYCLE: " &
"DUTY_CYCLE = " & integer'image(to_integer(unsigned(readdata))) & "; " &
"DUTY_CYCLE_expected = " & integer'image(expected_val)
severity error;
when REG_CTRL_OFST =>
assert to_integer(unsigned(readdata)) = expected_val
report "Unexpected CTRL: " &
"CTRL = " & integer'image(to_integer(unsigned(readdata))) & "; " &
"CTRL_expected = " & integer'image(expected_val)
severity error;
when others =>
null;
end case;
end procedure read_register_check;
begin
-- Default values
reset <= '0';
address <= (others => '0');
read <= '0';
write <= '0';
writedata <= (others => '0');
wait until rising_edge(clk);
-- Reset the circuit
async_reset;
-- Write desired configuration to PWM Avalon-MM slave.
write_register(REG_PERIOD_OFST, CONFIG_PERIOD);
write_register(REG_DUTY_CYCLE_OFST, CONFIG_DUTY_CYCLE);
-- Read back configuration from PWM Avalon-MM slave. Note that we have
-- not started the PWM unit yet, so the new configuration must not be
-- read back at this point (as per the register map).
read_register_check(REG_PERIOD_OFST, DEFAULT_PERIOD);
read_register_check(REG_DUTY_CYCLE_OFST, DEFAULT_DUTY_CYCLE);
read_register_check(REG_CTRL_OFST, 0);
-- Start PWM
write_register(REG_CTRL_OFST, CONFIG_CTRL_START);
-- Wait until PWM pulses for the first time after we sent START.
wait until rising_edge(pwm_out);
-- Read back configuration from PWM Avalon-MM slave. Now that we have
-- started the PWM unit, we should be able to read back the
-- configuration we wrote (as per the register map).
read_register_check(REG_PERIOD_OFST, CONFIG_PERIOD);
read_register_check(REG_DUTY_CYCLE_OFST, CONFIG_DUTY_CYCLE);
read_register_check(REG_CTRL_OFST, 0);
-- Wait for 2 PWM periods to finish
wait for 2 * CLK_PERIOD * CONFIG_PERIOD;
-- Stop PWM.
write_register(REG_CTRL_OFST, CONFIG_CTRL_STOP);
-- Wait for PWM period to finish
wait for 1 * CLK_PERIOD * CONFIG_PERIOD;
-- Instruct "clk_generation" process to halt execution.
sim_finished <= true;
-- Make this process wait indefinitely (it will never re-execute from
-- its beginning again).
wait;
end process simulation;
end architecture rtl;

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<library>
<!-- date: 2017.05.14.23:41:43 -->
<!-- generated by: ip-make-ipx -->
<!-- -->
<!-- 5 in ../../hdl/ -->
<!-- -->
<component
name="framebuffer_manager"
file="../../hdl/displays/framebuffer_manager/hdl/framebuffer_manager_hw.tcl"
displayName="framebuffer_manager"
version="1.0"
description=""
tags="AUTHORSHIP=Philemon Favrod /// CONNECTION_TYPES=avalon,avalon_streaming,clock,conduit,interrupt,reset /// INTERNAL_COMPONENT=false"
categories="LCD"
factory="TclModuleFactory">
<tag2 key="ALLOW_GREYBOX_GENERATION" value="false" />
<tag2 key="COMPONENT_EDITABLE" value="true" />
<tag2 key="COMPONENT_HIDE_FROM_SOPC" value="true" />
<tag2 key="INSTANTIATE_IN_SYSTEM_MODULE" value="true" />
<tag2 key="OPAQUE_ADDRESS_MAP" value="true" />
<tag2 key="REPORT_HIERARCHY" value="false" />
<tag2 key="SUPPORTED_FILE_SETS" value="QUARTUS_SYNTH" />
<tag2 key="TCL_PACKAGE_VERSION" value="16.0" />
</component>
<component
name="lepton"
file="../../hdl/lepton/hdl/lepton_hw.tcl"
displayName="lepton"
version="1.0"
description="IR Camera 80x60"
tags="AUTHORSHIP=Philemon Favrod &amp; Sahand Kashani-Akhavan /// CONNECTION_TYPES=avalon,clock,conduit,reset /// INTERNAL_COMPONENT=false"
categories="Camera"
factory="TclModuleFactory">
<tag2 key="ALLOW_GREYBOX_GENERATION" value="false" />
<tag2 key="COMPONENT_EDITABLE" value="true" />
<tag2 key="COMPONENT_HIDE_FROM_SOPC" value="true" />
<tag2 key="INSTANTIATE_IN_SYSTEM_MODULE" value="true" />
<tag2 key="OPAQUE_ADDRESS_MAP" value="true" />
<tag2 key="REPORT_HIERARCHY" value="false" />
<tag2 key="SUPPORTED_FILE_SETS" value="QUARTUS_SYNTH" />
<tag2 key="TCL_PACKAGE_VERSION" value="16.0" />
</component>
<component
name="mcp3204"
file="../../hdl/joysticks/hdl/mcp3204_hw.tcl"
displayName="mcp3204"
version="1.0"
description="4-Channel 12-Bit A/D Converter with SPI Serial Interface"
tags="AUTHORSHIP=Philemon Favrod &amp; Sahand Kashani-Akhavan /// CONNECTION_TYPES=avalon,clock,conduit,reset /// INTERNAL_COMPONENT=false"
categories="Joystick"
factory="TclModuleFactory">
<tag2 key="ALLOW_GREYBOX_GENERATION" value="false" />
<tag2 key="COMPONENT_EDITABLE" value="true" />
<tag2 key="COMPONENT_HIDE_FROM_SOPC" value="true" />
<tag2 key="INSTANTIATE_IN_SYSTEM_MODULE" value="true" />
<tag2 key="OPAQUE_ADDRESS_MAP" value="true" />
<tag2 key="REPORT_HIERARCHY" value="false" />
<tag2 key="SUPPORTED_FILE_SETS" value="QUARTUS_SYNTH" />
<tag2 key="TCL_PACKAGE_VERSION" value="16.0" />
</component>
<component
name="pwm"
file="../../hdl/pantilt/hdl/pwm_hw.tcl"
displayName="pwm"
version="1.0"
description="Pan-tilt"
tags="AUTHORSHIP= /// CONNECTION_TYPES=avalon,clock,conduit,reset /// INTERNAL_COMPONENT=false"
categories="Pan-tilt"
factory="TclModuleFactory">
<tag2 key="ALLOW_GREYBOX_GENERATION" value="false" />
<tag2 key="COMPONENT_EDITABLE" value="true" />
<tag2 key="COMPONENT_HIDE_FROM_SOPC" value="true" />
<tag2 key="INSTANTIATE_IN_SYSTEM_MODULE" value="true" />
<tag2 key="OPAQUE_ADDRESS_MAP" value="true" />
<tag2 key="REPORT_HIERARCHY" value="false" />
<tag2 key="SUPPORTED_FILE_SETS" value="QUARTUS_SYNTH" />
<tag2 key="TCL_PACKAGE_VERSION" value="16.0" />
</component>
<component
name="vga_sequencer"
file="../../hdl/displays/vga_sequencer/hdl/vga_sequencer_hw.tcl"
displayName="vga_sequencer"
version="1.0"
description=""
tags="AUTHORSHIP=Philemon Favrod /// CONNECTION_TYPES=avalon,avalon_streaming,clock,conduit,reset /// INTERNAL_COMPONENT=false"
categories="LCD"
factory="TclModuleFactory">
<tag2 key="ALLOW_GREYBOX_GENERATION" value="false" />
<tag2 key="COMPONENT_EDITABLE" value="true" />
<tag2 key="COMPONENT_HIDE_FROM_SOPC" value="true" />
<tag2 key="INSTANTIATE_IN_SYSTEM_MODULE" value="true" />
<tag2 key="OPAQUE_ADDRESS_MAP" value="true" />
<tag2 key="REPORT_HIERARCHY" value="false" />
<tag2 key="SUPPORTED_FILE_SETS" value="QUARTUS_SYNTH" />
<tag2 key="TCL_PACKAGE_VERSION" value="16.0" />
</component>
</library>

View File

@ -0,0 +1,31 @@
# -------------------------------------------------------------------------- #
#
# Copyright (C) 1991-2015 Altera Corporation. All rights reserved.
# Your use of Altera Corporation's design tools, logic functions
# and other software and tools, and its AMPP partner logic
# functions, and any output files from any of the foregoing
# (including device programming or simulation files), and any
# associated documentation or information are expressly subject
# to the terms and conditions of the Altera Program License
# Subscription Agreement, the Altera Quartus Prime License Agreement,
# the Altera MegaCore Function License Agreement, or other
# applicable license agreement, including, without limitation,
# that your use is for the sole purpose of programming logic
# devices manufactured by Altera and sold by Altera or its
# authorized distributors. Please refer to the applicable
# agreement for further details.
#
# -------------------------------------------------------------------------- #
#
# Quartus Prime
# Version 15.1.0 Build 185 10/21/2015 SJ Lite Edition
# Date created = 11:03:02 February 05, 2016
#
# -------------------------------------------------------------------------- #
QUARTUS_VERSION = "15.1"
DATE = "11:03:02 February 05, 2016"
# Revisions
PROJECT_REVISION = "lab_4_0"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
create_clock -period 20 [get_ports FPGA_CLK1_50]
create_clock -period 20 [get_ports FPGA_CLK2_50]
create_clock -period 20 [get_ports FPGA_CLK3_50]
derive_pll_clocks
derive_clock_uncertainty

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,6 @@
#include <stdlib.h>
int main(void) {
/* TODO : complete this function with your application */
return EXIT_SUCCESS;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -0,0 +1,84 @@
/**
* @author Philemon Favrod
* @brief Example of ping-pong buffering using the framebuffer.
*/
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <assert.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <unistd.h>
struct fb_fix_screeninfo fix_info;
struct fb_var_screeninfo var_info;
uint32_t *frame_buffer;
int num_buffers;
int num_pixels_per_buffer;
int fb_fd;
inline uint32_t make_color(uint8_t red, uint8_t green, uint8_t blue)
{
uint32_t r = red << var_info.red.offset;
uint32_t g = green << var_info.green.offset;
uint32_t b = blue << var_info.blue.offset;
return r | g | b;
}
int main(void)
{
fb_fd = open("/dev/fb0", O_RDWR);
assert(fb_fd >= 0);
// Get screen information
int ret = ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix_info);
assert(ret >= 0);
ret = ioctl(fb_fd, FBIOGET_VSCREENINFO, &var_info);
assert(ret >= 0);
// Map the frame buffer in user memory
frame_buffer = mmap(NULL, var_info.yres_virtual * fix_info.line_length, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
assert(frame_buffer != MAP_FAILED);
// Reminder: with prsoc_fbdev driver the number of buffer can be changed in the device tree
num_buffers = (var_info.yres_virtual * var_info.xres_virtual) / (var_info.xres * var_info.yres);
num_pixels_per_buffer = var_info.yres * var_info.xres;
int buffer_idx;
for (buffer_idx = 0; buffer_idx < num_buffers; ++buffer_idx) {
// Compute the color of the buffer
// Buffers 0, 3, 6, ... will be red
// Buffers 1, 4, 7, ... will be green
// Buffers 2, 5, 8, ... will be blue
uint32_t color = make_color(0xff, 0, 0);
if (buffer_idx % 3 == 1) {
color = make_color(0, 0xff, 0);
} else if (buffer_idx % 3 == 2) {
color = make_color(0, 0, 0xff);
}
int pixel_idx;
for (pixel_idx = buffer_idx * num_pixels_per_buffer; pixel_idx < (buffer_idx + 1) * num_pixels_per_buffer; ++pixel_idx) {
frame_buffer[pixel_idx] = color;
}
}
while (1) {
int i;
for (i = 0; i < num_buffers; ++i) {
var_info.yoffset = i * var_info.yres;
ret = ioctl(fb_fd, FBIOPAN_DISPLAY, &var_info);
assert(ret >= 0);
usleep(3000000);
}
}
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,24 @@
#ifndef __IORW_H__
#define __IORW_H__
#ifdef __nios2_arch__
#include <io.h>
#define io_write_8(base, ofst, data) (IOWR_8DIRECT((base), (ofst), (data)))
#define io_write_16(base, ofst, data) (IOWR_16DIRECT((base), (ofst), (data)))
#define io_write_32(base, ofst, data) (IOWR_32DIRECT((base), (ofst), (data)))
#define io_read_8(base, ofst) (IORD_8DIRECT((base), (ofst)))
#define io_read_16(base, ofst) (IORD_16DIRECT((base), (ofst)))
#define io_read_32(base, ofst) (IORD_32DIRECT((base), (ofst)))
#else
#include <socal/socal.h>
#define io_write_8(base, ofst, data) (alt_write_byte((uintptr_t) (base) + (ofst), (data)))
#define io_write_16(base, ofst, data) (alt_write_hword((uintptr_t) (base) + (ofst), (data)))
#define io_write_32(base, ofst, data) (alt_write_word((uintptr_t) (base) + (ofst), (data)))
#define io_read_8(base, ofst) (alt_read_byte((uintptr_t) (base) + (ofst)))
#define io_read_16(base, ofst) (alt_read_hword((uintptr_t) (base) + (ofst)))
#define io_read_32(base, ofst) (alt_read_word((uintptr_t) (base) + (ofst)))
#endif
#endif

View File

@ -0,0 +1,79 @@
#include "joysticks.h"
#define JOYSTICK_RIGHT_VRY_MCP3204_CHANNEL (0)
#define JOYSTICK_RIGHT_VRX_MCP3204_CHANNEL (1)
#define JOYSTICK_LEFT_VRY_MCP3204_CHANNEL (2)
#define JOYSTICK_LEFT_VRX_MCP3204_CHANNEL (3)
/**
* joysticks_inst
*
* Instantiate a joysticks device structure.
*
* @param base Base address of the MCP3204 component connected to the joysticks.
*/
joysticks_dev joysticks_inst(void *mcp3204_base) {
joysticks_dev dev;
dev.mcp3204 = mcp3204_inst((void *) mcp3204_base);
return dev;
}
/**
* joysticks_init
*
* Initializes the joysticks device.
*
* @param dev joysticks device structure.
*/
void joysticks_init(joysticks_dev *dev) {
mcp3204_init(&(dev->mcp3204));
}
/**
* joysticks_read_left_vertical
*
* Returns the vertical position of the left joystick. Return value ranges
* between JOYSTICKS_MIN_VALUE and JOYSTICKS_MAX_VALUE.
*
* @param dev joysticks device structure.
*/
uint32_t joysticks_read_left_vertical(joysticks_dev *dev) {
return JOYSTICKS_MAX_VALUE - mcp3204_read(&dev->mcp3204, JOYSTICK_RIGHT_VRY_MCP3204_CHANNEL);
}
/**
* joysticks_read_left_horizontal
*
* Returns the horizontal position of the left joystick. Return value ranges
* between JOYSTICKS_MIN_VALUE and JOYSTICKS_MAX_VALUE.
*
* @param dev joysticks device structure.
*/
uint32_t joysticks_read_left_horizontal(joysticks_dev *dev) {
return mcp3204_read(&dev->mcp3204, JOYSTICK_LEFT_VRX_MCP3204_CHANNEL);
}
/**
* joysticks_read_right_vertical
*
* Returns the vertical position of the right joystick. Return value ranges
* between JOYSTICKS_MIN_VALUE and JOYSTICKS_MAX_VALUE.
*
* @param dev joysticks device structure.
*/
uint32_t joysticks_read_right_vertical(joysticks_dev *dev) {
return JOYSTICKS_MAX_VALUE - mcp3204_read(&dev->mcp3204, JOYSTICK_RIGHT_VRY_MCP3204_CHANNEL);
}
/**
* joysticks_read_right_horizontal
*
* Returns the horizontal position of the left joystick. Return value ranges
* between JOYSTICKS_MIN_VALUE and JOYSTICKS_MAX_VALUE.
*
* @param dev joysticks device structure.
*/
uint32_t joysticks_read_right_horizontal(joysticks_dev *dev) {
return mcp3204_read(&dev->mcp3204, JOYSTICK_RIGHT_VRX_MCP3204_CHANNEL);
}

View File

@ -0,0 +1,27 @@
#ifndef __JOYSTICKS_H__
#define __JOYSTICKS_H__
#include "mcp3204/mcp3204.h"
/* joysticks device structure */
typedef struct joysticks_dev {
mcp3204_dev mcp3204; /* MCP3204 device handle */
} joysticks_dev;
/*******************************************************************************
* Public API
******************************************************************************/
#define JOYSTICKS_MIN_VALUE (MCP3204_MIN_VALUE)
#define JOYSTICKS_MAX_VALUE (MCP3204_MAX_VALUE)
joysticks_dev joysticks_inst(void *mcp3204_base);
void joysticks_init(joysticks_dev *dev);
uint32_t joysticks_read_left_vertical(joysticks_dev *dev);
uint32_t joysticks_read_left_horizontal(joysticks_dev *dev);
uint32_t joysticks_read_right_vertical(joysticks_dev *dev);
uint32_t joysticks_read_right_horizontal(joysticks_dev *dev);
#endif /* __JOYSTICKS_H__ */

View File

@ -0,0 +1,44 @@
#include "mcp3204.h"
#include "iorw.h"
#define MCP3204_NUM_CHANNELS (4)
/**
* mcp3204_inst
*
* Instantiate a mcp3204 device structure.
*
* @param base Base address of the component.
*/
mcp3204_dev mcp3204_inst(void *base) {
mcp3204_dev dev;
dev.base = base;
return dev;
}
/**
* mcp3204_init
*
* Initializes the mcp3204 device.
*
* @param dev mcp3204 device structure.
*/
void mcp3204_init(mcp3204_dev *dev) {
return;
}
/**
* mcp3204_read
*
* Reads the register corresponding to the supplied channel parameter.
*
* @param dev mcp3204 device structure.
* @param channel channel to be read
*/
uint32_t mcp3204_read(mcp3204_dev *dev, uint32_t channel) {
if (channel >= 4)
return 0;
return io_read_32(dev->base, channel * 4);
}

View File

@ -0,0 +1,23 @@
#ifndef __MCP3204_H__
#define __MCP3204_H__
#include <stdint.h>
/* mcp3204 device structure */
typedef struct mcp3204_dev {
void *base; /* Base address of component */
} mcp3204_dev;
/*******************************************************************************
* Public API
******************************************************************************/
#define MCP3204_MIN_VALUE (0)
#define MCP3204_MAX_VALUE (4095)
mcp3204_dev mcp3204_inst(void *base);
void mcp3204_init(mcp3204_dev *dev);
uint32_t mcp3204_read(mcp3204_dev *dev, uint32_t channel);
#endif /* __MCP3204_H__ */

View File

@ -0,0 +1,9 @@
#ifndef __MCP3204_REGS_H__
#define __MCP3204_REGS_H__
#define MCP3204_CHANNEL_0_OFST (0 * 4) /* RO */
#define MCP3204_CHANNEL_1_OFST (1 * 4) /* RO */
#define MCP3204_CHANNEL_2_OFST (2 * 4) /* RO */
#define MCP3204_CHANNEL_3_OFST (3 * 4) /* RO */
#endif /* __MCP3204_REGS_H__ */

View File

@ -0,0 +1,117 @@
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <unistd.h>
#include "lepton_regs.h"
#include "lepton.h"
#include "iorw.h"
/**
* lepton_inst
*
* Instantiate a lepton device structure.
*
* @param base Base address of the component.
*/
lepton_dev lepton_inst(void *base) {
lepton_dev dev;
dev.base = base;
return dev;
}
/**
* lepton_init
*
* Initializes the lepton device.
*
* @param dev lepton device structure.
*/
void lepton_init(lepton_dev *dev) {
return;
}
/**
* lepton_start_capture
*
* Instructs the device to start the frame capture process.
*
* @param dev lepton device structure.
*/
void lepton_start_capture(lepton_dev *dev) {
io_write_16(dev->base, LEPTON_REGS_COMMAND_OFST, 0x1);
}
/**
* lepton_error_check
*
* @abstract Check for errors at the device level.
* @param dev lepton device structure.
* @return true if there was an error, and false otherwise.
*/
bool lepton_error_check(lepton_dev *dev) {
return (io_read_16(dev->base, LEPTON_REGS_STATUS_OFST) & 0x2) != 0;
}
/**
* lepton_wait_until_eof
*
* Waits until the frame being captured has been fully received and saved in the
* internal memory.
*
* @param dev lepton device structure.
*/
void lepton_wait_until_eof(lepton_dev *dev) {
while (io_read_16(dev->base, LEPTON_REGS_STATUS_OFST) & 0x1);
}
/**
* lepton_save_capture
*
* Saves the captured frame on the host filesystem under the supplied filename.
* The frame will be saved in PGM format.
*
* @param dev lepton device structure.
* @param adjusted Setting this parameter to false will cause RAW sensor data to
* be written to the file.
* Setting this parameter to true will cause a preprocessed image
* (with a stretched dynamic range) to be saved to the file.
*
* @param fname the output file name.
*/
void lepton_save_capture(lepton_dev *dev, bool adjusted, FILE* file) {
assert(file);
const uint8_t num_rows = 60;
const uint8_t num_cols = 80;
uint16_t offset = LEPTON_REGS_RAW_BUFFER_OFST;
uint16_t max_value = io_read_16(dev->base, LEPTON_REGS_MAX_OFST);
if (adjusted) {
offset = LEPTON_REGS_ADJUSTED_BUFFER_OFST;
max_value = 0x3fff;
}
/* Write PGM header */
fprintf(file, "P2\n%" PRIu8 " %" PRIu8 "\n%" PRIu16, num_cols, num_rows, max_value);
/* Write body */
uint8_t row = 0;
for (row = 0; row < num_rows; ++row) {
fprintf(file, "\n");
uint8_t col = 0;
for (col = 0; col < num_cols; ++col) {
if (col > 0) {
fprintf(file, " ");
}
uint16_t current_ofst = offset + (row * num_cols + col) * sizeof(uint16_t);
uint16_t pix_value = io_read_16(dev->base, current_ofst);
fprintf(file, "%" PRIu16, pix_value);
}
}
assert(!fclose(file));
}

View File

@ -0,0 +1,23 @@
#ifndef __LEPTON_H__
#define __LEPTON_H__
#include <stdbool.h>
/* lepton device structure */
typedef struct {
void *base; /* Base address of the component */
} lepton_dev;
/*******************************************************************************
* Public API
******************************************************************************/
lepton_dev lepton_inst(void *base);
void lepton_init(lepton_dev *dev);
void lepton_start_capture(lepton_dev *dev);
void lepton_wait_until_eof(lepton_dev *dev);
bool lepton_error_check(lepton_dev *dev);
void lepton_save_capture(lepton_dev *dev, bool adjusted, FILE* file);
#endif /* __LEPTON_H__ */

View File

@ -0,0 +1,25 @@
#ifndef __LEPTON_REGS_H__
#define __LEPTON_REGS_H__
/* Register offsets */
#define LEPTON_REGS_COMMAND_OFST ( 0 * 2) /* WO */
#define LEPTON_REGS_STATUS_OFST ( 1 * 2) /* RO */
#define LEPTON_REGS_MIN_OFST ( 2 * 2) /* RO */
#define LEPTON_REGS_MAX_OFST ( 3 * 2) /* RO */
#define LEPTON_REGS_SUM_LSB_OFST ( 4 * 2) /* RO */
#define LEPTON_REGS_SUM_MSB_OFST ( 5 * 2) /* RO */
#define LEPTON_REGS_ROW_IDX_OFST ( 6 * 2) /* RO */
#define LEPTON_REGS_RAW_BUFFER_OFST ( 8 * 2) /* RO */
#define LEPTON_REGS_ADJUSTED_BUFFER_OFST (8192 * 2) /* RO */
/* Command register */
#define LEPTON_COMMAND_START (0x0001)
/* Status register */
#define LEPTON_STATUS_CAPTURE_IN_PROGRESS_MASK (1 << 0)
#define LEPTON_STATUS_ERROR_MASK (1 << 1)
#define LEPTON_REGS_BUFFER_NUM_PIXELS (80 * 60)
#define LEPTON_REGS_BUFFER_BYTELENGTH (LEPTON_REGS_BUFFER_NUM_PIXELS * 2)
#endif /* __LEPTON_REGS_H__ */

View File

@ -0,0 +1,109 @@
#include "pantilt.h"
/**
* pantilt_inst
*
* Instantiate a pantilt device structure.
*
* @param pwm_v_base Base address of the vertical PWM component.
* @param pwm_h_base Base address of the horizontal PWM component.
*/
pantilt_dev pantilt_inst(void *pwm_v_base, void *pwm_h_base) {
pantilt_dev dev;
dev.pwm_v = pwm_inst(pwm_v_base);
dev.pwm_h = pwm_inst(pwm_h_base);
return dev;
}
/**
* pantilt_init
*
* Initializes the pantilt device.
*
* @param dev pantilt device structure.
*/
void pantilt_init(pantilt_dev *dev) {
pwm_init(&(dev->pwm_v));
pwm_init(&(dev->pwm_h));
}
/**
* pantilt_configure_vertical
*
* Configure the vertical PWM component.
*
* @param dev pantilt device structure.
* @param duty_cycle pwm duty cycle in us.
*/
void pantilt_configure_vertical(pantilt_dev *dev, uint32_t duty_cycle) {
// Need to compensate for inverted servo rotation.
duty_cycle = PANTILT_PWM_V_MAX_DUTY_CYCLE_US - duty_cycle + PANTILT_PWM_V_MIN_DUTY_CYCLE_US;
pwm_configure(&(dev->pwm_v),
duty_cycle,
PANTILT_PWM_PERIOD_US,
PANTILT_PWM_CLOCK_FREQ_HZ);
}
/**
* pantilt_configure_horizontal
*
* Configure the horizontal PWM component.
*
* @param dev pantilt device structure.
* @param duty_cycle pwm duty cycle in us.
*/
void pantilt_configure_horizontal(pantilt_dev *dev, uint32_t duty_cycle) {
// Need to compensate for inverted servo rotation.
duty_cycle = PANTILT_PWM_H_MAX_DUTY_CYCLE_US - duty_cycle + PANTILT_PWM_H_MIN_DUTY_CYCLE_US;
pwm_configure(&(dev->pwm_h),
duty_cycle,
PANTILT_PWM_PERIOD_US,
PANTILT_PWM_CLOCK_FREQ_HZ);
}
/**
* pantilt_start_vertical
*
* Starts the vertical pwm controller.
*
* @param dev pantilt device structure.
*/
void pantilt_start_vertical(pantilt_dev *dev) {
pwm_start(&(dev->pwm_v));
}
/**
* pantilt_start_horizontal
*
* Starts the horizontal pwm controller.
*
* @param dev pantilt device structure.
*/
void pantilt_start_horizontal(pantilt_dev *dev) {
pwm_start(&(dev->pwm_h));
}
/**
* pantilt_stop_vertical
*
* Stops the vertical pwm controller.
*
* @param dev pantilt device structure.
*/
void pantilt_stop_vertical(pantilt_dev *dev) {
pwm_stop(&(dev->pwm_v));
}
/**
* pantilt_stop_horizontal
*
* Stops the horizontal pwm controller.
*
* @param dev pantilt device structure.
*/
void pantilt_stop_horizontal(pantilt_dev *dev) {
pwm_stop(&(dev->pwm_h));
}

View File

@ -0,0 +1,39 @@
#ifndef __PANTILT_H__
#define __PANTILT_H__
#include "pwm/pwm.h"
/* joysticks device structure */
typedef struct pantilt_dev {
pwm_dev pwm_v; /* Vertical PWM device handle */
pwm_dev pwm_h; /* Horizontal PWM device handle */
} pantilt_dev;
/*******************************************************************************
* Public API
******************************************************************************/
#define PANTILT_PWM_CLOCK_FREQ_HZ (50000000) // 50.00 MHz
#define PANTILT_PWM_PERIOD_US (25000) // 25.00 ms
/* Vertical servo */
#define PANTILT_PWM_V_MIN_DUTY_CYCLE_US (950) // 0.95 ms
#define PANTILT_PWM_V_MAX_DUTY_CYCLE_US (2150) // 2.15 ms
/* Horizontal servo */
#define PANTILT_PWM_H_MIN_DUTY_CYCLE_US (1000) // 1.00 ms
#define PANTILT_PWM_H_MAX_DUTY_CYCLE_US (2000) // 2.00 ms
pantilt_dev pantilt_inst(void *pwm_v_base, void *pwm_h_base);
void pantilt_init(pantilt_dev *dev);
void pantilt_configure_vertical(pantilt_dev *dev, uint32_t duty_cycle);
void pantilt_configure_horizontal(pantilt_dev *dev, uint32_t duty_cycle);
void pantilt_start_vertical(pantilt_dev *dev);
void pantilt_start_horizontal(pantilt_dev *dev);
void pantilt_stop_vertical(pantilt_dev *dev);
void pantilt_stop_horizontal(pantilt_dev *dev);
#endif /* __PANTILT_H__ */

View File

@ -0,0 +1,68 @@
#include "pwm.h"
#include "pwm_regs.h"
#include "iorw.h"
#define MICROSEC_TO_CLK(time, freq) ((time) * ((freq) / 1000000))
/**
* pwm_inst
*
* Instantiate a pwm device structure.
*
* @param base Base address of the component.
*/
pwm_dev pwm_inst(void *base) {
pwm_dev dev;
dev.base = base;
return dev;
}
/**
* pwm_init
*
* Initializes the pwm device. This function stops the controller.
*
* @param dev pwm device structure.
*/
void pwm_init(pwm_dev *dev) {
pwm_stop(dev);
}
/**
* pwm_configure
*
* Configure pwm component.
*
* @param dev pwm device structure.
* @param duty_cycle pwm duty cycle in us.
* @param period pwm period in us.
* @param module_frequency frequency at which the component is clocked.
*/
void pwm_configure(pwm_dev *dev, uint32_t duty_cycle, uint32_t period, uint32_t module_frequency) {
io_write_32(dev->base, PWM_PERIOD_OFST, MICROSEC_TO_CLK(period, module_frequency));
io_write_32(dev->base, PWM_DUTY_CYCLE_OFST, MICROSEC_TO_CLK(duty_cycle, module_frequency));
}
/**
* pwm_start
*
* Starts the pwm controller.
*
* @param dev pwm device structure.
*/
void pwm_start(pwm_dev *dev) {
io_write_32(dev->base, PWM_CTRL_OFST, PWM_CTRL_START_MASK);
}
/**
* pwm_stop
*
* Stops the pwm controller.
*
* @param dev pwm device structure.
*/
void pwm_stop(pwm_dev *dev) {
io_write_32(dev->base, PWM_CTRL_OFST, PWM_CTRL_START_MASK);
}

View File

@ -0,0 +1,21 @@
#ifndef __PWM_H__
#define __PWM_H__
#include <stdint.h>
/* pwm device structure */
typedef struct pwm_dev {
void *base; /* Base address of component */
} pwm_dev;
/*******************************************************************************
* Public API
******************************************************************************/
pwm_dev pwm_inst(void *base);
void pwm_init(pwm_dev *dev);
void pwm_configure(pwm_dev *dev, uint32_t duty_cycle, uint32_t period, uint32_t module_frequency);
void pwm_start(pwm_dev *dev);
void pwm_stop(pwm_dev *dev);
#endif /* __PWM_H__ */

View File

@ -0,0 +1,11 @@
#ifndef __PWM_REGS_H__
#define __PWM_REGS_H__
#define PWM_PERIOD_OFST (0 * 4) /* RW */
#define PWM_DUTY_CYCLE_OFST (1 * 4) /* RW */
#define PWM_CTRL_OFST (2 * 4) /* WO */
#define PWM_CTRL_STOP_MASK (0)
#define PWM_CTRL_START_MASK (1)
#endif /* __PWM_REGS_H__ */

View File

@ -0,0 +1,37 @@
#include "socfpga_cyclone5_de0_sockit.dts"
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#define VGA_SEQUENCER_REG_CSR 0x00
#define VGA_SEQUENCER_REG_HBP 0x04
#define VGA_SEQUENCER_REG_HFP 0x08
#define VGA_SEQUENCER_REG_VBP 0x0c
#define VGA_SEQUENCER_REG_VFP 0x10
#define VGA_SEQUENCER_REG_HDATA 0x14
#define VGA_SEQUENCER_REG_VDATA 0x18
#define VGA_SEQUENCER_REG_HSYNC 0x1c
#define VGA_SEQUENCER_REG_VSYNC 0x20
/ {
soc {
display {
compatible = "prsoc,display";
reg = <0xff200080 0x40 /* Frame manager <address span> */
0xff200000 0x80>; /* VGA sequencer <address span> */
interrupts = <GIC_SPI 40 IRQ_TYPE_EDGE_RISING>;
prsoc,screen-width = <480>;
prsoc,screen-height = <272>;
prsoc,buffer-width = <480>;
prsoc,buffer-height = <544>; // -> 2 buffers
prsoc,reg-init = <VGA_SEQUENCER_REG_VSYNC 10>,
<VGA_SEQUENCER_REG_VBP 2>,
<VGA_SEQUENCER_REG_VDATA 272>,
<VGA_SEQUENCER_REG_VFP 3>,
<VGA_SEQUENCER_REG_HSYNC 41>,
<VGA_SEQUENCER_REG_HBP 47>,
<VGA_SEQUENCER_REG_HDATA 480>,
<VGA_SEQUENCER_REG_HFP 8>,
<VGA_SEQUENCER_REG_CSR 1>;
};
};
};

View File

@ -0,0 +1,9 @@
obj-m += prsoc_fbdev.o
KERNEL_SOURCE_PATH='../../source/'
all:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERNEL_SOURCE_PATH) M=$(PWD) modules
clean:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERNEL_SOURCE_PATH) clean

View File

@ -0,0 +1,416 @@
/*
* @file prsoc_vga_fbdev
* @author Philemon Favrod
* @date 18 May 2016
* @brief The framebuffer Linux driver for the PrSoC extension board.
*
* This file is divided in two sections. The first contains the framebuffer
* driver code. The second contains the boilerplate code to create the
* device associated with the framebuffer. The latter allow us to use
* much less error-prone APIs (devm_* or dmam_*).
*
* More precisely, the LCD is viewed as a platform device, i.e. a device
* that is directly addressable from the CPU. Platform device are loaded
* based on their compatible string (here "prsoc,display"). In other words,
* once this driver is known to the kernel (c.f. insmod), the kernel will
* call its associated probe function if its associated compatible string
* is present in a device node (= an element of the device tree).
*
* In our case, the probe function is prsoc_display_platform_probe that you
* can find at the end of this file. Its main role is to allocate the resources
* based on what the device tree says. It uses the so-called managed API to
* do so. This API has the advantage of letting the kernel do the clean up based on
* whether or not the driver is loaded. It makes the code more readable.
* At the end of the probe function, the framebuffer is registered.
*
* For more information about this, here is a collection of resources that
* might be helpful:
* - https://www.kernel.org/doc/Documentation/driver-model/platform.txt
* -
*
* Revisions:
* 5/18/2016 Created (only for simple VGA)
* 5/28/2016 Adapted for TFT043
* 5/28/2016 Extended with mmap support
* 6/15/2016 Extend configurability from DT + panning
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/fb.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/types.h>
/* Offsets of the framebuffer manager's registers. */
#define FM_REG_FRAME_START_ADDRESS 0x00
#define FM_REG_FRAME_PIX_PER_LINE 0x04
#define FM_REG_FRAME_NUM_LINES 0x08
#define FM_REG_FRAME_EOL_BYTE_OFST 0x0C
#define FM_REG_CONTROL 0x10
#define FM_REG_BURST_COUNT 0x14
#define FM_CONTROL_ENABLE_DMA_MASK (1UL << 0)
#define FM_CONTROL_ENABLE_IRQ_MASK (1UL << 2)
#define FM_CONTROL_ACKNOWLEDGE_IRQ_MASK (1UL << 4)
/* Enclose the driver data. */
struct prsoc_display_drvdata {
uint8_t *fm_regs; /* a pointer to the frame manager's regs */
uint8_t *lcd_int_regs; /* a pointer to the LCD interface's regs */
uint32_t *front_buffer; /* a dmable frame buffer */
unsigned long front_buffer_phys; /* physical address of the frame buffer */
int irq;
};
#define FM_WR(DRVDATA, REG, VAL) \
iowrite32((VAL), (DRVDATA)->fm_regs + (REG))
#define LCD_INTERFACE_WR(DRVDATA, REG, VAL) \
iowrite32((VAL), (DRVDATA)->lcd_int_regs + (REG))
/* Framebuffer driver */
/* ISR called at the end of each frame. Called at the beginning
* of the vertical back porch, i.e. as soon as possible to avoid
* tearing effect. */
static irqreturn_t vsync_isr(int irq, void *data)
{
/*printk("IRQ received.\n");*/
//int i;
struct prsoc_display_drvdata *drvdata = data;
/* Acknowledge the IRQ */
FM_WR(drvdata, FM_REG_CONTROL, FM_CONTROL_ACKNOWLEDGE_IRQ_MASK);
return IRQ_HANDLED;
}
/* Defaults screen parameters */
static struct fb_fix_screeninfo prsocfb_fix_defaults = {
.id = "prsocfb",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_DIRECTCOLOR,
.accel = FB_ACCEL_NONE,
.ypanstep = 1 // support y panning
};
static struct fb_var_screeninfo prsocfb_var_defaults = {
.bits_per_pixel = 32,
.red = { .offset = 16, .length = 8 },
.green = { .offset = 8, .length = 8 },
.blue = { .offset = 0, .length = 8 }
};
uint32_t pseudo_palette[16];
static int prsocfb_setcoloreg(unsigned regno, unsigned red,
unsigned green, unsigned blue,
unsigned transp, struct fb_info *info)
{
if (regno >= 16)
return -EINVAL;
red *= 0xff;
green *= 0xff;
blue *= 0xff;
red /= 0xffff;
green /= 0xffff;
blue /= 0xffff;
pseudo_palette[regno] = (red << 16) | (green << 8) | blue;
return 0;
}
int prsocfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct prsoc_display_drvdata *drvdata = (struct prsoc_display_drvdata *)info->par;
uint32_t byte_offset;
if ((var->yoffset + var->yres > var->yres_virtual) ||
(var->xoffset + var->xres > var->xres_virtual))
{
return -EINVAL;
}
byte_offset = (var->yoffset * info->fix.line_length) +
(var->xoffset * (var->bits_per_pixel / 8));
FM_WR(drvdata, FM_REG_FRAME_START_ADDRESS, drvdata->front_buffer_phys + byte_offset);
return 0;
}
/* purpose: mmap the front buffer. */
static int prsocfb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
struct prsoc_display_drvdata *drvdata = (struct prsoc_display_drvdata *)info->par;
unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end - vma->vm_start;
unsigned long screen_size = info->var.xres_virtual * info->var.yres_virtual * sizeof(uint32_t);
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long pfn = -1;
void * pos = phys_to_virt(drvdata->front_buffer_phys) + offset;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); // non cachable page
vma->vm_flags |= VM_IO;
/* Compute the screen size in PAGE_SIZE. */
screen_size += PAGE_SIZE - 1;
screen_size >>= PAGE_SHIFT;
screen_size <<= PAGE_SHIFT;
/* Make sure that it maps only the back buffer */
if (offset + size > screen_size) {
printk(KERN_ERR "prsocfb: trying to mmap too much memory. %lu %lu %lu\n",
offset, size, screen_size);
return -EINVAL;
}
while (size > 0) {
/* Extract the page number of the current position
* in the buffer. */
pfn = virt_to_pfn(pos);
/* Map it in the user virtual memory. */
if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, vma->vm_page_prot)) {
printk(KERN_ERR "prsocfb: remap_pfn_range failed\n");
return -EAGAIN;
}
start += PAGE_SIZE;
pos += PAGE_SIZE;
if (size > PAGE_SIZE)
size -= PAGE_SIZE;
else
size = 0;
}
return 0;
}
static struct fb_ops prsocfb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = prsocfb_setcoloreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_mmap = prsocfb_mmap,
.fb_pan_display = prsocfb_pan_display
};
/* Platform driver */
/* Informs the kernel of the corresponding compatible string. */
static const struct of_device_id prsoc_display_device_ids[] = {
{ .compatible = "prsoc,display" },
{ }
};
MODULE_DEVICE_TABLE(of, prsoc_display_device_ids);
/* To understand Device tree parsing, see:
* - http://xillybus.com/tutorials/device-tree-zynq-4
* - http://xillybus.com/tutorials/device-tree-zynq-5
*/
#define EXTRACT_INT_FROM_DT_OR_FAIL(NP, PROP) ({ \
const void *property = of_get_property((NP), (PROP), NULL); \
if (!property) { \
printk(KERN_ERR "no '" PROP "' in the device tree."); \
return -EINVAL; \
} \
be32_to_cpup(property); \
})
/* Apply configuration from device tree. */
static int configure_from_dt(
struct platform_device *pdev,
struct prsoc_display_drvdata *drvdata,
struct fb_fix_screeninfo *fix_screeninfo,
struct fb_var_screeninfo *var_screeninfo)
{
struct resource *rsrc;
int err, i;
const __be32 *properties;
int len;
/* Extract a pointer to the device node. */
struct device_node *np = pdev->dev.of_node;
dma_addr_t phys;
/* Get the width and height properties. */
uint32_t screen_width = EXTRACT_INT_FROM_DT_OR_FAIL(np, "prsoc,screen-width");
uint32_t screen_height = EXTRACT_INT_FROM_DT_OR_FAIL(np, "prsoc,screen-height");
uint32_t buffer_width = EXTRACT_INT_FROM_DT_OR_FAIL(np, "prsoc,buffer-width");
uint32_t buffer_height = EXTRACT_INT_FROM_DT_OR_FAIL(np, "prsoc,buffer-height");
printk(KERN_INFO "According to the device tree, the screen is %ux%u and the buffer is %ux%u.",
screen_width, screen_height, buffer_width, buffer_height);
/* Maps the addresses of the registers of the framebuffer manager. */
rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
drvdata->fm_regs = devm_ioremap_resource(&pdev->dev, rsrc);
if (IS_ERR(drvdata->fm_regs))
return PTR_ERR(drvdata->fm_regs);
printk(KERN_INFO "Framebuffer manager regs @ 0x%x-0x%x\n",
rsrc->start, rsrc->end);
/* Maps the addresses of the video interface. */
rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 1);
drvdata->lcd_int_regs = devm_ioremap_resource(&pdev->dev, rsrc);
if (IS_ERR(drvdata->lcd_int_regs))
return PTR_ERR(drvdata->lcd_int_regs);
printk(KERN_INFO "Interface regs @ 0x%x-0x%x\n", rsrc->start,
rsrc->end);
/* Register the ISR for vertical blanking notification. */
drvdata->irq = platform_get_irq(pdev, 0);
err = devm_request_irq(
&pdev->dev, drvdata->irq,
(irq_handler_t) vsync_isr,
0, "prsoc-fbdev", drvdata);
if (err) {
printk(KERN_ERR "couldn't register ISR. Is 'interrupts' " \
"field in the device tree?\n");
return -ENXIO;
}
/* Set the screeninfo to default values */
*fix_screeninfo = prsocfb_fix_defaults;
*var_screeninfo = prsocfb_var_defaults;
/* Set the size properties */
var_screeninfo->xres = screen_width;
var_screeninfo->yres = screen_height;
var_screeninfo->xres_virtual = buffer_width;
var_screeninfo->yres_virtual = buffer_height;
fix_screeninfo->line_length = screen_width * sizeof(uint32_t);
/* Allocate DMAble frame buffer. */
drvdata->front_buffer = dmam_alloc_coherent(
&pdev->dev,
buffer_width * buffer_height * sizeof(uint32_t),
&phys,
GFP_KERNEL);
if (!drvdata->front_buffer) {
printk(KERN_ERR "prsoc_fbdev: couldn't allocate a dmable buffer.\n");
return -ENOMEM;
}
drvdata->front_buffer_phys = (unsigned long)phys;
printk(KERN_INFO "DMABLE BUFFER @ 0x%lx\n", drvdata->front_buffer_phys);
/* Parse the reg-init sequence */
properties = of_get_property(pdev->dev.of_node, "prsoc,reg-init", &len);
if (!properties) {
printk(KERN_INFO "no 'prsoc,reg-init' property found in Device Tree.\n");
return 0; // reg-init is optional
}
len /= sizeof(__be32);
if (len % 2 != 0) {
printk(KERN_ERR "'prsoc,reg-init' in Device Tree should have format <ADDR1 VAL1>, <ADDR2 VAL2>, ...\n");
return -EINVAL;
}
printk(KERN_INFO "Initialize registers as specified in Device Tree:\n");
for (i = 0; i < len; i += 2) {
uint32_t offset = be32_to_cpup(properties + i);
uint32_t value = be32_to_cpup(properties + i + 1);
LCD_INTERFACE_WR(drvdata, offset, value);
printk(KERN_INFO "\tWrite 0x%x at offset 0x%x\n", value, offset);
}
return 0;
}
/*
* The following method is called when the driver is loaded.
* It collects information from the device tree.
*/
static int
prsoc_display_platform_probe(struct platform_device *pdev)
{
struct prsoc_display_drvdata *drvdata;
struct fb_info *info;
/* Defensive programming: let's make sure this is the right device. */
if (!of_match_device(prsoc_display_device_ids, &pdev->dev))
return -EINVAL;
/* Allocate the framebuffer. */
info = framebuffer_alloc(sizeof(struct prsoc_display_drvdata), &pdev->dev);
if (!info) {
return -ENOMEM;
}
/* Extract the allocated driver data structure. */
drvdata = (struct prsoc_display_drvdata *)info->par;
platform_set_drvdata(pdev, drvdata);
printk(KERN_INFO "Configure from Device Tree.\n");
configure_from_dt(pdev, drvdata, &info->fix, &info->var);
printk(KERN_INFO "Initialize the Frame Manager.\n");
FM_WR(drvdata, FM_REG_FRAME_START_ADDRESS, drvdata->front_buffer_phys);
FM_WR(drvdata, FM_REG_FRAME_PIX_PER_LINE, info->var.xres);
FM_WR(drvdata, FM_REG_FRAME_NUM_LINES, info->var.yres);
FM_WR(drvdata, FM_REG_FRAME_EOL_BYTE_OFST, 0);
FM_WR(drvdata, FM_REG_BURST_COUNT, 4);
FM_WR(drvdata, FM_REG_CONTROL, FM_CONTROL_ENABLE_DMA_MASK);
/* Enable IRQ */
// FM_WR(drvdata, FM_REG_CONTROL, FM_CONTROL_ENABLE_IRQ_MASK);
/* Configure the framebuffer */
info->screen_base = (void *)drvdata->front_buffer;
info->screen_size = info->var.xres * info->var.yres * sizeof(uint32_t);
info->fbops = &prsocfb_ops;
info->pseudo_palette = pseudo_palette;
info->flags = FBINFO_DEFAULT;
if (fb_alloc_cmap(&info->cmap, 256, 0))
return -ENOMEM;
return register_framebuffer(info);
}
int prsoc_display_platform_remove(struct platform_device *pdev)
{
struct prsoc_display_drvdata *drvdata = platform_get_drvdata(pdev);
struct fb_info *info = container_of((void *)drvdata, struct fb_info, par);
unregister_framebuffer(info);
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
return 0;
}
static struct platform_driver prsoc_display_pdriver = {
.probe = prsoc_display_platform_probe,
.driver = {
.name = "PrSoC displays",
.owner = THIS_MODULE,
.of_match_table = prsoc_display_device_ids,
},
};
MODULE_LICENSE("GPL");
module_platform_driver(prsoc_display_pdriver);

View File

@ -0,0 +1,23 @@
#!/bin/bash -x
# apt sources
# uncomment the "deb" lines (no need to uncomment "deb src" lines)
# Edit the “/etc/apt/sources.list” file to configure the package manager. This
# file contains a list of mirrors that the package manager queries. By default,
# this file has all fields commented out, so the package manager will not have
# access to any mirrors. The following command uncomments all commented out
# lines starting with "deb". These contain the mirrors we are interested in.
sudo perl -pi -e 's/^#+\s+(deb\s+http)/$1/g' "/etc/apt/sources.list"
# When writing our linux applications, we want to use ARM DS-5s remote
# debugging feature to automatically transfer our binaries to the target device
# and to start a debugging session. The remote debugging feature requires an SSH
# server and a remote gdb server to be available on the target. These are easy
# to install as we have a package manager available
sudo apt update
sudo apt -y install ssh gdbserver
# Allow root SSH login with password (needed so we can use ARM DS-5 for remote
# debugging)
sudo perl -pi -e 's/^(PermitRootLogin) without-password$/$1 yes/g' "/etc/ssh/sshd_config"

View File

@ -0,0 +1,94 @@
#!/bin/bash -x
# Configure the locale to have proper language support.
localedef -i en_US -c -f UTF-8 en_US.UTF-8
dpkg-reconfigure locales
# Configure the timezone.
echo "Europe/Zurich" > "/etc/timezone"
dpkg-reconfigure -f noninteractive tzdata
# Set the machines hostname.
echo "DE0-Nano-SoC" > "/etc/hostname"
tee "/etc/hosts" >"/dev/null" <<EOF
127.0.0.1 localhost
127.0.1.1 DE0-Nano-SoC
EOF
# Create the “/etc/network/interfaces” file that describes the network
# interfaces available on the board.
tee "/etc/network/interfaces" > "/dev/null" <<EOF
# interfaces(5) file used by ifup(8) and ifdown(8)
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
auto eth0
iface eth0 inet static
address 10.42.0.2
netmask 255.255.255.0
gateway 10.42.0.1
EOF
# DNS configuration for name resolution. We use google's public DNS server here.
sudo tee "/etc/resolv.conf" > "/dev/null" <<EOF
nameserver 8.8.8.8
EOF
# Configure Ubuntu Core to display a login shell on the serial console once the
# kernel boots. We had previously configured U-Boot to supply the command-line
# argument "console=ttyS0,115200" to the linux kernel. This argument instructs
# the kernel to use serial console “ttyS0” as the boot shell, so here we choose
# to use the same serial console for the login shell-
tee "/etc/init/ttyS0.conf" > "/dev/null" <<EOF
# ttyS0 - getty
#
# This service maintains a getty on ttyS0
description "Get a getty on ttyS0"
start on runlevel [2345]
stop on runlevel [016]
respawn
exec /sbin/getty -L 115200 ttyS0 vt102
EOF
# Create a user and a password. In this example, we create a user called
# “sahand” with password "1234". Note that we compute an encrypted version of
# the password, because useradd does not allow plain text passwords to be used
# in non-interactive mode.
username="sahand"
password="1234"
encrypted_password="$(perl -e 'printf("%s\n", crypt($ARGV[0], "password"))' "${password}")"
useradd -m -p "${encrypted_password}" -s "/bin/bash" "${username}"
# Ubuntu requires the admin to be part of the "adm" and "sudo" groups, so add
# the previously-created user to the 2 groups.
addgroup ${username} adm
addgroup ${username} sudo
# Set root password to "1234" (same as previously-created user).
echo -e "${password}\n${password}\n" | passwd root
# Remove "/rootfs_config.sh" from /etc/rc.local to avoid reconfiguring system on
# next boot
tee "/etc/rc.local" > "/dev/null" <<EOF
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
exit 0
EOF