CubeMX: SPI4 + SDMMC1/FatFs + I2S6, audio BSP et debug VS Code (Linux)

Regeneration CubeMX (Appli) preparant le driver ST67W611M1 et la carte SD :
- SPI4 (PE12/13/14, CS PF8) + DMA GPDMA1 canaux 4/5, SPI_RDY (PD12/EXTI12),
  CHIP_EN (PD13) et BOOT (PD15) pour la X-NUCLEO-67W61M1 sur l'Arduino
- SDMMC1 + FatFs (appels d'init non generes dans main, IRQ SDMMC1 prio 14),
  PM14 en open-drain ; I2S6_CK sur PA5 pour liberer PC12 (SDMMC1_CK)
- HAL UART retire ; USE_BSP_COM_FEATURE=0
- Audio preserve : ADF 4/16/24, prio IRQ 2, DMA canal 0 en priorite haute,
  GPDMA1_Channel2_IRQHandler deplace dans audio_irq.c (hors fichiers generes),
  BSP_MX_I2S6_Init (renommage dans le BSP pour eviter le conflit avec CubeMX)
- Middlewares/ST/ST67W6X_Network_Driver, FatFs et sources HAL SPI/SD ajoutes
  (driver ST67 pas encore integre au build)

Build et debug sous Linux :
- gcc/toolchain-env.sh, gdbserver.sh, arm-gdb.sh : outils de STM32CubeIDE par
  glob ; flash.sh les retrouve ; ruby_compat.rb pour Ruby >= 3.2 (TouchGFX)
- makefile_appli : sources SD/SPI/FatFs/audio_irq ; chmod +x des .out TouchGFX
- Objets de build (*.o, *.d, *.su) retires de l'index (deja dans .gitignore)
- AGENTS.md : toolchain Linux, configs VS Code (cppdbg et ST stlinkgdbtarget),
  pieges de l'extension ST (.settings/ide.store.json, preRunCommands reset)

Verifie sur carte : audio OK, debug Appli/Boot OK.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
thomasandClaude Sonnet 5.5 committed 2026-10-23 22:49:06 +02:00
1 parent b119a6abd7
commit 66bb319423
1092 files changed
+172728 -133236

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,285 @@
/**
******************************************************************************
* @file spi_iface.h
* @brief SPI bus interface definition
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/**
* This file is based on QCC74xSDK provided by Qualcomm.
* See https://git.codelinaro.org/clo/qcc7xx/QCCSDK-QCC74x for more information.
*
* Reference source: examples/stm32_spi_host/QCC743_SPI_HOST/Core/Inc/spi.h
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef SPI_IFACE_H
#define SPI_IFACE_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/** SPI message control structure */
struct spi_msg_control
{
/** Ref SPI_MSG_CTRL_xxx */
uint8_t type;
/** Length of the following control data */
uint8_t len;
/** Pointer to the control data */
void *val;
};
/** SPI message structure */
struct spi_msg
{
union
{
/** For spi_write and spi_read */
struct
{
/** Data pointer for spi_write and spi_read */
void *data;
/** Data length for spi_write and spi_read */
uint32_t data_len;
};
/** Data buffer for spi_write when type is SPI_MSG_OP_BUFFER */
struct spi_buffer *buffer;
/** Data buffer for spi_read when type is SPI_MSG_OP_BUFFER_PTR */
struct spi_buffer **buffer_ptr;
};
/** Pointer to control information */
struct spi_msg_control *ctrl;
/** Message flags */
uint32_t flags;
/** Operation type: Ref SPI_MSG_OP_xxx */
unsigned char op_type;
};
/** SPI transfer engine structure */
struct spi_stat
{
uint64_t tx_pkts; /*!< Number of transmitted packets */
uint64_t tx_bytes; /*!< Number of transmitted bytes */
uint64_t rx_pkts; /*!< Number of received packets */
uint64_t rx_bytes; /*!< Number of received bytes */
uint64_t rx_drop; /*!< Number of dropped received packets */
uint64_t io_err; /*!< Number of I/O errors */
uint64_t hdr_err; /*!< Number of header errors */
uint64_t wait_txn_timeouts; /*!< Number of wait transaction timeouts */
uint64_t wait_msg_xfer_timeouts; /*!< Number of wait message transfer timeouts */
uint64_t wait_hdr_ack_timeouts; /*!< Number of wait header ack timeouts */
uint64_t mem_err; /*!< Number of memory errors */
uint64_t rx_stall; /*!< Number of RX stalls */
};
/** SPI buffer structure */
struct spi_buffer
{
/** Pointer to the data */
void *data;
/** Length of the data */
uint16_t len;
/** Capacity of the buffer, >= len */
uint32_t cap;
/** Buffer flags */
uint32_t flags;
/** Control block for private data */
unsigned char cb[16];
};
/** Callback function type for received data notification */
typedef void (*spi_rxd_notify_func_t)(void *arg);
/** SPI message control traffic type enumeration */
typedef enum
{
SPI_MSG_CTRL_TRAFFIC_AT_CMD = 0,
SPI_MSG_CTRL_TRAFFIC_NETWORK_STA,
SPI_MSG_CTRL_TRAFFIC_NETWORK_AP,
SPI_MSG_CTRL_TRAFFIC_HCI,
SPI_MSG_CTRL_TRAFFIC_OT,
SPI_MSG_CTRL_TRAFFIC_TYPE_MAX,
} spi_msg_ctrl_t;
/* Exported constants --------------------------------------------------------*/
/** SPI message flags */
#define SPI_MSG_F_TRUNCATED 0x1U
/** SPI message control types */
#define SPI_MSG_CTRL_TRAFFIC_TYPE 0x1U
/** Length of traffic type control info */
#define SPI_MSG_CTRL_TRAFFIC_TYPE_LEN 1U
/** SPI message operation type: data copy */
#define SPI_MSG_OP_DATA 0U
/** SPI message operation type: buffer pointer for write */
#define SPI_MSG_OP_BUFFER 1U
/** SPI message operation type: buffer pointer for read */
#define SPI_MSG_OP_BUFFER_PTR 2U
/** Maximum SPI buffer size */
#define SPI_XFER_MTU_BYTES W61_MAX_SPI_XFER
/* Exported macro ------------------------------------------------------------*/
/**
* @brief Initialize a SPI message control structure
* @param c: spi_msg_control structure to initialize
* @param t: Control type
* @param l: Control data length
* @param v: Pointer to control data
*/
#define SPI_MSG_CONTROL_INIT(c, t, l, v) do { \
struct spi_msg_control *_c = &(c); \
_c->type = t; \
_c->len = l; \
_c->val = v; \
} while (false)
/**
* @brief Initialize a SPI message structure
* @param m: spi_msg structure to initialize
* @param t: Operation type
* @param c: Pointer to control information
* @param f: Message flags
*/
#define SPI_MSG_INIT(m, t, c, f) do { \
struct spi_msg *_m = &(m); \
_m->op_type = t; \
_m->ctrl = c; \
_m->flags = f; \
} while (false)
/* Exported functions ------------------------------------------------------- */
/**
* @brief Initialize SPI transaction context
* @return 0 on success, negative error code on failure
*/
int32_t spi_transaction_init(void);
/**
* @brief Deinitialize SPI transaction context
* @return 0 on success, negative error code on failure
*/
int32_t spi_transaction_deinit(void);
/**
* @brief Allocate a SPI buffer
* @param size: Size of the buffer to allocate
* @return Pointer to the allocated buffer, or NULL on failure
*/
struct spi_buffer *spi_tx_buffer_alloc(uint32_t size);
/**
* @brief Free a SPI buffer
* @param buf: Pointer to the buffer to free
*/
void spi_buffer_free(struct spi_buffer *buf);
/**
* @brief Get data pointer from SPI buffer
* @param buf: Pointer to the SPI buffer
* @return Pointer to the data
*/
static inline void *spi_buffer_data(struct spi_buffer *buf)
{
return buf->data;
}
/**
* @brief Get data length from SPI buffer
* @param buf: Pointer to the SPI buffer
* @return Length of the data
*/
static inline uint32_t spi_buffer_len(struct spi_buffer *buf)
{
return buf->len;
}
/**
* @brief Bind a specific traffic type to a dedicated receive queue
* @param type: Traffic type to bind (must be < SPI_MSG_CTRL_TRAFFIC_TYPE_MAX)
* @param rxq_size: Size of receive queue to create (0 for default)
* @return 0 on success, negative value on error
*
* @note This function should be called during initialization before
* any SPI transfers start, as it's not fully thread-safe. Multiple
* concurrent binds or binding while transfers are in progress could
* lead to race conditions.
*/
int32_t spi_bind(unsigned char type, int32_t rxq_size);
/**
* @brief Read data from the SPI interface
* This function handles both raw data and buffer pointer operations based on the
* message operation type (op_type) field.
*
* @param msg: Message structure for receiving data
* @param timeout_ms: Timeout for queue operations in milliseconds (-1 for infinite)
* @return Number of bytes read or negative error code
*/
int32_t spi_read(struct spi_msg *msg, int32_t timeout_ms);
/**
* @brief Write data to the SPI interface
* This function handles both raw data and pre-allocated buffers based on the
* message operation type (op_type) field.
*
* @param msg: Message containing data or buffer to send
* @param timeout_ms: Timeout for queue operations in milliseconds (-1 for infinite)
* @return Number of bytes written or negative error code
*/
int32_t spi_write(struct spi_msg *msg, int32_t timeout_ms);
/**
* @brief Register a callback for received data of a specific traffic type
* @param type: Traffic type
* @param cb: Callback function
* @param arg: Argument to pass to the callback
* @return 0 on success, negative error code on failure
*/
int32_t spi_rxd_callback_register(spi_msg_ctrl_t type, spi_rxd_notify_func_t cb, void *arg);
/**
* @brief Handle SPI transaction/data ready event
* @return 0 on success, negative error code on failure
*/
int32_t spi_on_txn_data_ready(void);
/**
* @brief Handle SPI header acknowledgment event
* @return 0 on success, negative error code on failure
*/
int32_t spi_on_header_ack(void);
/**
* @brief Dump SPI transaction state and statistics
*/
void spi_dump(void);
/**
* @brief Get SPI transaction statistics
* @param stat: Pointer to the statistics structure to fill
* @return 0 on success, negative error code on failure
*/
int32_t spi_get_stats(struct spi_stat *stat);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SPI_IFACE_H */
@@ -0,0 +1,157 @@
/**
******************************************************************************
* @file spi_port.h
* @brief SPI bus interface porting layer
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/**
* This file is based on QCC74xSDK provided by Qualcomm.
* See https://git.codelinaro.org/clo/qcc7xx/QCCSDK-QCC74x for more information.
*
* Reference source: examples/stm32_spi_host/QCC743_SPI_HOST/Core/Src/spi_iface.c
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef SPI_PORT_H
#define SPI_PORT_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include <inttypes.h>
#include <stdint.h>
#include "logging.h"
/* Exported types ------------------------------------------------------------*/
typedef void (*spi_transaction_complete_t)(void);
/* Exported constants --------------------------------------------------------*/
/** Transfer with size greater than this value should use DMA */
#define SPI_DMA_XFER_SIZE_THRESHOLD 8U
/** SPI wait txn data ready timeout in milliseconds */
#define SPI_WAIT_TXN_TIMEOUT_MS 2000
/** SPI transaction timeout in milliseconds */
#define SPI_WAIT_MSG_XFER_TIMEOUT_MS 500
/** SPI header ack timeout in milliseconds */
#define SPI_WAIT_HDR_ACK_TIMEOUT_MS 100
/** SPI polling transfer timeout in milliseconds */
#define SPI_WAIT_POLL_XFER_TIMEOUT_MS 100
#ifndef SPI_PORT_ERROR_ENABLE
/** Enable/Disable SPI port error logging */
#define SPI_PORT_ERROR_ENABLE 1
#endif /* SPI_PORT_ERROR_ENABLE */
/** SPI event Tx pending */
#define SPI_EVT_TXN_PENDING 0x1U
/** SPI event Tx ready */
#define SPI_EVT_TXN_RDY 0x2U
/** SPI event Header acknowledged */
#define SPI_EVT_HDR_ACKED 0x4U
/** SPI event Hardware transfer done */
#define SPI_EVT_HW_XFER_DONE 0x8U
#ifndef SHORT_FILE
/** Macro to extract short file name from __FILE__ */
#define SHORT_FILE \
(strchr(__FILE__, '\\') \
? ((strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)) \
: ((strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)))
#endif /* SHORT_FILE */
/* Exported macro ------------------------------------------------------------*/
/**
* \def spi_err( ... )
* \brief SPI error logging macro
*/
#if (SPI_PORT_ERROR_ENABLE == 1)
#define spi_err(...) LogError(__VA_ARGS__)
#else
#define spi_err(...)
#endif /* SPI_PORT_ERROR_ENABLE */
/** SPI trace logging. Disabled by default */
#define spi_trace(...)
/* Exported functions ------------------------------------------------------- */
/**
* @brief Initialize SPI port
* @param transaction_complete_cb: Callback function to be called when a DMA transaction is completed
* @retval 0 if successful, -1 otherwise
*/
int32_t spi_port_init(spi_transaction_complete_t transaction_complete_cb);
/**
* @brief De-Initialize SPI port
* @retval 0 if successful, -1 otherwise
*/
int32_t spi_port_deinit(void);
/**
* @brief Execute SPI transaction in blocking mode (polling) with timeout. Can be TxRX or Rx only
* @param tx_buf: Pointer to the transmit buffer
* @param rx_buf: Pointer to the receive buffer
* @param len: Length of the transfer
* @param timeout: Timeout in milliseconds
* @retval 0 if successful, -1 otherwise
*/
int32_t spi_port_transfer(void *tx_buf, void *rx_buf, uint16_t len, uint32_t timeout);
/**
* @brief Execute SPI transaction in non-blocking mode (interrupt). Can be TxRX or Rx only
* @param tx_buf: Pointer to the transmit buffer
* @param rx_buf: Pointer to the receive buffer
* @param len: Length of the transfer
* @retval 0 if successful, -1 otherwise
*/
int32_t spi_port_transfer_dma(void *tx_buf, void *rx_buf, uint16_t len);
/**
* @brief Check if NCP requires to send a new data packet
* @retval 1 if ready, 0 otherwise
*/
int32_t spi_port_is_ready(void);
/**
* @brief Enable or disable the SPI Chip Select (CS) line
* @param state: 1 to set the CS line high, 0 to set it low
* @retval 0 if successful, -1 otherwise
*/
int32_t spi_port_set_cs(int32_t state);
/**
* @brief Copy memory from source to destination
* @note This function can be implemented as 32-bit memcpy
* @param dest: Destination address
* @param src: Source address
* @param len: Length of data to copy in bytes
* @retval Destination address
*/
void *spi_port_memcpy(void *dest, const void *src, unsigned int len);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SPI_PORT_H */
@@ -0,0 +1,138 @@
/**
******************************************************************************
* @file w61_io.c
* @author ST67 Application Team
* @brief This file provides the IO operations to deal with the STM32W61 module.
* It mainly initialize and de-initialize the SPI interface.
* Send and receive data over it.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "logging.h"
#include "w61_io.h"
#include "FreeRTOS.h"
#include "task.h"
/* Global variables ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/** Initialization flag */
static volatile int32_t BusIo_initialized = 0;
/* Private function prototypes -----------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
int32_t BusIo_SPI_Init(void)
{
int32_t ret;
if (BusIo_initialized == 1)
{
return -1;
}
ret = spi_transaction_init();
if (ret == 0)
{
BusIo_initialized = 1;
}
return ret;
}
int32_t BusIo_SPI_DeInit(void)
{
BusIo_initialized = 0;
return spi_transaction_deinit();
}
int32_t BusIo_SPI_Bind(uint8_t type, int32_t rxq_size, BusIo_SPI_rxd_notify_func_t cb)
{
int32_t ret = spi_bind(type, rxq_size);
if (ret != 0)
{
return ret;
}
if ((cb != NULL) && ((type == SPI_MSG_CTRL_TRAFFIC_NETWORK_STA) || (type == SPI_MSG_CTRL_TRAFFIC_NETWORK_AP)))
{
ret = spi_rxd_callback_register((spi_msg_ctrl_t)type, cb, NULL);
}
return ret;
}
void BusIo_SPI_Delay(uint32_t Delay)
{
vTaskDelay(pdMS_TO_TICKS(Delay));
}
int32_t BusIo_SPI_SendData(uint8_t type, uint8_t *pBuf, uint16_t length, uint32_t Timeout)
{
struct spi_msg_control ctrl;
struct spi_msg m;
SPI_MSG_CONTROL_INIT(ctrl, SPI_MSG_CTRL_TRAFFIC_TYPE, SPI_MSG_CTRL_TRAFFIC_TYPE_LEN, &type);
SPI_MSG_INIT(m, SPI_MSG_OP_DATA, &ctrl, 0);
m.data = (void *)pBuf;
m.data_len = length;
return spi_write(&m, Timeout);
}
int32_t BusIo_SPI_ReceiveData(uint8_t type, uint8_t *pBuf, uint16_t length, uint32_t Timeout)
{
struct spi_msg_control ctrl;
struct spi_msg m;
SPI_MSG_CONTROL_INIT(ctrl, SPI_MSG_CTRL_TRAFFIC_TYPE, SPI_MSG_CTRL_TRAFFIC_TYPE_LEN, &type);
SPI_MSG_INIT(m, SPI_MSG_OP_DATA, &ctrl, 0);
m.data = pBuf;
m.data_len = length;
return spi_read(&m, Timeout);
}
int32_t BusIo_SPI_ReceivePtr(uint8_t type, void **buffer, uint8_t **data, uint32_t Timeout)
{
struct spi_msg_control ctrl;
struct spi_msg m;
int32_t ret = 0;
struct spi_buffer *spi_buf = NULL;
*buffer = NULL;
*data = NULL;
SPI_MSG_CONTROL_INIT(ctrl, SPI_MSG_CTRL_TRAFFIC_TYPE, SPI_MSG_CTRL_TRAFFIC_TYPE_LEN, &type);
SPI_MSG_INIT(m, SPI_MSG_OP_BUFFER_PTR, &ctrl, 0);
m.buffer_ptr = &spi_buf;
ret = spi_read(&m, Timeout);
if ((ret >= 0) && (spi_buf != NULL))
{
*buffer = (void *)spi_buf;
*data = spi_buf->data;
}
return ret;
}
int32_t BusIo_SPI_Free(void *buffer)
{
if (buffer != NULL)
{
vPortFree(buffer);
}
return 0;
}
@@ -0,0 +1,117 @@
/**
******************************************************************************
* @file w61_io.h
* @author ST67 Application Team
* @brief This file provides the common defines and functions prototypes for
* the ST67W611M IO operations.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef W61_IO_H
#define W61_IO_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdint.h>
#include "spi_iface.h" /* Needed for SPI_XFER_MTU_BYTES */
/* Exported types ------------------------------------------------------------*/
/** @brief Callback function prototype called when new data are received */
typedef void (*BusIo_SPI_rxd_notify_func_t)(void *arg);
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/**
* @brief ST67W611M IO Initialization.
* This function initialize the SPI interface to deal with the w61,
* then starts asynchronous listening on the RX port.
* @retval forward spisync_init ret
*/
int32_t BusIo_SPI_Init(void);
/**
* @brief ST67W611M IO Deinitialization.
* This function De-initialize the SPI interface of the ST67W611M module.
* When called the w61 commands can't be executed anymore.
* @retval forward spisync_deinit ret
*/
int32_t BusIo_SPI_DeInit(void);
/**
* @brief ST67W611M IO bind interface.
* This function bind the SPI interface to deal with the w61,
* then starts asynchronous listening on the RX port.
* @param type: Traffic type to bind (must be < SPI_MSG_CTRL_TRAFFIC_TYPE_MAX)
* @param rxq_size: size of the RX queue
* @param cb: callback function to be called when new data are received
* @retval forward spisync_init ret
*/
int32_t BusIo_SPI_Bind(uint8_t type, int32_t rxq_size, BusIo_SPI_rxd_notify_func_t cb);
/**
* @brief Delay
* @param Delay in ticks (often 1 ticks is config to 1 ms)
*/
void BusIo_SPI_Delay(uint32_t Delay);
/**
* @brief Send commands and raw data to the ST67W611M module over the SPI interface.
* This function allows sending bytes to the ST67W611M module, the
* data can be either an AT command or raw data to send over
* a pre-established WiFi connection.
* @param type: Traffic type to use (must be < SPI_MSG_CTRL_TRAFFIC_TYPE_MAX)
* @param pBuf: data to send
* @param length: the data length
* @param Timeout: max time to wait before returning
* @retval forward spisync_deinit ret
*/
int32_t BusIo_SPI_SendData(uint8_t type, uint8_t *pBuf, uint16_t length, uint32_t Timeout);
/**
* @brief Receive data from the ST67W611M module over the SPI interface
* @param type: Traffic type to use (must be < SPI_MSG_CTRL_TRAFFIC_TYPE_MAX)
* @param pBuf: receive buffer
* @param length: max length to be retrieved
* @param Timeout: max time to wait before returning
* @retval size of the buffer actually retrieved (could be smaller the the length param)
*/
int32_t BusIo_SPI_ReceiveData(uint8_t type, uint8_t *pBuf, uint16_t length, uint32_t Timeout);
/**
* @brief Receive pointer of data from the ST67W611M module over the SPI interface
* @param type: Traffic type to use (must be < SPI_MSG_CTRL_TRAFFIC_TYPE_MAX)
* @param buffer: receive spi_buffer
* @param data: receive buffer
* @param Timeout: max time to wait before returning
* @retval size of the buffer actually retrieved (could be smaller the the length param)
*/
int32_t BusIo_SPI_ReceivePtr(uint8_t type, void **buffer, uint8_t **data, uint32_t Timeout);
/**
* @brief Free spi_buffer containing the data
* @param buffer: Pointer to store the spi_buffer
* @return Operation status
*/
int32_t BusIo_SPI_Free(void *buffer);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* W61_IO_H */