之前发了MC9S12XEP100数据手册上的SPI模块的翻译http://blog.csdn.net/lin_strong/article/details/79122482。
于是乎,现在对其的封装也来了。目前先完成了硬件驱动部分的封装。软件部分还没完全想好怎么弄。
这次的封装我尝试使用两个头文件的方式来区分protect与public。
全部内部使用的函数(不带参数检查)都放在了SPI_Internal.h中,而对用户的接口(可选参数检查)都放在了SPI.h中
使用时请只#include “SPI.h” 然后使用里头提供的接口。
下面上代码:
/*
*******************************************************************************************
*
*
* SPI(Serial Peripheral Interface) SUPPORT PACKAGE
* Freescale MC9S12XEP100
* 飞思卡尔 MC9S12XEP100 SPI支持包
*
* File : SPI.h
* By : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date: 2018/02/01
* version: V1.0
* History: 2018/02/01 V1.0 the prototype
* NOTE(s):a.refer to the code of uCOS-II
* b.this file define the interface for user. user should include this file to use the
* spi module.
* c.this module has three files — SPI.h、SPI_Internal.h、SPI.c
* d.steps to use this module:
* 1. configure whether you use single port in CONFIGURE
* 2. configure the init parameter in INITIALIZATION CONFIGURE
* 3. use the interface function to send/receive data. e.g.
* ......
* INT8U dataSend,dataRecv;
* SPI_Init(SPI0);
* SPI_Enable(SPI0);
* for(TRUE){
* dataRecv = SPI_ExchangeChar(SPI0,dataSend);
* // deal with the dataRecv.
* }
*********************************************************************************************
*/
#ifndef SPI_H
#define SPI_H
/*
********************************************************************************************
* MISCELLANEOUS
********************************************************************************************
*/
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef NULL
#define NULL 0x00
#endif
/*
******************************************************************************************
* CONSTANT
******************************************************************************************
*/
#define SPI0 0x00 /* SPI0 */
#define SPI1 0x01 /* SPI1 */
#define SPI2 0x02 /* SPI2 */
// spi behavior when cpu is in wait mode
#define SPI_INWAITMODE_STOP 0 // SPI module will keep running when cpu in wait mode
#define SPI_INWAITMODE_RUN 1 // SPI module will stop when cpu in wait mode
// format of spi clock
#define SPI_SCKFMT_MODE_0 0 // CPHA=0、CPOL=0
#define SPI_SCKFMT_MODE_1 1 // CPHA=0、CPOL=1
#define SPI_SCKFMT_MODE_2 2 // CPHA=1、CPOL=0
#define SPI_SCKFMT_MODE_3 3 // CPHA=1、CPOL=1
// the bit order when transmit/receive.
#define SPI_BITORDER_LSB 0 // Least significant bit first
#define SPI_BITORDER_MSB 1 // Most significant bit first
// how spi system control SS pin
#define SPI_SS_CTRL_OFF 0 // SPI module don't use SS pin.
#define SPI_SS_CTRL_ON 1 // only for master, SS pin is used for slave control.
#define SPI_SS_LISTEN_MODF 2 // only for master, SS pin is used for listening mode fault
/*
*******************************************************************************************
* CONFIGURE 主配置
*******************************************************************************************
*/
#define SPI_MODULE_EN TRUE /* TRUE: 启用SPI驱动模块 */
// TRUE: just use single port(declare in SPI_MONOPORT_USED), so the module can create
// optimised code.
#define SPI_MONOPORT_NEEDED FALSE
#define SPI_MONOPORT_USED SPI0
#define SPI_ARGUMENT_CHECK_EN TRUE /* TRUE: 启用参数检查 */
/*
*******************************************************************************************
* INCLUDES
*******************************************************************************************
*/
#include <MC9S12XEP100.h>
/*
****************************************************************************************
* ERROR CODES
****************************************************************************************
*/
#define SPI_NO_ERR 0 /* Function call was successful */
#define SPI_INVALID_PORT 1 /* Invalid communications port channel */
#define SPI_ARGUMENT_OUT 2 /* Argument out of range */
#define SPI_RX_EMPTY 3 /* Rx buffer is empty, no character available */
#define SPI_TX_FULL 4 /* Tx buffer is full, could not deposit character */
#define SPI_TX_EMPTY 5 /* If the Tx buffer is empty. */
#define SPI_RX_TIMEOUT 6 /* If a timeout occurred while waiting for a character*/
#define SPI_TX_TIMEOUT 7 /* If a timeout occurred while waiting to send a char.*/
#define SPI_ERR_UNKNOWN 8
/*
******************************************************************************************
* TYPE DEFINE
******************************************************************************************
*/
// for any init-style
typedef struct spi_init_struct{
unsigned char isMaster; // TRUE: spi is master. FALSE: spi is slave.
unsigned char SSctrl; // see SPI_SS_CTRL
unsigned char bitorder; // see SPI_BITORDER
unsigned char inWaitMode; // see SPI_INWAITMODE
unsigned char sckfmt; // see SPI_SCKFMT
// BaudRateDivisor = (SPPR + 1) * 2^(SPR + 1)
// BaudRate = Busclock / BaudRateDivisor
unsigned char SPR; // 0-7,SPI Baud Rate Selection
unsigned char SPPR; // 0-7,SPI Baud Rate Preselection
}SPI_INIT_STRUCT,*pSPI_INIT_STRUCT;
/*
*******************************************************************************************
* INITIALIZATION CONFIGURE 初始化配置
*******************************************************************************************
*/
// the default parameter to initialize the SPI system
// 初始化SPI的默认参数
#define SPI_INIT_ISMASTER TRUE // TRUE: spi is master. FALSE: spi is slave.
#define SPI_INIT_SSCTRL SPI_SS_CTRL_ON // see SPI_SS_CTRL
#define SPI_INIT_BITORDER SPI_BITORDER_MSB // see SPI_BITORDER
#define SPI_INIT_INWAITMODE SPI_INWAITMODE_STOP // see SPI_INWAITMODE
#define SPI_INIT_SCKFMT SPI_SCKFMT_MODE_3 // see SPI_SCKFMT
// BaudRateDivisor = (SPPR + 1) * 2^(SPR + 1)
// BaudRate = Busclock / BaudRateDivisor
#define SPI_INIT_SPR 1 // 0-7,SPI Baud Rate Selection
#define SPI_INIT_SPPR 3 // 0-7,SPI Baud Rate Preselection
/*
************************************************************************************
* FUNCTION PROTOTYPES 函数原型
************************************************************************************
*/
// unsigned char SPI_Init(unsigned char port,pSPI_INIT_STRUCT arg);
unsigned char SPI_Init(unsigned char port);
unsigned char SPI_Enable(unsigned char port);
unsigned char SPI_Disable(unsigned char port);
unsigned char SPI_EnableTxInt(unsigned char port);
unsigned char SPI_DisableRxInt(unsigned char port);
unsigned char SPI_EnableRxInt(unsigned char port);
unsigned char SPI_DisableTxInt(unsigned char port);
unsigned char SPI_setMaster(unsigned char port,unsigned char isMaster);
unsigned char SPI_setSSctrl(unsigned char port,unsigned char option);
unsigned char SPI_setBehaviorInWaitMode(unsigned char port,unsigned char option);
unsigned char SPI_setSCKFormat(unsigned char port,unsigned char option);
unsigned char SPI_setBaudRate(unsigned char port,unsigned char SPR,unsigned char SPPR);
unsigned char SPI_PutChar(unsigned char port, unsigned char c);
unsigned char SPI_DataHasReceived(unsigned char port);
unsigned char SPI_GetChar(unsigned char port);
unsigned char SPI_ExchangeChar(unsigned char port, unsigned char c);
/*
************************************************************************************
* ERROR CHECK 错误检查
************************************************************************************
*/
#ifndef SPI_MODULE_EN
#error "SPI_MODULE_EN must be defined."
#endif
#if (SPI_MONOPORT_NEEDED == TRUE)
#ifndef SPI_MONOPORT_USED
#error "SPI_MONOPORT_USED must be specified if you use single port."
#endif
#endif
#if (SPI_INIT_BITORDER != SPI_BITORDER_LSB && SPI_INIT_BITORDER != SPI_BITORDER_MSB)
#error "SPI_INIT_BITORDER must be SPI_BITORDER_LSB or SPI_BITORDER_MSB"
#endif
#if(SPI_INIT_ISMASTER != TRUE && SPI_INIT_ISMASTER != FALSE)
#error "SPI_INIT_ISMASTER must be TRUE or FALSE"
#endif
#if(SPI_INIT_SSCTRL != SPI_SS_CTRL_ON && SPI_INIT_SSCTRL != SPI_SS_CTRL_OFF && \
SPI_INIT_SSCTRL != SPI_SS_LISTEN_MODF)
#error "SPI_INIT_SSCTRL must be SPI_SS_CTRL_ON or SPI_SS_CTRL_OFF or SPI_SS_LISTEN_MODF"
#endif
#if(SPI_INIT_BITORDER != SPI_BITORDER_MSB && SPI_INIT_BITORDER != SPI_BITORDER_LSB)
#error "SPI_INIT_BITORDER must be SPI_BITORDER_MSB or SPI_BITORDER_LSB"
#endif
#if(SPI_INIT_INWAITMODE != SPI_INWAITMODE_STOP && SPI_INIT_INWAITMODE != SPI_INWAITMODE_RUN)
#error "SPI_INIT_INWAITMODE must be SPI_INWAITMODE_STOP or SPI_INWAITMODE_RUN"
#endif
#if(SPI_INIT_SCKFMT != SPI_SCKFMT_MODE_0 && SPI_INIT_SCKFMT != SPI_SCKFMT_MODE_1 && \
SPI_INIT_SCKFMT != SPI_SCKFMT_MODE_2 && SPI_INIT_SCKFMT != SPI_SCKFMT_MODE_3)
#error "SPI_INIT_SSCTRL must be SPI_SCKFMT_MODE_X(X=0/1/2/3)"
#endif
#if(SPI_INIT_SPR < 0 || SPI_INIT_SPR > 7 ||SPI_INIT_SPPR < 0 || SPI_INIT_SPPR > 7 )
#error "SPI_INIT_SPR and SPI_INIT_SPPR must between 0 and 7"
#endif
#endif // of SPI_DEF_H
/*
*******************************************************************************************
*
*
* SPI(Serial Peripheral Interface) SUPPORT PACKAGE
* Freescale MC9S12XEP100
* 飞思卡尔 MC9S12XEP100 SPI支持包
*
* File : SPI_Internal.h
* By : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date: 2018/02/01
* version: V1.0
* History: 2018/02/01 V1.0 the prototype
* NOTE(s):a.refer to the code of uCOS-II
* b.this file is for internal use or extension. User shouldn't include this file.
* 这个文件是用于内部使用或扩展的。用户不应该include这个文件
*********************************************************************************************
*/
#ifndef SPI_INTERNAL_H
#define SPI_INTERNAL_H
/*
*******************************************************************************************
* INCLUDES
*******************************************************************************************
*/
#include "SPI.h"
#if(SPI_MONOPORT_NEEDED == TRUE)
#define SPI_MONO SPI_MONOPORT_USED
#endif
/*
******************************************************************************************
* TYPE DEFINITION
******************************************************************************************
*/
// struct of SPI register
typedef struct{
SPI0CR1STR CR1;
SPI0CR2STR CR2;
SPI0BRSTR BR;
SPI0SRSTR SR;
SPI0DRSTR DR;
} SPISTR,*pSPISTR;
// 如定义了SPI_MONO则会为单个端口生成代码
#ifdef SPI_MONO
#if(SPI_MONO == 0)
#define SPICR1(pSPIstr) _SPI0CR1
#define SPICR2(pSPIstr) _SPI0CR2
#define SPIBR(pSPIstr) _SPI0BR
#define SPISR(pSPIstr) _SPI0SR
#define SPIDR(pSPIstr) SPI0DR
#define SPIDRL(pSPIstr) SPI0DRL
#define SPIDRH(pSPIstr) SPI0DRH
#elif(SPI_MONO == 1)
#define SPICR1(pSPIstr) _SPI1CR1
#define SPICR2(pSPIstr) _SPI1CR2
#define SPIBR(pSPIstr) _SPI1BR
#define SPISR(pSPIstr) _SPI1SR
#define SPIDR(pSPIstr) SPI1DR
#define SPIDRL(pSPIstr) SPI1DRL
#define SPIDRH(pSPIstr) SPI1DRH
#elif(SPI_MONO == 2)
#define SPICR1(pSPIstr) _SPI2CR1
#define SPICR2(pSPIstr) _SPI2CR2
#define SPIBR(pSPIstr) _SPI2BR
#define SPISR(pSPIstr) _SPI2SR
#define SPIDR(pSPIstr) SPI2DR
#define SPIDRL(pSPIstr) SPI2DRL
#define SPIDRH(pSPIstr) SPI2DRH
#else
#error "SPI_MONO must be 0(for SPI0)/1(for SPI1)/2(for SPI2)."
#endif
#else
#define SPICR1(pSPIstr) (pSPIstr->CR1)
#define SPICR2(pSPIstr) (pSPIstr->CR2)
#define SPIBR(pSPIstr) (pSPIstr->BR)
#define SPISR(pSPIstr) (pSPIstr->SR)
#define SPIDR(pSPIstr) (pSPIstr->DR.Word)
#define SPIDRL(pSPIstr) (pSPIstr->DR.Overlap_STR.SPI0DRLSTR.Byte)
#define SPIDRH(pSPIstr) (pSPIstr->DR.Overlap_STR.SPI0DRHSTR.Byte)
#endif
/*** SPICR1 - SPI Control Register 1 ***/
#define SPICR1_BYTE(pSPIstr) (SPICR1(pSPIstr).Byte)
#define SPICR1_BITS(pSPIstr) (SPICR1(pSPIstr).Bits)
#define SPICR1_LSBFE(pSPIstr) (SPICR1_BITS(pSPIstr).LSBFE) /* SPI LSB-First Enable */
#define SPICR1_SSOE(pSPIstr) (SPICR1_BITS(pSPIstr).SSOE) /* Slave Select Output Enable */
#define SPICR1_CPHA(pSPIstr) (SPICR1_BITS(pSPIstr).CPHA) /* SPI Clock Phase Bit */
#define SPICR1_CPOL(pSPIstr) (SPICR1_BITS(pSPIstr).CPOL) /* SPI Clock Polarity Bit */
#define SPICR1_MSTR(pSPIstr) (SPICR1_BITS(pSPIstr).MSTR) /* SPI Master/Slave Mode Select Bit */
#define SPICR1_SPTIE(pSPIstr) (SPICR1_BITS(pSPIstr).SPTIE) /* SPI Transmit Interrupt Enable */
#define SPICR1_SPE(pSPIstr) (SPICR1_BITS(pSPIstr).SPE) /* SPI System Enable Bit */
#define SPICR1_SPIE(pSPIstr) (SPICR1_BITS(pSPIstr).SPIE) /* SPI Interrupt Enable Bit */
#define SPICR1_LSBFE_MASK 1U
#define SPICR1_SSOE_MASK 2U
#define SPICR1_CPHA_MASK 4U
#define SPICR1_CPOL_MASK 8U
#define SPICR1_MSTR_MASK 16U
#define SPICR1_SPTIE_MASK 32U
#define SPICR1_SPE_MASK 64U
#define SPICR1_SPIE_MASK 128U
/*** SPICR2 - SPI Control Register 2 ***/
#define SPICR2_BYTE(pSPIstr) (SPICR2(pSPIstr).Byte)
#define SPICR2_BITS(pSPIstr) (SPICR2(pSPIstr).Bits)
#define SPICR2_SPC0(pSPIstr) (SPICR2_BITS(pSPIstr).SPC0)
#define SPICR2_SPISWAI(pSPIstr) (SPICR2_BITS(pSPIstr).SPISWAI)
#define SPICR2_BIDIROE(pSPIstr) (SPICR2_BITS(pSPIstr).BIDIROE)
#define SPICR2_MODFEN(pSPIstr) (SPICR2_BITS(pSPIstr).MODFEN)
#define SPICR2_XFRW(pSPIstr) (SPICR2_BITS(pSPIstr).XFRW)
#define SPICR2_SPC0_MASK 1U
#define SPICR2_SPISWAI_MASK 2U
#define SPICR2_BIDIROE_MASK 8U
#define SPICR2_MODFEN_MASK 16U
#define SPICR2_XFRW_MASK 64U
/*** SPIBR - SPI Baud Rate Register ***/
#define SPIBR_BYTE(pSPIstr) (SPIBR(pSPIstr).Byte)
#define SPIBR_BITS(pSPIstr) (SPIBR(pSPIstr).Bits)
#define SPIBR_MBITS(pSPIstr) (SPIBR(pSPIstr).MergedBits)
#define SPIBR_SPR0(pSPIstr) (SPIBR_BITS(pSPIstr).SPR0) /* SPI Baud Rate Selection Bit 0 */
#define SPIBR_SPR1(pSPIstr) (SPIBR_BITS(pSPIstr).SPR1) /* SPI Baud Rate Selection Bit 1 */
#define SPIBR_SPR2(pSPIstr) (SPIBR_BITS(pSPIstr).SPR2) /* SPI Baud Rate Selection Bit 2 */
#define SPIBR_SPPR0(pSPIstr) (SPIBR_BITS(pSPIstr).SPPR0) /* SPI Baud Rate Preselection Bits 0 */
#define SPIBR_SPPR1(pSPIstr) (SPIBR_BITS(pSPIstr).SPPR1) /* SPI Baud Rate Preselection Bits 1 */
#define SPIBR_SPPR2(pSPIstr) (SPIBR_BITS(pSPIstr).SPPR2) /* SPI Baud Rate Preselection Bits 2 */
#define SPIBR_SPR(pSPIstr) (SPIBR_MBITS(pSPIstr).grpSPR)
#define SPIBR_SPPR(pSPIstr) (SPIBR_MBITS(pSPIstr).grpSPPR)
#define SPIBR_SPR0_MASK 1U
#define SPIBR_SPR1_MASK 2U
#define SPIBR_SPR2_MASK 4U
#define SPIBR_SPPR0_MASK 16U
#define SPIBR_SPPR1_MASK 32U
#define SPIBR_SPPR2_MASK 64U
#define SPIBR_SPR_MASK 7U
/*** SPISR - SPI Status Register ***/
#define SPISR_BYTE(pSPIstr) (SPISR(pSPIstr).Byte)
#define SPISR_BITS(pSPIstr) (SPISR(pSPIstr).Bits)
#define SPISR_MODF(pSPIstr) (SPISR_BITS(pSPIstr).MODF)
#define SPISR_SPTEF(pSPIstr) (SPISR_BITS(pSPIstr).SPTEF)
#define SPISR_SPIF(pSPIstr) (SPISR_BITS(pSPIstr).SPIF)
#define SPISR_MODF_MASK 16U
#define SPISR_SPTEF_MASK 32U
#define SPISR_SPIF_MASK 128U
/*** SPIDR - SPI Data Register ***/
#define SPIDR_WORD(pSPIstr) SPIDR(pSPIstr)
#define SPIDRL_BYTE(pSPIstr) SPIDRL(pSPIstr)
#define SPIDRH_BYTE(pSPIstr) SPIDRH(pSPIstr)
/*
******************************************************************************************
* REGISTER VARIABLE DECLARATION
******************************************************************************************
*/
extern pSPISTR const ptr_SPI[];
#define SPI_CNT 3
#define pSPI(port) (ptr_SPI[port])
/*
****************************************************************************************
* ERROR CODES
****************************************************************************************
*/
#define SPI_NO_ERR 0 /* Function call was successful */
#define SPI_BAD_CH 1 /* Invalid communications port channel */
#define SPI_ARGUMENT_OUT 2 /* Argument out of range */
#define SPI_RX_EMPTY 3 /* Rx buffer is empty, no character available */
#define SPI_TX_FULL 4 /* Tx buffer is full, could not deposit character */
#define SPI_TX_EMPTY 5 /* If the Tx buffer is empty. */
#define SPI_RX_TIMEOUT 6 /* If a timeout occurred while waiting for a character*/
#define SPI_TX_TIMEOUT 7 /* If a timeout occurred while waiting to send a char.*/
#define SPI_ERR_UNKNOWN 8
/*
************************************************************************************
* FUNCTION PROTOTYPES 函数原型
************************************************************************************
*/
#define SPI_isSystemEnable_set_internal(pSPIstr,b) (SPICR1_SPE(pSPIstr) = (b))
#define SPI_isSystemEnable_get_internal(pSPIstr) SPICR1_SPE(pSPIstr)
#define SPI_Enable_internal(pSPIstr) SPI_isSystemEnable_set_internal(pSPIstr,TRUE)
#define SPI_Disable_internal(pSPIstr) SPI_isSystemEnable_set_internal(pSPIstr,FALSE)
#define SPI_isMaster_set_internal(pSPIstr,b) (SPICR1_MSTR(pSPIstr) = (b))
#define SPI_isMaster_get_internal(pSPIstr) SPICR1_MSTR(pSPIstr)
#define SPI_isStopInWait_set_internal(pSPIstr,b) (SPICR2_SPISWAI(pSPIstr) = (b))
#define SPI_isStopInWait_get_internal(pSPIstr) SPICR2_SPISWAI(pSPIstr)
// TRUE: data is word-wide;FALSE:char-wide.
#define SPI_isWordWide_set_internal(pSPIstr,b) (SPICR2_XFRW(pSPIstr) = (b))
#define SPI_isWordWide_get_internal(pSPIstr) SPICR2_XFRW(pSPIstr)
#define SPI_isLSBFirst_set_internal(pSPIstr,b) (SPICR1_LSBFE(pSPIstr) = (b))
#define SPI_isLSBFirst_get_internal(pSPIstr) SPICR1_LSBFE(pSPIstr)
#define SPI_isHighIdle_set_internal(pSPIstr,b) (SPICR1_CPHA(pSPIstr) = (b))
#define SPI_isHighIdle_get_internal(pSPIstr) SPICR1_CPHA(pSPIstr)
#define SPI_isEvenSample_set_internal(pSPIstr,b) (SPICR1_CPOL(pSPIstr) = (b))
#define SPI_isEvenSample_get_internal(pSPIstr) SPICR1_CPOL(pSPIstr)
#define SPI_isTxIntEnable_set_internal(pSPIstr,b) (SPICR1_SPTIE(pSPIstr) = (b))
#define SPI_isTxIntEnable_get_internal(pSPIstr) SPICR1_SPTIE(pSPIstr)
#define SPI_EnableTxInt_internal(pSPIstr) SPI_isTxIntEnable_set_internal(pSPIstr,TRUE)
#define SPI_DisableTxInt_internal(pSPIstr) SPI_isTxIntEnable_set_internal(pSPIstr,FALSE)
// 实际上同时使能了接收和MODF中断
#define SPI_isRxIntEnable_set_internal(pSPIstr,b) (SPICR1_SPIE(pSPIstr) = (b))
#define SPI_isRxIntEnable_get_internal(pSPIstr) SPICR1_SPIE(pSPIstr)
#define SPI_EnableRxInt_internal(pSPIstr) SPI_isRxIntEnable_set_internal(pSPIstr,TRUE)
#define SPI_DisableRxInt_internal(pSPIstr) SPI_isRxIntEnable_set_internal(pSPIstr,FALSE)
// if is master node.
// when MODFEN = 1 && SSOE = 0, SS is for dectect MODF;
// when MODFEN = 1 && SSOE = 1, SS is for slave selection;
#define SPI_isSSoutputEnable_set_internal(pSPIstr,b) (SPICR1_SSOE(pSPIstr) = (b))
#define SPI_isSSoutputEnable_get_internal(pSPIstr) SPICR1_SSOE(pSPIstr)
#define SPI_isMODFEnable_set_internal(pSPIstr,b) (SPICR2_MODFEN(pSPIstr) = (b))
#define SPI_isMODFEnable_get_internal(pSPIstr) SPICR2_MODFEN(pSPIstr)
// BaudRateDivisor = (SPPR + 1) * 2^(SPR + 1)
// BaudRate = Busclock / BaudRateDivisor
// 分频系数 = (SPPR + 1) * 2^(SPR + 1)
// 波特率 = 总线时钟 / 分频系数
#define SPI_SPR_set_internal(pSPIstr,val) (SPIBR_SPR(pSPIstr) = (val))
#define SPI_SPR_get_internal(pSPIstr) SPIBR_SPR(pSPIstr)
#define SPI_SPPR_set_internal(pSPIstr,val) (SPIBR_SPPR(pSPIstr) = (val))
#define SPI_SPPR_get_internal(pSPIstr) SPIBR_SPPR(pSPIstr)
#define SPI_isDataReceived(pSPIstr) SPISR_SPIF(pSPIstr)
#define SPI_waitUntilDataReceived(pSPIstr) while(!SPI_isDataReceived(pSPIstr));
#define SPI_isTxReady(pSPIstr) SPISR_SPTEF(pSPIstr)
#define SPI_waitUntilTxReady(pSPIstr) while(!SPI_isTxReady(pSPIstr));
#define SPI_isModeFaultHappened(pSPIstr) SPISR_MODF(pSPIstr)
#define SPI_getChar_internal(pSPIstr) SPIDRL_BYTE(pSPIstr)
#define SPI_putChar_internal(pSPIstr,c) (SPIDRL_BYTE(pSPIstr) = (c))
#define SPI_getWord_internal(pSPIstr) SPIDR_WORD(pSPIstr)
#define SPI_putWord_internal(pSPIstr,w) (SPIDR_WORD(pSPIstr) = (w))
#endif // of SPI_DEF_H
/*
*********************************************************************************************************
*
*
* SPI(Serial Communication Interface) SUPPORT PACKAGE
* Freescale MC9S12XEP100
* 飞思卡尔 MC9S12XEP100 SPI支持包
*
* File : SPI.c
* By : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date : 2018/02/01
* version: V1.0
* History: 2018/02/01 V1.0 the prototype
* NOTE(s): 1. refer to the code of uCOS-II
* 2. the function in this file is not thread-safe, which means user should make sure that only
* one thread will call the same function for the same port at the same time.
* 这个文件中的实现都不是线程安全的,也就是说,用户需要保证在同一时间只有一个线程调用某一端口
* 的同个函数
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* INCLUDES
*********************************************************************************************************
*/
#include "SPI_Internal.h"
/*
*********************************************************************************************************
* REGISTER VARIABLE DEFINITION
*********************************************************************************************************
*/
pSPISTR const ptr_SPI[] = {(pSPISTR)&_SPI0CR1,(pSPISTR)&_SPI1CR1,(pSPISTR)&_SPI2CR1};
/*
*********************************************************************************************************
* LOCAL FUNCTION DECLARATION
*********************************************************************************************************
*/
#if(SPI_ARGUMENT_CHECK_EN == TRUE)
#define argCheck(arg,ceil,rVal) if((arg) >= (ceil)) return (rVal);
#else
#define argCheck(arg,ceil,rVal)
#endif // of (SPI_ARGUMENT_CHECK_EN == TRUE)
#if(SPI_MONOPORT_NEEDED == TRUE)
#define portCheck()
#define portCheck2(rVal)
#else
#define portCheck() argCheck(port,SPI_CNT,SPI_BAD_CH)
#define portCheck2(rVal) argCheck(port,SPI_CNT,rVal)
#endif
#if(SPI_MODULE_EN == TRUE)
/*
*********************************************************************************************************
* SPI_Init()
*
* Description : Initialize SPI support hardware(struct style). 初始化SPI硬件(结构体风格)
*
* Arguments : port SPI0-SPI2 the port to Initialize; 选择要初始化的端口;
* arg arguments used to initialize the SPI port; 用于初始化SPI端口的参数
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
*
* Note(s) : 1.will use the arguments in init_struct to initialize SPI;
* 会使用结构体中的参数来初始化SPI
* 2.don't forget to enable the spi after initialization.
* 不要忘了在初始化后使能SPI
* 3.if you want this style, comment the another SPI_Init() and uncomment this one.
* However, the trade-off is that the code size will be much bigger.
* 如果想要使用这种初始化风格的话,注释掉另一个SPI_Init()然后取消注释这一个。
* 但是代价就是生成的代码会大得多。
*********************************************************************************************************
*/
/*unsigned char SPI_Init(unsigned char port,pSPI_INIT_STRUCT arg){
pSPISTR pPort = pSPI(port);
portCheck();
argCheck(arg->SPR,8,SPI_ARGUMENT_OUT);
argCheck(arg->SPPR,8,SPI_ARGUMENT_OUT);
argCheck(arg->sckfmt,SPI_SCKFMT_MODE_3 + 1,SPI_ARGUMENT_OUT);
argCheck(arg->SSctrl,SPI_SS_LISTEN_MODF + 1,SPI_ARGUMENT_OUT);
SPI_isMaster_set_internal(pPort,!!arg->isMaster);
switch(arg->SSctrl){
case SPI_SS_CTRL_OFF:
SPI_isMODFEnable_set_internal(pPort,FALSE);
break;
case SPI_SS_CTRL_ON:
SPI_isMODFEnable_set_internal(pPort,TRUE);
SPI_isSSoutputEnable_set_internal(pPort,TRUE);
break;
case SPI_SS_LISTEN_MODF:
SPI_isMODFEnable_set_internal(pPort,TRUE);
SPI_isSSoutputEnable_set_internal(pPort,FALSE);
break;
}
SPI_isHighIdle_set_internal(pPort,!!((arg->sckfmt) & 0x02));
SPI_isEvenSample_set_internal(pPort,(arg->sckfmt) & 0x01);
SPI_isLSBFirst_set_internal(pPort, (arg->bitorder) == SPI_BITORDER_LSB);
SPI_isStopInWait_set_internal(pPort, (arg->inWaitMode) == SPI_INWAITMODE_STOP);
SPI_SPR_set_internal(pPort,(arg->SPR));
SPI_SPPR_set_internal(pPort,(arg->SPPR));
return SPI_NO_ERR;
} // */
/*
*********************************************************************************************************
* SPI_Init()
*
* Description : Initialize SPI support hardware(marco style). 初始化SPI硬件(宏参数风格)
*
* Arguments : port SPI0-SPI2 the port to Initialize; 选择要初始化的端口;
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
*
* Note(s) : 1.will use marco arguments(see SPI_INIT_XXXX) in SPI.h to initialize SPI;
* 会使用SPI.h 中的宏参数(见 SPI_INIT_XXXX)来初始化SPI
* 2.don't forget to enable the spi after initialization.
* 不要忘了在初始化后使能SPI
*********************************************************************************************************
*/
unsigned char SPI_Init(unsigned char port){
pSPISTR pPort = pSPI(port);
portCheck();
SPI_isMaster_set_internal(pPort,SPI_INIT_ISMASTER);
#if(SPI_INIT_ISMASTER == TRUE)
#if(SPI_INIT_SSCTRL == SPI_SS_CTRL_OFF)
SPI_isMODFEnable_set_internal(pPort,FALSE);
#elif(SPI_INIT_SSCTRL == SPI_SS_CTRL_ON)
SPI_isMODFEnable_set_internal(pPort,TRUE);
SPI_isSSoutputEnable_set_internal(pPort,TRUE);
#else
SPI_isMODFEnable_set_internal(pPort,TRUE);
SPI_isSSoutputEnable_set_internal(pPort,FALSE);
#endif
#endif
SPI_isHighIdle_set_internal(pPort,!!(SPI_INIT_SCKFMT & 0x02));
SPI_isEvenSample_set_internal(pPort,SPI_INIT_SCKFMT & 0x01);
SPI_isLSBFirst_set_internal(pPort, SPI_INIT_BITORDER == SPI_BITORDER_LSB);
SPI_isStopInWait_set_internal(pPort, SPI_INIT_INWAITMODE == SPI_INWAITMODE_STOP);
SPI_SPR_set_internal(pPort,SPI_INIT_SPR);
SPI_SPPR_set_internal(pPort,SPI_INIT_SPPR);
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_Enable()
*
* Description : Enable SPI System 使能SPI系统
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
*
* Note:
*********************************************************************************************************
*/
unsigned char SPI_Enable(unsigned char port){
portCheck();
SPI_Enable_internal(pSPI(port));
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_Disable()
*
* Description : Disable SPI System 禁用SPI系统
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
*
* Note:
*********************************************************************************************************
*/
unsigned char SPI_Disable(unsigned char port){
portCheck();
SPI_Disable_internal(pSPI(port));
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_EnableTxInt()
*
* Description : Enable Tx interrupt 使能传输中断
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
*
* Note:
*********************************************************************************************************
*/
unsigned char SPI_EnableTxInt(unsigned char port){
portCheck();
SPI_EnableTxInt_internal(pSPI(port));
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_DisableTxInt()
*
* Description : Disable Tx interrupt 禁用传输中断
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
*
* Note:
*********************************************************************************************************
*/
unsigned char SPI_DisableTxInt(unsigned char port){
portCheck();
SPI_DisableTxInt_internal(pSPI(port));
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_EnableRxInt()
*
* Description : Enable Rx interrupt 使能接收中断
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
*
* Note:
*********************************************************************************************************
*/
unsigned char SPI_EnableRxInt(unsigned char port){
portCheck();
SPI_EnableRxInt_internal(pSPI(port));
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_DisableRxInt()
*
* Description : Disable Rx interrupt 禁用接收中断
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
*
* Note:
*********************************************************************************************************
*/
unsigned char SPI_DisableRxInt(unsigned char port){
portCheck();
SPI_DisableRxInt_internal(pSPI(port));
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_setMaster()
*
* Description : determine whether the SPI is master(or slave). 设置SPI系统为主机还是从机
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
* isMaster TRUE set SPI port as master
* FALSE set SPI port as slave.
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
*
* Note:
*********************************************************************************************************
*/
unsigned char SPI_setMaster(unsigned char port,unsigned char isMaster){
portCheck();
SPI_isMaster_set_internal(pSPI(port),!!isMaster);
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_setSSctrl()
*
* Description : determine the function of SS pin. 设置SS引脚的功能
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
* option see SPI_SS_CTRL
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
* SPI_ARGUMENT_OUT if argument out of range.
* Note:
*********************************************************************************************************
*/
unsigned char SPI_setSSctrl(unsigned char port,unsigned char option){
pSPISTR pPort = pSPI(port);
portCheck();
argCheck(option,SPI_SS_LISTEN_MODF + 1,SPI_ARGUMENT_OUT);
switch(option){
case SPI_SS_CTRL_OFF:
SPI_isMODFEnable_set_internal(pPort,FALSE);
break;
case SPI_SS_CTRL_ON:
SPI_isMODFEnable_set_internal(pPort,TRUE);
SPI_isSSoutputEnable_set_internal(pPort,TRUE);
break;
case SPI_SS_LISTEN_MODF:
SPI_isMODFEnable_set_internal(pPort,TRUE);
SPI_isSSoutputEnable_set_internal(pPort,FALSE);
break;
}
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_setBehaviorInWaitMode()
*
* Description : determine what SPI system will do when cpu is in wait mode. 设置SPI在CPU为wait模式时的行为
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
* option see SPI_INWAITMODE
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
* SPI_ARGUMENT_OUT if argument out of range.
* Note:
*********************************************************************************************************
*/
unsigned char SPI_setBehaviorInWaitMode(unsigned char port,unsigned char option){
portCheck();
SPI_isStopInWait_set_internal(pSPI(port), option == SPI_INWAITMODE_STOP);
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_setSCKFormat()
*
* Description : determine the format of SPI clock. 设置SPI时钟格式
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
* option see SPI_SCKFMT
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
* SPI_ARGUMENT_OUT if argument out of range.
* Note:
*********************************************************************************************************
*/
unsigned char SPI_setSCKFormat(unsigned char port,unsigned char option){
pSPISTR pPort = pSPI(port);
portCheck();
argCheck(option,SPI_SCKFMT_MODE_3 + 1,SPI_ARGUMENT_OUT);
SPI_isHighIdle_set_internal(pPort,!!(option & 0x02));
SPI_isEvenSample_set_internal(pPort,option & 0x01);
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_setBaudRate()
*
* Description : determine the baud rate of SPI. 设置SPI系统的波特率
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
* SPR 0-7,SPI Baud Rate Selection Bits
* SPPR 0-7,SPI Baud Rate Preselection Bits
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
* SPI_ARGUMENT_OUT if argument out of range.
*
* Note : BaudRateDivisor = (SPPR + 1) * 2^(SPR + 1)
* BaudRate = Busclock / BaudRateDivisor
*********************************************************************************************************
*/
unsigned char SPI_setBaudRate(unsigned char port,unsigned char SPR,unsigned char SPPR){
pSPISTR pPort = pSPI(port);
portCheck();
argCheck(SPR,8,SPI_ARGUMENT_OUT);
argCheck(SPPR,8,SPI_ARGUMENT_OUT);
SPI_SPR_set_internal(pPort,SPR);
SPI_SPPR_set_internal(pPort,SPPR);
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_PutChar()
*
* Description : Transmit one char 发送一个字符/字节
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
* c the char to transmit; 要发送的字符;
*
* Return : SPI_NO_ERR if success.
* SPI_BAD_CH if invalid port used.
*
* Note: 1. this function will block until transmiter idle and transmit the char;
* 这个函数会阻塞到发送器空闲,然后发送字符
*********************************************************************************************************
*/
unsigned char SPI_PutChar(unsigned char port, unsigned char c){
portCheck();
SPI_waitUntilTxReady(pSPI(port));
SPI_putChar_internal(pSPI(port),c);
return SPI_NO_ERR;
}
/*
*********************************************************************************************************
* SPI_DataHasReceived()
*
* Description : To check whether there is a data in receive buffer. 检测是否接收寄存器中有数据
*
* Arguments : port SPI0-SPI2 the port to Choose. 选择端口.
*
* Return : 0xEE port invalid. 端口错误
* TRUE there is data in receive buffer. 接收寄存器内有数据
* FALSE receive buffer is empty. 接受寄存器为空
*
* Note: 1. this function just check whether there is a data now, and then return;
*********************************************************************************************************
*/
unsigned char SPI_DataHasReceived(unsigned char port){
portCheck2(0xEE);
return !!SPI_isDataReceived(pSPI(port));
}
/*
*********************************************************************************************************
* SPI_GetChar()
*
* Description : Receive one char 接收一个字符/字节
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
*
* Return : 0xEE port invalid or the char received is 0xEE; 端口错误或接收到的字符正好是0xEE;
* others the char received. 接收到的字符
*
* Note: 1.this function will block until receiver get a char,and return the char;
* 这个函数会阻塞到接收器寄存器满,然后返回字符
*********************************************************************************************************
*/
unsigned char SPI_GetChar(unsigned char port){
portCheck2(0xEE);
SPI_waitUntilDataReceived(pSPI(port));
return SPI_getChar_internal(pSPI(port));
}
/*
*********************************************************************************************************
* SPI_ExchangeChar()
*
* Description : Exchange one char with the peer. 接收一个字符/字节
*
* Arguments : port SPI0-SPI2 the port to Choose; 选择端口;
* c the char to transmit; 要发送的字符;
*
* Return : 0xEE port invalid or the char received is 0xEE; 端口错误或接收到的字符正好是0xEE;
* others the char received. 接收到的字符
*
* Note: 1.this function will block until receiver get a char,and return the char;
* 这个函数会阻塞到接收器寄存器满,然后返回字符
*********************************************************************************************************
*/
unsigned char SPI_ExchangeChar(unsigned char port, unsigned char c){
pSPISTR pPort = pSPI(port);
portCheck2(0xEE);
SPI_waitUntilTxReady(pPort);
SPI_putChar_internal(pPort,c);
SPI_waitUntilDataReceived(pPort);
return SPI_getChar_internal(pPort);
}
#endif // of SPI_MODULE_EN == TRUE
SPI与SCI有点区别,它是同步通信,也就是说每发出去一个字符一定会接收到一个字符,这就产生了非常蛋疼的主机从机怎么协调的问题:从机为了发送数据,必须提前先把数据写入寄存器,然后等待主机的时钟信号,在发送成功的同时收到主机发来的数据;而主机为了收到从机答复的数据,即使你没有数据要给从机,也必须往从机发送数据,才能一一对应的接收到从机发来的数据。
还有一点要注意的是,SPI是双缓冲的,换句话说,如果你的SPI主机连续发了三个字节,然后在提取字节的话可能会有多种情况(也可能分析有误或者不全面,敬请指出)。
1. 如果你提取的足够快,最后一个字符才刚放入发送寄存器还没有发出去,那你会先提取到第一个字节对应的返回字节,然后立刻可以提取第二个字节对应的返回字节。然而提取完后不一定立刻能提取第三个字节对应的返回字节,也可能传输的很快,直接就能提取了,也可能要过一会才能传输完成,然后才能提取。
2. 如果慢了一点,最后一个字节已经发出去了,那第二个字节对应的返回字节就会把第一个字节对应的给挤掉,所以你直接提取到的就是第二个字节对应的返回字节了。然后第三个能不能立刻提取到同上分析。
所以如果你只需要第三个字节对应的返回字节,那一种办法就是发完三个字节后等待足够长的时间,然后提取两个字节。第二个就是。另一种办法就是确保发送和接收一一对应,不发生丢数据的情况。
可以使用提供的SPI_DataHasReceived函数来检查是否接收寄存器中有数据,然后去提取,其他几个方法SPI_GetChar、SPI_PutChar和SPI_ExchangeChar都是阻塞式的方法,直到完成任务才会返回。
对于SPI主机,只要你保证全部都使用SPI_ExchangeChar来发送或接收数据就能保证数据的同步性。而对于SPI从机,你还需要保证在主机发送数据前已经调用了SPI_ExchangeChar。 或者就只能用等待足够长的时间的方法来保证数据同步性了。
使用示例:
先到SPI.h中进行各种初始化设置,然后初始化后使用SPI_ExchangeChar阻塞循环交互数据:
static void AppTaskStart (void *p_arg)
{
unsigned char strSend[] = "Tran:a\n";
#define STR_SEND_SIZE (sizeof(strSend)/sizeof(strSend[0]) - 1)
unsigned char strRecv[] = "Recv:a\n";
#define STR_RECV_SIZE (sizeof(strRecv)/sizeof(strRecv[0]) - 1)
unsigned char dataSend = 'A';
unsigned char dataRecv;
(void)p_arg; /* Prevent compiler warning */
BSP_Init();
Console_Init();
Console_Clear();
SPI_Init(SPI0);
SPI_Enable(SPI0);
while (DEF_TRUE)
{
strSend[5] = dataSend;
Console_PutChars_Mutex(strSend,STR_SEND_SIZE);
dataRecv = SPI_ExchangeChar(SPI0,dataSend++);
strRecv[5] = dataRecv;
Console_PutChars_Mutex(strRecv,STR_RECV_SIZE);
if(dataSend > 'Z')
dataSend = 'A';
OSTimeDlyHMSM(0,0,1,0);
}
}
其中 Console是我自己写的使用LCD屏的模拟控制台显示的模块,没有公开出来,当成printf来看就行了。