📄 spi.c
字号:
/***********************************************Copyright (c)*********************************************
** Guangzou ZLG-MCU Development Co.,LTD.
**
** http://www.zlgmcu.com
**
**--------------File Info---------------------------------------------------------------------------------
** File name: SPI.c
** Last modified Date: 2007-10-15
** Last Version: 1.0
** Descriptions: SPI函数实现,采用设备描述符来操作
**
**--------------------------------------------------------------------------------------------------------
** Created by: lixiaocheng
** Created date: 2007-10-15
** Version: 1.0
** Descriptions: 无
**
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date:
** Version:
** Descriptions:
**
*********************************************************************************************************/
#include "Config.h"
#include "SpiPrivate.h"
#include "Spi.h"
/*********************************************************************************************************
定义操作SPI操作结构体,有多个器件就需要声明多个结构体
*********************************************************************************************************/
static __SPI_INFO __GsiData0;
/*********************************************************************************************************
下面使用指针数组来保存结构体指针,方便对该驱动的扩展
*********************************************************************************************************/
const __PSPI_INFO __GpsiDataTab[__SPI_MAX_NUM] = { &__GsiData0};
/*********************************************************************************************************
下面定义了SPI基地址值,如果有多个SPI器件可以在该位置添加相应的基地址即可
*********************************************************************************************************/
const uint32 __GuiSpiBaseAddrTab[__SPI_MAX_NUM] = { SPI0_BASE_ADDR};
/*********************************************************************************************************
定义驱动使用的数据缓冲区数组
*********************************************************************************************************/
static uint8 __GucSpiSendQueue[__SPI_MAX_NUM][__SPI_MAX_SEND_QUEUE];
static uint8 __GucSpiRecvQueue[__SPI_MAX_NUM][__SPI_MAX_RECV_QUEUE];
/*********************************************************************************************************
** Function name: __spiInit()
** Descriptions: SPI初始化函数,内部使用
** Input parameters: ID 设备号,例如0表示使用SPI0
** PARM 传入参数的结构体
** Output parameters: NONE
** Returned value: 初始化失败: OPERATE_FAIL
** 管脚连接错误: PIN_ERR
** 初始化成功: OPERATE_SUCCESS
*********************************************************************************************************/
static int32 __spiInit( uint32 ID, __SPI_PARM PARM )
{
volatile uint32 *puiBaseAddr;
uint32 uiOffBase;
uint32 uiSpeed;
/*
* 参数过滤
*/
if (ID >= __SPI_MAX_NUM) {
return OPERATE_FAIL;
}
if (PARM.uiSpiSpeed > Fpclk/8) { /* 过滤速度 */
PARM.uiSpiSpeed = Fpclk/8;
}
if (PARM.uiSpiSpeed == 0) { /* 过滤速度 */
return OPERATE_FAIL;
}
if (PARM.ucpha > __SPI_PHA_H) { /* 过滤相位 */
return OPERATE_FAIL;
}
if (PARM.ucpol > __SPI_POL_L) { /* 过滤CLK高低电平 */
return OPERATE_FAIL;
}
if (PARM.uclsb > __SPI_LSB) { /* 过滤LSB参数 */
return OPERATE_FAIL;
}
if (PARM.ucpie > __SPI_INT_EN) { /* 判断中断设置参数 */
return OPERATE_FAIL;
}
/*
* 管脚链接判断
*/
if (ID == 0) {
if (((PINSEL0 >> 8) & 3) != P0_04_SCK0 || /* SCKO */
((PINSEL0 >> 10) & 3) != P0_05_MISO0 || /* MISO0 */
((PINSEL0 >> 12) & 3) != P0_06_MOSI0 || /* MOSI0 */
((PINSEL0 >> 14) & 3) != P0_07_SSEL0 ) { /* SSEL0 */
return PIN_ERR;
}
} else {
if (((PINSEL0 >> 28) & 3) != P0_14_SCK1 || /* SCK1 */
((PINSEL1 >> 6 ) & 3) != P0_19_MISO1 || /* MISO1 */
((PINSEL1 >> 8 ) & 3) != P0_20_MOSI1 || /* MOSI1 */
((PINSEL1 >> 10) & 3) != P0_21_SSEL1 ) { /* SSEL1 */
return PIN_ERR;
}
}
/*
* 初始化设备结构体
*/
QueueCreate(__GucSpiSendQueue[ID], sizeof(__GucSpiSendQueue[ID]), NULL, NULL);
/* 初始化发送队列 */
QueueCreate(__GucSpiRecvQueue[ID], sizeof(__GucSpiRecvQueue[ID]), NULL, NULL);
/* 初始化接收队列 */
__GpsiDataTab[ID]->puiAddrBase = (uint32 *)__GuiSpiBaseAddrTab[ID];
__GpsiDataTab[ID]->uiOffBase = 0;
__GpsiDataTab[ID]->ucSpiflag = SPI_IDLE;
__GpsiDataTab[ID]->ucSlave = __SPI_MASTER;
__GpsiDataTab[ID]->sendQueue = (__PDATA_QUEUE)__GucSpiSendQueue[ID];
__GpsiDataTab[ID]->recvQueue = (__PDATA_QUEUE)__GucSpiRecvQueue[ID];
/*
* 初始化部件功能参数
*/
puiBaseAddr = __GpsiDataTab[ID]->puiAddrBase;
uiOffBase = __GpsiDataTab[ID]->uiOffBase;
puiBaseAddr[__B_SPI_PCR<<uiOffBase] = (PARM.ucpha << 3) | /* 初始化相位等参数 */
(PARM.ucpol << 4) | /* 初始化时钟极性 */
(__SPI_MASTER << 5) | /* 初始化SPI为主机 */
(PARM.uclsb << 6) | /* 初始化高低字节先后顺序 */
(PARM.ucpie << 7); /* 初始化中断是否使能 */
uiSpeed = ((Fpclk/PARM.uiSpiSpeed) % 2) ? (Fpclk/PARM.uiSpiSpeed)+1 : (Fpclk/PARM.uiSpiSpeed);
if (uiSpeed > 255) { /* 因为SPICCR是8位的 */
uiSpeed = 254;
}
puiBaseAddr[__B_SPI_CCR<<uiOffBase] = uiSpeed; /* 确保初始化的速度为偶数 */
return OPERATE_SUCCESS;
}
/*********************************************************************************************************
** Function name: spiInit()
** Descriptions: SPI初始化函数,使用字符串传入参数
** Input parameters: uiParmID 设备号,例如0表示使用SPI0
** pcParmArg 传入参数的字符串指针,参数列表和取值意义如下
** Spiclk: spi的通讯速率,范围Fpclk/254 ~ Fpclk/8
** Cpha : 0为第一个时钟采样,1为第二个时钟采样
** Cpol : 0为CLK高电平有效,1为CLK低电平有效
** Lsbf : 0表示MSB在先,1表示LSB在先
** pvRsv 保留参数
** Output parameters: NONE
** Returned value: 初始化失败: OPERATE_FAIL
** 管脚连接错误: PIN_ERR
** 初始化成功: OPERATE_SUCCESS
*********************************************************************************************************/
int32 spiInit (uint32 uiParmID,
char *pcParmArg,
void *Rsv)
{
__SPI_PARM spParm;
uint32 uiParmTable[4] = {-1, -1, -1, -1};
Rsv = Rsv; /* 防止编译报警 */
ImpCmd(Tab_SPI, pcParmArg, uiParmTable); /* 转换字符按串参数 */
spParm.uiSpiSpeed = uiParmTable[Spiclk];
spParm.ucpha = (uint8)uiParmTable[Cpha];
spParm.ucpol = (uint8)uiParmTable[Cpol];
spParm.uclsb = (uint8)uiParmTable[Lsbf];
spParm.ucpie = __SPI_INT_EN; /* 始终使能SPI中断 */
return __spiInit(uiParmID, spParm); /* 传入参数进行初始化 */
}
/*********************************************************************************************************
** Function name: spiWrite()
** Descriptions: SPI写函数
** Input parameters: uiParmID 设备号,例如0表示使用SPI0
** pucParmData 写入数据首指针
** uiParmLen 要写入数据的长度
** ucFlag 写模式,0为写的同时丢弃返回值,1为保留返回值,返回值的获取通过
** spiRead()获取。
** Output parameters: NONE
** Returned value: 写失败: OPERATE_FAIL
** >=0 已发送数据个数
*********************************************************************************************************/
int32 spiWrite (uint32 uiParmID,
uint8 *pucParmData,
uint32 uiParmLen,
uint8 ucFlag)
{
volatile uint32 *puiBaseAddr;
uint32 uiOffBase;
uint32 i;
/*
* 参数过滤
*/
if (uiParmID >= __SPI_MAX_NUM) {
return OPERATE_FAIL;
}
if (uiParmLen == 0) { /* 不允许发送0个字节数据 */
return OPERATE_FAIL;
}
if (__GpsiDataTab[uiParmID]->ucSpiflag == SPI_READ) { /* 设备正在读返回错误 */
return OPERATE_FAIL;
}
if (__GpsiDataTab[uiParmID]->ucSlave == __SPI_SLAVE) { /* 是从设备返回错误 */
return OPERATE_FAIL;
}
if (ucFlag > SPI_SAVE_BACK) { /* 检查用户输入宏是否正确 */
return OPERATE_FAIL;
}
puiBaseAddr = __GpsiDataTab[uiParmID]->puiAddrBase; /* 获得设备地址 */
uiOffBase = __GpsiDataTab[uiParmID]->uiOffBase;
if (__GpsiDataTab[uiParmID]->ucSpiflag == SPI_IDLE) { /* 设备空闲,就发送数据 */
__SPI_CS_ENABLE(__GpsiDataTab[uiParmID]->uiSpiCsPin); /* 使能片选 */
__GpsiDataTab[uiParmID]->ucSpiflag = SPI_WRITE; /* 标识设备为写状态 */
__GpsiDataTab[uiParmID]->ucWriteMode = ucFlag; /* 确定写模式 */
IRQDisable(); /* 关中断等待数据入队结束 */
puiBaseAddr[__B_SPI_PDR << uiOffBase] = *pucParmData; /* 发送数据到SPI数据寄存器 */
uiParmLen--; /* 调整数据长度 */
pucParmData++; /* 调整数据首指针 */
} else {
if (__GpsiDataTab[uiParmID]->ucWriteMode != ucFlag) { /* 发现写操作与当前写操作模式 */
/* 不同,则不允许把两次写重叠 */
return OPERATE_FAIL;
}
IRQDisable(); /* 关中断等待数据入队结束 */
}
for (i = 0; i < uiParmLen; i++) { /* 数据入队 */
if (QueueWrite(__GpsiDataTab[uiParmID]->sendQueue, pucParmData[i]) != QUEUE_OK) {
IRQEnable(); /* 数据入队结束,开中断 */
return i; /* 返回已发送数据个数 */
}
}
IRQEnable(); /* 数据入队结束,开中断 */
return uiParmLen; /* 已全部发送成功 */
}
/*********************************************************************************************************
** Function name: spiReadStart()
** Descriptions: SPI读启动函数
** Input parameters: uiParmID 设备号,例如0表示使用SPI0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -