diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2008-10-15 14:19:46 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2008-10-15 14:19:46 +0000 |
commit | de69e9a67bddcb0f59cce0ca1c0d7277c854261c (patch) | |
tree | b9501dee2adf701e8ab808f4178d7eef69cbbace | |
parent | be95ad8513dc7c1c192ea259cdf9c0a88b526b58 (diff) | |
download | px4-nuttx-de69e9a67bddcb0f59cce0ca1c0d7277c854261c.tar.gz px4-nuttx-de69e9a67bddcb0f59cce0ca1c0d7277c854261c.tar.bz2 px4-nuttx-de69e9a67bddcb0f59cce0ca1c0d7277c854261c.zip |
Add simple SPI-based MMC/SD block driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1043 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r-- | nuttx/ChangeLog | 4 | ||||
-rw-r--r-- | nuttx/Documentation/NuttX.html | 5 | ||||
-rw-r--r-- | nuttx/configs/mcu123-lpc214x/src/up_spi.c | 125 | ||||
-rw-r--r-- | nuttx/drivers/Makefile | 15 | ||||
-rw-r--r-- | nuttx/include/nuttx/mmcsd.h | 89 | ||||
-rw-r--r-- | nuttx/include/nuttx/spi.h | 105 |
6 files changed, 216 insertions, 127 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 8d78e3239..420f2e51a 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -502,4 +502,6 @@ * Incorporate patch "[2164503] nuttx-0.3.16 does not build for ARM with USB disabled" * Reduced the amount of memory reserved for USB serial control requests. It was unnecessarily large. - * Add LPC214x SPI1 driver to interface with MMC on mcu123.com board. + * Added LPC214x SPI1 driver to interface with MMC on mcu123.com board. + * Added a simple SPI-based MMC/SD block driver + diff --git a/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html index 26730ef42..ef667163c 100644 --- a/nuttx/Documentation/NuttX.html +++ b/nuttx/Documentation/NuttX.html @@ -8,7 +8,7 @@ <tr align="center" bgcolor="#e4e4e4"> <td> <h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1> - <p>Last Updated: October 11, 2008</p> + <p>Last Updated: October 15, 2008</p> </td> </tr> </table> @@ -1134,7 +1134,8 @@ nuttx-0.3.17 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> * Incorporate patch "[2164503] nuttx-0.3.16 does not build for ARM with USB disabled" * Reduced the amount of memory reserved for USB serial control requests. It was unnecessarily large. - * Add LPC214x SPI1 driver to interface with MMC on mcu123.com board. + * Added LPC214x SPI1 driver to interface with MMC on mcu123.com board. + * Added a simple SPI-based MMC/SD block driver pascal-0.1.3 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/nuttx/configs/mcu123-lpc214x/src/up_spi.c b/nuttx/configs/mcu123-lpc214x/src/up_spi.c index a9bf42246..67323eeb3 100644 --- a/nuttx/configs/mcu123-lpc214x/src/up_spi.c +++ b/nuttx/configs/mcu123-lpc214x/src/up_spi.c @@ -87,13 +87,12 @@ * Private Function Prototypes ****************************************************************************/ -static void spi_select(boolean select); -static uint32 spi_setfrequency(uint32 frequency); -static ubyte spi_status(void); -static void spi_sndbyte(ubyte ch); -static int spi_waitready(void); -static void spi_sndblock(FAR const ubyte *data, int datlen); -static void spi_recvblock(FAR ubyte *data, int datlen); +static void spi_select(FAR struct spi_dev_s *dev, boolean selected); +static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency); +static ubyte spi_status(FAR struct spi_dev_s *dev); +static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch); +static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen); +static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen); /**************************************************************************** * Private Data @@ -105,11 +104,12 @@ static const struct spi_ops_s g_spiops = .setfrequency = spi_setfrequency, .status = spi_status, .sndbyte = spi_sndbyte, - .waitready = spi_waitready, .sndblock = spi_sndblock, .recvblock = spi_recvblock, }; +static struct spi_dev_s g_spidev = { &g_spiops }; + /**************************************************************************** * Public Data ****************************************************************************/ @@ -125,18 +125,18 @@ static const struct spi_ops_s g_spiops = * Enable/disable the SPI chip select * * Input Parameters: - * select: TRUE: chip selected, FALSE: chip de-selected + * selected: TRUE: chip selected, FALSE: chip de-selected * * Returned Value: * None * ****************************************************************************/ -void spi_select(boolean select) +void spi_select(FAR struct spi_dev_s *dev, boolean selected) { uint32 bit = 1 << 20; - if (select) + if (selected) { /* Enable chip select (low enables) */ @@ -180,7 +180,7 @@ void spi_select(boolean select) * ****************************************************************************/ -uint32 spi_setfrequency(uint32 frequency) +uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency) { uint32 divisor = LPC214X_PCLKFREQ / frequency; @@ -212,7 +212,7 @@ uint32 spi_setfrequency(uint32 frequency) * ****************************************************************************/ -ubyte spi_status(void) +ubyte spi_status(FAR struct spi_dev_s *dev) { /* I don't think there is anyway to determine these things on the mcu123.com * board. @@ -231,17 +231,17 @@ ubyte spi_status(void) * ch - the byte to send * * Returned Value: - * None + * response * ****************************************************************************/ -void spi_sndbyte(ubyte ch) +ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch) { /* Wait while the TX FIFO is full */ while (!(getreg8(LPC214X_SPI1_SR) & LPC214X_SPI1SR_TNF)); - /* Send the byte */ + /* Write the byte to the TX FIFO */ putreg16(ch, LPC214X_SPI1_DR); @@ -249,45 +249,9 @@ void spi_sndbyte(ubyte ch) while (!(getreg8(LPC214X_SPI1_SR) & LPC214X_SPI1SR_RNE)); - /* Get the value from the RX FIFO */ - - (void)getreg16(LPC214X_SPI1_DR); -} - -/**************************************************************************** - * Name: spi_waitready - * - * Description: - * Wait for SPI to be ready - * - * Input Parameters: None - * - * Returned Value: - * OK if no error occured; a negated errno otherwise. - * - ****************************************************************************/ - -int spi_waitready(void) -{ - ubyte ret; - - do - { - /* Write 0xff to the data register */ - - putreg16(0xff, LPC214X_SPI1_DR); - - /* Wait until the controller reports RX FIFO not empty */ + /* Get the value from the RX FIFO and return it */ - while (!(getreg8(LPC214X_SPI1_SR) & LPC214X_SPI1SR_RNE)); - - /* Check by reading back the from the RX FIFO */ - - ret = (ubyte)getreg16(LPC214X_SPI1_DR); - } - while (ret != 0xff); - - return OK; + return (ubyte)getreg16(LPC214X_SPI1_DR); } /************************************************************************* @@ -297,39 +261,42 @@ int spi_waitready(void) * Send a block of data on SPI * * Input Parameters: - * data - A pointer to the buffer of data to be sent - * datlen - the length of data to send from the buffer + * buffer - A pointer to the buffer of data to be sent + * buflen - the length of data to send from the buffer * * Returned Value: * None * ****************************************************************************/ -void spi_sndblock(FAR const ubyte *data, int datlen) +void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen) { /* Loop while thre are bytes remaining to be sent */ - while (datlen > 0) + while (buflen > 0) { /* While the TX FIFO is not full and there are bytes left to send */ - while ((getreg8(LPC214X_SPI1_SR) & LPC214X_SPI1SR_TNF) && datlen) + while ((getreg8(LPC214X_SPI1_SR) & LPC214X_SPI1SR_TNF) && buflen) { /* Send the data */ - putreg16((uint16)*data, LPC214X_SPI1_DR); - data++; - datlen--; + putreg16((uint16)*buffer, LPC214X_SPI1_DR); + buffer++; + buflen--; } } - /* Then read from the FIFO while the RX FIFO is not empty or the TX FIFO - * is not empty. + /* Then read from the RX FIFO while the RX FIFO is not empty or the TX FIFO + * is not empty. We should get the same number of bytes in response as were + * sent. */ while ((getreg8(LPC214X_SPI1_SR) & LPC214X_SPI1SR_RNE) || !(getreg8(LPC214X_SPI1_SR) & LPC214X_SPI1SR_TFE)) { + /* Read and discard */ + (void)getreg16(LPC214X_SPI1_DR); } } @@ -341,21 +308,21 @@ void spi_sndblock(FAR const ubyte *data, int datlen) * Revice a block of data from SPI * * Input Parameters: - * data - A pointer to the buffer in which to recieve data - * datlen - the length of data that can be received in the buffer + * buffer - A pointer to the buffer in which to recieve data + * buflen - the length of data that can be received in the buffer * * Returned Value: * None * ****************************************************************************/ -static void spi_recvblock(FAR ubyte *data, int datlen) +static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen) { uint32 fifobytes = 0; - /* While there is remaining to be sent (and no error has occurred */ + /* While there is remaining to be sent (and no synchronization error has occurred) */ - while (datlen || fifobytes) + while (buflen || fifobytes) { /* Fill the transmit FIFO with 0xff... * Write 0xff to the data register while (1) the TX FIFO is @@ -364,19 +331,19 @@ static void spi_recvblock(FAR ubyte *data, int datlen) */ while ((getreg8(LPC214X_SPI1_SR) & LPC214X_SPI1SR_TNF) && - (fifobytes < LPC214X_SPI1_FIFOSZ) && datlen) + (fifobytes < LPC214X_SPI1_FIFOSZ) && buflen) { putreg16(0xff, LPC214X_SPI1_DR); - --datlen; - ++fifobytes; + buflen--; + fifobytes++; } - /* Now, read the RX data from the FIFO while the RX FIFO is not empty */ + /* Now, read the RX data from the RX FIFO while the RX FIFO is not empty */ while (getreg8(LPC214X_SPI1_SR) & LPC214X_SPI1SR_RNE) { - *data++ = (ubyte)getreg16(LPC214X_SPI1_DR); - --fifobytes; + *buffer++ = (ubyte)getreg16(LPC214X_SPI1_DR); + fifobytes--; } } } @@ -395,11 +362,11 @@ static void spi_recvblock(FAR ubyte *data, int datlen) * Port number (for hardware that has mutiple SPI interfaces) * * Returned Value: - * Valid vtable pointer on succcess; NULL on failure + * Valid SPI device structre reference on succcess; a NULL on failure * ****************************************************************************/ -FAR const struct spi_ops_s *up_spiinitialize(int port) +FAR struct spi_dev_s *up_spiinitialize(int port) { uint32 regval32; ubyte regval8; @@ -453,7 +420,7 @@ FAR const struct spi_ops_s *up_spiinitialize(int port) /* Set the initial clock frequency for indentification mode < 400kHz */ - spi_setfrequency(400000); + spi_setfrequency(NULL, 400000); /* Enable the SPI */ @@ -465,5 +432,5 @@ FAR const struct spi_ops_s *up_spiinitialize(int port) (void)getreg16(LPC214X_SPI1_DR); } - return &g_spiops; + return &g_spidev; } diff --git a/nuttx/drivers/Makefile b/nuttx/drivers/Makefile index a132365d3..846a4208b 100644 --- a/nuttx/drivers/Makefile +++ b/nuttx/drivers/Makefile @@ -47,7 +47,13 @@ ROOTDEPPATH = --dep-path . USBDEVDEPPATH = --dep-path usbdev endif -ASRCS = $(NET_ASRCS) $(USBDEV_ASRCS) +ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y) +include mmcsd/Make.defs +ROOTDEPPATH = --dep-path . +MMCSDDEPPATH = --dep-path mmcsd +endif + +ASRCS = $(NET_ASRCS) $(USBDEV_ASRCS) $(MMCSD_ASRCS) AOBJS = $(ASRCS:.S=$(OBJEXT)) CSRCS = @@ -58,7 +64,7 @@ ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y) CSRCS += ramdisk.c endif endif -CSRCS += $(NET_CSRCS) $(USBDEV_CSRCS) +CSRCS += $(NET_CSRCS) $(USBDEV_CSRCS) $(MMCSD_CSRCS) COBJS = $(CSRCS:.c=$(OBJEXT)) SRCS = $(ASRCS) $(CSRCS) @@ -66,7 +72,7 @@ OBJS = $(AOBJS) $(COBJS) BIN = libdrivers$(LIBEXT) -VPATH = net:usbdev +VPATH = net:usbdev:mmcsd all: $(BIN) @@ -82,7 +88,8 @@ $(BIN): $(OBJS) done ; ) .depend: Makefile $(SRCS) - @$(MKDEP) $(ROOTDEPPATH) $(NETDEPPATH) $(USBDEVDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @$(MKDEP) $(ROOTDEPPATH) $(NETDEPPATH) $(USBDEVDEPPATH) $(MMCSDDEPPATH) \ + $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep @touch $@ depend: .depend diff --git a/nuttx/include/nuttx/mmcsd.h b/nuttx/include/nuttx/mmcsd.h new file mode 100644 index 000000000..ea41290c0 --- /dev/null +++ b/nuttx/include/nuttx/mmcsd.h @@ -0,0 +1,89 @@ +/**************************************************************************** + * include/nuttx/mmcsd.h + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * 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 __NUTTX_MMCSD_H +#define __NUTTX_MMCSD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <sys/types.h> + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: mmcsd_spislotinitialize + * + * Description: + * Initialize one slot for operation using the SPI MMC/SD interface + * + * Input Parameters: + * minor - The MMC/SD minor device number. The MMC/SD device will be + * registered as /dev/mmcsdN where N is the minor number + * slotno - The slot number to use. This is only meaningful for architectures + * that support multiple MMC/SD slots. This value must be in the range + * {0, ..., CONFIG_MMCSD_NSLOTS}. + * spi - And instance of an SPI interface obtained by called + * up_spiinitialize() with the appropriate port number (see spi.h) + * + ****************************************************************************/ + +EXTERN int mmcsd_spislotinitialize(int minor, int slotno, FAR struct spi_dev_s *spi); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __NUTTX_MMCSD_H */ diff --git a/nuttx/include/nuttx/spi.h b/nuttx/include/nuttx/spi.h index fbcee72e8..3fe9131c4 100644 --- a/nuttx/include/nuttx/spi.h +++ b/nuttx/include/nuttx/spi.h @@ -50,10 +50,10 @@ /* Access macros */ /**************************************************************************** - * Name:SPI_SELECT + * Name: SPI_SELECT * * Description: - * Enable/disable the SPI chip select + * Enable/disable the SPI chip select. Required. * * Input Parameters: * select: TRUE: chip selected, FALSE: chip de-selected @@ -63,13 +63,13 @@ * ****************************************************************************/ -#define SPI_SELECT(s,b) ((s)->select(b)) +#define SPI_SELECT(d,b) ((d)->ops->select(d,b)) /**************************************************************************** * Name: SPI_SETFREQUENCY * * Description: - * Set the SPI frequency. + * Set the SPI frequency. Required. * * Input Parameters: * frequency: The SPI frequency requested @@ -79,13 +79,13 @@ * ****************************************************************************/ -#define SPI_SETFREQUENCY(s,f) ((s)->setfrequency(f)) +#define SPI_SETFREQUENCY(d,f) ((d)->ops->setfrequency(d,f)) /**************************************************************************** * Name: SPI_STATUS * * Description: - * Get SPI/MMC status + * Get SPI/MMC status. Optional. * * Input Parameters: * None @@ -95,13 +95,21 @@ * ****************************************************************************/ -#define SPI_STATUS(s) ((s)->status()) +#define SPI_STATUS(d) \ + ((d)->ops->status ? (d)->ops->status(d) : SPI_STATUS_PRESENT) + +/* SPI status bits -- Some dedicated for SPI MMC/SD support and may have no + * relationship to SPI other than needed by the SPI MMC/SD interface + */ + +#define SPI_STATUS_PRESENT 0x01 /* Bit 0=1: MMC/SD card present */ +#define SPI_STATUS_WRPROTECTED 0x02 /* Bit 1=1: MMC/SD card write protected */ /**************************************************************************** * Name: SPI_SNDBYTE * * Description: - * Send one byte on SPI + * Send one byte on SPI. Required. * * Input Parameters: * ch - the byte to send @@ -111,77 +119,92 @@ * ****************************************************************************/ -#define SPI_SNDBYTE(s,ch) ((s)->sndbyte(ch)) +#define SPI_SNDBYTE(d,ch) ((d)->ops->sndbyte(d,ch)) /**************************************************************************** - * Name: SPI_WAITREADY + * Name: SPI_SNDBLOCK * * Description: - * Wait for SPI to be ready + * Send a block of data on SPI. Required. * - * Input Parameters: None + * Input Parameters: + * buffer - A pointer to the buffer of data to be sent + * buflen - the length of data to send from the buffer * * Returned Value: - * OK if no error occured; a negated errno otherwise. + * None * ****************************************************************************/ -#define SPI_WAITREADY(s) ((s)->waitready()) +#define SPI_SNDBLOCK(d,b,l) ((d)->ops->sndblock(d,b,l)) /**************************************************************************** - * Name: SPI_SNDBLOCK + * Name: SPI_RECVBLOCK * * Description: - * Send a block of data on SPI + * Revice a block of data from SPI. Required. * * Input Parameters: - * data - A pointer to the buffer of data to be sent - * datlen - the length of data to send from the buffer + * buffer - A pointer to the buffer in which to recieve data + * buflen - the length of data that can be received in the buffer * * Returned Value: * None * ****************************************************************************/ -#define SPI_SNDBLOCK(s,d,l) ((s)->sndblock(d,l)) +#define SPI_RECVBLOCK(d,b,l) ((d)->ops->recvblock(d,b,l)) /**************************************************************************** - * Name: SPI_RECVBLOCK + * Name: SPI_REGISTERCALLBACK * * Description: - * Revice a block of data from SPI + * Register a callback that that will be invoked on any media status + * change (i.e, anything that would be reported differently by SPI_STATUS). + * Optional * * Input Parameters: - * data - A pointer to the buffer in which to recieve data - * datlen - the length of data that can be received in the buffer + * callback - The funtion to call on the media change + * arg - A caller provided value to return with the callback * * Returned Value: - * None + * 0 on success; negated errno on failure. * ****************************************************************************/ -#define SPI_RECVBLOCK(s,d,l) ((s)->recvblock(d,l)) - -/* SPI status bits -- Some dedicated for SPI MMC support and may have not - * relationship to SPI other than needed by the SPI MMC interface - */ - -#define SPI_STATUS_PRESENT 0x01 /* MMC card present */ -#define SPI_STATUS_WRPROTECTED 0x02 /* MMC card write protected */ +#define SPI_REGISTERCALLBACK(d,c,a) \ + ((d)->ops->registercallback ? (d)->ops->registercallback(d,c,a) : -ENOSYS) /**************************************************************************** * Public Types ****************************************************************************/ +/* The type of the media change callback function */ + +typedef void (*mediachange_t)(void *arg); + +/* The SPI vtable */ + +struct spi_dev_s; struct spi_ops_s { - void (*select)(boolean select); - uint32 (*setfrequency)(uint32 frequency); - ubyte (*status)(void); - void (*sndbyte)(ubyte ch); - int (*waitready)(void); - void (*sndblock)(FAR const ubyte *data, int datlen); - void (*recvblock)(FAR ubyte *data, int datlen); + void (*select)(FAR struct spi_dev_s *dev, boolean selected); + uint32 (*setfrequency)(FAR struct spi_dev_s *dev, uint32 frequency); + ubyte (*status)(FAR struct spi_dev_s *dev); + ubyte (*sndbyte)(FAR struct spi_dev_s *dev, ubyte ch); + void (*sndblock)(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen); + void (*recvblock)(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen); + int (*registercallback)(FAR struct spi_dev_s *dev, mediachange_t callback, void *arg); +}; + +/* SPI private data. This structure only defines the initial fields of the + * structure visible to the SPI client. The specific implementation may + * add additional, device specific fields + */ + +struct spi_dev_s +{ + struct spi_ops_s *ops; }; /**************************************************************************** @@ -206,11 +229,11 @@ extern "C" { * Port number (for hardware that has mutiple SPI interfaces) * * Returned Value: - * Valid vtable pointer on succcess; a NULL on failure + * Valid SPI device structre reference on succcess; a NULL on failure * ****************************************************************************/ -EXTERN FAR const struct spi_ops_s *up_spiinitialize(int port); +EXTERN FAR struct spi_dev_s *up_spiinitialize(int port); #undef EXTERN #if defined(__cplusplus) |