Add a general bit-bang SPI upper-half driver

This commit is contained in:
Gregory Nutt 2013-07-01 12:23:26 -06:00
parent 09faaccc02
commit 8b68ea2f94
11 changed files with 934 additions and 23 deletions

View file

@ -5096,4 +5096,7 @@
SPI-related files. includes/nuttx/spi.h moved to include/nuttx/spi/.;
SPI-related Kconfig info moved from drivers/Kconfig to drivers/spi/kconfig
(2013-7-1).
* drivers/spi/spi_bitbang.c and include/nuttx/spi/spi_bitbang.h: Add
support for a generic bit-bang SPI driver. This checkout is the
common upper-half logic. Still missing the lower half (2013-7-1).

View file

@ -4,4 +4,13 @@
#
if ARCH_BOARD_ARDUINO_DUE
config ARDUINO_ITHEAD_TFT
bool "ITEAD 2.4 inch TFT w/Touch"
default n
---help---
Select this option if you have the ITEAD 2.4" TFT module installed.
This will enable support for the peripherals on that module
including the SD card, TFT LCD, and touchscreen controller.
endif

View file

@ -122,19 +122,22 @@ ITEAD 2.4" TFT with Touch
The Arduino 2.4" TFT Touch shield uses the S6D1121 controller , it
supports 8-bit data interface. The touch IC is TSC2046.
Arduino ATSAM3X Due ITHEAD
Due PIN GPIO FUNCTION SIGNAL PIN SIGNAL NOTES
---------- --------------------------- ----------- ----- ---------- ------------------
Arduino ATSAM3X Due ITHEAD
Due PIN GPIO FUNCTION SIGNAL PIN SIGNAL NOTES
---------- ---- ---------------------- ----------- ----- ---------- ------------------
PWMH
10 SCL1 PA18 TWCK0/A20/WKUP9 SCL1 --- --- SCL not available
9 SDA1 PA17 TWD0SPCK0 SDA1 --- --- SDA not available
8 Aref --- --- AREF Vref --- ---
7 GND --- --- GND GND --- ---
6 PWM13 PB27 SPI0_SPCK/A20/WKUP10 PWM13 D13 SD_SCK SCK, also LED "L"
6 PWM13 PB27 SPI0_SPCK/A20/WKUP10 PWM13 D13 SD_SCK SCK, also LED "L", Pulled low on-board
5 PWM12 PD8 A21/NANDALE/TIOB8 PWM12 D12 SD_MISO MISO not available
4 PWM11 PD7 A17/BA1/TIOA8 PWM11 D11 SD_MOSI MOSI not available
3 PWM10 ??? ??? SS0/PWM10 D10 SD_CS ???
2 PWM9 PC21 A0/NBS0/PWML4 PWM9 D9 Touch_IRQ ---
1 PWM8 PC22 A1/PWML5 PWM8 D8 Touch_Dout ---
4 PWM11 PD7 A17/BA1/TIOA8 PWM11 D11 SD_MOSI MOSI not available, Pulled low on-board
3 PWM10 ??? ??? SS0/PWM10 D10 SD_CS Pulled low on-board
2 PWM9 PC21 A0/NBS0/PWML4 PWM9 D9 Touch_Dout ---
1 PWM8 PC22 A1/PWML5 PWM8 D8 Touch_IRQ ---
PWML
8 PWM7 PC23 A2/PWML6 PWM7 D7 DB15 ---
7 PWM6 PC24 A3/PWML7 PWM6 D6 DB14 ---
@ -144,7 +147,7 @@ ITEAD 2.4" TFT with Touch
3 PWM2 PB25 RTS0/TIOA0 PWM2 D2 DB10 ---
2 PWM1 PA9 UTXD/PWMH3 TX D1 DB9 UART0 TX
1 PWM0 PA8 URXD/PWMH0/WKUP4 RX D0 DB8 UART0 RX
---------- ---- ---------------------- ----------- ----- ---------- ------------------
POWER
1 --- --- --- --- --- --- ---
2 IOref --- --- IOREF +3V3 --- --- ---
@ -163,14 +166,15 @@ ITEAD 2.4" TFT with Touch
6 A5 PA4 TCLK1/NWAIT/AD2 AD5 A5 TFT_RS ---
7 A6 PA3 TIOB1/PWMFI1/AD1/WKUP1 AD6 --- --- ---
8 A7 PA2 TIOA1/NANDRDY/AD0 AD7 --- --- ---
---------- ---- ---------------------- ----------- ----- ---------- ------------------
NOTE:
NOTES:
1. It is not possible to use any of the SPI devices on the Shield unless
a bit-bang SPI interface is used. This includes the touch controller
and the SD card.
2. UART0 cannot be used
3. Parallel data is not contiguous in any PIO register
2. UART0 cannot be used. USARTs on the COMM connector should be available.
3. Parallel data is not contiguous in the PIO register
4. 3.3V and 5V are reversed.
Development Environment

