changeset 3196:c766accdd9a1

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. Add looback test.
author vae
date Thu, 03 Jan 2013 08:49:26 +0000
parents 6877414b6275
children 376086cd0778
files packages/devs/spi/freescale/dspi/current/ChangeLog packages/devs/spi/freescale/dspi/current/cdl/spi_freescale_dspi.cdl packages/devs/spi/freescale/dspi/current/src/spi_freescale_dspi.c packages/devs/spi/freescale/dspi/current/tests/spi_loopback.c
diffstat 4 files changed, 364 insertions(+), 164 deletions(-) [+]
line wrap: on
line diff
--- a/packages/devs/spi/freescale/dspi/current/ChangeLog
+++ b/packages/devs/spi/freescale/dspi/current/ChangeLog
@@ -1,3 +1,13 @@
+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: 
--- a/packages/devs/spi/freescale/dspi/current/cdl/spi_freescale_dspi.cdl
+++ b/packages/devs/spi/freescale/dspi/current/cdl/spi_freescale_dspi.cdl
@@ -64,7 +64,8 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
     cdl_option CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE {
         display "DSPI FIFO size"
         flavor data
-        calculated 4
+        default_value 4
+        legal_values { 4 5 6 7 8 }
     }
 
     cdl_component CYGHWR_DEVS_SPI_FREESCALE_DSPI_CTAR_NUM {
@@ -117,6 +118,7 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
     for { set ::spibus 0 } { $::spibus < 3 } { 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] {
@@ -124,7 +126,6 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
             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
@@ -142,141 +143,24 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
                         implies CYGHWR_FREESCALE_DSPI[set ::spibus]_CS5 == 0
                 }
 
-                cdl_interface CYGINT_FREESCALE_DSPI[set ::spibus]_CS0 {
-                    description "
-                        Number of devices selected by CS0.
-                        May be be 0 or 1"
-                }
-
-                cdl_component CYGHWR_FREESCALE_DSPI[set ::spibus]_CS0 {
-                    display "CS0"
-                    flavor bool
-                    calculated CYGINT_FREESCALE_DSPI[set ::spibus]_CS0
-                    active_if CYGINT_FREESCALE_DSPI[set ::spibus]_CS0
-
-                    requires CYGINT_FREESCALE_DSPI[set ::spibus]_CS0 == 1
-
-                    cdl_option CYGHWR_FREESCALE_DSPI[set ::spibus]_CS0_IS {
-                        display "CS0 Inactive state Hi(1) Lo(0)"
-                        flavor data
-                        no_define
-                        default_value { 1 }
-                        legal_values { 0 1 }
-                    }
-                }
-
-                cdl_interface CYGINT_FREESCALE_DSPI[set ::spibus]_CS1 {
-                    description "
-                        Number of devices selected by CS1.
-                        May be be 0 or 1"
-                }
-
-                cdl_component CYGHWR_FREESCALE_DSPI[set ::spibus]_CS1 {
-                    display "CS1"
-                    flavor bool
-                    calculated CYGINT_FREESCALE_DSPI[set ::spibus]_CS1
-                    active_if CYGINT_FREESCALE_DSPI[set ::spibus]_CS1
-
-                    requires CYGINT_FREESCALE_DSPI[set ::spibus]_CS1 == 1
-
-                    cdl_option CYGHWR_FREESCALE_DSPI[set ::spibus]_CS1_IS {
-                        display "CS1 Inactive state Hi(1) Lo(0)"
-                        flavor data
-                        no_define
-                        default_value { 1 }
-                        legal_values { 0 1 }
-                    }
-                }
-
-                cdl_interface CYGINT_FREESCALE_DSPI[set ::spibus]_CS2 {
-                    description "
-                        Number of devices selected by CS2.
-                        May be be 0 or 1"
-                }
-
-                cdl_component CYGHWR_FREESCALE_DSPI[set ::spibus]_CS2 {
-                    display "CS2"
-                    flavor bool
-                    calculated CYGINT_FREESCALE_DSPI[set ::spibus]_CS2
-                    active_if CYGINT_FREESCALE_DSPI[set ::spibus]_CS2
-
-                    requires CYGINT_FREESCALE_DSPI[set ::spibus]_CS2 == 1
-
-                    cdl_option CYGHWR_FREESCALE_DSPI[set ::spibus]_CS2_IS {
-                        display "CS2 Inactive state Hi(1) Lo(0)"
-                        flavor data
-                        no_define
-                        default_value { 1 }
-                        legal_values { 0 1 }
+                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_interface CYGINT_FREESCALE_DSPI[set ::spibus]_CS3 {
-                    description "
-                        Number of devices selected by CS3.
-                        May be be 0 or 1"
-                }
-
-                cdl_component CYGHWR_FREESCALE_DSPI[set ::spibus]_CS3 {
-                    display "CS3"
-                    flavor bool
-                    calculated CYGINT_FREESCALE_DSPI[set ::spibus]_CS3
-                    active_if CYGINT_FREESCALE_DSPI[set ::spibus]_CS3
-
-                    requires CYGINT_FREESCALE_DSPI[set ::spibus]_CS3 == 1
-
-                    cdl_option CYGHWR_FREESCALE_DSPI[set ::spibus]_CS3_IS {
-                        display "CS3 Inactive state Hi(1) Lo(0)"
-                        flavor data
-                        no_define
-                        default_value { 1 }
-                        legal_values { 0 1 }
-                    }
-                }
-
-                cdl_interface CYGINT_FREESCALE_DSPI[set ::spibus]_CS4 {
-                    description "
-                        Number of devices selected by CS4.
-                        May be be 0 or 1"
-                }
-
-                cdl_component CYGHWR_FREESCALE_DSPI[set ::spibus]_CS4 {
-                    display "CS4"
-                    flavor bool
-                    calculated CYGINT_FREESCALE_DSPI[set ::spibus]_CS4
-                    active_if CYGINT_FREESCALE_DSPI[set ::spibus]_CS4
-
-                    requires CYGINT_FREESCALE_DSPI[set ::spibus]_CS4 == 1
-
-                    cdl_option CYGHWR_FREESCALE_DSPI[set ::spibus]_CS4_IS {
-                        display "CS4 Inactive state Hi(1) Lo(0)"
-                        flavor data
-                        no_define
-                        default_value { 1 }
-                        legal_values { 0 1 }
-                    }
-                }
-
-                cdl_interface CYGINT_FREESCALE_DSPI[set ::spibus]_CS5 {
-                    description "
-                        Number of devices selected by CS5.
-                        May be be 0 or 1"
-                }
-
-                cdl_component CYGHWR_FREESCALE_DSPI[set ::spibus]_CS5 {
-                    display "CS5"
-                    flavor bool
-                    calculated CYGINT_FREESCALE_DSPI[set ::spibus]_CS5
-                    active_if CYGINT_FREESCALE_DSPI[set ::spibus]_CS5
-
-                    requires CYGINT_FREESCALE_DSPI[set ::spibus]_CS5 == 1
-
-                    cdl_option CYGHWR_FREESCALE_DSPI[set ::spibus]_CS5_IS {
-                        display "CS5 Inactive state Hi(1) Lo(0)"
-                        flavor data
-                        no_define
-                        default_value { 1 }
-                        legal_values { 0 1 }
+                    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 }
+                        }
                     }
                 }
 
@@ -294,20 +178,20 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
             }
 
             cdl_interface CYGINT_FREESCALE_DSPI[set ::spibus]_HAS_MASS {
-                description "SPI bus serves mas data device(s)."
+                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."
+                    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
@@ -326,7 +210,7 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
 
                 active_if CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_PUSHQUE_SIZE > \
                     CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE
-                default_value 6
+                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"
 
@@ -361,7 +245,7 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
                     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"
@@ -375,7 +259,7 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
 
                 active_if CYGNUM_DEVS_SPI_FREESCALE_DSPI[set ::spibus]_PUSHQUE_SIZE > \
                     CYGHWR_DEVS_SPI_FREESCALE_DSPI_FIFO_SIZE
-                default_value 7
+                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"
 
@@ -416,7 +300,17 @@ cdl_package CYGPKG_DEVS_SPI_FREESCALE_DS
         }
     }
 
