diff options
author | Michael Gielda <mgielda@antmicro.com> | 2014-04-03 14:53:04 +0200 |
---|---|---|
committer | Michael Gielda <mgielda@antmicro.com> | 2014-04-03 14:53:04 +0200 |
commit | ae1e4e08a1005a0c487f03ba189d7536e7fdcba6 (patch) | |
tree | f1c296f8a966a9a39876b0e98e16d9c5da1776dd /ecos/packages/devs/spi | |
parent | f157da5337118d3c5cd464266796de4262ac9dbd (diff) |
Added the OS files
Diffstat (limited to 'ecos/packages/devs/spi')
29 files changed, 7798 insertions, 0 deletions
diff --git a/ecos/packages/devs/spi/arm/at91/current/ChangeLog b/ecos/packages/devs/spi/arm/at91/current/ChangeLog new file mode 100644 index 0000000..23cfb31 --- /dev/null +++ b/ecos/packages/devs/spi/arm/at91/current/ChangeLog @@ -0,0 +1,113 @@ +2009-04-02 John Dallaway <john@dallaway.org.uk> + + * cdl/spi_at91.cdl: Fix typographical error for + CYGINT_DEVS_SPI_ARM_AT91_HAS_BUS1. [ Bugzilla 1000737 ] + +2009-02-16 Jonathan Larmour <jifl@eCosCentric.com> + + * src/spi_at91.c (cyg_spi_at91_bus_init): Partially revert change of + 2009-02-11. Define an empty CYGBLD_ATTRIB_C_INIT_PRI and rely on + spi_at91_init.cxx to call, in case the compiler does not supply + that macro (e.g. if too old). + * cdl/spi_at91.cdl: Revert change of 2009-02-11. + * src/spi_at91_init.cxx: Revive. Set priority to CYG_INIT_BUS_SPI. + Conditionalise on CYGBLD_ATTRIB_C_INIT_PRI. + +2009-02-12 Nick Garnett <nickg@ecoscentric.com> + + * cdl/spi_at91.cdl: Add a requires for CYGPKG_ERROR. + +2009-02-11 Bart Veer <bartv@ecoscentric.com> + + * src/spi_at91.c (cyg_spi_at91_bus_init): turn into a prioritized + constructor, make it a static and rename. + + * cdl/spi_at91.cdl: remove src/spi_at91_init.cxx + + * src/spi_at91_init.cxx: removed, no longer needed. + +2008-10-19 Igor B. Poretsky <poretsky@mlbox.ru> + + * src/spi_at91.c: Typo fixes from var_io.h. Correctly calculate + the board rate. Before it was two times too fast. + +2006-09-27 Andrew Lunn <andrew.lunn@ascom.ch> + + * src/spi_at91.c (spi_at91_transaction_begin): Don't use #ifdef + inside a macro invocation. The compiler throws a wobbly. + +2006-09-07 John Eigelaar <jeigelaar@mweb.co.za> + + * src/spi_at91.c: Fixed the chip select functions. + Changed the Mode Register setup as to disable the Mode Failure + Detaction for variants that support it. The Mode Failure Detection + breaks because NPCS0 is not connected, we are using GPIO, and is + thus floating. + +2006-06-01 John Eigelaar <jeigelaar@mweb.co.za> + + * src/spi_at91.c: + * cdl/spi_at91.cdl: + * include/spi_at91.h: Generalize so that multiple SPI + busses can be driven. + +2006-05-19 Andrew Lunn <andrew.lunn@ascom.ch> + + * src/spi_at91.c: Use the AT91 GPIO/PIO macros to aid + portability between different AT91 device. + +2004-11-11 Sebastian Block <sebastianblock@gmx.net> + + * src/spi_at91.c: Fixed negation of the chip select signal when + not using a 4 to 16 decoder + +2004-10-13 Savin Zlobec <savin@elatec.si> + + * src/spi_at91.c: Fixed a typo in spi_at91_transfer reported by + Nicolas Brouard. + +2004-08-31 Savin Zlobec <savin@elatec.si> + + * include/spi_at91.h: + * src/spi_at91.c: + Moved SPI registers and bits defines to HAL headers, added support + for 4 to 16 decoder of chip select signals, support for transfers + larger than 2^16 and per device configurable delay between two + transfers. + * cdl/spi_at91.cdl: + Added option to enable support for 4 to 16 decoder of chip select + signals. + +2004-08-27 Savin Zlobec <savin@elatec.si> + + * cdl/spi_at91.cdl: + * include/spi_at91.h: + * src/spi_at91.c: + * src/spi_at91_init.cxx: + Atmel AT91 SPI bus driver implementation. + + + +//=========================================================================== +// ####GPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2009 Free Software Foundation, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. +// ------------------------------------------- +// ####GPLCOPYRIGHTEND#### +//=========================================================================== diff --git a/ecos/packages/devs/spi/arm/at91/current/cdl/spi_at91.cdl b/ecos/packages/devs/spi/arm/at91/current/cdl/spi_at91.cdl new file mode 100644 index 0000000..e366daf --- /dev/null +++ b/ecos/packages/devs/spi/arm/at91/current/cdl/spi_at91.cdl @@ -0,0 +1,225 @@ +# ==================================================================== +# +# spi_at91.cdl +# +# Atmel AT91 (ARM) SPI driver configuration data +# +# ==================================================================== +## ####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 1998, 1999, 2000, 2001, 2002, 2009 Free Software Foundation, Inc. +## +## eCos is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free +## Software Foundation; either version 2 or (at your option) any later +## version. +## +## eCos is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with eCos; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## As a special exception, if other files instantiate templates or use +## macros or inline functions from this file, or you compile this file +## and link it with other works to produce a work based on this file, +## this file does not by itself cause the resulting work to be covered by +## the GNU General Public License. However the source code for this file +## must still be made available in accordance with section (3) of the GNU +## General Public License v2. +## +## This exception does not invalidate any other reasons why a work based +## on this file might be covered by the GNU General Public License. +## ------------------------------------------- +## ####ECOSGPLCOPYRIGHTEND#### +# ==================================================================== +######DESCRIPTIONBEGIN#### +# +# Author(s): Savin Zlobec <savin@elatec.si> +# Date: 2004-08-25 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_DEVS_SPI_ARM_AT91 { + parent CYGPKG_IO_SPI + active_if CYGPKG_IO_SPI + display "Atmel AT91 SPI driver" + requires CYGPKG_HAL_ARM_AT91 + requires CYGPKG_ERROR + hardware + include_dir cyg/io + compile spi_at91.c + compile -library=libextras.a spi_at91_init.cxx + + cdl_option CYGHWR_DEVS_SPI_ARM_AT91_BUS0 { + display "Enable support for SPI bus 0" + flavor bool + default_value 1 + description "Enable this option to add support for the first + SPI peripheral. The most AT91 devices only have one bus" + } + + cdl_interface CYGINT_DEVS_SPI_ARM_AT91_HAS_BUS1 { + description " + This interface is implemented by HALs for devices which have + the second SPI bus controller." + } + + + cdl_option CYGHWR_DEVS_SPI_ARM_AT91_BUS1 { + active_if CYGINT_DEVS_SPI_ARM_AT91_HAS_BUS1 + display "Enable support for SPI bus 1" + flavor bool + default_value 0 + description "Enable this option to add support for the second + SPI peripheral. The most AT91 devices only have one bus" + } + + cdl_component CYGPKG_DEVS_SPI_ARM_AT91_BUS0_CFG { + active_if CYGHWR_DEVS_SPI_ARM_AT91_BUS0 + display "Configuration options for SPI Bus 0" + flavor none + description "This is the configuration options for SPI Bus 0" + + cdl_option CYGHWR_DEVS_SPI_ARM_AT91_BUS0_PCSDEC { + display "Support 4 to 16 decoder of chip select signals." + flavor bool + default_value 0 + description "Enable this option if SPI peripheral chip + selects are connected through an 4 to 16 decoder." + } + + cdl_option CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS0 { + display "PIO-Pin used for NPSC0" + flavor data + default_value {"AT91_SPI_NPCS0"} + description "Any GPIO pin is able to be used as the SPI driver + uses GPIO to control the chip selects. Specify the pin + as \"AT91_GPIO_PA13\" or \"AT91_GPIO_PB5\" etc. Specify + \"NONE\" if this chip select is to be disabled" + } + + cdl_option CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS1 { + display "PIO-Pin used for NPSC1" + flavor data + default_value {"AT91_SPI_NPCS1"} + description "Any GPIO pin is able to be used as the SPI driver + uses GPIO to control the chip selects. Specify the pin + as \"AT91_GPIO_PA13\" or \"AT91_GPIO_PB5\" etc. Specify + \"NONE\" if this chip select is to be disabled" + } + cdl_option CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS2 { + display "PIO-Pin used for NPSC2" + flavor data + default_value {"AT91_SPI_NPCS2"} + description "Any GPIO pin is able to be used as the SPI driver + uses GPIO to control the chip selects. Specify the pin + as \"AT91_GPIO_PA13\" or \"AT91_GPIO_PB5\" etc. Specify + \"NONE\" if this chip select is to be disabled" + } + cdl_option CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS3 { + display "PIO-Pin used for NPSC3" + flavor data + default_value {"AT91_SPI_NPCS3"} + description "Any GPIO pin is able to be used as the SPI driver + uses GPIO to control the chip selects. Specify the pin + as \"AT91_GPIO_PA13\" or \"AT91_GPIO_PB5\" etc. Specify + \"NONE\" if this chip select is to be disabled" + } + + } + + cdl_component CYGPKG_DEVS_SPI_ARM_AT91_BUS1_CFG { + active_if CYGHWR_DEVS_SPI_ARM_AT91_BUS1 + display "Configuration options for SPI Bus 1" + flavor none + description "This is the configuration options for SPI Bus 1" + + cdl_option CYGHWR_DEVS_SPI_ARM_AT91_BUS1_PCSDEC { + display "Support 4 to 16 decoder of chip select signals." + flavor bool + default_value 0 + description "Enable this option if SPI peripheral chip + selects are connected through an 4 to 16 decoder." + } + + cdl_option CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS0 { + display "PIO-Pin used for NPSC0" + flavor data + default_value {"AT91_SPI1_NPCS0"} + description "Any GPIO pin is able to be used as the SPI driver + uses GPIO to control the chip selects. Specify the pin + as \"AT91_GPIO_PA13\" or \"AT91_GPIO_PB5\" etc. Specify + \"NONE\" if this chip select is to be disabled" + } + + cdl_option CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS1 { + display "PIO-Pin used for NPSC1" + flavor data + default_value {"AT91_SPI1_NPCS1"} + description "Any GPIO pin is able to be used as the SPI driver + uses GPIO to control the chip selects. Specify the pin + as \"AT91_GPIO_PA13\" or \"AT91_GPIO_PB5\" etc. Specify + \"NONE\" if this chip select is to be disabled" + } + cdl_option CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS2 { + display "PIO-Pin used for NPSC2" + flavor data + default_value {"AT91_SPI1_NPCS2"} + description "Any GPIO pin is able to be used as the SPI driver + uses GPIO to control the chip selects. Specify the pin + as \"AT91_GPIO_PA13\" or \"AT91_GPIO_PB5\" etc. Specify + \"NONE\" if this chip select is to be disabled" + } + cdl_option CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS3 { + display "PIO-Pin used for NPSC3" + flavor data + default_value {"AT91_SPI1_NPCS3"} + description "Any GPIO pin is able to be used as the SPI driver + uses GPIO to control the chip selects. Specify the pin + as \"AT91_GPIO_PA13\" or \"AT91_GPIO_PB5\" etc. Specify + \"NONE\" if this chip select is to be disabled" + } + + } + + + cdl_component CYGPKG_DEVS_SPI_ARM_AT91_OPTIONS { + display "Atmel AT91 SPI driver build options" + flavor none + description " + Package specific build options including control over + compiler flags used only in building this package, + and details of which tests are built." + + cdl_option CYGPKG_DEVS_SPI_ARM_AT91_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the SPI device. These flags are used in addition + to the set of global flags." + } + + cdl_option CYGPKG_DEVS_SPI_ARM_AT91_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the SPI device. These flags are removed from + the set of global flags if present." + } + } +} + +# EOF spi_at91.cdl diff --git a/ecos/packages/devs/spi/arm/at91/current/include/spi_at91.h b/ecos/packages/devs/spi/arm/at91/current/include/spi_at91.h new file mode 100644 index 0000000..e64f63c --- /dev/null +++ b/ecos/packages/devs/spi/arm/at91/current/include/spi_at91.h @@ -0,0 +1,121 @@ +#ifndef CYGONCE_DEVS_SPI_ARM_AT91_H +#define CYGONCE_DEVS_SPI_ARM_AT91_H +//========================================================================== +// +// spi_at91.h +// +// Atmel AT91 (ARM) SPI driver defines +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Savin Zlobec <savin@elatec.si> +// Date: 2004-08-25 +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/hal.h> +#include <pkgconf/io_spi.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/hal/drv_api.h> +#include <cyg/io/spi.h> + +//----------------------------------------------------------------------------- +// AT91 SPI BUS + +typedef struct cyg_spi_at91_bus_s +{ + // ---- Upper layer data ---- + + cyg_spi_bus spi_bus; // Upper layer SPI bus data + + // ---- Lower layer data ---- + + cyg_interrupt spi_interrupt; // SPI interrupt object + cyg_handle_t spi_interrupt_handle; // SPI interrupt handle + cyg_drv_mutex_t transfer_mx; // Transfer mutex + cyg_drv_cond_t transfer_cond; // Transfer condition + cyg_bool transfer_end; // Transfer end flag + cyg_bool cs_up; // Chip Select up flag + cyg_vector_t interrupt_number; // SPI Interrupt Number + cyg_addrword_t base; // Base Address of the SPI peripheral + cyg_uint8 cs_en[4]; // The Configurations state for the CS + cyg_uint32 cs_gpio[4]; // The GPIO Configurations for the CS +} cyg_spi_at91_bus_t; + +//----------------------------------------------------------------------------- +// AT91 SPI DEVICE + +typedef struct cyg_spi_at91_device_s +{ + // ---- Upper layer data ---- + + cyg_spi_device spi_device; // Upper layer SPI device data + + // ---- Lower layer data (configurable) ---- + + cyg_uint8 dev_num; // Device number + cyg_uint8 cl_pol; // Clock polarity (0 or 1) + cyg_uint8 cl_pha; // Clock phase (0 or 1) + cyg_uint32 cl_brate; // Clock baud rate + cyg_uint16 cs_up_udly; // Delay in us between CS up and transfer start + cyg_uint16 cs_dw_udly; // Delay in us between transfer end and CS down + cyg_uint16 tr_bt_udly; // Delay in us between two transfers + + // ---- Lower layer data (internal) ---- + + cyg_bool init; // Is device initialized + cyg_uint8 cl_scbr; // Value of SCBR (SPI clock) reg field + cyg_uint8 cl_div32; // Divide SPI master clock by 32 +} cyg_spi_at91_device_t; + +//----------------------------------------------------------------------------- +// AT91 SPI exported busses + +/* For backwards compatability */ +#define cyg_spi_at91_bus cyg_spi_at91_bus0 + +externC cyg_spi_at91_bus_t cyg_spi_at91_bus0; +externC cyg_spi_at91_bus_t cyg_spi_at91_bus1; + +//----------------------------------------------------------------------------- + +#endif // CYGONCE_DEVS_SPI_ARM_AT91_H + +//----------------------------------------------------------------------------- +// End of spi_at91.h diff --git a/ecos/packages/devs/spi/arm/at91/current/src/spi_at91.c b/ecos/packages/devs/spi/arm/at91/current/src/spi_at91.c new file mode 100644 index 0000000..a64bec8 --- /dev/null +++ b/ecos/packages/devs/spi/arm/at91/current/src/spi_at91.c @@ -0,0 +1,707 @@ +//========================================================================== +// +// spi_at91.c +// +// Atmel AT91 (ARM) SPI driver +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2009 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Savin Zlobec <savin@elatec.si> +// Date: 2004-08-25 +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/hal.h> +#include <pkgconf/io_spi.h> +#include <pkgconf/devs_spi_arm_at91.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/hal/hal_io.h> +#include <cyg/hal/hal_if.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/hal/drv_api.h> +#include <cyg/io/spi.h> +#include <cyg/io/spi_at91.h> +#include <cyg/error/codes.h> + +// ------------------------------------------------------------------------- +static void spi_at91_init_bus(cyg_spi_at91_bus_t * bus); + +static cyg_uint32 spi_at91_ISR(cyg_vector_t vector, cyg_addrword_t data); + +static void spi_at91_DSR(cyg_vector_t vector, + cyg_ucount32 count, + cyg_addrword_t data); + +static void spi_at91_transaction_begin(cyg_spi_device *dev); + +static void spi_at91_transaction_transfer(cyg_spi_device *dev, + cyg_bool polled, + cyg_uint32 count, + const cyg_uint8 *tx_data, + cyg_uint8 *rx_data, + cyg_bool drop_cs); + +static void spi_at91_transaction_tick(cyg_spi_device *dev, + cyg_bool polled, + cyg_uint32 count); + +static void spi_at91_transaction_end(cyg_spi_device* dev); + +static int spi_at91_get_config(cyg_spi_device *dev, + cyg_uint32 key, + void *buf, + cyg_uint32 *len); + +static int spi_at91_set_config(cyg_spi_device *dev, + cyg_uint32 key, + const void *buf, + cyg_uint32 *len); + +// ------------------------------------------------------------------------- +// AT91 SPI BUS + +#ifdef CYGHWR_DEVS_SPI_ARM_AT91_BUS0 +cyg_spi_at91_bus_t cyg_spi_at91_bus0 = { + .spi_bus.spi_transaction_begin = spi_at91_transaction_begin, + .spi_bus.spi_transaction_transfer = spi_at91_transaction_transfer, + .spi_bus.spi_transaction_tick = spi_at91_transaction_tick, + .spi_bus.spi_transaction_end = spi_at91_transaction_end, + .spi_bus.spi_get_config = spi_at91_get_config, + .spi_bus.spi_set_config = spi_at91_set_config, + .interrupt_number = CYGNUM_HAL_INTERRUPT_SPI, + .base = AT91_SPI, +#ifndef CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS0_NONE + .cs_en[0] = true, + .cs_gpio[0] = CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS0, +#else + .cs_en[0] = false, +#endif +#ifndef CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS1_NONE + .cs_en[1] = true, + .cs_gpio[1] = CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS1, +#else + .cs_en[1] = false, +#endif +#ifndef CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS2_NONE + .cs_en[2] = true, + .cs_gpio[2] = CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS2, +#else + .cs_en[2] = false, +#endif +#ifndef CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS3_NONE + .cs_en[3] = true, + .cs_gpio[3] = CYGDAT_DEVS_SPI_ARM_AT91_BUS0_NPCS3, +#else + .cs_en[3] = false, +#endif +}; + +CYG_SPI_DEFINE_BUS_TABLE(cyg_spi_at91_device_t, 0); +#endif +#ifdef CYGHWR_DEVS_SPI_ARM_AT91_BUS1 +cyg_spi_at91_bus_t cyg_spi_at91_bus1 = { + .spi_bus.spi_transaction_begin = spi_at91_transaction_begin, + .spi_bus.spi_transaction_transfer = spi_at91_transaction_transfer, + .spi_bus.spi_transaction_tick = spi_at91_transaction_tick, + .spi_bus.spi_transaction_end = spi_at91_transaction_end, + .spi_bus.spi_get_config = spi_at91_get_config, + .spi_bus.spi_set_config = spi_at91_set_config, + .interrupt_number = CYGNUM_HAL_INTERRUPT_SPI1, + .base = AT91_SPI1, +#ifndef CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS0_NONE + .cs_en[0] = true, + .cs_gpio[0] = CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS0, +#else + .cs_en[0] = false, +#endif +#ifndef CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS1_NONE + .cs_en[1] = true, + .cs_gpio[1] = CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS1, +#else + .cs_en[1] = false, +#endif +#ifndef CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS2_NONE + .cs_en[2] = true, + .cs_gpio[2] = CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS2, +#else + .cs_en[2] = false, +#endif +#ifndef CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS3_NONE + .cs_en[3] = true, + .cs_gpio[3] = CYGDAT_DEVS_SPI_ARM_AT91_BUS1_NPCS3, +#else + .cs_en[3] = false, +#endif +}; + +CYG_SPI_DEFINE_BUS_TABLE(cyg_spi_at91_device_t, 1); +#endif +// ------------------------------------------------------------------------- + +// If C constructor with init priority functionality is not in compiler, +// rely on spi_at91_init.cxx to init us. +#ifndef CYGBLD_ATTRIB_C_INIT_PRI +# define CYGBLD_ATTRIB_C_INIT_PRI(x) +#endif + +void CYGBLD_ATTRIB_C_INIT_PRI(CYG_INIT_BUS_SPI) +cyg_spi_at91_bus_init(void) +{ + +#ifdef CYGHWR_DEVS_SPI_ARM_AT91_BUS0 + // NOTE: here we let the SPI controller control + // the data in, out and clock signals, but + // we need to handle the chip selects manually + // in order to achieve better chip select control + // in between transactions. + + // Put SPI MISO, MOSI and SPCK pins into peripheral mode + HAL_ARM_AT91_PIO_CFG(AT91_SPI_SPCK); + HAL_ARM_AT91_PIO_CFG(AT91_SPI_MISO); + HAL_ARM_AT91_PIO_CFG(AT91_SPI_MOSI); + spi_at91_init_bus(&cyg_spi_at91_bus0); +#endif +#ifdef CYGHWR_DEVS_SPI_ARM_AT91_BUS1 + // NOTE: here we let the SPI controller control + // the data in, out and clock signals, but + // we need to handle the chip selects manually + // in order to achieve better chip select control + // in between transactions. + + // Put SPI MISO, MOSI and SPCK pins into peripheral mode + HAL_ARM_AT91_PIO_CFG(AT91_SPI1_SPCK); + HAL_ARM_AT91_PIO_CFG(AT91_SPI1_MISO); + HAL_ARM_AT91_PIO_CFG(AT91_SPI1_MOSI); + spi_at91_init_bus(&cyg_spi_at91_bus1); +#endif +} + +// ------------------------------------------------------------------------- + +static void spi_at91_init_bus(cyg_spi_at91_bus_t * spi_bus) +{ + cyg_uint32 ctr; + // Create and attach SPI interrupt object + cyg_drv_interrupt_create(spi_bus->interrupt_number, + 4, + (cyg_addrword_t)spi_bus, + spi_at91_ISR, + spi_at91_DSR, + &spi_bus->spi_interrupt_handle, + &spi_bus->spi_interrupt); + + cyg_drv_interrupt_attach(spi_bus->spi_interrupt_handle); + + // Init transfer mutex and condition + cyg_drv_mutex_init(&spi_bus->transfer_mx); + cyg_drv_cond_init(&spi_bus->transfer_cond, + &spi_bus->transfer_mx); + + // Init flags + spi_bus->transfer_end = true; + spi_bus->cs_up = false; + + // Soft reset the SPI controller + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_CR, AT91_SPI_CR_SWRST); + + // Configure SPI pins + + + // Put SPI chip select pins in IO output mode + for(ctr = 0;ctr<4;ctr++) + { + if(spi_bus->cs_en[ctr]) + { + HAL_ARM_AT91_GPIO_CFG_DIRECTION(spi_bus->cs_gpio[ctr],AT91_PIN_OUT); + HAL_ARM_AT91_GPIO_SET(spi_bus->cs_gpio[ctr]); + } + } + // Call upper layer bus init + CYG_SPI_BUS_COMMON_INIT(&spi_bus->spi_bus); +} + +static cyg_uint32 +spi_at91_ISR(cyg_vector_t vector, cyg_addrword_t data) +{ + cyg_uint32 stat; + cyg_spi_at91_bus_t * spi_bus = (cyg_spi_at91_bus_t *)data; + // Read the status register and disable + // the SPI int events that have occurred + + HAL_READ_UINT32(spi_bus->base+AT91_SPI_SR, stat); + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_IDR, stat); + + cyg_drv_interrupt_mask(vector); + cyg_drv_interrupt_acknowledge(vector); + + return CYG_ISR_CALL_DSR; +} + +static void +spi_at91_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + cyg_spi_at91_bus_t *spi_bus = (cyg_spi_at91_bus_t *) data; + cyg_uint32 stat; + + // Read the status register and + // check for transfer completion + + HAL_READ_UINT32(spi_bus->base+AT91_SPI_SR, stat); + + if((stat & AT91_SPI_SR_ENDRX) && (stat & AT91_SPI_SR_ENDTX)) + { + // Transfer ended + spi_bus->transfer_end = true; + cyg_drv_cond_signal(&spi_bus->transfer_cond); + } + else + { + // Transfer still in progress - unmask the SPI + // int so we can get more SPI int events + cyg_drv_interrupt_unmask(vector); + } +} + +static cyg_bool +spi_at91_calc_scbr(cyg_spi_at91_device_t *dev) +{ + cyg_uint32 scbr; + cyg_bool res = true; + + // Calculate SCBR from baud rate + + scbr = CYGNUM_HAL_ARM_AT91_CLOCK_SPEED / dev->cl_brate; + if ((2*(CYGNUM_HAL_ARM_AT91_CLOCK_SPEED % dev->cl_brate)) >= dev->cl_brate) + scbr++; + + if (scbr < 2) + { + dev->cl_scbr = 2; + dev->cl_div32 = 0; + res = false; + } + else if (scbr > 255) + { + dev->cl_div32 = 1; + + scbr = CYGNUM_HAL_ARM_AT91_CLOCK_SPEED / (32*dev->cl_brate); + + if (scbr < 2) + { + dev->cl_scbr = 2; + res = false; + } + else if (scbr > 255) + { + dev->cl_scbr = 255; + res = false; + } + else + dev->cl_scbr = (cyg_uint8)scbr; + } + else + { + dev->cl_scbr = (cyg_uint8)scbr; + dev->cl_div32 = 0; + } + + return res; +} + +static void +spi_at91_set_npcs(cyg_spi_at91_bus_t *spi_bus,int val) +{ + cyg_uint32 ctr; + for(ctr=0;ctr<4;ctr++) + { + if(spi_bus->cs_en[ctr]) + { + HAL_ARM_AT91_GPIO_PUT(spi_bus->cs_gpio[ctr], (val & (1<<ctr))); + } + } +} + +static void +spi_at91_start_transfer(cyg_spi_at91_device_t *dev) +{ + cyg_spi_at91_bus_t *spi_bus = (cyg_spi_at91_bus_t *)dev->spi_device.spi_bus; + + if (spi_bus->cs_up) + return; + + // Force minimal delay between two transfers - in case two transfers + // follow each other w/o delay, then we have to wait here in order for + // the peripheral device to detect cs transition from inactive to active. + CYGACC_CALL_IF_DELAY_US(dev->tr_bt_udly); + + // Raise CS + +#ifdef CYGHWR_DEVS_SPI_ARM_AT91_PCSDEC + spi_at91_set_npcs(spi_bus,~dev->dev_num); +#else + spi_at91_set_npcs(spi_bus,~(1<<dev->dev_num)); +#endif + CYGACC_CALL_IF_DELAY_US(dev->cs_up_udly); + + spi_bus->cs_up = true; +} + +static void +spi_at91_drop_cs(cyg_spi_at91_device_t *dev) +{ + cyg_spi_at91_bus_t *spi_bus = (cyg_spi_at91_bus_t *)dev->spi_device.spi_bus; + + if (!spi_bus->cs_up) + return; + + // Drop CS + + CYGACC_CALL_IF_DELAY_US(dev->cs_dw_udly); + spi_at91_set_npcs(spi_bus,0x0F); + spi_bus->cs_up = false; +} + +static void +spi_at91_transfer(cyg_spi_at91_device_t *dev, + cyg_uint32 count, + const cyg_uint8 *tx_data, + cyg_uint8 *rx_data) +{ + cyg_spi_at91_bus_t *spi_bus = (cyg_spi_at91_bus_t *)dev->spi_device.spi_bus; + + // Since PDC transfer buffer counters are 16 bit long, + // we have to split longer transfers into chunks. + while (count > 0) + { + cyg_uint16 tr_count = count > 0xFFFF ? 0xFFFF : count; + + // Set rx buf pointer and counter + if (NULL != rx_data) + { + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_RPR, (cyg_uint32)rx_data); + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_RCR, (cyg_uint32)tr_count); + } + + // Set tx buf pointer and counter + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_TPR, (cyg_uint32)tx_data); + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_TCR, (cyg_uint32)tr_count); + +#ifdef AT91_SPI_PTCR + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_PTCR, + AT91_SPI_PTCR_RXTEN | AT91_SPI_PTCR_TXTEN); +#endif + // Enable the SPI int events we are interested in + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_IER, + AT91_SPI_SR_ENDRX | AT91_SPI_SR_ENDTX); + + cyg_drv_mutex_lock(&spi_bus->transfer_mx); + { + spi_bus->transfer_end = false; + + // Unmask the SPI int + cyg_drv_interrupt_unmask(spi_bus->interrupt_number); + + // Wait for its completion + cyg_drv_dsr_lock(); + { + while (!spi_bus->transfer_end) + cyg_drv_cond_wait(&spi_bus->transfer_cond); + } + cyg_drv_dsr_unlock(); + } + cyg_drv_mutex_unlock(&spi_bus->transfer_mx); + + if (NULL == rx_data) + { + cyg_uint32 val; + + // If rx buffer was NULL, then the PDC receiver data transfer + // was not started and we didn't wait for ENDRX, but only for + // ENDTX. Meaning that right now the last byte is being serialized + // over the line and when finished input data will appear in + // rx data reg. We have to wait for this to happen here, if we + // don't we'll get the last received byte as the first one in the + // next transfer! + + // FIXME: is there any better way to do this? + // If not, then precalculate this value. + val = 8000000/dev->cl_brate; + CYGACC_CALL_IF_DELAY_US(val > 1 ? val : 1); + + // Clear the rx data reg + HAL_READ_UINT32(spi_bus->base+AT91_SPI_RDR, val); + } + + // Adjust running variables + + if (NULL != rx_data) + rx_data += tr_count; + tx_data += tr_count; + count -= tr_count; + } +} + +static void +spi_at91_transfer_polled(cyg_spi_at91_device_t *dev, + cyg_uint32 count, + const cyg_uint8 *tx_data, + cyg_uint8 *rx_data) +{ + cyg_uint32 val; + cyg_spi_at91_bus_t *spi_bus = (cyg_spi_at91_bus_t *)dev->spi_device.spi_bus; + + // Transmit and receive byte by byte + while (count-- > 0) + { + // Wait for transmit data register empty + do + { + HAL_READ_UINT32(spi_bus->base+AT91_SPI_SR, val); + } while ( !(val & AT91_SPI_SR_TDRE) ); + + // Send next byte over the wire + val = *tx_data++; + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_TDR, val); + + // Wait for reveive data register full + do + { + HAL_READ_UINT32(spi_bus->base+AT91_SPI_SR, val); + } while ( !(val & AT91_SPI_SR_RDRF) ); + + // Store received byte + HAL_READ_UINT32(spi_bus->base+AT91_SPI_RDR, val); + if (NULL != rx_data) + *rx_data++ = val; + } +} + +// ------------------------------------------------------------------------- + +static void +spi_at91_transaction_begin(cyg_spi_device *dev) +{ + cyg_spi_at91_device_t *at91_spi_dev = (cyg_spi_at91_device_t *) dev; + cyg_spi_at91_bus_t *spi_bus = + (cyg_spi_at91_bus_t *)at91_spi_dev->spi_device.spi_bus; + cyg_uint32 val; + + if (!at91_spi_dev->init) + { + at91_spi_dev->init = true; + spi_at91_calc_scbr(at91_spi_dev); + } + + // Configure SPI channel 0 - this is the only channel we + // use for all devices since we drive chip selects manually + + val = AT91_SPI_CSR_BITS8; + + if (1 == at91_spi_dev->cl_pol) + val |= AT91_SPI_CSR_CPOL; + + if (1 == at91_spi_dev->cl_pha) + val |= AT91_SPI_CSR_NCPHA; + + val |= AT91_SPI_CSR_SCBR(at91_spi_dev->cl_scbr); + + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_CSR0, val); + + // Enable SPI clock + HAL_WRITE_UINT32(AT91_PMC+AT91_PMC_PCER, 1<<spi_bus->interrupt_number); + + // Enable the SPI controller + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_CR, AT91_SPI_CR_SPIEN); + + /* As we are using this driver only in master mode with NPCS0 + configured as GPIO instead of a peripheral pin, it is necessary + for the Mode Failure detection to be switched off as this will + cause havoc with the driver */ + + // Put SPI bus into master mode + if (1 == at91_spi_dev->cl_div32) { + val = AT91_SPI_MR_MSTR | AT91_SPI_MR_DIV32; +#ifdef AT91_SPI_MR_MODFDIS + val |= AT91_SPI_MR_MODFDIS; +#endif + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_MR, val); + } else { + val = AT91_SPI_MR_MSTR; +#ifdef AT91_SPI_MR_MODFDIS + val |= AT91_SPI_MR_MODFDIS; +#endif + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_MR, val); + } +} + +static void +spi_at91_transaction_transfer(cyg_spi_device *dev, + cyg_bool polled, + cyg_uint32 count, + const cyg_uint8 *tx_data, + cyg_uint8 *rx_data, + cyg_bool drop_cs) +{ + cyg_spi_at91_device_t *at91_spi_dev = (cyg_spi_at91_device_t *) dev; + + // Select the device if not already selected + spi_at91_start_transfer(at91_spi_dev); + + // Perform the transfer + if (polled) + spi_at91_transfer_polled(at91_spi_dev, count, tx_data, rx_data); + else + spi_at91_transfer(at91_spi_dev, count, tx_data, rx_data); + + // Deselect the device if requested + if (drop_cs) + spi_at91_drop_cs(at91_spi_dev); +} + +static void +spi_at91_transaction_tick(cyg_spi_device *dev, + cyg_bool polled, + cyg_uint32 count) +{ + const cyg_uint32 zeros[10] = { 0,0,0,0,0,0,0,0,0,0 }; + + cyg_spi_at91_device_t *at91_spi_dev = (cyg_spi_at91_device_t *) dev; + + // Transfer count zeros to the device - we don't touch the + // chip select, the device could be selected or deselected. + // It is up to the device driver to decide in wich state the + // device will be ticked. + + while (count > 0) + { + int tcnt = count > 40 ? 40 : count; + + if (polled) + spi_at91_transfer_polled(at91_spi_dev, tcnt, + (const cyg_uint8 *) zeros, NULL); + else + spi_at91_transfer(at91_spi_dev, tcnt, + (const cyg_uint8 *) zeros, NULL); + + count -= tcnt; + } +} + +static void +spi_at91_transaction_end(cyg_spi_device* dev) +{ + cyg_spi_at91_device_t * at91_spi_dev = (cyg_spi_at91_device_t *)dev; + cyg_spi_at91_bus_t *spi_bus = + (cyg_spi_at91_bus_t *)at91_spi_dev->spi_device.spi_bus; + + // Disable the SPI controller + HAL_WRITE_UINT32(spi_bus->base+AT91_SPI_CR, AT91_SPI_CR_SPIDIS); + + // Disable SPI clock + HAL_WRITE_UINT32(AT91_PMC+AT91_PMC_PCDR,1<<spi_bus->interrupt_number); + + spi_at91_drop_cs((cyg_spi_at91_device_t *) dev); +} + +static int +spi_at91_get_config(cyg_spi_device *dev, + cyg_uint32 key, + void *buf, + cyg_uint32 *len) +{ + cyg_spi_at91_device_t *at91_spi_dev = (cyg_spi_at91_device_t *) dev; + + switch (key) + { + case CYG_IO_GET_CONFIG_SPI_CLOCKRATE: + { + if (*len != sizeof(cyg_uint32)) + return -EINVAL; + else + { + cyg_uint32 *cl_brate = (cyg_uint32 *)buf; + *cl_brate = at91_spi_dev->cl_brate; + } + } + break; + default: + return -EINVAL; + } + return ENOERR; +} + +static int +spi_at91_set_config(cyg_spi_device *dev, + cyg_uint32 key, + const void *buf, + cyg_uint32 *len) +{ + cyg_spi_at91_device_t *at91_spi_dev = (cyg_spi_at91_device_t *) dev; + + switch (key) + { + case CYG_IO_SET_CONFIG_SPI_CLOCKRATE: + { + if (*len != sizeof(cyg_uint32)) + return -EINVAL; + else + { + cyg_uint32 cl_brate = *((cyg_uint32 *)buf); + cyg_uint32 old_cl_brate = at91_spi_dev->cl_brate; + + at91_spi_dev->cl_brate = cl_brate; + + if (!spi_at91_calc_scbr(at91_spi_dev)) + { + at91_spi_dev->cl_brate = old_cl_brate; + spi_at91_calc_scbr(at91_spi_dev); + return -EINVAL; + } + } + } + break; + default: + return -EINVAL; + } + return ENOERR; +} + +// ------------------------------------------------------------------------- +// EOF spi_at91.c diff --git a/ecos/packages/devs/spi/arm/at91/current/src/spi_at91_init.cxx b/ecos/packages/devs/spi/arm/at91/current/src/spi_at91_init.cxx new file mode 100644 index 0000000..b8fc586 --- /dev/null +++ b/ecos/packages/devs/spi/arm/at91/current/src/spi_at91_init.cxx @@ -0,0 +1,73 @@ +//========================================================================== +// +// spi_at91_init.cxx +// +// Atmel AT91 (ARM) SPI bus init +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2009 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Savin Zlobec <savin@elatec.si> +// Date: 2004-08-25 +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <cyg/infra/cyg_type.h> + +// This file is not needed if we support CYGBLD_ATTRIB_C_INIT_PRI, as the +// init happens directly in spi_at91.c then. +#ifndef CYGBLD_ATTRIB_C_INIT_PRI + +// ------------------------------------------------------------------------- + +externC void cyg_spi_at91_bus_init(void); + +class cyg_spi_at91_bus_init_class { +public: + cyg_spi_at91_bus_init_class(void) { + cyg_spi_at91_bus_init(); + } +}; + +// ------------------------------------------------------------------------- + +static cyg_spi_at91_bus_init_class spi_at91_bus_init CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_BUS_SPI); + +#endif // ifndef CYGBLD_ATTRIB_C_INIT_PRI + +// ------------------------------------------------------------------------- +// EOF spi_at91_init.cxx diff --git a/ecos/packages/devs/spi/arm/eb55/current/ChangeLog b/ecos/packages/devs/spi/arm/eb55/current/ChangeLog new file mode 100644 index 0000000..bc7a855 --- /dev/null +++ b/ecos/packages/devs/spi/arm/eb55/current/ChangeLog @@ -0,0 +1,50 @@ +2009-02-12 Nick Garnett <nickg@ecoscentric.com> + + * src/spi_eb55.c: Export static structure for dataflash SPI device + rather than pointer. The latter cannot be used in the initializer + for a dataflash flash driver. + +2006-06-01 Andrew Lunn <andrew.lunn@ascom.ch> + + * cdl/spi_eb55.cdl: Updates needed for recent changes to AT91 SPI + driver. + +2004-08-31 Savin Zlobec <savin@elatec.si> + + * cdl/spi_eb55.cdl: + Added a require for 4 to 16 decoder of chip select signals option. + * src/spi_eb55.c: + Defined time between two transfers. + +2004-08-27 Savin Zlobec <savin@elatec.si> + + * cdl/spi_eb55.cdl: + * include/spi_eb55.h: + * src/spi_eb55.c: + Atmel AT91EB55 SPI devices. + + + +//=========================================================================== +// ####GPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. +// ------------------------------------------- +// ####GPLCOPYRIGHTEND#### +//=========================================================================== diff --git a/ecos/packages/devs/spi/arm/eb55/current/cdl/spi_eb55.cdl b/ecos/packages/devs/spi/arm/eb55/current/cdl/spi_eb55.cdl new file mode 100644 index 0000000..9a77825 --- /dev/null +++ b/ecos/packages/devs/spi/arm/eb55/current/cdl/spi_eb55.cdl @@ -0,0 +1,97 @@ +# ==================================================================== +# +# spi_eb55.cdl +# +# Atmel AT91EB55 SPI devices configuration data +# +# ==================================================================== +## ####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +## +## eCos is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free +## Software Foundation; either version 2 or (at your option) any later +## version. +## +## eCos is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with eCos; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## As a special exception, if other files instantiate templates or use +## macros or inline functions from this file, or you compile this file +## and link it with other works to produce a work based on this file, +## this file does not by itself cause the resulting work to be covered by +## the GNU General Public License. However the source code for this file +## must still be made available in accordance with section (3) of the GNU +## General Public License v2. +## +## This exception does not invalidate any other reasons why a work based +## on this file might be covered by the GNU General Public License. +## ------------------------------------------- +## ####ECOSGPLCOPYRIGHTEND#### +# ==================================================================== +######DESCRIPTIONBEGIN#### +# +# Author(s): Savin Zlobec <savin@elatec.si> +# Date: 2004-08-27 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_DEVS_SPI_ARM_EB55 { + parent CYGPKG_IO_SPI + active_if CYGPKG_IO_SPI + active_if CYGPKG_DEVS_SPI_ARM_AT91 + display "Atmel AT91EB55 SPI devices" + requires CYGHWR_DEVS_SPI_ARM_AT91_BUS0_PCSDEC + hardware + include_dir cyg/io + compile spi_eb55.c + + define_proc { + puts $::cdl_system_header "/***** SPI exported devices begin *****/" + puts $::cdl_system_header "#include <cyg/io/spi_eb55.h>" + puts $::cdl_system_header "/***** SPI exported devices end *****/" + } + + cdl_component CYGPKG_DEVS_SPI_ARM_EB55_OPTIONS { + display "Atmel AT91EB55 SPI devices build options" + flavor none + description " + Package specific build options including control over + compiler flags used only in building this package, + and details of which tests are built." + + cdl_option CYGPKG_DEVS_SPI_ARM_EB55_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the SPI device. These flags are used in addition + to the set of global flags." + } + + cdl_option CYGPKG_DEVS_SPI_ARM_EB55_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the SPI device. These flags are removed from + the set of global flags if present." + } + } +} + +# EOF spi_eb55.cdl diff --git a/ecos/packages/devs/spi/arm/eb55/current/include/spi_eb55.h b/ecos/packages/devs/spi/arm/eb55/current/include/spi_eb55.h new file mode 100644 index 0000000..d5df99f --- /dev/null +++ b/ecos/packages/devs/spi/arm/eb55/current/include/spi_eb55.h @@ -0,0 +1,62 @@ +#ifndef CYGONCE_DEVS_SPI_ARM_EB55_H +#define CYGONCE_DEVS_SPI_ARM_EB55_H +//========================================================================== +// +// spi_eb55.h +// +// Atmel AT91EB55 SPI devices defines +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Savin Zlobec <savin@elatec.si> +// Date: 2004-08-27 +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +//----------------------------------------------------------------------------- +// AT91EB55 SPI exported devices + +#define HAL_SPI_EXPORTED_DEVICES \ + externC cyg_spi_device *cyg_spi_dataflash_dev0; + +//----------------------------------------------------------------------------- + +#endif // CYGONCE_DEVS_SPI_ARM_EB55_H + +//----------------------------------------------------------------------------- +// End of spi_eb55.h diff --git a/ecos/packages/devs/spi/arm/eb55/current/src/spi_eb55.c b/ecos/packages/devs/spi/arm/eb55/current/src/spi_eb55.c new file mode 100644 index 0000000..81772b5 --- /dev/null +++ b/ecos/packages/devs/spi/arm/eb55/current/src/spi_eb55.c @@ -0,0 +1,74 @@ +//========================================================================== +// +// spi_eb55.c +// +// Atmel AT91EB55 SPI devices +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Savin Zlobec <savin@elatec.si> +// Date: 2004-08-27 +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/hal.h> +#include <pkgconf/io_spi.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/io/spi.h> +#include <cyg/io/spi_at91.h> + +// ------------------------------------------------------------------------- +// AT91EB55 SPI exported devices + +// AT45DB321B DataFlash +cyg_spi_at91_device_t spi_dataflash_dev0 CYG_SPI_DEVICE_ON_BUS(0) = +{ + .spi_device.spi_bus = &cyg_spi_at91_bus.spi_bus, + + .dev_num = 0, // Device number + .cl_pol = 1, // Clock polarity (0 or 1) + .cl_pha = 0, // Clock phase (0 or 1) + .cl_brate = 8192000, // Clock baud rate + .cs_up_udly = 1, // Delay in usec between CS up and transfer start + .cs_dw_udly = 1, // Delay in usec between transfer end and CS down + .tr_bt_udly = 1 // Delay in usec between two transfers +}; + +// ------------------------------------------------------------------------- +// EOF spi_eb55.c diff --git a/ecos/packages/devs/spi/arm/lpc2xxx/current/ChangeLog b/ecos/packages/devs/spi/arm/lpc2xxx/current/ChangeLog new file mode 100644 index 0000000..df50e0f --- /dev/null +++ b/ecos/packages/devs/spi/arm/lpc2xxx/current/ChangeLog @@ -0,0 +1,45 @@ +2009-02-18 Jonathan Larmour <jifl@eCosCentric.com> + + * cdl/spi_lpc2xxx.cdl: Fix my mistake in below change and make + CDL requires match option names. + +2009-02-17 Jonathan Larmour <jifl@eCosCentric.com> +2009-01-27 Sergei Gavrikov <sergei.gavrikov@gmail.com> + + * cdl/spi_lpc2xxx.cdl: Ensure the SPI interrupts are using different + priorities: CYGNUM_IO_SPI_ARM_LPC2XXX_SPI{0,1}_INTPRIO entered. + * include/spi_lpc2xxx.h: cyg_spi_lpc2xxx_bus_t: spi_prio field added. + * src/spi_lpc2xxx.cxx: spi_lpc2xxx_set_config(): fixed copy & paste + typo, spi_lpc2xxx_init_bus(): added 'prio' argument to initializer. + +2009-02-10 Bart Veer <bartv@ecoscentric.com> + + * src/spi_lpc2xxx.cxx: update init priority. + +2007-07-12 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> + + * lpc2xxx: driver for on-chip SPI units + +//=========================================================================== +// ####GPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2009 Free Software Foundation, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. +// ------------------------------------------- +// ####GPLCOPYRIGHTEND#### +//=========================================================================== diff --git a/ecos/packages/devs/spi/arm/lpc2xxx/current/cdl/spi_lpc2xxx.cdl b/ecos/packages/devs/spi/arm/lpc2xxx/current/cdl/spi_lpc2xxx.cdl new file mode 100644 index 0000000..b802c2b --- /dev/null +++ b/ecos/packages/devs/spi/arm/lpc2xxx/current/cdl/spi_lpc2xxx.cdl @@ -0,0 +1,103 @@ +# ==================================================================== +# +# spi_lpc2xxx.cdl +# +# SPI driver for LPC2xxx +# +# ==================================================================== +## ####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 1998, 1999, 2000, 2001, 2002 ,2009 Free Software Foundation, Inc. +## +## eCos is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free +## Software Foundation; either version 2 or (at your option) any later +## version. +## +## eCos is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with eCos; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## As a special exception, if other files instantiate templates or use +## macros or inline functions from this file, or you compile this file +## and link it with other works to produce a work based on this file, +## this file does not by itself cause the resulting work to be covered by +## the GNU General Public License. However the source code for this file +## must still be made available in accordance with section (3) of the GNU +## General Public License v2. +## +## This exception does not invalidate any other reasons why a work based +## on this file might be covered by the GNU General Public License. +## ------------------------------------------- +## ####ECOSGPLCOPYRIGHTEND#### +# ==================================================================== +######DESCRIPTIONBEGIN#### +# +# Author(s): Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> +# Contributors: +# Date: 2007-07-12 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_DEVS_SPI_ARM_LPC2XXX { + display "LPC2xxx SPI driver" + requires CYGPKG_HAL_ARM_LPC2XXX + + parent CYGPKG_IO_SPI + active_if CYGPKG_IO_SPI + + include_dir cyg/io + compile spi_lpc2xxx.cxx + + cdl_component CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS0 { + display "Enable SPI interface 0" + flavor bool + default_value 1 + description "The LPC2xxx controllers contain two SPI interfaces. + Enable this component to get support for SPI + interface 0." + + cdl_option CYGNUM_IO_SPI_ARM_LPC2XXX_BUS0_INTPRIO { + display "Interrupt priority of the SPI bus 0 ISR" + flavor data + legal_values 0 to 15 + default_value 12 + requires { is_active(CYGNUM_IO_SPI_ARM_LPC2XXX_BUS1_INTPRIO) + implies (CYGNUM_IO_SPI_ARM_LPC2XXX_BUS0_INTPRIO != + CYGNUM_IO_SPI_ARM_LPC2XXX_BUS1_INTPRIO) + } + description " + This option specifies the interrupt priority of the ISR of + the SPI bus 0 interrupt in the VIC. Slot 0 has the highest + priority and slot 15 the lowest." + } + } + + cdl_component CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS1 { + display "Enable SPI interface 1" + flavor bool + default_value 1 + description "The LPC2xxx controllers contain two SPI interfaces. + Enable this component to get support for SPI + interface 1." + + cdl_option CYGNUM_IO_SPI_ARM_LPC2XXX_BUS1_INTPRIO { + display "Interrupt priority of the SPI bus 1 ISR" + flavor data + legal_values 0 to 15 + default_value 13 + description " + This option specifies the interrupt priority of the ISR of + the SPI bus 1 interrupt in the VIC. Slot 0 has the highest + priority and slot 15 the lowest." + } + } +} diff --git a/ecos/packages/devs/spi/arm/lpc2xxx/current/include/spi_lpc2xxx.h b/ecos/packages/devs/spi/arm/lpc2xxx/current/include/spi_lpc2xxx.h new file mode 100644 index 0000000..17eee8e --- /dev/null +++ b/ecos/packages/devs/spi/arm/lpc2xxx/current/include/spi_lpc2xxx.h @@ -0,0 +1,108 @@ +#ifndef CYGONCE_DEVS_SPI_ARM_LPC2XXX_H +#define CYGONCE_DEVS_SPI_ARM_LPC2XXX_H + +//========================================================================== +// +// spi_lpc2xxx.h +// +// SPI driver for LPC2xxx +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> +// Contributors: +// Date: 2007-07-12 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/hal.h> +#include <pkgconf/io_spi.h> +#include <pkgconf/devs_spi_arm_lpc2xxx.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/hal/drv_api.h> +#include <cyg/io/spi.h> + +struct spi_dev { + volatile cyg_uint32 spcr; + volatile cyg_uint32 spsr; + volatile cyg_uint32 spdr; + volatile cyg_uint32 spccr; + cyg_uint32 d1, d2, d3; + volatile cyg_uint32 spint; +}; + +typedef struct { + cyg_spi_bus spi_bus; + + cyg_interrupt spi_intr; + cyg_handle_t spi_hand; + cyg_vector_t spi_vect; + cyg_priority_t spi_prio; + cyg_drv_mutex_t spi_lock; + cyg_drv_cond_t spi_wait; + + struct spi_dev *spi_dev; + + volatile cyg_uint32 count; + volatile const cyg_uint8 *tx; + volatile cyg_uint8 *rx; +} cyg_spi_lpc2xxx_bus_t; + +typedef struct { + cyg_spi_device spi_device; + + cyg_uint8 spi_cpha; + cyg_uint8 spi_cpol; + cyg_uint8 spi_lsbf; + cyg_uint32 spi_baud; + + void (*spi_cs)(int); +} cyg_spi_lpc2xxx_dev_t; + +#ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS0 +externC cyg_spi_lpc2xxx_bus_t cyg_spi_lpc2xxx_bus0; +#endif + +#ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS1 +externC cyg_spi_lpc2xxx_bus_t cyg_spi_lpc2xxx_bus1; +#endif + +#endif diff --git a/ecos/packages/devs/spi/arm/lpc2xxx/current/src/spi_lpc2xxx.cxx b/ecos/packages/devs/spi/arm/lpc2xxx/current/src/spi_lpc2xxx.cxx new file mode 100644 index 0000000..e6cc9e1 --- /dev/null +++ b/ecos/packages/devs/spi/arm/lpc2xxx/current/src/spi_lpc2xxx.cxx @@ -0,0 +1,367 @@ +//========================================================================== +// +// spi_lpc2xxx.cxx +// +// SPI driver for LPC2xxx +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2009 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> +// Contributors: +// Date: 2007-07-12 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/hal.h> +#include <pkgconf/io_spi.h> +#include <pkgconf/devs_spi_arm_lpc2xxx.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/hal/hal_io.h> +#include <cyg/hal/hal_if.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/io/spi.h> +#include <cyg/io/spi_lpc2xxx.h> +#include <cyg/error/codes.h> + +#define SPI_SPCR_SPIE 0x80 +#define SPI_SPCR_LSBF 0x40 +#define SPI_SPCR_MSTR 0x20 +#define SPI_SPCR_CPOL 0x10 +#define SPI_SPCR_CPHA 0x08 + +#define SPI_SPSR_SPIF 0x80 +#define SPI_SPSR_WCOL 0x40 +#define SPI_SPSR_ROVR 0x20 +#define SPI_SPSR_MODF 0x10 +#define SPI_SPSR_ABRT 0x08 + +#define SPI_SPINT 0x01 + +#ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS0 +cyg_spi_lpc2xxx_bus_t cyg_spi_lpc2xxx_bus0; +CYG_SPI_DEFINE_BUS_TABLE(cyg_spi_lpc2xxx_dev_t, 0); +#endif +#ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS1 +cyg_spi_lpc2xxx_bus_t cyg_spi_lpc2xxx_bus1; +CYG_SPI_DEFINE_BUS_TABLE(cyg_spi_lpc2xxx_dev_t, 1); +#endif + +/* + * Interrupt routine + * read & write the next byte until count reaches zero + */ +static cyg_uint32 +spi_lpc2xxx_isr(cyg_vector_t vec, cyg_addrword_t data) +{ + cyg_spi_lpc2xxx_bus_t *bus = (cyg_spi_lpc2xxx_bus_t *) data; + cyg_uint8 tmp; + + tmp = bus->spi_dev->spsr; + + if(tmp & SPI_SPSR_MODF) + bus->spi_dev->spcr = bus->spi_dev->spcr | SPI_SPCR_MSTR; + + tmp = bus->spi_dev->spdr; + + if(bus->count) { + if(bus->rx) + *bus->rx++ = tmp; + if(--bus->count) { + bus->spi_dev->spint = SPI_SPINT; + bus->spi_dev->spdr = bus->tx ? *bus->tx++ : 0; + cyg_drv_interrupt_acknowledge(bus->spi_vect); + return CYG_ISR_HANDLED; + } + } + + bus->count = 0; + bus->tx = NULL; + bus->rx = NULL; + + bus->spi_dev->spint = SPI_SPINT; + cyg_drv_interrupt_acknowledge(bus->spi_vect); + return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR; +} + +static void +spi_lpc2xxx_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data) +{ + cyg_drv_cond_signal(&((cyg_spi_lpc2xxx_bus_t *) data)->spi_wait); +} + + +/* + * Configure bus for a specific baud rate + */ +static void +spi_lpc2xxx_baud(cyg_spi_lpc2xxx_bus_t *bus, cyg_uint32 baud) +{ + cyg_uint32 ccr = 8; + + if(baud) { + ccr = (CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED + / CYGNUM_HAL_ARM_LPC2XXX_VPBDIV) / baud; + if(((CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED + / CYGNUM_HAL_ARM_LPC2XXX_VPBDIV) / ccr) > baud) + ccr++; + ccr++; + ccr &= 0xfe; + } + + bus->spi_dev->spccr = ccr < 8 ? 8 : ccr; +} + +/* + * get/set configuration + */ +static int +spi_lpc2xxx_get_config(cyg_spi_device *device, cyg_uint32 key, void *buf, + cyg_uint32 *len) +{ + cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; + + switch(key) { + case CYG_IO_GET_CONFIG_SPI_CLOCKRATE: + if(*len == sizeof(cyg_uint32)) { + cyg_uint32 *b = (cyg_uint32 *) buf; + *b = dev->spi_baud; + } else return -EINVAL; + break; + default: + return -EINVAL; + } + + return ENOERR; +} + +static int +spi_lpc2xxx_set_config(cyg_spi_device *device, cyg_uint32 key, const void *buf, + cyg_uint32 *len) +{ + cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; + + switch(key) { + case CYG_IO_SET_CONFIG_SPI_CLOCKRATE: + if(*len == sizeof(cyg_uint32)) { + dev->spi_baud = * (cyg_uint32 *) buf; + spi_lpc2xxx_baud((cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus, + dev->spi_baud); + } + else return -EINVAL; + break; + default: + return -EINVAL; + } + + return ENOERR; +} + + +/* + * Begin transaction + * configure bus for device and drive CS by calling device cs() function + */ +static void +spi_lpc2xxx_begin(cyg_spi_device *device) +{ + cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; + cyg_spi_lpc2xxx_bus_t *bus = + (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus; + + cyg_uint8 cr = + (dev->spi_cpha ? SPI_SPCR_CPHA : 0) | + (dev->spi_cpol ? SPI_SPCR_CPOL : 0) | + (dev->spi_lsbf ? SPI_SPCR_LSBF : 0); + + bus->spi_dev->spcr = SPI_SPCR_MSTR | cr; + + spi_lpc2xxx_baud(bus, dev->spi_baud); + + dev->spi_cs(1); +} + + +/* + * Transfer a buffer to a device, + * fill another buffer with data from the device + */ +static void +spi_lpc2xxx_transfer(cyg_spi_device *device, cyg_bool polled, cyg_uint32 count, + const cyg_uint8 *tx_data, cyg_uint8 *rx_data, + cyg_bool drop_cs) +{ + cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; + cyg_spi_lpc2xxx_bus_t *bus = + (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus; + cyg_uint8 tmp; + + if(!count) return; + + if(!polled) { + bus->count = count; + bus->tx = tx_data; + bus->rx = rx_data; + + bus->spi_dev->spcr |= SPI_SPCR_SPIE; + bus->spi_dev->spdr = bus->tx ? *bus->tx++ : 0; + + cyg_drv_mutex_lock(&bus->spi_lock); + cyg_drv_dsr_lock(); + cyg_drv_interrupt_unmask(bus->spi_vect); + while(bus->count) + cyg_drv_cond_wait(&bus->spi_wait); + cyg_drv_interrupt_mask(bus->spi_vect); + cyg_drv_dsr_unlock(); + cyg_drv_mutex_unlock(&bus->spi_lock); + } else do { + bus->spi_dev->spdr = tx_data ? *tx_data++ : 0; + while(!(bus->spi_dev->spsr & SPI_SPSR_SPIF)); + tmp = bus->spi_dev->spdr; + if(rx_data) + *rx_data++ = tmp; + count--; + } while(count); + + if(drop_cs) + dev->spi_cs(0); + + return; +} + + +/* + * Tick + */ +static void +spi_lpc2xxx_tick(cyg_spi_device *device, cyg_bool polled, cyg_uint32 count) +{ + spi_lpc2xxx_transfer(device, polled, count, NULL, NULL, false); +} + + +/* + * End transaction + * disable SPI bus, drop CS, reset transfer variables + */ +static void +spi_lpc2xxx_end(cyg_spi_device *device) +{ + cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device; + cyg_spi_lpc2xxx_bus_t *bus = + (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus; + + bus->spi_dev->spcr = 0; + dev->spi_cs(0); + + bus->count = 0; + bus->tx = NULL; + bus->rx = NULL; +} + + +/* + * Driver & bus initialization + */ +static void +spi_lpc2xxx_init_bus(cyg_spi_lpc2xxx_bus_t *bus, + cyg_addrword_t dev, + cyg_vector_t vec, + cyg_priority_t prio) +{ + bus->spi_bus.spi_transaction_begin = spi_lpc2xxx_begin; + bus->spi_bus.spi_transaction_transfer = spi_lpc2xxx_transfer; + bus->spi_bus.spi_transaction_tick = spi_lpc2xxx_tick; + bus->spi_bus.spi_transaction_end = spi_lpc2xxx_end; + bus->spi_bus.spi_get_config = spi_lpc2xxx_get_config; + bus->spi_bus.spi_set_config = spi_lpc2xxx_set_config; + CYG_SPI_BUS_COMMON_INIT(&bus->spi_bus); + + cyg_drv_mutex_init(&bus->spi_lock); + cyg_drv_cond_init(&bus->spi_wait, &bus->spi_lock); + + bus->spi_dev = (struct spi_dev *) dev; + bus->spi_vect = vec; + bus->spi_prio = prio; + cyg_drv_interrupt_create( + vec, prio, (cyg_addrword_t) bus, + &spi_lpc2xxx_isr, &spi_lpc2xxx_dsr, + &bus->spi_hand, &bus->spi_intr); + cyg_drv_interrupt_attach(bus->spi_hand); +} + +/* + * initialization class + */ +class cyg_spi_lpc2xxx_init_class { +public: + cyg_spi_lpc2xxx_init_class(void) { + cyg_uint32 addr, tmp; + +#ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS0 + addr = (CYGARC_HAL_LPC2XXX_REG_PIN_BASE + + CYGARC_HAL_LPC2XXX_REG_PINSEL0); + HAL_READ_UINT32(addr, tmp); + tmp |= 0x5500; + HAL_WRITE_UINT32(addr, tmp); + + spi_lpc2xxx_init_bus(&cyg_spi_lpc2xxx_bus0, + CYGARC_HAL_LPC2XXX_REG_SPI0_BASE, + CYGNUM_HAL_INTERRUPT_SPI0, + CYGNUM_IO_SPI_ARM_LPC2XXX_BUS0_INTPRIO); +#endif +#ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS1 + addr = (CYGARC_HAL_LPC2XXX_REG_PIN_BASE + + CYGARC_HAL_LPC2XXX_REG_PINSEL1); + HAL_READ_UINT32(addr, tmp); + tmp |= 0x2a8; + HAL_WRITE_UINT32(addr, tmp); + spi_lpc2xxx_init_bus(&cyg_spi_lpc2xxx_bus1, + CYGARC_HAL_LPC2XXX_REG_SPI1_BASE, + CYGNUM_HAL_INTERRUPT_SPI1, + CYGNUM_IO_SPI_ARM_LPC2XXX_BUS1_INTPRIO); +#endif + } +}; + +static cyg_spi_lpc2xxx_init_class spi_lpc2xxx_init + CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_BUS_SPI); + diff --git a/ecos/packages/devs/spi/cortexm/a2fxxx/current/ChangeLog b/ecos/packages/devs/spi/cortexm/a2fxxx/current/ChangeLog new file mode 100644 index 0000000..80da248 --- /dev/null +++ b/ecos/packages/devs/spi/cortexm/a2fxxx/current/ChangeLog @@ -0,0 +1,35 @@ +2012-01-04 Christophe Coutand <ecos@hotmail.co.uk> + * src/spi_a2fxxx.c: + Fix compiler warning, used uninitialized variable in a2fxxx_spi_set_ss(). + +2011-04-13 Christophe Coutand <ecos@hotmail.co.uk> + + * cdl/spi_a2fxxx.cdl: + * include/spi_a2fxxx.h: + * src/spi_a2fxxx.c: + New package -- Smartfusion Cortex-M3 SPI driver package. + [Bugzilla 1001291] + +//=========================================================================== +// ####GPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2011 Free Software Foundation, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. +// ------------------------------------------- +// ####GPLCOPYRIGHTEND#### +//=========================================================================== diff --git a/ecos/packages/devs/spi/cortexm/a2fxxx/current/cdl/spi_a2fxxx.cdl b/ecos/packages/devs/spi/cortexm/a2fxxx/current/cdl/spi_a2fxxx.cdl new file mode 100644 index 0000000..8d16000 --- /dev/null +++ b/ecos/packages/devs/spi/cortexm/a2fxxx/current/cdl/spi_a2fxxx.cdl @@ -0,0 +1,175 @@ +##============================================================================= +## +## spi_a2fxxx.cdl +## +## Smartfusion Cortex-M3 SPI driver configuration options. +## +##============================================================================= +## ####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. +## +## eCos is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free +## Software Foundation; either version 2 or (at your option) any later +## version. +## +## eCos is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with eCos; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## As a special exception, if other files instantiate templates or use +## macros or inline functions from this file, or you compile this file +## and link it with other works to produce a work based on this file, +## this file does not by itself cause the resulting work to be covered by +## the GNU General Public License. However the source code for this file +## must still be made available in accordance with section (3) of the GNU +## General Public License v2. +## +## This exception does not invalidate any other reasons why a work based +## on this file might be covered by the GNU General Public License. +## ------------------------------------------- +## ####ECOSGPLCOPYRIGHTEND#### +##============================================================================= +#######DESCRIPTIONBEGIN#### +## +## Author(s): ccoutand, updated for Smartfusion Cortex-M3 +## Original(s): Chris Holgate +## Date: 2011-04-25 +## Purpose: Configure Smartfusion Cortex-M3 SPI driver. +## +######DESCRIPTIONEND#### +## +##============================================================================= + +cdl_package CYGPKG_DEVS_SPI_CORTEXM_A2FXXX { + display "Actel Smartfusion SPI driver" + description " + This package provides SPI driver support for the Smartfusion Cortex-M3 + series of microcontrollers. + " + parent CYGPKG_IO_SPI + active_if CYGPKG_IO_SPI + requires CYGPKG_HAL_CORTEXM_A2FXXX + hardware + include_dir cyg/io + compile -library=libextras.a spi_a2fxxx.c + + cdl_option CYGDBG_DEVS_SPI_CORTEXM_A2FXXX_TRACE { + display "Display status messages during SPI operations" + flavor bool + default_value 0 + description " + Selecting this option will cause the SPI driver to print status + messages as various SPI operations are undertaken." + } + + cdl_component CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS1 { + display "Actel Smartfusion SPI bus 1" + description " + Enable SPI bus 1 on the A2FXXX device. + " + flavor bool + default_value false + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS1_TX_DMA { + display "Transmit DMA channel number" + flavor data + default_value 0 + } + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS1_RX_DMA { + display "Receive DMA channel number" + flavor data + default_value 1 + } + + cdl_option CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS1_TX_DMA_PRI { + display "Transmit DMA channel priority" + legal_values { "HIGH" "LOW" } + flavor data + default_value { "HIGH" } + } + + cdl_option CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS1_RX_DMA_PRI { + display "Receive DMA channel priority" + legal_values { "HIGH" "LOW" } + flavor data + default_value { "HIGH" } + } + } + + cdl_component CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS2 { + display "Actel Smartfusion SPI bus 2" + description " + Enable SPI bus 2 on the A2FXXX device. + " + flavor bool + default_value false + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS2_TX_DMA { + display "Transmit DMA channel number" + flavor data + default_value 2 + } + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS2_RX_DMA { + display "Receive DMA channel number" + flavor data + default_value 3 + } + + cdl_option CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS2_TX_DMA_PRI { + display "Transmit DMA channel priority" + legal_values { "HIGH" "LOW" } + flavor data + default_value { "HIGH" } + } + + cdl_option CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS2_RX_DMA_PRI { + display "Receive DMA channel priority" + legal_values { "HIGH" "LOW" } + flavor data + default_value { "HIGH" } + } + } + + cdl_component CYGPKG_DEVS_SPI_CORTEXM_A2FXXX_OPTIONS { + display "Actel Smartfusion SPI driver build options" + flavor none + description " + Package specific build options including control over + compiler flags used only in building this package, + and details of which tests are built." + + cdl_option CYGPKG_DEVS_SPI_CORTEXM_A2FXXX_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the A2FXXX SPI driver. These flags are used in addition + to the set of global flags." + } + + cdl_option CYGPKG_DEVS_SPI_CORTEXM_A2FXXX_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the A2FXXX SPI driver. These flags are removed from + the set of global flags if present." + } + } + +} +# EOF spi_a2fxxx.cdl diff --git a/ecos/packages/devs/spi/cortexm/a2fxxx/current/include/spi_a2fxxx.h b/ecos/packages/devs/spi/cortexm/a2fxxx/current/include/spi_a2fxxx.h new file mode 100644 index 0000000..a871b9a --- /dev/null +++ b/ecos/packages/devs/spi/cortexm/a2fxxx/current/include/spi_a2fxxx.h @@ -0,0 +1,195 @@ +#ifndef CYGONCE_DEVS_SPI_CORTEXM_STM32_H +# define CYGONCE_DEVS_SPI_CORTEXM_STM32_H +//============================================================================= +// +// spi_a2fxxx.h +// +// Header definitions for Smartfusion Cortex-M3 SPI driver. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): ccoutand, updated for Smartfusion Cortex-M3 +// Original(s): Chris Holgate +// Date: 2011-04-25 +// Purpose: Smartfusion Cortex-M3 SPI driver definitions. +// Description: +// Usage: #include <cyg/io/spi_a2fxxx.h> +// +//####DESCRIPTIONEND#### +// +//============================================================================= + +# include <pkgconf/hal.h> +# include <pkgconf/io_spi.h> +# include <pkgconf/devs_spi_cortexm_a2fxxx.h> + +# include <cyg/infra/cyg_type.h> +# include <cyg/hal/drv_api.h> +# include <cyg/io/spi.h> + +__externC cyg_uint32 a2fxxx_dma_ch_attach(cyg_uint8, cyg_ISR_t *, cyg_DSR_t *, + cyg_addrword_t); + +typedef enum a2fxxx_spi_mode { + A2FXXX_SPI_MOTOROLA = 0x00, + A2FXXX_SPI_TI_SYNC_SERIAL = 0x01, + A2FXXX_SPI_NS_MICROWIRE = 0x02 +} a2fxxx_spi_mode; + +//----------------------------------------------------------------------------- +// Macro for defining a SPI device and attaching it to the appropriate bus. +// +// _name_ is the name of the SPI device. This will be used to reference a +// data structure of type cyg_spi_device which can be passed to the +// SPI driver API without needing a cast. +// _bus_ is the bus number to which this device is attached (1, 2 or 3). +// _csnum_ when _csgpio_ is set to false : is the chip select line used for +// this device, numbered from 0. +// when _csgpio_ is set to true : is the GPIO number used to drive the +// device chip select line. +// _csgpio_ when set to false, the device chip select line is controlled by the +// SPI controller. +// when set to true, the device chip select line is a GPIO of the processor +// control by the SPI driver. +// _proto_ is the SPI bus protocol: +// 0 -> Motorola SPI Protocol (_clpol_ and _clpha_ are valid in this mode) +// 1 -> National Semiconductor MICROWIRE Protocol +// 2 -> Texas Instruments (TI) Synchronous Serial Protocol +// _clpol_ is the SPI bus clock polarity used by the device. This must be +// set to 1 if a clock line pullup resistor is used and 0 if a +// clock line pulldown resistor is used. +// _clpha_ is the SPI bus clock phase used by the device. +// _brate_ is the SPI bus clock baud rate used by the device, measured in Hz. +// _csup_dly_ is the minimum delay between chip select assert and transfer +// start, measured in microseconds. +// _csdw_dly_ is the minimum delay between transfer end and chip select deassert, +// measured in microseconds. +// _trbt_dly_ is the minimum delay between consecutive transfers. + +# define CYG_DEVS_SPI_CORTEXM_A2FXXX_DEVICE( \ + _name_, _bus_, _csnum_, _csgpio_, _proto_, _clpol_, _clpha_, _brate_, _csup_dly_, _csdw_dly_, _trbt_dly_\ +) \ +cyg_spi_cortexm_a2fxxx_device_t _name_ ##_a2fxxx CYG_SPI_DEVICE_ON_BUS(_bus_) = { \ +{ .spi_bus = (cyg_spi_bus*) &cyg_spi_a2fxxx_bus## _bus_ }, \ + .dev_num = _csnum_, \ + .cs_gpio = _csgpio_, \ + .cs_gpio_n = _csnum_, \ + .proto = _proto_, \ + .cl_pol = _clpol_, \ + .cl_pha = _clpha_, \ + .cl_brate = _brate_, \ + .cs_up_udly = _csup_dly_, \ + .cs_dw_udly = _csdw_dly_, \ + .tr_bt_udly = _trbt_dly_, \ + .spi_cr_val = 0, \ +}; \ +extern cyg_spi_device _name_ __attribute__((alias ( #_name_ "_a2fxxx" ))); + +//----------------------------------------------------------------------------- +// A2FXXX SPI bus configuration and state. + +typedef struct cyg_spi_cortexm_a2fxxx_bus_setup_s { + cyg_uint32 apb_freq; // Peripheral bus frequency (fp). + cyg_haladdress spi_reg_base; // Base address of SPI register block. + cyg_haladdress dma_reg_base; // Base address of DMA register block. + cyg_uint8 dma_tx_channel; // TX DMA channel for this bus. + cyg_uint8 dma_rx_channel; // RX DMA channel for this bus. + cyg_uint8 cs_gpio_num; // Number of chip selects for this bus. + const cyg_uint8 *cs_gpio_list; // List of GPIOs used as chip selects. + const cyg_uint8 *spi_gpio_list; // List of GPIOs used by the SPI interface. + cyg_bool dma_tx_pri; // Priority for DMA transmit. + cyg_bool dma_rx_pri; // Priority for DMA receive. + cyg_haladdress *rx_dma_null; + cyg_haladdress *tx_dma_null; +} cyg_spi_cortexm_a2fxxx_bus_setup_t; + +typedef struct cyg_spi_cortexm_a2fxxx_bus_s { + // ---- Upper layer data ---- + cyg_spi_bus spi_bus; // Upper layer SPI bus data. + + // ---- Bus configuration constants ---- + const cyg_spi_cortexm_a2fxxx_bus_setup_t *setup; + + // ---- Driver state (private) ---- + cyg_interrupt tx_intr_data; // DMA interrupt data (TX). + cyg_interrupt rx_intr_data; // DMA interrupt data (RX). + cyg_handle_t tx_intr_handle; // DMA interrupt handle (TX). + cyg_handle_t rx_intr_handle; // DMA interrupt handle (RX). + cyg_drv_mutex_t mutex; // Transfer mutex. + cyg_drv_cond_t condvar; // Transfer condition variable. + cyg_bool tx_dma_done; // Flags used to signal completion. + cyg_bool rx_dma_done; // Flags used to signal completion. + cyg_bool cs_up; // Chip select asserted flag. + +} cyg_spi_cortexm_a2fxxx_bus_t; + +//----------------------------------------------------------------------------- +// A2FXXX SPI device. + +typedef struct cyg_spi_cortexm_a2fxxx_device_s { + // ---- Upper layer data ---- + cyg_spi_device spi_device; // Upper layer SPI device data. + + // ---- Device setup (user configurable) ---- + cyg_uint8 dev_num; // Device number. + a2fxxx_spi_mode proto; // Protocol + cyg_bool cs_gpio; // True = use GPIO to control CS line + cyg_uint32 cs_gpio_n; // GPIO # + cyg_uint8 cl_pol; // Clock polarity (0 or 1). + cyg_uint8 cl_pha; // Clock phase (0 or 1). + cyg_uint32 cl_brate; // Clock baud rate. + cyg_uint16 cs_up_udly; // Minimum delay in us between CS up and transfer start. + cyg_uint16 cs_dw_udly; // Minimum delay in us between transfer end and CS down. + cyg_uint16 tr_bt_udly; // Minimum delay in us between two transfers. + + // ---- Device state (private) ---- + cyg_uint32 spi_cr_val; // SPI configuration register (initialised to 0). + +} cyg_spi_cortexm_a2fxxx_device_t; + +//----------------------------------------------------------------------------- +// Exported bus data structures. + +# ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS1 +externC cyg_spi_cortexm_a2fxxx_bus_t cyg_spi_a2fxxx_bus1; +# endif + +# ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS2 +externC cyg_spi_cortexm_a2fxxx_bus_t cyg_spi_a2fxxx_bus2; +# endif + +//============================================================================= +#endif // CYGONCE_DEVS_SPI_CORTEXM_A2FXXX_H diff --git a/ecos/packages/devs/spi/cortexm/a2fxxx/current/src/spi_a2fxxx.c b/ecos/packages/devs/spi/cortexm/a2fxxx/current/src/spi_a2fxxx.c new file mode 100644 index 0000000..3459fdc --- /dev/null +++ b/ecos/packages/devs/spi/cortexm/a2fxxx/current/src/spi_a2fxxx.c @@ -0,0 +1,638 @@ +//============================================================================= +// +// spi_a2fxxx.c +// +// SPI driver implementation for Smartfusion Cortex-M3 +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): ccoutand, updated for Smartfusion Cortex-M3 +// Original(s): Chris Holgate +// Date: 2011-04-25 +// Purpose: Smartfusion Cortex-M3 SPI driver implementation +// +//####DESCRIPTIONEND#### +// +//============================================================================= + +#include <cyg/hal/hal_io.h> +#include <cyg/hal/hal_if.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/hal/drv_api.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/diag.h> + +#include <cyg/io/spi.h> +#include <cyg/io/spi_a2fxxx.h> + +#include <pkgconf/devs_spi_cortexm_a2fxxx.h> + +#include <string.h> + +#if defined(CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS1) || \ + defined(CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS2) + +#ifdef CYGDBG_DEVS_SPI_CORTEXM_A2FXXX_TRACE +# define SPI_TRACE(args...) diag_printf(args) +#else +# define SPI_TRACE(args...) +#endif + +//----------------------------------------------------------------------------- +// API function call forward references. + +static void a2fxxx_transaction_begin (cyg_spi_device*); +static void a2fxxx_transaction_transfer (cyg_spi_device*, cyg_bool, cyg_uint32, const cyg_uint8*, cyg_uint8*, cyg_bool); +static void a2fxxx_transaction_tick (cyg_spi_device*, cyg_bool, cyg_uint32); +static void a2fxxx_transaction_end (cyg_spi_device*); +static int a2fxxx_get_config (cyg_spi_device*, cyg_uint32, void*, cyg_uint32*); +static int a2fxxx_set_config (cyg_spi_device*, cyg_uint32, const void*, cyg_uint32*); + +//----------------------------------------------------------------------------- +// Instantiate the bus state data structures. + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS1 + +static cyg_haladdress rx1_dma_null = 0x0; +static cyg_haladdress tx1_dma_null = 0x0; + +static const cyg_spi_cortexm_a2fxxx_bus_setup_t bus1_setup = { + .spi_reg_base = CYGHWR_HAL_A2FXXX_SPI0, + .dma_reg_base = CYGHWR_HAL_A2FXXX_DMA, + .dma_tx_channel = CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS1_TX_DMA, + .dma_rx_channel = CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS1_RX_DMA, +#ifdef CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS1_TX_DMA_PRI_HIGH + .dma_tx_pri = true, +#else + .dma_tx_pri = false, +#endif +#ifdef CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS1_RX_DMA_PRI_HIGH + .dma_rx_pri = true, +#else + .dma_rx_pri = false, +#endif + .rx_dma_null = &rx1_dma_null, + .tx_dma_null = &tx1_dma_null, +}; + +cyg_spi_cortexm_a2fxxx_bus_t cyg_spi_a2fxxx_bus1 = { + .spi_bus.spi_transaction_begin = a2fxxx_transaction_begin, + .spi_bus.spi_transaction_transfer = a2fxxx_transaction_transfer, + .spi_bus.spi_transaction_tick = a2fxxx_transaction_tick, + .spi_bus.spi_transaction_end = a2fxxx_transaction_end, + .spi_bus.spi_get_config = a2fxxx_get_config, + .spi_bus.spi_set_config = a2fxxx_set_config, + .setup = &bus1_setup, + .cs_up = false +}; +#endif + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS2 + +static cyg_haladdress rx2_dma_null = 0x0; +static cyg_haladdress tx2_dma_null = 0x0; + +static const cyg_spi_cortexm_a2fxxx_bus_setup_t bus2_setup = { + .spi_reg_base = CYGHWR_HAL_A2FXXX_SPI1, + .dma_reg_base = CYGHWR_HAL_A2FXXX_DMA, + .dma_tx_channel = CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS2_TX_DMA, + .dma_rx_channel = CYGNUM_DEVS_SPI_CORTEXM_A2FXXX_BUS2_RX_DMA, +#ifdef CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS2_TX_DMA_PRI_HIGH + .dma_tx_pri = true, +#else + .dma_tx_pri = false, +#endif +#ifdef CYGDAT_DEVS_SPI_CORTEXM_A2FXXX_BUS2_RX_DMA_PRI_HIGH + .dma_rx_pri = true, +#else + .dma_rx_pri = false, +#endif + .rx_dma_null = &rx2_dma_null, + .tx_dma_null = &tx2_dma_null, +}; + +cyg_spi_cortexm_a2fxxx_bus_t cyg_spi_a2fxxx_bus2 = { + .spi_bus.spi_transaction_begin = a2fxxx_transaction_begin, + .spi_bus.spi_transaction_transfer = a2fxxx_transaction_transfer, + .spi_bus.spi_transaction_tick = a2fxxx_transaction_tick, + .spi_bus.spi_transaction_end = a2fxxx_transaction_end, + .spi_bus.spi_get_config = a2fxxx_get_config, + .spi_bus.spi_set_config = a2fxxx_set_config, + .setup = &bus2_setup, + .cs_up = false +}; +#endif + + +//----------------------------------------------------------------------------- +// Implement DMA ISRs. These clear the DMA channel interrupts and +// schedule their respective DSRs. + +static cyg_uint32 a2fxxx_tx_ISR + (cyg_vector_t vector, cyg_addrword_t data) +{ + cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus = + (cyg_spi_cortexm_a2fxxx_bus_t*) data; + cyg_uint8 chan = a2fxxx_bus->setup->dma_tx_channel; + SPI_TRACE("SPI : Handle TX ISR\n"); + a2fxxx_dma_clear_interrupt ( chan ); + return (CYG_ISR_CALL_DSR | CYG_ISR_HANDLED); +} + +static cyg_uint32 a2fxxx_rx_ISR + (cyg_vector_t vector, cyg_addrword_t data) +{ + cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus = + (cyg_spi_cortexm_a2fxxx_bus_t*) data; + cyg_uint8 chan = a2fxxx_bus->setup->dma_rx_channel; + SPI_TRACE("SPI : Handle RX ISR\n"); + a2fxxx_dma_clear_interrupt ( chan ); + return (CYG_ISR_CALL_DSR | CYG_ISR_HANDLED); +} + +//----------------------------------------------------------------------------- +// Implement DMA DSRs. These clear down the interrupt conditions and assert +// their respective 'transaction complete' flags. + +static void a2fxxx_tx_DSR + (cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus = + (cyg_spi_cortexm_a2fxxx_bus_t*) data; + SPI_TRACE("SPI : Handle TX DSR\n"); + cyg_drv_dsr_lock (); + a2fxxx_bus->tx_dma_done = true; + cyg_drv_cond_signal (&a2fxxx_bus->condvar); + cyg_drv_dsr_unlock (); +} + +static void a2fxxx_rx_DSR + (cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus = + (cyg_spi_cortexm_a2fxxx_bus_t*) data; + SPI_TRACE("SPI : Handle RX DSR\n"); + cyg_drv_dsr_lock (); + a2fxxx_bus->rx_dma_done = true; + cyg_drv_cond_signal (&a2fxxx_bus->condvar); + cyg_drv_dsr_unlock (); +} + +//----------------------------------------------------------------------------- +// Set up a new SPI bus on initialization. + +static void a2fxxx_spi_bus_setup + (cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus) +{ + cyg_uint8 dma_tx_type, dma_rx_type; + + if( a2fxxx_bus->setup->spi_reg_base == CYGHWR_HAL_A2FXXX_SPI1 ){ + CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI1_DO ); + CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI1_DI ); + CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI1_CLK ); + dma_tx_type = CYGHWR_HAL_A2FXXX_DMA_XFER(TO_SPI1); + dma_rx_type = CYGHWR_HAL_A2FXXX_DMA_XFER(FROM_SPI1); + } + else { + CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI0_DO ); + CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI0_DI ); + CYGHWR_HAL_A2FXXX_GPIO_SET( CYGHWR_HAL_A2FXXX_SPI0_CLK ); + dma_tx_type = CYGHWR_HAL_A2FXXX_DMA_XFER(TO_SPI0); + dma_rx_type = CYGHWR_HAL_A2FXXX_DMA_XFER(FROM_SPI0); + } + + // Initialize the synchronization primitives. + cyg_drv_mutex_init (&a2fxxx_bus->mutex); + cyg_drv_cond_init (&a2fxxx_bus->condvar, &a2fxxx_bus->mutex); + + // Setup DMA channel + a2fxxx_dma_ch_setup(a2fxxx_bus->setup->dma_tx_channel, dma_tx_type, + CYGHWR_HAL_A2FXXX_DMA_OUTBOUND, sizeof(cyg_uint8), 0, + a2fxxx_bus->setup->dma_tx_pri, 9); + a2fxxx_dma_ch_setup(a2fxxx_bus->setup->dma_rx_channel, dma_rx_type, + CYGHWR_HAL_A2FXXX_DMA_INBOUND, 0, sizeof(cyg_uint8), + a2fxxx_bus->setup->dma_rx_pri, 9); + + // Register ISR /DSR + a2fxxx_dma_ch_attach(a2fxxx_bus->setup->dma_tx_channel, + a2fxxx_tx_ISR, a2fxxx_tx_DSR, (cyg_addrword_t) a2fxxx_bus); + + a2fxxx_dma_ch_attach(a2fxxx_bus->setup->dma_rx_channel, + a2fxxx_rx_ISR, a2fxxx_rx_DSR, (cyg_addrword_t) a2fxxx_bus); + + // Call upper layer bus init. + CYG_SPI_BUS_COMMON_INIT(&a2fxxx_bus->spi_bus); +} + +//----------------------------------------------------------------------------- +// Drive a GPIO pin as a SPI chip select line. + +static inline void a2fxxx_spi_chip_select + (cyg_spi_device* device, cyg_bool assert) +{ + cyg_spi_cortexm_a2fxxx_device_t* a2fxxx_device = + (cyg_spi_cortexm_a2fxxx_device_t*) device; + cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus = + (cyg_spi_cortexm_a2fxxx_bus_t*) device->spi_bus; + + // CS is driven from GPIO + if( a2fxxx_device->cs_gpio == true) { + if (assert == true) + CYGHWR_HAL_A2FXXX_GPIO_OUT( a2fxxx_device->cs_gpio_n, 0 ); + else + CYGHWR_HAL_A2FXXX_GPIO_OUT( a2fxxx_device->cs_gpio_n, 1 ); + } + // CS is driven from controller + else { + cyg_uint32 reg_addr = a2fxxx_bus->setup->spi_reg_base + + CYGHWR_HAL_A2FXXX_SPI_SLAVE_SEL; + cyg_uint32 reg_data; + HAL_READ_UINT32 (reg_addr, reg_data); + if (assert == true) + reg_data |= CYGHWR_HAL_A2FXXX_SPI_CS_SEL(a2fxxx_device->dev_num); + else + reg_data &= ~CYGHWR_HAL_A2FXXX_SPI_CS_SEL(a2fxxx_device->dev_num); + HAL_WRITE_UINT32 (reg_addr, reg_data); + } +} + +//----------------------------------------------------------------------------- +// Configure build-in SPI chip select line + +static inline void a2fxxx_spi_set_ss + (cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus, cyg_uint8 ss_num) +{ + cyg_uint32 ss; + + if( a2fxxx_bus->setup->spi_reg_base == CYGHWR_HAL_A2FXXX_SPI0 ){ + if ( ss_num == 0 ) { + ss = CYGHWR_HAL_A2FXXX_SPI0_SS0; + } else if( ss_num == 1 ) { + ss = CYGHWR_HAL_A2FXXX_SPI0_SS1; + } else if( ss_num == 2 ) { + ss = CYGHWR_HAL_A2FXXX_SPI0_SS2; + } else if( ss_num == 3 ) { + ss = CYGHWR_HAL_A2FXXX_SPI0_SS3; + } else { + CYG_ASSERT (ss < 4, "SPI : SPI0 SS out of range."); + return; + } + } + else { + if ( ss_num == 0 ) { + ss = CYGHWR_HAL_A2FXXX_SPI1_SS0; + } else if( ss_num == 1 ) { + ss = CYGHWR_HAL_A2FXXX_SPI1_SS1; + } else if( ss_num == 2 ) { + ss = CYGHWR_HAL_A2FXXX_SPI1_SS2; + } else if( ss_num == 3 ) { + ss = CYGHWR_HAL_A2FXXX_SPI1_SS3; + } else if( ss_num == 4 ) { + ss = CYGHWR_HAL_A2FXXX_SPI1_SS4; + } else if( ss_num == 5 ) { + ss = CYGHWR_HAL_A2FXXX_SPI1_SS5; + } else if( ss_num == 6 ) { + ss = CYGHWR_HAL_A2FXXX_SPI1_SS6; + } else if( ss_num == 7 ) { + ss = CYGHWR_HAL_A2FXXX_SPI1_SS7; + } else { + CYG_ASSERT (ss < 8, "SPI : SPI1 SS out of range."); + return; + } + } + + CYGHWR_HAL_A2FXXX_GPIO_SET( ss ); +} + +//----------------------------------------------------------------------------- +// Initiate a DMA transfer over the SPI interface. + +static void spi_transaction_dma + (cyg_spi_device* device, cyg_bool tick_only, cyg_bool polled, cyg_uint32 count, + const cyg_uint8* tx_data, cyg_uint8* rx_data, cyg_bool drop_cs) +{ + cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus = + (cyg_spi_cortexm_a2fxxx_bus_t*) device->spi_bus; + cyg_spi_cortexm_a2fxxx_device_t* a2fxxx_device = + (cyg_spi_cortexm_a2fxxx_device_t*) device; + cyg_haladdress reg_addr; + cyg_uint32 spi_cr_val = a2fxxx_device->spi_cr_val; + cyg_haladdress spi_reg_base = a2fxxx_bus->setup->spi_reg_base; + + SPI_TRACE("SPI : Transfer start\n"); + + // Drive chip select low, either from GPIO or build in SS signal + if( !a2fxxx_bus->cs_up && !tick_only ){ + SPI_TRACE("SPI : Setup CS\n"); + CYGACC_CALL_IF_DELAY_US (a2fxxx_device->tr_bt_udly); + a2fxxx_spi_chip_select (device, true); + CYGACC_CALL_IF_DELAY_US (a2fxxx_device->cs_up_udly); + a2fxxx_bus->cs_up = true; + } + + // Disable the SPI controller. + reg_addr = spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_CTRL; + HAL_WRITE_UINT32 (reg_addr, a2fxxx_device->spi_cr_val); + + // Write down transfer count + spi_cr_val |= CYGHWR_HAL_A2FXXX_SPI_CTRL_COUNT( count ); + reg_addr = spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_CTRL; + HAL_WRITE_UINT32 (reg_addr, spi_cr_val); + + // + // Setup DMA channels + // For null source or destination pointer, replace the buffer with the SPI driver + // dummy buffer and set the DMA address increment to 0 + // + if(tx_data == NULL) + a2fxxx_dma_update_incr(a2fxxx_bus->setup->dma_tx_channel, false, 0); + else + a2fxxx_dma_update_incr(a2fxxx_bus->setup->dma_tx_channel, false, + sizeof(cyg_uint8)); + + if(rx_data == NULL) + a2fxxx_dma_update_incr(a2fxxx_bus->setup->dma_rx_channel, true, 0); + else + a2fxxx_dma_update_incr(a2fxxx_bus->setup->dma_rx_channel, true, + sizeof(cyg_uint8)); + + a2fxxx_bus->tx_dma_done = false; + a2fxxx_dma_xfer (a2fxxx_bus->setup->dma_tx_channel, polled, count, + ((tx_data == NULL) ? (cyg_uint8*) a2fxxx_bus->setup->tx_dma_null : + (cyg_uint8*) tx_data), + (cyg_uint8*)(a2fxxx_bus->setup->spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_TX)); + + a2fxxx_bus->rx_dma_done = false; + a2fxxx_dma_xfer (a2fxxx_bus->setup->dma_rx_channel, polled, count, + (cyg_uint8*)(a2fxxx_bus->setup->spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_RX), + ((rx_data == NULL) ? (cyg_uint8*) a2fxxx_bus->setup->rx_dma_null : + (cyg_uint8*) rx_data)); + + // + // Run the DMA (polling for completion). + // + if (polled) + { + // Enable the SPI controller. + SPI_TRACE("SPI : Control Register 0x%x, 0x%x, %d\n", reg_addr, + spi_cr_val, count); + HAL_WRITE_UINT32 (reg_addr, spi_cr_val | CYGHWR_HAL_A2FXXX_SPI_CTRL_EN); + + // Wait transfer completed. + do { + if(a2fxxx_dma_get_comp_flag(a2fxxx_bus->setup->dma_rx_channel)) + a2fxxx_bus->rx_dma_done = true; + if(a2fxxx_dma_get_comp_flag(a2fxxx_bus->setup->dma_tx_channel)) + a2fxxx_bus->tx_dma_done = true; + } while ( !(a2fxxx_bus->tx_dma_done && a2fxxx_bus->rx_dma_done) ); + + // Acknowledge transfer + a2fxxx_dma_clear_interrupt (a2fxxx_bus->setup->dma_rx_channel); + a2fxxx_dma_clear_interrupt (a2fxxx_bus->setup->dma_tx_channel); + + } else { + cyg_drv_mutex_lock (&a2fxxx_bus->mutex); + cyg_drv_dsr_lock (); + + // Enable the SPI controller. + SPI_TRACE("SPI : Control Register 0x%x, 0x%x, %d\n", reg_addr, + spi_cr_val, count); + HAL_WRITE_UINT32 (reg_addr, spi_cr_val | CYGHWR_HAL_A2FXXX_SPI_CTRL_EN); + + // Sit back and wait for the ISR/DSRs to signal completion. + do { + cyg_drv_cond_wait (&a2fxxx_bus->condvar); + } while (!(a2fxxx_bus->tx_dma_done && a2fxxx_bus->rx_dma_done)); + + cyg_drv_dsr_unlock (); + cyg_drv_mutex_unlock (&a2fxxx_bus->mutex); + } + + SPI_TRACE("SPI : Transfer completed\n"); + + if (drop_cs && !tick_only) { + SPI_TRACE("SPI : Release chip select\n"); + CYGACC_CALL_IF_DELAY_US (a2fxxx_device->cs_dw_udly); + a2fxxx_spi_chip_select (device, false); + a2fxxx_bus->cs_up = false; + } +} + +//----------------------------------------------------------------------------- +// Initialize SPI interfaces on startup. + +static void CYGBLD_ATTRIB_C_INIT_PRI(CYG_INIT_BUS_SPI) +a2fxxx_spi_init(void) +{ + hal_dma_init(); + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS1 + CYGHWR_HAL_A2FXXX_PERIPH_RELEASE( CYGHWR_HAL_A2FXXX_PERIPH_SOFTRST(SPI0) ); + a2fxxx_spi_bus_setup (&cyg_spi_a2fxxx_bus1); +#endif + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_A2FXXX_BUS2 + CYGHWR_HAL_A2FXXX_PERIPH_RELEASE( CYGHWR_HAL_A2FXXX_PERIPH_SOFTRST(SPI1) ); + a2fxxx_spi_bus_setup (&cyg_spi_a2fxxx_bus2); +#endif +} + +//----------------------------------------------------------------------------- +// Start a SPI transaction. + +static void a2fxxx_transaction_begin + (cyg_spi_device* device) +{ + cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus = + (cyg_spi_cortexm_a2fxxx_bus_t*) device->spi_bus; + cyg_spi_cortexm_a2fxxx_device_t* a2fxxx_device = + (cyg_spi_cortexm_a2fxxx_device_t*) device; + + cyg_haladdress reg_addr; + cyg_uint32 reg_data, divided_clk, br, cs_gpio_n; + + SPI_TRACE("SPI : Transfer begin\n"); + SPI_TRACE("SPI : Device baud rate = %d\n", a2fxxx_device->cl_brate); + SPI_TRACE("SPI : Device clock polarity = %d\n", a2fxxx_device->cl_pol); + SPI_TRACE("SPI : Device clock phase = %d\n", a2fxxx_device->cl_pha); + + // On the first transaction, generate the values to be programmed into the + // SPI configuration registers for this device and cache them. This avoids + // having to recalculate the values for every transaction. + if (!a2fxxx_device->spi_cr_val) { + + // SPI bus protocol + switch( a2fxxx_device->proto ) { + case A2FXXX_SPI_TI_SYNC_SERIAL: + reg_data = CYGHWR_HAL_A2FXXX_SPI_CTRL_PROTO_TI; + break; + case A2FXXX_SPI_NS_MICROWIRE: + reg_data = CYGHWR_HAL_A2FXXX_SPI_CTRL_PROTO_NS; + break; + default: + reg_data = CYGHWR_HAL_A2FXXX_SPI_CTRL_PROTO_MOTOROLA; + break; + } + + // Bus polarity + if (a2fxxx_device->cl_pol) + reg_data |= CYGHWR_HAL_A2FXXX_SPI_CTRL_SPO; + if (a2fxxx_device->cl_pha) + reg_data |= CYGHWR_HAL_A2FXXX_SPI_CTRL_SPH; + + // Master mode + reg_data |= CYGHWR_HAL_A2FXXX_SPI_CTRL_MASTER; + + // Calculate the maximum viable bus speed. + divided_clk = hal_a2fxxx_spi_clock(a2fxxx_bus->setup->spi_reg_base) >> 1; + for (br = 0; (br < 7) && (divided_clk > a2fxxx_device->cl_brate); br++) + divided_clk >>= 1; + + CYG_ASSERT (divided_clk <= a2fxxx_device->cl_brate, + "A2FXXX SPI : Cannot run bus slowly enough for peripheral."); + + SPI_TRACE("SPI : Clock divider = %d\n", divided_clk); + + reg_addr = a2fxxx_bus->setup->spi_reg_base + + CYGHWR_HAL_A2FXXX_SPI_CLK_GEN; + HAL_WRITE_UINT32 (reg_addr, br); + + // Set transfer size (byte mode) + reg_addr = a2fxxx_bus->setup->spi_reg_base + + CYGHWR_HAL_A2FXXX_SPI_TXRXDF_SIZE; + HAL_WRITE_UINT32 (reg_addr, 8); + + // Cache the configuration register settings. + a2fxxx_device->spi_cr_val = reg_data; + + // Configure GPIO as chip select + if(a2fxxx_device->cs_gpio == true) { + cs_gpio_n = a2fxxx_device->cs_gpio_n; + SPI_TRACE("SPI : Setup GPIO for CS => %d\n", cs_gpio_n); + a2fxxx_device->cs_gpio_n = + CYGHWR_HAL_A2FXXX_CS_GPIO( cs_gpio_n, OUT, cs_gpio_n, DISABLE ); + CYGHWR_HAL_A2FXXX_GPIO_SET( a2fxxx_device->cs_gpio_n ); + CYGHWR_HAL_A2FXXX_GPIO_OUT( a2fxxx_device->cs_gpio_n, 1); + } + // Configure build-in SPI chip select line + else { + SPI_TRACE("SPI : Setup SPI SS => %d\n", a2fxxx_device->dev_num); + a2fxxx_spi_set_ss(a2fxxx_bus, a2fxxx_device->dev_num); + } + } + + // Set up the SPI controller. + reg_addr = a2fxxx_bus->setup->spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_CTRL; + HAL_WRITE_UINT32 (reg_addr, a2fxxx_device->spi_cr_val); +} + +//----------------------------------------------------------------------------- +// Run a transaction transfer. + +static void a2fxxx_transaction_transfer + (cyg_spi_device* device, cyg_bool polled, cyg_uint32 count, + const cyg_uint8* tx_data, cyg_uint8* rx_data, cyg_bool drop_cs) +{ + // Check for unsupported transactions. + CYG_ASSERT (count > 0, "A2FXXX SPI : Null transfer requested."); + + // Perform transfer + spi_transaction_dma (device, false, polled, count, tx_data, rx_data, drop_cs); +} + +//----------------------------------------------------------------------------- +// Carry out a bus tick operation - this just pushes the required number of +// zeros onto the bus, leaving the chip select in its current state. + +static void a2fxxx_transaction_tick + (cyg_spi_device* device, cyg_bool polled, cyg_uint32 count) +{ + // Check for unsupported transactions. + CYG_ASSERT (count > 0, "A2FXXX SPI : Null transfer requested."); + + SPI_TRACE("SPI : Transfer tick\n"); + + // Perform null transfer. + spi_transaction_dma (device, true, polled, count, NULL, NULL, false); +} + +//----------------------------------------------------------------------------- +// Terminate a SPI transaction, disabling the SPI controller. + +static void a2fxxx_transaction_end + (cyg_spi_device* device) +{ + cyg_spi_cortexm_a2fxxx_bus_t* a2fxxx_bus = + (cyg_spi_cortexm_a2fxxx_bus_t*) device->spi_bus; + cyg_spi_cortexm_a2fxxx_device_t* a2fxxx_device = + (cyg_spi_cortexm_a2fxxx_device_t*) device; + cyg_haladdress reg_addr; + + SPI_TRACE("SPI : Transfer end\n"); + + // De-assert chip select + if( a2fxxx_bus->cs_up == true ){ + SPI_TRACE("SPI : Release chip select\n"); + CYGACC_CALL_IF_DELAY_US (a2fxxx_device->cs_dw_udly); + a2fxxx_spi_chip_select (device, false); + a2fxxx_bus->cs_up = false; + } + + // Disable controller + reg_addr = a2fxxx_bus->setup->spi_reg_base + CYGHWR_HAL_A2FXXX_SPI_CTRL; + HAL_WRITE_UINT32 (reg_addr, a2fxxx_device->spi_cr_val); +} + +//----------------------------------------------------------------------------- +// Note that no dynamic configuration options are currently defined. + +static int a2fxxx_get_config + (cyg_spi_device* dev, cyg_uint32 key, void* buf, cyg_uint32* len) +{ + return -1; +} + +static int a2fxxx_set_config + (cyg_spi_device* dev, cyg_uint32 key, const void* buf, cyg_uint32* len) +{ + return -1; +} + +#endif + +//============================================================================= diff --git a/ecos/packages/devs/spi/cortexm/stm32/current/ChangeLog b/ecos/packages/devs/spi/cortexm/stm32/current/ChangeLog new file mode 100644 index 0000000..ef60956 --- /dev/null +++ b/ecos/packages/devs/spi/cortexm/stm32/current/ChangeLog @@ -0,0 +1,140 @@ +2012-03-28 Jonathan Larmour <jifl@eCosCentric.com> + + * src/spi_stm32.c (bus3_rx_bbuf): Fix typo in attribute. + +2012-03-23 James Smith <jsmith@ecoscentric.com> + + * src/spi_stm32.c (CYGHWR_HAL_STM32_GPIO_MODE_OUT_SPEED_SPI): + Rename CYGHWR_HAL_STM32_GPIO_MODE_OUT_SPI to allow the same + SPEED_SPI value to be used for F1 and F2/F4 targets. + (SPI_CS): Use new wrapper macros to provide a single common SPI_CS + manifest. + +2012-03-15 James Smith <jsmith@ecoscentric.com> + + * src/spi_stm32.c: Use HIPERFORMANCE manifest to allow F2 and F4 + device GPIO initialisation support. + (dma_channel_setup): Avoid compiler pointer type warning. + +2012-03-05 James Smith <jsmith@ecoscentric.com> + + * src/spi_stm32.c (spi_transaction_dma): Avoid race condition by + seting the TX and RX DMA done flags to false prior to configuring + (and starting) the DMA transfer. + +2012-01-12 Nick Garnett <nickg@ecoscentric.com> + + * cdl/spi_stm32.cdl: Select pin toggle rate based on STM32 + family. Define interrupt priorities to include DMA channel + priorities. Undo 2011-12-09 change, F2 now supported. + + * include/spi_stm32.h (cyg_spi_cortexm_stm32_bus_s): + * src/spi_stm32.c: Substantial reorganization to use DMA API. + NOTE: Currently only fully tested on F2 parts. + +2011-12-09 Jonathan Larmour <jifl@eCosCentric.com> + + * cdl/spi_stm32.cdl: For now, only allow this package to be + active with F1 family processors. + +2011-09-27 Ilija Stanislevik <ilijas@siva.mk> + + * src/spi_stm32.c: Add support for CYG_IO_GET_CONFIG_SPI_CLOCKRATE and + CYG_IO_SET_CONFIG_SPI_CLOCKRATE (possibility to retrieve and to set + the SPI clockrate). + +2011-03-10 John Dallaway <john@dallaway.org.uk> + + * cdl/spi_stm32.cdl: Add build options for CFLAGS and loopback test. + +2009-10-22 Nick Garnett <nickg@ecoscentric.com> + + * cdl/spi_stm32.cdl: Fix descriptions for chip select + options. Only build local test if SPI bus 1 is active. + + * include/spi_stm32.h (cyg_spi_cortexm_stm32_bus_setup_s): Add + spi_gpio_remap field. + + * src/spi_stm32.c (bus1_setup, bus2_setup, bus3_setup): Fix CS + number calculation, add remap to each bus. + (stm32_spi_bus_setup): Move enables to correct place. Add code to + remap SPI pins if defined. + +2009-08-24 Simon Kallweit <simon.kallweit@intefo.ch> + + * cdl/spi_stm32.cdl: added testcase. + * include/spi_stm32.h: initializing spi_cr1_val with zero. + +2009-06-29 Nick Garnett <nickg@ecoscentric.com> + + * cdl/spi_stm32.cdl: + * include/spi_stm32.h (cyg_spi_cortexm_stm32_bus_setup_s): + * src/spi_stm32.c: Add support for individual device clock + enables. Also change mechanism for specifying CS lines that is + more in keeping with other devices. + +2009-03-23 Nick Garnett <nickg@ecoscentric.com> + + * cdl/spi_stm32.cdl: Fix up a few oddities. + + * src/spi_stm32.c (spi_diag): Add some diagnostics. + +2009-02-10 Bart Veer <bartv@ecoscentric.com> + + * src/spi_stm32.c (cyg_spi_cortexm_stm32_init): mark as + prioritized constructor and rename. + + * cdl/spi_stm32.cdl: stop building spi_stm32_init.cxx + + * src/spi_stm32_init.cxx: removed, no longer needed. + +2009-02-10 Chris Holgate <chris@zynaptic.com> + + * src/spi_stm32.c: + * cdl/spi_stm32.cdl: + Add option to automatically disable JTAG port when initialising SPI3. + +2009-02-10 Nick Garnett <nickg@ecoscentric.com> + + * src/spi_stm32.c (bus3_setup): Fix typo. + +2009-02-05 Nick Garnett <nickg@ecoscentric.com> + + * include/spi_stm32.h: Add macro to define an STM32 SPI device. + + * src/spi_stm32.c: Fix potential compile error. + + * src/spi_stm32_init.cxx: Change constructor init priority to use + CYG_INIT_BUS_SPI. + +2009-01-30 Nick Garnett <nickg@ecoscentric.com> + + * cdl/spi_stm32.cdl: + * include/spi_stm32.h: + * src/spi_stm32.c: + * src/spi_stm32_init.cxx: + New package, STM32 SPI driver contributed by Chris Holgate. + +//=========================================================================== +// ####GPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. +// ------------------------------------------- +// ####GPLCOPYRIGHTEND#### +//=========================================================================== diff --git a/ecos/packages/devs/spi/cortexm/stm32/current/cdl/spi_stm32.cdl b/ecos/packages/devs/spi/cortexm/stm32/current/cdl/spi_stm32.cdl new file mode 100644 index 0000000..32d5b24 --- /dev/null +++ b/ecos/packages/devs/spi/cortexm/stm32/current/cdl/spi_stm32.cdl @@ -0,0 +1,272 @@ +##============================================================================= +## +## spi_stm32.cdl +## +## STM32 SPI driver configuration options. +## +##============================================================================= +## ####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 2008, 2009, 2011, 2012 Free Software Foundation, Inc. +## +## eCos is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free +## Software Foundation; either version 2 or (at your option) any later +## version. +## +## eCos is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with eCos; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## As a special exception, if other files instantiate templates or use +## macros or inline functions from this file, or you compile this file +## and link it with other works to produce a work based on this file, +## this file does not by itself cause the resulting work to be covered by +## the GNU General Public License. However the source code for this file +## must still be made available in accordance with section (3) of the GNU +## General Public License v2. +## +## This exception does not invalidate any other reasons why a work based +## on this file might be covered by the GNU General Public License. +## ------------------------------------------- +## ####ECOSGPLCOPYRIGHTEND#### +##============================================================================= +#######DESCRIPTIONBEGIN#### +## +## Author(s): Chris Holgate +## Contributor: jld +## Date: 2008-11-27 +## Purpose: Configure STM32 SPI driver. +## +######DESCRIPTIONEND#### +## +##============================================================================= + +cdl_package CYGPKG_DEVS_SPI_CORTEXM_STM32 { + display "ST STM32 SPI driver" + description " + This package provides SPI driver support for the ST STM32 series + of microcontrollers. + " + parent CYGPKG_IO_SPI + active_if CYGPKG_IO_SPI + requires CYGPKG_HAL_CORTEXM_STM32 + hardware + include_dir cyg/io + compile spi_stm32.c + +cdl_option CYGNUM_DEVS_SPI_CORTEXM_STM32_PIN_TOGGLE_RATE { + display "Pin toggle rate" + description " + Selects the pin toggle rate in MHz to be used for the SPI interfaces. Higher toggle + rates allow increased baud rates at the expense of power and EMI. Only certain rates + are valid on different STM32 families, check part documentation for which may be used." + flavor data + default_value { (CYGHWR_HAL_CORTEXM_STM32_FAMILY == "F1") ? 10 : 25 } + legal_values { 2 10 25 50 80 100 } +} + +cdl_component CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS1 { + display "ST STM32 SPI bus 1" + description " + Enable SPI bus 1 on the STM32 device. + " + flavor bool + default_value 0 + + cdl_option CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS1_CS_GPIOS { + display "SPI chip selects" + description " + This is a comma separated list of GPIOs which are to be used as chip + select lines for the SPI bus. Each GPIO is defined by the SPI_CS() + macro which gives the port and pin number. + " + flavor data + default_value { "SPI_CS(A, 4)" } + } + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS1_BBUF_SIZE { + display "Bounce buffer size" + description " + DMA bounce buffers are required when running out of external + memory. Set this to the maximum SPI packet size which will be + used to enable the DMA bounce buffers. Set to 0 to disable + bounce buffers when running from on-chip memory. + " + flavor data + default_value 0 + } + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS1_TXINTR_PRI { + display "Transmit DMA interrupt priority" + flavor data + default_value 64+5 + } + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS1_RXINTR_PRI { + display "Receive DMA interrupt priority" + flavor data + default_value 128+6 + } +} + +cdl_component CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS2 { + display "ST STM32 SPI bus 2" + description " + Enable SPI bus 2 on the STM32 device. + " + flavor bool + default_value 0 + + cdl_option CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS2_CS_GPIOS { + display "SPI chip selects" + description " + This is a comma separated list of GPIOs which are to be used as chip + select lines for the SPI bus. Each GPIO is defined by the SPI_CS() + macro which gives the port and pin number. + " + flavor data + default_value { "SPI_CS(B, 12)" } + } + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS2_BBUF_SIZE { + display "Bounce buffer size" + description " + DMA bounce buffers are required when running out of external + memory. Set this to the maximum SPI packet size which will be + used to enable the DMA bounce buffers. Set to 0 to disable + bounce buffers when running from on-chip memory. + " + flavor data + default_value 0 + } + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS2_TXINTR_PRI { + display "Transmit DMA interrupt priority" + flavor data + default_value 64+7 + } + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS2_RXINTR_PRI { + display "Receive DMA interrupt priority" + flavor data + default_value 128+8 + } +} + +cdl_component CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS3 { + display "ST STM32 SPI bus 3" + description " + Enable SPI bus 3 on the STM32 device. Note that SPI bus 3 shares pins + with the JTAG port which means that debug should ideally be disabled + on startup. However, there is also the option of disabling it during + SPI bus initialisation instead. + " + flavor bool + default_value 0 + + cdl_option CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS3_DISABLE_DEBUG_PORT { + display "Disable debug port" + description " + When set the debug port will automatically be disabled on + initialising SPI bus 3, freeing up the SPI interface pins. + " + flavor bool + default_value 0 + } + + cdl_option CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS3_CS_GPIOS { + display "SPI chip selects" + description " + This is a comma separated list of GPIOs which are to be used as chip + select lines for the SPI bus. Each GPIO is defined by the SPI_CS() + macro which gives the port and pin number. + " + flavor data + default_value { "SPI_CS(A, 15)" } + } + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS3_BBUF_SIZE { + display "Bounce buffer size" + description " + DMA bounce buffers are required when running out of external + memory. Set this to the maximum SPI packet size which will be + used to enable the DMA bounce buffers. Set to 0 to disable + bounce buffers when running from on-chip memory. + " + flavor data + default_value 0 + } + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS3_TXINTR_PRI { + display "Transmit DMA interrupt priority" + flavor data + default_value 64+9 + } + + cdl_option CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS3_RXINTR_PRI { + display "Receive DMA interrupt priority" + flavor data + default_value 128+10 + } +} + +cdl_component CYGPKG_DEVS_SPI_CORTEXM_STM32_OPTIONS { + display "ST STM32 SPI driver build options" + flavor none + description " + Package specific build options including control over + compiler flags used only in building this package, + and details of which tests are built." + + cdl_option CYGPKG_DEVS_SPI_CORTEXM_STM32_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the STM32 SPI driver. These flags are used in addition + to the set of global flags." + } + + cdl_option CYGPKG_DEVS_SPI_CORTEXM_STM32_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the STM32 SPI driver. These flags are removed from + the set of global flags if present." + } + + cdl_option CYGBLD_DEVS_SPI_CORTEXM_STM32_LOOPBACK_TEST { + display "Build STM32 SPI loopback test" + flavor bool + no_define + default_value 0 + requires CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS1 + description " + This option enables the building of the STM32 SPI loopback test. + Refer to the comments in tests/loopback.c for details of how to + use this test." + } + + cdl_option CYGPKG_DEVS_SPI_CORTEXM_STM32_TESTS { + display "SPI tests" + active_if CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS1 + flavor data + no_define + calculated { CYGBLD_DEVS_SPI_CORTEXM_STM32_LOOPBACK_TEST ? "tests/loopback" : "" } + } +} + +} +# EOF spi_stm32.cdl diff --git a/ecos/packages/devs/spi/cortexm/stm32/current/include/spi_stm32.h b/ecos/packages/devs/spi/cortexm/stm32/current/include/spi_stm32.h new file mode 100644 index 0000000..a1370e2 --- /dev/null +++ b/ecos/packages/devs/spi/cortexm/stm32/current/include/spi_stm32.h @@ -0,0 +1,182 @@ +#ifndef CYGONCE_DEVS_SPI_CORTEXM_STM32_H +#define CYGONCE_DEVS_SPI_CORTEXM_STM32_H +//============================================================================= +// +// spi_stm32.h +// +// Header definitions for STM32 SPI driver. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2008, 2009, 2012 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Chris Holgate, nickg +// Date: 2008-11-27 +// Purpose: STM32 SPI driver definitions. +// Description: +// Usage: #include <cyg/io/spi_stm32.h> +// +//####DESCRIPTIONEND#### +// +//============================================================================= + +#include <pkgconf/hal.h> +#include <pkgconf/io_spi.h> +#include <pkgconf/devs_spi_cortexm_stm32.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/hal/drv_api.h> +#include <cyg/io/spi.h> + +#include <cyg/hal/var_dma.h> + +//----------------------------------------------------------------------------- +// Macro for defining a SPI device and attaching it to the appropriate bus. +// +// _name_ is the name of the SPI device. This will be used to reference a +// data structure of type cyg_spi_device which can be passed to the +// SPI driver API without needing a cast. +// _bus_ is the bus number to which this device is attached (1, 2 or 3). +// _csnum_ is the chip select line used for this device, numbered from 0. +// _16bit_ is set to true if the device uses 16 bit transactions and false +// if the bus uses 8 bit transactions. +// _clpol_ is the SPI bus clock polarity used by the device. This must be +// set to 1 if a clock line pullup resistor is used and 0 if a +// clock line pulldown resistor is used. +// _clpha_ is the SPI bus clock phase used by the device. +// _brate_ is the SPI bus clock baud rate used by the device, measured in Hz. +// _csup_dly_ is the minimum delay between chip select assert and transfer +// start, measured in microseconds. +// _csdw_dly_ is the minimum delay between transfer end and chip select deassert, +// measured in microseconds. +// _trbt_dly_ is the minimum delay between consecutive transfers. + +#define CYG_DEVS_SPI_CORTEXM_STM32_DEVICE( \ + _name_, _bus_, _csnum_, _16bit_, _clpol_, _clpha_, _brate_, _csup_dly_, _csdw_dly_, _trbt_dly_\ +) \ +cyg_spi_cortexm_stm32_device_t _name_ ##_stm32 CYG_SPI_DEVICE_ON_BUS(_bus_) = { \ +{ .spi_bus = (cyg_spi_bus*) &cyg_spi_stm32_bus## _bus_ }, \ + .dev_num = _csnum_, \ + .bus_16bit = _16bit_ ? 1 : 0, \ + .cl_pol = _clpol_, \ + .cl_pha = _clpha_, \ + .cl_brate = _brate_, \ + .cs_up_udly = _csup_dly_, \ + .cs_dw_udly = _csdw_dly_, \ + .tr_bt_udly = _trbt_dly_, \ + .spi_cr1_val = 0, \ +}; \ +extern cyg_spi_device _name_ __attribute__((alias ( #_name_ "_stm32" ))); + +//----------------------------------------------------------------------------- +// STM32 SPI bus configuration and state. + +typedef struct cyg_spi_cortexm_stm32_bus_setup_s +{ + cyg_uint32 *apb_freq; // Peripheral bus frequency. + cyg_haladdress spi_reg_base; // Base address of SPI register block. + + cyg_uint32 spi_enable; // SPI bus clock enable + cyg_uint8 cs_gpio_num; // Number of chip selects for this bus. + const cyg_uint32* cs_gpio_list; // List of GPIOs used as chip selects. + const cyg_uint32* spi_gpio_list; // List of GPIOs used by the SPI interface. + cyg_uint32 spi_gpio_remap; // Remap GPIO lines to alternate pins. + cyg_priority_t dma_tx_intr_pri; // Interrupt priority for DMA transmit. + cyg_priority_t dma_rx_intr_pri; // Interrupt priority for DMA receive. + cyg_uint32 bbuf_size; // Size of bounce buffers. + cyg_uint8* bbuf_tx; // Pointer to transmit bounce buffer. + cyg_uint8* bbuf_rx; // Pointer to receive bounce buffer. + +} cyg_spi_cortexm_stm32_bus_setup_t; + +typedef struct cyg_spi_cortexm_stm32_bus_s +{ + // ---- Upper layer data ---- + cyg_spi_bus spi_bus; // Upper layer SPI bus data. + + // ---- Bus configuration constants ---- + const cyg_spi_cortexm_stm32_bus_setup_t* setup; + + // ---- Driver state (private) ---- + + hal_stm32_dma_stream dma_tx_stream; // TX DMA stream for this bus. + hal_stm32_dma_stream dma_rx_stream; // RX DMA stream for this bus. + cyg_drv_mutex_t mutex; // Transfer mutex. + cyg_drv_cond_t condvar; // Transfer condition variable. + cyg_bool tx_dma_done; // Flags used to signal completion. + cyg_bool rx_dma_done; // Flags used to signal completion. + cyg_bool cs_up; // Chip select asserted flag. + +} cyg_spi_cortexm_stm32_bus_t; + +//----------------------------------------------------------------------------- +// STM32 SPI device. + +typedef struct cyg_spi_cortexm_stm32_device_s +{ + // ---- Upper layer data ---- + cyg_spi_device spi_device; // Upper layer SPI device data. + + // ---- Device setup (user configurable) ---- + cyg_uint8 dev_num; // Device number. + cyg_uint8 bus_16bit; // Use 16 bit (1) or 8 bit (0) transfers. + cyg_uint8 cl_pol; // Clock polarity (0 or 1). + cyg_uint8 cl_pha; // Clock phase (0 or 1). + cyg_uint32 cl_brate; // Clock baud rate. + cyg_uint16 cs_up_udly; // Minimum delay in us between CS up and transfer start. + cyg_uint16 cs_dw_udly; // Minimum delay in us between transfer end and CS down. + cyg_uint16 tr_bt_udly; // Minimum delay in us between two transfers. + + // ---- Device state (private) ---- + cyg_uint32 spi_cr1_val; // SPI configuration register (initialised to 0). + +} cyg_spi_cortexm_stm32_device_t; + +//----------------------------------------------------------------------------- +// Exported bus data structures. + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS1 +externC cyg_spi_cortexm_stm32_bus_t cyg_spi_stm32_bus1; +#endif + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS2 +externC cyg_spi_cortexm_stm32_bus_t cyg_spi_stm32_bus2; +#endif + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS3 +externC cyg_spi_cortexm_stm32_bus_t cyg_spi_stm32_bus3; +#endif + +//============================================================================= +#endif // CYGONCE_DEVS_SPI_CORTEXM_STM32_H diff --git a/ecos/packages/devs/spi/cortexm/stm32/current/src/spi_stm32.c b/ecos/packages/devs/spi/cortexm/stm32/current/src/spi_stm32.c new file mode 100644 index 0000000..54a97b1 --- /dev/null +++ b/ecos/packages/devs/spi/cortexm/stm32/current/src/spi_stm32.c @@ -0,0 +1,805 @@ +//============================================================================= +// +// spi_stm32.c +// +// SPI driver implementation for STM32 +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2008, 2009, 2011, 2012 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Chris Holgate, nickg +// Date: 2008-11-27 +// Purpose: STM32 SPI driver implementation +// +//####DESCRIPTIONEND#### +// +//============================================================================= + +#include <cyg/hal/hal_io.h> +#include <cyg/hal/hal_if.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/hal/drv_api.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/diag.h> + +#include <cyg/io/spi.h> +#include <cyg/io/spi_stm32.h> + +#include <pkgconf/devs_spi_cortexm_stm32.h> + +#include <string.h> + +//----------------------------------------------------------------------------- +// Diagnostics + +#if 0 +#define spi_diag( __fmt, ... ) diag_printf("SPI: %30s[%3d]: " __fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__ ); +#define spi_dump_buf( __addr, __size ) diag_dump_buf( __addr, __size ) +#else +#define spi_diag( __fmt, ... ) +#define spi_dump_buf( __addr, __size ) +#endif + +//----------------------------------------------------------------------------- +// Bus frequencies + +__externC cyg_uint32 hal_stm32_pclk1; +__externC cyg_uint32 hal_stm32_pclk2; + +//----------------------------------------------------------------------------- +// API function call forward references. + +static void stm32_transaction_begin (cyg_spi_device*); +static void stm32_transaction_transfer (cyg_spi_device*, cyg_bool, cyg_uint32, const cyg_uint8*, cyg_uint8*, cyg_bool); +static void stm32_transaction_tick (cyg_spi_device*, cyg_bool, cyg_uint32); +static void stm32_transaction_end (cyg_spi_device*); +static int stm32_get_config (cyg_spi_device*, cyg_uint32, void*, cyg_uint32*); +static int stm32_set_config (cyg_spi_device*, cyg_uint32, const void*, cyg_uint32*); + +//----------------------------------------------------------------------------- +// DMA callbacks + +static void stm32_dma_tx_callback( hal_stm32_dma_stream *stream, cyg_uint32 count, CYG_ADDRWORD data ); +static void stm32_dma_rx_callback( hal_stm32_dma_stream *stream, cyg_uint32 count, CYG_ADDRWORD data ); + +//----------------------------------------------------------------------------- +// Null data source and sink must be placed in the on-chip SRAM. This is +// either done explicitly (bounce buffers instantiated) or implicitly (no +// bounce buffers implies that the data area is already on SRAM). + +#if (defined (CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS1) && (CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS1_BBUF_SIZE > 0)) || \ + (defined (CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS2) && (CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS2_BBUF_SIZE > 0)) || \ + (defined (CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS3) && (CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS3_BBUF_SIZE > 0)) +static cyg_uint16 dma_tx_null __attribute__((section (".sram"))) = 0xFFFF; +static cyg_uint16 dma_rx_null __attribute__((section (".sram"))) = 0xFFFF; + +#else +static cyg_uint16 dma_tx_null = 0xFFFF; +static cyg_uint16 dma_rx_null = 0xFFFF; +#endif + +//----------------------------------------------------------------------------- +// Useful GPIO macros for 'dynamic' pin setup. + +#if defined (CYGHWR_HAL_CORTEXM_STM32_FAMILY_F1) + +#if (CYGNUM_DEVS_SPI_CORTEXM_STM32_PIN_TOGGLE_RATE == 2) +#define CYGHWR_HAL_STM32_GPIO_MODE_OUT_SPEED_SPI CYGHWR_HAL_STM32_GPIO_MODE_OUT_2MHZ + +#elif (CYGNUM_DEVS_SPI_CORTEXM_STM32_PIN_TOGGLE_RATE == 10) +#define CYGHWR_HAL_STM32_GPIO_MODE_OUT_SPEED_SPI CYGHWR_HAL_STM32_GPIO_MODE_OUT_10MHZ + +#elif (CYGNUM_DEVS_SPI_CORTEXM_STM32_PIN_TOGGLE_RATE == 50) +#define CYGHWR_HAL_STM32_GPIO_MODE_OUT_SPEED_SPI CYGHWR_HAL_STM32_GPIO_MODE_OUT_50MHZ + +#else +#error "Invalid SPI bus toggle rate." +#endif + +#elif defined (CYGHWR_HAL_CORTEXM_STM32_FAMILY_HIPERFORMANCE) + +#if (CYGNUM_DEVS_SPI_CORTEXM_STM32_PIN_TOGGLE_RATE == 2) +#define CYGHWR_HAL_STM32_GPIO_OSPEED_SPEED_SPI CYGHWR_HAL_STM32_GPIO_OSPEED_2MHZ + +#elif (CYGNUM_DEVS_SPI_CORTEXM_STM32_PIN_TOGGLE_RATE == 25) +#define CYGHWR_HAL_STM32_GPIO_OSPEED_SPEED_SPI CYGHWR_HAL_STM32_GPIO_OSPEED_25MHZ + +#elif (CYGNUM_DEVS_SPI_CORTEXM_STM32_PIN_TOGGLE_RATE == 50) +#define CYGHWR_HAL_STM32_GPIO_OSPEED_SPEED_SPI CYGHWR_HAL_STM32_GPIO_OSPEED_50MHZ + +#elif (CYGNUM_DEVS_SPI_CORTEXM_STM32_PIN_TOGGLE_RATE == 80) +#define CYGHWR_HAL_STM32_GPIO_OSPEED_SPEED_SPI CYGHWR_HAL_STM32_GPIO_OSPEED_HIGH + +#elif (CYGNUM_DEVS_SPI_CORTEXM_STM32_PIN_TOGGLE_RATE == 100) +#define CYGHWR_HAL_STM32_GPIO_OSPEED_SPEED_SPI CYGHWR_HAL_STM32_GPIO_OSPEED_HIGH + +#else +#error "Invalid SPI bus toggle rate." +#endif + +#else + +#error "Unknown STM32 family" + +#endif + +#define SPI_CS( __port, __bit ) CYGHWR_HAL_STM32_PIN_OUT( __port, __bit, PUSHPULL, NONE, SPEED_SPI ) + +//----------------------------------------------------------------------------- + +// Instantiate the bus state data structures. + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS1 +static const cyg_uint32 bus1_cs_gpio_list[] = { CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS1_CS_GPIOS }; +static const cyg_uint32 bus1_spi_gpio_list[] = { CYGHWR_HAL_STM32_SPI1_SCK, + CYGHWR_HAL_STM32_SPI1_MISO, + CYGHWR_HAL_STM32_SPI1_MOSI }; + +#if (CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS1_BBUF_SIZE > 0) +static cyg_uint8 bus1_tx_bbuf [CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS1_BBUF_SIZE] + __attribute__((aligned (2), section (".sram"))) = { 0 }; +static cyg_uint8 bus1_rx_bbuf [CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS1_BBUF_SIZE] + __attribute__((aligned (2), section (".sram"))) = { 0 }; +#endif + +static const cyg_spi_cortexm_stm32_bus_setup_t bus1_setup = { + .apb_freq = &hal_stm32_pclk2, + .spi_reg_base = CYGHWR_HAL_STM32_SPI1, + .spi_enable = CYGHWR_HAL_STM32_SPI1_CLOCK, + .cs_gpio_num = sizeof (bus1_cs_gpio_list)/sizeof(cyg_uint32), + .cs_gpio_list = bus1_cs_gpio_list, + .spi_gpio_list = bus1_spi_gpio_list, + .spi_gpio_remap = CYGHWR_HAL_STM32_SPI1_REMAP_CONFIG, + .dma_tx_intr_pri = CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS1_TXINTR_PRI, + .dma_rx_intr_pri = CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS1_RXINTR_PRI, + +#if (CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS1_BBUF_SIZE > 0) + .bbuf_size = CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS1_BBUF_SIZE, + .bbuf_tx = bus1_tx_bbuf, + .bbuf_rx = bus1_rx_bbuf, +#else + .bbuf_size = 0, +#endif +}; + +cyg_spi_cortexm_stm32_bus_t cyg_spi_stm32_bus1 = { + .spi_bus.spi_transaction_begin = stm32_transaction_begin, + .spi_bus.spi_transaction_transfer = stm32_transaction_transfer, + .spi_bus.spi_transaction_tick = stm32_transaction_tick, + .spi_bus.spi_transaction_end = stm32_transaction_end, + .spi_bus.spi_get_config = stm32_get_config, + .spi_bus.spi_set_config = stm32_set_config, + .setup = &bus1_setup, + .cs_up = false, + + .dma_tx_stream.desc = CYGHWR_HAL_STM32_SPI1_DMA_TX, + .dma_tx_stream.callback = stm32_dma_tx_callback, + .dma_tx_stream.data = (CYG_ADDRWORD)&cyg_spi_stm32_bus1, + + .dma_rx_stream.desc = CYGHWR_HAL_STM32_SPI1_DMA_RX, + .dma_rx_stream.callback = stm32_dma_rx_callback, + .dma_rx_stream.data = (CYG_ADDRWORD)&cyg_spi_stm32_bus1, + + + +}; +#endif + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS2 +static const cyg_uint32 bus2_cs_gpio_list[] = { CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS2_CS_GPIOS }; +static const cyg_uint32 bus2_spi_gpio_list[] = { CYGHWR_HAL_STM32_SPI2_SCK, + CYGHWR_HAL_STM32_SPI2_MISO, + CYGHWR_HAL_STM32_SPI2_MOSI }; + +#if (CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS2_BBUF_SIZE > 0) +static cyg_uint8 bus2_tx_bbuf [CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS2_BBUF_SIZE] + __attribute__((aligned (2), section (".sram"))) = { 0 }; +static cyg_uint8 bus2_rx_bbuf [CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS2_BBUF_SIZE] + __attribute__((aligned (2), section (".sram"))) = { 0 }; +#endif + +static const cyg_spi_cortexm_stm32_bus_setup_t bus2_setup = { + .apb_freq = &hal_stm32_pclk1, + .spi_reg_base = CYGHWR_HAL_STM32_SPI2, + .spi_enable = CYGHWR_HAL_STM32_SPI2_CLOCK, + .cs_gpio_num = sizeof (bus2_cs_gpio_list)/sizeof(cyg_uint32), + .cs_gpio_list = bus2_cs_gpio_list, + .spi_gpio_list = bus2_spi_gpio_list, + .spi_gpio_remap = CYGHWR_HAL_STM32_SPI2_REMAP_CONFIG, + .dma_tx_intr_pri = CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS2_TXINTR_PRI, + .dma_rx_intr_pri = CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS2_RXINTR_PRI, + +#if (CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS2_BBUF_SIZE > 0) + .bbuf_size = CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS2_BBUF_SIZE, + .bbuf_tx = bus2_tx_bbuf, + .bbuf_rx = bus2_rx_bbuf, +#else + .bbuf_size = 0, +#endif +}; + +cyg_spi_cortexm_stm32_bus_t cyg_spi_stm32_bus2 = { + .spi_bus.spi_transaction_begin = stm32_transaction_begin, + .spi_bus.spi_transaction_transfer = stm32_transaction_transfer, + .spi_bus.spi_transaction_tick = stm32_transaction_tick, + .spi_bus.spi_transaction_end = stm32_transaction_end, + .spi_bus.spi_get_config = stm32_get_config, + .spi_bus.spi_set_config = stm32_set_config, + .setup = &bus2_setup, + .cs_up = false, + + .dma_tx_stream.desc = CYGHWR_HAL_STM32_SPI2_DMA_TX, + .dma_tx_stream.callback = stm32_dma_tx_callback, + .dma_tx_stream.data = (CYG_ADDRWORD)&cyg_spi_stm32_bus2, + + .dma_rx_stream.desc = CYGHWR_HAL_STM32_SPI2_DMA_RX, + .dma_rx_stream.callback = stm32_dma_rx_callback, + .dma_rx_stream.data = (CYG_ADDRWORD)&cyg_spi_stm32_bus2, + + +}; +#endif + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS3 +static const cyg_uint32 bus3_cs_gpio_list[] = { CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS3_CS_GPIOS }; +static const cyg_uint32 bus3_spi_gpio_list[] = { CYGHWR_HAL_STM32_SPI3_SCK, + CYGHWR_HAL_STM32_SPI3_MISO, + CYGHWR_HAL_STM32_SPI3_MOSI }; + +#if (CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS3_BBUF_SIZE > 0) +static cyg_uint8 bus3_tx_bbuf [CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS3_BBUF_SIZE] + __attribute__((aligned (2), section (".sram"))) = { 0 }; +static cyg_uint8 bus3_rx_bbuf [CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS3_BBUF_SIZE] + __attribute__((aligned (2), section (".sram"))) = { 0 }; +#endif + +static const cyg_spi_cortexm_stm32_bus_setup_t bus3_setup = { + .apb_freq = &hal_stm32_pclk1, + .spi_reg_base = CYGHWR_HAL_STM32_SPI3, + .spi_enable = CYGHWR_HAL_STM32_SPI3_CLOCK, + .cs_gpio_num = sizeof (bus3_cs_gpio_list)/sizeof(cyg_uint32), + .cs_gpio_list = bus3_cs_gpio_list, + .spi_gpio_list = bus3_spi_gpio_list, + .spi_gpio_remap = CYGHWR_HAL_STM32_SPI3_REMAP_CONFIG, + .dma_tx_intr_pri = CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS3_TXINTR_PRI, + .dma_rx_intr_pri = CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS3_RXINTR_PRI, + +#if (CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS3_BBUF_SIZE > 0) + .bbuf_size = CYGNUM_DEVS_SPI_CORTEXM_STM32_BUS3_BBUF_SIZE, + .bbuf_tx = bus3_tx_bbuf, + .bbuf_rx = bus3_rx_bbuf, +#else + .bbuf_size = 0, +#endif +}; + +cyg_spi_cortexm_stm32_bus_t cyg_spi_stm32_bus3 = { + .spi_bus.spi_transaction_begin = stm32_transaction_begin, + .spi_bus.spi_transaction_transfer = stm32_transaction_transfer, + .spi_bus.spi_transaction_tick = stm32_transaction_tick, + .spi_bus.spi_transaction_end = stm32_transaction_end, + .spi_bus.spi_get_config = stm32_get_config, + .spi_bus.spi_set_config = stm32_set_config, + .setup = &bus3_setup, + .cs_up = false, + + .dma_tx_stream.desc = CYGHWR_HAL_STM32_SPI3_DMA_TX, + .dma_tx_stream.callback = stm32_dma_tx_callback, + .dma_tx_stream.data = (CYG_ADDRWORD)&cyg_spi_stm32_bus3, + + .dma_rx_stream.desc = CYGHWR_HAL_STM32_SPI3_DMA_RX, + .dma_rx_stream.callback = stm32_dma_rx_callback, + .dma_rx_stream.data = (CYG_ADDRWORD)&cyg_spi_stm32_bus3, + + +}; +#endif + +//----------------------------------------------------------------------------- +// Configure a GPIO pin as a SPI chip select line. + +static inline void stm32_spi_gpio_cs_setup + (cyg_uint32 gpio_num) +{ + CYGHWR_HAL_STM32_GPIO_SET (gpio_num); + CYGHWR_HAL_STM32_GPIO_OUT (gpio_num, 1); +} + +//----------------------------------------------------------------------------- +// Drive a GPIO pin as a SPI chip select line. + +static inline void stm32_spi_chip_select + (cyg_uint32 gpio_num, cyg_bool assert) +{ + CYGHWR_HAL_STM32_GPIO_OUT( gpio_num, assert ? 0 : 1); +} + +//----------------------------------------------------------------------------- +// DMA Callbacks. The DMA driver has disabled the DMA channel and +// masked the interrupt condition, here we need to wake up the client +// thread. + +static void stm32_dma_tx_callback( hal_stm32_dma_stream *stream, cyg_uint32 count, CYG_ADDRWORD data ) +{ + cyg_spi_cortexm_stm32_bus_t* stm32_bus = (cyg_spi_cortexm_stm32_bus_t*) data; + + cyg_drv_dsr_lock (); + stm32_bus->tx_dma_done = true; + cyg_drv_cond_signal (&stm32_bus->condvar); + cyg_drv_dsr_unlock (); +} + +static void stm32_dma_rx_callback( hal_stm32_dma_stream *stream, cyg_uint32 count, CYG_ADDRWORD data ) +{ + cyg_spi_cortexm_stm32_bus_t* stm32_bus = (cyg_spi_cortexm_stm32_bus_t*) data; + + cyg_drv_dsr_lock (); + stm32_bus->rx_dma_done = true; + cyg_drv_cond_signal (&stm32_bus->condvar); + cyg_drv_dsr_unlock (); +} + +//----------------------------------------------------------------------------- +// Set up a new SPI bus on initialisation. + +static void stm32_spi_bus_setup + (cyg_spi_cortexm_stm32_bus_t* stm32_bus) +{ + int i; + cyg_haladdress reg_addr; + cyg_uint32 reg_data; + + spi_diag("bus %p\n", stm32_bus ); + // Set up the GPIOs for use as chip select lines. + for (i = 0; i < stm32_bus->setup->cs_gpio_num; i ++) { + stm32_spi_gpio_cs_setup (stm32_bus->setup->cs_gpio_list[i]); + } + +#if defined (CYGHWR_HAL_CORTEXM_STM32_FAMILY_F1) + // Remap GPIO pins if required + if( stm32_bus->setup->spi_gpio_remap ) + { + CYG_ADDRESS afio = CYGHWR_HAL_STM32_AFIO; + cyg_uint32 mapr; + spi_diag("remap %08x\n", stm32_bus->setup->spi_gpio_remap ); + CYGHWR_HAL_STM32_CLOCK_ENABLE( CYGHWR_HAL_STM32_AFIO_CLOCK ); + HAL_READ_UINT32( afio+CYGHWR_HAL_STM32_AFIO_MAPR, mapr ); + mapr |= stm32_bus->setup->spi_gpio_remap; + HAL_WRITE_UINT32( afio+CYGHWR_HAL_STM32_AFIO_MAPR, mapr ); + } +#endif + + CYGHWR_HAL_STM32_GPIO_SET( stm32_bus->setup->spi_gpio_list[0] ); + CYGHWR_HAL_STM32_GPIO_SET( stm32_bus->setup->spi_gpio_list[1] ); + CYGHWR_HAL_STM32_GPIO_SET( stm32_bus->setup->spi_gpio_list[2] ); + + CYGHWR_HAL_STM32_CLOCK_ENABLE( stm32_bus->setup->spi_enable ); + //CYGHWR_HAL_STM32_CLOCK_ENABLE( stm32_bus->setup->dma_enable ); + + // Set up SPI default configuration. + reg_addr = stm32_bus->setup->spi_reg_base + CYGHWR_HAL_STM32_SPI_CR2; + reg_data = CYGHWR_HAL_STM32_SPI_CR2_TXDMAEN | CYGHWR_HAL_STM32_SPI_CR2_RXDMAEN; + HAL_WRITE_UINT32 (reg_addr, reg_data); + + // Initialise the synchronisation primitivies. + cyg_drv_mutex_init (&stm32_bus->mutex); + cyg_drv_cond_init (&stm32_bus->condvar, &stm32_bus->mutex); + + // Initialize DMA streams + hal_stm32_dma_init( &stm32_bus->dma_tx_stream, stm32_bus->setup->dma_tx_intr_pri ); + hal_stm32_dma_init( &stm32_bus->dma_rx_stream, stm32_bus->setup->dma_rx_intr_pri ); + + // Call upper layer bus init. + CYG_SPI_BUS_COMMON_INIT(&stm32_bus->spi_bus); +} + +//----------------------------------------------------------------------------- +// Set up a DMA channel. + +static void dma_channel_setup + (cyg_spi_device* device, cyg_uint8* data_buf, cyg_uint32 count, cyg_bool is_tx, cyg_bool polled) +{ + cyg_spi_cortexm_stm32_bus_t* stm32_bus = (cyg_spi_cortexm_stm32_bus_t*) device->spi_bus; + cyg_spi_cortexm_stm32_device_t* stm32_device = (cyg_spi_cortexm_stm32_device_t*) device; + hal_stm32_dma_stream *stream = is_tx ? &stm32_bus->dma_tx_stream : &stm32_bus->dma_rx_stream; + + hal_stm32_dma_configure( stream, + stm32_device->bus_16bit ? 16 : 8, + (data_buf==NULL), + polled ); + + if( data_buf == NULL ) + data_buf = (cyg_uint8 *)(is_tx ? &dma_tx_null : &dma_rx_null); + + hal_stm32_dma_start( stream, + data_buf, + stm32_bus->setup->spi_reg_base+CYGHWR_HAL_STM32_SPI_DR, + count ); + + hal_stm32_dma_show( stream ); +} + +//----------------------------------------------------------------------------- +// Initiate a DMA transfer over the SPI interface. + +static void spi_transaction_dma + (cyg_spi_device* device, cyg_bool tick_only, cyg_bool polled, cyg_uint32 count, + const cyg_uint8* tx_data, cyg_uint8* rx_data, cyg_bool drop_cs) +{ + cyg_spi_cortexm_stm32_bus_t* stm32_bus = (cyg_spi_cortexm_stm32_bus_t*) device->spi_bus; + cyg_spi_cortexm_stm32_device_t* stm32_device = (cyg_spi_cortexm_stm32_device_t*) device; + + cyg_haladdress reg_addr; + + cyg_haladdress spi_reg_base = stm32_bus->setup->spi_reg_base; + + spi_diag("device %p\n", device ); + // Ensure the chip select is asserted, inserting inter-transaction guard + // time if required. Note that when ticking the device we do not touch the CS. + if (!stm32_bus->cs_up && !tick_only) { + CYGACC_CALL_IF_DELAY_US (stm32_device->tr_bt_udly); + stm32_spi_chip_select (stm32_bus->setup->cs_gpio_list[stm32_device->dev_num], true); + stm32_bus->cs_up = true; + CYGACC_CALL_IF_DELAY_US (stm32_device->cs_up_udly); + } + + // Clear done flags prior to configuring DMA: + stm32_bus->tx_dma_done = false; + stm32_bus->rx_dma_done = false; + + // Set up the DMA channels. + dma_channel_setup (device, (cyg_uint8*) tx_data, count, true, polled); + dma_channel_setup (device, rx_data, count, false, polled); + + // Run the DMA (polling for completion). + if (polled) { + // Enable the SPI controller. + reg_addr = spi_reg_base + CYGHWR_HAL_STM32_SPI_CR1; + HAL_WRITE_UINT32 (reg_addr, stm32_device->spi_cr1_val | CYGHWR_HAL_STM32_SPI_CR1_SPE); + + while( !(stm32_bus->tx_dma_done && stm32_bus->rx_dma_done) ) + { + hal_stm32_dma_poll( &stm32_bus->dma_tx_stream ); + hal_stm32_dma_poll( &stm32_bus->dma_rx_stream ); + } + } + // Run the DMA (interrupt driven). + else { + cyg_drv_mutex_lock (&stm32_bus->mutex); + cyg_drv_dsr_lock (); + + // Enable the SPI controller. + reg_addr = spi_reg_base + CYGHWR_HAL_STM32_SPI_CR1; + HAL_WRITE_UINT32 (reg_addr, stm32_device->spi_cr1_val | CYGHWR_HAL_STM32_SPI_CR1_SPE); + + // Sit back and wait for the ISR/DSRs to signal completion. + do { + cyg_drv_cond_wait (&stm32_bus->condvar); + } while (!(stm32_bus->tx_dma_done && stm32_bus->rx_dma_done)); + + cyg_drv_dsr_unlock (); + cyg_drv_mutex_unlock (&stm32_bus->mutex); + } + + + // Disable the SPI controller. + reg_addr = spi_reg_base + CYGHWR_HAL_STM32_SPI_CR1; + HAL_WRITE_UINT32 (reg_addr, stm32_device->spi_cr1_val); + + // Deassert the chip select. + if (drop_cs && !tick_only) { + CYGACC_CALL_IF_DELAY_US (stm32_device->cs_dw_udly); + stm32_spi_chip_select (stm32_bus->setup->cs_gpio_list[stm32_device->dev_num], false); + stm32_bus->cs_up = false; + } +} + +//----------------------------------------------------------------------------- +// Calculate BR bits for SPI_CR1. +static int calculate_br_bits + (cyg_spi_cortexm_stm32_bus_t* bus, cyg_uint32 *target_clockrate, cyg_uint32 *br) +{ + cyg_uint32 divided_clk; + + // Calculate the maximum viable bus speed. + divided_clk = *bus->setup->apb_freq / 2; + for (*br = 0; (*br < 7) && (divided_clk > *target_clockrate); (*br)++) + divided_clk >>= 1; + + if ( divided_clk <= *target_clockrate ) + return 0; + + return -1; +} + +//----------------------------------------------------------------------------- +// Initialise SPI interfaces on startup. + +static void CYGBLD_ATTRIB_C_INIT_PRI(CYG_INIT_BUS_SPI) +stm32_spi_init(void) +{ + spi_diag("\n"); +#if defined(CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS3) && \ + defined(CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS3_DISABLE_DEBUG_PORT) + // Disable debug port, freeing up SPI bus 3 pins. + cyg_uint32 reg_val; + HAL_READ_UINT32 (CYGHWR_HAL_STM32_AFIO + CYGHWR_HAL_STM32_AFIO_MAPR, reg_val); + reg_val &= ~((cyg_uint32) CYGHWR_HAL_STM32_AFIO_MAPR_SWJ_MASK); + reg_val |= CYGHWR_HAL_STM32_AFIO_MAPR_SWJ_SWDPDIS; + HAL_WRITE_UINT32 (CYGHWR_HAL_STM32_AFIO + CYGHWR_HAL_STM32_AFIO_MAPR, reg_val); +#endif + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS1 + stm32_spi_bus_setup (&cyg_spi_stm32_bus1); +#endif + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS2 + stm32_spi_bus_setup (&cyg_spi_stm32_bus2); +#endif + +#ifdef CYGHWR_DEVS_SPI_CORTEXM_STM32_BUS3 + stm32_spi_bus_setup (&cyg_spi_stm32_bus3); +#endif +} + +//----------------------------------------------------------------------------- +// Start a SPI transaction. + +static void stm32_transaction_begin + (cyg_spi_device* device) +{ + cyg_spi_cortexm_stm32_bus_t* stm32_bus = (cyg_spi_cortexm_stm32_bus_t*) device->spi_bus; + cyg_spi_cortexm_stm32_device_t* stm32_device = (cyg_spi_cortexm_stm32_device_t*) device; + + cyg_haladdress reg_addr; + cyg_uint32 reg_data, br; + + spi_diag("\n"); + // On the first transaction, generate the values to be programmed into the + // SPI configuration registers for this device and cache them. This avoids + // having to recalculate the prescaler for every transaction. + if (!stm32_device->spi_cr1_val) { + reg_data = CYGHWR_HAL_STM32_SPI_CR1_MSTR | + CYGHWR_HAL_STM32_SPI_CR1_SSI | CYGHWR_HAL_STM32_SPI_CR1_SSM; + if (stm32_device->cl_pol) + reg_data |= CYGHWR_HAL_STM32_SPI_CR1_CPOL; + if (stm32_device->cl_pha) + reg_data |= CYGHWR_HAL_STM32_SPI_CR1_CPHA; + if (stm32_device->bus_16bit) + reg_data |= CYGHWR_HAL_STM32_SPI_CR1_DFF; + + // Get divider bits + if ( 0 != calculate_br_bits(stm32_bus, (cyg_uint32 *)&(stm32_device->cl_brate), &br) ) + CYG_ASSERT (false, "STM32 SPI : Cannot run bus slowly enough for peripheral."); + + reg_data |= CYGHWR_HAL_STM32_SPI_CR1_BR (br); + + // Cache the configuration register settings. + stm32_device->spi_cr1_val = reg_data; + } + + // Set up the SPI controller. + reg_addr = stm32_bus->setup->spi_reg_base + CYGHWR_HAL_STM32_SPI_CR1; + HAL_WRITE_UINT32 (reg_addr, stm32_device->spi_cr1_val); +} + +//----------------------------------------------------------------------------- +// Run a transaction transfer. + +static void stm32_transaction_transfer + (cyg_spi_device* device, cyg_bool polled, cyg_uint32 count, + const cyg_uint8* tx_data, cyg_uint8* rx_data, cyg_bool drop_cs) +{ + cyg_spi_cortexm_stm32_bus_t* stm32_bus = (cyg_spi_cortexm_stm32_bus_t*) device->spi_bus; + cyg_spi_cortexm_stm32_device_t* stm32_device = (cyg_spi_cortexm_stm32_device_t*) device; + + // Check for unsupported transactions. + CYG_ASSERT (count > 0, "STM32 SPI : Null transfer requested."); + + spi_diag("count %d\n", count); + if( tx_data ) spi_dump_buf(tx_data, count ); + + // We check that the buffers are half-word aligned and that count is a + // multiple of two in order to carry out the 16-bit transfer. + if (stm32_device->bus_16bit) { + CYG_ASSERT (!(count & 1) && !((cyg_uint32) tx_data & 1) && !((cyg_uint32) rx_data & 1), + "STM32 SPI : Misaligned data in 16-bit transfer."); + } + + // Perform transfer via the bounce buffers. + if (stm32_bus->setup->bbuf_size != 0) { + cyg_uint8* tx_local = NULL; + cyg_uint8* rx_local = NULL; + + // If the requested transfer is too large for the bounce buffer we assert + // in debug builds and truncate in production builds. + if (count > stm32_bus->setup->bbuf_size) { + CYG_ASSERT (false, "STM32 SPI : Transfer exceeds bounce buffer size."); + count = stm32_bus->setup->bbuf_size; + } + if (tx_data != NULL) { + tx_local = stm32_bus->setup->bbuf_tx; + memcpy (tx_local, tx_data, count); + } + if (rx_data != NULL) { + rx_local = stm32_bus->setup->bbuf_rx; + } + spi_transaction_dma (device, false, polled, count, tx_local, rx_local, drop_cs); + if (rx_data != NULL) { + memcpy (rx_data, rx_local, count); + } + } + + // Perform conventional transfer. + else { + spi_transaction_dma (device, false, polled, count, tx_data, rx_data, drop_cs); + } + + spi_diag("done\n"); + if( rx_data ) spi_dump_buf(rx_data, count ); + +} + +//----------------------------------------------------------------------------- +// Carry out a bus tick operation - this just pushes the required number of +// zeros onto the bus, leaving the chip select in its current state. + +static void stm32_transaction_tick + (cyg_spi_device* device, cyg_bool polled, cyg_uint32 count) +{ + cyg_spi_cortexm_stm32_device_t* stm32_device = (cyg_spi_cortexm_stm32_device_t*) device; + + // Check for unsupported transactions. + CYG_ASSERT (count > 0, "STM32 SPI : Null transfer requested."); + + spi_diag("count %d\n", count); + + // We check that count is a multiple of two in order to carry out the 16-bit transfer. + if (stm32_device->bus_16bit) { + CYG_ASSERT (!(count & 1), + "STM32 SPI : Misaligned data in 16-bit transfer."); + } + + // Perform null transfer. + spi_transaction_dma (device, true, polled, count, NULL, NULL, false); +} + +//----------------------------------------------------------------------------- +// Terminate a SPI transaction, disabling the SPI controller. + +static void stm32_transaction_end + (cyg_spi_device* device) +{ + cyg_spi_cortexm_stm32_bus_t* stm32_bus = (cyg_spi_cortexm_stm32_bus_t*) device->spi_bus; + cyg_spi_cortexm_stm32_device_t* stm32_device = (cyg_spi_cortexm_stm32_device_t*) device; + + cyg_haladdress reg_addr; + + spi_diag("\n"); + // Ensure that the chip select is deasserted. + if (stm32_bus->cs_up) { + CYGACC_CALL_IF_DELAY_US (stm32_device->cs_dw_udly); + stm32_spi_chip_select (stm32_bus->setup->cs_gpio_list[stm32_device->dev_num], false); + stm32_bus->cs_up = false; + } + + // Ensure the SPI controller is disabled. + reg_addr = stm32_bus->setup->spi_reg_base + CYGHWR_HAL_STM32_SPI_CR1; + HAL_WRITE_UINT32 (reg_addr, stm32_device->spi_cr1_val); +} + +//----------------------------------------------------------------------------- +static int stm32_get_config + (cyg_spi_device* device, cyg_uint32 key, void* buf, cyg_uint32* len) +{ + cyg_spi_cortexm_stm32_bus_t* stm32_bus = (cyg_spi_cortexm_stm32_bus_t*) device->spi_bus; + cyg_spi_cortexm_stm32_device_t* stm32_device = (cyg_spi_cortexm_stm32_device_t*) device; + cyg_uint32* data_p = buf; + + switch (key) + { + case CYG_IO_GET_CONFIG_SPI_CLOCKRATE : + // Sanity check + if (NULL == len) { + CYG_ASSERT (false, "STM32 SPI : Null pointer as len argument for stm32_get_config()."); + return -1; + } + if (sizeof(cyg_uint32) != *len) { + CYG_ASSERT (false, "STM32 SPI : Invalid length with stm32_get_config()."); + return -1; + } + if (NULL == buf) { + CYG_ASSERT (false, "STM32 SPI : Null poiter as buf argument for stm32_get_config()."); + return -1; + } + + *data_p = *stm32_bus->setup->apb_freq >> ((( stm32_device->spi_cr1_val >> 3 ) & 7) + 1 ) ; + return 0; + + default : + break; + } + + return -1; +} + +//----------------------------------------------------------------------------- +static int stm32_set_config + (cyg_spi_device* device, cyg_uint32 key, const void* buf, cyg_uint32* len) +{ + cyg_spi_cortexm_stm32_bus_t* stm32_bus = (cyg_spi_cortexm_stm32_bus_t*) device->spi_bus; + cyg_spi_cortexm_stm32_device_t* stm32_device = (cyg_spi_cortexm_stm32_device_t*) device; + + cyg_uint32 br; + + switch (key) + { + case CYG_IO_SET_CONFIG_SPI_CLOCKRATE : + // Sanity check + if (NULL == len) { + CYG_ASSERT (false, "STM32 SPI : Null pointer as len argument for stm32_set_config()."); + return -1; + } + if (sizeof(cyg_uint32) != *len) { + CYG_ASSERT (false, "STM32 SPI : Invalid length with stm32_set_config()."); + return -1; + } + if (NULL == buf) { + CYG_ASSERT (false, "STM32 SPI : Null pointer as buf argument for stm32_set_config()."); + return -1; + } + + // Get divider bits + if ( 0 != calculate_br_bits(stm32_bus, (cyg_uint32 *)buf, &br) ) { + CYG_ASSERT (false, "STM32 SPI : Cannot run bus as slowly as requested."); + return -1; + } + + // Update the cache of the configuration register settings. + stm32_device->spi_cr1_val &= ~CYGHWR_HAL_STM32_SPI_CR1_BR(7); + stm32_device->spi_cr1_val |= CYGHWR_HAL_STM32_SPI_CR1_BR(br); + + return 0; + + default : + break; + } + + return -1; +} + +//============================================================================= diff --git a/ecos/packages/devs/spi/cortexm/stm32/current/tests/loopback.c b/ecos/packages/devs/spi/cortexm/stm32/current/tests/loopback.c new file mode 100644 index 0000000..876ab45 --- /dev/null +++ b/ecos/packages/devs/spi/cortexm/stm32/current/tests/loopback.c @@ -0,0 +1,185 @@ +//============================================================================= +// +// loopback.c +// +// Standalone SPI loopback test. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2008, 2009 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Chris Holgate +// Date: 2008-11-27 +// Purpose: STM32 SPI loopback test +// Description: Standalone SPI loopback test. +// Usage: Compile as a standalone application. +// +//####DESCRIPTIONEND#### +// +//============================================================================= + +//============================================================================= +// This is a quick loopback test for the STM32 SPI driver. It only checks +// the data transfer functionality - chip select handling will require +// testing with external devices. In order to run the test, the MOSI and +// MISO pins for the test port need to be shorted together to provide an +// external loopback. Don't do this on a bus which has external devices +// attached unless you first make sure that none of them are connected to +// the chip select used by the test harness. +// The default port and chip select used for this test are SPI bus 1, +// chip select 0. These can be changed by editing the loopback_device +// data structure directly. +// Note that this is intended to be run as a standalone test and not as part +// of the standard board tests since it requires a hardware modification. +//============================================================================= + +#include <cyg/infra/cyg_type.h> +#include <cyg/infra/testcase.h> // Test macros +#include <cyg/infra/cyg_ass.h> // Assertion macros +#include <cyg/infra/diag.h> // Diagnostic output + +#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL +#include <cyg/kernel/kapi.h> + +#include <cyg/io/spi.h> // Common SPI API +#include <cyg/io/spi_stm32.h> // STM32 data structures + +#include <string.h> + +//--------------------------------------------------------------------------- +// Thread data structures. + +cyg_uint8 stack [CYGNUM_HAL_STACK_SIZE_TYPICAL]; +cyg_thread thread_data; +cyg_handle_t thread_handle; + +externC cyg_spi_cortexm_stm32_bus_t cyg_spi_stm32_bus2; + +//--------------------------------------------------------------------------- +// SPI loopback device driver data structures. + +cyg_spi_cortexm_stm32_device_t loopback_device = { + .spi_device.spi_bus = &cyg_spi_stm32_bus1.spi_bus, + .dev_num = 0 , // Only 1 device. + .cl_pol = 1, + .cl_pha = 1, + .cl_brate = 8000000, // Nominal 8Mhz. + .cs_up_udly = 1, + .cs_dw_udly = 1, + .tr_bt_udly = 1, + .bus_16bit = false, +}; + +//--------------------------------------------------------------------------- + +const char tx_data[] = "Testing, testing, 12, 123."; +const char tx_data1[] = "Testing extended API..."; +const char tx_data2[] = "Testing extended API for a second transaction."; + +char rx_data [sizeof(tx_data)]; +char rx_data1 [sizeof(tx_data1)]; +char rx_data2 [sizeof(tx_data2)]; + +//--------------------------------------------------------------------------- +// Run single loopback transaction using simple transfer API call. + +void run_test_1 (cyg_bool polled) +{ + diag_printf ("Test 1 : Simple transfer test (polled = %d).\n", polled ? 1 : 0); + cyg_spi_transfer (&loopback_device.spi_device, polled, sizeof (tx_data), + (const cyg_uint8*) &tx_data[0], (cyg_uint8*) &rx_data[0]); + + diag_printf (" Tx data : %s\n", tx_data); + diag_printf (" Rx data : %s\n", rx_data); + CYG_ASSERT (memcmp (tx_data, rx_data, sizeof (tx_data)) == 0, + "Simple transfer loopback failed - mismatched data.\n"); +} + +//--------------------------------------------------------------------------- +// Run two loopback transactions using extended transfer API. + +void run_test_2 (cyg_bool polled) +{ + diag_printf ("Test 2 : Extended API test (polled = %d).\n", polled ? 1 : 0); + cyg_spi_transaction_begin (&loopback_device.spi_device); + cyg_spi_transaction_transfer (&loopback_device.spi_device, polled, sizeof (tx_data1), + (const cyg_uint8*) &tx_data1[0], (cyg_uint8*) &rx_data1[0], false); + cyg_spi_transaction_transfer (&loopback_device.spi_device, polled, sizeof (tx_data2), + (const cyg_uint8*) &tx_data2[0], (cyg_uint8*) &rx_data2[0], false); + cyg_spi_transaction_end (&loopback_device.spi_device); + + diag_printf (" Tx data 1 : %s\n", tx_data1); + diag_printf (" Rx data 1 : %s\n", rx_data1); + diag_printf (" Tx data 2 : %s\n", tx_data2); + diag_printf (" Rx data 2 : %s\n", rx_data2); + CYG_ASSERT (memcmp (tx_data1, rx_data1, sizeof (tx_data1)) == 0, + "Simple transfer loopback failed - mismatched data (transfer 1).\n"); + CYG_ASSERT (memcmp (tx_data2, rx_data2, sizeof (tx_data2)) == 0, + "Simple transfer loopback failed - mismatched data (transfer 2).\n"); +} + +//--------------------------------------------------------------------------- +// Run all PL022 SPI interface loopback tests. + +void run_tests (void) +{ + diag_printf ("Running STM32 SPI driver loopback tests.\n"); + run_test_1 (true); + run_test_1 (false); + run_test_2 (true); + run_test_2 (false); + CYG_TEST_PASS_FINISH ("Loopback tests ran OK"); +} + +//--------------------------------------------------------------------------- +// User startup - tests are run in their own thread. + +void cyg_user_start(void) +{ + CYG_TEST_INIT(); + cyg_thread_create( + 10, // Arbitrary priority + (cyg_thread_entry_t*) run_tests, // Thread entry point + 0, // + "test_thread", // Thread name + &stack[0], // Stack + CYGNUM_HAL_STACK_SIZE_TYPICAL, // Stack size + &thread_handle, // Thread handle + &thread_data // Thread data structure + ); + cyg_thread_resume(thread_handle); + cyg_scheduler_start(); +} + +//============================================================================= diff --git a/ecos/packages/devs/spi/freescale/dspi/current/ChangeLog b/ecos/packages/devs/spi/freescale/dspi/current/ChangeLog new file mode 100644 index 0000000..ca08fc7 --- /dev/null +++ b/ecos/packages/devs/spi/freescale/dspi/current/ChangeLog @@ -0,0 +1,79 @@ +2013-07-09 Mike Jones <mjones@proclivis.com> + + * src/spi_freescale_dspi.c: Fix: Kinetis DSPI infinite polling + [ Bugzilla 10011879 ] + +2013-05-08 Ilija Kocho <ilijak@siva.com.mk> + + * src/spi_freescale_dspi.cdl: Add CYGINT_DEVS_SPI_DMA_USE + * src/spi_freescale_dspi.c: Fix: Disable DMA requests for transfers + that don't use DMA. [ Bugzilla 1001815 ] + +2013-04-01 Ilija Kocho <ilijak@siva.com.mk> + + * include/spi_freescale_dspi.h, include/spi_freescale_busses.inl + * include/spi_freescale_dspi_io.h, src/spi_freescale_dspi.c: + Optimised receiving of messages that fit in FIFO. Add clock gating. + Fix race condition bug in dspi_transaction_end(). [ Bugzilla 1001815 ] + +2013-02-06 Stefan Singer <stefan.singer@freescale.com> + Ilija Kocho <ilijak@siva.com.mk> + + * include/spi_freescale_dspi.h, include/spi_freescale_busses.inl + * include/spi_freescale_dspi_io.h, include/spi_freescale_dspi_bd.h, + * src/spi_freescale_dspi.c: + enhanced endianness support for devices with big and little endian + added support for MPC5xxx in addition to Kinetis + extended support for up to 8 DSPIs + (see Bugzilla 1001752). + +2012-12-28 Ilija Kocho <ilijak@siva.com.mk> + + * cdl/spi_freescale_dspi.cdl, src/spi_freescale_dspi.c: + Tick-only now has option to beehive like other drivers + rather than RM (see Bugzilla 1001676). + Fixed bug with dropping CS. Chip select options consolidated in a for loop. + + * tests/spi_loopback.c: New file. Add looback test. + [Bugzilla 1001719] + +2012-05-04 Ilija Kocho <ilijak@siva.com.mk> + + * cdl/spi_freescale_dspi.cdl: + * include/spi_freescale_dspi_buses.inl + * src/spi_freescale_dspi.c: + Add: support for 32 channel eDMA, support for cached memory. + [Bugzilla 1001579] + +2012-01-06 Ilija Kocho <ilijak@siva.com.mk> + + * cdl/spi_freescale_dspi.cdl: + * include/spi_freescale_dspi.h + * include/spi_freescale_dspi_io.h: + * include/spi_freescale_dspi_buses.inl + * src/spi_freescale_dspi.c: + New package -- Freescale DSPI SPI driver. [Bugzilla 1001450] + +//=========================================================================== +// ####GPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. +// ------------------------------------------- +// ####GPLCOPYRIGHTEND#### +//=========================================================================== diff --git a/ecos/packages/devs/spi/freescale/dspi/current/cdl/spi_freescale_dspi.cdl b/ecos/packages/devs/spi/freescale/dspi/current/cdl/spi_freescale_dspi.cdl new file mode 100644 index 0000000..f1be8ba --- /dev/null +++ b/ecos/packages/devs/spi/freescale/dspi/current/cdl/spi_freescale_dspi.cdl @@ -0,0 +1,387 @@ +##============================================================================= +## +## spi_freescale_dspi.cdl +## +## Freescale DSPI driver configuration options. +## +##============================================================================= +## ####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 2011 Free Software Foundation, Inc. +## +## eCos is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free +## Software Foundation; either version 2 or (at your option) any later +## version. +## +## eCos is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with eCos; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## As a special exception, if other files instantiate templates or use +## macros or inline functions from this file, or you compile this file +## and link it with other works to produce a work based on this file, +## this file does not by itself cause the resulting work to be covered by +## the GNU General Public License. However the source code for this file +## must still be made available in accordance with section (3) of the GNU +## General Public License v2. +## +## This exception does not invalidate any other reasons why a work based +## on this file might be covered by the GNU General Public License. +## ------------------------------------------- +## ####ECOSGPLCOPYRIGHTEND#### +##============================================================================= +#######DESCRIPTIONBEGIN#### +## +## Author(s): Ilija Kocho +## Date: 2011-11-03 +## Purpose: Configure Freescale DSPI driver. +## +######DESCRIPTIONEND#### +## +##============================================================================= + +cdl_package CYGPKG_DEVS_SPI_FREESCALE_DSPI { + display "Freescale DSPI driver" + description " + This package provides SPI driver support for the Freescale + microcontrollers that employ DSPI interface." + + parent CYGPKG_IO_SPI + active_if CYGPKG_IO_SPI + requires CYGPKG_HAL_CORTEXM_KINETIS || CYGPKG_HAL_POWERPC_MPC5xxx + + hardware + include_dir cyg/io + compile spi_freescale_dspi.c + + cdl_option CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE { + display "DSPI FIFO size" + flavor data + default_value 4 + legal_values { 4 5 6 7 8 } + } + + cdl_component CYGHWR_DEVS_SPI_FREESCALE_DSPI_CTAR_NUM { + display "CTAR registers" + flavor data + calculated 2 + + description "DSPI can have from 2 to 8 CTAR registers that keep + transfer communication settings. In eCos CTAR0 is used for + all normal transfers while CTAR1 is used as auxiliary for + 'transaction end' (non)transfer." + + cdl_component CYGHWR_DEVS_SPI_FREESCALEDSPI_DSPI_CTAR1_AUX { + display "CTAR1 Aux settings" + flavor none + no_define + + cdl_component CYGHWR_DEVS_FREESCALEDSPI_DSPI_CTAR1_AUX_SPEED { + display "Nominal clock speed Hz" + flavor data + default_value 25000000 + + cdl_option CYGHWR_DEVS_FREESCALEDSPI_DSPI_CTAR1_AUX_USE_DBR { + display "Use double baud rate" + flavor bool + default_value 1 + description "Double baud rate is a feature of Freescale DSPI + that may provide higher baud rates but duty the cycle may be + different than 50/50 depdent on scaler/prescaler setting + for achieved baud rate." + } + } + + cdl_option CYGHWR_DEVS_FREESCALEDSPI_DSPI_CTAR1_AUX_CS_DELAY { + display "Nominal chip select delay (units)" + flavor data + legal_values { 1 to 1000 } + default_value 1 + } + + cdl_option CYGHWR_DEVS_FREESCALE_DSPI_DSPI_CTAR1_AUX_DELAY_UNIT { + display "Chip select delay unit (ns)" + flavor data + calculated 100 + } + } + } + + cdl_interface CYGINT_DEVS_SPI_DSPI_DMA_USE { + display "DSPI DMA use" + flavor data + description "Number of DMA channels used by DSPI buses." + } + + for { set ::spibus 0 } { $::spibus < 8 } { incr ::spibus } { + + cdl_interface CYGINT_DEVS_SPI_FREESCALE_DSPI[set ::spibus] { + display "Number of devices using DSPI bus [set ::spibus]" + } + + cdl_component CYGHWR_DEVS_SPI_FREESCALE_DSPI[set ::spibus] { + display "Freescale DSPI bus [set ::spibus]" + description "Enable DSPI bus [set :: spibus]." + flavor bool + default_value CYGINT_DEVS_SPI_FREESCALE_DSPI[set ::spibus] + active_if CYGINT_DEVS_SPI_FREESCALE_DSPI[set ::spibus] + + implements CYGINT_HAL_DMA + requires CYGPKG_HAL_FREESCALE_EDMA + + cdl_component CYGHWR_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_CS { + display "Chip-selects" + flavor none + no_define + cdl_option CYHGWR_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_PCSS { + display "Chip-select Strobe enable" + flavor bool + default_value 0 + + requires CYHGWR_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_PCSS == 1 \ + implies CYGHWR_FREESCALE_DSPI[set ::spibus]_CS5 == 0 + } + + for { set ::spics 0 } { $::spics < 5 } { incr ::spics } { + cdl_interface CYGINT_FREESCALE_DSPI[set ::spibus]_CS[set ::spics] { + flavor bool + requires CYGHWR_FREESCALE_DSPI[set ::spibus]_CS[set ::spics] == 1 + display "Use CS[set ::spics]" + } + + cdl_component CYGHWR_FREESCALE_DSPI[set ::spibus]_CS[set ::spics] { + display "CS[set ::spics]" + flavor bool + default_value 0 + cdl_option CYGHWR_FREESCALE_DSPI[set ::spibus]_CS[set ::spics]_IS { + display "CS[set ::spics] Inactive state Hi(1) Lo(0)" + flavor data + no_define + default_value { 1 } + legal_values { 0 1 } + } + } + } + + cdl_component CYGHWR_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_PCSIS { + display "Peripheral CS inactive states" + flavor data + calculated (0x0 + \ + (get_data(CYGHWR_FREESCALE_DSPI[set ::spibus]_CS0_IS) == 1 ? 1 : 0) + \ + (get_data(CYGHWR_FREESCALE_DSPI[set ::spibus]_CS1_IS) == 1 ? 2 : 0) + \ + (get_data(CYGHWR_FREESCALE_DSPI[set ::spibus]_CS2_IS) == 1 ? 4 : 0) + \ + (get_data(CYGHWR_FREESCALE_DSPI[set ::spibus]_CS3_IS) == 1 ? 8 : 0) + \ + (get_data(CYGHWR_FREESCALE_DSPI[set ::spibus]_CS4_IS) == 1 ? 16 : 0) + \ + (get_data(CYGHWR_FREESCALE_DSPI[set ::spibus]_CS5_IS) == 1 ? 32 : 0)) + } + } + + cdl_interface CYGINT_FREESCALE_DSPI[set ::spibus]_HAS_MASS { + description "SPI bus serves mass data device(s)." + } + + cdl_option CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_PUSHQUE_SIZE { + display "Queue buffer size" + description " + DSPI requires a command for every transfer so output + data must be re-packed in additional buffer prior to + being submitted to DMA. + If Queue capacity is same as DSPI FIFO size, the minimal + legal value, the DMA is not needed so no buffer memory + is allocated. Note: For every entry, byte (8 bit transfer) + or half word (16 bit transfer) a whole 32 bit word + is being allocated." + + legal_values { CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE to 2048 } + flavor data + default_value CYGINT_FREESCALE_DSPI[set ::spibus]_HAS_MASS ? 128 : \ + CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE + } + + cdl_interface CYGINT_DEVS_SPI_DSPI[set ::spibus]_USES_DMA { + flavor bool + } + + cdl_component CYGHWR_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_TX_DMA_CHAN { + display "TX DMA channel" + flavor data + implements CYGINT_DEVS_SPI_DSPI_DMA_USE + implements CYGINT_DEVS_SPI_DSPI[set ::spibus]_USES_DMA + + active_if CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_PUSHQUE_SIZE > \ + CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE + default_value 4 + [set ::spibus] * 2 + legal_values { 0 to (CYGNUM_HAL_FREESCALE_EDMA_CHAN_NUM-1) } + description "DMA channel assigned to the trasmitter of SPI bus" + + cdl_component CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_TX_DMA_PRI { + display "Transmit DMA channel priority" + flavor data + legal_values { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 255 } + default_value 255 + description " + DMA can work in either round robin or preeptve arbitration + mode. In preemptive mode, DMA each channel has unique priority, + lower number meaning lower priority. + 255 is a phony meaning \"default channel priority\"." + + cdl_option CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_TX_DMA_ECP { + display "Enable channel preemption" + flavor data + legal_values { 0 1 } + default_value 0 + } + + cdl_option CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_TX_DMA_DPA { + display "Disable preempt ability" + flavor data + legal_values { 0 1 } + default_value 0 + } + + } + + cdl_option CYGOPT_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_TCD_SECTION { + display "DMA TCD section" + flavor data + default_value CYGHWR_HAL_EDMA_TCD_SECTION + + description " + Section in which will be DMA Transfer Control + Descriptors shall reside" + } + } + + cdl_component CYGHWR_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_RX_DMA_CHAN { + display "RX DMA channel" + flavor data + implements CYGINT_DEVS_SPI_DSPI_DMA_USE + implements CYGINT_DEVS_SPI_DSPI[set ::spibus]_USES_DMA + + active_if CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_PUSHQUE_SIZE > \ + CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE + default_value 5 + [set ::spibus] * 2 + legal_values { 0 to (CYGNUM_HAL_FREESCALE_EDMA_CHAN_NUM-1) } + description "DMA channel assigned to the receiver of SPI bus" + + cdl_component CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_RX_DMA_PRI { + display "Receive DMA channel priority" + flavor data + legal_values { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 255 } + default_value 255 + description " + DMA can work in either round robin or preeptve arbitration + mode. In preemptive mode, DMA each channel has unique priority, + lower number meaning lower priority. + 255 is a phony meaning \"default channel priority\"." + + cdl_option CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_RX_DMA_ECP { + display "Enable channel preemption" + flavor data + legal_values { 0 1 } + default_value 0 + } + + cdl_option CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_RX_DMA_DPA { + display "Disable preempt ability" + flavor data + legal_values { 0 1 } + default_value 0 + } + } + } + + cdl_option CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_ISR_PRI { + display "Interrupt priority" + flavor data + requires CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_ISR_PRI_SP + calculated CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_ISR_PRI_SP + description "Interrupt priority set-point is provided by HAL" + } + } + } + + cdl_option CYGOPT_DEVS_SPI_FREESCALE_DSPI_TICK_ONLY_DROPS_CS { + display "Tick-only drops CS" + default_value 0 + + description " + eCos Reference Manual states that CS should drop prior to sending ticks, + but other drivers (so far) do not touch the CS. This option selects + between conformance with manual or compatibility with other drivers." + } + + cdl_option CYGPKG_DEVS_SPI_FREESCALE_DSPI_DEBUG_LEVEL { + display "Driver debug output level" + flavor data + legal_values { 0 1 2 3 } + default_value 0 + description " + This option specifies the level of debug data output by + the Freescale DSPI device driver. A value of 0 signifies + no debug data output; 1 signifies normal debug data + output; and 2 signifies maximum debug data output." + } + + + cdl_component CYGPKG_DEVS_SPI_FREESCALE_DSPI_OPTIONS { + display "Freescale DSPI driver build options" + flavor none + description " + Package specific build options including control over + compiler flags used only in building this package, + and details of which tests are built." + + cdl_option CYGPKG_DEVS_SPI_FREESCALE_DSPI_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the Freescale DSPI driver. These flags are used in addition + to the set of global flags." + } + + cdl_option CYGPKG_DEVS_SPI_FREESCALE_DSPI_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the Freescale DSPI driver. These flags are removed from + the set of global flags if present." + } + + } + + cdl_component CYGPKG_DEVS_SPI_FREESCALE_DSPI_TESTS { + display "Freescale DSPI tests" + flavor data + no_define + calculated { CYGBLD_DEVS_SPI_FREESCALE_DSPI_LOOPBACK_TEST ? "tests/spi_loopback" : "" } + + cdl_option CYGBLD_DEVS_SPI_FREESCALE_DSPI_LOOPBACK_TEST { + display "Build Freescale DSPI loopback test" + flavor bool + no_define + default_value 0 + requires { CYGHWR_DEVS_SPI_FREESCALE_DSPI0 || + CYGHWR_DEVS_SPI_FREESCALE_DSPI1 || + CYGHWR_DEVS_SPI_FREESCALE_DSPI2 } + description " + This option enables the building of the Freescale DSPI loopback test. + Refer to the comments in tests/loopback.c for details of how to + use this test." + } + } +} +# EOF spi_freescale_dspi.cdl diff --git a/ecos/packages/devs/spi/freescale/dspi/current/include/spi_freescale_dspi.h b/ecos/packages/devs/spi/freescale/dspi/current/include/spi_freescale_dspi.h new file mode 100644 index 0000000..f1fe610 --- /dev/null +++ b/ecos/packages/devs/spi/freescale/dspi/current/include/spi_freescale_dspi.h @@ -0,0 +1,207 @@ +#ifndef CYGONCE_DEVS_SPI_FREESCALE_DSPI_H +#define CYGONCE_DEVS_SPI_FREESCALE_DSPI_H +//============================================================================= +// +// spi_freescale_dspi.h +// +// Header definitions for Freescale DSPI driver. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2011 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): ilijak +// Date: 2011-11-03 +// Purpose: Freescale DSPI driver definitions. +// Description: +// Usage: #include <cyg/io/spi_freescale_dspi.h> +// +//####DESCRIPTIONEND#### +// +//============================================================================= + +#include <pkgconf/hal.h> +#include <pkgconf/io_spi.h> +#include <pkgconf/devs_spi_freescale_dspi.h> +#include <pkgconf/hal_freescale_edma.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/hal/drv_api.h> +#include <cyg/io/spi.h> +#include <cyg/hal/freescale_edma.h> +#include <cyg/io/spi_freescale_dspi_io.h> + +//----------------------------------------------------------------------------- +// Macro for defining a SPI device and attaching it to the appropriate bus. +// +// _name_ is the name of the SPI device. This will be used to reference a +// data structure of type cyg_spi_device which can be passed to the +// SPI driver API without needing a cast. +// _bus_ is the bus number to which this device is attached (0, 1 or 2). +// _csnum_ is the chip select line used for this device, numbered from 0. +// _fmsz_ is set device SPI frame size (bits) +// _clpol_ is the SPI bus clock polarity used by the device. This must be +// set to 1 if clock inactive state is high, 0 if clock inactive +// state is low. +// _clpha_ is the SPI bus clock phase used by the device. +// _brate_ is the SPI bus clock baud rate used by the device, measured in Hz. +// _csup_dly_ is the minimum delay between chip select assert and transfer +// start, measured in microseconds. +// _csdw_dly_ is the minimum delay between transfer end and chip select deassert, +// measured in delay units. +// _trbt_dly_ is the minimum delay between consecutive transfers. +// _dlu_ is delay unit in ns +// _dbr_ is enabling double baud rate feature + + +#define CYGNUM_DSPI_DELAY_UNIT(__val) (__val/10) + +#define CYG_SPI_BUS_NAME(_b_) cyg_spi_dspi_bus ## _b_ + +#define CYG_DEVS_SPI_FREESCALE_DSPI_DEVICE( \ + _name_, _bus_, _csnum_, _fmsz_, _clpol_, _clpha_, _brate_, _csup_dly_, _csdw_dly_, _trbt_dly_, _dlu_, _dbr_ \ +) \ + cyg_spi_freescale_dspi_device_t _name_ ##_fs_dspi CYG_SPI_DEVICE_ON_BUS(_bus_) = { \ +{ .spi_bus = (cyg_spi_bus*) &CYG_SPI_BUS_NAME(_bus_) }, \ + .dev_num = _csnum_, \ + .clocking.bus_16bit = _fmsz_ > 8 ? 1 : 0, \ + .clocking.frame_size = _fmsz_, \ + .clocking.cl_pol = _clpol_, \ + .clocking.cl_pha = _clpha_, \ + .clocking.cl_brate = _brate_, \ + .clocking.cs_up_udly = _csup_dly_, \ + .clocking.cs_dw_udly = _csdw_dly_, \ + .clocking.tr_bt_udly = _trbt_dly_, \ + .clocking.dl_unit = CYGNUM_DSPI_DELAY_UNIT(_dlu_), \ + .clocking.cl_dbr = _dbr_, \ + .clocking.dspi_ctar = 0 \ +}; \ +extern cyg_spi_device _name_ __attribute__((alias ( #_name_ "_fs_dspi" ))) + +enum { SPI_DMA_CHAN_TX_I, SPI_DMA_CHAN_RX_I }; + +//----------------------------------------------------------------------------- +// Freescale DSPI bus configuration and state. + +typedef struct cyg_spi_freescale_dspi_bus_setup_s +{ + cyghwr_devs_freescale_dspi_t* dspi_p; // Base address of SPI register block. + cyghwr_hal_freescale_dma_set_t* dma_set_p; // DMA configuration block. + cyg_vector_t intr_num; // DSPI interrupt vector + cyg_priority_t intr_prio; // Interrupt priority + cyg_uint32 mcr_opt ; // Module Configuratyon Register options + const cyg_uint32* spi_pin_list_p; // List of GPIOs used by the SPI interface. + const cyg_uint32* cs_pin_list_p; // List of GPIOs used as chip selects. + cyg_uint16 clk_gate; // Clock gate + cyg_uint8 cs_pin_num; // Number of chip selects for this bus. +} cyg_spi_freescale_dspi_bus_setup_t; + +#define SPI_DMA_CHAN_I(__dma_set,__rt) (__dma_set->chan_p[SPI_DMA_CHAN_ ## __rt ## _I].dma_chan_i) + +typedef struct cyg_spi_freescale_dspi_bus_s +{ + // ---- Upper layer data ---- + cyg_spi_bus spi_bus; // Upper layer SPI bus data. + + // ---- Bus configuration constants ---- + const cyg_spi_freescale_dspi_bus_setup_t* setup_p; + // ---- Driver state (private) ---- + // DMA transfer control descriptors + const cyghwr_hal_freescale_edma_tcd_t* tx_dma_tcd_ini_p; // TCD init. + const cyghwr_hal_freescale_edma_tcd_t* rx_dma_tcd_ini_p; // data + volatile cyghwr_hal_freescale_edma_tcd_t* rx_dma_tcd_p; // DMA TCD (RX) + volatile cyghwr_hal_freescale_edma_tcd_t* tx_dma_tcd_p; // DMA TCD (TX) + volatile cyg_uint32* pushque_p; // Tx command queue + cyg_uint16 pushque_n; // Tx command buffer size + cyg_uint8 txfifo_n; // TxFIFO size + cyg_uint8 rxfifo_n; // RxFIFO size + cyg_interrupt intr_data; // Interrupt state + cyg_handle_t intr_handle; // Interrupt handle + cyg_drv_mutex_t transfer_mutex; // Transfer mutex. + cyg_drv_cond_t transfer_done; // Transfer condition variable. + cyg_uint32 clock_freq; // Clock provided by hal +} cyg_spi_freescale_dspi_bus_t; + +//----------------------------------------------------------------------------- +// Freescale DSPI device. + +typedef struct cyg_freescale_dspi_clocking_s { + cyg_uint32 dspi_ctar; // DSPI Clock and Transfer Attributes Rregister shadow. + cyg_uint32 cl_brate; // Clock baud rate. + cyg_uint8 bus_16bit; // Use 16 bit (1) or 8 bit (0) transfers. + cyg_uint8 cl_pol; // Clock polarity (0 or 1). + cyg_uint8 cl_pha; // Clock phase (0 or 1). + cyg_uint8 cl_dbr; // Use double baud-rate feature if needed + cyg_uint8 cs_up_udly; // Minimum delay in us/ns between CS up and transfer start. + cyg_uint8 cs_dw_udly; // Minimum delay in us/ns between transfer end and CS down. + cyg_uint8 tr_bt_udly; // Minimum delay in us/ns between two transfers. + cyg_uint8 dl_unit; // Delay unit (1/10 * ns) + cyg_uint8 lsb_first; // LSbit shifted first. + cyg_uint8 frame_size; // Device SPI frame size (bits). +} cyg_freescale_dspi_clocking_t;; + +typedef struct cyg_spi_freescale_dspi_device_s +{ + // ---- Upper layer data ---- + cyg_spi_device spi_device; // Upper layer SPI device data. + + // ---- Device setup (user configurable) ---- + cyg_freescale_dspi_clocking_t clocking; + cyg_uint8 dev_num; // Device SPI select. + cyg_uint8 chip_sel; + // ---- Device state (private) ---- +} cyg_spi_freescale_dspi_device_t; + +//----------------------------------------------------------------------------- +// Exported bus data structures. + +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI0 +externC cyg_spi_freescale_dspi_bus_t cyg_spi_dspi_bus0; +#endif + +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI1 +externC cyg_spi_freescale_dspi_bus_t cyg_spi_dspi_bus1; +#endif + +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI2 +externC cyg_spi_freescale_dspi_bus_t cyg_spi_dspi_bus2; +#endif + +__externC void cyghwr_devs_freescale_dspi_diag(cyg_spi_freescale_dspi_bus_t* spi_bus_p); +__externC void cyghwr_devs_freescale_dspi_diag_array(char* name_p, + volatile cyg_uint32* fifo_p, + cyg_uint32 fifo_n); + +//============================================================================= +#endif // CYGONCE_DEVS_SPI_FREESCALE_DSPI_H diff --git a/ecos/packages/devs/spi/freescale/dspi/current/include/spi_freescale_dspi_buses.inl b/ecos/packages/devs/spi/freescale/dspi/current/include/spi_freescale_dspi_buses.inl new file mode 100644 index 0000000..5fb16f2 --- /dev/null +++ b/ecos/packages/devs/spi/freescale/dspi/current/include/spi_freescale_dspi_buses.inl @@ -0,0 +1,586 @@ +#ifndef SPI_FREESCALE_DSPI_BUSES_INL +#define SPI_FREESCALE_DSPI_BUSES_INL +//============================================================================= +// +// spi_freescale_dspi_buses.inl +// +// SPI bus instantiation for Freescale DSPI +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2011, 2013 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): ilijak +// Date: 2011-11-09 +// Purpose: Freescale DSPI DSPI bus instantiation +// +//####DESCRIPTIONEND#### +// +//============================================================================= + +#define PUSHQUE_ALIGN CYGBLD_ATTRIB_ALIGN(4) + +#define DSPI_DMA_BANDWIDTH FREESCALE_EDMA_CSR_BWC_0 + +//----------------------------------------------------------------------------- +// Instantiate the bus state data structures. + +// Some auxiliary macros + +#if (CYG_BYTEORDER == CYG_MSBFIRST) // AKA Big endian +#define EDMA_TCD_SADDR(__bus) \ + .saddr = (void *)(((unsigned int)&CYGADDR_IO_SPI_FREESCALE_DSPI ## __bus ## _P->popr) + 3) +#else // AKA Little endian +#define EDMA_TCD_SADDR(__bus) \ + .saddr = (cyg_uint32 *)&CYGADDR_IO_SPI_FREESCALE_DSPI ## __bus ## _P->popr +#endif + +#define DSPI_EDMA_CHAN_SET(__bus) \ +static volatile cyg_uint32 \ +dspi ## __bus ## _pushque[CYGNUM_DEVS_SPI_FREESCALE_DSPI ## __bus ## _PUSHQUE_SIZE+4] \ +PUSHQUE_ALIGN EDMA_RAM_BUF_SECTION; \ + \ +static const cyghwr_hal_freescale_dma_chan_set_t dspi ## __bus ## _dma_chan[2] = \ +{ \ + { \ + .dma_src = FREESCALE_DMAMUX_SRC_SPI ## __bus ## _TX \ + | FREESCALE_DMAMUX_CHCFG_ENBL_M, \ + .dma_chan_i = CYGHWR_DEVS_SPI_FREESCALE_DSPI ## __bus ## _TX_DMA_CHAN, \ + .dma_prio = CYGNUM_DEVS_SPI_FREESCALE_DSPI ## __bus ## _TX_DMA_PRI, \ + }, \ + { \ + .dma_src = FREESCALE_DMAMUX_SRC_SPI ## __bus ## _RX \ + | FREESCALE_DMAMUX_CHCFG_ENBL_M, \ + .dma_chan_i = CYGHWR_DEVS_SPI_FREESCALE_DSPI ## __bus ## _RX_DMA_CHAN, \ + .dma_prio = CYGNUM_DEVS_SPI_FREESCALE_DSPI ## __bus ## _RX_DMA_PRI, \ + } \ +}; \ + \ +static cyghwr_hal_freescale_dma_set_t dspi ## __bus ## _dma_set = { \ + .chan_p = dspi ## __bus ## _dma_chan, \ + .chan_n = 2 \ +}; \ + \ +static const cyghwr_hal_freescale_edma_tcd_t dspi ## __bus ## _dma_tcd_tx_ini = \ +{ \ + .saddr = (cyg_uint32 *) dspi ## __bus ## _pushque, \ + .soff = 4, \ + .attr = FREESCALE_EDMA_ATTR_SSIZE(FREESCALE_EDMA_ATTR_SIZE_32) | \ + FREESCALE_EDMA_ATTR_DSIZE(FREESCALE_EDMA_ATTR_SIZE_32) | \ + FREESCALE_EDMA_ATTR_SMOD(0) | \ + FREESCALE_EDMA_ATTR_DMOD(0), \ + .daddr = (cyg_uint32 *) \ + &CYGADDR_IO_SPI_FREESCALE_DSPI ## __bus ## _P->pushr, \ + .doff = 0, \ + .nbytes.mlno = 4, \ + .slast = 0, \ + .citer.elinkno = 1, \ + .dlast_sga.dlast = 0, \ + .biter.elinkno = 1, \ + .csr = DSPI_DMA_BANDWIDTH \ +}; \ + \ +static const cyghwr_hal_freescale_edma_tcd_t dspi ## __bus ## _dma_tcd_rx_ini = \ +{ \ + EDMA_TCD_SADDR(__bus), \ + .soff = 0, \ + .attr = FREESCALE_EDMA_ATTR_SSIZE(FREESCALE_EDMA_ATTR_SIZE_32) | \ + FREESCALE_EDMA_ATTR_DSIZE(FREESCALE_EDMA_ATTR_SIZE_32) | \ + FREESCALE_EDMA_ATTR_SMOD(0) | \ + FREESCALE_EDMA_ATTR_DMOD(0), \ + .daddr = NULL, \ + .doff = 4, \ + .nbytes.mlno = 4, \ + .slast = 0, \ + .citer.elinkno = 1, \ + .dlast_sga.dlast = 0, \ + .biter.elinkno = 1, \ + .csr = DSPI_DMA_BANDWIDTH \ +} + +#define DSPI_EDMA_SET_P_YES(__bus) .dma_set_p = &dspi ## __bus ## _dma_set +#define DSPI_EDMA_SET_P_NULL(__bus) .dma_set_p = NULL + +#define DSPI_EDMA_TCD_YES(__bus) \ + .tx_dma_tcd_p = &CYGHWR_IO_FREESCALE_EDMA0_P-> \ + tcd[CYGHWR_DEVS_SPI_FREESCALE_DSPI ## __bus ## _TX_DMA_CHAN], \ + .rx_dma_tcd_p = &CYGHWR_IO_FREESCALE_EDMA0_P-> \ + tcd[CYGHWR_DEVS_SPI_FREESCALE_DSPI ## __bus ## _RX_DMA_CHAN], \ + .tx_dma_tcd_ini_p = &dspi ## __bus ## _dma_tcd_tx_ini, \ + .rx_dma_tcd_ini_p = &dspi ## __bus ## _dma_tcd_rx_ini, \ + .pushque_p = dspi ## __bus ## _pushque + +#define DSPI_EDMA_TCD_NULL(__bus) \ + .tx_dma_tcd_p = NULL, \ + .rx_dma_tcd_p = NULL, \ + .tx_dma_tcd_ini_p = NULL, \ + .rx_dma_tcd_ini_p = NULL, \ + .pushque_p = NULL + +// End DSPI_EDMA + +#define DSPI_BUS_SETUP(__bus) \ +static const cyg_spi_freescale_dspi_bus_setup_t dspi ## __bus ## _setup = { \ + .dspi_p = CYGADDR_IO_SPI_FREESCALE_DSPI ## __bus ## _P, \ + .intr_num = CYGNUM_HAL_INTERRUPT_SPI ## __bus, \ + .intr_prio = CYGNUM_DEVS_SPI_FREESCALE_DSPI ## __bus ## _ISR_PRI, \ + .spi_pin_list_p = spi ## __bus ## _pins, \ + .cs_pin_list_p = spi ## __bus ## _cs_pins, \ + .clk_gate = CYGHWR_IO_FREESCALE_DSPI ## __bus ## _CLK, \ + .cs_pin_num = sizeof(spi ## __bus ## _cs_pins)/ \ + sizeof(spi ## __bus ## _cs_pins[0]), \ + .mcr_opt = CYGHWR_FREESCALE_DSPI ## __bus ## _MCR_PCSSE | \ + FREESCALE_DSPI_MCR_PCSIS( \ + CYGHWR_DEVS_SPI_FREESCALE_DSPI ## __bus ## _PCSIS), \ + DSPI ## __bus ## _EDMA_SET_P \ +} + +#define DSPI_BUS(__bus) \ +cyg_spi_freescale_dspi_bus_t cyg_spi_dspi_bus ## __bus = { \ + .spi_bus.spi_transaction_begin = dspi_transaction_begin, \ + .spi_bus.spi_transaction_transfer = dspi_transaction_transfer, \ + .spi_bus.spi_transaction_tick = dspi_transaction_tick, \ + .spi_bus.spi_transaction_end = dspi_transaction_end, \ + .spi_bus.spi_get_config = dspi_get_config, \ + .spi_bus.spi_set_config = dspi_set_config, \ + .setup_p = &dspi ## __bus ## _setup, \ + DSPI ## __bus ## _EDMA_TCD, \ + .pushque_n = CYGNUM_DEVS_SPI_FREESCALE_DSPI ## __bus ## _PUSHQUE_SIZE, \ + .txfifo_n = CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE, \ + .rxfifo_n = CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE \ +} + +#define DSPI_BUS_PINS(__bus) \ +static const cyg_uint32 spi ## __bus ## _pins[] = { \ + CYGHWR_IO_FREESCALE_SPI ## __bus ## _PIN_SIN, \ + CYGHWR_IO_FREESCALE_SPI ## __bus ## _PIN_SOUT, \ + CYGHWR_IO_FREESCALE_SPI ## __bus ## _PIN_SCK \ +} + +// DSPI BUS Instances ======================================================= + +// DSPI BUS 0 ================================================================ +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI0 + +#define CYGBLD_DSPI0_TCD_SECTION \ + CYGBLD_ATTRIB_SECTION(CYGOPT_DEVS_SPI_FREESCALE_DSPI0_TCD_SECTION) + +#ifdef CYHGWR_DEVS_SPI_FREESCALE_DSPI0_PCSS +#define CYGHWR_FREESCALE_DSPI0_MCR_PCSSE FREESCALE_DSPI_MCR_PCSSE_M +#else +#define CYGHWR_FREESCALE_DSPI0_MCR_PCSSE 0 +#endif + +// SPI chip select pins. +static const cyg_uint32 spi0_cs_pins[] = { +#ifdef CYGHWR_FREESCALE_DSPI0_CS0 + CYGHWR_IO_FREESCALE_SPI0_PIN_CS0, +#endif +#ifdef CYGHWR_FREESCALE_DSPI0_CS1 + CYGHWR_IO_FREESCALE_SPI0_PIN_CS1, +#endif +#ifdef CYGHWR_FREESCALE_DSPI0_CS2 + CYGHWR_IO_FREESCALE_SPI0_PIN_CS2, +#endif +#ifdef CYGHWR_FREESCALE_DSPI0_CS3 + CYGHWR_IO_FREESCALE_SPI0_PIN_CS3, +#endif +#ifdef CYGHWR_FREESCALE_DSPI0_CS4 + CYGHWR_IO_FREESCALE_SPI0_PIN_CS4, +#endif +#ifdef CYGHWR_FREESCALE_DSPI0_CS5 + CYGHWR_IO_FREESCALE_SPI0_PIN_CS5 +#endif +}; + +#ifdef CYGINT_DEVS_SPI_DSPI0_USES_DMA + DSPI_EDMA_CHAN_SET(0); +# define DSPI0_EDMA_SET_P DSPI_EDMA_SET_P_YES(0) +# define DSPI0_EDMA_TCD DSPI_EDMA_TCD_YES(0) +#else +# define DSPI0_EDMA_SET_P DSPI_EDMA_SET_P_NULL(0) +# define DSPI0_EDMA_TCD DSPI_EDMA_TCD_NULL(0) +#endif // CYGINT_DEVS_SPI_DSPI0_USES_DMA + +DSPI_BUS_PINS(0); +DSPI_BUS_SETUP(0); +DSPI_BUS(0); + +#endif // CYGHWR_DEVS_SPI_FREESCALE_DSPI0 + +// DSPI BUS 1 ================================================================ +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI1 + +#define CYGBLD_DSPI1_TCD_SECTION \ + CYGBLD_ATTRIB_SECTION(CYGOPT_DEVS_SPI_FREESCALE_DSPI1_TCD_SECTION) + +#ifdef CYHGWR_DEVS_SPI_FREESCALE_DSPI1_PCSS +#define CYGHWR_FREESCALE_DSPI1_MCR_PCSSE FREESCALE_DSPI_MCR_PCSSE_M +#else +#define CYGHWR_FREESCALE_DSPI1_MCR_PCSSE 0 +#endif + +// SPI chip select pins. +static const cyg_uint32 spi1_cs_pins[] = { +#ifdef CYGHWR_FREESCALE_DSPI1_CS0 + CYGHWR_IO_FREESCALE_SPI1_PIN_CS0, +#endif +#ifdef CYGHWR_FREESCALE_DSPI1_CS1 + CYGHWR_IO_FREESCALE_SPI1_PIN_CS1, +#endif +#ifdef CYGHWR_FREESCALE_DSPI1_CS2 + CYGHWR_IO_FREESCALE_SPI1_PIN_CS2, +#endif +#ifdef CYGHWR_FREESCALE_DSPI1_CS3 + CYGHWR_IO_FREESCALE_SPI1_PIN_CS3, +#endif +#ifdef CYGHWR_FREESCALE_DSPI1_CS4 + CYGHWR_IO_FREESCALE_SPI1_PIN_CS4, +#endif +#ifdef CYGHWR_FREESCALE_DSPI1_CS5 + CYGHWR_IO_FREESCALE_SPI1_PIN_CS5 +#endif +}; + +#ifdef CYGINT_DEVS_SPI_DSPI1_USES_DMA + DSPI_EDMA_CHAN_SET(1); +# define DSPI1_EDMA_SET_P DSPI_EDMA_SET_P_YES(1) +# define DSPI1_EDMA_TCD DSPI_EDMA_TCD_YES(1) +#else +# define DSPI1_EDMA_SET_P DSPI_EDMA_SET_P_NULL(1) +# define DSPI1_EDMA_TCD DSPI_EDMA_TCD_NULL(1) +#endif // CYGINT_DEVS_SPI_DSPI1_USES_DMA + +DSPI_BUS_PINS(1); +DSPI_BUS_SETUP(1); +DSPI_BUS(1); + +#endif // CYGHWR_DEVS_SPI_FREESCALE_DSPI1 + +// DSPI BUS 2 ================================================================ +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI2 + +#define CYGBLD_DSPI2_TCD_SECTION \ + CYGBLD_ATTRIB_SECTION(CYGOPT_DEVS_SPI_FREESCALE_DSPI2_TCD_SECTION) + +#ifdef CYHGWR_DEVS_SPI_FREESCALE_DSPI2_PCSS +#define CYGHWR_FREESCALE_DSPI2_MCR_PCSSE FREESCALE_DSPI_MCR_PCSSE_M +#else +#define CYGHWR_FREESCALE_DSPI2_MCR_PCSSE 0 +#endif + +// SPI chip select pins. +static const cyg_uint32 spi2_cs_pins[] = { +#ifdef CYGHWR_FREESCALE_DSPI2_CS0 + CYGHWR_IO_FREESCALE_SPI2_PIN_CS0, +#endif +#ifdef CYGHWR_FREESCALE_DSPI2_CS1 + CYGHWR_IO_FREESCALE_SPI2_PIN_CS1, +#endif +#ifdef CYGHWR_FREESCALE_DSPI2_CS2 + CYGHWR_IO_FREESCALE_SPI2_PIN_CS2, +#endif +#ifdef CYGHWR_FREESCALE_DSPI2_CS3 + CYGHWR_IO_FREESCALE_SPI2_PIN_CS3, +#endif +#ifdef CYGHWR_FREESCALE_DSPI2_CS4 + CYGHWR_IO_FREESCALE_SPI2_PIN_CS4, +#endif +#ifdef CYGHWR_FREESCALE_DSPI2_CS5 + CYGHWR_IO_FREESCALE_SPI2_PIN_CS5 +#endif +}; + +#ifdef CYGINT_DEVS_SPI_DSPI2_USES_DMA + DSPI_EDMA_CHAN_SET(2); +# define DSPI2_EDMA_SET_P DSPI_EDMA_SET_P_YES(2) +# define DSPI2_EDMA_TCD DSPI_EDMA_TCD_YES(2) +#else +# define DSPI2_EDMA_SET_P DSPI_EDMA_SET_P_NULL(2) +# define DSPI2_EDMA_TCD DSPI_EDMA_TCD_NULL(2) +#endif // CYGINT_DEVS_SPI_DSPI2_USES_DMA + +DSPI_BUS_PINS(2); +DSPI_BUS_SETUP(2); +DSPI_BUS(2); + +#endif // CYGHWR_DEVS_SPI_FREESCALE_DSPI2 + +// DSPI BUS 3 ================================================================ +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI3 + +#define CYGBLD_DSPI3_TCD_SECTION \ + CYGBLD_ATTRIB_SECTION(CYGOPT_DEVS_SPI_FREESCALE_DSPI3_TCD_SECTION) + +#ifdef CYHGWR_DEVS_SPI_FREESCALE_DSPI3_PCSS +#define CYGHWR_FREESCALE_DSPI3_MCR_PCSSE FREESCALE_DSPI_MCR_PCSSE_M +#else +#define CYGHWR_FREESCALE_DSPI3_MCR_PCSSE 0 +#endif + +// SPI chip select pins. +static const cyg_uint32 spi3_cs_pins[] = { +#ifdef CYGHWR_FREESCALE_DSPI3_CS0 + CYGHWR_IO_FREESCALE_SPI3_PIN_CS0, +#endif +#ifdef CYGHWR_FREESCALE_DSPI3_CS1 + CYGHWR_IO_FREESCALE_SPI3_PIN_CS1, +#endif +#ifdef CYGHWR_FREESCALE_DSPI3_CS2 + CYGHWR_IO_FREESCALE_SPI3_PIN_CS2, +#endif +#ifdef CYGHWR_FREESCALE_DSPI3_CS3 + CYGHWR_IO_FREESCALE_SPI3_PIN_CS3, +#endif +#ifdef CYGHWR_FREESCALE_DSPI3_CS4 + CYGHWR_IO_FREESCALE_SPI3_PIN_CS4, +#endif +#ifdef CYGHWR_FREESCALE_DSPI3_CS5 + CYGHWR_IO_FREESCALE_SPI3_PIN_CS5 +#endif +}; + +#ifdef CYGINT_DEVS_SPI_DSPI3_USES_DMA + DSPI_EDMA_CHAN_SET(3); +# define DSPI3_EDMA_SET_P DSPI_EDMA_SET_P_YES(3) +# define DSPI3_EDMA_TCD DSPI_EDMA_TCD_YES(3) +#else +# define DSPI3_EDMA_SET_P DSPI_EDMA_SET_P_NULL(3) +# define DSPI3_EDMA_TCD DSPI_EDMA_TCD_NULL(3) +#endif // CYGINT_DEVS_SPI_DSPI3_USES_DMA + +DSPI_BUS_PINS(3); +DSPI_BUS_SETUP(3); +DSPI_BUS(3); + +#endif // CYGHWR_DEVS_SPI_FREESCALE_DSPI3 + +// DSPI BUS 4 ================================================================ +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI4 + +#define CYGBLD_DSPI4_TCD_SECTION \ + CYGBLD_ATTRIB_SECTION(CYGOPT_DEVS_SPI_FREESCALE_DSPI4_TCD_SECTION) + +#ifdef CYHGWR_DEVS_SPI_FREESCALE_DSPI4_PCSS +#define CYGHWR_FREESCALE_DSPI4_MCR_PCSSE FREESCALE_DSPI_MCR_PCSSE_M +#else +#define CYGHWR_FREESCALE_DSPI4_MCR_PCSSE 0 +#endif + +// SPI chip select pins. +static const cyg_uint32 spi4_cs_pins[] = { +#ifdef CYGHWR_FREESCALE_DSPI4_CS0 + CYGHWR_IO_FREESCALE_SPI4_PIN_CS0, +#endif +#ifdef CYGHWR_FREESCALE_DSPI4_CS1 + CYGHWR_IO_FREESCALE_SPI4_PIN_CS1, +#endif +#ifdef CYGHWR_FREESCALE_DSPI4_CS2 + CYGHWR_IO_FREESCALE_SPI4_PIN_CS2, +#endif +#ifdef CYGHWR_FREESCALE_DSPI4_CS3 + CYGHWR_IO_FREESCALE_SPI4_PIN_CS3, +#endif +#ifdef CYGHWR_FREESCALE_DSPI4_CS4 + CYGHWR_IO_FREESCALE_SPI4_PIN_CS4, +#endif +#ifdef CYGHWR_FREESCALE_DSPI4_CS5 + CYGHWR_IO_FREESCALE_SPI4_PIN_CS5 +#endif +}; + +#ifdef CYGINT_DEVS_SPI_DSPI4_USES_DMA + DSPI_EDMA_CHAN_SET(4); +# define DSPI4_EDMA_SET_P DSPI_EDMA_SET_P_YES(4) +# define DSPI4_EDMA_TCD DSPI_EDMA_TCD_YES(4) +#else +# define DSPI4_EDMA_SET_P DSPI_EDMA_SET_P_NULL(4) +# define DSPI4_EDMA_TCD DSPI_EDMA_TCD_NULL(4) +#endif // CYGINT_DEVS_SPI_DSPI4_USES_DMA + +DSPI_BUS_PINS(4); +DSPI_BUS_SETUP(4); +DSPI_BUS(4); + +#endif // CYGHWR_DEVS_SPI_FREESCALE_DSPI4 + +// DSPI BUS 5 ================================================================ +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI5 + +#define CYGBLD_DSPI5_TCD_SECTION \ + CYGBLD_ATTRIB_SECTION(CYGOPT_DEVS_SPI_FREESCALE_DSPI5_TCD_SECTION) + +#ifdef CYHGWR_DEVS_SPI_FREESCALE_DSPI5_PCSS +#define CYGHWR_FREESCALE_DSPI5_MCR_PCSSE FREESCALE_DSPI_MCR_PCSSE_M +#else +#define CYGHWR_FREESCALE_DSPI5_MCR_PCSSE 0 +#endif + +// SPI chip select pins. +static const cyg_uint32 spi5_cs_pins[] = { +#ifdef CYGHWR_FREESCALE_DSPI5_CS0 + CYGHWR_IO_FREESCALE_SPI5_PIN_CS0, +#endif +#ifdef CYGHWR_FREESCALE_DSPI5_CS1 + CYGHWR_IO_FREESCALE_SPI5_PIN_CS1, +#endif +#ifdef CYGHWR_FREESCALE_DSPI5_CS2 + CYGHWR_IO_FREESCALE_SPI5_PIN_CS2, +#endif +#ifdef CYGHWR_FREESCALE_DSPI5_CS3 + CYGHWR_IO_FREESCALE_SPI5_PIN_CS3, +#endif +#ifdef CYGHWR_FREESCALE_DSPI5_CS4 + CYGHWR_IO_FREESCALE_SPI5_PIN_CS4, +#endif +#ifdef CYGHWR_FREESCALE_DSPI5_CS5 + CYGHWR_IO_FREESCALE_SPI5_PIN_CS5 +#endif +}; + +#ifdef CYGINT_DEVS_SPI_DSPI5_USES_DMA + DSPI_EDMA_CHAN_SET(5); +# define DSPI5_EDMA_SET_P DSPI_EDMA_SET_P_YES(5) +# define DSPI5_EDMA_TCD DSPI_EDMA_TCD_YES(5) +#else +# define DSPI5_EDMA_SET_P DSPI_EDMA_SET_P_NULL(5) +# define DSPI5_EDMA_TCD DSPI_EDMA_TCD_NULL(5) +#endif // CYGINT_DEVS_SPI_DSPI5_USES_DMA + +DSPI_BUS_PINS(5); +DSPI_BUS_SETUP(5); +DSPI_BUS(5); + +#endif // CYGHWR_DEVS_SPI_FREESCALE_DSPI5 + +// DSPI BUS 6 ================================================================ +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI6 + +#define CYGBLD_DSPI6_TCD_SECTION \ + CYGBLD_ATTRIB_SECTION(CYGOPT_DEVS_SPI_FREESCALE_DSPI6_TCD_SECTION) + +#ifdef CYHGWR_DEVS_SPI_FREESCALE_DSPI6_PCSS +#define CYGHWR_FREESCALE_DSPI6_MCR_PCSSE FREESCALE_DSPI_MCR_PCSSE_M +#else +#define CYGHWR_FREESCALE_DSPI6_MCR_PCSSE 0 +#endif + +// SPI chip select pins. +static const cyg_uint32 spi6_cs_pins[] = { +#ifdef CYGHWR_FREESCALE_DSPI6_CS0 + CYGHWR_IO_FREESCALE_SPI6_PIN_CS0, +#endif +#ifdef CYGHWR_FREESCALE_DSPI6_CS1 + CYGHWR_IO_FREESCALE_SPI6_PIN_CS1, +#endif +#ifdef CYGHWR_FREESCALE_DSPI6_CS2 + CYGHWR_IO_FREESCALE_SPI6_PIN_CS2, +#endif +#ifdef CYGHWR_FREESCALE_DSPI6_CS3 + CYGHWR_IO_FREESCALE_SPI6_PIN_CS3, +#endif +#ifdef CYGHWR_FREESCALE_DSPI6_CS4 + CYGHWR_IO_FREESCALE_SPI6_PIN_CS4, +#endif +#ifdef CYGHWR_FREESCALE_DSPI6_CS5 + CYGHWR_IO_FREESCALE_SPI6_PIN_CS5 +#endif +}; + +#ifdef CYGINT_DEVS_SPI_DSPI6_USES_DMA + DSPI_EDMA_CHAN_SET(6); +# define DSPI6_EDMA_SET_P DSPI_EDMA_SET_P_YES(6) +# define DSPI6_EDMA_TCD DSPI_EDMA_TCD_YES(6) +#else +# define DSPI6_EDMA_SET_P DSPI_EDMA_SET_P_NULL(6) +# define DSPI6_EDMA_TCD DSPI_EDMA_TCD_NULL(6) +#endif // CYGINT_DEVS_SPI_DSPI6_USES_DMA + +DSPI_BUS_PINS(6); +DSPI_BUS_SETUP(6); +DSPI_BUS(6); + +#endif // CYGHWR_DEVS_SPI_FREESCALE_DSPI6 + +// DSPI BUS 7 ================================================================ +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI7 + +#define CYGBLD_DSPI7_TCD_SECTION \ + CYGBLD_ATTRIB_SECTION(CYGOPT_DEVS_SPI_FREESCALE_DSPI7_TCD_SECTION) + +#ifdef CYHGWR_DEVS_SPI_FREESCALE_DSPI7_PCSS +#define CYGHWR_FREESCALE_DSPI7_MCR_PCSSE FREESCALE_DSPI_MCR_PCSSE_M +#else +#define CYGHWR_FREESCALE_DSPI7_MCR_PCSSE 0 +#endif + +// SPI chip select pins. +static const cyg_uint32 spi7_cs_pins[] = { +#ifdef CYGHWR_FREESCALE_DSPI7_CS0 + CYGHWR_IO_FREESCALE_SPI7_PIN_CS0, +#endif +#ifdef CYGHWR_FREESCALE_DSPI7_CS1 + CYGHWR_IO_FREESCALE_SPI7_PIN_CS1, +#endif +#ifdef CYGHWR_FREESCALE_DSPI7_CS2 + CYGHWR_IO_FREESCALE_SPI7_PIN_CS2, +#endif +#ifdef CYGHWR_FREESCALE_DSPI7_CS3 + CYGHWR_IO_FREESCALE_SPI7_PIN_CS3, +#endif +#ifdef CYGHWR_FREESCALE_DSPI7_CS4 + CYGHWR_IO_FREESCALE_SPI7_PIN_CS4, +#endif +#ifdef CYGHWR_FREESCALE_DSPI7_CS5 + CYGHWR_IO_FREESCALE_SPI7_PIN_CS5 +#endif +}; + +#ifdef CYGINT_DEVS_SPI_DSPI7_USES_DMA + DSPI_EDMA_CHAN_SET(7); +# define DSPI7_EDMA_SET_P DSPI_EDMA_SET_P_YES(7) +# define DSPI7_EDMA_TCD DSPI_EDMA_TCD_YES(7) +#else +# define DSPI7_EDMA_SET_P DSPI_EDMA_SET_P_NULL(7) +# define DSPI7_EDMA_TCD DSPI_EDMA_TCD_NULL(7) +#endif // CYGINT_DEVS_SPI_DSPI7_USES_DMA + +DSPI_BUS_PINS(7); +DSPI_BUS_SETUP(7); +DSPI_BUS(7); + +#endif // CYGHWR_DEVS_SPI_FREESCALE_DSPI7 + +//============================================================================= +#endif // SPI_FREESCALE_DSPI_BUSES_INL diff --git a/ecos/packages/devs/spi/freescale/dspi/current/include/spi_freescale_dspi_io.h b/ecos/packages/devs/spi/freescale/dspi/current/include/spi_freescale_dspi_io.h new file mode 100644 index 0000000..798160e --- /dev/null +++ b/ecos/packages/devs/spi/freescale/dspi/current/include/spi_freescale_dspi_io.h @@ -0,0 +1,292 @@ +#ifndef CYGONCE_DEVS_SPI_FREESCALE_DSPI_IO_H +#define CYGONCE_DEVS_SPI_FREESCALE_DSPI_IO_H +//============================================================================= +// +// spi_freescale_dspi_io.h +// +// IO definitions for Freescale DSPI. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2011 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): ilijak +// Date: 2011-11-03 +// Purpose: Freescale DSPI I/O definitions. +// Description: +// Usage: #include <cyg/io/spi_freescale_dspi_io.h> +// +//####DESCRIPTIONEND#### +// +//============================================================================= + + +// ---------------------------------------------------------------------------- +// DSPI + +typedef volatile struct cyghwr_devs_freescale_dspi_s { + cyg_uint32 mcr; // Module Configuration Register + cyg_uint32 reserved_0; + cyg_uint32 tcr; // Transfer Count Register + // Clock and Transfer Attributes Register + cyg_uint32 ctar[CYGHWR_DEVS_SPI_FREESCALE_DSPI_CTAR_NUM]; +#if CYGHWR_DEVS_SPI_FREESCALE_DSPI_CTAR_NUM < 8 + cyg_uint32 reserved_1[8-CYGHWR_DEVS_SPI_FREESCALE_DSPI_CTAR_NUM]; +#endif + cyg_uint32 sr; // Status Register + cyg_uint32 rser; // DMA/IRQ Request Select and Enable Register + cyg_uint32 pushr; // TX FIFO PUSH Register + cyg_uint32 popr; // RX FIFO POP Register + // Transmit FIFO Registers + cyg_uint32 txfr[CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE]; +#if CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE < 16 + cyg_uint32 reserved_2[16-CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE]; +#endif + // Receive FIFO Registers + cyg_uint32 rxfr[CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE]; +#if CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE < 16 + cyg_uint32 reserved_3[16-CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE]; +#endif +} cyghwr_devs_freescale_dspi_t; + +// MCR Bit Fields +#define FREESCALE_DSPI_MCR_HALT_M 0x1 +#define FREESCALE_DSPI_MCR_HALT_S 0 +#define FREESCALE_DSPI_MCR_SMPL_PT_M 0x300 +#define FREESCALE_DSPI_MCR_SMPL_PT_S 8 +#define FREESCALE_DSPI_MCR_SMPL_PT(__val) \ + VALUE_(FREESCALE_DSPI_MCR_SMPL_PT_S, __val) +#define FREESCALE_DSPI_MCR_CLR_RXF_M 0x400 +#define FREESCALE_DSPI_MCR_CLR_RXF_S 10 +#define FREESCALE_DSPI_MCR_CLR_TXF_M 0x800 +#define FREESCALE_DSPI_MCR_CLR_TXF_S 11 +#define FREESCALE_DSPI_MCR_DIS_RXF_M 0x1000 +#define FREESCALE_DSPI_MCR_DIS_RXF_S 12 +#define FREESCALE_DSPI_MCR_DIS_TXF_M 0x2000 +#define FREESCALE_DSPI_MCR_DIS_TXF_S 13 +#define FREESCALE_DSPI_MCR_MDIS_M 0x4000 +#define FREESCALE_DSPI_MCR_MDIS_S 14 +#define FREESCALE_DSPI_MCR_DOZE_M 0x8000 +#define FREESCALE_DSPI_MCR_DOZE_S 15 +#define FREESCALE_DSPI_MCR_PCSIS_M 0x3F0000 +#define FREESCALE_DSPI_MCR_PCSIS_S 16 +#define FREESCALE_DSPI_MCR_PCSIS(__val) \ + VALUE_(FREESCALE_DSPI_MCR_PCSIS_S, __val) +#define FREESCALE_DSPI_MCR_ROOE_M 0x1000000 +#define FREESCALE_DSPI_MCR_ROOE_S 24 +#define FREESCALE_DSPI_MCR_PCSSE_M 0x2000000 +#define FREESCALE_DSPI_MCR_PCSSE_S 25 +#define FREESCALE_DSPI_MCR_MTFE_M 0x4000000 +#define FREESCALE_DSPI_MCR_MTFE_S 26 +#define FREESCALE_DSPI_MCR_FRZ_M 0x8000000 +#define FREESCALE_DSPI_MCR_FRZ_S 27 +#define FREESCALE_DSPI_MCR_DCONF_M 0x30000000 +#define FREESCALE_DSPI_MCR_DCONF_S 28 +#define FREESCALE_DSPI_MCR_DCONF(__val) \ + VALUE_(FREESCALE_DSPI_MCR_DCONF_S, __val) +#define FREESCALE_DSPI_MCR_CONT_SCKE_M 0x40000000 +#define FREESCALE_DSPI_MCR_CONT_SCKE_S 30 +#define FREESCALE_DSPI_MCR_MSTR_M 0x80000000 +#define FREESCALE_DSPI_MCR_MSTR_S 31 +// TCR Bit Fields +#define FREESCALE_DSPI_TCR_DSPI_TCNT_M 0xFFFF0000 +#define FREESCALE_DSPI_TCR_DSPI_TCNT_S 16 +#define FREESCALE_DSPI_TCR_DSPI_TCNT(__val) \ + VALUE_(FREESCALE_DSPI_TCR_DSPI_TCNT_S, __val) +// CTAR Bit Fields +#define FREESCALE_DSPI_CTAR_BR_M 0xF +#define FREESCALE_DSPI_CTAR_BR_S 0 +#define FREESCALE_DSPI_CTAR_BR(__val) \ + VALUE_(FREESCALE_DSPI_CTAR_BR_S, __val) +#define FREESCALE_DSPI_CTAR_DT_M 0xF0 +#define FREESCALE_DSPI_CTAR_DT_S 4 +#define FREESCALE_DSPI_CTAR_DT(__val) \ + VALUE_(FREESCALE_DSPI_CTAR_DT_S, __val) +#define FREESCALE_DSPI_CTAR_ASC_M 0xF00 +#define FREESCALE_DSPI_CTAR_ASC_S 8 +#define FREESCALE_DSPI_CTAR_ASC(__val) \ + VALUE_(FREESCALE_DSPI_CTAR_ASC_S, __val) +#define FREESCALE_DSPI_CTAR_CSSCK_M 0xF000 +#define FREESCALE_DSPI_CTAR_CSSCK_S 12 +#define FREESCALE_DSPI_CTAR_CSSCK(__val) \ + VALUE_(FREESCALE_DSPI_CTAR_CSSCK_S, __val) +#define FREESCALE_DSPI_CTAR_PBR_M 0x30000 +#define FREESCALE_DSPI_CTAR_PBR_S 16 +#define FREESCALE_DSPI_CTAR_PBR(__val) \ + VALUE_(FREESCALE_DSPI_CTAR_PBR_S, __val) +#define FREESCALE_DSPI_CTAR_PDT_M 0xC0000 +#define FREESCALE_DSPI_CTAR_PDT_S 18 +#define FREESCALE_DSPI_CTAR_PDT(__val) \ + VALUE_(FREESCALE_DSPI_CTAR_PDT_S, __val) +#define FREESCALE_DSPI_CTAR_PASC_M 0x300000 +#define FREESCALE_DSPI_CTAR_PASC_S 20 +#define FREESCALE_DSPI_CTAR_PASC(__val) \ + VALUE_(FREESCALE_DSPI_CTAR_PASC_S, __val) +#define FREESCALE_DSPI_CTAR_PCSSCK_S 22 +#define FREESCALE_DSPI_CTAR_PCSSCK(__val) \ + VALUE_(FREESCALE_DSPI_CTAR_PCSSCK_S, __val) +#define FREESCALE_DSPI_CTAR_LSBFE_S 24 +#define FREESCALE_DSPI_CTAR_LSBFE_M 0x1000000 + +#define FREESCALE_DSPI_CTAR_FMSZ_M 0x78000000 +#define FREESCALE_DSPI_CTAR_FMSZ_S 27 +#define FREESCALE_DSPI_CTAR_FMSZ(__val) \ + VALUE_(FREESCALE_DSPI_CTAR_FMSZ_S, __val) +#define FREESCALE_DSPI_CTAR_DBR_M 0x80000000 +#define FREESCALE_DSPI_CTAR_DBR_S 31 +// CTAR_SLAVE Bit Fields +#define FREESCALE_DSPI_CTAR_SLAVE_CPHA_M 0x2000000 +#define FREESCALE_DSPI_CTAR_SLAVE_CPHA_S 25 +#define FREESCALE_DSPI_CTAR_SLAVE_CPOL_M 0x4000000 +#define FREESCALE_DSPI_CTAR_SLAVE_CPOL_S 26 +#define FREESCALE_DSPI_CTAR_SLAVE_FMSZ_M 0xF8000000 +#define FREESCALE_DSPI_CTAR_SLAVE_FMSZ_S 27 +#define FREESCALE_DSPI_CTAR_SLAVE_FMSZ(__val) \ + VALUE_(FREESCALE_DSPI_CTAR_SLAVE_FMSZ_S, __val) +// SR Bit Fields +#define FREESCALE_DSPI_SR_POPNXTPTR_M 0xF +#define FREESCALE_DSPI_SR_POPNXTPTR_S 0 +#define FREESCALE_DSPI_SR_POPNXTPTR(__val) \ + VALUE_(FREESCALE_DSPI_SR_POPNXTPTR_S, __val) +#define FREESCALE_DSPI_SR_RXCTR_M 0xF0 +#define FREESCALE_DSPI_SR_RXCTR_S 4 +#define FREESCALE_DSPI_SR_RXCTR(__val) \ + VALUE_(FREESCALE_DSPI_SR_RXCTR_S, __val) +#define FREESCALE_DSPI_SR_TXNXTPTR_M 0xF00 +#define FREESCALE_DSPI_SR_TXNXTPTR_S 8 +#define FREESCALE_DSPI_SR_TXNXTPTR(__val) \ + VALUE_(FREESCALE_DSPI_SR_TXNXTPTR_S, __val) +#define FREESCALE_DSPI_SR_TXCTR_M 0xF000 +#define FREESCALE_DSPI_SR_TXCTR_S 12 +#define FREESCALE_DSPI_SR_TXCTR(__val) \ + VALUE_(FREESCALE_DSPI_SR_TXCTR_S, __val) +#define FREESCALE_DSPI_SR_RFDF_M 0x20000 +#define FREESCALE_DSPI_SR_RFDF_S 17 +#define FREESCALE_DSPI_SR_RFOF_M 0x80000 +#define FREESCALE_DSPI_SR_RFOF_S 19 +#define FREESCALE_DSPI_SR_TFFF_M 0x2000000 +#define FREESCALE_DSPI_SR_TFFF_S 25 +#define FREESCALE_DSPI_SR_TFUF_M 0x8000000 +#define FREESCALE_DSPI_SR_TFUF_S 27 +#define FREESCALE_DSPI_SR_EOQF_M 0x10000000 +#define FREESCALE_DSPI_SR_EOQF_S 28 +#define FREESCALE_DSPI_SR_TXRXS_M 0x40000000 +#define FREESCALE_DSPI_SR_TXRXS_S 30 +#define FREESCALE_DSPI_SR_TCF_M 0x80000000 +#define FREESCALE_DSPI_SR_TCF_S 31 + +#define FREESCALE_DSPI_CLEAR_FIFOS (FREESCALE_DSPI_SR_TFUF_M |\ + FREESCALE_DSPI_SR_RFOF_M) + +// RSER Bit Fields +#define FREESCALE_DSPI_RSER_RFDF_DIRS_M 0x10000 +#define FREESCALE_DSPI_RSER_RFDF_DIRS_S 16 +#define FREESCALE_DSPI_RSER_RFDF_RE_M 0x20000 +#define FREESCALE_DSPI_RSER_RFDF_RE_S 17 +#define FREESCALE_DSPI_RSER_RFOF_RE_M 0x80000 +#define FREESCALE_DSPI_RSER_RFOF_RE_S 19 +#define FREESCALE_DSPI_RSER_TFFF_DIRS_M 0x1000000 +#define FREESCALE_DSPI_RSER_TFFF_DIRS_S 24 +#define FREESCALE_DSPI_RSER_TFFF_RE_M 0x2000000 +#define FREESCALE_DSPI_RSER_TFFF_RE_S 25 +#define FREESCALE_DSPI_RSER_TFUF_RE_M 0x8000000 +#define FREESCALE_DSPI_RSER_TFUF_RE_S 27 +#define FREESCALE_DSPI_RSER_EOQF_RE_M 0x10000000 +#define FREESCALE_DSPI_RSER_EOQF_RE_S 28 +#define FREESCALE_DSPI_RSER_TCF_RE_M 0x80000000 +#define FREESCALE_DSPI_RSER_TCF_RE_S 31 +// PUSHR Bit Fields +#define FREESCALE_DSPI_PUSHR_TXDATA_M 0xFFFF +#define FREESCALE_DSPI_PUSHR_TXDATA_S 0 +#define FREESCALE_DSPI_PUSHR_TXDATA(__val) \ + VALUE_(FREESCALE_DSPI_PUSHR_TXDATA_S, __val) +#define FREESCALE_DSPI_PUSHR_PCS_M 0x3F0000 +#define FREESCALE_DSPI_PUSHR_PCS_S 16 +#define FREESCALE_DSPI_PUSHR_PCS(__val) VALUE_(FREESCALE_DSPI_PUSHR_PCS_S, __val) +#define FREESCALE_DSPI_PUSHR_CTCNT_M 0x4000000 +#define FREESCALE_DSPI_PUSHR_CTCNT_S 26 +#define FREESCALE_DSPI_PUSHR_EOQ_M 0x8000000 +#define FREESCALE_DSPI_PUSHR_EOQ_S 27 +#define FREESCALE_DSPI_PUSHR_CTAS_M 0x70000000 +#define FREESCALE_DSPI_PUSHR_CTAS_S 28 +#define FREESCALE_DSPI_PUSHR_CTAS(__val) \ + VALUE_(FREESCALE_DSPI_PUSHR_CTAS_S, __val) +#define FREESCALE_DSPI_PUSHR_CONT_M 0x80000000 +#define FREESCALE_DSPI_PUSHR_CONT_S 31 +// PUSHR_SLAVE Bit Fields +#define FREESCALE_DSPI_PUSHR_SLAVE_TXDATA_M 0xFFFFFFFF +#define FREESCALE_DSPI_PUSHR_SLAVE_TXDATA_S 0 +#define FREESCALE_DSPI_PUSHR_SLAVE_TXDATA(__val) \ +VALUE_(FREESCALE_DSPI_PUSHR_SLAVE_TXDATA_S, __val) + +#define FREESCALE_DSPI_PUSHR_PCS_CLEAR(__val)\ +CYG_MACRO_START\ + __val &= ~FREESCALE_DSPI_PUSHR_PCS_M; \ +CYG_MACRO_END + +// POPR Bit Fields +#define FREESCALE_DSPI_POPR_RXDATA_M 0xFFFFFFFF +#define FREESCALE_DSPI_POPR_RXDATA_S 0 +#define FREESCALE_DSPI_POPR_RXDATA(__val) \ + VALUE_(FREESCALE_DSPI_POPR_RXDATA_S, __val) +// TXFR Bit Fields +#define FREESCALE_DSPI_TXFR_TXDATA_M 0xFFFF +#define FREESCALE_DSPI_TXFR_TXDATA_S 0 +#define FREESCALE_DSPI_TXFR_TXCMD_TXDATA_M 0xFFFF0000 +#define FREESCALE_DSPI_TXFR_TXCMD_TXDATA_S 16 +#define FREESCALE_DSPI_TXFR_TXCMD_TXDATA(__fr,__val) \ + VALUE_(FREESCALE_DSPI_TXFR##__fr##_TXCMD_TXDATA_S, __val) +// RXFR Bit Fields +#define FREESCALE_DSPI_RXFR_RXDATA_M 0xFFFFFFFF +#define FREESCALE_DSPI_RXFR_RXDATA_S 0 +#define FREESCALE_DSPI_RXFR_RXDATA(__fr,__val) \ + VALUE_(FREESCALE_DSPI_RXFR##_fr##_RXDATA_S, __val) + +// Borrow following macros from HAL + +// CYGADDR_IO_SPI_FREESCALE_DSPIx_P + +// CYGHWR_IO_CLOCK_ENABLE(__clkgate) +// CYGHWR_IO_FREESCALE_DSPIx_CLK + +// CYGHWR_IO_FREESCALE_DSPI_PIN(__pin) + +// CYGHWR_IO_FREESCALE_SPIx_PIN_SIN +// CYGHWR_IO_FREESCALE_SPIx_PIN_SOUT +// CYGHWR_IO_FREESCALE_SPIx_PIN_SCK + +// CYGHWR_IO_FREESCALE_SPIx_PIN_CSn + +//============================================================================= +#endif // CYGONCE_DEVS_SPI_FREESCALE_DSPI_IO_H diff --git a/ecos/packages/devs/spi/freescale/dspi/current/src/spi_freescale_dspi.c b/ecos/packages/devs/spi/freescale/dspi/current/src/spi_freescale_dspi.c new file mode 100644 index 0000000..b6842e1 --- /dev/null +++ b/ecos/packages/devs/spi/freescale/dspi/current/src/spi_freescale_dspi.c @@ -0,0 +1,1190 @@ +//============================================================================= +// +// spi_freescale_dspi.c +// +// SPI driver implementation for Freescale DSPI +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2011, 2013 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): ilijak +// Date: 2011-11-04 +// Purpose: Freescale DSPI SPI driver implementation +// +//####DESCRIPTIONEND#### +// +//============================================================================= + +#include <pkgconf/hal.h> +#include <string.h> +#include <cyg/hal/hal_io.h> +#include <cyg/hal/hal_if.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/hal/drv_api.h> +#include <cyg/hal/hal_cache.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/diag.h> + +#include <cyg/io/spi.h> +#include <cyg/hal/hal_endian.h> + +#include <pkgconf/devs_spi_freescale_dspi.h> +#if defined(CYGHWR_DEVS_SPI_FREESCALE_DSPI0) || \ + defined(CYGHWR_DEVS_SPI_FREESCALE_DSPI1) || \ + defined(CYGHWR_DEVS_SPI_FREESCALE_DSPI2) + +#include <cyg/io/spi_freescale_dspi.h> + + +#define DEBUG_SPI CYGPKG_DEVS_SPI_FREESCALE_DSPI_DEBUG_LEVEL + +#if DEBUG_SPI >= 3 +# define DEBUG3_PRINTF(args...) diag_printf(args) +#else +# define DEBUG3_PRINTF(args...) +#endif + +#if DEBUG_SPI >= 2 +# define DEBUG2_PRINTF(args...) diag_printf(args) +#else +# define DEBUG2_PRINTF(args...) +#endif + +#if DEBUG_SPI >= 1 +# define DEBUG1_PRINTF(args...) diag_printf(args) +#else +# define DEBUG1_PRINTF(args...) +#endif + +# define DEBUG0_PRINTF(args...) diag_printf(args) + +#define PUSHR_NULL (0xFFFF) + +//----------------------------------------------------------------------------- +// API function call forward references. + +static void dspi_transaction_begin (cyg_spi_device*); +static void dspi_transaction_transfer (cyg_spi_device*, cyg_bool, cyg_uint32, + const cyg_uint8*, cyg_uint8*, cyg_bool); +static void dspi_transaction_tick (cyg_spi_device*, cyg_bool, cyg_uint32); +static void dspi_transaction_end (cyg_spi_device*); +static int dspi_get_config (cyg_spi_device*, cyg_uint32, + void*, cyg_uint32*); +static int dspi_set_config (cyg_spi_device*, cyg_uint32, + const void*, cyg_uint32*); + +//----------------------------------------------------------------------------- +// Instantiate the bus state data structures. + +#include <cyg/io/spi_freescale_dspi_buses.inl> + +// Some hardware manipulation inline functions and macros + +static inline void dspi_disable(cyghwr_devs_freescale_dspi_t* dspi_p) +{ + dspi_p->mcr |= FREESCALE_DSPI_MCR_MDIS_M; +} + +static inline void dspi_enable(cyghwr_devs_freescale_dspi_t* dspi_p) +{ + dspi_p->mcr &= ~FREESCALE_DSPI_MCR_MDIS_M; +} + +static inline void dspi_halt(cyghwr_devs_freescale_dspi_t* dspi_p) +{ + dspi_p->mcr |= FREESCALE_DSPI_MCR_HALT_M; +} + +static inline void dspi_tlah(cyghwr_devs_freescale_dspi_t* dspi_p) +{ + dspi_p->mcr &= ~FREESCALE_DSPI_MCR_HALT_M; +} + +static inline void +dspi_irq_enable(cyghwr_devs_freescale_dspi_t* dspi_p, cyg_uint32 irq_mask) +{ + dspi_p->rser |= irq_mask; +} + +static inline void +dspi_irq_disable(cyghwr_devs_freescale_dspi_t* dspi_p, cyg_uint32 irq_mask) +{ + dspi_p->rser &= ~irq_mask; +} + +static inline void +dspi_status_clear(cyghwr_devs_freescale_dspi_t* dspi_p, cyg_uint32 sr_mask) +{ + dspi_p->sr |= sr_mask; +} + +static inline void +dspi_fifo_clear(cyghwr_devs_freescale_dspi_t* dspi_p) +{ + dspi_p->mcr |= FREESCALE_DSPI_MCR_CLR_RXF_M | FREESCALE_DSPI_MCR_CLR_TXF_M; +} + +static inline void +dspi_fifo_drain(cyghwr_devs_freescale_dspi_t* dspi_p) +{ + dspi_p->sr |= FREESCALE_DSPI_SR_RFDF_M; +} + + +#define DSPI_IRQ_ENABLE(__dspi_p) \ + dspi_irq_enable(__dspi_p, FREESCALE_DSPI_RSER_EOQF_RE_M) +#define DSPI_IRQ_DISABLE(__dspi_p) \ + dspi_irq_disable(__dspi_p, FREESCALE_DSPI_RSER_EOQF_RE_M) +#define DSPI_EOQ_CLEAR(__dspi_p) \ + dspi_status_clear(__dspi_p, FREESCALE_DSPI_SR_EOQF_M | \ + FREESCALE_DSPI_SR_TCF_M | \ + FREESCALE_DSPI_SR_RFDF_M) +#define DSPI_TXRX_ENABLE(__dspi_p) \ + dspi_status_clear(__dspi_p, FREESCALE_DSPI_SR_TXRXS_M) + +// Alternate clocking for spi_transaction_end() +// Used to initialize CTAR1. +static const cyg_freescale_dspi_clocking_t aux_clocking = +{ + .frame_size = 4, + .cl_pol = 0, + .cl_pha = 0, + .cl_brate = CYGHWR_DEVS_FREESCALEDSPI_DSPI_CTAR1_AUX_SPEED, + .cs_up_udly = CYGHWR_DEVS_FREESCALEDSPI_DSPI_CTAR1_AUX_CS_DELAY, + .cs_dw_udly = CYGHWR_DEVS_FREESCALEDSPI_DSPI_CTAR1_AUX_CS_DELAY, + .tr_bt_udly =CYGHWR_DEVS_FREESCALEDSPI_DSPI_CTAR1_AUX_CS_DELAY, + .dl_unit = CYGNUM_DSPI_DELAY_UNIT( + CYGHWR_DEVS_FREESCALE_DSPI_DSPI_CTAR1_AUX_DELAY_UNIT), + .cl_dbr = CYGHWR_DEVS_FREESCALEDSPI_DSPI_CTAR1_AUX_USE_DBR +}; + +//----------------------------------------------------------------------------- +// Implement DSPI ISRs. + +// ISR for DSPI with DMA +// Disable DSPI IRQ and Tx DMA channel and schedule DSR. +static cyg_uint32 dspi_dma_ISR(cyg_vector_t vector, cyg_addrword_t data) +{ + cyg_spi_freescale_dspi_bus_t* dspi_bus_p = + (cyg_spi_freescale_dspi_bus_t*) data; + cyghwr_devs_freescale_dspi_t* dspi_p = dspi_bus_p->setup_p->dspi_p; + cyghwr_hal_freescale_dma_set_t *dma_set_p = dspi_bus_p->setup_p->dma_set_p; + cyghwr_hal_freescale_edma_t *edma_p; + edma_p = dma_set_p->edma_p; + + cyg_drv_isr_lock(); + + // Disable the Tx DMA channel and DSPI IRQ. + hal_freescale_edma_erq_disable(edma_p, SPI_DMA_CHAN_I(dma_set_p, TX)); + DSPI_IRQ_DISABLE(dspi_p); + + cyg_drv_interrupt_acknowledge(vector); + cyg_drv_isr_unlock(); + return (CYG_ISR_CALL_DSR | CYG_ISR_HANDLED); +} + +// ISR for DSPI without DMA +// Disable DSPI IRQ and schedule DSR. +static cyg_uint32 dspi_nodma_ISR(cyg_vector_t vector, cyg_addrword_t data) +{ + cyg_spi_freescale_dspi_bus_t* dspi_bus_p = + (cyg_spi_freescale_dspi_bus_t*) data; + cyghwr_devs_freescale_dspi_t* dspi_p = dspi_bus_p->setup_p->dspi_p; + + cyg_drv_isr_lock(); + + // Disable the DSPI IRQ. + DSPI_IRQ_DISABLE(dspi_p); + + cyg_drv_interrupt_acknowledge(vector); + cyg_drv_isr_unlock(); + return (CYG_ISR_CALL_DSR | CYG_ISR_HANDLED); +} + +// DSPI DSR +static void dspi_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + cyg_spi_freescale_dspi_bus_t* dspi_bus = (cyg_spi_freescale_dspi_bus_t*) data; + + cyg_drv_dsr_lock(); + cyg_drv_cond_signal(&dspi_bus->transfer_done); + cyg_drv_dsr_unlock(); +} + +//----------------------------------------------------------------------------- +// Calculate best fit CTAR baud rate setting (using some brute force). +// Best fit is considered the highest frequency that is not highe than set point. + +static const cyg_uint16 ctar_br[16] = { 2/2, 4/2, 6/2, 8/2, 16/2, 32/2, 64/2, + 128/2, 256/2, 512/2, 1024/2, 2048/2, 4096/2, 8192/2, 16384/2, 32768/2 }; +static const cyg_uint8 ctar_pbr[4] = { 2, 3, 5, 7 }; + +static const cyg_uint16 ctar_cssck[16] = { 2/2, 4/2, 8/2, 16/2, 32/2, 64/2, + 128/2, 256/2, 512/2, 1024/2, 2048/2, 4096/2, 8192/2, 16384/2, 32768/2, + 65536/2 }; +static const cyg_uint8 ctar_pcssck[4] = { 1, 3, 5, 7 }; + +typedef struct ctar_br_s { + cyg_uint8 valid; + cyg_uint8 br; + cyg_uint8 dbr; + cyg_uint8 pbr; +} ctar_br_t; + +static int dspi_ctar_brbf (const cyg_freescale_dspi_clocking_t* spi_cocking, + ctar_br_t* brs_p, const cyg_uint16* br_p, + const cyg_uint8* pbr_p, cyg_uint32* alt_brate, + cyg_uint32 sys_clk) +{ + cyg_uint32 pbr_i; + cyg_uint32 br_i; + cyg_uint32 dbr; + cyg_uint32 clk; + cyg_uint32 baud_bf = 0; // Best fit + cyg_uint32 baud_tmp; + cyg_uint32 baud_sp = alt_brate ? *alt_brate : + spi_cocking->cl_brate; // Set point + + // Calculate the maximal viable bus speed. + clk = sys_clk; + // Desired baud rate very high, use DBR if allowed + dbr = (baud_sp > (clk / 4)) && spi_cocking->cl_dbr && (br_p == ctar_br); + + for(pbr_i = 0; pbr_i < 3; pbr_i++) { + for(br_i = 0; br_i < 15; br_i++) { + if((baud_tmp = (clk * (1+dbr)) / (pbr_p[pbr_i] * (2*br_p[br_i]))) + <= baud_sp) + { + if(baud_tmp > baud_bf) { + DEBUG3_PRINTF("DSPI Baud:" + " SP=%d pbr=0x%x br=0x%x dbr=%d Temp=%d (SysClk=%d)\n", + baud_sp, pbr_i, br_i, dbr, baud_tmp, clk); + brs_p->br = br_i; + brs_p->pbr = pbr_i; + brs_p->valid = 1; + baud_bf = baud_tmp; + if(baud_tmp == baud_sp) + goto baud_found; + } + } + } + } + if(!brs_p->valid) { + pbr_i = 3; + br_i = 15; + DEBUG1_PRINTF("DSPI Baud too low:" + " SP=%d pbr=0x%x br=0x%x Actual=%d (SysClk=%d)\n", + baud_sp, pbr_i, br_i, + (clk * (1+dbr)) / (pbr_p[pbr_i] * (2*br_p[br_i])), clk); + brs_p->br = br_i; + brs_p->pbr = pbr_i; + + return -1; + } else { +baud_found: + brs_p->dbr = dbr; + DEBUG1_PRINTF("DSPI Baud found:" + " SP=%d pbr=0x%x br=0x%x dbr=%d Actual=%dHz (%dns) (SysClk=%d)\n", + baud_sp, brs_p->pbr, brs_p->br, dbr, baud_bf, 1000000000/baud_bf, clk); + + return 0; + } +} + +// Set Clock and Transfer Attributes Register +#define CYG_ASSERT_LOW_FREQ \ + CYG_ASSERT (false, "Freescale DSPI: Cannot run bus as slowly as requested.") +cyg_uint32 +dspi_calc_ctar(const cyg_freescale_dspi_clocking_t* spi_clocking, cyg_uint32 sys_clk) +{ + cyg_uint32 regval; + ctar_br_t brs; + cyg_uint32 delay_brate; + + regval = FREESCALE_DSPI_CTAR_FMSZ(spi_clocking->frame_size - 1); + if(spi_clocking->cl_pol) + regval |= FREESCALE_DSPI_CTAR_SLAVE_CPOL_M; + if(spi_clocking->cl_pha) + regval |= FREESCALE_DSPI_CTAR_SLAVE_CPHA_M; + if(spi_clocking->lsb_first) + regval |= FREESCALE_DSPI_CTAR_LSBFE_M; + + // Get divider bits + // Baud rate + brs.dbr = 0; + if (!dspi_ctar_brbf(spi_clocking, &brs, ctar_br, ctar_pbr, NULL, sys_clk)) + { + regval |= FREESCALE_DSPI_CTAR_BR(brs.br) | + FREESCALE_DSPI_CTAR_PBR(brs.pbr) | + (brs.dbr ? FREESCALE_DSPI_CTAR_DBR_M : 0); + } else + CYG_ASSERT_LOW_FREQ; + + delay_brate = 100000000 / (spi_clocking->dl_unit * spi_clocking->cs_up_udly); + if (!dspi_ctar_brbf(spi_clocking, &brs, ctar_cssck, ctar_pcssck, + &delay_brate, sys_clk)) + { + regval |= FREESCALE_DSPI_CTAR_CSSCK(brs.br) | + FREESCALE_DSPI_CTAR_PCSSCK(brs.pbr); + } else + CYG_ASSERT_LOW_FREQ; + + // Delay between clock and CS negation + delay_brate = 100000000 / (spi_clocking->dl_unit * spi_clocking->cs_dw_udly); + if (!dspi_ctar_brbf(spi_clocking, &brs, ctar_cssck, ctar_pcssck, + &delay_brate, sys_clk)) + { + regval |= FREESCALE_DSPI_CTAR_ASC(brs.br) | + FREESCALE_DSPI_CTAR_PASC(brs.pbr); + } else + CYG_ASSERT_LOW_FREQ; + + // Delay between clock and CS negation and assertion + delay_brate = 100000000 / (spi_clocking->dl_unit * spi_clocking->tr_bt_udly); + if (!dspi_ctar_brbf(spi_clocking, &brs, ctar_cssck, ctar_pcssck, + &delay_brate, sys_clk)) + { + regval |= FREESCALE_DSPI_CTAR_DT(brs.br) | + FREESCALE_DSPI_CTAR_PDT(brs.pbr); + } else + CYG_ASSERT_LOW_FREQ; + return regval; +} + +//---------------------------------------------------------------------------- +//Set up SPI bus pins + +static void dspi_pin_setup(const cyg_uint32* spi_pins_p, + const cyg_uint32* cs_pins_p, cyg_uint32 cs_pin_n) +{ + const cyg_uint32* pin_p; + + for(pin_p = spi_pins_p; + pin_p < spi_pins_p + 3; + CYGHWR_IO_FREESCALE_DSPI_PIN(*pin_p++)); + + for(pin_p = cs_pins_p; + pin_p < cs_pins_p + cs_pin_n; + CYGHWR_IO_FREESCALE_DSPI_PIN(*pin_p++)); +} + +//----------------------------------------------------------------------------- +// Set up a new SPI bus on initialisation. + +static void dspi_bus_setup(cyg_spi_freescale_dspi_bus_t* spi_bus_p) +{ + cyghwr_devs_freescale_dspi_t* dspi_p = spi_bus_p->setup_p->dspi_p; + cyghwr_hal_freescale_dma_set_t* dma_set_p; + cyghwr_hal_freescale_edma_t* edma_p; + cyg_uint32 dma_chan_i; + + // Set up the clocking. + CYGHWR_IO_CLOCK_ENABLE(spi_bus_p->setup_p->clk_gate); + spi_bus_p->clock_freq = CYGHWR_IO_SPI_FREESCALE_DSPI_CLOCK; + DEBUG1_PRINTF("DSPI BUS %p: SysClk=%d\n", spi_bus_p, spi_bus_p->clock_freq); + + // Set up the pins. + dspi_pin_setup(spi_bus_p->setup_p->spi_pin_list_p, + spi_bus_p->setup_p->cs_pin_list_p, + spi_bus_p->setup_p->cs_pin_num); + + // Set up default SPI configuration. + dspi_p->mcr = spi_bus_p->setup_p->mcr_opt | FREESCALE_DSPI_MCR_MSTR_M | + FREESCALE_DSPI_MCR_CLR_RXF_M | FREESCALE_DSPI_MCR_CLR_TXF_M | + FREESCALE_DSPI_MCR_MDIS_M; + + // Enable DSPI controller. + dspi_enable(dspi_p); + + if((dma_set_p=spi_bus_p->setup_p->dma_set_p)) { + // Initialize DMA channels + hal_freescale_edma_init_chanset(dma_set_p); +#if DEBUG_SPI >= 1 + hal_freescale_edma_diag(dma_set_p, 0xffff); + cyghwr_devs_freescale_dspi_diag(spi_bus_p); +#endif + // Set up DMA transfer control descriptors + edma_p = dma_set_p->edma_p; + dma_chan_i = dma_set_p->chan_p[SPI_DMA_CHAN_TX_I].dma_chan_i; + hal_freescale_edma_transfer_init(edma_p, dma_chan_i, + spi_bus_p->tx_dma_tcd_ini_p); +#if DEBUG_SPI >= 1 + hal_freescale_edma_transfer_diag(edma_p, dma_chan_i, true); +#endif + dma_chan_i = dma_set_p->chan_p[SPI_DMA_CHAN_RX_I].dma_chan_i; + hal_freescale_edma_transfer_init(edma_p, dma_chan_i, + spi_bus_p->rx_dma_tcd_ini_p); +#if DEBUG_SPI >= 1 + hal_freescale_edma_transfer_diag(edma_p, dma_chan_i, true); +#endif + } +#if DEBUG_SPI >= 1 + cyghwr_devs_freescale_dspi_diag(spi_bus_p); +#endif + // Initialise the synchronisation primitivies. + cyg_drv_mutex_init (&spi_bus_p->transfer_mutex); + cyg_drv_cond_init (&spi_bus_p->transfer_done, &spi_bus_p->transfer_mutex); + + // Hook up the ISR and DSR. + cyg_drv_interrupt_create (spi_bus_p->setup_p->intr_num, + spi_bus_p->setup_p->intr_prio, + (cyg_addrword_t) spi_bus_p, + dma_set_p ? dspi_dma_ISR : dspi_nodma_ISR, + dspi_DSR, &spi_bus_p->intr_handle, + &spi_bus_p->intr_data); + cyg_drv_interrupt_attach (spi_bus_p->intr_handle); + + dspi_p->ctar[1] = dspi_calc_ctar(&aux_clocking, spi_bus_p->clock_freq); + + // Call upper layer bus init. + CYG_SPI_BUS_COMMON_INIT(&spi_bus_p->spi_bus); +} + +//----------------------------------------------------------------------------- +// Set up Rx DMA channel +static void +rx_dma_channel_setup(cyghwr_hal_freescale_dma_set_t *dma_set_p, + cyg_uint8* data_buf, cyg_uint32 bus_16bit, + volatile cyghwr_hal_freescale_edma_tcd_t *tcd_p) +{ + cyg_uint32 step, sdsize; + static cyg_uint8 popr_sink; + + // Set the correct transfer size. + if(bus_16bit) { + step = 2; + sdsize = FREESCALE_EDMA_ATTR_SIZE_16; + } else { + step = 1; + sdsize = FREESCALE_EDMA_ATTR_SIZE_8; + } + if(data_buf) { + tcd_p->doff = step; + tcd_p->daddr = data_buf; + } else { + tcd_p->doff = 0; + tcd_p->daddr = &popr_sink; + } + tcd_p->nbytes.mlno = step; + tcd_p->attr = FREESCALE_EDMA_ATTR_SSIZE(sdsize) | + FREESCALE_EDMA_ATTR_DSIZE(sdsize) | + FREESCALE_EDMA_ATTR_SMOD(0) | + FREESCALE_EDMA_ATTR_DMOD(0); +#if DEBUG_SPI >= 3 + hal_freescale_edma_tcd_diag(tcd_p, -1, "[DSPI Rx]"); +#endif +} + +//---------------------------------------------------------------------------- +// Set up Tx FIFO queue +// Set up Tx FIFO command queue +// DSPI requires sending command for every transfer. +// Used for transfers that fit within DSPI FIFO. + +#if DEBUG_SPI >= 2 +static const char debug_format[] = "BUFF %dbit %s: %p 0x%08x remain %d:\n"; +static const char debug_format1[] = "PUSHR 0x%08x %s: %p 0x%08x remain %d:\n"; +#endif + +static inline volatile cyg_uint32 +fifo_pushque_fill(cyg_spi_freescale_dspi_bus_t* dspi_bus, cyg_uint8* + data_p, cyg_uint32 count, cyg_bool bus_16bit, cyg_uint32 pushr, + cyg_bool drop_cs) +{ + cyghwr_devs_freescale_dspi_t* dspi_p = dspi_bus->setup_p->dspi_p; + cyg_uint32 txfifo_n = dspi_bus->txfifo_n; + + if(data_p) { + if(!bus_16bit) { + for(; count > 1; count--) { + if(!(--txfifo_n)) { + dspi_p->pushr = pushr |= *data_p | FREESCALE_DSPI_PUSHR_EOQ_M; + count--; + DEBUG2_PRINTF(debug_format, 8, "FBK", data_p, + pushr | *data_p, count); + return count; + } + DEBUG3_PRINTF(debug_format, 8, "FAD", data_p, + pushr | *data_p, count-1); + dspi_p->pushr = pushr | *data_p++; + } + pushr |= *data_p; + } else { + cyg_uint16* data16_p = (cyg_uint16 *)data_p; + cyg_uint16 data_word; + + for(; count > 2; count-=2) { + if(!(--txfifo_n)) { + dspi_p->pushr = pushr |= *data16_p | FREESCALE_DSPI_PUSHR_EOQ_M; + count-=2; + DEBUG2_PRINTF(debug_format, 16, "FBK", data_p, + pushr, count); + return count; + } + DEBUG3_PRINTF(debug_format, 16, "FAD", data16_p, + pushr | *data16_p, (count-1)*2); + data_word = *data16_p++; + dspi_p->pushr = pushr | data_word; + } + data_word = *data16_p; + pushr |= data_word; + } + } else { + pushr |= PUSHR_NULL; + for(; count > 1; count--) { + if(!(--txfifo_n)) { + dspi_p->pushr = pushr |= FREESCALE_DSPI_PUSHR_EOQ_M; + count--; + DEBUG2_PRINTF(debug_format, 0, "FBK", &dspi_p->pushr, + pushr, count); + return count; + } + dspi_p->pushr = pushr; + DEBUG3_PRINTF(debug_format, 0, "FAD", &dspi_p->pushr, pushr, + count-1); + } + } + if(drop_cs) + pushr &= ~FREESCALE_DSPI_PUSHR_CONT_M; + dspi_p->pushr = pushr |= FREESCALE_DSPI_PUSHR_EOQ_M; + DEBUG2_PRINTF(data_p ? debug_format : debug_format1, data_p ? (bus_16bit ? 16 :8) : pushr, + (drop_cs ? "FEN" : "FSG"), data_p /*&dspi_p->pushr*/, pushr, 0); + return 0; +} + +//---------------------------------------------------------------------------- +// Set up Tx +// Set up Tx DMA command queue +// DSPI requires sending command for every transfer. +// Used for transfers larger than DSPI FIFO + +static inline volatile cyg_uint32 +dma_pushque_fill(cyg_spi_freescale_dspi_bus_t* dspi_bus, cyg_uint8* data_p, + cyg_uint32 count, cyg_bool bus_16bit, cyg_uint32 pushr, + cyg_bool drop_cs) +{ + volatile cyg_uint32* pushque_p; + volatile cyg_uint32* pushque_end; + + pushque_p = dspi_bus->pushque_p; + pushque_end = pushque_p + (dspi_bus->pushque_n - (bus_16bit ? 2 : 1)); + pushque_p = dspi_bus->pushque_p; + if(data_p) { + if(!bus_16bit) { + do { + if(pushque_p == pushque_end) { + *pushque_p = pushr | *data_p | FREESCALE_DSPI_PUSHR_EOQ_M; + count--; + + DEBUG2_PRINTF(debug_format, 8, "BRK", pushque_p, + pushque_p[0], count); + return count; + } + *pushque_p++ = pushr | *data_p++; + DEBUG3_PRINTF(debug_format, 8, "ADD", pushque_p-1, + pushque_p[-1], count-1); + } while(--count > 1); + pushr |= *data_p; + } else { + cyg_uint16* data16_p = (cyg_uint16 *)data_p; + cyg_uint16 data_word; + do { + if(pushque_p == pushque_end) { + data_word = *data16_p; + *pushque_p = pushr | data_word | FREESCALE_DSPI_PUSHR_EOQ_M; + count-=2; + + DEBUG2_PRINTF(debug_format, 16, "BRK", pushque_p, + pushque_p[0], count); + return count; + } + data_word = *data16_p++; + *pushque_p++ = pushr | data_word; + DEBUG3_PRINTF(debug_format, 16, "ADD", pushque_p-1, + pushque_p[-1], count-2); + } while((count -= 2) > 2); + data_word = *data16_p; + pushr |= data_word; + } + } else { + pushr |= PUSHR_NULL; + do { + if(pushque_p == pushque_end) { + *pushque_p = pushr | FREESCALE_DSPI_PUSHR_EOQ_M; + count--; + + DEBUG2_PRINTF(debug_format, 0, "BRK", pushque_p, + pushque_p[0], count); + return count; + } + *pushque_p++ = pushr; + DEBUG3_PRINTF(debug_format, 0, "ADD", pushque_p-1, pushque_p[-1], + count-1); + } while(--count > 1); + } + if(drop_cs) pushr &= ~FREESCALE_DSPI_PUSHR_CONT_M; + *pushque_p = pushr |= FREESCALE_DSPI_PUSHR_EOQ_M; + DEBUG2_PRINTF(debug_format, data_p ? (bus_16bit ? 16 :8) : 0, + (drop_cs ? "END" : "SGM"), pushque_p, pushque_p[0], 0); + + return 0; +} + +// Set up Tx DMA channel +// Used for transfers larger than DSPI FIFO + +static inline cyg_uint32 +tx_dma_channel_setup(cyg_spi_freescale_dspi_bus_t* dspi_bus, + cyg_uint8* data_buf, cyg_uint32 count, + cyg_bool bus_16bit, + cyg_uint32 pushr, cyg_bool drop_cs) +{ + cyghwr_hal_freescale_dma_set_t *dma_set_p = dspi_bus->setup_p->dma_set_p; + cyghwr_hal_freescale_edma_t *edma_p = dma_set_p->edma_p; + volatile cyghwr_hal_freescale_edma_tcd_t *tcd_p; + cyg_uint32 remain=0; + cyg_uint32 dma_chan_i; + + remain = dma_pushque_fill(dspi_bus, data_buf, count, bus_16bit, pushr, drop_cs); + dma_chan_i = SPI_DMA_CHAN_I(dma_set_p, TX); + tcd_p = &edma_p->tcd[dma_chan_i]; + tcd_p->saddr = dspi_bus->pushque_p; + DEBUG2_PRINTF("DSPI: Tx channel setup\n"); +#if DEBUG_SPI >= 3 + hal_freescale_edma_transfer_diag(edma_p, dma_chan_i, true); +#endif + return remain; +} + +//----------------------------------------------------------------------------- +// Set SPI peripheral chip select. + +static inline cyg_uint32 +dspi_chip_select_set(cyg_int32 cs_i, cyg_bool pccse, cyg_bool assert) +{ + cyg_uint32 spi_pushr; + + if(cs_i < 0) { + spi_pushr = 0; + } else { + if(pccse) { + spi_pushr = cs_i; + } else { + if(cs_i < 5) { + if(assert) { + cs_i = 1 << cs_i; + spi_pushr = FREESCALE_DSPI_PUSHR_PCS(cs_i); + } else + spi_pushr = 0; + } else { + CYG_ASSERT(1, "DSPI: Peripheral Chip Select out of range.\n"); + spi_pushr = 1 << 5; + } + } + } + return spi_pushr; +} + +//----------------------------------------------------------------------------- +// Execute SPI transaction. + +static void spi_transaction_do (cyg_spi_device* device, cyg_bool tick_only, + cyg_bool polled, cyg_uint32 count, + const cyg_uint8* tx_data, cyg_uint8* rx_data, + cyg_bool drop_cs) +{ + cyg_spi_freescale_dspi_bus_t* dspi_bus = + (cyg_spi_freescale_dspi_bus_t*) device->spi_bus; + cyg_spi_freescale_dspi_device_t* dspi_device = + (cyg_spi_freescale_dspi_device_t*) device; + cyg_bool bus_16bit = dspi_device->clocking.bus_16bit; + cyghwr_devs_freescale_dspi_t* dspi_p = dspi_bus->setup_p->dspi_p; + + cyghwr_hal_freescale_dma_set_t* dma_set_p; + cyghwr_hal_freescale_edma_t* edma_p = NULL; + + cyg_uint32 count_down; + cyg_uint32 txfifo_n = dspi_bus->txfifo_n; + cyg_uint32 pushr; + cyg_uint32 pushque_n; + cyg_uint32 dma_chan_rx_i = 0; + cyg_uint32 dma_chan_tx_i = 0; + cyg_uint8* rx_data0; + +#if DEBUG_SPI >= 2 + cyg_uint32 first_turn = 1; +#endif + + DEBUG2_PRINTF("DSPI: transaction: count=%d drop_cs=%d tick_only=%d\n", + count, drop_cs, tick_only); + + // Set up peripheral CS field. DSPI automatically asserts and deasserts CS + pushr = +#ifndef CYGOPT_DEVS_SPI_FREESCALE_DSPI_TICK_ONLY_DROPS_CS + // Compatibility option + // eCos Reference Manual states that CS should drop prior to sending + // ticks, but other SPI drivers do not touch the CS. + tick_only ? dspi_p->pushr & 0x87FF0000 : +#endif + dspi_chip_select_set( +#ifdef CYGOPT_DEVS_SPI_FREESCALE_DSPI_TICK_ONLY_DROPS_CS + // Compatibility option. See comment above. + tick_only ? -1 : +#endif + dspi_device->dev_num, + dspi_p->mcr & FREESCALE_DSPI_MCR_PCSSE_M, true); + pushr |= FREESCALE_DSPI_PUSHR_CONT_M; + + dspi_fifo_clear(dspi_p); + + pushque_n = dspi_bus->pushque_n; + if(bus_16bit) + txfifo_n *= 2; + + dma_set_p = dspi_bus->setup_p->dma_set_p; + if((count > txfifo_n) && dma_set_p) { + rx_data0 = rx_data; + edma_p = dma_set_p->edma_p; + // Set up the DMA channels. + dma_chan_rx_i = SPI_DMA_CHAN_I(dma_set_p, RX); + dma_chan_tx_i = SPI_DMA_CHAN_I(dma_set_p, TX); + rx_dma_channel_setup(dma_set_p, (cyg_uint8*) rx_data, + bus_16bit, &edma_p->tcd[dma_chan_rx_i]); + hal_freescale_edma_erq_enable(edma_p, dma_chan_rx_i); + dspi_irq_enable(dspi_p, + FREESCALE_DSPI_RSER_TFFF_RE_M | + FREESCALE_DSPI_RSER_RFDF_RE_M | + FREESCALE_DSPI_RSER_TFFF_DIRS_M | + FREESCALE_DSPI_RSER_RFDF_DIRS_M); + } else { + rx_data0 = NULL; + // If byte count fits in the FIFO don't bother with DMA. + if(dma_set_p) { + edma_p = dma_set_p->edma_p; + hal_freescale_edma_erq_disable(edma_p, SPI_DMA_CHAN_I(dma_set_p, RX)); + } + dma_set_p = NULL; + dspi_irq_disable(dspi_p, + FREESCALE_DSPI_RSER_TFFF_RE_M | + FREESCALE_DSPI_RSER_RFDF_RE_M | + FREESCALE_DSPI_RSER_TFFF_DIRS_M | + FREESCALE_DSPI_RSER_RFDF_DIRS_M); + } + + if(!polled) + cyg_drv_interrupt_unmask(dspi_bus->setup_p->intr_num); + count_down = count; + while(count_down) { +#if DEBUG_SPI >= 2 + if(first_turn) { + if(dspi_bus->pushque_p) + dspi_bus->pushque_p[0] |= FREESCALE_DSPI_PUSHR_CTCNT_M; + first_turn = 0; + } +#endif + if(dma_set_p && (count_down > txfifo_n)) { + // Transfer size is larger than DSPI FIFO + // Use DMA Tx + count_down = tx_dma_channel_setup(dspi_bus, (cyg_uint8*) tx_data, + count_down, bus_16bit, + pushr, drop_cs); +#if DEBUG_SPI >= 3 + hal_freescale_edma_transfer_diag(edma_p, dma_chan_rx_i, true); +#endif + // Enable the Tx DMA / SPI controller. + hal_freescale_edma_erq_enable(edma_p, dma_chan_tx_i); + DSPI_EOQ_CLEAR(dspi_p); + } else { + // Transfer size fits within DSPI FIFO + // No need for DMA Tx + DSPI_EOQ_CLEAR(dspi_p); + count_down = fifo_pushque_fill(dspi_bus, (cyg_uint8*) tx_data, + count_down, bus_16bit, + pushr, drop_cs); +#if DEBUG_SPI >= 3 + cyghwr_devs_freescale_dspi_diag(dspi_bus); +#endif + } + + if(polled) { + DEBUG2_PRINTF("DSPI Polled:\n"); + // Busy-wait for DSPI/DMA (polling for completion). + while(!(dspi_p->sr & FREESCALE_DSPI_SR_EOQF_M)); + + if(dma_set_p) { + // Disable the Tx DMA channel on completion. + hal_freescale_edma_erq_disable(edma_p, dma_chan_tx_i); + } + } else { + // Wait for DSPI/DMA completion. (interrupt driven). + cyg_drv_mutex_lock(&dspi_bus->transfer_mutex); + cyg_drv_dsr_lock(); + + DSPI_IRQ_ENABLE(dspi_p); + DEBUG2_PRINTF("DSPI IRQ: Enabled\n"); + + // Sit back and wait for the ISR/DSRs to signal completion. + cyg_drv_cond_wait (&dspi_bus->transfer_done); + + cyg_drv_dsr_unlock(); + cyg_drv_mutex_unlock(&dspi_bus->transfer_mutex); + } + + if(dma_set_p) { + // Make sure that Rx has been drained by DMA. + while((dspi_p->sr & FREESCALE_DSPI_SR_RFDF_M)); + DEBUG2_PRINTF("Fifo Drained by DMA 0x%08x\n", dspi_p->sr); + if(count_down <= txfifo_n && count_down > 0) { + hal_freescale_edma_erq_disable(edma_p, dma_chan_rx_i); + dma_set_p = NULL; + } + } else { + // No DMA - "manually" drain Rx FIFO + DEBUG2_PRINTF("DSPI FIFO: 'Manually' drain Rx fifo rx_data=%p bus_16bit=%d\n", + rx_data, bus_16bit); +#if DEBUG_SPI >= 3 + cyghwr_devs_freescale_dspi_diag(dspi_bus); +#endif + if(rx_data) { + if(bus_16bit) { + cyg_uint16* rx_data16 = (cyg_uint16*) rx_data; + while(dspi_p->sr & FREESCALE_DSPI_SR_RXCTR_M) { + DEBUG2_PRINTF(" Fifo Pull16 at %p\n", rx_data16); + *rx_data16++ = dspi_p->popr; + } + rx_data = (cyg_uint8*) rx_data16; + } else { + while(dspi_p->sr & FREESCALE_DSPI_SR_RXCTR_M) { + DEBUG2_PRINTF(" Fifo Pull at %p\n", rx_data); + *rx_data++ = dspi_p->popr; + } + } + } + dspi_fifo_drain(dspi_p); + } + dspi_fifo_clear(dspi_p); + // Prepare for next iteration + if(tx_data) { + tx_data += pushque_n; + if(bus_16bit) + tx_data += pushque_n; + } + } + if(rx_data0) { + // Rx buffer may be out of sync with cache. + DEBUG2_PRINTF("DSPI DMA: Flush cache %p len=%d\n", rx_data0, count); + HAL_DCACHE_INVALIDATE(rx_data0, count); + DEBUG2_PRINTF("DSPI DMA: Cache flushed\n"); + } + + if(!polled) + cyg_drv_interrupt_mask(dspi_bus->setup_p->intr_num); + + dspi_device->chip_sel = !drop_cs; + DEBUG2_PRINTF("cyg_transaction_do() chip_sel = %d drop_cs = %d\n", dspi_device->chip_sel, drop_cs); +} + +//----------------------------------------------------------------------------- +// Initialise SPI interfaces on startup. + +static void CYGBLD_ATTRIB_C_INIT_PRI(CYG_INIT_BUS_SPI) +dspi_spi_init(void) +{ +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI0 + dspi_bus_setup (&cyg_spi_dspi_bus0); +#endif + +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI1 + dspi_bus_setup (&cyg_spi_dspi_bus1); +#endif + +#ifdef CYGHWR_DEVS_SPI_FREESCALE_DSPI2 + dspi_bus_setup (&cyg_spi_dspi_bus2); +#endif +} + + +//----------------------------------------------------------------------------- +// Start a SPI transaction. + +static void dspi_transaction_begin(cyg_spi_device* device) +{ + cyg_spi_freescale_dspi_bus_t* dspi_bus = + (cyg_spi_freescale_dspi_bus_t*) device->spi_bus; + cyg_spi_freescale_dspi_device_t* dspi_device = + (cyg_spi_freescale_dspi_device_t*) device; + + // On the first transaction, generate the values to be programmed into the + // SPI configuration registers for this device and cache them. This avoids + // having to recalculate the prescaler for every transaction. + if(!(dspi_device->clocking.dspi_ctar)) + dspi_device->clocking.dspi_ctar = dspi_calc_ctar(&dspi_device->clocking, + dspi_bus->clock_freq); + // Set up the SPI controller. + dspi_bus->setup_p->dspi_p->ctar[0] = dspi_device->clocking.dspi_ctar; +#if DEBUG_SPI >= 2 + cyghwr_devs_freescale_dspi_diag(dspi_bus); +#endif +} + +//----------------------------------------------------------------------------- +// Run a transaction transfer. + +static void dspi_transaction_transfer(cyg_spi_device* device, cyg_bool polled, + cyg_uint32 count, + const cyg_uint8* tx_data, + cyg_uint8* rx_data, + cyg_bool drop_cs) +{ + cyg_spi_freescale_dspi_device_t* dspi_device = + (cyg_spi_freescale_dspi_device_t*) device; + + DEBUG2_PRINTF("Transaction rx_data = %p tx_data = %p count=%d\n", rx_data, tx_data, count); + + // Check for unsupported transactions. + CYG_ASSERT (count > 0, "DSPI: Null transfer requested."); + + // We check that the buffers are half-word aligned and that count is a + // multiple of two in order to carry out the 16-bit transfer. + if (dspi_device->clocking.bus_16bit) { + CYG_ASSERT (!(count & 1) && !((cyg_uint32) tx_data & 1) && + !((cyg_uint32) rx_data & 1), + "DSPI: Misaligned data in 16-bit transfer."); + } + spi_transaction_do (device, false, polled, count, tx_data, rx_data, drop_cs); +} + +//----------------------------------------------------------------------------- +// Carry out a bus tick operation - this drops chip select then pushes the +// required number of NULL frames onto the bus. + +static void dspi_transaction_tick(cyg_spi_device* device, cyg_bool polled, + cyg_uint32 count) +{ + cyg_spi_freescale_dspi_device_t* dspi_device = + (cyg_spi_freescale_dspi_device_t*) device; + + // Check for unsupported transactions. + CYG_ASSERT (count > 0, "DSPI: Null transfer requested."); + + // We check that count is a multiple of two in order + // to carry out the 16-bit transfer. + if (dspi_device->clocking.bus_16bit) { + CYG_ASSERT (!(count & 1), + "DSPI: Misaligned data in 16-bit transfer."); + } + + // Perform null transfer + DEBUG2_PRINTF("cyg_transaction_tick()\n"); + spi_transaction_do (device, true, polled, count, NULL, NULL, false); +} + +//----------------------------------------------------------------------------- +// Terminate a SPI transaction, disabling the SPI controller. + +static void dspi_transaction_end(cyg_spi_device* device) +{ + cyg_spi_freescale_dspi_bus_t* dspi_bus = + (cyg_spi_freescale_dspi_bus_t*) device->spi_bus; + cyg_spi_freescale_dspi_device_t* dspi_device = + (cyg_spi_freescale_dspi_device_t*) device; + + const cyghwr_hal_freescale_dma_set_t *dma_set_p = dspi_bus->setup_p->dma_set_p; + cyghwr_hal_freescale_edma_t *edma_p; + cyghwr_devs_freescale_dspi_t* dspi_p = dspi_bus->setup_p->dspi_p; + + DEBUG2_PRINTF("cyg_transaction_end() chip_sel = %d\n", dspi_device->chip_sel); + if(dma_set_p) { + edma_p = dma_set_p->edma_p; + hal_freescale_edma_erq_disable(edma_p, SPI_DMA_CHAN_I(dma_set_p, TX)); + hal_freescale_edma_erq_disable(edma_p, SPI_DMA_CHAN_I(dma_set_p, RX)); + } + + if(dspi_device->chip_sel){ + // Clear peripheral CS by executing a dummy 4 bit transfer. + dspi_p->pushr = PUSHR_NULL | FREESCALE_DSPI_PUSHR_EOQ_M | + FREESCALE_DSPI_PUSHR_CTAS(1); + while(!(dspi_p->sr & FREESCALE_DSPI_SR_EOQF_M)); + DSPI_EOQ_CLEAR(dspi_p); + dspi_fifo_drain(dspi_p); + dspi_device->chip_sel = 0; + } +} + +//----------------------------------------------------------------------------- +// Get DSPI configuration parameter + +static int dspi_get_config (cyg_spi_device* device, cyg_uint32 key, + void* buf, cyg_uint32* len) +{ + cyg_spi_freescale_dspi_bus_t* dspi_bus = + (cyg_spi_freescale_dspi_bus_t*) device->spi_bus; + cyg_spi_freescale_dspi_device_t* dspi_device = + (cyg_spi_freescale_dspi_device_t*) device; + cyg_uint32* data_p = buf; + + switch (key) { + case CYG_IO_GET_CONFIG_SPI_CLOCKRATE : + // Sanity check + if (NULL == len) { + CYG_ASSERT (false, "Freescale DSPI:" + " Null pointer as len argument for dspi_get_config()."); + return -1; + } else if (sizeof(cyg_uint32) != *len) { + CYG_ASSERT (false, "Freescale DSPI:" + " Invalid length with dspi_get_config()."); + return -1; + } else if (NULL == buf) { + CYG_ASSERT (false, "Freescale DSPI:" + " Null poiter as buf argument for dspi_get_config()."); + return -1; + } else { + cyg_uint32 ctar, dbr, br, pbr; + + ctar = dspi_device->clocking.dspi_ctar; + dbr = (ctar & FREESCALE_DSPI_CTAR_DBR_M) >> + FREESCALE_DSPI_CTAR_DBR_S; + br = (ctar & FREESCALE_DSPI_CTAR_BR_M) >> + FREESCALE_DSPI_CTAR_BR_S; + pbr = (ctar & FREESCALE_DSPI_CTAR_PBR_M) >> + FREESCALE_DSPI_CTAR_PBR_S; + *data_p = (dspi_bus->clock_freq * (1+dbr)) / (pbr * br); + + DEBUG2_PRINTF("DSPI Get Config: baud = %d\n", *data_p); + + return 0; + } + + default : + break; + } + return -1; +} + +//----------------------------------------------------------------------------- +// Change some SPI device configuration parameters + +static int dspi_set_config(cyg_spi_device* device, cyg_uint32 key, + const void* buf, cyg_uint32* len) +{ + cyg_spi_freescale_dspi_device_t* dspi_device = + (cyg_spi_freescale_dspi_device_t*) device; + cyg_spi_freescale_dspi_bus_t* dspi_bus = + (cyg_spi_freescale_dspi_bus_t*) device->spi_bus; + + cyg_uint32 regval; + ctar_br_t brs; + + switch (key) { + case CYG_IO_SET_CONFIG_SPI_CLOCKRATE : + // Sanity check + if (NULL == len) { + CYG_ASSERT (false, "Freescale DSPI:" + " Null pointer as len argument for dspi_set_config()."); + return -1; + } else if (sizeof(cyg_uint32) != *len) { + CYG_ASSERT (false, "Freescale DSPI:" + " Invalid length with dspi_set_config()."); + return -1; + } else if (NULL == buf) { + CYG_ASSERT (false, "Freescale DSPI:" + " Null pointer as buf argument for dspi_set_config()."); + return -1; + } else { + // Get divider bits + if (!dspi_ctar_brbf(&dspi_device->clocking, &brs, + ctar_br, ctar_pbr, (cyg_uint32 *)buf, dspi_bus->clock_freq)) + { + // Update the cache of the configuration register settings. + regval = dspi_device->clocking.dspi_ctar; + regval &= ~(FREESCALE_DSPI_CTAR_BR_M | + FREESCALE_DSPI_CTAR_PBR_M); + regval |= FREESCALE_DSPI_CTAR_BR(brs.br) | + FREESCALE_DSPI_CTAR_PBR(brs.pbr); + dspi_device->clocking.dspi_ctar = regval; + + return 0; + + } else { + CYG_ASSERT (false, "Freescale DSPI:" + " Cannot run bus as slowly as requested."); + return -1; + } + } + default : + break; + } + return -1; +} + +#if DEBUG_SPI +//---------------------------------------------------------------------------- +// Print out a DSPI array state +// Helper for cyghwr_devs_freescale_dspi_diag() + +void cyghwr_devs_freescale_dspi_diag_array(char* name_p, + volatile cyg_uint32* array_p, + cyg_uint32 array_n) +{ + diag_printf("%s %p[%u]: ", name_p, array_p, array_n); + for(; array_n; array_n--) { + diag_printf(" 0x%08x", *array_p++); + } + diag_printf("\n"); +} + +//---------------------------------------------------------------------------- +// Print out DSPI state + +void cyghwr_devs_freescale_dspi_diag(cyg_spi_freescale_dspi_bus_t* dspi_bus_p) +{ + cyghwr_devs_freescale_dspi_t* dspi_p = dspi_bus_p->setup_p->dspi_p; + + diag_printf("DSPI %p\n", dspi_p); + diag_printf(" MCR = 0x%08x TCR = 0x%08x\n", dspi_p->mcr, dspi_p->tcr); + cyghwr_devs_freescale_dspi_diag_array(" CTAR", dspi_p->ctar, + CYGHWR_DEVS_SPI_FREESCALE_DSPI_CTAR_NUM); + diag_printf(" SR = 0x%08x RSER = 0x%08x PUSHR = 0x%08x POPR = 0x%08x\n", + dspi_p->sr, dspi_p->rser, dspi_p->pushr, dspi_p->popr); + cyghwr_devs_freescale_dspi_diag_array(" TXFR", dspi_p->txfr, dspi_bus_p->txfifo_n); + cyghwr_devs_freescale_dspi_diag_array(" RXFR", dspi_p->rxfr, dspi_bus_p->rxfifo_n); +} +#endif // DEBUG_SPI + +#endif // defined(CYGHWR_DEVS_SPI_FREESCALE_DSPIx) + +//============================================================================= diff --git a/ecos/packages/devs/spi/freescale/dspi/current/tests/spi_loopback.c b/ecos/packages/devs/spi/freescale/dspi/current/tests/spi_loopback.c new file mode 100644 index 0000000..6e70e0c --- /dev/null +++ b/ecos/packages/devs/spi/freescale/dspi/current/tests/spi_loopback.c @@ -0,0 +1,285 @@ +//============================================================================= +// +// spi_loopback.c +// +// Standalone SPI loopback test. +// +//============================================================================= +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Ilija Kocho +// Original: Chris Holgate +// Date: 2012-12-27 +// Purpose: Freescale DSPI loopback test +// Description: Standalone SPI loopback test. +// Usage: Compile as a standalone application. +// +//####DESCRIPTIONEND#### +// +//============================================================================= + +//============================================================================= +// This is a quick loopback test for the Freescale DSPI SPI driver. It only checks +// the data transfer functionality - chip select handling will require +// testing with external devices. In order to run the test, the MOSI and +// MISO pins for the test port need to be shorted together to provide an +// external loopback. Don't do this on a bus which has external devices +// attached unless you first make sure that none of them are connected to +// the chip select used by the test harness. +// The default port and chip select used for this test are SPI bus 1, +// chip select 0. These can be changed by editing the loopback_device +// data structure directly. +// Note that this is intended to be run as a standalone test and not as part +// of the standard board tests since it requires a hardware modification. +//============================================================================= + +#include <cyg/infra/cyg_type.h> +#include <cyg/infra/testcase.h> // Test macros + +#include <cyg/infra/cyg_ass.h> // Assertion macros +#include <cyg/infra/diag.h> // Diagnostic output + +#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL +#include <cyg/kernel/kapi.h> + +#include <cyg/io/spi.h> // Common SPI API +#include <cyg/io/spi_freescale_dspi.h> // Freescale DSPI data structures + +#include <string.h> + +//--------------------------------------------------------------------------- +// Thread data structures. + +cyg_uint8 stack [CYGNUM_HAL_STACK_SIZE_TYPICAL]; +cyg_thread thread_data; +cyg_handle_t thread_handle; + +externC cyg_spi_freescale_dspi_bus_t cyg_spi_dspi_bus1; + +//--------------------------------------------------------------------------- +// SPI loopback device driver data structures. + +CYG_DEVS_SPI_FREESCALE_DSPI_DEVICE( + loopback_device, // Device name + 1, //SPI bus + 0, // Dev num + 8, // Frame size + 0, // Clock pol + 0, // Clock phase + 6000000, // Clock speed + 1, // CS assert delay + 1, // CS negate delay + 1, // Delay between transfers + 1000, // Delay unit [ns] + 0 // Double baud rate +); + +//--------------------------------------------------------------------------- + +static int errors = 0; + +const char tx_data0[] = "0123456789a123456789b123456789c123456789d123456789e"; +const char tx_data1[] = "Performing extended API test first transaction..|"; +const char tx_data2[] = "Testing extended API for a second transaction!"; + +char rx_data [256]; +char rx_data1 [256]; +char rx_data2 [256]; + +static void memclr(char *dest_p, cyg_uint32 byte_n) +{ + while(byte_n--) { + *dest_p++ = 0; + } +} + + +//--------------------------------------------------------------------------- +// Run single loopback transaction using simple transfer API call. + +void run_test_tick (cyg_bool polled, cyg_uint32 count) +{ + diag_printf ("Test 0 : Tick (polled = %d).\n", polled ? 1 : 0); + cyg_spi_tick(&loopback_device, polled, count); + diag_printf (" Tick end\n"); +} + +void run_test_1 (cyg_bool polled, const char* tx_data_p, cyg_uint32 count) +{ + diag_printf ("Test 1 : Simple transfer test polled = %d, count=%d\n", + polled ? 1 : 0, count); + memclr(rx_data1, sizeof(rx_data1)); + memclr(rx_data2, sizeof(rx_data1)); + cyg_spi_transfer (&loopback_device, polled, count, + (const cyg_uint8*) tx_data_p, (cyg_uint8*) &rx_data[0]); + diag_printf (" Tx data : %s\n", tx_data_p); + diag_printf (" Rx data : %s 0x%02x\n", rx_data, rx_data[0]); + + if (memcmp (tx_data_p, rx_data, count) != 0) { + errors++; + diag_printf("Simple transfer loopback failed - mismatched data.\n"); + } +} + +//--------------------------------------------------------------------------- +// Run two loopback transactions using extended transfer API. + +void run_test_2 (cyg_bool polled) +{ + diag_printf ("Test 2 : Extended API test (polled = %d).\n", polled ? 1 : 0); + memclr(rx_data1, sizeof(rx_data1)); + memclr(rx_data2, sizeof(rx_data1)); + cyg_spi_transaction_begin (&loopback_device); + cyg_spi_transaction_transfer (&loopback_device, polled, sizeof (tx_data1), + (const cyg_uint8*) &tx_data1[0], (cyg_uint8*) &rx_data1[0], false); + cyg_spi_transaction_transfer (&loopback_device, polled, sizeof (tx_data2), + (const cyg_uint8*) &tx_data2[0], (cyg_uint8*) &rx_data2[0], true); + cyg_spi_transaction_end (&loopback_device); + + diag_printf (" Tx data 1 (%u Bytes): %s\n", sizeof(tx_data1), tx_data1); + diag_printf (" Rx data 1 : %s\n", rx_data1); + diag_printf (" Tx data 2 (%u Bytes): %s\n", sizeof(tx_data2), tx_data2); + diag_printf (" Rx data 2 : %s\n", rx_data2); + if (memcmp (tx_data1, rx_data1, sizeof (tx_data1)) != 0) { + errors++; + diag_printf("Simple transfer loopback failed - mismatched data (transfer 1).\n"); + } + if (memcmp (tx_data2, rx_data2, sizeof (tx_data2)) != 0) { + errors++; + diag_printf("Simple transfer loopback failed - mismatched data (transfer 2).\n"); + } +} + +void run_test_3 (cyg_bool polled) +{ + diag_printf ("Test 3 : Extended API test (polled = %d).\n", polled ? 1 : 0); + memclr(rx_data1, sizeof(rx_data1)); + memclr(rx_data2, sizeof(rx_data1)); + + cyg_spi_transaction_begin (&loopback_device); + cyg_spi_transaction_transfer (&loopback_device, polled, sizeof (tx_data1), + (const cyg_uint8*) &tx_data1[0], (cyg_uint8*) &rx_data1[0], false); + cyg_spi_transaction_transfer (&loopback_device, polled, sizeof (tx_data2), + (const cyg_uint8*) &tx_data2[0], (cyg_uint8*) &rx_data2[0], true); + cyg_spi_transaction_end (&loopback_device); + diag_printf (" Tx data 1 (%u Bytes): %s\n", sizeof(tx_data1), tx_data1); + diag_printf (" Rx data 31 : %s\n", rx_data1); + diag_printf (" Tx data 2 (%u Bytes): %s\n", sizeof(tx_data2), tx_data2); + diag_printf (" Rx data 32 : %s\n", rx_data2); + + if (memcmp (tx_data1, rx_data1, sizeof (tx_data1)) != 0) { + errors++; + diag_printf("Simple transfer loopback failed - mismatched data (transfer 1).\n"); + } + if (memcmp (tx_data2, rx_data2, sizeof (tx_data2)) != 0) { + errors++; + diag_printf("Simple transfer loopback failed - mismatched data (transfer 2).\n"); + } +} + +void run_test_4 (cyg_bool polled) +{ + diag_printf ("Test 4 : Extended API test NULL transfer (polled = %d).\n", polled ? 1 : 0); + memclr(rx_data1, sizeof(rx_data1)); + memclr(rx_data2, sizeof(rx_data1)); + + cyg_spi_transaction_begin (&loopback_device); + cyg_spi_transaction_transfer (&loopback_device, polled, sizeof (tx_data1), + (const cyg_uint8*) NULL, NULL, true); + cyg_spi_transaction_end (&loopback_device); + diag_printf (" Tx data 41 (%u Bytes): %s\n", sizeof(tx_data1), tx_data1); + diag_printf (" Rx data 1 : %s\n", rx_data1); + diag_printf (" Tx data 42 (%u Bytes): %s\n", sizeof(tx_data2), tx_data2); + diag_printf (" Rx data 2 : %s\n", rx_data2); + + if (memcmp (rx_data1, rx_data2, sizeof (tx_data1)) != 0) { + errors++; + diag_printf("Simple transfer loopback failed - mismatched data.\n"); + errors++; + } +} + + +//--------------------------------------------------------------------------- +// Run all SPI interface loopback tests. + + +void run_tests (void) +{ + bool polled = true; + diag_printf ("Running Freescale Kinetis/MPC5xxx DSPI driver loopback tests.\n"); + + diag_printf ("\nPolled\n"); + run_test_tick (polled, 1024); + run_test_1 (polled, &tx_data0[3], 4); + run_test_2 (polled); + run_test_3 (polled); + run_test_4 (polled); + + polled = false; + diag_printf ("\nInterrupt driven.\n"); + run_test_tick (polled,2048); + run_test_1 (polled, &tx_data0[7], 10); + run_test_2 (polled); + run_test_3 (polled); + run_test_4 (polled); + + if(errors) + CYG_TEST_FAIL("Errors detected"); + else + CYG_TEST_PASS_FINISH ("Loopback tests ran OK"); +} + +//--------------------------------------------------------------------------- +// User startup - tests are run in their own thread. + +void cyg_user_start(void) +{ + CYG_TEST_INIT(); + cyg_thread_create( + 10, // Arbitrary priority + (cyg_thread_entry_t*) run_tests, // Thread entry point + 0, // + "test_thread", // Thread name + &stack[0], // Stack + CYGNUM_HAL_STACK_SIZE_TYPICAL, // Stack size + &thread_handle, // Thread handle + &thread_data // Thread data structure + ); + cyg_thread_resume(thread_handle); + cyg_scheduler_start(); +} + +//============================================================================= |