View file

@ -245,6 +245,7 @@ CONFIG_NSH_MMCSDMINOR=0
#
# Board-Specific Options
#
# CONFIG_ARDUINO_ITHEAD_TFT is not set
#
# RTOS Features

View file

@ -52,6 +52,23 @@ else
CSRCS += sam_userleds.c
endif
ifeq ($(CONFIG_ARDUINO_ITHEAD_TFT),y)
ifeq ($(CONFIG_SPI_BITBANG),y)
ifeq ($(CONFIG_MMC_SPI),y)
CSRCS += sam_mmcsd.c
endif
ifeq ($(CONFIG_INPUT),y)
CSRCS += sam_touchscreen.c
endif
endif
ifeq ($(CONFIG_LCD),y)
CSRCS += sam_lcd.c
endif
endif
COBJS = $(CSRCS:.c=$(OBJEXT))
SRCS = $(ASRCS) $(CSRCS)

View file

@ -97,6 +97,163 @@
#define GPIO_LED_TX (GPIO_OUTPUT | GPIO_CFG_PULLUP | GPIO_OUTPUT_SET | \
GPIO_PORT_PIOA | GPIO_PIN21)
/* ITEAD 2.4" TFT with Touch
*
* The Arduino 2.4" TFT Touch Shield is designed for all the Arduino
* compatible boards. It works in 3.3V voltage level. It can be directly
* plugged on the Arduino and other compatible boards. It will offer
* display, touch and storage functions for the Arduino board
*
* Features:
*
* 1. Compatible with 3.3/5V operation voltage level
* 2. Compatible with UTFT library
* 3. With SD Card Socket
*
* The Arduino 2.4" TFT Touch shield uses the S6D1121 controller , it
* supports 8-bit data interface. The touch IC is TSC2046.
*
* ---------- --------------------------- ----------- ----- ---------- ------------------
* Arduino ATSAM3X Due ITHEAD
* Due PIN GPIO FUNCTION SIGNAL PIN SIGNAL NOTES
* ---------- ---- ---------------------- ----------- ----- ---------- ------------------
* PWMH
* 10 SCL1 PA18 TWCK0/A20/WKUP9 SCL1 --- --- SCL not available
* 9 SDA1 PA17 TWD0SPCK0 SDA1 --- --- SDA not available
* 8 Aref --- --- AREF Vref --- ---
* 7 GND --- --- GND GND --- ---
* 6 PWM13 PB27 SPI0_SPCK/A20/WKUP10 PWM13 D13 SD_SCK SCK, also LED "L", Pulled low on-board
* 5 PWM12 PD8 A21/NANDALE/TIOB8 PWM12 D12 SD_MISO MISO not available
* 4 PWM11 PD7 A17/BA1/TIOA8 PWM11 D11 SD_MOSI MOSI not available, Pulled low on-board
* 3 PWM10 ??? ??? SS0/PWM10 D10 SD_CS Pulled low on-board
* 2 PWM9 PC21 A0/NBS0/PWML4 PWM9 D9 Touch_Dout ---
* 1 PWM8 PC22 A1/PWML5 PWM8 D8 Touch_IRQ ---
* PWML
* 8 PWM7 PC23 A2/PWML6 PWM7 D7 DB15 ---
* 7 PWM6 PC24 A3/PWML7 PWM6 D6 DB14 ---
* 6 PWM5 PC25 A4/TIOA6 PWM5 D5 DB13 ---
* 5 PWM4 PC26 A5/TIOB6 SS1/PWM4 D4 DB12 ---
* 4 PWM3 PC28 A7/TIOA7 PWM3 D3 DB11 ---
* 3 PWM2 PB25 RTS0/TIOA0 PWM2 D2 DB10 ---
* 2 PWM1 PA9 UTXD/PWMH3 TX D1 DB9 UART0 TX
* 1 PWM0 PA8 URXD/PWMH0/WKUP4 RX D0 DB8 UART0 RX
* ---------- ---- ---------------------- ----------- ----- ---------- ------------------
* POWER
* 1 --- --- --- --- --- --- ---
* 2 IOref --- --- IOREF +3V3 --- --- ---
* 3 RESET --- --- MASTER_RESET RST --- ---
* 4 3.3V --- --- +3V3 5V --- ---
* 5 5V --- --- +5V 3.3V --- ---
* 6 GND --- --- GND GND --- ---
* 7 GND --- --- GND GND --- ---
* 8 Vin --- --- VIN Vin --- ---
* ADCL
* 1 A0 PA16 SPCK1/TD/AD7 AD0 A0 Touch_Din ---
* 2 A1 PA24 MCDA3/PCK1/AD6 AD1 A1 Touch_CLK ---
* 3 A2 PA23 MCDA2/TCLK4/AD5 AD2 A2 --- ---
* 4 A3 PA22 MCDA1/TCLK3/AD4 AD3 A3 TFT_CS ---
* 5 A4 PA6 TIOB2/NCS0/AD3 AD4 A4 TFT_WR ---
* 6 A5 PA4 TCLK1/NWAIT/AD2 AD5 A5 TFT_RS ---
* 7 A6 PA3 TIOB1/PWMFI1/AD1/WKUP1 AD6 --- --- ---
* 8 A7 PA2 TIOA1/NANDRDY/AD0 AD7 --- --- ---
* ---------- ---- ---------------------- ----------- ----- ---------- ------------------
*
* NOTES:
*
* 1. It is not possible to use any of the SPI devices on the Shield unless
* a bit-bang SPI interface is used. This includes the touch controller
* and the SD card.
* 2. UART0 cannot be used. USARTs on the COMM connector should be available.
* 3. Parallel data is not contiguous in the PIO register
* 4. 3.3V and 5V are reversed.
*/
#ifdef CONFIG_ARDUINO_ITHEAD_TFT
/* In order to use the SD card on the ITEAD shield, you must enable the
* SPI bit-bang driver as well as support for SPI-based MMC/SD cards.
*/
# if defined(CONFIG_SPI_BITBANG) && defined(CONFIG_MMC_SPI)
/* The SD slot shares the pin with LED "L" so LED support must be disabled
* to use the MMC/SD card on the ITEAD shield.
*/
# ifdef CONFIG_ARCH_LEDs
# error LEDs may not be used with the ITEAD SD card
# endif
# define GPIO_SD_SCK (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOB | GPIO_PIN27)
# define GPIO_SD_MISO (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOD | GPIO_PIN8)
# define GPIO_SD_MOSI (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOD | GPIO_PIN7)
# define GPIO_SD_CS (GPIO_OUTPUT | GPIO_CFG_PULLUP | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIO? | GPIO_PIN?)
# endif
/* In order to use the touchscreen on the ITEAD shield, you must enable the
* SPI bit-bang driver and INPUT device support.
*/
# if defined(CONFIG_SPI_BITBANG) && defined(CONFIG_INPUT)
# define GPIO_TSC_SCK (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOA | GPIO_PIN24)
# define GPIO_TSC_MISO (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOC | GPIO_PIN21)
# define GPIO_TSC_MOSI (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOA | GPIO_PIN16)
# define GPIO_TSC_CS (GPIO_OUTPUT | GPIO_CFG_PULLUP | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIO? | GPIO_PIN?)
# define GPIO_TSC_IRQ (GPIO_INPUT | GPIO_CFG_PULLUP | GPIO_INT_BOTHEDGES | \
GPIO_PORT_PIOC | GPIO_PIN22)
# define SAM_TCS_IRQ SAM_IRQ_PC21
# endif
/* Only CONFIG_LCD is expected to enable the TFT LCD */
# ifdef CONFIG_LCD
/* UART0 cannot be used with the LCD because the UART0 pins are used
* by the LCD.
*/
# ifdef CONFIG_SAM34_UART0
# error "UART0 cannot be used with the ITEAD LCD"
# endif
/* Data pins are initially configured but may be switched dynamically to
* either inputs or outputs as needed.
*/
# define GPIO_LCD_D0IN (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOA | GPIO_PIN8)
# define GPIO_LCD_D1IN (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOA | GPIO_PIN9)
# define GPIO_LCD_D2IN (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOB | GPIO_PIN25)
# define GPIO_LCD_D3IN (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOC | GPIO_PIN28)
# define GPIO_LCD_D4IN (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOC | GPIO_PIN26)
# define GPIO_LCD_D5IN (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOC | GPIO_PIN25)
# define GPIO_LCD_D6IN (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOC | GPIO_PIN24)
# define GPIO_LCD_D7IN (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOC | GPIO_PIN23)
# define GPIO_LCD_D7IN (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOC | GPIO_PIN23)
# define GPIO_LCD_CS (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOA | GPIO_PIN22)
# define GPIO_LCD_WR (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOA | GPIO_PIN6)
# define GPIO_LCD_RS (GPIO_OUTPUT | GPIO_CFG_DEFAULT | GPIO_OUTPUT_CLR | \
GPIO_PORT_PIOA | GPIO_PIN4)
# endif
#endif
/************************************************************************************
* Public Types
************************************************************************************/