-cdl_option CYGPKG_DEVS_SPI_FREESCALE_DSPI_DEBUG_LEVEL {
+    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 }
@@ -459,6 +353,14 @@ cdl_option CYGPKG_DEVS_SPI_FREESCALE_DSP
             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
@@ -468,18 +370,10 @@ cdl_option CYGPKG_DEVS_SPI_FREESCALE_DSP
                 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."
-        }
-
-        cdl_option CYGPKG_DEVS_SPI_FREESCALE_DSPI_TESTS {
-            display "Freescale DSPI tests"
-            flavor data
-            no_define
-            calculated { CYGBLD_DEVS_SPI_FREESCALE_DSPI_LOOPBACK_TEST ? "tests/loopback" : "" }
+                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
--- a/packages/devs/spi/freescale/dspi/current/src/spi_freescale_dspi.c
+++ b/packages/devs/spi/freescale/dspi/current/src/spi_freescale_dspi.c
@@ -92,6 +92,7 @@
 
 # define DEBUG0_PRINTF(args...) diag_printf(args)
 
+#define PUSHR_NULL (0xFFFF)
 
 //-----------------------------------------------------------------------------
 // API function call forward references.
@@ -566,6 +567,7 @@ fifo_pushque_fill(cyg_spi_freescale_dspi
             pushr |= data_word;
         }
     } else {
+        pushr |= PUSHR_NULL;
         for(; count > 1; count--) {
             if(!(--txfifo_n)) {
                 dspi_p->pushr = pushr |= FREESCALE_DSPI_PUSHR_EOQ_M;
@@ -639,6 +641,7 @@ dma_pushque_fill(cyg_spi_freescale_dspi_
             pushr |= data_word;
         }
     } else {
+        pushr |= PUSHR_NULL;
         do {
             if(pushque_p == pushque_end) {
                 pushque_p[0] = pushr;
@@ -747,8 +750,15 @@ static void spi_transaction_do (cyg_spi_
     DEBUG2_PRINTF("DSPI: transaction: count=%d drop_cs=%d\n", count, drop_cs);
 
     // Set up peripheral CS field. DSPI automatically asserts and deasserts CS
-    pushr = dspi_chip_select_set(tick_only ? -1 : dspi_device->dev_num,
-                                dspi_p->mcr & FREESCALE_DSPI_MCR_PCSSE_M, true);
+    pushr = dspi_chip_select_set(
+#ifdef CYGOPT_DEVS_SPI_FREESCALE_DSPI_TICK_ONLY_DROPS_CS
+                                 // eCos Reference Manual states that CS should
+                                 // drop prior to send ticks, but other drivers
+                                 // (so far do not) touch the CS.
+                                 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);
@@ -941,7 +951,7 @@ static void dspi_transaction_transfer(cy
 
 //-----------------------------------------------------------------------------
 // Carry out a bus tick operation - this drops chip select then pushes the
-// required number of zeros onto the bus.
+// required number of NULL frames onto the bus.
 
 static void dspi_transaction_tick(cyg_spi_device* device, cyg_bool polled,
                                   cyg_uint32 count)
@@ -960,7 +970,7 @@ static void dspi_transaction_tick(cyg_sp
     }
 
     // Perform null transfer
-    spi_transaction_do (device, true, polled, count, NULL, NULL, true);
+    spi_transaction_do (device, true, polled, count, NULL, NULL, false);
 }
 
 //-----------------------------------------------------------------------------
@@ -985,7 +995,8 @@ static void dspi_transaction_end(cyg_spi
 
     if(dspi_device->chip_sel){
         // Clear peripheral CS by executing a dummy 4 bit transfer.
-        dspi_p->pushr = FREESCALE_DSPI_PUSHR_EOQ_M | FREESCALE_DSPI_PUSHR_CTAS(1);
+        dspi_p->pushr = PUSHR_NULL | FREESCALE_DSPI_PUSHR_EOQ_M |
+                        FREESCALE_DSPI_PUSHR_CTAS(1);
         DSPI_EOQ_CLEAR(dspi_p);
         while(!(dspi_p->sr & FREESCALE_DSPI_SR_EOQF_M));
         dspi_device->chip_sel = 0;
new file mode 100644
--- /dev/null
+++ b/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 Kinetis SPI 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();
+}
+
+//=============================================================================