在cc2640的board相关的文件中,经常会看到如下的配置:
/* SPI objects */
SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650_LAUNCHXL_SPICOUNT];
/* SPI configuration structure, describing which pins are to be used */
const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650_LAUNCHXL_SPICOUNT] = {
{
.baseAddr = SSI0_BASE,
.intNum = INT_SSI0_COMB,
.intPriority = ~0,
.swiPriority = 0,
.powerMngrId = PowerCC26XX_PERIPH_SSI0,
.defaultTxBufValue = 0,
.rxChannelBitMask = 1<<UDMA_CHAN_SSI0_RX,
.txChannelBitMask = 1<<UDMA_CHAN_SSI0_TX,
.mosiPin = Board_SPI0_MOSI,
.misoPin = Board_SPI0_MISO,
.clkPin = Board_SPI0_CLK,
.csnPin = Board_SPI0_CSN
},
{
.baseAddr = SSI1_BASE,
.intNum = INT_SSI1_COMB,
.intPriority = ~0,
.swiPriority = 0,
.powerMngrId = PowerCC26XX_PERIPH_SSI1,
.defaultTxBufValue = 0,
.rxChannelBitMask = 1<<UDMA_CHAN_SSI1_RX,
.txChannelBitMask = 1<<UDMA_CHAN_SSI1_TX,
.mosiPin = Board_SPI1_MOSI,
.misoPin = Board_SPI1_MISO,
.clkPin = Board_SPI1_CLK,
.csnPin = Board_SPI1_CSN
}
};
/* SPI configuration structure */
const SPI_Config SPI_config[] = {
{
.fxnTablePtr = &SPICC26XXDMA_fxnTable,
.object = &spiCC26XXDMAObjects[0],
.hwAttrs = &spiCC26XXDMAHWAttrs[0]
},
{
.fxnTablePtr = &SPICC26XXDMA_fxnTable,
.object = &spiCC26XXDMAObjects[1],
.hwAttrs = &spiCC26XXDMAHWAttrs[1]
},
{NULL, NULL, NULL}
};
这里有两个SPI端口,但是使用不同的配置。
其中object的定义如下:
typedef struct SPICC26XXDMA_Object {
/* SPI control variables */
SPI_TransferMode transferMode; /*!< Blocking or Callback mode */
unsigned int transferTimeout; /*!< Timeout for the transfer when in blocking mode */
SPI_CallbackFxn transferCallbackFxn; /*!< Callback function pointer */
SPI_Mode mode; /*!< Master or Slave mode */
/*! @brief SPI bit rate in Hz.
*
* When the SPI is configured as SPI slave, the maximum bitrate is 4MHz.
*
* When the SPI is configured as SPI master, the maximum bitrate is 12MHz.
*/
unsigned int bitRate;
unsigned int dataSize; /*!< SPI data frame size in bits */
SPI_FrameFormat frameFormat; /*!< SPI frame format */
/* SPI SYS/BIOS objects */
ti_sysbios_family_arm_m3_Hwi_Struct hwi; /*!< Hwi object handle */
Swi_Struct swi; /*!< Swi object */
Semaphore_Struct transferComplete; /*!< Notify finished SPICC26XXDMA transfer */
/* SPI current transaction */
SPI_Transaction *currentTransaction; /*!< Ptr to the current transaction*/
SPICC26XXDMA_FrameSize frameSize; /*!< Data frame size variable */
/* Support for dynamic CSN pin allocation */
PIN_Id csnPin; /*!< SPI CSN pin */
/* PIN driver state object and handle */
PIN_State pinState;
PIN_Handle pinHandle;
/* UDMA driver handle */
UDMACC26XX_Handle udmaHandle;
/* Optional slave mode features */
bool returnPartial; /*!< Optional slave mode return partial on CSN deassert */
#ifdef SPICC26XXDMA_WAKEUP_ENABLED
SPICC26XXDMA_CallbackFxn wakeupCallbackFxn;/*!< Optional slave mode wake up on CSN assert */
#endif
/* Scratch buffer of size uint32_t */
uint16_t scratchBuf;
/* SPI pre- and post notification functions */
void *spiPreFxn; /*!< SPI pre-notification function pointer */
void *spiPostFxn; /*!< SPI post-notification function pointer */
Power_NotifyObj spiPreObj; /*!< SPI pre-notification object */
Power_NotifyObj spiPostObj; /*!< SPI post-notification object */
volatile bool spiPowerConstraint; /*!< SPI power constraint flag, guard to avoid power constraints getting out of sync */
bool isOpen; /*!< Has the object been opened */
} SPICC26XXDMA_Object, *SPICC26XXDMA_Handle;
这里的object是指和spi相关的一些变量及callback地址等。
留意最后一句:*SPICC26XXDMA_Handle,这意味着*SPICC26XXDMA_Handle为某个spi的object结构体的首地址,知道这个首地址就可以修改该object相关的参数。
通常,外设初始化的时候,我们会初始化一个params结构体,给params的成员赋值,然后再把params的首地址给某个init函数。实际上就是把params的参数传给object的结构体。object结构体的内容包含params的内容。
hwattr的定义如下
typedef struct SPICC26XXDMA_HWAttrsV1 {
/*! SPI Peripheral's base address */
uint32_t baseAddr;
/*! SPI CC26XXDMA Peripheral's interrupt vector */
uint8_t intNum;
/*! @brief SPI CC26XXDMA Peripheral's interrupt priority.
The CC26xx uses three of the priority bits,
meaning ~0 has the same effect as (7 << 5).
(7 << 5) will apply the lowest priority.
(1 << 5) will apply the highest priority.
Setting the priority to 0 is not supported by this driver.
HWI's with priority 0 ignore the HWI dispatcher to support zero-latency interrupts, thus invalidating the critical sections in this driver.
*/
uint8_t intPriority;
/*! @brief SPI SWI priority.
The higher the number, the higher the priority.
The minimum is 0 and the maximum is 15 by default.
The maximum can be reduced to save RAM by adding or modifying Swi.numPriorities in the kernel configuration file.
*/
uint32_t swiPriority;
/*! SPI Peripheral's power manager ID */
PowerCC26XX_Resource powerMngrId;
/*! Default TX value if txBuf == NULL */
uint16_t defaultTxBufValue;
/*! uDMA controlTable channel index */
uint32_t rxChannelBitMask;
/*! uDMA controlTable channel index */
uint32_t txChannelBitMask;
/*!< SPI MOSI pin */
PIN_Id mosiPin;
/*!< SPI MISO pin */
PIN_Id misoPin;
/*!< SPI CLK pin */
PIN_Id clkPin;
/*!< SPI CSN pin */
PIN_Id csnPin;
} SPICC26XXDMA_HWAttrsV1;
HWAttrs通常是和硬件相关的一些参数,比如pin之类的const的内容。在board的.c文件中,给HWAttrs赋初值。
FxnTable定义了SPI能够使用的API,这里用一个结构体把这些函数指针整合起来。
const SPI_FxnTable SPICC26XXDMA_fxnTable = {
SPICC26XXDMA_close,
SPICC26XXDMA_control,
SPICC26XXDMA_init,
SPICC26XXDMA_open,
SPICC26XXDMA_transfer,
SPICC26XXDMA_transferCancel,
SPICC26XXDMA_serviceISR
};
同样,需要写这些函数的源代码,然后在某个.c文件中集中到SPI_FxnTable结构体中,等待外部引用。
SPI_Config其实就是把以上三个结构体的指针用数据的方式集中起来。
const SPI_Config SPI_config[] = {
{
.fxnTablePtr = &SPICC26XXDMA_fxnTable,
.object = &spiCC26XXDMAObjects[0],
.hwAttrs = &spiCC26XXDMAHWAttrs[0]
},
{
.fxnTablePtr = &SPICC26XXDMA_fxnTable,
.object = &spiCC26XXDMAObjects[1],
.hwAttrs = &spiCC26XXDMAHWAttrs[1]
},
{NULL, NULL, NULL}
};
然后定义 handle 为config的指针。操作该handle就能操作该SPI相关所有的变量、硬件配置、可用的函数。
获取handle的方式,实际是上定义了一个名称SPIName,该名称定义为一个enmu的数字index,这样SPI0的handele, SPIhandle0 = gethandleFxn( index)。
对于SPIDMA这里是有原型的,如果没有原型,那么使用的是libary文件,参见工程->Option->Linker->Library里面的lib文件
其中library可以用在给客户提供API但是不让客户看到源码的场景下。