View file

@ -1,7 +1,7 @@
############################################################################
# drivers/Makefile
#
# Copyright (C) 2007-2012 Gregory Nutt. All rights reserved.
# Copyright (C) 2007-2013 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# Redistribution and use in source and binary forms, with or without
@ -62,6 +62,7 @@ include power$(DELIM)Make.defs
include sensors$(DELIM)Make.defs
include sercomm$(DELIM)Make.defs
include serial$(DELIM)Make.defs
include spi$(DELIM)Make.defs
include syslog$(DELIM)Make.defs
include usbdev$(DELIM)Make.defs
include usbhost$(DELIM)Make.defs

View file

@ -33,7 +33,7 @@
#
############################################################################
# Don't build anything if there is no NX support for input devices
# Don't build anything if there is no support for input devices
ifeq ($(CONFIG_INPUT),y)

View file

@ -3,22 +3,15 @@
# see misc/tools/kconfig-language.txt.
#
config SPI
bool "SPI Driver Support"
default n
---help---
This selection enables selection of common SPI options. This option
should be enabled by all platforms that support SPI interfaces.
See include/nuttx/spi/spi.h for further SPI driver information.
if SPI
config SPI_OWNBUS
bool "SPI single device"
default n
---help---
Set if there is only one active device on the SPI bus. No locking or
SPI configuration will be performed. It is not necessary for clients to
lock, re-configure, etc..
lock, re-configure, etc.
config SPI_EXCHANGE
bool "SPI exchange"
@ -36,5 +29,11 @@ config SPI_CMDDATA
either 9-bit SPI (yech) or 8-bit SPI and a GPIO output that selects
between command and data.
endif
config SPI_BITBANG
bool "SPI bit-bang device"
default n
---help---
Enable support for a generic SPI bit-bang device.
See include/nuttx/spi/spi_bitbang.h for further information.
endif

