diff --git a/XilinxProcessorIPLib/drivers/spi/data/spi.mdd b/XilinxProcessorIPLib/drivers/spi/data/spi.mdd new file mode 100755 index 00000000..0976f4c6 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/data/spi.mdd @@ -0,0 +1,60 @@ +############################################################################### +# +# Copyright (C) 2004 - 2014 Xilinx, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +############################################################################### +# +# MODIFICATION HISTORY: +# Ver Who Date Changes +# -------- ------ -------- -------------------------------------------------- +# 4.0 adk 10/12/13 Removed support for xps_spi xps_insystem_flash +############################################################################## +## @BEGIN_CHANGELOG EDK_M +## +## 11/27/09 ktn Removed support for opb_spi +## +## @END_CHANGELOG + +## @BEGIN_CHANGELOG EDK_MS3 +## +## 06/16/10 sv Added support for axi_spi +## +## @END_CHANGELOG + +OPTION psf_version = 2.1; + +BEGIN driver spi + + OPTION supported_peripherals = (axi_spi axi_quad_spi); + OPTION driver_state = ACTIVE; + OPTION copyfiles = all; + OPTION VERSION = 4.1; + OPTION NAME = spi; + +END driver diff --git a/XilinxProcessorIPLib/drivers/spi/data/spi.tcl b/XilinxProcessorIPLib/drivers/spi/data/spi.tcl new file mode 100755 index 00000000..02842431 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/data/spi.tcl @@ -0,0 +1,348 @@ +############################################################################### +# +# Copyright (C) 2004 - 2014 Xilinx, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +############################################################################### +############################################################################## +# +# Modification History +# +# Ver Who Date Changes +# ----- ---- -------- ----------------------------------------------- +# 3.03a sdm 08/11/10 Added C_SPI_MODE parameter to config structure +# 3.04a bss 03/21/12 Added C_TYPE_OF_AXI4_INTERFACE, C_AXI4_BASEADDR and +# C_XIP_MODE to config structure. +# Modified such that based on C_XIP_MODE and +# C_TYPE_OF_AXI4_INTERFACE parameters C_BASEADDR will +# be updated with the value of C_AXI4_BASEADDR. +# Modified such that C_FIFO_EXIST will be updated based +# on C_FIFO_DEPTH for compatability of driver +# 3.06a adk 07/08/13 Added C_USE_STARTUP parameter to the config structure +# 4.0 adk 12/10/13 Updated as per the New Tcl API's +# +############################################################################## + +#uses "xillib.tcl" + +set periph_config_params_spi 0 +set periph_ninstances_spi 0 + +proc init_periph_config_struct_spi { deviceid } { + global periph_config_params_spi + set periph_config_params_spi($deviceid) [list] +} + +proc add_field_to_periph_config_struct_spi { deviceid fieldval } { + global periph_config_params_spi + lappend periph_config_params_spi($deviceid) $fieldval +} + +proc get_periph_config_struct_fields_spi { deviceid } { + global periph_config_params_spi + return $periph_config_params_spi($deviceid) +} + +proc xdefine_axispi_include_file {drv_handle file_name drv_string} { + global periph_ninstances + + # Open include file + set file_handle [::hsm::utils::open_include_file $file_name] + + # Get all peripherals connected to this driver + set periphs [::hsm::utils::get_common_driver_ips $drv_handle] + + # Handle NUM_INSTANCES + set periph_ninstances 0 + puts $file_handle "/* Definitions for driver [string toupper [get_property NAME $drv_handle]] */" + foreach periph $periphs { + init_periph_config_struct_spi $periph_ninstances + incr periph_ninstances 1 + } + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $drv_string NUM_INSTANCES] $periph_ninstances" + + + # Now print all useful parameters for all peripherals + set device_id 0 + foreach periph $periphs { + puts $file_handle "" + + xdefine_axispi_params_instance $file_handle $periph $device_id + + xdefine_axispi_params_canonical $file_handle $periph $device_id + incr device_id + puts $file_handle "\n" + } + puts $file_handle "\n/******************************************************************/\n" + close $file_handle +} + +proc xdefine_axispi_params_instance {file_handle periph device_id} { + set ip [get_cells $periph] + set xip_mode_value [get_property CONFIG.C_XIP_MODE $ip] + if {[llength $xip_mode_value] == 0} { + set xip_mode_value 0 + } + set axi_type_value [get_property CONFIG.C_TYPE_OF_AXI4_INTERFACE $periph] + if {[llength $axi_type_value] == 0} { + set axi_type_value 0 + } + set axi4_baseaddr_value [get_property CONFIG.C_S_AXI4_BASEADDR $periph] + if {[llength $axi4_baseaddr_value] == 0} { + set axi4_baseaddr_value 0 + } + set axi4_highaddr_value [get_property CONFIG.C_S_AXI4_HIGHADDR $periph] + if {[llength $axi4_highaddr_value] == 0} { + set axi4_highaddr_value 0 + } + puts $file_handle "/* Definitions for peripheral [string toupper [get_property NAME $periph]] */" + + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "DEVICE_ID"] $device_id" + if {$xip_mode_value == 0} { + if {$axi_type_value == 0} { + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "BASEADDR"] [get_property CONFIG.C_BASEADDR $periph]" + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph HIGHADDR] [get_property CONFIG.C_HIGHADDR $periph]" + } else { + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "BASEADDR"] $axi4_baseaddr_value" + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph HIGHADDR] $axi4_highaddr_value" + } + } else { + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "BASEADDR"] [get_property CONFIG.C_BASEADDR $periph]" + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph HIGHADDR] [get_property CONFIG.C_HIGHADDR $periph]" + } + + set value [get_property CONFIG.C_FIFO_EXIST $periph] + if {[llength $value] == 0} { + set value1 [get_property CONFIG.C_FIFO_DEPTH $periph] + if {[llength $value1] == 0} { + set value1 0 + } else { + set value1 [get_property CONFIG.C_FIFO_DEPTH $periph] + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "FIFO_DEPTH"] $value1" + if {$value1 == 0} { + set value1 0 + } else { + set value1 1 + } + } + } else { + set value1 $value + } + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "FIFO_EXIST"] $value1" + + set value [get_property CONFIG.C_SPI_SLAVE_ONLY $periph] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "SPI_SLAVE_ONLY"] $value" + set value [get_property CONFIG.C_NUM_SS_BITS $periph] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "NUM_SS_BITS"] $value" + set value [get_property CONFIG.C_NUM_TRANSFER_BITS $periph] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "NUM_TRANSFER_BITS"] $value" + set value [get_property CONFIG.C_SPI_MODE $periph] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "SPI_MODE"] $value" + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "TYPE_OF_AXI4_INTERFACE"] $axi_type_value" + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "AXI4_BASEADDR"] $axi4_baseaddr_value" + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "AXI4_HIGHADDR"] $axi4_highaddr_value" + puts $file_handle "\#define [::hsm::utils::get_driver_param_name $periph "XIP_MODE"] $xip_mode_value" +} + +proc xdefine_axispi_params_canonical {file_handle periph device_id} { + + set xip_mode_value [get_property CONFIG.C_XIP_MODE $periph] + if {[llength $xip_mode_value] == 0} { + set xip_mode_value 0 + } + set axi_type_value [get_property CONFIG.C_TYPE_OF_AXI4_INTERFACE $periph] + if {[llength $axi_type_value] == 0} { + set axi_type_value 0 + } + set axi4_baseaddr_value [get_property CONFIG.C_S_AXI4_BASEADDR $periph] + if {[llength $axi4_baseaddr_value] == 0} { + set axi4_baseaddr_value 0 + } + set axi4_highaddr_value [get_property CONFIG.C_S_AXI4_HIGHADDR $periph] + if {[llength $axi4_highaddr_value] == 0} { + set axi4_highaddr_value 0 + } + + set use_startup_value [get_property CONFIG.C_USE_STARTUP $periph] + if {[llength $use_startup_value] == 0} { + set use_startup_value 0 + } + + puts $file_handle "\n/* Canonical definitions for peripheral [string toupper [get_property NAME $periph]] */" + + set canonical_tag [string toupper [format "XPAR_SPI_%d" $device_id]] + + # Handle device ID + set canonical_name [format "%s_DEVICE_ID" $canonical_tag] + puts $file_handle "\#define $canonical_name $device_id" + add_field_to_periph_config_struct_spi $device_id $canonical_name + + if {$xip_mode_value == 0} { + if {$axi_type_value == 0} { + set canonical_name [format "%s_BASEADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name [get_property CONFIG.C_BASEADDR $periph]" + add_field_to_periph_config_struct_spi $device_id $canonical_name + set canonical_name [format "%s_HIGHADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name [get_property CONFIG.C_HIGHADDR $periph]" + } else { + set canonical_name [format "%s_BASEADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name $axi4_baseaddr_value" + add_field_to_periph_config_struct_spi $device_id $canonical_name + set canonical_name [format "%s_HIGHADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name $axi4_highaddr_value" + } + } else { + set canonical_name [format "%s_BASEADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name [get_property CONFIG.C_BASEADDR $periph]" + add_field_to_periph_config_struct_spi $device_id $canonical_name + set canonical_name [format "%s_HIGHADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name [get_property CONFIG.C_HIGHADDR $periph]" + } + set canonical_name [format "%s_FIFO_EXIST" $canonical_tag] + set value [get_property CONFIG.C_FIFO_EXIST $periph] + if {[llength $value] == 0} { + set value1 [get_property CONFIG.C_FIFO_DEPTH $periph] + if {[llength $value1] == 0} { + set value1 0 + } else { + set canonical_name1 [format "%s_FIFO_DEPTH" $canonical_tag] + puts $file_handle "\#define $canonical_name1 $value1" + if {$value1 == 0} { + set value1 0 + } else { + set value1 1 + } + } + } else { + set value1 $value + } + puts $file_handle "\#define $canonical_name $value1" + add_field_to_periph_config_struct_spi $device_id $canonical_name + + set canonical_name [format "%s_SPI_SLAVE_ONLY" $canonical_tag] + set value [get_property CONFIG.C_SPI_SLAVE_ONLY $periph] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct_spi $device_id $canonical_name + + set canonical_name [format "%s_NUM_SS_BITS" $canonical_tag] + set value [get_property CONFIG.C_NUM_SS_BITS $periph] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct_spi $device_id $canonical_name + + set canonical_name [format "%s_NUM_TRANSFER_BITS" $canonical_tag] + set value [get_property CONFIG.C_NUM_TRANSFER_BITS $periph] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct_spi $device_id $canonical_name + + set canonical_name [format "%s_SPI_MODE" $canonical_tag] + set value [get_property CONFIG.C_SPI_MODE $periph] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct_spi $device_id $canonical_name + + set canonical_name [format "%s_TYPE_OF_AXI4_INTERFACE" $canonical_tag] + puts $file_handle "\#define $canonical_name $axi_type_value" + add_field_to_periph_config_struct_spi $device_id $canonical_name + + set canonical_name [format "%s_AXI4_BASEADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name $axi4_baseaddr_value" + add_field_to_periph_config_struct_spi $device_id $canonical_name + + set canonical_name [format "%s_AXI4_HIGHADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name $axi4_highaddr_value" + + set canonical_name [format "%s_XIP_MODE" $canonical_tag] + puts $file_handle "\#define $canonical_name $xip_mode_value" + add_field_to_periph_config_struct_spi $device_id $canonical_name + + set canonical_name [format "%s_USE_STARTUP" $canonical_tag] + puts $file_handle "\#define $canonical_name $use_startup_value" + add_field_to_periph_config_struct_spi $device_id $canonical_name +} + +proc xdefine_axispi_config_file {file_name drv_string} { + + global periph_ninstances + + set filename [file join "src" $file_name] + file delete $filename + set config_file [open $filename w] + ::hsm::utils::write_c_header $config_file "Driver configuration" + puts $config_file "\#include \"xparameters.h\"" + puts $config_file "\#include \"[string tolower $drv_string].h\"" + puts $config_file "\n/*" + puts $config_file "* The configuration table for devices" + puts $config_file "*/\n" + puts $config_file [format "%s_Config %s_ConfigTable\[\] =" $drv_string $drv_string] + puts $config_file "\{" + + set start_comma "" + for {set i 0} {$i < $periph_ninstances} {incr i} { + + puts $config_file [format "%s\t\{" $start_comma] + set comma "" + foreach field [get_periph_config_struct_fields_spi $i] { + puts -nonewline $config_file [format "%s\t\t%s" $comma $field] + set comma ",\n" + } + + puts -nonewline $config_file "\n\t\}" + set start_comma ",\n" + } + puts $config_file "\n\};\n" + close $config_file +} + +proc generate {drv_handle} { + xdefine_axispi_include_file $drv_handle "xparameters.h" "XSpi" + xdefine_axispi_config_file "xspi_g.c" "XSpi" +} + diff --git a/XilinxProcessorIPLib/drivers/spi/data/spi_header.h b/XilinxProcessorIPLib/drivers/spi/data/spi_header.h new file mode 100755 index 00000000..be0f5893 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/data/spi_header.h @@ -0,0 +1,42 @@ +/****************************************************************************** +* +* Copyright (C) 2007 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +#ifndef SPI_HEADER_H /* prevent circular inclusions */ +#define SPI_HEADER_H /* by using protection macros */ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xstatus.h" + +int SpiSelfTestExample(u16 DeviceId); + +#endif + diff --git a/XilinxProcessorIPLib/drivers/spi/data/spi_intr_header.h b/XilinxProcessorIPLib/drivers/spi/data/spi_intr_header.h new file mode 100755 index 00000000..a5401988 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/data/spi_intr_header.h @@ -0,0 +1,53 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +#ifndef SPI_INTR_HEADER_H /* prevent circular inclusions */ +#define SPI_INTR_HEADER_H /* by using protection macros */ + + +#include "xil_types.h" +#include "xil_assert.h" +#include "xstatus.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +int SpiIntrExample(XIntc *IntcInstancePtr, \ + XSpi *SpiInstancePtr, \ + u16 SpiDeviceId, \ + u16 SpiIntrId); +#else +int SpiIntrExample(XScuGic *IntcInstancePtr, \ + XSpi *SpiInstancePtr, \ + u16 SpiDeviceId, \ + u16 SpiIntrId); + +#endif +#endif + diff --git a/XilinxProcessorIPLib/drivers/spi/data/spi_tapp.tcl b/XilinxProcessorIPLib/drivers/spi/data/spi_tapp.tcl new file mode 100755 index 00000000..00135615 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/data/spi_tapp.tcl @@ -0,0 +1,236 @@ +############################################################################### +# +# Copyright (C) 2005 - 2014 Xilinx, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +############################################################################### +# +# MODIFICATION HISTORY: +# Ver Who Date Changes +# -------- ------ -------- ------------------------------------ +# 4.0 adk 12/10/13 Updated as per the New Tcl API's +############################################################################## + +## @BEGIN_CHANGELOG EDK_L_SP4 +## +## - Removed the checking of the parametr C_INTERRUPT_PRESENT as +## this is not present in the core +## +## @END_CHANGELOG + +## @BEGIN_CHANGELOG EDK_Im_SP2 +## +## - Added Interrupt support +## +## @END_CHANGELOG + +## @BEGIN_CHANGELOG EDK_I +## +## - include header files +## +## @END_CHANGELOG + +## @BEGIN_CHANGELOG EDK_H +## +## - Added support for generation of multiple applications. +## All TCL procedures are now required to have a software +## project type as its first argument +## +## @END_CHANGELOG + + +# Uses $XILINX_EDK/bin/lib/xillib_sw.tcl + +# ----------------------------------------------------------------- +# Software Project Types (swproj): +# 0 : MemoryTest - Calls basic memorytest routines from common driver dir +# 1 : PeripheralTest - Calls any existing polled_example and/or selftest +# ----------------------------------------------------------------- + +# ----------------------------------------------------------------- +# TCL Procedures: +# ----------------------------------------------------------------- + +proc gen_include_files {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + set spi_intr [::hsm::utils::is_ip_interrupting_current_proc $mhsinst] + if { ${spi_intr} == 1} { + set inc_file_lines {xspi.h spi_header.h spi_intr_header.h} + } else { + set inc_file_lines {xspi.h spi_header.h} + } + + return $inc_file_lines + } +} + +proc gen_src_files {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + set spi_intr [::hsm::utils::is_ip_interrupting_current_proc $mhsinst] + if { ${spi_intr} == 1} { + set inc_file_lines {examples/xspi_selftest_example.c examples/xspi_intr_example.c data/spi_header.h data/spi_intr_header.h} + } else { + set inc_file_lines {examples/xspi_selftest_example.c data/spi_header.h} + } + + return $inc_file_lines + } +} + +proc gen_testfunc_def {swproj mhsinst} { + return "" +} + +proc gen_init_code {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + set spi_intr [::hsm::utils::is_ip_interrupting_current_proc $mhsinst] + set ipname [get_property NAME $mhsinst] + + if { ${spi_intr} == 1} { + set decl " static XSpi ${ipname}_Spi;" + set inc_file_lines $decl + return $inc_file_lines + } else { + return "" + } + } +} + +proc gen_testfunc_call {swproj mhsinst} { + + if {$swproj == 0} { + return "" + } + + set ipname [get_property NAME $mhsinst] + set deviceid [::hsm::utils::get_ip_param_name $mhsinst "DEVICE_ID"] + set stdout [get_property CONFIG.STDOUT [get_os]] + if { $stdout == "" || $stdout == "none" } { + set hasStdout 0 + } else { + set hasStdout 1 + } + set spi_intr [::hsm::utils::is_ip_interrupting_current_proc $mhsinst] + + if { ${spi_intr} == 1} { + set intr_pin_name [get_pins -of_objects [get_cells $ipname] -filter "TYPE==INTERRUPT"] + set intcname [::hsm::utils::get_connected_intr_cntrl $ipname $intr_pin_name] + set intcvar intc + set proc [get_property IP_NAME [get_cells [get_sw_processor]]] + } + + set testfunc_call "" + + if {${hasStdout} == 0} { + + append testfunc_call " + + { + XStatus status; + + status = SpiSelfTestExample(${deviceid}); + + }" + if { ${spi_intr} == 1} { + if { + $proc == "microblaze" + } then { + set intr_id "XPAR_${intcname}_${ipname}_${intr_pin_name}_INTR" + } else { + set intr_id "XPAR_FABRIC_${ipname}_${intr_pin_name}_INTR" + } + set intr_id [string toupper $intr_id] + append testfunc_call " + { + XStatus Status; + + Status = SpiIntrExample(&${intcvar}, &${ipname}_Spi, \\ + ${deviceid}, \\ + ${intr_id}); + }" + } + + + } else { + + append testfunc_call " + + { + XStatus status; + + print(\"\\r\\n Runnning SpiSelfTestExample() for ${ipname}...\\r\\n\"); + + status = SpiSelfTestExample(${deviceid}); + + if (status == 0) { + print(\"SpiSelfTestExample PASSED\\r\\n\"); + } + else { + print(\"SpiSelfTestExample FAILED\\r\\n\"); + } + }" + if { ${spi_intr} == 1} { + if { + $proc == "microblaze" + } then { + set intr_id "XPAR_${intcname}_${ipname}_${intr_pin_name}_INTR" + } else { + set intr_id "XPAR_FABRIC_${ipname}_${intr_pin_name}_INTR" + } + set intr_id [string toupper $intr_id] + append testfunc_call " + { + XStatus Status; + + print(\"\\r\\n Running Interrupt Test for ${ipname}...\\r\\n\"); + + Status = SpiIntrExample(&${intcvar}, &${ipname}_Spi, \\ + ${deviceid}, \\ + ${intr_id}); + if (Status == 0) { + print(\"Spi Interrupt Test PASSED\\r\\n\"); + } + else { + print(\"Spi Interrupt Test FAILED\\r\\n\"); + } + + }" + } + } + + return $testfunc_call +} diff --git a/XilinxProcessorIPLib/drivers/spi/examples/index.html b/XilinxProcessorIPLib/drivers/spi/examples/index.html new file mode 100755 index 00000000..c849d5b7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/examples/index.html @@ -0,0 +1,27 @@ + + +
+ + +Copyright � 1995-2014 Xilinx, Inc. All rights reserved.
+ + \ No newline at end of file diff --git a/XilinxProcessorIPLib/drivers/spi/examples/xspi_atmel_flash_example.c b/XilinxProcessorIPLib/drivers/spi/examples/xspi_atmel_flash_example.c new file mode 100755 index 00000000..380b094e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/examples/xspi_atmel_flash_example.c @@ -0,0 +1,692 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/****************************************************************************** +* +* @file xspi_atmel_flash_example.c +* +* This file contains a design example using the SPI driver (XSpi) and +* hardware device with an Atmel Serial Flash Device (AT45XX series). +* This example erases the Page, writes to the Page, reads back from the Page and +* compares the data. +* +* This example works for an Atmel AT45DB161D. The bytes per page +* (ATMEL_PAGE_SIZE) in this device is 528 bytes for default addressing mode and +* 512 bytes in Power-of-2 addressing mode. +* For further details of device refer to the Atmel Datasheet of AT45DB161D +* device. +* +* The ATMEL_PAGE_SIZE constant need to be updated by the user according to the +* Device used. +* +* The ATMEL_FLASH_TEST_ADDRESS constant need to be updated by the user according +* to the serial flash device used, there is no error checking done in the +* example for the address specified by the user. +* +* This example also works with the In-System Flash(ISF) in the S3AN devices. +* The ATMEL_PAGE_SIZE and ATMEL_FLASH_TEST_ADDRESS need to be defined properly +* based on the device used. For further details of the ISF refer to the +* Spartan-3AN FPGA In-System Flash User Guide (UG333). +* +* This example assumes that the underlying processor is MicroBlaze and default +* addressing mode is used in the Flash Device. +* +* @note +* +* None. +* +*+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a sdn 02/26/08 First release +* 1.00a sdn 07/02/08 Changed the initialization so that the SPI +* Master works in Spi Mode 3 as the In-System Flash +* works only in Spi Mode 3 +* 3.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. Replaced call to +* XSpi_Initialize API with XSpi_LookupConfig and +* XSpi_CfgInitialize. +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* EDK generated parameters */ +#include "xintc.h" /* Interrupt controller device driver */ +#include "xspi.h" /* SPI device driver */ +#include "xil_exception.h" + + +/************************** Constant Definitions *****************************/ + + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define SPI_INTR_ID XPAR_INTC_0_SPI_0_VEC_ID + +/* + * The following constant defines the slave select signal that is used to + * to select the Flash device on the SPI bus, this signal is typically + * connected to the chip select of the device. + */ +#define ATMEL_SPI_SELECT 0x01 + + +/* + * Definition of the commands + */ +#define ATMEL_COMMAND_READ 0x03 /* Read command */ +#define ATMEL_COMMAND_WRITE 0x82 /* Write command */ +#define ATMEL_COMMAND_STATUSREG_READ 0xD7 /* Status Register Read command */ +#define ATMEL_COMMAND_PAGE_ERASE 0x81 /* Erase command */ + +/* + * The following definition specify the EXTRA bytes in the command + * transactions. This count includes Command byte, address bytes and any + * don't care bytes needed. + */ +#define ATMEL_READ_WRITE_EXTRA_BYTES 0x4 /* Read/Write extra bytes */ +#define ATMEL_PAGE_ERASE_BYTES 0x4 /* Page erase extra bytes */ +#define ATMEL_STATUS_READ_BYTES 0x2 /* Status read bytes count */ + +/* + * The following constants define the offsets for command and data. + * Note that the read data offset is not the same as the write data + * because the SPI driver is designed to allow full duplex transfers + * such that the number of bytes received is the number sent and received. + */ +#define ATMEL_COMMAND_OFFSET 0 +#define ATMEL_ADDRESS_BYTE1_OFFSET 1 +#define ATMEL_ADDRESS_BYTE2_OFFSET 2 +#define ATMEL_ADDRESS_BYTE3_OFFSET 3 + +/* + * The following definitions specify the status register bit definitions. + */ +#define ATMEL_FLASH_SR_IS_READY_MASK 0x80 + +#define ATMEL_PAGE_SIZE 264 /* Page Size */ + +/* + * Address of the page to perform Erase, Write and Read operations. + */ +#define ATMEL_FLASH_TEST_ADDRESS 0x259800 + +/* + * Byte offset value written to Flash. This needs to redefined for writing + * different patterns of data to the Flash device. + */ +#define ATMEL_TEST_BYTE 0x10 /* Test value written to Flash */ + + +#define ATMEL_DUMMYBYTE 0xFF +#define ATMEL_INITBYTE 0x00 + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +static int SetupInterruptSystem(XSpi *SpiPtr); +void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount); +int SpiAtmelFlashRead(XSpi *SpiPtr, u32 Address, u16 ByteCount); +int SpiAtmelFlashWrite(XSpi *SpiPtr, u32 Address, u16 ByteCount); +int SpiAtmelFlashPageErase(XSpi *SpiPtr, u32 Address); +static int SpiAtmelFlashWaitForFlashNotBusy(XSpi *SpiPtr); + +/************************** Variable Definitions *****************************/ + +/* + * The instances to support the device drivers are global such that they + * are initialized to zero each time the program runs. They could be local + * but should at least be static so they are zeroed. + */ +static XIntc InterruptController; +static XSpi Spi; + +/* + * The following variables are shared between non-interrupt processing and + * interrupt processing such that they must be global. + */ +volatile static int TransferInProgress; + +/* + * The following variable tracks any errors that occur during interrupt + * processing. + */ +int ErrorCount; + +/* + * Buffers used during read and write transactions. + */ +u8 ReadBuffer[ATMEL_PAGE_SIZE + ATMEL_READ_WRITE_EXTRA_BYTES]; +u8 WriteBuffer[ATMEL_PAGE_SIZE + ATMEL_READ_WRITE_EXTRA_BYTES]; + +/************************** Function Definitions ******************************/ + +/*****************************************************************************/ +/** +* +* Main function to execute the Atmel Flash example. +* +* @param None +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int main() +{ + int Status; + u32 Index; + u32 Address; + XSpi_Config *ConfigPtr; /* Pointer to Configuration data */ + + /* + * Initialize the SPI driver so that it is ready to use. + */ + ConfigPtr = XSpi_LookupConfig(SPI_DEVICE_ID); + if (ConfigPtr == NULL) { + return XST_DEVICE_NOT_FOUND; + } + + Status = XSpi_CfgInitialize(&Spi, ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + /* + * Connect the SPI driver to the interrupt subsystem such that + * interrupts can occur. This function is application specific. + */ + Status = SetupInterruptSystem(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the handler for the SPI that will be called from the interrupt + * context when an SPI status occurs, specify a pointer to the SPI + * driver instance as the callback reference so the handler is able to + * access the instance data. + */ + XSpi_SetStatusHandler(&Spi, &Spi, (XSpi_StatusHandler)SpiHandler); + + /* + * Set the SPI device as a master and in manual slave select mode such + * that the slave select signal does not toggle for every byte of a + * transfer, this must be done before the slave select is set. + */ + Status = XSpi_SetOptions(&Spi, XSP_MASTER_OPTION | + XSP_MANUAL_SSELECT_OPTION | + XSP_CLK_PHASE_1_OPTION | + XSP_CLK_ACTIVE_LOW_OPTION); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Select the slave on the SPI bus so that the Atmel Flash device can be + * read and written using the SPI bus. + */ + Status = XSpi_SetSlaveSelect(&Spi, ATMEL_SPI_SELECT); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the SPI driver so that interrupts and the device are enabled. + */ + XSpi_Start(&Spi); + + + /* + * Specify the address in the flash device for the Erase/Write/Read + * operations. + */ + Address = ATMEL_FLASH_TEST_ADDRESS; + + + /* + * Erase the Page. + */ + Status = SpiAtmelFlashPageErase(&Spi, Address); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the current Erase command is executed in the Flash + * and the Flash is ready for the next command. + */ + Status = SpiAtmelFlashWaitForFlashNotBusy(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Write the data to the Page. + */ + Status = SpiAtmelFlashWrite(&Spi, Address, ATMEL_PAGE_SIZE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the current Write command is executed in the Flash + * and the Flash is ready for the next command. + */ + Status = SpiAtmelFlashWaitForFlashNotBusy(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Read the data from the Page. + */ + Status = SpiAtmelFlashRead(&Spi, Address, ATMEL_PAGE_SIZE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the current Write command is executed in the Flash + * and the Flash is ready for the next command. + */ + Status = SpiAtmelFlashWaitForFlashNotBusy(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + /* + * Compare the data read with what is written. + */ + for(Index = ATMEL_READ_WRITE_EXTRA_BYTES; Index < (ATMEL_PAGE_SIZE + + ATMEL_READ_WRITE_EXTRA_BYTES); Index++) { + if(ReadBuffer[Index] != (u8)(Index + ATMEL_TEST_BYTE)) { + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function reads data from the Atmel Flash device connected to the SPI +* interface. +* +* @param SpiPtr is a pointer to the SPI driver component to use. +* @param Addr is the address from which the data is to be read from +* the Flash. +* @param ByteCount is the number of bytes to read. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int SpiAtmelFlashRead(XSpi *SpiPtr, u32 Address, u16 ByteCount) +{ + u16 Index; + + /* + * Setup the read command with the specified address and data for the + * Atmel Flash. + */ + WriteBuffer[ATMEL_COMMAND_OFFSET] = ATMEL_COMMAND_READ; + WriteBuffer[ATMEL_ADDRESS_BYTE1_OFFSET] = (u8) (Address >> 16); + WriteBuffer[ATMEL_ADDRESS_BYTE2_OFFSET] = (u8) (Address >> 8); + WriteBuffer[ATMEL_ADDRESS_BYTE3_OFFSET] = (u8) Address; + + /* + * Prepare the write buffer. Fill in some dummy data. + */ + for(Index = 4; Index < (ByteCount + ATMEL_READ_WRITE_EXTRA_BYTES); + Index++) { + WriteBuffer[Index] = ATMEL_DUMMYBYTE; + } + + /* + * Prepare the Read Buffer. Fill in some initialization data into the + * the buffer. + */ + for(Index = 0; Index < (ByteCount + + ATMEL_READ_WRITE_EXTRA_BYTES); Index++) { + ReadBuffer[Index] = ATMEL_INITBYTE; + } + + /* + * Send the read command to the Atmel Flash to read the specified number + * of bytes. + */ + TransferInProgress = TRUE; + XSpi_Transfer(SpiPtr, WriteBuffer, ReadBuffer, + ByteCount + ATMEL_READ_WRITE_EXTRA_BYTES); + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction. + */ + while (TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function writes to the Atmel Flash device connected to the SPI interface. +* +* @param SpiPtr is a pointer to the SPI driver component to use. +* @param Address is the address to which the data is written. +* @param ByteCount contains the number of bytes to write. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int SpiAtmelFlashWrite(XSpi *SpiPtr, u32 Address, u16 ByteCount) +{ + u16 Index; + + /* + * Setup the write command with the specified address, and data to be + * written to the flash. + */ + WriteBuffer[ATMEL_COMMAND_OFFSET] = ATMEL_COMMAND_WRITE; + WriteBuffer[ATMEL_ADDRESS_BYTE1_OFFSET] = (u8) (Address >> 16); + WriteBuffer[ATMEL_ADDRESS_BYTE2_OFFSET] = (u8) (Address >> 8); + WriteBuffer[ATMEL_ADDRESS_BYTE3_OFFSET] = (u8) (Address); + + /* + * Prepare the write buffer. Fill in the data that is to be written into + * the Flash. + */ + for(Index = 4; Index < (ByteCount + ATMEL_READ_WRITE_EXTRA_BYTES); + Index++) { + WriteBuffer[Index] = (u8)(ATMEL_TEST_BYTE + Index); + } + + /* + * Send the write command, address, and data to the Flash. + * No receive buffer is specified since there is nothing to receive. + */ + TransferInProgress = TRUE; + XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + ByteCount + ATMEL_READ_WRITE_EXTRA_BYTES) + ; + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction. + */ + while (TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function erases the contents of the specified Page in the Flash. +* +* @param SpiPtr is a pointer to the SPI driver component to use. +* @param Address contains the address of the page to be erased. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int SpiAtmelFlashPageErase(XSpi *SpiPtr, u32 Address) { + + /* + * Prepare the Write Buffer. + */ + WriteBuffer[ATMEL_COMMAND_OFFSET] = ATMEL_COMMAND_PAGE_ERASE; + WriteBuffer[ATMEL_ADDRESS_BYTE1_OFFSET] = (u8) (Address >> 16); + WriteBuffer[ATMEL_ADDRESS_BYTE2_OFFSET] = (u8) (Address >> 8); + WriteBuffer[ATMEL_ADDRESS_BYTE3_OFFSET] = ATMEL_DUMMYBYTE; + + /* + * Send the Erase command and address to the flash. + * No receive buffer is specified since there is nothing to + * receive. + */ + TransferInProgress = TRUE; + XSpi_Transfer(SpiPtr, WriteBuffer, NULL, ATMEL_PAGE_ERASE_BYTES); + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction. + */ + while (TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function waits till the flash is ready to accept next command. +* +* @param SpiPtr is a pointer to the SPI driver component to use. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +static int SpiAtmelFlashWaitForFlashNotBusy(XSpi *SpiPtr) +{ + u8 StatusReg; + + /* + * Prepare the Write Buffer. + */ + WriteBuffer[ATMEL_COMMAND_OFFSET] = ATMEL_COMMAND_STATUSREG_READ; + WriteBuffer[ATMEL_ADDRESS_BYTE1_OFFSET] = ATMEL_DUMMYBYTE; + + /* + * Prepare the Read Buffer. + */ + ReadBuffer[0] = ATMEL_INITBYTE; + ReadBuffer[1] = ATMEL_INITBYTE; + + while(1) { + + /* + * Transmit the data. + */ + TransferInProgress = TRUE; + XSpi_Transfer(&Spi, WriteBuffer, ReadBuffer, + ATMEL_STATUS_READ_BYTES); + + /* + * Wait for the transmission to be complete and + * check if there are any errors in the transaction. + */ + while (TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + StatusReg = ReadBuffer[1]; + + if ((StatusReg & ATMEL_FLASH_SR_IS_READY_MASK)) + break; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function is the handler which performs processing for the SPI driver. +* It is called from an interrupt context such that the amount of processing +* performed should be minimized. It is called when a transfer of SPI data +* completes or an error occurs. +* +* This handler provides an example of how to handle SPI interrupts and +* is application specific. +* +* @param CallBackRef is the upper layer callback reference passed back +* when the callback function is invoked. +* @param StatusEvent is the event that just occurred. +* @param ByteCount is the number of bytes transferred up until the event +* occurred. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount) +{ + /* + * Indicate the transfer on the SPI bus is no longer in progress + * regardless of the status event. + */ + TransferInProgress = FALSE; + + /* + * If the event was not transfer done, then track it as an error. + */ + if (StatusEvent != XST_SPI_TRANSFER_DONE) { + ErrorCount++; + } +} + +/*****************************************************************************/ +/** +* +* This function setups the interrupt system such that interrupts can occur +* for the Spi device. This function is application specific since the actual +* system may or may not have an interrupt controller. The Spi device could be +* directly connected to a processor without an interrupt controller. The +* user should modify this function to fit the application. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None +* +******************************************************************************/ +static int SetupInterruptSystem(XSpi *SpiPtr) +{ + + int Status; + + /* + * Initialize the interrupt controller driver so that + * it's ready to use, specify the device ID that is generated in + * xparameters.h + */ + Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect a device driver handler that will be called when an interrupt + * for the device occurs, the device driver handler performs the + * specific interrupt processing for the device + */ + Status = XIntc_Connect(&InterruptController, + SPI_INTR_ID, + (XInterruptHandler)XSpi_InterruptHandler, + (void *)SpiPtr); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller such that interrupts are enabled for + * all devices that cause interrupts, specific real mode so that + * the SPI can cause interrupts thru the interrupt controller. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the interrupt for the SPI. + */ + XIntc_Enable(&InterruptController, SPI_INTR_ID); + + + /* + * Initialize the exception table. + */ + Xil_ExceptionInit(); + + /* + * Register the interrupt controller handler with the exception table. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler) XIntc_InterruptHandler, + &InterruptController); + + /* + * Enable non-critical exceptions. + */ + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/spi/examples/xspi_eeprom_example.c b/XilinxProcessorIPLib/drivers/spi/examples/xspi_eeprom_example.c new file mode 100755 index 00000000..f13e7720 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/examples/xspi_eeprom_example.c @@ -0,0 +1,589 @@ +/****************************************************************************** +* +* Copyright (C) 2001 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/****************************************************************************** +* +* @file xspi_eeprom_example.c +* +* +* This file contains a design example using the SPI driver (XSpi) and +* hardware device with a serial EEPROM device. The hardware which this +* example runs on must have a serial EEPROM (Microchip 25XX320 or 25XX160) +* for it to run. This example has been tested with the SPI EEPROM on the ML410 +* platform for PPC processor. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00b jhl 02/27/01 First release +* 1.00c jhl 08/15/03 Fixed bugs (local instances and large buffers are now +* moved to globals) +* 1.11a sv 9/10/07 Minor changes to comply to Doxygen and coding guidelines +* 3.00a ktn 10/28/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. Replaced call to +* XSpi_Initialize API with XSpi_LookupConfig and +* XSpi_CfgInitialize. +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* EDK generated parameters */ +#include "xspi.h" /* SPI device driver */ +#include "xintc.h" /* Interrupt controller device driver */ +#include "xil_exception.h" + + + +/************************** Constant Definitions *****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define SPI_INTR_ID XPAR_INTC_0_SPI_0_VEC_ID + + +/* + * The following constants define the commands which may be sent to the EEPROM + * device. + */ +#define WRITE_STATUS_CMD 1 +#define WRITE_CMD 2 +#define READ_CMD 3 +#define WRITE_DISABLE_CMD 4 +#define READ_STATUS_CMD 5 +#define WRITE_ENABLE_CMD 6 + +/* + * The following constants define the offsets within a EepromBuffer data + * type for each kind of data. Note that the read data offset is not the + * same as the write data because the SPI driver is designed to allow full + * duplex transfers such that the number of bytes received is the number + * sent and received. + */ +#define COMMAND_OFFSET 0 /* EEPROM instruction */ +#define ADDRESS_MSB_OFFSET 1 /* MSB of address to read or write */ +#define ADDRESS_LSB_OFFSET 2 /* LSB of address to read or write */ +#define DATA_OFFSET 3 +#define WRITE_DATA_OFFSET 3 /* Start of data to write to the EEPROM */ +#define READ_DATA_OFFSET 6 /* Start of data read from the EEPROM */ + +/* + * The following constants specify the extra bytes which are sent to the + * EEPROM on the SPI interface, that are not data, but control information + * which includes the command and address + */ +#define OVERHEAD_SIZE 3 + +/* + * The following constants specify the page size and number of pages for the + * EEPROM. The page size specifies a max number of bytes that can be written + * to the EEPROM with a single transfer using the SPI driver. + */ +#define PAGE_SIZE 16 +#define PAGE_COUNT 128 + +/* + * The following constants specify the max amount of data and the size of the + * the buffer required to hold the data and overhead to transfer the data to + * and from the EEPROM. + */ +#define MAX_DATA PAGE_COUNT * PAGE_SIZE +#define BUFFER_SIZE MAX_DATA + READ_DATA_OFFSET + +/* + * The following constant defines the slave select signal that is used to + * to select the EEPROM device on the SPI bus, this signal is typically + * connected to the chip select of the device + */ +#define SEEPROM_SPI_SELECT 0x01 + +/**************************** Type Definitions *******************************/ + +/* + * The following data type is used to send and receive data to the serial + * EEPROM device connected to the SPI interface. It is an array of bytes + * rather than a structure for portability avoiding packing issues. The + * application must setup the data to be written in this buffer and retrieve + * the data read from it. + */ +typedef u8 EepromBuffer[BUFFER_SIZE]; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +static int SetupInterruptSystem(XSpi *SpiPtr); + +void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount); + +void EepromRead(XSpi *SpiPtr, u16 Address, int ByteCount, EepromBuffer Buffer); + +void EepromWrite(XSpi *SpiPtr, u16 Address, u8 ByteCount, EepromBuffer Buffer); + +/************************** Variable Definitions *****************************/ + +/* + * The instances to support the device drivers are global such that the + * are initialized to zero each time the program runs. They could be local + * but should at least be static so they are zeroed. + */ +XIntc InterruptController; +XSpi Spi; + +/* + * The following variables are shared between non-interrupt processing and + * interrupt processing such that they must be global. + */ +volatile int TransferInProgress; + +/* + * The following variable tracks any errors that occur during interrupt + * processing + */ +int Error; + +/* + * The following variable allows a test value to be added to the values that + * are written to the EEPROM such that unique values can be generated to + * guarantee the writes to the EEPROM were successful + */ +int Test; + +/* + * The following variables are used to read and write to the eeprom and they + * are global to avoid having large buffers on the stack + */ +EepromBuffer ReadBuffer; +EepromBuffer WriteBuffer; + +/***************************************************************************** +* +* The purpose of this function is to illustrate how to use the XSpi +* device driver. This test writes and reads data from a Microchip serial EEPROM. +* This part must be present in the hardware to use this example. +* +* @param None +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note +* +* This function calls functions which contain loops that may be infinite +* if interrupts are not working such that it may not return. If the device +* slave select is not correct and the device is not responding on bus it will +* read a status of 0xFF for the status register as the bus is pulled up. +* +*****************************************************************************/ +int main() +{ + int Status; + u8 *BufferPtr; + u8 UniqueValue; + int Count; + int Page; + XSpi_Config *ConfigPtr; /* Pointer to Configuration data */ + + /* + * Initialize the SPI driver so that it is ready to use. + */ + ConfigPtr = XSpi_LookupConfig(SPI_DEVICE_ID); + if (ConfigPtr == NULL) { + return XST_DEVICE_NOT_FOUND; + } + Status = XSpi_CfgInitialize(&Spi, ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect the SPI driver to the interrupt subsystem such that + * interrupts can occur. This function is application specific. + */ + Status = SetupInterruptSystem(&Spi); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the handler for the SPI that will be called from the interrupt + * context when an SPI status occurs, specify a pointer to the SPI + * driver instance as the callback reference so the handler is able to + * access the instance data + */ + XSpi_SetStatusHandler(&Spi, &Spi, (XSpi_StatusHandler)SpiHandler); + + /* + * Set the SPI device as a master and in manual slave select mode such + * that the slave select signal does not toggle for every byte of a + * transfer, this must be done before the slave select is set + */ + Status = XSpi_SetOptions(&Spi, XSP_MASTER_OPTION | + XSP_MANUAL_SSELECT_OPTION); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Select the slave on the SPI bus, the EEPROM device so that it can be + * read and written using the SPI bus + */ + Status = XSpi_SetSlaveSelect(&Spi, SEEPROM_SPI_SELECT); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the SPI driver so that interrupts and the device are enabled + */ + XSpi_Start(&Spi); + + /* + * Initialize the write buffer for a pattern to write to the EEPROM + * and the read buffer to zero so it can be verified after the read, the + * test value that is added to the unique value allows the value to be + * changed in a debug environment to guarantee + */ + for (UniqueValue = 10, Count = 0; Count < MAX_DATA; + Count++, UniqueValue++) { + WriteBuffer[WRITE_DATA_OFFSET + Count] = + (u8)(UniqueValue + Test); + ReadBuffer[READ_DATA_OFFSET + Count] = 0; + } + + /* + * Write the data in the write buffer to the serial EEPROM a page at a + * time + */ + for (Page = 0; Page < PAGE_COUNT; Page++) { + EepromWrite(&Spi, Page * PAGE_SIZE, PAGE_SIZE, + &WriteBuffer[Page * PAGE_SIZE]); + } + + /* + * Read the contents of the entire EEPROM from address 0, since this + * function reads the entire EEPROM it will take some amount of time to + * complete + */ + EepromRead(&Spi, 0, MAX_DATA, ReadBuffer); + + /* + * Setup a pointer to the start of the data that was read into the read + * buffer and verify the data read is the data that was written + */ + BufferPtr = &ReadBuffer[READ_DATA_OFFSET]; + + for (UniqueValue = 10, Count = 0; Count < MAX_DATA; + Count++, UniqueValue++) { + if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + +/****************************************************************************** +* +* This function is the handler which performs processing for the SPI driver. +* It is called from an interrupt context such that the amount of processing +* performed should be minimized. It is called when a transfer of SPI data +* completes or an error occurs. +* +* This handler provides an example of how to handle SPI interrupts +* but is application specific. +* +* +* @param CallBackRef is a reference passed to the handler. +* @param StatusEvent is the status of the SPI . +* @param ByteCount is the number of bytes transferred. +* +* @return None +* +* @note None. +* +******************************************************************************/ +void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount) +{ + /* + * Indicate the transfer on the SPI bus is no longer in progress + * regardless of the status event + */ + TransferInProgress = FALSE; + + /* + * If the event was not transfer done, then track it as an error + */ + if (StatusEvent != XST_SPI_TRANSFER_DONE) { + Error++; + } +} + +/****************************************************************************** +* +* This function reads from the Microchip serial EEPROM connected to the +* SPI interface. +* +* @param SpiPtr is a pointer to the SPI driver component to use. +* @param Address contains the address to read data from in the EEPROM. +* @param ByteCount contains the number of bytes to read. +* @param Buffer is a buffer to read the data into. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void EepromRead(XSpi *SpiPtr, u16 Address, int ByteCount, EepromBuffer Buffer) +{ + /* + * Setup the write command with the specified address and data for the + * EEPROM + */ + Buffer[COMMAND_OFFSET] = READ_CMD; + Buffer[ADDRESS_MSB_OFFSET] = (u8)((Address & 0xFF00) >> 8); + Buffer[ADDRESS_LSB_OFFSET] = (u8)(Address & 0x00FF); + + /* + * Send the read command to the EEPROM to read the specified number + * of bytes from the EEPROM, send the read command and address and + * receive the specified number of bytes of data in the data buffer + */ + TransferInProgress = TRUE; + + XSpi_Transfer(SpiPtr, Buffer, &Buffer[DATA_OFFSET], + ByteCount + OVERHEAD_SIZE); + + /* + * Wait for the transfer on the SPI bus to be complete before proceeding + */ + while (TransferInProgress); +} + +/****************************************************************************** +* +* +* This function writes to the Microchip serial EEPROM connected to the +* SPI interface. This function is not designed to be a driver to handle all +* the conditions of the EEPROM device. The EEPROM contains a 32 byte write +* buffer which can be filled and then a write is automatically performed by +* the device. All the data put into the buffer must be in the same page of +* the device with page boundaries being on 32 byte boundaries. +* +* @param SpiPtr is a pointer to the SPI driver component to use. +* @param Address contains the address to write data to in the EEPROM. +* @param ByteCount contains the number of bytes to write. +* @param Buffer is a buffer of data to write from. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void EepromWrite(XSpi *SpiPtr, u16 Address, u8 ByteCount, EepromBuffer Buffer) +{ + u8 WriteEnableCmd = { WRITE_ENABLE_CMD }; + u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 }; /* must send 2 bytes */ + u8 EepromStatus[2]; + int DelayCount = 0; + + /* + * Send the write enable command to the SEEPOM so that it can be + * written to, this needs to be sent as a seperate transfer before + * the write + */ + TransferInProgress = TRUE; + + XSpi_Transfer(SpiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); + + /* + * Wait for the transfer on the SPI bus to be complete before proceeding + */ + while (TransferInProgress); + + /* + * Setup the write command with the specified address and data for the + * EEPROM + */ + Buffer[COMMAND_OFFSET] = WRITE_CMD; + Buffer[ADDRESS_MSB_OFFSET] = (u8)((Address & 0xFF00) >> 8); + Buffer[ADDRESS_LSB_OFFSET] = (u8)(Address & 0x00FF); + + /* + * Send the write command, address, and data to the EEPROM to be + * written, no receive buffer is specified since there is nothing to + * receive + */ + TransferInProgress = TRUE; + + XSpi_Transfer(SpiPtr, Buffer, NULL, ByteCount + OVERHEAD_SIZE); + + while (TransferInProgress); + + /* + * Wait for a bit of time to allow the programming to occur as reading + * the status while programming causes it to fail because of noisy power + * on the board containing the EEPROM, this loop does not need to be + * very long but is longer to hopefully work for a faster processor + */ + while (DelayCount++ < 10000) { + } + + /* + * Wait for the write command to the EEPROM to be completed, it takes + * some time for the data to be written + */ + while (1) { + /* + * Poll the status register of the device to determine when it + * completes by sending a read status command and receiving the + * status byte + */ + TransferInProgress = TRUE; + + XSpi_Transfer(SpiPtr, ReadStatusCmd, EepromStatus, + sizeof(ReadStatusCmd)); + + /* + * Wait for the transfer on the SPI bus to be complete before + * proceeding + */ + while (TransferInProgress); + + /* + * If the status indicates the write is done, the stop waiting, + * if a value of 0xFF in the status byte is read from the + * device and this loop never exits, the device slave select is + * possibly incorrect such that the device status is not being + * read + */ + if ((EepromStatus[1] & 0x03) == 0) { + break; + } + } +} + +/**************************************************************************** +* +* +* This function setups the interrupt system such that interrupts can occur +* for the SPI driver. This function is application specific since the actual +* system may or may not have an interrupt controller. The SPI device could +* be directly connected to a processor without an interrupt controller. The +* user should modify this function to fit the application. +* +* @param SpiPtr contains a pointer to the instance of the XSpi component +* which is going to be connected to the interrupt controller. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +****************************************************************************/ +static int SetupInterruptSystem(XSpi *SpiPtr) +{ + + int Status; + + + /* + * Initialize the interrupt controller driver so that + * it's ready to use, specify the device ID that is generated in + * xparameters.h + */ + Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + /* + * Connect a device driver handler that will be called when an interrupt + * for the device occurs, the device driver handler performs the + * specific interrupt processing for the device + */ + Status = XIntc_Connect(&InterruptController, + SPI_INTR_ID, + (XInterruptHandler)XSpi_InterruptHandler, + (void *)SpiPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + /* + * Start the interrupt controller such that interrupts are enabled for + * all devices that cause interrupts, specific real mode so that + * the SPI can cause interrupts thru the interrupt controller. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the interrupt for the Spi device + */ + XIntc_Enable(&InterruptController, SPI_INTR_ID); + + + /* + * Initialize the exception table + */ + Xil_ExceptionInit(); + + /* + * Register the interrupt controller handler with the exception table + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)XIntc_InterruptHandler, + &InterruptController); + + /* + * Enable non-critical exceptions + */ + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} + diff --git a/XilinxProcessorIPLib/drivers/spi/examples/xspi_intel_flash_example.c b/XilinxProcessorIPLib/drivers/spi/examples/xspi_intel_flash_example.c new file mode 100755 index 00000000..740aba02 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/examples/xspi_intel_flash_example.c @@ -0,0 +1,911 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/****************************************************************************** +* +* @file xspi_intel_flash_example.c +* +* This file contains a design example using the SPI driver (XSpi) and hardware +* device with an Intel Serial Flash Memory (S33) in the interrupt mode. +* This example erases a sector, writes to a Page within the sector, reads back +* from that Page and compares the data. +* +* The example works with an Intel Serial Flash Memory (S33). The number of bytes +* per page in this device is 256. For further details about the device refer to +* the Intel Serial Flash Memory (S33) Data sheet +* +* This example assumes that the underlying processor is MicroBlaze. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a sd 02/26/08 First release +* 3.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. Replaced call to +* XSpi_Initialize API with XSpi_LookupConfig and +* XSpi_CfgInitialize. +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* EDK generated parameters */ +#include "xintc.h" /* Interrupt controller device driver */ +#include "xspi.h" /* SPI device driver */ +#include "xil_exception.h" + + +/************************** Constant Definitions *****************************/ + + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define SPI_INTR_ID XPAR_INTC_0_SPI_0_VEC_ID + +/* + * The following constant defines the slave select signal that is used to + * to select the Flash device on the SPI bus, this signal is typically + * connected to the chip select of the device. + */ +#define INTEL_SPI_SELECT 0x01 + + +/* + * Definitions of the commands shown in this example. + */ +#define INTEL_COMMAND_RANDOM_READ 0x03 /* Random read command */ +#define INTEL_COMMAND_PAGEPROGRAM_WRITE 0x02 /* Page Program command */ +#define INTEL_COMMAND_WRITE_ENABLE 0x06 /* Write Enable command */ +#define INTEL_COMMAND_SECTOR_ERASE 0xD8 /* Sector Erase command */ +#define INTEL_COMMAND_BULK_ERASE 0xC7 /* Bulk Erase command */ +#define INTEL_COMMAND_STATUSREG_READ 0x05 /* Status read command */ +#define INTEL_COMMAND_STATUSREG_WRITE 0x01 /* Status write command */ + +/* + * This definitions specify the EXTRA bytes for each of the command + * transactions. This count includes command byte, address bytes and any + * don't care bytes needed. + */ +#define INTEL_READ_WRITE_EXTRA_BYTES 4 /* Read/Write extra bytes */ +#define INTEL_WRITE_ENABLE_BYTES 1 /* Write Enable bytes */ +#define INTEL_SECTOR_ERASE_BYTES 4 /* Sector erase extra bytes */ +#define INTEL_BULK_ERASE_BYTES 1 /* Bulk erase extra bytes */ +#define INTEL_STATUS_READ_BYTES 2 /* Status read bytes count */ +#define INTEL_STATUS_WRITE_BYTES 2 /* Status write bytes count */ + +/* + * Flash not busy mask in the status register of the flash device. + */ +#define INTEL_FLASH_SR_IS_READY_MASK 0x01 /* Ready mask */ + +/* + * Sector protection disable mask in the status register for all the sectors of + * the flash device. + */ +#define INTEL_DISABLE_PROTECTION_ALL 0x00 + +/* + * Number of bytes per page in the flash device. + */ +#define INTEL_FLASH_PAGE_SIZE 256 + + +/* + * Address of the page to perform Erase, Write and Read operations. + */ +#define INTEL_FLASH_TEST_ADDRESS 0x00 + +/* + * Byte offset value written to Flash. This needs to redefined for writing + * different patterns of data to the Flash device. + */ +#define INTEL_FLASH_TEST_BYTE 0x20 + +/* + * Byte Positions. + */ +#define BYTE1 0 /* Byte 1 position */ +#define BYTE2 1 /* Byte 2 position */ +#define BYTE3 2 /* Byte 3 position */ +#define BYTE4 3 /* Byte 4 position */ +#define BYTE5 4 /* Byte 5 position */ + +#define INTEL_DUMMYBYTE 0xFF /* Dummy byte */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int SpiIntelFlashWriteEnable(XSpi *SpiPtr); +int SpiIntelFlashWrite(XSpi *SpiPtr, u32 Addr, u32 ByteCount); +int SpiIntelFlashRead(XSpi *SpiPtr, u32 Addr, u32 ByteCount); +int SpiIntelFlashBulkErase(XSpi *SpiPtr); +int SpiIntelFlashSectorErase(XSpi *SpiPtr, u32 Addr); +int SpiIntelFlashGetStatus(XSpi *SpiPtr); +int SpiIntelFlashWriteStatus(XSpi *SpiPtr, u8 StatusRegister); +static int SpiIntelFlashWaitForFlashNotBusy(void); +void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount); +static int SetupInterruptSystem(XSpi *SpiPtr); + +/************************** Variable Definitions *****************************/ + +/* + * The instances to support the device drivers are global such that they + * are initialized to zero each time the program runs. They could be local + * but should at least be static so they are zeroed. + */ +static XIntc InterruptController; +static XSpi Spi; + +/* + * The following variables are shared between non-interrupt processing and + * interrupt processing such that they must be global. + */ +volatile static int TransferInProgress; + +/* + * The following variable tracks any errors that occur during interrupt + * processing. + */ +int ErrorCount; + +/* + * Buffers used during read and write transactions. + */ +u8 ReadBuffer[INTEL_FLASH_PAGE_SIZE + INTEL_READ_WRITE_EXTRA_BYTES]; +u8 WriteBuffer[INTEL_FLASH_PAGE_SIZE + INTEL_READ_WRITE_EXTRA_BYTES]; + +/************************** Function Definitions ******************************/ + +/*****************************************************************************/ +/** +* +* Main function to execute the Flash example. +* +* @param None +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int main() +{ + int Status; + u32 Index; + u32 Address; + XSpi_Config *ConfigPtr; /* Pointer to Configuration data */ + + /* + * Initialize the SPI driver so that it is ready to use. + */ + ConfigPtr = XSpi_LookupConfig(SPI_DEVICE_ID); + if (ConfigPtr == NULL) { + return XST_DEVICE_NOT_FOUND; + } + + Status = XSpi_CfgInitialize(&Spi, ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect the SPI driver to the interrupt subsystem such that + * interrupts can occur. This function is application specific. + */ + Status = SetupInterruptSystem(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the handler for the SPI that will be called from the interrupt + * context when an SPI status occurs, specify a pointer to the SPI + * driver instance as the callback reference so the handler is able to + * access the instance data. + */ + XSpi_SetStatusHandler(&Spi, &Spi, (XSpi_StatusHandler)SpiHandler); + + /* + * Set the SPI device as a master and in manual slave select mode such + * that the slave select signal does not toggle for every byte of a + * transfer, this must be done before the slave select is set. + */ + Status = XSpi_SetOptions(&Spi, XSP_MASTER_OPTION | + XSP_MANUAL_SSELECT_OPTION); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Select the Intel Serial Flash device, so that it can be + * read and written using the SPI bus. + */ + Status = XSpi_SetSlaveSelect(&Spi, INTEL_SPI_SELECT); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the SPI driver so that interrupts and the device are enabled. + */ + XSpi_Start(&Spi); + + /* + * Perform the Write Enable operation. + */ + Status = SpiIntelFlashWriteEnable(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Flash is not Busy. + */ + Status = SpiIntelFlashWaitForFlashNotBusy(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Disable the sector protection + */ + Status = SpiIntelFlashWriteStatus(&Spi, INTEL_DISABLE_PROTECTION_ALL); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Flash is not Busy. + */ + Status = SpiIntelFlashWaitForFlashNotBusy(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Specify the address in the flash device for the Erase/Write/Read + * operations. + */ + Address = INTEL_FLASH_TEST_ADDRESS; + + /* + * Perform the Write Enable operation. + */ + Status = SpiIntelFlashWriteEnable(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Flash is not Busy. + */ + Status = SpiIntelFlashWaitForFlashNotBusy(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Perform the Sector Erase operation. + */ + Status = SpiIntelFlashSectorErase(&Spi, Address); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Flash is not Busy. + */ + Status = SpiIntelFlashWaitForFlashNotBusy(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Perform the Write Enable operation. + */ + Status = SpiIntelFlashWriteEnable(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Flash is not Busy. + */ + Status = SpiIntelFlashWaitForFlashNotBusy(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Write the data to the Page. + * Perform the Write operation. + */ + Status = SpiIntelFlashWrite(&Spi, Address, INTEL_FLASH_PAGE_SIZE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Flash is not Busy. + */ + Status = SpiIntelFlashWaitForFlashNotBusy(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + /* + * Clear the read Buffer. + */ + for(Index = 0; Index < INTEL_FLASH_PAGE_SIZE + + INTEL_READ_WRITE_EXTRA_BYTES; Index++) { + ReadBuffer[Index] = 0x0; + } + + /* + * Read the data from the Page. + */ + Status = SpiIntelFlashRead(&Spi, Address, INTEL_FLASH_PAGE_SIZE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + /* + * Compare the data read against the data that was Written. + */ + for(Index = 0; Index < INTEL_FLASH_PAGE_SIZE; Index++) { + if(ReadBuffer[Index + INTEL_READ_WRITE_EXTRA_BYTES] != + (u8)(Index + INTEL_FLASH_TEST_BYTE)) { + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function enables writes to the Intel Serial Flash memory. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int SpiIntelFlashWriteEnable(XSpi *SpiPtr) +{ + int Status; + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = INTEL_COMMAND_WRITE_ENABLE; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + INTEL_WRITE_ENABLE_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function writes the data to the specified locations in the Intel Serial +* Flash memory. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* @param Addr is the address in the Buffer, where to write the data. +* @param ByteCount is the number of bytes to be written. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note A minimum of one byte and a maximum of one Page can be written +* using this API. +* +******************************************************************************/ +int SpiIntelFlashWrite(XSpi *SpiPtr, u32 Addr, u32 ByteCount) +{ + u32 Index; + int Status; + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = INTEL_COMMAND_PAGEPROGRAM_WRITE; + WriteBuffer[BYTE2] = (u8) (Addr >> 16); + WriteBuffer[BYTE3] = (u8) (Addr >> 8); + WriteBuffer[BYTE4] = (u8) Addr; + + + /* + * Fill in the TEST data that is to be written into the STM Serial Flash + * device. + */ + for(Index = 4; Index < ByteCount + INTEL_READ_WRITE_EXTRA_BYTES; + Index++) { + WriteBuffer[Index] = (u8)((Index - 4) + INTEL_FLASH_TEST_BYTE); + } + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + (ByteCount + INTEL_READ_WRITE_EXTRA_BYTES)); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function reads the data from the Intel Serial Flash Memory +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* @param Addr is the starting address in the Flash Memory from which the +* data is to be read. +* @param ByteCount is the number of bytes to be read. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int SpiIntelFlashRead(XSpi *SpiPtr, u32 Addr, u32 ByteCount) +{ + int Status; + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = INTEL_COMMAND_RANDOM_READ; + WriteBuffer[BYTE2] = (u8) (Addr >> 16); + WriteBuffer[BYTE3] = (u8) (Addr >> 8); + WriteBuffer[BYTE4] = (u8) Addr; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer( SpiPtr, WriteBuffer, ReadBuffer, + (ByteCount + INTEL_READ_WRITE_EXTRA_BYTES)); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function erases the entire contents of the Intel Serial Flash. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note The erased bytes will read as 0xFF. +* +******************************************************************************/ +int SpiIntelFlashBulkErase(XSpi *SpiPtr) +{ + int Status; + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = INTEL_COMMAND_BULK_ERASE; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + INTEL_BULK_ERASE_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function erases the contents of the specified Sector in the Intel Serial +* Flash. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* @param Addr is the address within a sector of the Buffer, which is to +* be erased. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note The erased bytes will read as 0xFF. +* +******************************************************************************/ +int SpiIntelFlashSectorErase(XSpi *SpiPtr, u32 Addr) +{ + int Status; + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = INTEL_COMMAND_SECTOR_ERASE; + WriteBuffer[BYTE2] = (u8) (Addr >> 16); + WriteBuffer[BYTE3] = (u8) (Addr >> 8); + WriteBuffer[BYTE4] = (u8) (Addr); + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + INTEL_SECTOR_ERASE_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function reads the Status register of the Intel Serial Flash. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note The status register content is stored at the second byte pointed +* by the ReadBuffer. +* +******************************************************************************/ +int SpiIntelFlashGetStatus(XSpi *SpiPtr) +{ + int Status; + + /* + * Prepare the Write Buffer. + */ + WriteBuffer[BYTE1] = INTEL_COMMAND_STATUSREG_READ; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, ReadBuffer, + INTEL_STATUS_READ_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function writes to the Status register of the Intel Flash. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* @param StatusRegister is the value to be written to the status register +* of the flash device. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note The status register content is stored at the second byte pointed +* by the ReadPtr. +* +******************************************************************************/ +int SpiIntelFlashWriteStatus(XSpi *SpiPtr, u8 StatusRegister) +{ + int Status; + + /* + * Prepare the Write Buffer. + */ + WriteBuffer[BYTE1] = INTEL_COMMAND_STATUSREG_WRITE; + WriteBuffer[BYTE2] = StatusRegister; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + INTEL_STATUS_WRITE_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function waits till the Intel Serial Flash is ready to accept next +* command. +* +* @param None +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note This function reads the status register of the Buffer and waits +*. till the WIP bit of the status register becomes 0. +* +******************************************************************************/ +int SpiIntelFlashWaitForFlashNotBusy(void) +{ + int Status; + u8 StatusReg; + + while(1) { + + /* + * Get the Status Register. + */ + Status = SpiIntelFlashGetStatus(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Check if the flash is ready to accept the next command. + * If so break. + */ + StatusReg = ReadBuffer[1]; + if((StatusReg & INTEL_FLASH_SR_IS_READY_MASK) == 0) { + break; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function is the handler which performs processing for the SPI driver. +* It is called from an interrupt context such that the amount of processing +* performed should be minimized. It is called when a transfer of SPI data +* completes or an error occurs. +* +* This handler provides an example of how to handle SPI interrupts and +* is application specific. +* +* @param CallBackRef is the upper layer callback reference passed back +* when the callback function is invoked. +* @param StatusEvent is the event that just occurred. +* @param ByteCount is the number of bytes transferred up until the event +* occurred. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount) +{ + /* + * Indicate the transfer on the SPI bus is no longer in progress + * regardless of the status event. + */ + TransferInProgress = FALSE; + + /* + * If the event was not transfer done, then track it as an error. + */ + if (StatusEvent != XST_SPI_TRANSFER_DONE) { + ErrorCount++; + } +} + +/*****************************************************************************/ +/** +* +* This function setups the interrupt system such that interrupts can occur +* for the Spi device. This function is application specific since the actual +* system may or may not have an interrupt controller. The Spi device could be +* directly connected to a processor without an interrupt controller. The +* user should modify this function to fit the application. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None +* +******************************************************************************/ +static int SetupInterruptSystem(XSpi *SpiPtr) +{ + + int Status; + + /* + * Initialize the interrupt controller driver so that + * it's ready to use, specify the device ID that is generated in + * xparameters.h + */ + Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect a device driver handler that will be called when an interrupt + * for the device occurs, the device driver handler performs the + * specific interrupt processing for the device + */ + Status = XIntc_Connect(&InterruptController, + SPI_INTR_ID, + (XInterruptHandler)XSpi_InterruptHandler, + (void *)SpiPtr); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller such that interrupts are enabled for + * all devices that cause interrupts, specific real mode so that + * the SPI can cause interrupts thru the interrupt controller. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the interrupt for the SPI. + */ + XIntc_Enable(&InterruptController, SPI_INTR_ID); + + + /* + * Initialize the exception table + */ + Xil_ExceptionInit(); + + /* + * Register the interrupt controller handler with the exception table + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)XIntc_InterruptHandler, + &InterruptController); + + /* + * Enable non-critical exceptions + */ + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} + diff --git a/XilinxProcessorIPLib/drivers/spi/examples/xspi_intr_example.c b/XilinxProcessorIPLib/drivers/spi/examples/xspi_intr_example.c new file mode 100755 index 00000000..426e4bab --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/examples/xspi_intr_example.c @@ -0,0 +1,522 @@ +/****************************************************************************** +* +* Copyright (C) 2006 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* @file xspi_intr_example.c +* +* +* This file contains a design example using the Spi driver (XSpi) and the Spi +* device using the interrupt mode. +* +* This example works with a PPC/MicroBlaze processor. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- --------------------------------------------------------- +* 1.01a sv 05/29/06 First release for Test App Integration +* for Interrupt examples +* 1.11a sdm 03/03/08 Minor changes to comply to Doxygen and coding guidelines +* 3.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. Replaced call to +* XSpi_Initialize API with XSpi_LookupConfig and +* XSpi_CfgInitialize. +* 3.02a sdm 05/04/11 Updated to run the loopback test only in standard spi +* mode. +*+******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* XPAR parameters */ +#include "xspi.h" /* SPI device driver */ +#include "xil_exception.h" + +#ifdef XPAR_INTC_0_DEVICE_ID + #include "xintc.h" +#else + #include "xscugic.h" +#endif + +/************************** Constant Definitions *****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#ifndef TESTAPP_GEN +#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define SPI_IRPT_INTR XPAR_INTC_0_SPI_0_VEC_ID +#endif + +#ifdef XPAR_INTC_0_DEVICE_ID + #define INTC XIntc + #define INTC_HANDLER XIntc_InterruptHandler +#else + #define INTC XScuGic + #define INTC_HANDLER XScuGic_InterruptHandler +#endif + +/* + * This is the size of the buffer to be transmitted/received in this example. + */ +#define BUFFER_SIZE 12 + + +/**************************** Type Definitions *******************************/ + +/* + * The following data type is used to send and receive data on the SPI + * interface. + */ +typedef u8 DataBuffer[BUFFER_SIZE]; + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +int SpiIntrExample(INTC *IntcInstancePtr, XSpi *SpiInstancePtr, + u16 SpiDeviceId, u16 + SpiIntrId); + +void SpiIntrHandler(void *CallBackRef, u32 StatusEvent, u32 ByteCount); + +static int SpiSetupIntrSystem(INTC *IntcInstancePtr, XSpi *SpiInstancePtr, + u16 SpiIntrId); + +static void SpiDisableIntrSystem(INTC *IntcInstancePtr, u16 SpiIntrId); + +/************************** Variable Definitions *****************************/ + +/* + * The instances to support the device drivers are global such that the + * are initialized to zero each time the program runs. + */ +#ifndef TESTAPP_GEN +static INTC Intc; /* The instance of the Interrupt Controller */ +static XSpi SpiInstance; /* The instance of the SPI device */ +#endif + +/* + * The following variables are shared between non-interrupt processing and + * interrupt processing such that they must be global. + */ +volatile int TransferInProgress; + +/* + * The following variable tracks any errors that occur during interrupt + * processing + */ +int Error; + +/* + * The following variables are used to read and write to the Spi device, they + * are global to avoid having large buffers on the stack. + */ +u8 ReadBuffer[BUFFER_SIZE]; +u8 WriteBuffer[BUFFER_SIZE]; + + +/*****************************************************************************/ +/** +* +* Main function to call the Spi interrupt example. +* +* @param None +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None +* +******************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + + /* + * Run the Spi Interrupt example. + */ + Status = SpiIntrExample(&IntcInstance, + &SpiInstance, + SPI_DEVICE_ID, + SPI_IRPT_INTR); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} +#endif + +/*****************************************************************************/ +/** +* +* This function does a minimal test on the Spi device and driver as a +* design example. The purpose of this function is to illustrate how to use +* the XSpi component using the interrupt mode. +* +* This function sends data and expects to receive the same data. +* +* +* @param IntcInstancePtr is a pointer to the instance of the INTC +* component. +* @param SpiInstancePtr is a pointer to the instance of Spi component. +* @param SpiDeviceId is the Device ID of the Spi Device and is the +* XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ---------------------------------------------------------- +* 1.00b rpm 04/24/02 First release +* 1.00b jhl 09/10/02 Added code to ensure it works with a fast processor. +* 1.00b sv 05/16/05 Minor changes to comply to Doxygen and coding guidelines +* 3.00a ktn 10/28/09 Converted all register accesses to 32 bit access. +* 3.02a sdm 05/04/11 Added a note about dual/quad modes in axi_qspi. +* +*+*******************************************************************************/ + +/***************************** Include Files **********************************/ + +#include "xparameters.h" +#include "xstatus.h" +#include "xspi_l.h" + +/************************** Constant Definitions ******************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define SPI_BASEADDR XPAR_SPI_0_BASEADDR + +/**************************** Type Definitions ********************************/ + + +/***************** Macros (Inline Functions) Definitions **********************/ + + +/************************** Function Prototypes *******************************/ + +int XSpi_LowLevelExample(u32 BaseAddress); + +/************************** Variable Definitions ******************************/ + + +/* + * This is the size of the buffer to be transmitted/received in this example. + */ +#define BUFFER_SIZE 32 + +/* + * The buffer used for Transmission/Reception of the SPI test data + */ +u16 Buffer[BUFFER_SIZE]; + +/******************************************************************************/ +/** +* This function is the main function of the SPI Low Level example. +* +* @param None +* +* @return XST_SUCCESS to indicate success, else XST_FAILURE to indicate +* Failure. +* +* @note None +* +*******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the example, specify the Base Address that is generated in + * xparameters.h + */ + Status = XSpi_LowLevelExample(SPI_BASEADDR); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/******************************************************************************/ +/** +* +* This function does a simple loopback test within an SPI device. +* +* @param BaseAddress is the BaseAddress of the SPI device +* +* @return XST_SUCCESS if successful, XST_FAILURE if unsuccessful +* +* @note None +* +*******************************************************************************/ +int XSpi_LowLevelExample(u32 BaseAddress) +{ + u32 Control; + int NumBytesSent = 0; + int NumBytesRcvd = 0; + u32 Count; + + /* + * Set up the device in loopback mode and enable master mode. + */ + Control = XSpi_ReadReg(BaseAddress, XSP_CR_OFFSET); + Control |= (XSP_CR_LOOPBACK_MASK | XSP_CR_MASTER_MODE_MASK); + XSpi_WriteReg(BaseAddress, XSP_CR_OFFSET, Control); + + + /* + * Initialize the buffer with some data. + */ + for (Count = 0; Count < BUFFER_SIZE; Count++) { + Buffer[Count] = Count; + } + + /* + * Fill up the transmitter with data, assuming the receiver can hold + * the same amount of data. + */ + while ((XSpi_ReadReg(BaseAddress, XSP_SR_OFFSET) & + XSP_SR_TX_FULL_MASK) == 0) { + XSpi_WriteReg((BaseAddress), XSP_DTR_OFFSET, + Buffer[NumBytesSent++]); + } + + /* + * Enable the device. + */ + Control = XSpi_ReadReg(BaseAddress, XSP_CR_OFFSET); + Control |= XSP_CR_ENABLE_MASK; + Control &= ~XSP_CR_TRANS_INHIBIT_MASK; + XSpi_WriteReg(BaseAddress, XSP_CR_OFFSET, Control); + + /* + * Initialize the buffer with zeroes so that it can be used to receive + * data. + */ + for (Count = 0; Count < BUFFER_SIZE; Count++) { + Buffer[Count] = 0x0; + } + + /* + * Wait for the transmit FIFO to transition to empty before checking + * the receive FIFO, this prevents a fast processor from seeing the + * receive FIFO as empty + */ + while (!(XSpi_ReadReg(BaseAddress, XSP_SR_OFFSET) & + XSP_SR_TX_EMPTY_MASK)); + + /* + * Transmitter is full, now receive the data just looped back until + * the receiver is empty. + */ + while ((XSpi_ReadReg(BaseAddress, XSP_SR_OFFSET) & + XSP_SR_RX_EMPTY_MASK) == 0) { + Buffer[NumBytesRcvd++] = XSpi_ReadReg((BaseAddress), + XSP_DRR_OFFSET); + } + + /* + * If no data was sent or the data that was sent was not received, + * then return an error + */ + if ((NumBytesSent != NumBytesRcvd) || (NumBytesSent == 0)) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/spi/examples/xspi_numonyx_flash_quad_example.c b/XilinxProcessorIPLib/drivers/spi/examples/xspi_numonyx_flash_quad_example.c new file mode 100755 index 00000000..f364c98e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/examples/xspi_numonyx_flash_quad_example.c @@ -0,0 +1,1085 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/****************************************************************************** +* +* @file xspi_numonyx_flash_quad_example.c +* +* This file contains a design example using the SPI driver (XSpi) and axi_qspi +* device with a Numonyx quad serial flash device in the interrupt mode. +* This example erases a Sector, writes to a Page within the Sector, reads back +* from that Page and compares the data. +* +* This example has been tested with an N25Q128 device on KC705 and ZC770 +* board. The bytes per page (PAGE_SIZE) in N25Q128 is 256. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a bss 08/08/12 First release +* 3.04a bss 02/11/13 Modified to use ScuGic in case of Zynq (CR#683510) +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* EDK generated parameters */ +#include "xspi.h" /* SPI device driver */ +#include "xil_exception.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +#include "xintc.h" +#include
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- --------------------------------------------------------- +* 1.00a sdm 03/03/08 First Release +* 3.00a ktn 10/28/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. Replaced call to +* XSpi_Initialize API with XSpi_LookupConfig and +* XSpi_CfgInitialize. +* 3.02a sdm 05/04/11 Updated to run the loopback test only in standard spi +* mode. +*+******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* XPAR parameters */ +#include "xspi.h" /* SPI device driver */ +#include "xspi_l.h" + +/************************** Constant Definitions *****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID + +/* + * This is the size of the buffer to be transmitted/received in this example. + */ +#define BUFFER_SIZE 12 + + +/**************************** Type Definitions *******************************/ + +/* + * The following data type is used to send and receive data on the SPI + * interface. + */ +typedef u8 DataBuffer[BUFFER_SIZE]; + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +int SpiPolledExample(XSpi *SpiInstancePtr, u16 SpiDeviceId); + +/************************** Variable Definitions *****************************/ + +/* + * The instances to support the device drivers are global such that the + * are initialized to zero each time the program runs. + */ +static XSpi SpiInstance; /* The instance of the SPI device */ + +/* + * The following variables are used to read and write to the Spi device, they + * are global to avoid having large buffers on the stack. + */ +u8 ReadBuffer[BUFFER_SIZE]; +u8 WriteBuffer[BUFFER_SIZE]; + + +/*****************************************************************************/ +/** +* +* Main function to call the Spi Polled example. +* +* @param None +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the Spi Polled example. + */ + Status = SpiPolledExample(&SpiInstance, SPI_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function does a minimal test on the Spi device and driver as a +* design example. The purpose of this function is to illustrate how to use +* the XSpi component using the polled mode. +* +* This function sends data and expects to receive the same data. +* +* +* @param SpiInstancePtr is a pointer to the instance of Spi component. +* @param SpiDeviceId is the Device ID of the Spi Device and is the +* XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a sv 05/16/05 Initial release for TestApp integration. +* 1.11a sdm 03/03/08 Minor changes to comply to coding guidelines +* 3.00a ktn 10/28/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. Replaced call to +* XSpi_Initialize API with XSpi_LookupConfig and +* XSpi_CfgInitialize. +*+* +*******************************************************************************/ + +/***************************** Include Files **********************************/ + +#include "xparameters.h" +#include "xspi.h" +#include "xspi_l.h" + + +/************************** Constant Definitions ******************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID + +/**************************** Type Definitions ********************************/ + + +/***************** Macros (Inline Functions) Definitions **********************/ + + +/************************** Function Prototypes *******************************/ + +int SpiSelfTestExample(u16 DeviceId); + +/************************** Variable Definitions ******************************/ + +XSpi Spi; /* The instance of the SPI device */ + + +/******************************************************************************/ +/** +* Main function to call the example. This function is not included if the +* example is generated from the TestAppGen test tool. +* +* @param None +* +* @return XST_SUCCESS if successful, XST_FAILURE if unsuccessful +* +* @note None +* +*******************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + + /* + * Call the example , specify the device ID that is generated in + * xparameters.h + */ + Status = SpiSelfTestExample(SPI_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} +#endif + + +/*****************************************************************************/ +/** +* +* This function does a selftest and loopback test on the SPI device and +* XSpi driver as an example. The purpose of this function is to illustrate +* how to use the XSpi component. +* +* +* @param DeviceId is the XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- --------------------------------------------------------- +* 1.00a psk 09/05/08 First Release +* 3.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. Replaced call to +* XSpi_Initialize API with XSpi_LookupConfig and +* XSpi_CfgInitialize. +* 3.01a sdm 04/23/10 Enabled DTR Half_empty interrupt so that Tx FIFO is +* not empty during a transfer in slave mode. +* +*+******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* XPAR parameters */ +#include "xspi.h" /* SPI device driver */ +#include "xintc.h" /* Interrupt controller devive driver */ +#include "stdio.h" +#include "xil_exception.h" + +/************************** Constant Definitions *****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define SPI_IRPT_INTR XPAR_INTC_0_SPI_0_VEC_ID + +/* + * This is the size of the buffer to be transmitted/received in this example. + */ +#define BUFFER_SIZE 32 + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +static int SpiSlaveIntrExample(XSpi *SpiInstancePtr, u16 SpiDeviceId); + +static int SetupInterruptSystem(XSpi *SpiInstance); + +static void SpiHandler(void *CallBackRef, u32 StatusEvent, + unsigned int ByteCount); + +/************************** Variable Definitions *****************************/ +/* + * The instances to support the device drivers are global such that they are + * initialized to zero each time the program runs. They could be local but + * should at least be static so that they are zeroed. + */ +static XSpi SpiInstance; /* Instance of the SPI device */ +static XIntc IntcInstance; /* Instance of the Interrupt controller device */ + +/* + * The following variables are used to read/write from the Spi device, these + * are global to avoid having large buffers on the stack. + */ +u8 ReadBuffer[BUFFER_SIZE]; +u8 WriteBuffer[BUFFER_SIZE]; + +/* + * The following variable allows a test value to be added to the values that + * are sent in reflection to the Master transmission such that unique values can + * be generated to guarantee the transfer from Slave to Master is successful. + */ +int Test; + +/* + * The following variables are shared between non-interrupt processing and + * interrupt processing such that they must be global. + */ +static volatile int TransferInProgress; + +/*****************************************************************************/ +/** +* +* Main function to call the Spi Slave example in interrupt mode. +* +* @param None +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the Spi Slave interrupt example. + */ + Status = SpiSlaveIntrExample(&SpiInstance, SPI_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function does a minimal test on the Spi device and driver as a design +* example. The purpose of this function is to illustrate the device slave +* functionality in interrupt mode. This function receives data from a master and +* prints the received data. +* +* @param SpiInstancePtr is a pointer to the instance of Spi component. +* @param SpiDeviceId is the Device ID of the Spi Device and is the +* XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- --------------------------------------------------------- +* 1.00a psk 09/05/08 First Release +* 3.00a ktn 10/28/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. Replaced call to +* XSpi_Initialize API with XSpi_LookupConfig and +* XSpi_CfgInitialize. +* +*+******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* XPAR parameters */ +#include "xspi.h" /* SPI device driver */ +#include "stdio.h" + +/************************** Constant Definitions *****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID + +/* + * This is the size of the buffer to be transmitted/received in this example. + */ +#define BUFFER_SIZE 16 + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +static int SpiSlavePolledExample(XSpi *SpiInstancePtr, u16 SpiDeviceId); + +/************************** Variable Definitions *****************************/ + +/* + * The instances to support the device drivers are global such that they are + * initialized to zero each time the program runs. They could be local but + * should at least be static so that they are zeroed. + */ +static XSpi SpiInstance; /* The instance of the SPI device */ + +/* + * The following variables are used to read from the Spi device, these are + * global to avoid having large buffers on the stack. + */ +u8 ReadBuffer[BUFFER_SIZE]; +u8 WriteBuffer[BUFFER_SIZE]; + +/* + * The following variable allows a test value to be added to the values that + * are sent in reflection to the Master transmission such that unique values can + * be generated to guarantee the transfer from Slave to Master is successful. + */ +int Test; + +/*****************************************************************************/ +/** +* +* Main function to call the Spi Slave example in polled mode. +* +* @param None +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the Spi Slave polled example. + */ + Status = SpiSlavePolledExample(&SpiInstance, SPI_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function does a minimal test on the Spi device and driver as a design +* example. The purpose of this function is to illustrate the device slave +* functionality in polled mode. This function receives data from a master and +* prints the received data. +* +* @param SpiInstancePtr is a pointer to the instance of Spi component. +* +* @param SpiDeviceId is the Device ID of the Spi Device and is the +* XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a sd 02/26/08 First release +* 3.00a ktn 10/28/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. Replaced call to +* XSpi_Initialize API with XSpi_LookupConfig and +* XSpi_CfgInitialize. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* EDK generated parameters */ +#include "xintc.h" /* Interrupt controller device driver */ +#include "xspi.h" /* SPI device driver */ +#include "xil_exception.h" + + +/************************** Constant Definitions *****************************/ + + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define SPI_INTR_ID XPAR_INTC_0_SPI_0_VEC_ID + +/* + * The following constant defines the slave select signal that is used to + * to select the Flash device on the SPI bus, this signal is typically + * connected to the chip select of the device. + */ +#define STM_SPI_SELECT 0x01 + +/* + * Definitions of the commands shown in this example. + */ +#define STM_COMMAND_RANDOM_READ 0x03 /* Random read command */ +#define STM_COMMAND_PAGEPROGRAM_WRITE 0x02 /* Page Program command */ +#define STM_COMMAND_WRITE_ENABLE 0x06 /* Write Enable command */ +#define STM_COMMAND_SECTOR_ERASE 0xD8 /* Sector Erase command */ +#define STM_COMMAND_BULK_ERASE 0xC7 /* Bulk Erase command */ +#define STM_COMMAND_STATUSREG_READ 0x05 /* Status read command */ + + +/** + * This definitions specify the EXTRA bytes in each of the command + * transactions. This count includes Command byte, address bytes and any + * don't care bytes needed. + */ +#define STM_READ_WRITE_EXTRA_BYTES 4 /* Read/Write extra bytes */ +#define STM_WRITE_ENABLE_BYTES 1 /* Write Enable bytes */ +#define STM_SECTOR_ERASE_BYTES 4 /* Sector erase extra bytes */ +#define STM_BULK_ERASE_BYTES 1 /* Bulk erase extra bytes */ +#define STM_STATUS_READ_BYTES 2 /* Status read bytes count */ +#define STM_STATUS_WRITE_BYTES 2 /* Status write bytes count */ + +/* + * Flash not busy mask in the status register of the flash device. + */ +#define STM_FLASH_SR_IS_READY_MASK 0x01 /* Ready mask */ + +/* + * Number of bytes per page in the flash device. + */ +#define STM_PAGE_SIZE 256 + +/* + * Address of the page to perform Erase, Write and Read operations. + */ +#define STM_FLASH_TEST_ADDRESS 0x00 + +/* + * Byte offset value written to Flash. This needs to redefined for writing + * different patterns of data to the Flash device. + */ +#define STM_FLASH_TEST_BYTE 0x20 + +/* + * Byte Positions. + */ +#define BYTE1 0 /* Byte 1 position */ +#define BYTE2 1 /* Byte 2 position */ +#define BYTE3 2 /* Byte 3 position */ +#define BYTE4 3 /* Byte 4 position */ +#define BYTE5 4 /* Byte 5 position */ + +#define STM_DUMMYBYTE 0xFF /* Dummy byte */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int SpiStmFlashWriteEnable(XSpi *SpiPtr); +int SpiStmFlashWrite(XSpi *SpiPtr, u32 Addr, u32 ByteCount); +int SpiStmFlashRead(XSpi *SpiPtr, u32 Addr, u32 ByteCount); +int SpiStmFlashBulkErase(XSpi *SpiPtr); +int SpiStmFlashSectorErase(XSpi *SpiPtr, u32 Addr); +int SpiStmFlashGetStatus(XSpi *SpiPtr); +static int SpiStmFlashWaitForFlashNotBusy(void); +void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount); +static int SetupInterruptSystem(XSpi *SpiPtr); + +/************************** Variable Definitions *****************************/ + +/* + * The instances to support the device drivers are global such that they + * are initialized to zero each time the program runs. They could be local + * but should at least be static so they are zeroed. + */ +static XIntc InterruptController; +static XSpi Spi; + +/* + * The following variables are shared between non-interrupt processing and + * interrupt processing such that they must be global. + */ +volatile static int TransferInProgress; + +/* + * The following variable tracks any errors that occur during interrupt + * processing. + */ +int ErrorCount; + +/* + * Buffers used during read and write transactions. + */ +u8 ReadBuffer[STM_PAGE_SIZE + STM_READ_WRITE_EXTRA_BYTES]; +u8 WriteBuffer[STM_PAGE_SIZE + STM_READ_WRITE_EXTRA_BYTES]; + +/************************** Function Definitions ******************************/ + +/*****************************************************************************/ +/** +* +* Main function to execute the Flash example. +* +* @param None +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int main() +{ + int Status; + u32 Index; + u32 Address; + XSpi_Config *ConfigPtr; /* Pointer to Configuration data */ + + /* + * Initialize the SPI driver so that it's ready to use, + * specify the device ID that is generated in xparameters.h. + */ + ConfigPtr = XSpi_LookupConfig(SPI_DEVICE_ID); + if (ConfigPtr == NULL) { + return XST_DEVICE_NOT_FOUND; + } + + Status = XSpi_CfgInitialize(&Spi, ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect the SPI driver to the interrupt subsystem such that + * interrupts can occur. This function is application specific. + */ + Status = SetupInterruptSystem(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the handler for the SPI that will be called from the interrupt + * context when an SPI status occurs, specify a pointer to the SPI + * driver instance as the callback reference so the handler is able to + * access the instance data. + */ + XSpi_SetStatusHandler(&Spi, &Spi, (XSpi_StatusHandler)SpiHandler); + + /* + * Set the SPI device as a master and in manual slave select mode such + * that the slave select signal does not toggle for every byte of a + * transfer, this must be done before the slave select is set. + */ + Status = XSpi_SetOptions(&Spi, XSP_MASTER_OPTION | + XSP_MANUAL_SSELECT_OPTION); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Select the STM flash device on the SPI bus, so that it can be + * read and written using the SPI bus. + */ + Status = XSpi_SetSlaveSelect(&Spi, STM_SPI_SELECT); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the SPI driver so that interrupts and the device are enabled. + */ + XSpi_Start(&Spi); + + /* + * Specify the address in the STM Serial Flash for the Erase/Write/Read + * operations. + */ + Address = STM_FLASH_TEST_ADDRESS; + + + /* + * Perform the Write Enable operation. + */ + Status = SpiStmFlashWriteEnable(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Flash is not Busy. + */ + Status = SpiStmFlashWaitForFlashNotBusy(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Perform the Sector Erase operation. + */ + Status = SpiStmFlashSectorErase(&Spi, Address); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Flash is not Busy. + */ + Status = SpiStmFlashWaitForFlashNotBusy(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Perform the Write Enable operation. + */ + Status = SpiStmFlashWriteEnable(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Flash is not Busy. + */ + Status = SpiStmFlashWaitForFlashNotBusy(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Write the data to the Page. + * Perform the Write operation. + */ + Status = SpiStmFlashWrite(&Spi, Address, STM_PAGE_SIZE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Flash is not Busy. + */ + Status = SpiStmFlashWaitForFlashNotBusy(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Clear the read Buffer. + */ + for(Index = 0; Index < STM_PAGE_SIZE + STM_READ_WRITE_EXTRA_BYTES; + Index++) { + ReadBuffer[Index] = 0x0; + } + + + /* + * Read the data from the Page. + */ + Status = SpiStmFlashRead(&Spi, Address, STM_PAGE_SIZE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Compare the data read against the data Written. + */ + for(Index = 0; Index < STM_PAGE_SIZE; Index++) { + if(ReadBuffer[Index + STM_READ_WRITE_EXTRA_BYTES] != + (u8)(Index + STM_FLASH_TEST_BYTE)) { + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function enables writes to the STM Serial Flash memory. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int SpiStmFlashWriteEnable(XSpi *SpiPtr) +{ + int Status; + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = STM_COMMAND_WRITE_ENABLE; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + STM_WRITE_ENABLE_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function writes the data to the specified locations in the STM Serial +* Flash memory. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* @param Addr is the address in the Buffer, where to write the data. +* @param ByteCount is the number of bytes to be written. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int SpiStmFlashWrite(XSpi *SpiPtr, u32 Addr, u32 ByteCount) +{ + u32 Index; + int Status; + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = STM_COMMAND_PAGEPROGRAM_WRITE; + WriteBuffer[BYTE2] = (u8) (Addr >> 16); + WriteBuffer[BYTE3] = (u8) (Addr >> 8); + WriteBuffer[BYTE4] = (u8) Addr; + + + /* + * Fill in the TEST data that is to be written into the STM Serial Flash + * device. + */ + for(Index = 4; Index < ByteCount + STM_READ_WRITE_EXTRA_BYTES; + Index++) { + WriteBuffer[Index] = (u8)((Index - 4) + STM_FLASH_TEST_BYTE); + } + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + (ByteCount + STM_READ_WRITE_EXTRA_BYTES)); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function reads the data from the STM Serial Flash Memory +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* @param Addr is the starting address in the Flash Memory from which the +* data is to be read. +* @param ByteCount is the number of bytes to be read. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int SpiStmFlashRead(XSpi *SpiPtr, u32 Addr, u32 ByteCount) +{ + int Status; + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = STM_COMMAND_RANDOM_READ; + WriteBuffer[BYTE2] = (u8) (Addr >> 16); + WriteBuffer[BYTE3] = (u8) (Addr >> 8); + WriteBuffer[BYTE4] = (u8) Addr; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer( SpiPtr, WriteBuffer, ReadBuffer, + (ByteCount + STM_READ_WRITE_EXTRA_BYTES)); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function erases the entire contents of the STM Serial Flash device. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note The erased bytes will read as 0xFF. +* +******************************************************************************/ +int SpiStmFlashBulkErase(XSpi *SpiPtr) +{ + int Status; + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = STM_COMMAND_BULK_ERASE; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + STM_BULK_ERASE_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function erases the contents of the specified Sector in the STM Serial +* Flash device. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* @param Addr is the address within a sector of the Buffer, which is to +* be erased. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note The erased bytes will be read back as 0xFF. +* +******************************************************************************/ +int SpiStmFlashSectorErase(XSpi *SpiPtr, u32 Addr) +{ + int Status; + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = STM_COMMAND_SECTOR_ERASE; + WriteBuffer[BYTE2] = (u8) (Addr >> 16); + WriteBuffer[BYTE3] = (u8) (Addr >> 8); + WriteBuffer[BYTE4] = (u8) (Addr); + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + STM_SECTOR_ERASE_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function reads the Status register of the STM Flash. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note The status register content is stored at the second byte pointed +* by the ReadBuffer. +* +******************************************************************************/ +int SpiStmFlashGetStatus(XSpi *SpiPtr) +{ + int Status; + + /* + * Prepare the Write Buffer. + */ + WriteBuffer[BYTE1] = STM_COMMAND_STATUSREG_READ; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, ReadBuffer, + STM_STATUS_READ_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function waits till the STM serial Flash is ready to accept next command. +* +* @param None +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note This function reads the status register of the Buffer and waits +*. till the WIP bit of the status register becomes 0. +* +******************************************************************************/ +int SpiStmFlashWaitForFlashNotBusy(void) +{ + int Status; + u8 StatusReg; + + while(1) { + + /* + * Get the Status Register. + */ + Status = SpiStmFlashGetStatus(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Check if the flash is ready to accept the next command. + * If so break. + */ + StatusReg = ReadBuffer[1]; + if((StatusReg & STM_FLASH_SR_IS_READY_MASK) == 0) { + break; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function is the handler which performs processing for the SPI driver. +* It is called from an interrupt context such that the amount of processing +* performed should be minimized. It is called when a transfer of SPI data +* completes or an error occurs. +* +* This handler provides an example of how to handle SPI interrupts and +* is application specific. +* +* @param CallBackRef is the upper layer callback reference passed back +* when the callback function is invoked. +* @param StatusEvent is the event that just occurred. +* @param ByteCount is the number of bytes transferred up until the event +* occurred. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount) +{ + /* + * Indicate the transfer on the SPI bus is no longer in progress + * regardless of the status event. + */ + TransferInProgress = FALSE; + + /* + * If the event was not transfer done, then track it as an error. + */ + if (StatusEvent != XST_SPI_TRANSFER_DONE) { + ErrorCount++; + } +} + +/*****************************************************************************/ +/** +* +* This function setups the interrupt system such that interrupts can occur +* for the Spi device. This function is application specific since the actual +* system may or may not have an interrupt controller. The Spi device could be +* directly connected to a processor without an interrupt controller. The +* user should modify this function to fit the application. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None +* +******************************************************************************/ +static int SetupInterruptSystem(XSpi *SpiPtr) +{ + + int Status; + + /* + * Initialize the interrupt controller driver so that + * it's ready to use, specify the device ID that is generated in + * xparameters.h + */ + Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect a device driver handler that will be called when an interrupt + * for the device occurs, the device driver handler performs the + * specific interrupt processing for the device + */ + Status = XIntc_Connect(&InterruptController, + SPI_INTR_ID, + (XInterruptHandler)XSpi_InterruptHandler, + (void *)SpiPtr); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller such that interrupts are enabled for + * all devices that cause interrupts, specific real mode so that + * the SPI can cause interrupts thru the interrupt controller. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the interrupt for the SPI. + */ + XIntc_Enable(&InterruptController, SPI_INTR_ID); + + + /* + * Initialize the exception table. + */ + Xil_ExceptionInit(); + + /* + * Register the interrupt controller handler with the exception table. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)XIntc_InterruptHandler, + &InterruptController); + + /* + * Enable non-critical exceptions. + */ + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/spi/examples/xspi_winbond_flash_quad_example.c b/XilinxProcessorIPLib/drivers/spi/examples/xspi_winbond_flash_quad_example.c new file mode 100755 index 00000000..88a6a332 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/examples/xspi_winbond_flash_quad_example.c @@ -0,0 +1,1189 @@ +/****************************************************************************** +* +* Copyright (C) 2011 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/****************************************************************************** +* +* @file xspi_winbond_flash_quad_example.c +* +* This file contains a design example using the SPI driver (XSpi) and axi_qspi +* device with a Winbond quad serial flash device in the interrupt mode. +* This example erases a Sector, writes to a Page within the Sector, reads back +* from that Page and compares the data. +* +* This example has been tested with an W25Q64 device. The bytes per page +* (PAGE_SIZE) in W25Q64 is 256. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a sdm 04/01/11 First release +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* EDK generated parameters */ +#include "xintc.h" /* Interrupt controller device driver */ +#include "xspi.h" /* SPI device driver */ +#include "xil_exception.h" + +/************************** Constant Definitions *****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define SPI_INTR_ID XPAR_INTC_0_SPI_0_VEC_ID + +/* + * The following constant defines the slave select signal that is used to + * to select the Flash device on the SPI bus, this signal is typically + * connected to the chip select of the device. + */ +#define SPI_SELECT 0x01 + +/* + * Definitions of the commands shown in this example. + */ +#define COMMAND_PAGE_PROGRAM 0x02 /* Page Program command */ +#define COMMAND_QUAD_WRITE 0x32 /* Quad Input Fast Program */ +#define COMMAND_RANDOM_READ 0x03 /* Random read command */ +#define COMMAND_DUAL_READ 0x3B /* Dual Output Fast Read */ +#define COMMAND_DUAL_IO_READ 0xBB /* Dual IO Fast Read */ +#define COMMAND_QUAD_READ 0x6B /* Quad Output Fast Read */ +#define COMMAND_QUAD_IO_READ 0xEB /* Quad IO Fast Read */ +#define COMMAND_WRITE_ENABLE 0x06 /* Write Enable command */ +#define COMMAND_SECTOR_ERASE 0xD8 /* Sector Erase command */ +#define COMMAND_BULK_ERASE 0xC7 /* Bulk Erase command */ +#define COMMAND_STATUSREG_READ 0x05 /* Status read command */ + +/** + * This definitions specify the EXTRA bytes in each of the command + * transactions. This count includes Command byte, address bytes and any + * don't care bytes needed. + */ +#define READ_WRITE_EXTRA_BYTES 4 /* Read/Write extra bytes */ +#define WRITE_ENABLE_BYTES 1 /* Write Enable bytes */ +#define SECTOR_ERASE_BYTES 4 /* Sector erase extra bytes */ +#define BULK_ERASE_BYTES 1 /* Bulk erase extra bytes */ +#define STATUS_READ_BYTES 2 /* Status read bytes count */ +#define STATUS_WRITE_BYTES 2 /* Status write bytes count */ + +/* + * Flash not busy mask in the status register of the flash device. + */ +#define FLASH_SR_IS_READY_MASK 0x01 /* Ready mask */ + +/* + * Number of bytes per page in the flash device. + */ +#define PAGE_SIZE 256 + +/* + * Address of the page to perform Erase, Write and Read operations. + */ +#define FLASH_TEST_ADDRESS 0x00 + +/* + * Byte Positions. + */ +#define BYTE1 0 /* Byte 1 position */ +#define BYTE2 1 /* Byte 2 position */ +#define BYTE3 2 /* Byte 3 position */ +#define BYTE4 3 /* Byte 4 position */ +#define BYTE5 4 /* Byte 5 position */ +#define BYTE6 5 /* Byte 6 position */ +#define BYTE7 6 /* Byte 7 position */ +#define BYTE8 7 /* Byte 8 position */ + +/* + * The following definitions specify the number of dummy bytes to ignore in the + * data read from the flash, through various Read commands. This is apart from + * the dummy bytes returned in reponse to the command and address transmitted. + */ +/* + * After transmitting Dual Read command and address on DIO0, the quad spi device + * configures DIO0 and DIO1 in input mode and receives data on both DIO0 and + * DIO1 for 8 dummy clock cycles. So we end up with 16 dummy bits in DRR. The + * same logic applies Quad read command, so we end up with 4 dummy bytes in that + * case. + */ +#define DUAL_READ_DUMMY_BYTES 2 +#define QUAD_READ_DUMMY_BYTES 4 + +#define DUAL_IO_READ_DUMMY_BYTES 1 +#define QUAD_IO_READ_DUMMY_BYTES 3 + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int SpiFlashWriteEnable(XSpi *SpiPtr); +int SpiFlashWrite(XSpi *SpiPtr, u32 Addr, u32 ByteCount, u8 WriteCmd); +int SpiFlashRead(XSpi *SpiPtr, u32 Addr, u32 ByteCount, u8 ReadCmd); +int SpiFlashBulkErase(XSpi *SpiPtr); +int SpiFlashSectorErase(XSpi *SpiPtr, u32 Addr); +int SpiFlashGetStatus(XSpi *SpiPtr); +int SpiFlashQuadEnable(XSpi *SpiPtr); +int SpiFlashEnableHPM(XSpi *SpiPtr); +static int SpiFlashWaitForFlashReady(void); +void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount); +static int SetupInterruptSystem(XSpi *SpiPtr); + +/************************** Variable Definitions *****************************/ + +/* + * The instances to support the device drivers are global such that they + * are initialized to zero each time the program runs. They could be local + * but should at least be static so they are zeroed. + */ +static XIntc InterruptController; +static XSpi Spi; + +/* + * The following variables are shared between non-interrupt processing and + * interrupt processing such that they must be global. + */ +volatile static int TransferInProgress; + +/* + * The following variable tracks any errors that occur during interrupt + * processing. + */ +static int ErrorCount; + +/* + * Buffers used during read and write transactions. + */ +static u8 ReadBuffer[PAGE_SIZE + READ_WRITE_EXTRA_BYTES + 4]; +static u8 WriteBuffer[PAGE_SIZE + READ_WRITE_EXTRA_BYTES]; + +/* + * Byte offset value written to Flash. This needs to be redefined for writing + * different patterns of data to the Flash device. + */ +static u8 TestByte = 0x20; + +/************************** Function Definitions ******************************/ + +/*****************************************************************************/ +/** +* +* Main function to run the quad flash example. +* +* @param None +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int main(void) +{ + int Status; + u32 Index; + u32 Address; + XSpi_Config *ConfigPtr; /* Pointer to Configuration data */ + + /* + * Initialize the SPI driver so that it's ready to use, + * specify the device ID that is generated in xparameters.h. + */ + ConfigPtr = XSpi_LookupConfig(SPI_DEVICE_ID); + if (ConfigPtr == NULL) { + return XST_DEVICE_NOT_FOUND; + } + + Status = XSpi_CfgInitialize(&Spi, ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect the SPI driver to the interrupt subsystem such that + * interrupts can occur. This function is application specific. + */ + Status = SetupInterruptSystem(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the handler for the SPI that will be called from the interrupt + * context when an SPI status occurs, specify a pointer to the SPI + * driver instance as the callback reference so the handler is able to + * access the instance data. + */ + XSpi_SetStatusHandler(&Spi, &Spi, (XSpi_StatusHandler)SpiHandler); + + /* + * Set the SPI device as a master and in manual slave select mode such + * that the slave select signal does not toggle for every byte of a + * transfer, this must be done before the slave select is set. + */ + Status = XSpi_SetOptions(&Spi, XSP_MASTER_OPTION | + XSP_MANUAL_SSELECT_OPTION); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Select the quad flash device on the SPI bus, so that it can be + * read and written using the SPI bus. + */ + Status = XSpi_SetSlaveSelect(&Spi, SPI_SELECT); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the SPI driver so that interrupts and the device are enabled. + */ + XSpi_Start(&Spi); + + /* + * Specify the address in the Quad Serial Flash for the Erase/Write/Read + * operations. + */ + Address = FLASH_TEST_ADDRESS; + + /* + * Perform the Write Enable operation. + */ + Status = SpiFlashWriteEnable(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Perform the Sector Erase operation. + */ + Status = SpiFlashSectorErase(&Spi, Address); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the Quad Enable (QE) bit in the flash device, so that Quad + * operations can be perfomed on the flash. + */ + Status = SpiFlashQuadEnable(&Spi); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Perform the Write Enable operation. + */ + Status = SpiFlashWriteEnable(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Write the data to the Page using Page Program command. + */ + Status = SpiFlashWrite(&Spi, Address, PAGE_SIZE, COMMAND_PAGE_PROGRAM); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Clear the read Buffer. + */ + for(Index = 0; Index < PAGE_SIZE + READ_WRITE_EXTRA_BYTES; Index++) { + ReadBuffer[Index] = 0x0; + } + + /* + * Read the data from the Page using Random Read command. + */ + Status = SpiFlashRead(&Spi, Address, PAGE_SIZE, COMMAND_RANDOM_READ); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Compare the data read against the data written. + */ + for(Index = 0; Index < PAGE_SIZE; Index++) { + if(ReadBuffer[Index + READ_WRITE_EXTRA_BYTES] != + (u8)(Index + TestByte)) { + return XST_FAILURE; + } + } + + /* + * Clear the Read Buffer. + */ + for(Index = 0; Index < PAGE_SIZE + READ_WRITE_EXTRA_BYTES + + DUAL_READ_DUMMY_BYTES; Index++) { + ReadBuffer[Index] = 0x0; + } + + /* + * Read the data from the Page using Dual Output Fast Read command. + */ + Status = SpiFlashRead(&Spi, Address, PAGE_SIZE, COMMAND_DUAL_READ); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Compare the data read against the data written. + */ + for(Index = 0; Index < PAGE_SIZE; Index++) { + if(ReadBuffer[Index + READ_WRITE_EXTRA_BYTES + + DUAL_READ_DUMMY_BYTES] != + (u8)(Index + TestByte)) { + return XST_FAILURE; + } + } + + /* + * Perform the Write Enable operation. + */ + Status = SpiFlashWriteEnable(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Write the data to the next Page using Quad Fast Write command. + */ + TestByte = 0x09; + Address += PAGE_SIZE; + Status = SpiFlashWrite(&Spi, Address, PAGE_SIZE, COMMAND_QUAD_WRITE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait while the Flash is busy. + */ + Status = SpiFlashWaitForFlashReady(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Clear the read Buffer. + */ + for(Index = 0; Index < PAGE_SIZE + READ_WRITE_EXTRA_BYTES; + Index++) { + ReadBuffer[Index] = 0x0; + } + + /* + * Read the data from the Page using Normal Read command. + */ + Status = SpiFlashRead(&Spi, Address, PAGE_SIZE, COMMAND_RANDOM_READ); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Compare the data read against the data written. + */ + for(Index = 0; Index < PAGE_SIZE; Index++) { + if(ReadBuffer[Index + READ_WRITE_EXTRA_BYTES] != + (u8)(Index + TestByte)) { + return XST_FAILURE; + } + } + + /* + * Clear the read Buffer. + */ + for(Index = 0; Index < PAGE_SIZE + READ_WRITE_EXTRA_BYTES + + QUAD_READ_DUMMY_BYTES; Index++) { + ReadBuffer[Index] = 0x0; + } + + /* + * Read the data from the Page using Quad Output Fast Read command. + */ + Status = SpiFlashRead(&Spi, Address, PAGE_SIZE, COMMAND_QUAD_READ); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Compare the data read against the data written. + */ + for(Index = 0; Index < PAGE_SIZE; Index++) { + if(ReadBuffer[Index + READ_WRITE_EXTRA_BYTES + + QUAD_READ_DUMMY_BYTES] != + (u8)(Index + TestByte)) { + return XST_FAILURE; + } + } + + /* + * Enable High Performance Mode so that data can be read from the flash + * using DIO and QIO read commands. + */ + Status = SpiFlashEnableHPM(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Clear the read Buffer. + */ + for(Index = 0; Index < PAGE_SIZE + READ_WRITE_EXTRA_BYTES + + DUAL_IO_READ_DUMMY_BYTES; Index++) { + ReadBuffer[Index] = 0x0; + } + + /* + * Read the data from the Page using Dual IO Fast Read command. + */ + Status = SpiFlashRead(&Spi, Address, PAGE_SIZE, COMMAND_DUAL_IO_READ); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Compare the data read against the data written. + */ + for(Index = 0; Index < PAGE_SIZE; Index++) { + if(ReadBuffer[Index + READ_WRITE_EXTRA_BYTES + + DUAL_IO_READ_DUMMY_BYTES] != + (u8)(Index + TestByte)) { + return XST_FAILURE; + } + } + + /* + * Clear the read Buffer. + */ + for(Index = 0; Index < PAGE_SIZE + READ_WRITE_EXTRA_BYTES + + QUAD_IO_READ_DUMMY_BYTES; Index++) { + ReadBuffer[Index] = 0x0; + } + + /* + * Read the data from the Page using Quad IO Fast Read command. + */ + Status = SpiFlashRead(&Spi, Address, PAGE_SIZE, COMMAND_QUAD_IO_READ); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Compare the data read against the data written. + */ + for(Index = 0; Index < PAGE_SIZE; Index++) { + if(ReadBuffer[Index + READ_WRITE_EXTRA_BYTES + + QUAD_IO_READ_DUMMY_BYTES] != + (u8)(Index + TestByte)) { + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function enables writes to the Winbond Serial Flash memory. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int SpiFlashWriteEnable(XSpi *SpiPtr) +{ + int Status; + + /* + * Wait while the Flash is busy. + */ + Status = SpiFlashWaitForFlashReady(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = COMMAND_WRITE_ENABLE; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + WRITE_ENABLE_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function writes the data to the specified locations in the Winbond Serial +* Flash memory. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* @param Addr is the address in the Buffer, where to write the data. +* @param ByteCount is the number of bytes to be written. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int SpiFlashWrite(XSpi *SpiPtr, u32 Addr, u32 ByteCount, u8 WriteCmd) +{ + u32 Index; + int Status; + + /* + * Wait while the Flash is busy. + */ + Status = SpiFlashWaitForFlashReady(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = WriteCmd; + WriteBuffer[BYTE2] = (u8) (Addr >> 16); + WriteBuffer[BYTE3] = (u8) (Addr >> 8); + WriteBuffer[BYTE4] = (u8) Addr; + + + /* + * Fill in the TEST data that is to be written into the Winbond Serial + * Flash device. + */ + for(Index = 4; Index < ByteCount + READ_WRITE_EXTRA_BYTES; Index++) { + WriteBuffer[Index] = (u8)((Index - 4) + TestByte); + } + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + (ByteCount + READ_WRITE_EXTRA_BYTES)); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function reads the data from the Winbond Serial Flash Memory +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* @param Addr is the starting address in the Flash Memory from which the +* data is to be read. +* @param ByteCount is the number of bytes to be read. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int SpiFlashRead(XSpi *SpiPtr, u32 Addr, u32 ByteCount, u8 ReadCmd) +{ + int Status; + + /* + * Wait while the Flash is busy. + */ + Status = SpiFlashWaitForFlashReady(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = ReadCmd; + WriteBuffer[BYTE2] = (u8) (Addr >> 16); + WriteBuffer[BYTE3] = (u8) (Addr >> 8); + WriteBuffer[BYTE4] = (u8) Addr; + + if (ReadCmd == COMMAND_DUAL_READ) { + ByteCount += 2; + } else if (ReadCmd == COMMAND_DUAL_IO_READ) { + ByteCount++; + } else if (ReadCmd == COMMAND_QUAD_IO_READ) { + ByteCount += 3; + } else if (ReadCmd==COMMAND_QUAD_READ) { + ByteCount += 4; + } + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer( SpiPtr, WriteBuffer, ReadBuffer, + (ByteCount + READ_WRITE_EXTRA_BYTES)); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function erases the entire contents of the Winbond Serial Flash device. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note The erased bytes will read as 0xFF. +* +******************************************************************************/ +int SpiFlashBulkErase(XSpi *SpiPtr) +{ + int Status; + + /* + * Wait while the Flash is busy. + */ + Status = SpiFlashWaitForFlashReady(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = COMMAND_BULK_ERASE; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + BULK_ERASE_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function erases the contents of the specified Sector in the Winbond +* Serial Flash device. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* @param Addr is the address within a sector of the Buffer, which is to +* be erased. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note The erased bytes will be read back as 0xFF. +* +******************************************************************************/ +int SpiFlashSectorErase(XSpi *SpiPtr, u32 Addr) +{ + int Status; + + /* + * Wait while the Flash is busy. + */ + Status = SpiFlashWaitForFlashReady(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = COMMAND_SECTOR_ERASE; + WriteBuffer[BYTE2] = (u8) (Addr >> 16); + WriteBuffer[BYTE3] = (u8) (Addr >> 8); + WriteBuffer[BYTE4] = (u8) (Addr); + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, + SECTOR_ERASE_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function reads the Status register of the Winbond Flash. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note The status register content is stored at the second byte pointed +* by the ReadBuffer. +* +******************************************************************************/ +int SpiFlashGetStatus(XSpi *SpiPtr) +{ + int Status; + + /* + * Prepare the Write Buffer. + */ + WriteBuffer[BYTE1] = COMMAND_STATUSREG_READ; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, ReadBuffer, + STATUS_READ_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function sets the QuadEnable bit in Winbond flash. +* +* @param None +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int SpiFlashQuadEnable(XSpi *SpiPtr) +{ + int Status; + + /* + * Perform the Write Enable operation. + */ + Status = SpiFlashWriteEnable(SpiPtr); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait while the Flash is busy. + */ + Status = SpiFlashWaitForFlashReady(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = 0x01; + WriteBuffer[BYTE2] = 0x00; + WriteBuffer[BYTE3] = 0x02; /* QE = 1 */ + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, 3); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + /* + * Wait while the Flash is busy. + */ + Status = SpiFlashWaitForFlashReady(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Verify that QE bit is set by reading status register 2. + */ + + /* + * Prepare the Write Buffer. + */ + WriteBuffer[BYTE1] = 0x35; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, ReadBuffer, + STATUS_READ_BYTES); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function enabled High Performance Mode in Winbond flash, so that data can +* be read from the flash using DIO and QIO commands. +* +* @param None +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int SpiFlashEnableHPM(XSpi *SpiPtr) +{ + int Status; + + /* + * Perform the Write Enable operation. + */ + Status = SpiFlashWriteEnable(SpiPtr); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait while the Flash is busy. + */ + Status = SpiFlashWaitForFlashReady(); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Prepare the WriteBuffer. + */ + WriteBuffer[BYTE1] = 0xA3; + + /* + * Initiate the Transfer. + */ + TransferInProgress = TRUE; + Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL, 4); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the Transfer is complete and check if there are any errors + * in the transaction.. + */ + while(TransferInProgress); + if(ErrorCount != 0) { + ErrorCount = 0; + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function waits till the Winbond serial Flash is ready to accept next +* command. +* +* @param None +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note This function reads the status register of the Buffer and waits +*. till the WIP bit of the status register becomes 0. +* +******************************************************************************/ +int SpiFlashWaitForFlashReady(void) +{ + int Status; + u8 StatusReg; + + while(1) { + + /* + * Get the Status Register. + */ + Status = SpiFlashGetStatus(&Spi); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Check if the flash is ready to accept the next command. + * If so break. + */ + StatusReg = ReadBuffer[1]; + if((StatusReg & FLASH_SR_IS_READY_MASK) == 0) { + break; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function is the handler which performs processing for the SPI driver. +* It is called from an interrupt context such that the amount of processing +* performed should be minimized. It is called when a transfer of SPI data +* completes or an error occurs. +* +* This handler provides an example of how to handle SPI interrupts and +* is application specific. +* +* @param CallBackRef is the upper layer callback reference passed back +* when the callback function is invoked. +* @param StatusEvent is the event that just occurred. +* @param ByteCount is the number of bytes transferred up until the event +* occurred. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount) +{ + /* + * Indicate the transfer on the SPI bus is no longer in progress + * regardless of the status event. + */ + TransferInProgress = FALSE; + + /* + * If the event was not transfer done, then track it as an error. + */ + if (StatusEvent != XST_SPI_TRANSFER_DONE) { + ErrorCount++; + } +} + +/*****************************************************************************/ +/** +* +* This function setups the interrupt system such that interrupts can occur +* for the Spi device. This function is application specific since the actual +* system may or may not have an interrupt controller. The Spi device could be +* directly connected to a processor without an interrupt controller. The +* user should modify this function to fit the application. +* +* @param SpiPtr is a pointer to the instance of the Spi device. +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None +* +******************************************************************************/ +static int SetupInterruptSystem(XSpi *SpiPtr) +{ + + int Status; + + /* + * Initialize the interrupt controller driver so that + * it's ready to use, specify the device ID that is generated in + * xparameters.h + */ + Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect a device driver handler that will be called when an interrupt + * for the device occurs, the device driver handler performs the + * specific interrupt processing for the device + */ + Status = XIntc_Connect(&InterruptController, + SPI_INTR_ID, + (XInterruptHandler)XSpi_InterruptHandler, + (void *)SpiPtr); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller such that interrupts are enabled for + * all devices that cause interrupts, specific real mode so that + * the SPI can cause interrupts thru the interrupt controller. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if(Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the interrupt for the SPI. + */ + XIntc_Enable(&InterruptController, SPI_INTR_ID); + + + /* + * Initialize the exception table. + */ + Xil_ExceptionInit(); + + /* + * Register the interrupt controller handler with the exception table. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)XIntc_InterruptHandler, + &InterruptController); + + /* + * Enable non-critical exceptions. + */ + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/spi/examples/xspi_winbond_flash_xip_example.c b/XilinxProcessorIPLib/drivers/spi/examples/xspi_winbond_flash_xip_example.c new file mode 100755 index 00000000..00467bf8 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/examples/xspi_winbond_flash_xip_example.c @@ -0,0 +1,164 @@ +/****************************************************************************** +* +* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* @file xspi_polled_example.c +* +* +* This file contains a design example using the Spi driver (XSpi) and the Spi +* device configured in XIP Mode. This example reads data from the Flash Memory +* in the way RAM is accessed. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- --------------------------------------------------------- +* 3.04a bss 03/21/12 First Release +* +*+******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* XPAR parameters */ +#include "xspi.h" /* SPI device driver */ + + +/************************** Constant Definitions *****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID + + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +int SpiXipExample(XSpi *SpiInstancePtr, u16 SpiDeviceId); + +/************************** Variable Definitions *****************************/ + +/* + * The instances to support the device drivers are global such that the + * are initialized to zero each time the program runs. + */ +static XSpi SpiInstance; /* The instance of the SPI device */ + + +/*****************************************************************************/ +/** +* +* Main function to call the Spi XIP example. +* +* @param None +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the Spi XIP example. + */ + Status = SpiXipExample(&SpiInstance, SPI_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function reads data from Flash memory in the way any memory is accessed. +* The purpose of this function is to illustrate how to use SPI device in XIP +* Mode. +* +* This function reads data from Flash in the same way any other memory is +* accessed +* +* +* @param SpiInstancePtr is a pointer to the instance of Spi component. +* @param SpiDeviceId is the Device ID of the Spi Device and is the +* XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a rpm 10/11/01 First release +* 1.00b jhl 03/14/02 Repartitioned driver for smaller files. +* 1.00b rpm 04/25/02 Collapsed IPIF and reg base addresses into one +* 1.00b rmm 05/14/03 Fixed diab compiler warnings relating to asserts +* 1.01a jvb 12/13/05 Changed Initialize() into CfgInitialize(), and made +* CfgInitialize() take a pointer to a config structure +* instead of a device id. Moved Initialize() into +* xspi_sinit.c, and had Initialize() call CfgInitialize() +* after it retrieved the config structure using the device +* id. Removed include of xparameters.h along with any +* dependencies on xparameters.h and the _g.c config table. +* 1.11a wgr 03/22/07 Converted to new coding style. +* 1.11a rpm 01/22/08 Updated comment on Transfer regarding needing interrupts. +* 1.12a sdm 03/27/08 Updated the code to support 16/32 bit transfer width and +* polled mode of operation. Even for the polled mode of +* operation the Interrupt Logic in the core should be +* included. The driver can be put in polled mode of +* operation by disabling the Global Interrupt after the +* Spi Initialization is completed. +* 2.00a sdm 07/30/08 Updated the code to support 16/32 bit transfer width and +* polled mode of operation. Even for the polled mode of +* operation the Interrupt Logic in the core should be +* included. The driver can be put in polled mode of +* operation by disabling the Global Interrupt after the +* Spi Initialization is completed. +* 2.01b sdm 04/08/09 Fixed an issue in the XSpi_Transfer function where the +* Global Interrupt is being enabled in polled mode when a +* slave is not selected. +* 3.00a ktn 10/28/09 Updated all the register accesses as 32 bit access. +* Updated to use the HAL APIs/macros. +* Removed the macro XSpi_mReset, XSpi_Reset API should be +* used in its place. +* The macros have been renamed to remove _m from the name. +* Removed an unnecessary read to the core register in the +* XSpi_GetSlaveSelect API. +* 3.01a sdm 04/23/10 Updated the driver to handle new slave mode interrupts +* and the DTR Half Empty interrupt. +* 3.04a bss 03/21/12 Updated XSpi_CfgInitialize to support XIP Mode +* 3.05a adk 18/04/13 Updated the code to avoid unused variable +* warnings when compiling with the -Wextra -Wall flags +* In the file xspi.c. CR:705005. +* 3.06a adk 07/08/13 Added a dummy read in the CfgInitialize(), if startup +* block is used in the h/w design (CR 721229). +* 3.07a adk 11/10/13 In the xspi_transfer function moved the assert slave chip +* select after the configuration of the Data Transmit +* register inorder to work with CPOL and CPHA High Options. +* As per spec (Dual/Quad SPI Transaction instrunction 7,8,9) +* CR:732962 +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xspi.h" +#include "xspi_i.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +static void StubStatusHandler(void *CallBackRef, u32 StatusEvent, + unsigned int ByteCount); + +void XSpi_Abort(XSpi *InstancePtr); + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** +* +* Initializes a specific XSpi instance such that the driver is ready to use. +* +* The state of the device after initialization is: +* - Device is disabled +* - Slave mode +* - Active high clock polarity +* - Clock phase 0 +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param Config is a reference to a structure containing information +* about a specific SPI device. This function initializes an +* InstancePtr object for a specific device specified by the +* contents of Config. This function can initialize multiple +* instance objects with the use of multiple calls giving + different Config information on each call. +* @param EffectiveAddr is the device base address in the virtual memory +* address space. The caller is responsible for keeping the +* address mapping from EffectiveAddr to the device physical base +* address unchanged once this function is invoked. Unexpected +* errors may occur if the address mapping changes after this +* function is called. If address translation is not used, use +* Config->BaseAddress for this parameters, passing the physical +* address instead. +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_IS_STARTED if the device is started. It must be +* stopped to re-initialize. +* +* @note None. +* +******************************************************************************/ +int XSpi_CfgInitialize(XSpi *InstancePtr, XSpi_Config *Config, + u32 EffectiveAddr) +{ + u8 Buffer[3]; + u32 ControlReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + + /* + * If the device is started, disallow the initialize and return a status + * indicating it is started. This allows the user to stop the device + * and reinitialize, but prevents a user from inadvertently + * initializing. + */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + return XST_DEVICE_IS_STARTED; + } + + /* + * Set some default values. + */ + InstancePtr->IsStarted = 0; + InstancePtr->IsBusy = FALSE; + + InstancePtr->StatusHandler = StubStatusHandler; + + InstancePtr->SendBufferPtr = NULL; + InstancePtr->RecvBufferPtr = NULL; + InstancePtr->RequestedBytes = 0; + InstancePtr->RemainingBytes = 0; + InstancePtr->BaseAddr = EffectiveAddr; + InstancePtr->HasFifos = Config->HasFifos; + InstancePtr->SlaveOnly = Config->SlaveOnly; + InstancePtr->NumSlaveBits = Config->NumSlaveBits; + if (Config->DataWidth == 0) { + InstancePtr->DataWidth = XSP_DATAWIDTH_BYTE; + } else { + InstancePtr->DataWidth = Config->DataWidth; + } + + InstancePtr->SpiMode = Config->SpiMode; + + InstancePtr->FlashBaseAddr = Config->AxiFullBaseAddress; + InstancePtr->XipMode = Config->XipMode; + + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + + /* + * Create a slave select mask based on the number of bits that can + * be used to deselect all slaves, initialize the value to put into + * the slave select register to this value. + */ + InstancePtr->SlaveSelectMask = (1 << InstancePtr->NumSlaveBits) - 1; + InstancePtr->SlaveSelectReg = InstancePtr->SlaveSelectMask; + + /* + * Clear the statistics for this driver. + */ + InstancePtr->Stats.ModeFaults = 0; + InstancePtr->Stats.XmitUnderruns = 0; + InstancePtr->Stats.RecvOverruns = 0; + InstancePtr->Stats.SlaveModeFaults = 0; + InstancePtr->Stats.BytesTransferred = 0; + InstancePtr->Stats.NumInterrupts = 0; + + if(Config->Use_Startup == 1) { + /* + * Perform a dummy read this is used when startup block is + * enabled in the hardware to fix CR #721229. + */ + ControlReg = XSpi_GetControlReg(InstancePtr); + ControlReg |= XSP_CR_TXFIFO_RESET_MASK | XSP_CR_RXFIFO_RESET_MASK | + XSP_CR_ENABLE_MASK | XSP_CR_MASTER_MODE_MASK ; + XSpi_SetControlReg(InstancePtr, ControlReg); + + /* + * Initiate Read command to get the ID. This Read command is for + * Numonyx flash. + * + * NOTE: If user interfaces different flash to the SPI controller + * this command need to be changed according to target flash Read + * command. + */ + Buffer[0] = 0x9F; + Buffer[1] = 0x00; + Buffer[2] = 0x00; + + /* Write dummy ReadId to the DTR register */ + XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Buffer[0]); + XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Buffer[1]); + XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Buffer[2]); + + /* Master Inhibit enable in the CR */ + ControlReg = XSpi_GetControlReg(InstancePtr); + ControlReg &= ~XSP_CR_TRANS_INHIBIT_MASK; + XSpi_SetControlReg(InstancePtr, ControlReg); + + /* Master Inhibit disable in the CR */ + ControlReg = XSpi_GetControlReg(InstancePtr); + ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; + XSpi_SetControlReg(InstancePtr, ControlReg); + + /* Read the Rx Data Register */ + XSpi_ReadReg(InstancePtr->BaseAddr, XSP_DRR_OFFSET); + XSpi_ReadReg(InstancePtr->BaseAddr, XSP_DRR_OFFSET); + } + + /* + * Reset the SPI device to get it into its initial state. It is expected + * that device configuration will take place after this initialization + * is done, but before the device is started. + */ + XSpi_Reset(InstancePtr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function enables interrupts for the SPI device. If the Spi driver is used +* in interrupt mode, it is up to the user to connect the SPI interrupt handler +* to the interrupt controller before this function is called. If the Spi driver +* is used in polled mode the user has to disable the Global Interrupts after +* this function is called. If the device is configured with FIFOs, the FIFOs are +* reset at this time. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return +* - XST_SUCCESS if the device is successfully started +* - XST_DEVICE_IS_STARTED if the device was already started. +* +* @note None. +* +******************************************************************************/ +int XSpi_Start(XSpi *InstancePtr) +{ + u32 ControlReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * If it is already started, return a status indicating so. + */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + return XST_DEVICE_IS_STARTED; + } + + /* + * Enable the interrupts. + */ + XSpi_IntrEnable(InstancePtr, XSP_INTR_DFT_MASK); + + /* + * Indicate that the device is started before we enable the transmitter + * or receiver or interrupts. + */ + InstancePtr->IsStarted = XIL_COMPONENT_IS_STARTED; + + /* + * Reset the transmit and receive FIFOs if present. There is a critical + * section here since this register is also modified during interrupt + * context. So we wait until after the r/m/w of the control register to + * enable the Global Interrupt Enable. + */ + ControlReg = XSpi_GetControlReg(InstancePtr); + ControlReg |= XSP_CR_TXFIFO_RESET_MASK | XSP_CR_RXFIFO_RESET_MASK | + XSP_CR_ENABLE_MASK; + XSpi_SetControlReg(InstancePtr, ControlReg); + + /* + * Enable the Global Interrupt Enable just after we start. + */ + XSpi_IntrGlobalEnable(InstancePtr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function stops the SPI device by disabling interrupts and disabling the +* device itself. Interrupts are disabled only within the device itself. If +* desired, the caller is responsible for disabling interrupts in the interrupt +* controller and disconnecting the interrupt handler from the interrupt +* controller. +* +* In interrupt mode, if the device is in progress of transferring data on the +* SPI bus, this function returns a status indicating the device is busy. The +* user will be notified via the status handler when the transfer is complete, +* and at that time can again try to stop the device. As a master, we do not +* allow the device to be stopped while a transfer is in progress because the +* slave may be left in a bad state. As a slave, we do not allow the device to be +* stopped while a transfer is in progress because the master is not done with +* its transfer yet. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return +* - XST_SUCCESS if the device is successfully started. +* - XST_DEVICE_BUSY if a transfer is in progress and cannot be +* stopped. +* +* @note +* +* This function makes use of internal resources that are shared between the +* XSpi_Stop() and XSpi_SetOptions() functions. So if one task might be setting +* device options while another is trying to stop the device, the user is +* is required to provide protection of this shared data (typically using a +* semaphore). +* +******************************************************************************/ +int XSpi_Stop(XSpi *InstancePtr) +{ + u32 ControlReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Do not allow the user to stop the device while a transfer is in + * progress. + */ + if (InstancePtr->IsBusy) { + return XST_DEVICE_BUSY; + } + + /* + * Disable the device. First disable the interrupts since there is + * a critical section here because this register is also modified during + * interrupt context. The device is likely disabled already since there + * is no transfer in progress, but we do it again just to be sure. + */ + XSpi_IntrGlobalDisable(InstancePtr); + + ControlReg = XSpi_GetControlReg(InstancePtr); + XSpi_SetControlReg(InstancePtr, ControlReg & ~XSP_CR_ENABLE_MASK); + + InstancePtr->IsStarted = 0; + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Resets the SPI device by writing to the Software Reset register. Reset must +* only be called after the driver has been initialized. The configuration of the +* device after reset is the same as its configuration after initialization. +* Refer to the XSpi_Initialize function for more details. This is a hard reset +* of the device. Any data transfer that is in progress is aborted. +* +* The upper layer software is responsible for re-configuring (if necessary) +* and restarting the SPI device after the reset. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XSpi_Reset(XSpi *InstancePtr) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Abort any transfer that is in progress. + */ + XSpi_Abort(InstancePtr); + + /* + * Reset any values that are not reset by the hardware reset such that + * the software state matches the hardware device. + */ + InstancePtr->IsStarted = 0; + InstancePtr->SlaveSelectReg = InstancePtr->SlaveSelectMask; + + /* + * Reset the device. + */ + XSpi_WriteReg(InstancePtr->BaseAddr, XSP_SRR_OFFSET, + XSP_SRR_RESET_MASK); +} + +/*****************************************************************************/ +/** +* +* Transfers the specified data on the SPI bus. If the SPI device is configured +* to be a master, this function initiates bus communication and sends/receives +* the data to/from the selected SPI slave. If the SPI device is configured to +* be a slave, this function prepares the data to be sent/received when selected +* by a master. For every byte sent, a byte is received. +* +* This function/driver operates in interrupt mode and polled mode. +* - In interrupt mode this function is non-blocking and the transfer is +* initiated by this function and completed by the interrupt service routine. +* - In polled mode this function is blocking and the control exits this +* function only after all the requested data is transferred. +* +* The caller has the option of providing two different buffers for send and +* receive, or one buffer for both send and receive, or no buffer for receive. +* The receive buffer must be at least as big as the send buffer to prevent +* unwanted memory writes. This implies that the byte count passed in as an +* argument must be the smaller of the two buffers if they differ in size. +* Here are some sample usages: +*
+* XSpi_Transfer(InstancePtr, SendBuf, RecvBuf, ByteCount) +* The caller wishes to send and receive, and provides two different +* buffers for send and receive. +* +* XSpi_Transfer(InstancePtr, SendBuf, NULL, ByteCount) +* The caller wishes only to send and does not care about the received +* data. The driver ignores the received data in this case. +* +* XSpi_Transfer(InstancePtr, SendBuf, SendBuf, ByteCount) +* The caller wishes to send and receive, but provides the same buffer +* for doing both. The driver sends the data and overwrites the send +* buffer with received data as it transfers the data. +* +* XSpi_Transfer(InstancePtr, RecvBuf, RecvBuf, ByteCount) +* The caller wishes to only receive and does not care about sending +* data. In this case, the caller must still provide a send buffer, but +* it can be the same as the receive buffer if the caller does not care +* what it sends. The device must send N bytes of data if it wishes to +* receive N bytes of data. +*+* In interrupt mode, though this function takes a buffer as an argument, the +* driver can only transfer a limited number of bytes at time. It transfers only +* one byte at a time if there are no FIFOs, or it can transfer the number of +* bytes up to the size of the FIFO if FIFOs exist. +* - In interrupt mode a call to this function only starts the transfer, the +* subsequent transfer of the data is performed by the interrupt service +* routine until the entire buffer has been transferred.The status callback +* function is called when the entire buffer has been sent/received. +* - In polled mode this function is blocking and the control exits this +* function only after all the requested data is transferred. +* +* As a master, the SetSlaveSelect function must be called prior to this +* function. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param SendBufPtr is a pointer to a buffer of data which is to be sent. +* This buffer must not be NULL. +* @param RecvBufPtr is a pointer to a buffer which will be filled with +* received data. This argument can be NULL if the caller does not +* wish to receive data. +* @param ByteCount contains the number of bytes to send/receive. The +* number of bytes received always equals the number of bytes sent. +* +* @return +* -XST_SUCCESS if the buffers are successfully handed off to the +* driver for transfer. Otherwise, returns: +* - XST_DEVICE_IS_STOPPED if the device must be started before +* transferring data. +* - XST_DEVICE_BUSY indicates that a data transfer is already in +* progress. This is determined by the driver. +* - XST_SPI_NO_SLAVE indicates the device is configured as a +* master and a slave has not yet been selected. +* +* @notes +* +* This function is not thread-safe. The higher layer software must ensure that +* no two threads are transferring data on the SPI bus at the same time. +* +******************************************************************************/ +int XSpi_Transfer(XSpi *InstancePtr, u8 *SendBufPtr, + u8 *RecvBufPtr, unsigned int ByteCount) +{ + u32 ControlReg; + u32 GlobalIntrReg; + u32 StatusReg; + u32 Data = 0; + u8 DataWidth; + + /* + * The RecvBufPtr argument can be NULL. + */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(SendBufPtr != NULL); + Xil_AssertNonvoid(ByteCount > 0); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + if (InstancePtr->IsStarted != XIL_COMPONENT_IS_STARTED) { + return XST_DEVICE_IS_STOPPED; + } + + /* + * Make sure there is not a transfer already in progress. No need to + * worry about a critical section here. Even if the Isr changes the bus + * flag just after we read it, a busy error is returned and the caller + * can retry when it gets the status handler callback indicating the + * transfer is done. + */ + if (InstancePtr->IsBusy) { + return XST_DEVICE_BUSY; + } + + /* + * Save the Global Interrupt Enable Register. + */ + GlobalIntrReg = XSpi_IsIntrGlobalEnabled(InstancePtr); + + /* + * Enter a critical section from here to the end of the function since + * state is modified, an interrupt is enabled, and the control register + * is modified (r/m/w). + */ + XSpi_IntrGlobalDisable(InstancePtr); + + ControlReg = XSpi_GetControlReg(InstancePtr); + + /* + * If configured as a master, be sure there is a slave select bit set + * in the slave select register. If no slaves have been selected, the + * value of the register will equal the mask. When the device is in + * loopback mode, however, no slave selects need be set. + */ + if (ControlReg & XSP_CR_MASTER_MODE_MASK) { + if ((ControlReg & XSP_CR_LOOPBACK_MASK) == 0) { + if (InstancePtr->SlaveSelectReg == + InstancePtr->SlaveSelectMask) { + if (GlobalIntrReg == TRUE) { + /* Interrupt Mode of operation */ + XSpi_IntrGlobalEnable(InstancePtr); + } + return XST_SPI_NO_SLAVE; + } + } + } + + /* + * Set the busy flag, which will be cleared when the transfer + * is completely done. + */ + InstancePtr->IsBusy = TRUE; + + /* + * Set up buffer pointers. + */ + InstancePtr->SendBufferPtr = SendBufPtr; + InstancePtr->RecvBufferPtr = RecvBufPtr; + + InstancePtr->RequestedBytes = ByteCount; + InstancePtr->RemainingBytes = ByteCount; + + DataWidth = InstancePtr->DataWidth; + + /* + * Fill the DTR/FIFO with as many bytes as it will take (or as many as + * we have to send). We use the tx full status bit to know if the device + * can take more data. By doing this, the driver does not need to know + * the size of the FIFO or that there even is a FIFO. The downside is + * that the status register must be read each loop iteration. + */ + StatusReg = XSpi_GetStatusReg(InstancePtr); + + while (((StatusReg & XSP_SR_TX_FULL_MASK) == 0) && + (InstancePtr->RemainingBytes > 0)) { + if (DataWidth == XSP_DATAWIDTH_BYTE) { + /* + * Data Transfer Width is Byte (8 bit). + */ + Data = *InstancePtr->SendBufferPtr; + } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { + /* + * Data Transfer Width is Half Word (16 bit). + */ + Data = *(u16 *)InstancePtr->SendBufferPtr; + } else if (DataWidth == XSP_DATAWIDTH_WORD){ + /* + * Data Transfer Width is Word (32 bit). + */ + Data = *(u32 *)InstancePtr->SendBufferPtr; + } + + XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data); + InstancePtr->SendBufferPtr += (DataWidth >> 3); + InstancePtr->RemainingBytes -= (DataWidth >> 3); + StatusReg = XSpi_GetStatusReg(InstancePtr); + } + + + /* + * Set the slave select register to select the device on the SPI before + * starting the transfer of data. + */ + XSpi_SetSlaveSelectReg(InstancePtr, + InstancePtr->SlaveSelectReg); + + /* + * Start the transfer by no longer inhibiting the transmitter and + * enabling the device. For a master, this will in fact start the + * transfer, but for a slave it only prepares the device for a transfer + * that must be initiated by a master. + */ + ControlReg = XSpi_GetControlReg(InstancePtr); + ControlReg &= ~XSP_CR_TRANS_INHIBIT_MASK; + XSpi_SetControlReg(InstancePtr, ControlReg); + + /* + * If the interrupts are enabled as indicated by Global Interrupt + * Enable Register, then enable the transmit empty interrupt to operate + * in Interrupt mode of operation. + */ + if (GlobalIntrReg == TRUE) { /* Interrupt Mode of operation */ + + /* + * Enable the transmit empty interrupt, which we use to + * determine progress on the transmission. + */ + XSpi_IntrEnable(InstancePtr, XSP_INTR_TX_EMPTY_MASK); + + /* + * End critical section. + */ + XSpi_IntrGlobalEnable(InstancePtr); + + } else { /* Polled mode of operation */ + + /* + * If interrupts are not enabled, poll the status register to + * Transmit/Receive SPI data. + */ + while(ByteCount > 0) { + + /* + * Wait for the transfer to be done by polling the + * Transmit empty status bit + */ + do { + StatusReg = XSpi_GetStatusReg(InstancePtr); + } while ((StatusReg & XSP_SR_TX_EMPTY_MASK) == 0); + + /* + * A transmit has just completed. Process received data + * and check for more data to transmit. Always inhibit + * the transmitter while the transmit register/FIFO is + * being filled, or make sure it is stopped if we're + * done. + */ + ControlReg = XSpi_GetControlReg(InstancePtr); + XSpi_SetControlReg(InstancePtr, ControlReg | + XSP_CR_TRANS_INHIBIT_MASK); + + /* + * First get the data received as a result of the + * transmit that just completed. We get all the data + * available by reading the status register to determine + * when the Receive register/FIFO is empty. Always get + * the received data, but only fill the receive + * buffer if it points to something (the upper layer + * software may not care to receive data). + */ + StatusReg = XSpi_GetStatusReg(InstancePtr); + + while ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) { + + Data = XSpi_ReadReg(InstancePtr->BaseAddr, + XSP_DRR_OFFSET); + if (DataWidth == XSP_DATAWIDTH_BYTE) { + /* + * Data Transfer Width is Byte (8 bit). + */ + if(InstancePtr->RecvBufferPtr != NULL) { + *InstancePtr->RecvBufferPtr++ = + (u8)Data; + } + } else if (DataWidth == + XSP_DATAWIDTH_HALF_WORD) { + /* + * Data Transfer Width is Half Word + * (16 bit). + */ + if (InstancePtr->RecvBufferPtr != NULL){ + *(u16 *)InstancePtr->RecvBufferPtr = + (u16)Data; + InstancePtr->RecvBufferPtr += 2; + } + } else if (DataWidth == XSP_DATAWIDTH_WORD) { + /* + * Data Transfer Width is Word (32 bit). + */ + if (InstancePtr->RecvBufferPtr != NULL){ + *(u32 *)InstancePtr->RecvBufferPtr = + Data; + InstancePtr->RecvBufferPtr += 4; + } + } + InstancePtr->Stats.BytesTransferred += + (DataWidth >> 3); + ByteCount -= (DataWidth >> 3); + StatusReg = XSpi_GetStatusReg(InstancePtr); + } + + if (InstancePtr->RemainingBytes > 0) { + + /* + * Fill the DTR/FIFO with as many bytes as it + * will take (or as many as we have to send). + * We use the Tx full status bit to know if the + * device can take more data. + * By doing this, the driver does not need to + * know the size of the FIFO or that there even + * is a FIFO. + * The downside is that the status must be read + * each loop iteration. + */ + StatusReg = XSpi_GetStatusReg(InstancePtr); + + while(((StatusReg & XSP_SR_TX_FULL_MASK)== 0) && + (InstancePtr->RemainingBytes > 0)) { + if (DataWidth == XSP_DATAWIDTH_BYTE) { + /* + * Data Transfer Width is Byte + * (8 bit). + */ + Data = *InstancePtr-> + SendBufferPtr; + + } else if (DataWidth == + XSP_DATAWIDTH_HALF_WORD) { + + /* + * Data Transfer Width is Half + * Word (16 bit). + */ + Data = *(u16 *)InstancePtr-> + SendBufferPtr; + } else if (DataWidth == + XSP_DATAWIDTH_WORD) { + /* + * Data Transfer Width is Word + * (32 bit). + */ + Data = *(u32 *)InstancePtr-> + SendBufferPtr; + } + XSpi_WriteReg(InstancePtr->BaseAddr, + XSP_DTR_OFFSET, Data); + InstancePtr->SendBufferPtr += + (DataWidth >> 3); + InstancePtr->RemainingBytes -= + (DataWidth >> 3); + StatusReg = XSpi_GetStatusReg( + InstancePtr); + } + + /* + * Start the transfer by not inhibiting the + * transmitter any longer. + */ + ControlReg = XSpi_GetControlReg(InstancePtr); + ControlReg &= ~XSP_CR_TRANS_INHIBIT_MASK; + XSpi_SetControlReg(InstancePtr, ControlReg); + } + } + + /* + * Stop the transfer (hold off automatic sending) by inhibiting + * the transmitter. + */ + ControlReg = XSpi_GetControlReg(InstancePtr); + XSpi_SetControlReg(InstancePtr, + ControlReg | XSP_CR_TRANS_INHIBIT_MASK); + + /* + * Select the slave on the SPI bus when the transfer is + * complete, this is necessary for some SPI devices, + * such as serial EEPROMs work correctly as chip enable + * may be connected to slave select + */ + XSpi_SetSlaveSelectReg(InstancePtr, + InstancePtr->SlaveSelectMask); + InstancePtr->IsBusy = FALSE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Selects or deselect the slave with which the master communicates. Each slave +* that can be selected is represented in the slave select register by a bit. +* The argument passed to this function is the bit mask with a 1 in the bit +* position of the slave being selected. Only one slave can be selected. +* +* The user is not allowed to deselect the slave while a transfer is in progress. +* If no transfer is in progress, the user can select a new slave, which +* implicitly deselects the current slave. In order to explicitly deselect the +* current slave, a zero can be passed in as the argument to the function. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param SlaveMask is a 32-bit mask with a 1 in the bit position of the +* slave being selected. Only one slave can be selected. The +* SlaveMask can be zero if the slave is being deselected. +* +* @return +* - XST_SUCCESS if the slave is selected or deselected +* successfully. +* - XST_DEVICE_BUSY if a transfer is in progress, slave cannot be +* changed +* - XST_SPI_TOO_MANY_SLAVES if more than one slave is being +* selected. +* +* @note +* +* This function only sets the slave which will be selected when a transfer +* occurs. The slave is not selected when the SPI is idle. The slave select +* has no affect when the device is configured as a slave. +* +******************************************************************************/ +int XSpi_SetSlaveSelect(XSpi *InstancePtr, u32 SlaveMask) +{ + int NumAsserted; + int Index; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Do not allow the slave select to change while a transfer is in + * progress. + * No need to worry about a critical section here since even if the Isr + * changes the busy flag just after we read it, the function will return + * busy and the caller can retry when notified that their current + * transfer is done. + */ + if (InstancePtr->IsBusy) { + return XST_DEVICE_BUSY; + } + + /* + * Verify that only one bit in the incoming slave mask is set. + */ + NumAsserted = 0; + for (Index = (InstancePtr->NumSlaveBits - 1); Index >= 0; Index--) { + if ((SlaveMask >> Index) & 0x1) { + /* this bit is asserted */ + NumAsserted++; + } + } + + /* + * Return an error if more than one slave is selected. + */ + if (NumAsserted > 1) { + return XST_SPI_TOO_MANY_SLAVES; + } + + /* + * A single slave is either being selected or the incoming SlaveMask is + * zero, which means the slave is being deselected. Setup the value to + * be written to the slave select register as the inverse of the slave + * mask. + */ + InstancePtr->SlaveSelectReg = ~SlaveMask; + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Gets the current slave select bit mask for the SPI device. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return The value returned is a 32-bit mask with a 1 in the bit position +* of the slave currently selected. The value may be zero if no +* slaves are selected. +* +* @note This API is used to get the current slave select bit mask +* that was set using the XSpi_SetSlaveSelect API. +* This API deos not read the register from the core and returns +* the slave select register stored in the instance pointer. +* +******************************************************************************/ +u32 XSpi_GetSlaveSelect(XSpi *InstancePtr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Return the inverse of the value contained in + * InstancePtr->SlaveSelectReg. This value is set using the API + * XSpi_SetSlaveSelect. + */ + return ~InstancePtr->SlaveSelectReg; +} + +/*****************************************************************************/ +/** +* +* Sets the status callback function, the status handler, which the driver calls +* when it encounters conditions that should be reported to the higher layer +* software. The handler executes in an interrupt context, so it must minimize +* the amount of processing performed such as transferring data to a thread +* context. One of the following status events is passed to the status handler. +*
+* - XST_SPI_MODE_FAULT A mode fault error occurred, meaning another +* master tried to select this device as a slave +* when this device was configured to be a master. +* Any transfer in progress is aborted. +* +* - XST_SPI_TRANSFER_DONE The requested data transfer is done +* +* - XST_SPI_TRANSMIT_UNDERRUN As a slave device, the master clocked +* data but there were none available in the +* transmit register/FIFO. This typically means the +* slave application did not issue a transfer +* request fast enough, or the processor/driver +* could not fill the transmit register/FIFO fast +* enough. +* +* - XST_SPI_RECEIVE_OVERRUN The SPI device lost data. Data was received +* but the receive data register/FIFO was full. +* This indicates that the device is receiving data +* faster than the processor/driver can consume it. +* +* - XST_SPI_SLAVE_MODE_FAULT A slave SPI device was selected as a slave while +* it was disabled. This indicates the master is +* already transferring data (which is being +* dropped until the slave application issues a +* transfer). +*+* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param CallBackRef is the upper layer callback reference passed back +* when the callback function is invoked. +* @param FuncPtr is the pointer to the callback function. +* +* @return None. +* +* @note +* +* The handler is called within interrupt context, so it should do its work +* quickly and queue potentially time-consuming work to a task-level thread. +* +******************************************************************************/ +void XSpi_SetStatusHandler(XSpi *InstancePtr, void *CallBackRef, + XSpi_StatusHandler FuncPtr) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FuncPtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + InstancePtr->StatusHandler = FuncPtr; + InstancePtr->StatusRef = CallBackRef; +} + +/*****************************************************************************/ +/** +* +* This is a stub for the status callback. The stub is here in case the upper +* layers forget to set the handler. +* +* @param CallBackRef is a pointer to the upper layer callback reference +* @param StatusEvent is the event that just occurred. +* @param ByteCount is the number of bytes transferred up until the event +* occurred. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void StubStatusHandler(void *CallBackRef, u32 StatusEvent, + unsigned int ByteCount) +{ + (void )CallBackRef; + (void )StatusEvent; + (void ) ByteCount; + Xil_AssertVoidAlways(); +} + +/*****************************************************************************/ +/** +* +* The interrupt handler for SPI interrupts. This function must be connected +* by the user to an interrupt source. This function does not save and restore +* the processor context such that the user must provide this processing. +* +* The interrupts that are handled are: +* +* - Mode Fault Error. This interrupt is generated if this device is selected +* as a slave when it is configured as a master. The driver aborts any data +* transfer that is in progress by resetting FIFOs (if present) and resetting +* its buffer pointers. The upper layer software is informed of the error. +* +* - Data Transmit Register (FIFO) Empty. This interrupt is generated when the +* transmit register or FIFO is empty. The driver uses this interrupt during a +* transmission to continually send/receive data until there is no more data +* to send/receive. +* +* - Data Transmit Register (FIFO) Underrun. This interrupt is generated when +* the SPI device, when configured as a slave, attempts to read an empty +* DTR/FIFO. An empty DTR/FIFO usually means that software is not giving the +* device data in a timely manner. No action is taken by the driver other than +* to inform the upper layer software of the error. +* +* - Data Receive Register (FIFO) Overrun. This interrupt is generated when the +* SPI device attempts to write a received byte to an already full DRR/FIFO. +* A full DRR/FIFO usually means software is not emptying the data in a timely +* manner. No action is taken by the driver other than to inform the upper +* layer software of the error. +* +* - Slave Mode Fault Error. This interrupt is generated if a slave device is +* selected as a slave while it is disabled. No action is taken by the driver +* other than to inform the upper layer software of the error. +* +* - Command Error. This interrupt occurs when the first byte in the Tx FIFO, +* after the CS is asserted, doesn't match any command in the Lookup table. +* This interrupt is valid only for axi_qspi. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return None. +* +* @note +* +* The slave select register is being set to deselect the slave when a transfer +* is complete. This is being done regardless of whether it is a slave or a +* master since the hardware does not drive the slave select as a slave. +* +******************************************************************************/ +void XSpi_InterruptHandler(void *InstancePtr) +{ + XSpi *SpiPtr = (XSpi *)InstancePtr; + u32 IntrStatus; + unsigned int BytesDone; /* number of bytes done so far */ + u32 Data = 0; + u32 ControlReg; + u32 StatusReg; + u8 DataWidth; + + Xil_AssertVoid(InstancePtr != NULL); + + /* + * Update the statistics for the number of interrupts. + */ + SpiPtr->Stats.NumInterrupts++; + + /* + * Get the Interrupt Status. Immediately clear the interrupts in case + * this Isr causes another interrupt to be generated. If we clear at the + * end of the Isr, we may miss this newly generated interrupt. This + * occurs because we transmit from within the Isr, potentially causing + * another TX_EMPTY interrupt. + */ + IntrStatus = XSpi_IntrGetStatus(SpiPtr); + XSpi_IntrClear(SpiPtr, IntrStatus); + + /* + * Check for mode fault error. We want to check for this error first, + * before checking for progress of a transfer, since this error needs + * to abort any operation in progress. + */ + if (IntrStatus & XSP_INTR_MODE_FAULT_MASK) { + BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes; + SpiPtr->Stats.ModeFaults++; + + /* + * Abort any operation currently in progress. This includes + * clearing the mode fault condition by reading the status + * register. + * Note that the status register should be read after the Abort + * since reading the status register clears the mode fault + * condition and would cause the device to restart any transfer + * that may be in progress. + */ + XSpi_Abort(SpiPtr); + + (void) XSpi_GetStatusReg(SpiPtr); + + SpiPtr->StatusHandler(SpiPtr->StatusRef, XST_SPI_MODE_FAULT, + BytesDone); + + return; /* Do not continue servicing other interrupts */ + } + + DataWidth = SpiPtr->DataWidth; + if ((IntrStatus & XSP_INTR_TX_EMPTY_MASK) || + (IntrStatus & XSP_INTR_TX_HALF_EMPTY_MASK)) { + + /* + * A transmit has just completed. Process received data and + * check for more data to transmit. Always inhibit the + * transmitter while the Isr re-fills the transmit + * register/FIFO, or make sure it is stopped if we're done. + */ + ControlReg = XSpi_GetControlReg(SpiPtr); + XSpi_SetControlReg(SpiPtr, ControlReg | + XSP_CR_TRANS_INHIBIT_MASK); + + /* + * First get the data received as a result of the transmit that + * just completed. We get all the data available by reading the + * status register to determine when the receive register/FIFO + * is empty. Always get the received data, but only fill the + * receive buffer if it points to something (the upper layer + * software may not care to receive data). + */ + StatusReg = XSpi_GetStatusReg(SpiPtr); + + while ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) { + + Data = XSpi_ReadReg(SpiPtr->BaseAddr, XSP_DRR_OFFSET); + + /* + * Data Transfer Width is Byte (8 bit). + */ + if (DataWidth == XSP_DATAWIDTH_BYTE) { + if (SpiPtr->RecvBufferPtr != NULL) { + *SpiPtr->RecvBufferPtr++ = (u8) Data; + } + } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { + if (SpiPtr->RecvBufferPtr != NULL) { + *(u16 *) SpiPtr->RecvBufferPtr = + (u16) Data; + SpiPtr->RecvBufferPtr +=2; + } + } else if (DataWidth == XSP_DATAWIDTH_WORD) { + if (SpiPtr->RecvBufferPtr != NULL) { + *(u32 *) SpiPtr->RecvBufferPtr = + Data; + SpiPtr->RecvBufferPtr +=4; + } + } + + SpiPtr->Stats.BytesTransferred += (DataWidth >> 3); + StatusReg = XSpi_GetStatusReg(SpiPtr); + } + + /* + * See if there is more data to send. + */ + if (SpiPtr->RemainingBytes > 0) { + /* + * Fill the DTR/FIFO with as many bytes as it will take + * (or as many as we have to send). We use the full + * status bit to know if the device can take more data. + * By doing this, the driver does not need to know the + * size of the FIFO or that there even is a FIFO. + * The downside is that the status must be read each + * loop iteration. + */ + StatusReg = XSpi_GetStatusReg(SpiPtr); + while (((StatusReg & XSP_SR_TX_FULL_MASK) == 0) && + (SpiPtr->RemainingBytes > 0)) { + if (DataWidth == XSP_DATAWIDTH_BYTE) { + /* + * Data Transfer Width is Byte (8 bit). + */ + Data = *SpiPtr->SendBufferPtr; + + } else if (DataWidth == + XSP_DATAWIDTH_HALF_WORD) { + /* + * Data Transfer Width is Half Word + * (16 bit). + */ + Data = *(u16 *) SpiPtr->SendBufferPtr; + } else if (DataWidth == + XSP_DATAWIDTH_WORD) { + /* + * Data Transfer Width is Word (32 bit). + */ + Data = *(u32 *) SpiPtr->SendBufferPtr; + } + + XSpi_WriteReg(SpiPtr->BaseAddr, XSP_DTR_OFFSET, + Data); + SpiPtr->SendBufferPtr += (DataWidth >> 3); + SpiPtr->RemainingBytes -= (DataWidth >> 3); + StatusReg = XSpi_GetStatusReg(SpiPtr); + } + + /* + * Start the transfer by not inhibiting the transmitter + * any longer. + */ + XSpi_SetControlReg(SpiPtr, ControlReg); + } else { + + /* + * Select the slave on the SPI bus when the transfer is + * complete, this is necessary for some SPI devices, + * such as serial EEPROMs work correctly as chip enable + * may be connected to slave select. + */ + XSpi_SetSlaveSelectReg(SpiPtr, + SpiPtr->SlaveSelectMask); + /* + * No more data to send. Disable the interrupt and + * inform the upper layer software that the transfer is + * done. The interrupt will be re-enabled when another + * transfer is initiated. + */ + XSpi_IntrDisable(SpiPtr, XSP_INTR_TX_EMPTY_MASK); + + SpiPtr->IsBusy = FALSE; + + SpiPtr->StatusHandler(SpiPtr->StatusRef, + XST_SPI_TRANSFER_DONE, + SpiPtr->RequestedBytes); + } + } + + /* + * Check if the device has been addressed as a slave. Report the status + * to the application layer. + */ + if (IntrStatus & XSP_INTR_SLAVE_MODE_MASK) { + SpiPtr->StatusHandler(SpiPtr->StatusRef, + XST_SPI_SLAVE_MODE, 0); + } + + /* + * Check if the device has received data from the master. Report the + * status to the application layer. + */ + if (IntrStatus & XSP_INTR_RX_NOT_EMPTY_MASK) { + SpiPtr->StatusHandler(SpiPtr->StatusRef, + XST_SPI_RECEIVE_NOT_EMPTY, 0); + } + + /* + * Check for slave mode fault. Simply report the error and update the + * statistics. + */ + if (IntrStatus & XSP_INTR_SLAVE_MODE_FAULT_MASK) { + BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes; + SpiPtr->Stats.SlaveModeFaults++; + SpiPtr->StatusHandler(SpiPtr->StatusRef, + XST_SPI_SLAVE_MODE_FAULT, BytesDone); + } + + /* + * Check for overrun error. Simply report the error and update the + * statistics. + */ + if (IntrStatus & XSP_INTR_RX_OVERRUN_MASK) { + BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes; + SpiPtr->Stats.RecvOverruns++; + SpiPtr->StatusHandler(SpiPtr->StatusRef, + XST_SPI_RECEIVE_OVERRUN, BytesDone); + } + + /* + * Check for underrun error. Simply report the error and update the + * statistics. + */ + if (IntrStatus & XSP_INTR_TX_UNDERRUN_MASK) { + BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes; + SpiPtr->Stats.XmitUnderruns++; + SpiPtr->StatusHandler(SpiPtr->StatusRef, + XST_SPI_TRANSMIT_UNDERRUN, BytesDone); + } + + /* + * Check for command error. Simply report the error and update the + * statistics. + */ + if (IntrStatus & XSP_INTR_CMD_ERR_MASK) { + BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes; + SpiPtr->Stats.XmitUnderruns++; + SpiPtr->StatusHandler(SpiPtr->StatusRef, + XST_SPI_COMMAND_ERROR, BytesDone); + } +} + +/*****************************************************************************/ +/** +* +* Aborts a transfer in progress by setting the stop bit in the control register, +* then resetting the FIFOs if present. The byte counts are cleared and the +* busy flag is set to false. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return None. +* +* @note +* +* This function does a read/modify/write of the control register. The user of +* this function needs to take care of critical sections. +* +******************************************************************************/ +void XSpi_Abort(XSpi *InstancePtr) +{ + u16 ControlReg; + + /* + * Deselect the slave on the SPI bus to abort a transfer, this must be + * done before the device is disabled such that the signals which are + * driven by the device are changed without the device enabled. + */ + XSpi_SetSlaveSelectReg(InstancePtr, + InstancePtr->SlaveSelectMask); + /* + * Abort the operation currently in progress. Clear the mode + * fault condition by reading the status register (done) then + * writing the control register. + */ + ControlReg = XSpi_GetControlReg(InstancePtr); + + /* + * Stop any transmit in progress and reset the FIFOs if they exist, + * don't disable the device just inhibit any data from being sent. + */ + ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; + + if (InstancePtr->HasFifos) { + ControlReg |= (XSP_CR_TXFIFO_RESET_MASK | + XSP_CR_RXFIFO_RESET_MASK); + } + + XSpi_SetControlReg(InstancePtr, ControlReg); + + InstancePtr->RemainingBytes = 0; + InstancePtr->RequestedBytes = 0; + InstancePtr->IsBusy = FALSE; +} + diff --git a/XilinxProcessorIPLib/drivers/spi/src/xspi.h b/XilinxProcessorIPLib/drivers/spi/src/xspi.h new file mode 100755 index 00000000..1ad3717b --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/src/xspi.h @@ -0,0 +1,835 @@ +/****************************************************************************** +* +* Copyright (C) 2001 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xspi.h +* +* This component contains the implementation of the XSpi component. It is the +* driver for an SPI master or slave device. It supports 8-bit, 16-bit and 32-bit +* wide data transfers. +* +* SPI is a 4-wire serial interface. It is a full-duplex, synchronous bus that +* facilitates communication between one master and one slave. The device is +* always full-duplex, which means that for every byte sent, one is received, and +* vice-versa. The master controls the clock, so it can regulate when it wants +* to send or receive data. The slave is under control of the master, it must +* respond quickly since it has no control of the clock and must send/receive +* data as fast or as slow as the master does. +* +* The application software between master and slave must implement a higher +* layer protocol so that slaves know what to transmit to the master and when. +* +* Initialization & Configuration +* +* The XSpi_Config structure is used by the driver to configure itself. This +* configuration structure is typically created by the tool-chain based on HW +* build properties. +* +* To support multiple runtime loading and initialization strategies employed +* by various operating systems, the driver instance can be initialized in one +* of the following ways: +* +* - XSpi_Initialize(InstancePtr, DeviceId) - The driver looks up its own +* configuration structure created by the tool-chain based on an ID provided +* by the tool-chain. +* +* - XSpi_CfgInitialize(InstancePtr, CfgPtr, EffectiveAddr) - Uses a +* configuration structure provided by the caller. If running in a system +* with address translation, the provided virtual memory base address +* replaces the physical address present in the configuration structure. +* +* Multiple Masters +* +* More than one master can exist, but arbitration is the responsibility of the +* higher layer software. The device driver does not perform any type of +* arbitration. +* +* Multiple Slaves +* +* Multiple slaves are supported by adding additional slave select (SS) signals +* to each device, one for each slave on the bus. The driver ensures that only +* one slave can be selected at any one time. +* +* FIFOs +* +* The SPI hardware is parameterized such that it can be built with or without +* FIFOs. When using FIFOs, both send and receive must have FIFOs. The driver +* will not function correctly if one direction has a FIFO but the other +* direction does not. The frequency of the interrupts which occur is +* proportional to the data rate such that high data rates without the FIFOs +* could cause the software to consume large amounts of processing time. The +* driver is designed to work with or without the FIFOs. +* +* Interrupts +* +* The user must connect the interrupt handler of the driver, +* XSpi_InterruptHandler to an interrupt system such that it will be called when +* an interrupt occurs. This function does not save and restore the processor +* context such that the user must provide this processing. +* +* The driver handles the following interrupts: +* - Data Transmit Register/FIFO Empty +* - Data Transmit FIFO Half Empty +* - Data Transmit Register/FIFO Underrun +* - Data Receive Register/FIFO Overrun +* - Mode Fault Error +* - Slave Mode Fault Error +* - Slave Mode Select +* - Data Receive FIFO not Empty +* +* The Data Transmit Register/FIFO Empty interrupt indicates that the SPI device +* has transmitted all the data available to transmit, and now its data register +* (or FIFO) is empty. The driver uses this interrupt to indicate progress while +* sending data. The driver may have more data to send, in which case the data +* transmit register (or FIFO) is filled for subsequent transmission. When this +* interrupt arrives and all the data has been sent, the driver invokes the +* status callback with a value of XST_SPI_TRANSFER_DONE to inform the upper +* layer software that all data has been sent. +* +* The Data Transmit FIFO Half Empty interrupt indicates that the SPI device has +* transmitted half of the data available, in the FIFO, to transmit. The driver +* uses this interrupt to indicate progress while sending data. The driver may +* have more data to send, in which case the data transmit FIFO is filled for +* subsequent transmission. This interrupt is particualrly useful in slave mode, +* while transfering more than FIFO_DEPTH number of bytes. In this case, the +* driver ensures that the FIFO is never empty during a transfer and avoids +* master receiving invalid data. +* +* The Data Transmit Register/FIFO Underrun interrupt indicates that, as slave, +* the SPI device was required to transmit but there was no data available to +* transmit in the transmit register (or FIFO). This may not be an error if the +* master is not expecting data, but in the case where the master is expecting +* data this serves as a notification of such a condition. The driver reports +* this condition to the upper layer software through the status handler. +* +* The Data Receive Register/FIFO Overrun interrupt indicates that the SPI device +* received data and subsequently dropped the data because the data receive +* register (or FIFO) was full. The interrupt applies to both master and slave +* operation. The driver reports this condition to the upper layer software +* through the status handler. This likely indicates a problem with the higher +* layer protocol, or a problem with the slave performance. +* +* The Mode Fault Error interrupt indicates that while configured as a master, +* the device was selected as a slave by another master. This can be used by the +* application for arbitration in a multimaster environment or to indicate a +* problem with arbitration. When this interrupt occurs, the driver invokes the +* status callback with a status value of XST_SPI_MODE_FAULT. It is up to the +* application to resolve the conflict. +* +* The Slave Mode Fault Error interrupt indicates that a slave device was +* selected as a slave by a master, but the slave device was disabled. This can +* be used during system debugging or by the slave application to learn when the +* slave application has not prepared for a master operation in a timely fashion. +* This likely indicates a problem with the higher layer protocol, or a problem +* with the slave performance. +* +* The Slave Mode Select interrupt indicates that the SPI device was selected as +* a slave by a master. The driver reports this condition to the upper layer +* software through the status handler. +* +* Data Receive FIFO not Empty interrupt indicates that the SPI device, in slave +* mode, has received a data byte in the Data Receive FIFO, after the master has +* started a transfer. The driver reports this condition to the upper layer +* software through the status handler. +* +* Polled Operation +* +* This driver operates in polled mode operation too. To put the driver in polled +* mode the Global Interrupt must be disabled after the Spi is Initialized and +* Spi driver is started. +* +* Statistics are not updated in this mode of operation. +* +* Device Busy +* +* Some operations are disallowed when the device is busy. The driver tracks +* whether a device is busy. The device is considered busy when a data transfer +* request is outstanding, and is considered not busy only when that transfer +* completes (or is aborted with a mode fault error). This applies to both +* master and slave devices. +* +* Device Configuration +* +* The device can be configured in various ways during the FPGA implementation +* process. Configuration parameters are stored in the xspi_g.c file or passed +* in via _CfgInitialize(). A table is defined where each entry contains +* configuration information for an SPI device. This information includes such +* things as the base address of the memory-mapped device, the number of slave +* select bits in the device, and whether the device has FIFOs and is configured +* as slave-only. +* +* RTOS Independence +* +* This driver is intended to be RTOS and processor independent. It works +* with physical addresses only. Any needs for dynamic memory management, +* threads or thread mutual exclusion, virtual memory, or cache control must +* be satisfied by the layer above this driver. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a rpm 10/11/01 First release +* 1.00b jhl 03/14/02 Repartitioned driver for smaller files. +* 1.01a jvb 12/14/05 I separated dependency on the static config table and +* xparameters.h from the driver initialization by moving +* _Initialize and _LookupConfig to _sinit.c. I also added +* the new _CfgInitialize routine. +* 1.11a wgr 03/22/07 Converted to new coding style. +* 1.11a sv 02/22/08 Added the definition of LSB-MSB first option in xspi_l.h. +* 1.12a sdm 03/22/08 Updated the code to support 16/32 bit transfer width and +* polled mode of operation, removed the macros in xspi_l.h, +* added macros in xspi.h file, moved the interrupt +* register/bit definitions from xspi_i.h to xpsi_l.h. +* Even for the polled mode of operation the Interrupt Logic +* in the core should be included. The driver can be put in +* polled mode of operation by disabling the Global Interrupt +* after the Spi Initialization is completed and Spi is +* started. +* 2.00a sdm 07/30/08 Updated the code to support 16/32 bit transfer width and +* polled mode of operation, removed the macros in xspi_l.h, +* added macros in xspi.h file, moved the interrupt +* register/bit definitions from xspi_i.h to xpsi_l.h. +* Even for the polled mode of operation the Interrupt Logic +* in the core should be included. The driver can be put in +* polled mode of operation by disabling the Global Interrupt +* after the Spi Initialization is completed and Spi is +* started. +* 2.01a sdm 08/22/08 Removed support for static interrupt handlers from the MDD +* file +* 2.01b sdm 04/08/09 Fixed an issue in the XSpi_Transfer function where the +* Global Interrupt is being enabled in polled mode when a +* slave is not selected. +* 3.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated driver to use the HAL APIs/macros. +* Removed the macro XSpi_mReset, XSpi_Reset API should be +* used in its place. +* The macros have been renamed to remove _m from the name +* XSpi_mIntrGlobalEnable is renamed XSpi_IntrGlobalEnable, +* XSpi_mIntrGlobalDisable is now XSpi_IntrGlobalDisable, +* XSpi_mIsIntrGlobalEnabled is now XSpi_IsIntrGlobalEnabled, +* XSpi_mIntrGetStatus is now XSpi_IntrGetStatus, +* XSpi_mIntrClear is now XSpi_IntrClear, +* XSpi_mIntrEnable is now XSpi_IntrEnable, +* XSpi_mIntrDisable is now XSpi_IntrDisable, +* XSpi_mIntrGetEnabled is now XSpi_IntrGetEnabled, +* XSpi_mSetControlReg is now XSpi_SetControlReg, +* XSpi_mGetControlReg is now XSpi_GetControlReg, +* XSpi_mGetStatusReg is now XSpi_GetStatusReg, +* XSpi_mSetSlaveSelectReg is now XSpi_SetSlaveSelectReg, +* XSpi_mGetSlaveSelectReg is now XSpi_GetSlaveSelectReg, +* XSpi_mEnable is now XSpi_Enable, +* XSpi_mDisable is now XSpi_Disable. +* 3.01a sdm 04/23/10 Updated the driver to handle new slave mode interrupts +* and the DTR Half Empty interrupt. +* 3.02a sdm 03/30/11 Updated to support axi_qspi. +* 3.03a sdm 08/09/11 Updated the selftest to check for a correct default value +* in the case of axi_qspi - CR 620502 +* Updated tcl to generate a config parameter for C_SPI_MODE +* 3.04a bss 03/21/12 Updated XSpi_Config and XSpi instance structure to support +* XIP Mode. +* Updated XSpi_CfgInitialize to support XIP Mode +* Added XIP Mode Register masks in xspi_l.h +* Tcl Script changes: +* Added C_TYPE_OF_AXI4_INTERFACE, C_AXI4_BASEADDR and +* C_XIP_MODE to config structure. +* Modified such that based on C_XIP_MODE and +* C_TYPE_OF_AXI4_INTERFACE parameters C_BASEADDR will +* be updated with C_AXI4_BASEADDR. +* Modified such that C_FIFO_EXIST will be updated based +* on C_FIFO_DEPTH for compatability of the driver with +* Axi Spi. +* 3.05a adk 18/04/13 Updated the code to avoid unused variable +* warnings when compiling with the -Wextra -Wall flags +* In the file xspi.c. CR:705005. +* 3.06a adk 07/08/13 Added a dummy read in the CfgInitialize(), if startup +* block is used in the h/w design (CR 721229). +* 3.07a adk 11/10/13 Fixed CR:732962 Changes are made in the xspi.c file +* 4.0 adk 19/12/13 Updated as per the New Tcl API's +* +* +*+* +******************************************************************************/ + +#ifndef XSPI_H /* prevent circular inclusions */ +#define XSPI_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xstatus.h" +#include "xspi_l.h" + +/************************** Constant Definitions *****************************/ + +/** @name Configuration options + * + * The following options may be specified or retrieved for the device and + * enable/disable additional features of the SPI. Each of the options + * are bit fields, so more than one may be specified. + * + * @{ + */ +/** + *
+ * The Master option configures the SPI device as a master. By default, the + * device is a slave. + * + * The Active Low Clock option configures the device's clock polarity. Setting + * this option means the clock is active low and the SCK signal idles high. By + * default, the clock is active high and SCK idles low. + * + * The Clock Phase option configures the SPI device for one of two transfer + * formats. A clock phase of 0, the default, means data if valid on the first + * SCK edge (rising or falling) after the slave select (SS) signal has been + * asserted. A clock phase of 1 means data is valid on the second SCK edge + * (rising or falling) after SS has been asserted. + * + * The Loopback option configures the SPI device for loopback mode. Data is + * looped back from the transmitter to the receiver. + * + * The Manual Slave Select option, which is default, causes the device not + * to automatically drive the slave select. The driver selects the device + * at the start of a transfer and deselects it at the end of a transfer. + * If this option is off, then the device automatically toggles the slave + * select signal between bytes in a transfer. + *+ */ +#define XSP_MASTER_OPTION 0x1 +#define XSP_CLK_ACTIVE_LOW_OPTION 0x2 +#define XSP_CLK_PHASE_1_OPTION 0x4 +#define XSP_LOOPBACK_OPTION 0x8 +#define XSP_MANUAL_SSELECT_OPTION 0x10 +/*@}*/ + +/**************************** Type Definitions *******************************/ + +/******************************************************************************/ +/** +* The handler data type allows the user to define a callback function to +* handle the asynchronous processing of the SPI driver. The application using +* this driver is expected to define a handler of this type to support interrupt +* driven mode. The handler executes in an interrupt context such that minimal +* processing should be performed. +* +* @param CallBackRef A callback reference passed in by the upper layer when +* setting the callback functions, and passed back to the +* upper layer when the callback is invoked. Its type is +* unimportant to the driver component, so it is a void +* pointer. +* @param StatusEvent Indicates one or more status events that occurred. See +* the XSpi_SetStatusHandler() for details on the status +* events that can be passed in the callback. +* @param ByteCount Indicates how many bytes of data were successfully +* transferred. This may be less than the number of bytes +* requested if the status event indicates an error. +* +*******************************************************************************/ +typedef void (*XSpi_StatusHandler) (void *CallBackRef, u32 StatusEvent, + unsigned int ByteCount); + +/** + * XSpi statistics + */ +typedef struct { + u32 ModeFaults; /**< Number of mode fault errors */ + u32 XmitUnderruns; /**< Number of transmit underruns */ + u32 RecvOverruns; /**< Number of receive overruns */ + u32 SlaveModeFaults; /**< Num of selects as slave while disabled */ + u32 BytesTransferred; /**< Number of bytes transferred */ + u32 NumInterrupts; /**< Number of transmit/receive interrupts */ +} XSpi_Stats; + +/** + * This typedef contains configuration information for the device. + */ +typedef struct { + u16 DeviceId; /**< Unique ID of device */ + u32 BaseAddress; /**< Base address of the device */ + int HasFifos; /**< Does device have FIFOs? */ + u32 SlaveOnly; /**< Is the device slave only? */ + u8 NumSlaveBits; /**< Num of slave select bits on the device */ + u8 DataWidth; /**< Data transfer Width */ + u8 SpiMode; /**< Standard/Dual/Quad mode */ + u8 AxiInterface; /**< AXI-Lite/AXI Full Interface */ + u32 AxiFullBaseAddress; /**< AXI Full Interface Base address of + the device */ + u8 XipMode; /**< 0 if Non-XIP, 1 if XIP Mode */ + u8 Use_Startup; /**< 1 if Starup block is used in h/w */ +} XSpi_Config; + +/** + * The XSpi driver instance data. The user is required to allocate a + * variable of this type for every SPI device in the system. A pointer + * to a variable of this type is then passed to the driver API functions. + */ +typedef struct { + XSpi_Stats Stats; /**< Statistics */ + u32 BaseAddr; /**< Base address of device (IPIF) */ + int IsReady; /**< Device is initialized and ready */ + int IsStarted; /**< Device has been started */ + int HasFifos; /**< Device is configured with FIFOs or not */ + u32 SlaveOnly; /**< Device is configured to be slave only */ + u8 NumSlaveBits; /**< Number of slave selects for this device */ + u8 DataWidth; /**< Data Transfer Width 8 or 16 or 32 */ + u8 SpiMode; /**< Standard/Dual/Quad mode */ + u32 SlaveSelectMask; /**< Mask that matches the number of SS bits */ + u32 SlaveSelectReg; /**< Slave select register */ + + u8 *SendBufferPtr; /**< Buffer to send */ + u8 *RecvBufferPtr; /**< Buffer to receive */ + unsigned int RequestedBytes; /**< Total bytes to transfer (state) */ + unsigned int RemainingBytes; /**< Bytes left to transfer (state) */ + int IsBusy; /**< A transfer is in progress (state) */ + + XSpi_StatusHandler StatusHandler; /**< Status Handler */ + void *StatusRef; /**< Callback reference for status handler */ + u32 FlashBaseAddr; /**< Used in XIP Mode */ + u8 XipMode; /**< 0 if Non-XIP, 1 if XIP Mode */ +} XSpi; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/******************************************************************************/ +/** +* +* This macro writes to the global interrupt enable register to enable +* interrupts from the device. +* +* Interrupts enabled using XSpi_IntrEnable() will not occur until the global +* interrupt enable bit is set by using this function. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return None. +* +* @note C-Style signature: +* void XSpi_IntrGlobalEnable(XSpi *InstancePtr); +* +******************************************************************************/ +#define XSpi_IntrGlobalEnable(InstancePtr) \ + XSpi_WriteReg(((InstancePtr)->BaseAddr), XSP_DGIER_OFFSET, \ + XSP_GINTR_ENABLE_MASK) + +/******************************************************************************/ +/** +* +* This macro disables all interrupts for the device by writing to the Global +* interrupt enable register. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return None. +* +* @note C-Style signature: +* void XSpi_IntrGlobalDisable(XSpi *InstancePtr); +* +******************************************************************************/ +#define XSpi_IntrGlobalDisable(InstancePtr) \ + XSpi_WriteReg(((InstancePtr)->BaseAddr), XSP_DGIER_OFFSET, 0) + +/*****************************************************************************/ +/** +* +* This function determines if interrupts are enabled at the global level by +* reading the global interrupt register. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return +* - TRUE if global interrupts are enabled. +* - FALSE if global interrupts are disabled. +* +* @note C-Style signature: +* int XSpi_IsIntrGlobalEnabled(XSpi *InstancePtr); +* +******************************************************************************/ +#define XSpi_IsIntrGlobalEnabled(InstancePtr) \ + (XSpi_ReadReg(((InstancePtr)->BaseAddr), XSP_DGIER_OFFSET) == \ + XSP_GINTR_ENABLE_MASK) + +/*****************************************************************************/ +/** +* +* This function gets the contents of the Interrupt Status Register. +* This register indicates the status of interrupt sources for the device. +* The status is independent of whether interrupts are enabled such +* that the status register may also be polled when interrupts are not enabled. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return A status which contains the value read from the Interrupt +* Status Register. +* +* @note C-Style signature: +* u32 XSpi_IntrGetStatus(XSpi *InstancePtr); +* +******************************************************************************/ +#define XSpi_IntrGetStatus(InstancePtr) \ + XSpi_ReadReg(((InstancePtr)->BaseAddr), XSP_IISR_OFFSET) + +/*****************************************************************************/ +/** +* +* This function clears the specified interrupts in the Interrupt status +* Register. The interrupt is cleared by writing to this register with the bits +* to be cleared set to a one and all others bits to zero. Setting a bit which +* is zero within this register causes an interrupt to be generated. +* +* This function writes only the specified value to the register such that +* some status bits may be set and others cleared. It is the caller's +* responsibility to get the value of the register prior to setting the value +* to prevent an destructive behavior. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param ClearMask is the Bitmask for interrupts to be cleared. +* Bit positions of "1" clears the interrupt. Bit positions of 0 +* will keep the previous setting. This mask is formed by OR'ing +* XSP_INTR_* bits defined in xspi_l.h. +* +* @return None. +* +* @note C-Style signature: +* void XSpi_IntrClear(XSpi *InstancePtr, u32 ClearMask); +* +******************************************************************************/ +#define XSpi_IntrClear(InstancePtr, ClearMask) \ + XSpi_WriteReg(((InstancePtr)->BaseAddr), XSP_IISR_OFFSET, \ + XSpi_IntrGetStatus(InstancePtr) | (ClearMask)) + + +/******************************************************************************/ +/** +* +* This function sets the contents of the Interrupt Enable Register. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param EnableMask is the bitmask of the interrupts to be enabled. +* Bit positions of 1 will be enabled. Bit positions of 0 will +* keep the previous setting. This mask is formed by OR'ing +* XSP_INTR_* bits defined in xspi_l.h. +* +* @return None. +* +* @note C-Style signature: +* void XSpi_IntrEnable(XSpi *InstancePtr, u32 EnableMask); +* +******************************************************************************/ +#define XSpi_IntrEnable(InstancePtr, EnableMask) \ + XSpi_WriteReg(((InstancePtr)->BaseAddr), XSP_IIER_OFFSET, \ + (XSpi_ReadReg(((InstancePtr)->BaseAddr), \ + XSP_IIER_OFFSET)) | (((EnableMask) & XSP_INTR_ALL ))) + +/****************************************************************************/ +/** +* +* Disable the specified Interrupts in the Interrupt Enable Register. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param DisableMask is the bitmask of the interrupts to be disabled. +* Bit positions of 1 will be disabled. Bit positions of 0 will +* keep the previous setting. This mask is formed by OR'ing +* XSP_INTR_* bits defined in xspi_l.h. +* +* @return None. +* +* @note C-Style signature: +* void XSpi_IntrDisable(XSpi *InstancePtr, u32 DisableMask); +* +******************************************************************************/ +#define XSpi_IntrDisable(InstancePtr, DisableMask) \ + XSpi_WriteReg(((InstancePtr)->BaseAddr), XSP_IIER_OFFSET, \ + XSpi_ReadReg(((InstancePtr)->BaseAddr), \ + XSP_IIER_OFFSET) & (~ ((DisableMask) & XSP_INTR_ALL ))) + + +/*****************************************************************************/ +/** +* +* This function gets the contents of the Interrupt Enable Register. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return The contents read from the Interrupt Enable Register. +* +* @note C-Style signature: +* u32 XSpi_IntrGetEnabled(XSpi *InstancePtr) +* +******************************************************************************/ +#define XSpi_IntrGetEnabled(InstancePtr) \ + XSpi_ReadReg(((InstancePtr)->BaseAddr), XSP_IIER_OFFSET) + +/****************************************************************************/ +/** +* +* Set the contents of the control register. Use the XSP_CR_* constants defined +* above to create the bit-mask to be written to the register. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param Mask is the 32-bit value to write to the control register. +* +* @return None. +* +* @note C-Style signature: +* void XSpi_SetControlReg(XSpi *InstancePtr, u32 Mask); +* +*****************************************************************************/ +#define XSpi_SetControlReg(InstancePtr, Mask) \ + XSpi_WriteReg(((InstancePtr)->BaseAddr), XSP_CR_OFFSET, (Mask)) + +/****************************************************************************/ +/** +* +* Get the contents of the control register. Use the XSP_CR_* constants defined +* above to interpret the bit-mask returned. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return A 32-bit value representing the contents of the control +* register. +* +* @note C-Style signature: +* u32 XSpi_GetControlReg(XSpi *InstancePtr); +* +*****************************************************************************/ +#define XSpi_GetControlReg(InstancePtr) \ + XSpi_ReadReg(((InstancePtr)->BaseAddr), XSP_CR_OFFSET) + +/***************************************************************************/ +/** +* +* Get the contents of the status register. Use the XSP_SR_* constants defined +* above to interpret the bit-mask returned. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return An 32-bit value representing the contents of the status +* register. +* +* @note C-Style signature: +* u8 XSpi_GetStatusReg(XSpi *InstancePtr); +* +*****************************************************************************/ +#define XSpi_GetStatusReg(InstancePtr) \ + XSpi_ReadReg(((InstancePtr)->BaseAddr), XSP_SR_OFFSET) + +/****************************************************************************/ +/** +* +* Set the contents of the XIP control register. Use the XSP_CR_XIP_* constants +* defined above to create the bit-mask to be written to the register. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param Mask is the 32-bit value to write to the control register. +* +* @return None. +* +* @note C-Style signature: +* void XSpi_SetXipControlReg(XSpi *InstancePtr, u32 Mask); +* +*****************************************************************************/ +#define XSpi_SetXipControlReg(InstancePtr, Mask) \ + XSpi_WriteReg(((InstancePtr)->BaseAddr), XSP_CR_OFFSET, (Mask)) + +/****************************************************************************/ +/** +* +* Get the contents of the XIP control register. Use the XSP_CR_XIP_* constants +* defined above to interpret the bit-mask returned. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return A 32-bit value representing the contents of the control +* register. +* +* @note C-Style signature: +* u32 XSpi_GetXipControlReg(XSpi *InstancePtr); +* +*****************************************************************************/ +#define XSpi_GetXipControlReg(InstancePtr) \ + XSpi_ReadReg(((InstancePtr)->BaseAddr), XSP_CR_OFFSET) + +/****************************************************************************/ +/** +* +* Get the contents of the status register. Use the XSP_SR_XIP_* constants +* defined above to interpret the bit-mask returned. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return An 32-bit value representing the contents of the status +* register. +* +* @note C-Style signature: +* u8 XSpi_GetXipStatusReg(XSpi *InstancePtr); +* +*****************************************************************************/ +#define XSpi_GetXipStatusReg(InstancePtr) \ + XSpi_ReadReg(((InstancePtr)->BaseAddr), XSP_SR_OFFSET) + +/****************************************************************************/ +/** +* +* Set the contents of the slave select register. Each bit in the mask +* corresponds to a slave select line. Only one slave should be selected at +* any one time. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param Mask is the 32-bit value to write to the slave select register. +* +* @return None. +* +* @note C-Style signature: +* void XSpi_SetSlaveSelectReg(XSpi *InstancePtr, u32 Mask); +* +*****************************************************************************/ +#define XSpi_SetSlaveSelectReg(InstancePtr, Mask) \ + XSpi_WriteReg(((InstancePtr)->BaseAddr), XSP_SSR_OFFSET, (Mask)) + +/****************************************************************************/ +/** +* +* Get the contents of the slave select register. Each bit in the mask +* corresponds to a slave select line. Only one slave should be selected at +* any one time. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return The 32-bit value in the slave select register. +* +* @note C-Style signature: +* u32 XSpi_GetSlaveSelectReg(XSpi *InstancePtr); +* +*****************************************************************************/ +#define XSpi_GetSlaveSelectReg(InstancePtr) \ + XSpi_ReadReg((InstancePtr)->BaseAddr, XSP_SSR_OFFSET) + +/****************************************************************************/ +/** +* +* Enable the device and uninhibit master transactions. Preserves the current +* contents of the control register. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return None. +* +* @note C-Style signature: +* void XSpi_Enable(XSpi *InstancePtr); +* +*****************************************************************************/ +#define XSpi_Enable(InstancePtr) \ +{ \ + u16 Control; \ + Control = XSpi_GetControlReg((InstancePtr)); \ + Control |= XSP_CR_ENABLE_MASK; \ + Control &= ~XSP_CR_TRANS_INHIBIT_MASK; \ + XSpi_SetControlReg((InstancePtr), Control); \ +} + +/****************************************************************************/ +/** +* +* Disable the device. Preserves the current contents of the control register. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return None. +* +* @note C-Style signature: +* void XSpi_Disable(XSpi *InstancePtr); +* +*****************************************************************************/ +#define XSpi_Disable(InstancePtr) \ + XSpi_SetControlReg((InstancePtr), \ + XSpi_GetControlReg((InstancePtr)) & ~XSP_CR_ENABLE_MASK) + +/************************** Function Prototypes ******************************/ + +/* + * Initialization functions in xspi_sinit.c + */ +int XSpi_Initialize(XSpi *InstancePtr, u16 DeviceId); +XSpi_Config *XSpi_LookupConfig(u16 DeviceId); + +/* + * Functions, in xspi.c + */ +int XSpi_CfgInitialize(XSpi *InstancePtr, XSpi_Config * Config, + u32 EffectiveAddr); + +int XSpi_Start(XSpi *InstancePtr); +int XSpi_Stop(XSpi *InstancePtr); + +void XSpi_Reset(XSpi *InstancePtr); + +int XSpi_SetSlaveSelect(XSpi *InstancePtr, u32 SlaveMask); +u32 XSpi_GetSlaveSelect(XSpi *InstancePtr); + +int XSpi_Transfer(XSpi *InstancePtr, u8 *SendBufPtr, u8 *RecvBufPtr, + unsigned int ByteCount); + +void XSpi_SetStatusHandler(XSpi *InstancePtr, void *CallBackRef, + XSpi_StatusHandler FuncPtr); +void XSpi_InterruptHandler(void *InstancePtr); + + +/* + * Functions for selftest, in xspi_selftest.c + */ +int XSpi_SelfTest(XSpi *InstancePtr); + +/* + * Functions for statistics, in xspi_stats.c + */ +void XSpi_GetStats(XSpi *InstancePtr, XSpi_Stats *StatsPtr); +void XSpi_ClearStats(XSpi *InstancePtr); + +/* + * Functions for options, in xspi_options.c + */ +int XSpi_SetOptions(XSpi *InstancePtr, u32 Options); +u32 XSpi_GetOptions(XSpi *InstancePtr); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/spi/src/xspi_g.c b/XilinxProcessorIPLib/drivers/spi/src/xspi_g.c new file mode 100755 index 00000000..3c788282 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/src/xspi_g.c @@ -0,0 +1,104 @@ +/****************************************************************************** +* +* Copyright (C) 2001 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xspi_g.c +* +* This file contains a configuration table that specifies the configuration of +* SPI devices in the system. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a rpm 10/11/01 First release +* 1.00b jhl 03/14/02 Repartitioned driver for smaller files. +* 1.00b rpm 04/24/02 Condensed config typedef - got rid of versions and +* multiple base addresses. +* 1.11a wgr 03/22/07 Converted to new coding style. +* 1.12a sv 03/17/08 Updated the code to support 16/32 bit transfer width. +* 2.00a sv 07/30/08 Updated the code to support 16/32 bit transfer width. +* 3.02a sdm 05/04/11 Added a new parameter for the mode in which SPI device +* operates. +* 3.06a adk 07/08/13 Added a new parmeter for the startup block +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xspi.h" +#include "xparameters.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Prototypes ******************************/ + +/** + * This table contains configuration information for each SPI device + * in the system. + */ +XSpi_Config XSpi_ConfigTable[XPAR_XSPI_NUM_INSTANCES] = { + { + XPAR_SPI_0_DEVICE_ID, /* Device ID for instance */ + XPAR_SPI_0_BASEADDR, /* Device base address */ + XPAR_SPI_0_FIFO_EXIST, /* Does device have FIFOs? */ + XPAR_SPI_0_SLAVE_ONLY, /* Is the device slave only? */ + XPAR_SPI_0_NUM_SS_BITS, /* Number of slave select bits */ + XPAR_SPI_0_NUM_TRANSFER_BITS /* Transfer Data width */ + XPAR_SPI_0_SPI_MODE /* standard/dual/quad mode */ + XPAR_SPI_0_USE_STARTUP /* Startup Parameter */ + } + , + { + XPAR_SPI_1_DEVICE_ID, /* Device ID for instance */ + XPAR_SPI_1_BASEADDR, /* Device base address */ + XPAR_SPI_1_FIFO_EXIST, /* Does device have FIFOs? */ + XPAR_SPI_1_SLAVE_ONLY, /* Is the device slave only? */ + XPAR_SPI_1_NUM_SS_BITS, /* Number of slave select bits */ + XPAR_SPI_1_NUM_TRANSFER_BITS /* Transfer Data width */ + XPAR_SPI_1_SPI_MODE /* standard/dual/quad mode */ + XPAR_SPI_0_USE_STARTUP /* Startup Parameter */ + } +}; diff --git a/XilinxProcessorIPLib/drivers/spi/src/xspi_i.h b/XilinxProcessorIPLib/drivers/spi/src/xspi_i.h new file mode 100755 index 00000000..6fa3f9f7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/src/xspi_i.h @@ -0,0 +1,88 @@ +/****************************************************************************** +* +* Copyright (C) 2001 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xspi_i.h +* +* This header file contains internal identifiers. It is intended for internal +* use only. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a rpm 10/11/01 First release +* 1.00b jhl 03/14/02 Repartitioned driver for smaller files. +* 1.00b rpm 04/24/02 Moved register definitions to xspi_l.h +* 1.11a wgr 03/22/07 Converted to new coding style. +* 1.12a sv 03/28/08 Removed the Macro for statistics, moved the interrupt +* register definitions and bit definitions to _l.h. +* 2.00a sv 07/30/08 Removed the Macro for statistics, moved the interrupt +* register definitions and bit definitions to _l.h. +*+* +******************************************************************************/ + +#ifndef XSPI_I_H /* prevent circular inclusions */ +#define XSPI_I_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xspi_l.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +void XSpi_Abort(XSpi *InstancePtr); + +/************************** Variable Definitions *****************************/ + +extern XSpi_Config XSpi_ConfigTable[]; + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/spi/src/xspi_l.h b/XilinxProcessorIPLib/drivers/spi/src/xspi_l.h new file mode 100755 index 00000000..54130c14 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/src/xspi_l.h @@ -0,0 +1,363 @@ +/****************************************************************************** +* +* Copyright (C) 2001 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xspi_l.h +* +* This header file contains identifiers, Register Definitions and basic driver +* functions (or macros) that can be used to access the device. +* Refer xspi.h for information about the driver. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00b rpm 04/24/02 First release +* 1.11a wgr 03/22/07 Converted to new coding style. +* 1.11a sv 02/22/08 Added the definition of LSB-MSB first option. +* 1.12a sv 03/28/08 Removed macros in _l.h file, moved the +* interrupt register definitions from _i.h to _l.h. +* 2.00a sv 07/30/08 Removed macros in _l.h file, moved the +* interrupt register definitions from _i.h to _l.h. +* 3.00a ktn 10/28/09 Updated all the register accesses as 32 bit access. +* Added XSpi_ReadReg and XSpi_WriteReg macros. +* 3.01a sdm 04/23/10 Added definitions for the new slave mode interrupts. +* 3.02a sdm 03/30/11 Added definitions for the new register bits in axi_qspi. +* 3.04a bss 03/21/12 Added XIP Mode Register masks +* +*+* +******************************************************************************/ + +#ifndef XSPI_L_H /* prevent circular inclusions */ +#define XSPI_L_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xil_io.h" + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + +#define XSpi_In32 Xil_In32 +#define XSpi_Out32 Xil_Out32 + +/****************************************************************************/ +/** +* +* Read from the specified Spi device register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to select the specific register. +* +* @return The value read from the register. +* +* @note C-Style signature: +* u32 XSpi_ReadReg(u32 BaseAddress, u32 RegOffset); +* +******************************************************************************/ +#define XSpi_ReadReg(BaseAddress, RegOffset) \ + XSpi_In32((BaseAddress) + (RegOffset)) + +/***************************************************************************/ +/** +* +* Write to the specified Spi device register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to select the specific register. +* @param RegisterValue is the value to be written to the register. +* +* @return None. +* +* @note C-Style signature: +* void XSpi_WriteReg(u32 BaseAddress, u32 RegOffset, +* u32 RegisterValue); +******************************************************************************/ +#define XSpi_WriteReg(BaseAddress, RegOffset, RegisterValue) \ + XSpi_Out32((BaseAddress) + (RegOffset), (RegisterValue)) + +/************************** Function Prototypes ******************************/ + +/************************** Constant Definitions *****************************/ + +/** + * XSPI register offsets + */ +/** @name Register Map + * + * Register offsets for the XSpi device. + * @{ + */ +#define XSP_DGIER_OFFSET 0x1C /**< Global Intr Enable Reg */ +#define XSP_IISR_OFFSET 0x20 /**< Interrupt status Reg */ +#define XSP_IIER_OFFSET 0x28 /**< Interrupt Enable Reg */ +#define XSP_SRR_OFFSET 0x40 /**< Software Reset register */ +#define XSP_CR_OFFSET 0x60 /**< Control register */ +#define XSP_SR_OFFSET 0x64 /**< Status Register */ +#define XSP_DTR_OFFSET 0x68 /**< Data transmit */ +#define XSP_DRR_OFFSET 0x6C /**< Data receive */ +#define XSP_SSR_OFFSET 0x70 /**< 32-bit slave select */ +#define XSP_TFO_OFFSET 0x74 /**< Tx FIFO occupancy */ +#define XSP_RFO_OFFSET 0x78 /**< Rx FIFO occupancy */ + +/* @} */ + + +/** + * @name Global Interrupt Enable Register (GIER) mask(s) + * @{ + */ +#define XSP_GINTR_ENABLE_MASK 0x80000000 /**< Global interrupt enable */ + +/* @} */ + + +/** @name SPI Device Interrupt Status/Enable Registers + * + * Interrupt Status Register (IPISR) + * + * This register holds the interrupt status flags for the Spi device. + * + * Interrupt Enable Register (IPIER) + * + * This register is used to enable interrupt sources for the Spi device. + * Writing a '1' to a bit in this register enables the corresponding Interrupt. + * Writing a '0' to a bit in this register disables the corresponding Interrupt. + * + * ISR/IER registers have the same bit definitions and are only defined once. + * @{ + */ +#define XSP_INTR_MODE_FAULT_MASK 0x00000001 /**< Mode fault error */ +#define XSP_INTR_SLAVE_MODE_FAULT_MASK 0x00000002 /**< Selected as slave while + * disabled */ +#define XSP_INTR_TX_EMPTY_MASK 0x00000004 /**< DTR/TxFIFO is empty */ +#define XSP_INTR_TX_UNDERRUN_MASK 0x00000008 /**< DTR/TxFIFO underrun */ +#define XSP_INTR_RX_FULL_MASK 0x00000010 /**< DRR/RxFIFO is full */ +#define XSP_INTR_RX_OVERRUN_MASK 0x00000020 /**< DRR/RxFIFO overrun */ +#define XSP_INTR_TX_HALF_EMPTY_MASK 0x00000040 /**< TxFIFO is half empty */ +#define XSP_INTR_SLAVE_MODE_MASK 0x00000080 /**< Slave select mode */ +#define XSP_INTR_RX_NOT_EMPTY_MASK 0x00000100 /**< RxFIFO not empty */ + +/** + * The following bits are available only in axi_qspi Interrupt Status and + * Interrupt Enable registers. + */ +#define XSP_INTR_CPOL_CPHA_ERR_MASK 0x00000200 /**< CPOL/CPHA error */ +#define XSP_INTR_SLAVE_MODE_ERR_MASK 0x00000400 /**< Slave mode error */ +#define XSP_INTR_MSB_ERR_MASK 0x00000800 /**< MSB Error */ +#define XSP_INTR_LOOP_BACK_ERR_MASK 0x00001000 /**< Loop back error */ +#define XSP_INTR_CMD_ERR_MASK 0x00002000 /**< 'Invalid cmd' error */ + +/** + * Mask for all the interrupts in the IP Interrupt Registers. + */ +#define XSP_INTR_ALL (XSP_INTR_MODE_FAULT_MASK | \ + XSP_INTR_SLAVE_MODE_FAULT_MASK | \ + XSP_INTR_TX_EMPTY_MASK | \ + XSP_INTR_TX_UNDERRUN_MASK | \ + XSP_INTR_RX_FULL_MASK | \ + XSP_INTR_TX_HALF_EMPTY_MASK | \ + XSP_INTR_RX_OVERRUN_MASK | \ + XSP_INTR_SLAVE_MODE_MASK | \ + XSP_INTR_RX_NOT_EMPTY_MASK | \ + XSP_INTR_CMD_ERR_MASK | \ + XSP_INTR_LOOP_BACK_ERR_MASK | \ + XSP_INTR_MSB_ERR_MASK | \ + XSP_INTR_SLAVE_MODE_ERR_MASK | \ + XSP_INTR_CPOL_CPHA_ERR_MASK) + +/** + * The interrupts we want at startup. We add the TX_EMPTY interrupt in later + * when we're getting ready to transfer data. The others we don't care + * about for now. + */ +#define XSP_INTR_DFT_MASK (XSP_INTR_MODE_FAULT_MASK | \ + XSP_INTR_TX_UNDERRUN_MASK | \ + XSP_INTR_RX_OVERRUN_MASK | \ + XSP_INTR_SLAVE_MODE_FAULT_MASK | \ + XSP_INTR_CMD_ERR_MASK) +/* @} */ + +/** + * SPI Software Reset Register (SRR) mask. + */ +#define XSP_SRR_RESET_MASK 0x0000000A + + +/** @name SPI Control Register (CR) masks + * + * @{ + */ +#define XSP_CR_LOOPBACK_MASK 0x00000001 /**< Local loopback mode */ +#define XSP_CR_ENABLE_MASK 0x00000002 /**< System enable */ +#define XSP_CR_MASTER_MODE_MASK 0x00000004 /**< Enable master mode */ +#define XSP_CR_CLK_POLARITY_MASK 0x00000008 /**< Clock polarity high + or low */ +#define XSP_CR_CLK_PHASE_MASK 0x00000010 /**< Clock phase 0 or 1 */ +#define XSP_CR_TXFIFO_RESET_MASK 0x00000020 /**< Reset transmit FIFO */ +#define XSP_CR_RXFIFO_RESET_MASK 0x00000040 /**< Reset receive FIFO */ +#define XSP_CR_MANUAL_SS_MASK 0x00000080 /**< Manual slave select + assert */ +#define XSP_CR_TRANS_INHIBIT_MASK 0x00000100 /**< Master transaction + inhibit */ + +/** + * LSB/MSB first data format select. The default data format is MSB first. + * The LSB first data format is not available in all versions of the Xilinx Spi + * Device whereas the MSB first data format is supported by all the versions of + * the Xilinx Spi Devices. Please check the HW specification to see if this + * feature is supported or not. + */ +#define XSP_CR_LSB_MSB_FIRST_MASK 0x00000200 + +/* @} */ + +/** @name SPI Control Register (CR) masks for XIP Mode + * + * @{ + */ +#define XSP_CR_XIP_CLK_PHASE_MASK 0x00000001 /**< Clock phase 0 or 1 */ +#define XSP_CR_XIP_CLK_POLARITY_MASK 0x00000002 /**< Clock polarity + high or low */ + +/* @} */ + + + + +/** @name Status Register (SR) masks + * + * @{ + */ +#define XSP_SR_RX_EMPTY_MASK 0x00000001 /**< Receive Reg/FIFO is empty */ +#define XSP_SR_RX_FULL_MASK 0x00000002 /**< Receive Reg/FIFO is full */ +#define XSP_SR_TX_EMPTY_MASK 0x00000004 /**< Transmit Reg/FIFO is + empty */ +#define XSP_SR_TX_FULL_MASK 0x00000008 /**< Transmit Reg/FIFO is full */ +#define XSP_SR_MODE_FAULT_MASK 0x00000010 /**< Mode fault error */ +#define XSP_SR_SLAVE_MODE_MASK 0x00000020 /**< Slave mode select */ + +/* + * The following bits are available only in axi_qspi Status register. + */ +#define XSP_SR_CPOL_CPHA_ERR_MASK 0x00000040 /**< CPOL/CPHA error */ +#define XSP_SR_SLAVE_MODE_ERR_MASK 0x00000080 /**< Slave mode error */ +#define XSP_SR_MSB_ERR_MASK 0x00000100 /**< MSB Error */ +#define XSP_SR_LOOP_BACK_ERR_MASK 0x00000200 /**< Loop back error */ +#define XSP_SR_CMD_ERR_MASK 0x00000400 /**< 'Invalid cmd' error */ + +/* @} */ + +/** @name Status Register (SR) masks for XIP Mode + * + * @{ + */ +#define XSP_SR_XIP_RX_EMPTY_MASK 0x00000001 /**< Receive Reg/FIFO + is empty */ +#define XSP_SR_XIP_RX_FULL_MASK 0x00000002 /**< Receive Reg/FIFO + is full */ +#define XSP_SR_XIP_MASTER_MODF_MASK 0x00000004 /**< Receive Reg/FIFO + is full */ +#define XSP_SR_XIP_CPHPL_ERROR_MASK 0x00000008 /**< Clock Phase,Clock + Polarity Error */ +#define XSP_SR_XIP_AXI_ERROR_MASK 0x00000010 /**< AXI Transaction + Error */ + +/* @} */ + + +/** @name SPI Transmit FIFO Occupancy (TFO) mask + * + * @{ + */ +/* The binary value plus one yields the occupancy.*/ +#define XSP_TFO_MASK 0x0000001F + +/* @} */ + +/** @name SPI Receive FIFO Occupancy (RFO) mask + * + * @{ + */ +/* The binary value plus one yields the occupancy.*/ +#define XSP_RFO_MASK 0x0000001F + +/* @} */ + +/** @name Data Width Definitions + * + * @{ + */ +#define XSP_DATAWIDTH_BYTE 8 /**< Tx/Rx Reg is Byte Wide */ +#define XSP_DATAWIDTH_HALF_WORD 16 /**< Tx/Rx Reg is Half Word (16 bit) + Wide */ +#define XSP_DATAWIDTH_WORD 32 /**< Tx/Rx Reg is Word (32 bit) Wide */ + +/* @} */ + +/** @name SPI Modes + * + * The following constants define the modes in which qxi_qspi operates. + * + * @{ + */ +#define XSP_STANDARD_MODE 0 +#define XSP_DUAL_MODE 1 +#define XSP_QUAD_MODE 2 + + /*@}*/ +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/spi/src/xspi_options.c b/XilinxProcessorIPLib/drivers/spi/src/xspi_options.c new file mode 100755 index 00000000..bffc8a60 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/src/xspi_options.c @@ -0,0 +1,222 @@ +/****************************************************************************** +* +* Copyright (C) 2001 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xspi_options.c +* +* Contains functions for the configuration of the XSpi driver component. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00b jhl 2/27/02 First release +* 1.00b rpm 04/25/02 Collapsed IPIF and reg base addresses into one +* 1.11a wgr 03/22/07 Converted to new coding style. +* 3.00a ktn 10/28/09 Updated all the register accesses as 32 bit access. +* Updated driver to use the HAL APIs/macros. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xspi.h" +#include "xspi_i.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + +/* + * Create the table of options which are processed to get/set the device + * options. These options are table driven to allow easy maintenance and + * expansion of the options. + */ +typedef struct { + u32 Option; + u32 Mask; +} OptionsMap; + +static OptionsMap OptionsTable[] = { + {XSP_LOOPBACK_OPTION, XSP_CR_LOOPBACK_MASK}, + {XSP_CLK_ACTIVE_LOW_OPTION, XSP_CR_CLK_POLARITY_MASK}, + {XSP_CLK_PHASE_1_OPTION, XSP_CR_CLK_PHASE_MASK}, + {XSP_MASTER_OPTION, XSP_CR_MASTER_MODE_MASK}, + {XSP_MANUAL_SSELECT_OPTION, XSP_CR_MANUAL_SS_MASK} +}; + +#define XSP_NUM_OPTIONS (sizeof(OptionsTable) / sizeof(OptionsMap)) + +/*****************************************************************************/ +/** +* +* This function sets the options for the SPI device driver. The options control +* how the device behaves relative to the SPI bus. The device must be idle +* rather than busy transferring data before setting these device options. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param Options contains the specified options to be set. This is a bit +* mask where a 1 means to turn the option on, and a 0 means to +* turn the option off. One or more bit values may be contained in +* the mask. +* See the bit definitions named XSP_*_OPTIONS in the file xspi.h. +* +* @return +* -XST_SUCCESS if options are successfully set. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting options. +* - XST_SPI_SLAVE_ONLY if the caller attempted to configure a +* slave-only device as a master. +* +* @note +* +* This function makes use of internal resources that are shared between the +* XSpi_Stop() and XSpi_SetOptions() functions. So if one task might be setting +* device options while another is trying to stop the device, the user is +* required to provide protection of this shared data (typically using a +* semaphore). +* +******************************************************************************/ +int XSpi_SetOptions(XSpi *InstancePtr, u32 Options) +{ + u32 ControlReg; + u32 Index; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Do not allow the slave select to change while a transfer is in + * progress. + * No need to worry about a critical section here since even if the Isr + * changes the busy flag just after we read it, the function will return + * busy and the caller can retry when notified that their current + * transfer is done. + */ + if (InstancePtr->IsBusy) { + return XST_DEVICE_BUSY; + } + /* + * Do not allow master option to be set if the device is slave only. + */ + if ((Options & XSP_MASTER_OPTION) && (InstancePtr->SlaveOnly)) { + return XST_SPI_SLAVE_ONLY; + } + + ControlReg = XSpi_GetControlReg(InstancePtr); + + /* + * Loop through the options table, turning the option on or off + * depending on whether the bit is set in the incoming options flag. + */ + for (Index = 0; Index < XSP_NUM_OPTIONS; Index++) { + if (Options & OptionsTable[Index].Option) { + /* + *Turn it ON. + */ + ControlReg |= OptionsTable[Index].Mask; + } + else { + /* + *Turn it OFF. + */ + ControlReg &= ~OptionsTable[Index].Mask; + } + } + + /* + * Now write the control register. Leave it to the upper layers + * to restart the device. + */ + XSpi_SetControlReg(InstancePtr, ControlReg); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function gets the options for the SPI device. The options control how +* the device behaves relative to the SPI bus. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return +* +* Options contains the specified options to be set. This is a bit mask where a +* 1 means to turn the option on, and a 0 means to turn the option off. One or +* more bit values may be contained in the mask. See the bit definitions named +* XSP_*_OPTIONS in the file xspi.h. +* +* @note None. +* +******************************************************************************/ +u32 XSpi_GetOptions(XSpi *InstancePtr) +{ + u32 OptionsFlag = 0; + u32 ControlReg; + u32 Index; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Get the control register to determine which options are currently + * set. + */ + ControlReg = XSpi_GetControlReg(InstancePtr); + + /* + * Loop through the options table to determine which options are set. + */ + for (Index = 0; Index < XSP_NUM_OPTIONS; Index++) { + if (ControlReg & OptionsTable[Index].Mask) { + OptionsFlag |= OptionsTable[Index].Option; + } + } + + return OptionsFlag; +} diff --git a/XilinxProcessorIPLib/drivers/spi/src/xspi_selftest.c b/XilinxProcessorIPLib/drivers/spi/src/xspi_selftest.c new file mode 100755 index 00000000..6ade9bec --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/src/xspi_selftest.c @@ -0,0 +1,357 @@ +/****************************************************************************** +* +* Copyright (C) 2001 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xspi_selftest.c +* +* This component contains the implementation of selftest functions for the +* XSpi driver component. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00b jhl 2/27/02 First release +* 1.00b rpm 04/25/02 Collapsed IPIF and reg base addresses into one +* 1.11a wgr 03/22/07 Converted to new coding style. +* 1.12a sv 03/17/08 Updated the code to support 16/32 bit transfer width. +* 2.00a sv 07/30/08 Updated the code to support 16/32 bit transfer width. +* 3.00a sdm 10/28/09 Updated all the register accesses as 32 bit access. +* 3.02a sdm 05/04/11 Updated to run the loopback test only in standard spi +* mode. +* 3.03a sdm 08/09/11 Updated the selftest to check for a correct default value +* in the case of axi_qspi - CR 620502 +* 3.04a bss 03/21/12 Updated Selftest to check for XIP mode and return if XIP +* mode is true +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xspi.h" +#include "xspi_i.h" + +/************************** Constant Definitions *****************************/ + +#define XSP_SR_RESET_STATE 0x5 /* Default to Tx/Rx reg empty */ +#define XSP_CR_RESET_STATE 0x180 + +#define XSP_HALF_WORD_TESTBYTE 0x2200 /* Test Byte for Half Word */ +#define XSP_WORD_TESTBYTE 0xAA005500 /* Test Byte for Word */ + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +static int LoopbackTest(XSpi *InstancePtr); + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** +* +* Runs a self-test on the driver/device. The self-test is destructive in that +* a reset of the device is performed in order to check the reset values of +* the registers and to get the device into a known state. A simple loopback +* test is also performed to verify that transmit and receive are working +* properly. The device is changed to master mode for the loopback test, since +* only a master can initiate a data transfer. +* +* Upon successful return from the self-test, the device is reset. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return +* - XST_SUCCESS if successful. +* - XST_REGISTER_ERROR indicates a register did not read or write +* correctly. +* - XST_LOOPBACK_ERROR if a loopback error occurred. +* +* @note None. +* +******************************************************************************/ +int XSpi_SelfTest(XSpi *InstancePtr) +{ + int Result; + u32 Register; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + + /* Return Success if XIP Mode */ + if((InstancePtr->XipMode) == 1) { + return XST_SUCCESS; + } + + /* + * Reset the SPI device to leave it in a known good state. + */ + XSpi_Reset(InstancePtr); + + if(InstancePtr->XipMode) + { + Register = XSpi_GetControlReg(InstancePtr); + if (Register != XSP_CR_RESET_STATE) { + return XST_REGISTER_ERROR; + } + + Register = XSpi_GetStatusReg(InstancePtr); + if ((Register & XSP_SR_RESET_STATE) != XSP_SR_RESET_STATE) { + return XST_REGISTER_ERROR; + } + } + + + + + /* + * All the SPI registers should be in their default state right now. + */ + Register = XSpi_GetControlReg(InstancePtr); + if (Register != XSP_CR_RESET_STATE) { + return XST_REGISTER_ERROR; + } + + Register = XSpi_GetStatusReg(InstancePtr); + if ((Register & XSP_SR_RESET_STATE) != XSP_SR_RESET_STATE) { + return XST_REGISTER_ERROR; + } + + /* + * Each supported slave select bit should be set to 1. + */ + Register = XSpi_GetSlaveSelectReg(InstancePtr); + if (Register != InstancePtr->SlaveSelectMask) { + return XST_REGISTER_ERROR; + } + + /* + * If configured with FIFOs, the occupancy values should be 0. + */ + if (InstancePtr->HasFifos) { + Register = XSpi_ReadReg(InstancePtr->BaseAddr, + XSP_TFO_OFFSET); + if (Register != 0) { + return XST_REGISTER_ERROR; + } + Register = XSpi_ReadReg(InstancePtr->BaseAddr, + XSP_RFO_OFFSET); + if (Register != 0) { + return XST_REGISTER_ERROR; + } + } + + /* + * Run loopback test only in case of standard SPI mode. + */ + if (InstancePtr->SpiMode != XSP_STANDARD_MODE) { + return XST_SUCCESS; + } + + /* + * Run an internal loopback test on the SPI. + */ + Result = LoopbackTest(InstancePtr); + if (Result != XST_SUCCESS) { + return Result; + } + + /* + * Reset the SPI device to leave it in a known good state. + */ + XSpi_Reset(InstancePtr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/* +* +* Runs an internal loopback test on the SPI device. This is done as a master +* with a enough data to fill the FIFOs if FIFOs are present. If the device is +* configured as a slave-only, this function returns successfully even though +* no loopback test is performed. +* +* This function does not restore the device context after performing the test +* as it assumes the device will be reset after the call. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return +* - XST_SUCCESS if loopback was performed successfully or not +* performed at all if device is slave-only. +* - XST_LOOPBACK_ERROR if loopback failed. +* +* @note None. +* +******************************************************************************/ +static int LoopbackTest(XSpi *InstancePtr) +{ + u32 StatusReg; + u32 ControlReg; + u32 Index; + u32 Data; + u32 RxData; + u32 NumSent = 0; + u32 NumRecvd = 0; + u8 DataWidth; + + /* + * Cannot run as a slave-only because we need to be master in order to + * initiate a transfer. Still return success, though. + */ + if (InstancePtr->SlaveOnly) { + return XST_SUCCESS; + } + + /* + * Setup the control register to enable master mode and the loopback so + * that data can be sent and received. + */ + ControlReg = XSpi_GetControlReg(InstancePtr); + XSpi_SetControlReg(InstancePtr, ControlReg | + XSP_CR_LOOPBACK_MASK | XSP_CR_MASTER_MODE_MASK); + /* + * We do not need interrupts for this loopback test. + */ + XSpi_IntrGlobalDisable(InstancePtr); + + DataWidth = InstancePtr->DataWidth; + /* + * Send data up to the maximum size of the transmit register, which is + * one byte without FIFOs. We send data 4 times just to exercise the + * device through more than one iteration. + */ + for (Index = 0; Index < 4; Index++) { + Data = 0; + + /* + * Fill the transmit register. + */ + StatusReg = XSpi_GetStatusReg(InstancePtr); + while ((StatusReg & XSP_SR_TX_FULL_MASK) == 0) { + if (DataWidth == XSP_DATAWIDTH_BYTE) { + /* + * Data Transfer Width is Byte (8 bit). + */ + Data = 0; + } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { + /* + * Data Transfer Width is Half Word (16 bit). + */ + Data = XSP_HALF_WORD_TESTBYTE; + } else if (DataWidth == XSP_DATAWIDTH_WORD){ + /* + * Data Transfer Width is Word (32 bit). + */ + Data = XSP_WORD_TESTBYTE; + } + + XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, + Data + Index); + NumSent += (DataWidth >> 3); + StatusReg = XSpi_GetStatusReg(InstancePtr); + } + + /* + * Start the transfer by not inhibiting the transmitter and + * enabling the device. + */ + ControlReg = XSpi_GetControlReg(InstancePtr) & + (~XSP_CR_TRANS_INHIBIT_MASK); + XSpi_SetControlReg(InstancePtr, ControlReg | + XSP_CR_ENABLE_MASK); + + /* + * Wait for the transfer to be done by polling the transmit + * empty status bit. + */ + do { + StatusReg = XSpi_GetStatusReg(InstancePtr); + } while ((StatusReg & XSP_SR_TX_EMPTY_MASK) == 0); + + /* + * Receive and verify the data just transmitted. + */ + while ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) { + + RxData = XSpi_ReadReg(InstancePtr->BaseAddr, + XSP_DRR_OFFSET); + + if (DataWidth == XSP_DATAWIDTH_BYTE) { + if((u8)RxData != Index) { + return XST_LOOPBACK_ERROR; + } + } else if (DataWidth == + XSP_DATAWIDTH_HALF_WORD) { + if((u16)RxData != (u16)(Index + + XSP_HALF_WORD_TESTBYTE)) { + return XST_LOOPBACK_ERROR; + } + } else if (DataWidth == XSP_DATAWIDTH_WORD) { + if(RxData != (u32)(Index + XSP_WORD_TESTBYTE)) { + return XST_LOOPBACK_ERROR; + } + } + + NumRecvd += (DataWidth >> 3); + StatusReg = XSpi_GetStatusReg(InstancePtr); + } + + /* + * Stop the transfer (hold off automatic sending) by inhibiting + * the transmitter and disabling the device. + */ + ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; + XSpi_SetControlReg(InstancePtr , + ControlReg & ~ XSP_CR_ENABLE_MASK); + } + + /* + * One final check to make sure the total number of bytes sent equals + * the total number of bytes received. + */ + if (NumSent != NumRecvd) { + return XST_LOOPBACK_ERROR; + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/spi/src/xspi_sinit.c b/XilinxProcessorIPLib/drivers/spi/src/xspi_sinit.c new file mode 100755 index 00000000..a1b85ca8 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/src/xspi_sinit.c @@ -0,0 +1,150 @@ +/****************************************************************************** +* +* Copyright (C) 2005 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xspi_sinit.c +* +* The implementation of the XSpi component's static initialization +* functionality. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.01a jvb 10/13/05 First release +* 1.11a wgr 03/22/07 Converted to new coding style. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xspi.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +extern XSpi_Config XSpi_ConfigTable[]; + +/*****************************************************************************/ +/** +* +* Looks up the device configuration based on the unique device ID. A table +* contains the configuration info for each device in the system. +* +* @param DeviceId contains the ID of the device to look up the +* configuration for. +* +* @return +* +* A pointer to the configuration found or NULL if the specified device ID was +* not found. See xspi.h for the definition of XSpi_Config. +* +* @note None. +* +******************************************************************************/ +XSpi_Config *XSpi_LookupConfig(u16 DeviceId) +{ + XSpi_Config *CfgPtr = NULL; + u32 Index; + + for (Index = 0; Index < XPAR_XSPI_NUM_INSTANCES; Index++) { + if (XSpi_ConfigTable[Index].DeviceId == DeviceId) { + CfgPtr = &XSpi_ConfigTable[Index]; + break; + } + } + + return CfgPtr; +} + +/*****************************************************************************/ +/** +* +* Initializes a specific XSpi instance such that the driver is ready to use. +* +* The state of the device after initialization is: +* - Device is disabled +* - Slave mode +* - Active high clock polarity +* - Clock phase 0 +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param DeviceId is the unique id of the device controlled by this XSpi +* instance. Passing in a device id associates the generic XSpi +* instance to a specific device, as chosen by the caller or +* application developer. +* +* @return +* +* - XST_SUCCESS if successful. +* - XST_DEVICE_IS_STARTED if the device is started. It must be +* stopped to re-initialize. +* - XST_DEVICE_NOT_FOUND if the device was not found in the +* configuration such that initialization could not be +* accomplished. +* +* @note None. +* +******************************************************************************/ +int XSpi_Initialize(XSpi *InstancePtr, u16 DeviceId) +{ + XSpi_Config *ConfigPtr; /* Pointer to Configuration ROM data */ + + Xil_AssertNonvoid(InstancePtr != NULL); + + /* + * Lookup the device configuration in the temporary CROM table. Use this + * configuration info down below when initializing this component. + */ + ConfigPtr = XSpi_LookupConfig(DeviceId); + if (ConfigPtr == NULL) { + return XST_DEVICE_NOT_FOUND; + } + + return XSpi_CfgInitialize(InstancePtr, ConfigPtr, + ConfigPtr->BaseAddress); + +} diff --git a/XilinxProcessorIPLib/drivers/spi/src/xspi_stats.c b/XilinxProcessorIPLib/drivers/spi/src/xspi_stats.c new file mode 100755 index 00000000..06600019 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/spi/src/xspi_stats.c @@ -0,0 +1,128 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xspi_stats.c +* +* This component contains the implementation of statistics functions for the +* XSpi driver component. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00b jhl 03/14/02 First release +* 1.00b rpm 04/25/02 Changed macro naming convention +* 1.11a wgr 03/22/07 Converted to new coding style. +* 1.12a sv 03/28/08 Removed the call to the Macro for clearing statistics. +* 2.00a sv 07/30/08 Removed the call to the Macro for clearing statistics. +* 3.00a ktn 10/28/09 Updated all the register accesses as 32 bit access. +* Updated driver to use the HAL APIs/macros. +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xspi.h" +#include "xspi_i.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** +* +* Gets a copy of the statistics for an SPI device. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* @param StatsPtr is a pointer to a XSpi_Stats structure which will get a +* copy of current statistics. +* +* @return None. +* +* @note Statistics are not updated in polled mode of operation. +* +******************************************************************************/ +void XSpi_GetStats(XSpi *InstancePtr, XSpi_Stats *StatsPtr) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(StatsPtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + StatsPtr->ModeFaults = InstancePtr->Stats.ModeFaults; + StatsPtr->XmitUnderruns = InstancePtr->Stats.XmitUnderruns; + StatsPtr->RecvOverruns = InstancePtr->Stats.RecvOverruns; + StatsPtr->SlaveModeFaults = InstancePtr->Stats.SlaveModeFaults; + StatsPtr->BytesTransferred = InstancePtr->Stats.BytesTransferred; + StatsPtr->NumInterrupts = InstancePtr->Stats.NumInterrupts; +} + +/*****************************************************************************/ +/** +* +* Clears the statistics for the SPI device. +* +* @param InstancePtr is a pointer to the XSpi instance to be worked on. +* +* @return None. +* +* @note Statistics are not updated in polled mode of operation. +* +******************************************************************************/ +void XSpi_ClearStats(XSpi *InstancePtr) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + InstancePtr->Stats.ModeFaults = 0; + InstancePtr->Stats.XmitUnderruns = 0; + InstancePtr->Stats.RecvOverruns = 0; + InstancePtr->Stats.SlaveModeFaults = 0; + InstancePtr->Stats.BytesTransferred = 0; + InstancePtr->Stats.NumInterrupts = 0; + +}