544
drivers/spi/spi_bitbang.c Executable file
View file

@ -0,0 +1,544 @@
/****************************************************************************
* drivers/spi/spi_bitbang.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdlib.h>
#include <semaphore.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/spi/spi.h>
#include <nuttx/spi/spi_bitbang.h>
#ifdef CONFIG_SPI_BITBANG
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* This file holds the static, device-independ portion of the generica SPI-
* bit-bang driver. The full driver consists of 5 files:
*
* 1. drivers/spi/spi_bitbang.c: This file. This file holds the basic
* SPI driver framework and not perform any direct bit-bang operations.
* Rather, it will could out to board-specific logic to perform the
* low level data transfers.
* 2. include/nuttx/spi/spi_bitbang.h: This header file provides the
* data types and function prototypes needed to utilize the logic in
* this file.
* 3. configs/<board>/src/<file>: The implementation of the low-level
* bit-bang logic resides in some file in the board source directory.
* This board-specific logic includes the bit-bang skeleton logic
* provided in include/nuttx/spi/spi_bitband.c.
* 4. include/nuttx/spi/spi_bitband.c. Despite the .c extension, this
* really an included file. It is used in this way: 1) The board-
* specific logic in configs/<board>/src/<file> provides some definitions
* then 2) includes include/nuttx/spi/spi_bitband.c. That file will
* then use those definitions to implement the low-level bit-bang
* logic. the board-specific logic then calls spi_create_bitbang()
* in this file to instantiate the complete SPI driver.
*
* See include/nuttx/spi/spi_bitband.c for more detailed usage
* information.
*/
/* Debug ********************************************************************/
/* Check if SPI debut is enabled (non-standard.. no support in
* include/debug.h
*/
#ifndef CONFIG_DEBUG
# undef CONFIG_DEBUG_VERBOSE
# undef CONFIG_DEBUG_SPI
#endif
#ifdef CONFIG_DEBUG_SPI
# define spidbg lldbg
# ifdef CONFIG_DEBUG_VERBOSE
# define spivdbg lldbg
# else
# define spivdbg(x...)
# endif
#else
# define spidbg(x...)
# define spivdbg(x...)
#endif
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* SPI methods */
#ifndef CONFIG_SPI_OWNBUS
static int spi_lock(FAR struct spi_dev_s *dev, bool lock);
#endif
static void spi_select(FAR struct spi_dev_s *dev, enum spi_dev_e devid,
bool selected);
static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev,
uint32_t frequency);
static void spi_setmode(FAR struct spi_dev_s *dev,
enum spi_mode_e mode);
static void spi_setbits(FAR struct spi_dev_s *dev, int nbits);
static uint16_t spi_send(FAR struct spi_dev_s *dev, uint16_t ch);
static void spi_exchange(FAR struct spi_dev_s *dev,
FAR const void *txbuffer, FAR void *rxbuffer,
size_t nwords);
static uint8_t spi_status(FAR struct spi_dev_s *dev, enum spi_dev_e devid);
#ifdef CONFIG_SPI_CMDDATA
static int spi_cmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid,
bool cmd);
#endif
#ifndef CONFIG_SPI_EXCHANGE
static void spi_sndblock(FAR struct spi_dev_s *dev,
FAR const void *buffer, size_t nwords);
static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer,
size_t nwords);
#endif
/****************************************************************************
* Private Data
****************************************************************************/
/* SPI driver operations */
static const struct spi_ops_s g_spiops =
{
#ifndef CONFIG_SPI_OWNBUS
.lock = spi_lock,
#endif
.select = spi_select,
.setfrequency = spi_setfrequency,
.setmode = spi_setmode,
.setbits = spi_setbits,
.status = spi_status,
#ifdef CONFIG_SPI_CMDDATA
.cmddata = spi_cmddata,
#endif
.send = spi_send,
#ifdef CONFIG_SPI_EXCHANGE
.exchange = spi_exchange,
#else
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
.registercallback = 0, /* Not implemented */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: spi_lock
*
* Description:
* On SPI busses where there are multiple devices, it will be necessary to
* lock SPI to have exclusive access to the busses for a sequence of
* transfers. The bus should be locked before the chip is selected. After
* locking the SPI bus, the caller should then also call the setfrequency,
* setbits, and setmode methods to make sure that the SPI is properly
* configured for the device. If the SPI buss is being shared, then it
* may have been left in an incompatible state.
*
* Input Parameters:
* dev - Device-specific state data
* lock - true: Lock spi bus, false: unlock SPI bus
*
* Returned Value:
* None
*
****************************************************************************/
#ifndef CONFIG_SPI_OWNBUS
static int spi_lock(FAR struct spi_dev_s *dev, bool lock)
{
FAR struct spi_bitbang_s *priv = (FAR struct spi_bitbang_s *)dev;
spivdbg("lock=%d\n", lock);
if (lock)
{
/* Take the semaphore (perhaps waiting) */
while (sem_wait(&priv->exclsem) != 0)
{
/* The only case that an error should occur here is if the wait was awakened
* by a signal.
*/
ASSERT(errno == EINTR);
}
}
else
{
(void)sem_post(&priv->exclsem);
}
return OK;
}
#endif
/****************************************************************************
* Name: spi_select
*
* Description:
* Set/clear the chip select line for the selected device.
*
* Input Parameters:
* dev - Device-specific state data
* devid - Identifies the device to be selected
* selected - select or de-select device
*
* Returned Value:
* None
*
****************************************************************************/
static void spi_select(FAR struct spi_dev_s *dev, enum spi_dev_e devid,
bool selected)
{
FAR struct spi_bitbang_s *priv = (FAR struct spi_bitbang_s *)dev;
DEBUGASSERT(priv && priv->low->select);
priv->low->select(priv, devid, selected);
}
/****************************************************************************
* Name: spi_setfrequency
*
* Description:
* Set the SPI frequency.
*
* Input Parameters:
* dev - Device-specific state data
* frequency - The SPI frequency requested
*
* Returned Value:
* Returns the actual frequency selected
*
****************************************************************************/
static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency)
{
FAR struct spi_bitbang_s *priv = (FAR struct spi_bitbang_s *)dev;
/* SPI frequency cannot be precisely controlled with a bit-bang interface.
* Freqency corresponds to delay in toggle the SPI clock line: Set high,
* wait, set low, wait, set high, wait, etc.
*
* Here we calcalute the half period of the frequency in nanoseconds (i.e.,
* the amount of time that the clock should remain in the high or low state).
*
* frequency = psec / 1 sec - psec = full period in seconds
* psec = 1 sec / frequency
* hpsec = 1 sec / (2 * frequency) - hpsec = half period in seconds
* hpnsec = 1000000000 / (2 * frequency) - hpnsec = half period in nanoseconds
*/
priv->hpnsec = (1000000000ul + frequency) / (frequency << 2);
return frequency;
}
/****************************************************************************
* Name: spi_setmode
*
* Description:
* Set the SPI mode. Optional. See enum spi_mode_e for mode definitions
*
* Input Parameters:
* dev - Device-specific state data
* mode - The SPI mode requested
*
* Returned Value:
* none
*
****************************************************************************/
static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
{
FAR struct spi_bitbang_s *priv = (FAR struct spi_bitbang_s *)dev;
DEBUGASSERT(priv && priv->low->setmode);
priv->low->setmode(priv, mode);
}
/****************************************************************************
* Name: spi_setbits
*
* Description:
* Set the number if bits per word.
*
* Input Parameters:
* dev - Device-specific state data
* nbits - The number of bits requests
*
* Returned Value:
* none
*
****************************************************************************/
static void spi_setbits(FAR struct spi_dev_s *dev, int nbits)
{
#ifdef CONFIG_SPI_BITBANG_VARWIDTH
FAR struct spi_bitbang_s *priv = (FAR struct spi_bitbang_s *)dev;
spivdbg("nbits=%d\n", nbits);
DEBUGASSERT(priv && nbits > 0);
priv->nbits = nbits;
#else
spivdbg("nbits=%d\n", nbits);
DEBUGASSERT(nbits == 8);
#endif
}
/****************************************************************************
* Name: spi_send
*
* Description:
* Exchange one word on SPI
*
* Input Parameters:
* dev - Device-specific state data
* wd - The word to send. the size of the data is determined by the
* number of bits selected for the SPI interface.
*
* Returned Value:
* response
*
****************************************************************************/
static uint16_t spi_send(FAR struct spi_dev_s *dev, uint16_t wd)
{
FAR struct spi_bitbang_s *priv = (FAR struct spi_bitbang_s *)dev;
DEBUGASSERT(priv && priv->low && priv->low->exchange);
return priv->low->exchange(priv, wd);
}
/****************************************************************************
* Name: spi_exchange
*
* Description:
* Exahange a block of data from SPI. Required.
*
* Input Parameters:
* dev - Device-specific state data
* txbuffer - A pointer to the buffer of data to be sent
* rxbuffer - A pointer to the buffer in which to recieve data
* nwords - the length of data that to be exchanged in units of words.
* The wordsize is determined by the number of bits-per-word
* selected for the SPI interface. If nbits <= 8, the data is
* packed into uint8_t's; if nbits >8, the data is packed into
* uint16_t's
*
* Returned Value:
* None
*
****************************************************************************/
static void spi_exchange(FAR struct spi_dev_s *dev,
FAR const void *txbuffer, FAR void *rxbuffer,
size_t nwords)
{
FAR struct spi_bitbang_s *priv = (FAR struct spi_bitbang_s *)dev;
FAR const uint8_t *src = (FAR const uint8_t *)txbuffer;
FAR uint8_t *dest = (FAR uint8_t *)rxbuffer;
uint16_t dataout;
uint16_t datain;
DEBUGASSERT(priv && priv->low && priv->low->exchange);
/* If there is no data source, send 0xff */
if (!src)
{
dataout = 0xff;
}
/* Exchange each word */
while (nwords-- > 0)
{
/* If there is source data, get the next word from the source */
if (src)
{
dataout = (uint16_t)*src++;
#ifdef CONFIG_SPI_BITBANG_VARWIDTH
if (priv->nbits > 8)
{
#ifdef CONFIG_ENDIAN_BIG
dataout <<= 8;
dataout |= *src++;
#else
dataout |= (uint16_t)(*src++) << 8;
#endif
}
#endif
}
/* Exchange the word of data */
datain = priv->low->exchange(priv, dataout);
/* If there is a data sink, transfer the data to the receive buffer */
if (dest)
{
#ifdef CONFIG_SPI_BITBANG_VARWIDTH
if (priv->nbits > 8)
{
#ifdef CONFIG_ENDIAN_BIG
*dest++ = (uint8_t)(datain >> 8);
*dest++ = (uint8_t)datain;
#else
*dest++ = (uint8_t)datain;
*dest++ = (uint8_t)(datain >> 8);
#endif
}
#else
*dest++ = (uint8_t)datain;
#endif
}
}
}
/***************************************************************************
* Name: spi_sndblock
*
* Description:
* Send a block of data on SPI
*
* Input Parameters:
* dev - Device-specific state data
* buffer - A pointer to the buffer of data to be sent
* nwords - the length of data to send from the buffer in number of words.
* The wordsize is determined by the number of bits-per-word
* selected for the SPI interface. If nbits <= 8, the data is
* packed into uint8_t's; if nbits >8, the data is packed into uint16_t's
*
* Returned Value:
* None
*
****************************************************************************/
#ifndef CONFIG_SPI_EXCHANGE
static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords)
{
/* spi_exchange can do this. */
spi_exchange(dev, buffer, NULL, nwords);
}
#endif
/****************************************************************************
* Name: spi_recvblock
*
* Description:
* Revice a block of data from SPI
*
* Input Parameters:
* dev - Device-specific state data
* buffer - A pointer to the buffer in which to recieve data
* nwords - the length of data that can be received in the buffer in number
* of words. The wordsize is determined by the number of bits-per-word
* selected for the SPI interface. If nbits <= 8, the data is
* packed into uint8_t's; if nbits >8, the data is packed into uint16_t's
*
* Returned Value:
* None
*
****************************************************************************/
#ifndef CONFIG_SPI_EXCHANGE
static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords)
{
/* spi_exchange can do this. */
spi_exchange(dev, NULL, buffer, nwords);
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: spi_create_bitbang
*
* Descripton:
* Create an instance of the SPI bit-bang driver.
*
****************************************************************************/
FAR struct spi_dev_s *spi_create_bitbang(FAR const struct spi_bitbang_ops_s *low)
{
FAR struct spi_bitbang_s *priv;
DEBUGASSERT(low);
/* Allocate an instance of the SPI bit bang structure */
priv = (FAR struct spi_bitbang_s *)zalloc(sizeof(struct spi_bitbang_s));
if (!priv)
{
spidbg("Failed to allocate the device structure\n");
return NULL;
}
/* Initialize the driver structure */
priv->dev.ops = &g_spiops;
priv->low = low;
#ifdef CONFIG_SPI_BITBANG_VARWIDTH
priv->nbits = 8;
#endif
/* Select an initial state of mode 0, 8-bits, and 400KHz */
low->setmode(priv, SPIDEV_MODE0);
spi_setfrequency(&priv->dev, 400000);
/* And return the initialized driver structure */
return &priv->dev;
}
#endif /* CONFIG_SPI_BITBANG */

176
include/nuttx/spi/spi_bitbang.h Executable file
View file

@ -0,0 +1,176 @@
/****************************************************************************
* include/nuttx/spi/spi_bitbang.h
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_SPI_SPI_BITBANG_H
#define __INCLUDE_NUTTX_SPI_SPI_BITBANG_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/spi/spi.h>
#ifdef CONFIG_SPI_BITBANG
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
#ifndef SPI_BITBANG_MODE <<< NOOOO.. Needs to be programmable
# define SPI_BITBANG_MODE SPI_MODE0
#endif
#ifndef CONFIG_SPI_BITBANG_FREQUENCY <<< NOOOO.. Needs to be programmable
# define CONFIG_SPI_BITBANG_FREQUENCY 1000000
#endif
/* Debug ********************************************************************/
/* Check if SPI debut is enabled (non-standard.. no support in
* include/debug.h
*/
#ifndef CONFIG_DEBUG
# undef CONFIG_DEBUG_VERBOSE
# undef CONFIG_DEBUG_SPI
#endif
#ifdef CONFIG_DEBUG_SPI
# define spidbg lldbg
# ifdef CONFIG_DEBUG_VERBOSE
# define spivdbg lldbg
# else
# define spivdbg(x...)
# endif
#else
# define spidbg(x...)
# define spivdbg(x...)
#endif
/****************************************************************************
* Private Types
****************************************************************************/
#ifndef __ASSEMBLY__
/* These are the lower-half handlers that perform the level-level, platform-
* specific bit-bang operations.
*/
struct spi_bitbang_s; /* Forward reference */
struct spi_bitbang_ops_s
{
/* Platform specific chip select logic */
void (*select)(FAR struct spi_bitbang_s *priv, enum spi_dev_e devid,
bool selected);
/* Platform-specific, SPI mode function */
void (*setmode)(FAR struct spi_bitbang_s *priv, enum spi_mode_e mode);
/* Platform-specific word exchange function */
uint16_t (*exchange)(FAR struct spi_bitbang_s *priv, uint16_t dataout);
/* Platform-specific word exchange function */
uint8_t (*status)(FAR struct spi_bitbang_s *priv, enum spi_dev_e devid);
#ifdef CONFIG_SPI_CMDDATA
/* Platform-specific CMD/DATA function */
int (*cmddata)(FAR struct spi_bitbang_s *priv, enum spi_dev_e devid,
bool cmd);
#endif
};
/* This structure provides the state of the SPI bit-bang driver */
struct spi_bitbang_s
{
struct spi_dev_s dev; /* Publicly visible version of SPI driver */
FAR const struct spi_bitbang_ops_s *low; /* Low-level operations */
uint32_t hpnsec; /* Number of microseconds in a half cycle */
#ifndef CONFIG_SPI_OWNBUS
sem_t exclsem; /* Supports mutually exclusive access to SPI */
#endif
#ifdef CONFIG_SPI_BITBANG_VARWIDTH
uint8_t nbits; /* Number of bits in the transfer */
#endif
FAR void *priv; /* For use by the lower half driver */
};
/****************************************************************************
* Public Data
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: spi_create_bitbang
*
* Descripton:
* Create an instance of the SPI bit-bang driver.
*
* Input Parameters:
* low - Low-level, platform specific device operations.
*
* Returned Value:
* On success a non-NULL, initialized SPI driver instance is returned.
*
****************************************************************************/
FAR struct spi_dev_s *spi_create_bitbang(FAR const struct spi_bitbang_ops_s *low);
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_SPI_BITBANG */
#endif /* __INCLUDE_NUTTX_SPI_SPI_BITBANG_H */