#include <windows.h>
#include <ceddk.h>
#include <nkintr.h>
#include <DrvLib.h>
//#include "oal_intr.h"
#include <s3c6410.h> // for 6410
//#include <s3c6410_gpio.h>
//#include <s3c6410_base_regs.h>
//#include <s3c6410_spi.h>
//#include "pmplatform.h"
//#include "Pkfuncs.h"
//#include <bsp.h>
#include "SPI.h"
#define SPI0_POWER_ON (1<<21)
#define SPI1_POWER_ON (1<<22)
#define SPI_SCLK_ON (1<<20)
#define CPOL_RISING (0<<3)
#define CPOL_FALLING (1<<3)
#define CPHA_FORMAT_A (0<<2)
#define CPHA_FORMAT_B (1<<2)
#define HIGH_SPEED_MASK (1<<6)
#define HIGH_SPEED_DIS (0<<6)
#define HIGH_SPEED_EN (1<<6)
#define SPI_CLKSEL (0<<9)
#define SPI_ENCLK (1<<8)
#define SPI_SCALER (0x04)
#define MODE_DEFAULT 0
#define SW_RST (1<<5)
#define SPI_MASTER (0<<4)
#define SPI_SLAVE (1<<4)
#define ENCLK_DISABLE (0<<8)
#define PACKET_CNT_EN (1<<16)
#define TRAIL_CNT(n) (((n)&0x3FF)<<19)
#define CH_WIDTH_16BIT (0x1<<29)
#define BUS_WIDTH_16BIT (0x1<<17)
#define CH_WIDTH_32BIT (0x2<<29)
#define BUS_WIDTH_32BIT (0xe<<17)
#define SPI0 0
#define SPI1 1
#define SPI_SELECT SPI1 //SPI通道选择,0表示SPI0,1表示SPI1
volatile S3C6410_GPIO_REG *pGPIOregs;
volatile S3C6410_SPI_REG *pSPIregs; // For HS-SPI
volatile S3C6410_SYSCON_REG *pSYSCONregs;
int g_iBusWidth=8; //位宽,8/16/32
PUCHAR readtempUCHAR; //8bit
PUCHAR writetempUCHAR; //8bit
PUSHORT readtempUSHORT; //16bit
PUSHORT writetempUSHORT; //16bit
PULONG readtempULONG; //32bit
PULONG writetempULONG; //32bit
BOOL WINAPI
DllEntry(HANDLE
hinstDLL,
DWORD dwReason,
LPVOID Reserved/* lpvReserved */)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
DEBUGREGISTER((HINSTANCE)hinstDLL);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
#ifdef UNDER_CE
case DLL_PROCESS_EXITING:
break;
case DLL_SYSTEM_STARTED:
break;
#endif
}
return TRUE;
}
BOOL SPI_Deinit(DWORD hDeviceContext)
{
if (pGPIOregs) {
DrvLib_UnmapIoSpace((PVOID)pGPIOregs);
}
if (pSPIregs) {
DrvLib_UnmapIoSpace((PVOID)pSPIregs);
}
if (pSYSCONregs) {
DrvLib_UnmapIoSpace((PVOID)pSYSCONregs);
}
pGPIOregs = NULL;
pSPIregs = NULL;
pSYSCONregs = NULL;
return TRUE;
}
DWORD SPI_Init(DWORD dwContext)
{
bool bRet = TRUE;
pGPIOregs = (S3C6410_GPIO_REG *)DrvLib_MapIoSpace(S3C6410_BASE_REG_PA_GPIO, sizeof(S3C6410_GPIO_REG), FALSE);
if (pGPIOregs == NULL) {
RETAILMSG(1,(TEXT("SPI GPIO: VirtualAlloc failed\r\n")));
}
pSPIregs = (S3C6410_SPI_REG *)DrvLib_MapIoSpace(S3C6410_BASE_REG_PA_SPI1, sizeof(S3C6410_SPI_REG), FALSE);
if (pSPIregs == NULL) {
RETAILMSG(1,(TEXT("SPI: VirtualAlloc failed\r\n")));
}
pSYSCONregs = (S3C6410_SYSCON_REG *)DrvLib_MapIoSpace(S3C6410_BASE_REG_PA_SYSCON, sizeof(S3C6410_SYSCON_REG), FALSE);
if (pSPIregs == NULL) {
RETAILMSG(1,(TEXT("SPI SYSCON: VirtualAlloc failed\r\n")));
}
bRet = pGPIOregs != NULL && pSPIregs != NULL && pSYSCONregs != NULL;
return bRet;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
BOOL SPI_IOControl(DWORD hOpenContext,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut)
{
switch(dwCode)
{
case 0:
g_iBusWidth=8;
pSPIregs->MODE_CFG = MODE_DEFAULT;
//
pSPIregs->PACKET_COUNT = PACKET_CNT_EN | 0x1;
break;
case 1:
g_iBusWidth=16;
pSPIregs->MODE_CFG |= CH_WIDTH_16BIT|BUS_WIDTH_16BIT;
//
pSPIregs->PACKET_COUNT = PACKET_CNT_EN | 0x1;
break;
case 2:
g_iBusWidth=32;
pSPIregs->MODE_CFG |= CH_WIDTH_32BIT|BUS_WIDTH_32BIT;
//
pSPIregs->PACKET_COUNT = PACKET_CNT_EN | 0x1;
break;
}
return TRUE;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
DWORD SPI_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode)
{
#if (SPI_SELECT == SPI0) //使用SPI0
//Configure HS-SPI Port Drive Strength
pGPIOregs->SPCON = pGPIOregs->SPCON & ~(0x3<<28) | (2<<28);
//Set GPIO for MISO, MOSI, SPICLK, SS
pGPIOregs->GPCPUD = pGPIOregs->GPCPUD & ~(0xFF<<0); //SPI0用的是GPC0~3,配置GPCPUD的0~7位为0禁止上拉/下拉
pGPIOregs->GPCCON = pGPIOregs->GPCCON & ~(0xFFFF<<0) | (2<<0) | (2<<4) | (2<<8) |(2<<12); //使用管脚GPC0~3,SPI0
// Clock On
pSYSCONregs->PCLK_GATE |= SPI0_POWER_ON;
//#if (SPI_CLOCK == EPLL_CLOCK)
// pSYSCONregs->SCLK_GATE |= SPI_SCLK_ON;
//#elif (SPI_CLOCK == USB_HOST_CLOCK)
// pSYSCONregs->SCLK_GATE |= SPI_USBHOST_ON;
//#endif
#endif
#if (SPI_SELECT == SPI1) //使用SPI1
//Configure HS-SPI Port Drive Strength
pGPIOregs->SPCON = pGPIOregs->SPCON & ~(0x3<<28) | (2<<28);
//Set GPIO for MISO, MOSI, SPICLK, SS
pGPIOregs->GPCPUD = pGPIOregs->GPCPUD & ~(0xFF<<8); //SPI1用的是GPC4~7,配置GPCPUD的8~15位为0禁止上拉/下拉
pGPIOregs->GPCCON = pGPIOregs->GPCCON & ~(0xFFFF<<16) | (2<<16) | (2<<20) | (2<<24) |(2<<28); //使用管脚GPC4~7,SPI1
// Clock On
pSYSCONregs->PCLK_GATE |= SPI1_POWER_ON;
//#if (SPI_CLOCK == EPLL_CLOCK)
pSYSCONregs->SCLK_GATE |= SPI_SCLK_ON;
//#elif (SPI_CLOCK == USB_HOST_CLOCK)
// pSYSCONregs->SCLK_GATE |= SPI_USBHOST_ON;
//#endif
#endif
//配置SPI寄存器
pSPIregs->CH_CFG = CPOL_RISING|CPHA_FORMAT_A; //上升沿有效,格式A第一个上升沿采样
pSPIregs->CH_CFG &= ~(HIGH_SPEED_MASK);
pSPIregs->CH_CFG |= (HIGH_SPEED_EN); //SPI时钟高于30MHz时需要设置
pSPIregs->CH_CFG |= SPI_MASTER; //主模式
pSPIregs->CLK_CFG = SPI_CLKSEL|SPI_ENCLK|SPI_SCALER; //使用时钟选择PCLK,时钟使能,分频系数1
pSPIregs->MODE_CFG = MODE_DEFAULT;
//配置片选寄存器
pSPIregs->SLAVE_SEL = (0x4>>2); // NSSOUT 配置为未启动模式
// pSPIregs->SLAVE_SEL = pSPIregs->SLAVE_SEL & (0x00<<2);
return TRUE;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
BOOL SPI_Close(DWORD hOpenContext)
{
pSPIregs->CLK_CFG &= (0xE<<8);
return TRUE;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void SPI_PowerDown(DWORD hDeviceContext)
{
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void SPI_PowerUp(DWORD hDeviceContext)
{
RETAILMSG(1,(TEXT("SPI: PowerUp\r\n")));
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
DWORD SPI_Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count)
{
int i;
int RealByteNum=0;
//Reset
pSPIregs->CH_CFG |= SW_RST;
//
Sleep(5);
pSPIregs->CH_CFG &= ~SW_RST;
pSPIregs->CH_CFG = CPOL_RISING|CPHA_FORMAT_A; //上升沿有效,格式A第一个上升沿采样
pSPIregs->CH_CFG &= ~(HIGH_SPEED_MASK);
pSPIregs->CH_CFG |= (HIGH_SPEED_EN); //SPI时钟高于30MHz时需要设置
pSPIregs->CH_CFG |= SPI_MASTER; //主模式
//
pSPIregs->MODE_CFG = MODE_DEFAULT;
if(g_iBusWidth==8)
{
readtempUCHAR=(PUCHAR)pBuffer;
pSPIregs->MODE_CFG = MODE_DEFAULT;
pSPIregs->PACKET_COUNT = PACKET_CNT_EN | Count;
}
if(g_iBusWidth==16)
{
readtempUSHORT=(PUSHORT)pBuffer;
pSPIregs->MODE_CFG |= CH_WIDTH_16BIT|BUS_WIDTH_16BIT;
pSPIregs->PACKET_COUNT = PACKET_CNT_EN | (Count/2);
}
if(g_iBusWidth==32)
{
readtempULONG=(PULONG)pBuffer;
pSPIregs->MODE_CFG |= CH_WIDTH_32BIT|BUS_WIDTH_32BIT;
pSPIregs->PACKET_COUNT = PACKET_CNT_EN | (Count/4);
}
//配置片选寄存器
pSPIregs->SLAVE_SEL = (0x4>>2); // NSSOUT 配置为未启动模式
pSPIregs->CH_CFG |= (0x1<<1); //SPI RX Channel On
//
pSPIregs->PACKET_COUNT = PACKET_CNT_EN | (Count/2);
pSPIregs->SLAVE_SEL &= (0xF0>>3); // NSSOUT 配置为启动模式
pSPIregs->CLK_CFG = SPI_CLKSEL|SPI_ENCLK|SPI_SCALER; //使用时钟选择PCLK,时钟使能,分频系数1
while(Count >0)
{
int TimeCount=0;
int TotalTimeOut = 5000*100*50 + (1)*Count;
while (((pSPIregs ->SPI_STATUS>>13)&0x7f) == 0x0) //没有读取到数据,等待
{
;
}
if(g_iBusWidth==8)
{
*(PUCHAR)readtempUCHAR = pSPIregs->SPI_RX_DATA;
readtempUCHAR++;
RealByteNum++;
Count--;
}
if(g_iBusWidth==16)
{
*(PUSHORT)readtempUSHORT = pSPIregs->SPI_RX_DATA;
readtempUSHORT++;
RealByteNum=RealByteNum+2;
Count=Count-2;
}
if(g_iBusWidth==32)
{
*(PULONG)readtempULONG = pSPIregs->SPI_RX_DATA;
readtempULONG++;
RealByteNum=RealByteNum+4;
Count=Count-4;
}
//
RealByteNum++;
// Delay(100);
}
pSPIregs->CLK_CFG &= (0xE<<8);
pSPIregs->CH_CFG &= ~(0x2); //SPI RX Channel OFF
pSPIregs->SLAVE_SEL |= (0x1); // NSSOUT 配置为未启动模式
return RealByteNum;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
DWORD SPI_Seek(DWORD hOpenContext, long Amount, DWORD Type)
{
return 0;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
DWORD SPI_Write(DWORD hOpenContext, LPCVOID pSourceBytes, DWORD NumberOfBytes)
{
if(g_iBusWidth==8)
{
writetempUCHAR=(PUCHAR)pSourceBytes;
}
if(g_iBusWidth==16)
{
writetempUSHORT=(PUSHORT)pSourceBytes;
}
if(g_iBusWidth==32)
{
writetempULONG=(PULONG)pSourceBytes;
}
int i;
pSPIregs->CH_CFG |= (0x1); //SPI TX Channel On
Sleep(5);
pSPIregs->SLAVE_SEL &= (0xF0>>3); // NSSOUT 配置为启动模式
int RealByteNum=0;
for(i=0;i<NumberOfBytes;i++)
{
if(g_iBusWidth==8)
{
pSPIregs->SPI_TX_DATA = *(PUCHAR)writetempUCHAR;
}
if(g_iBusWidth==16)
{
pSPIregs->SPI_TX_DATA = *(PUSHORT)writetempUSHORT;
}
if(g_iBusWidth==32)
{
pSPIregs->SPI_TX_DATA = *(PULONG)writetempULONG;
}
int TimeOut=0;
while(((pSPIregs ->SPI_STATUS>>6) & 0x7f)) //发送缓冲区有数据
{
TimeOut++;
if(TimeOut == 1000)
{
// Timeout
//RETAILMSG (TRUE, (TEXT("Write timeout!!!\r\n")));
return 0;
break;
}
}
if(g_iBusWidth==8)
{
writetempUCHAR++;
}
if(g_iBusWidth==16)
{
writetempUSHORT++;
}
if(g_iBusWidth==32)
{
writetempULONG++;
}
RealByteNum++;
// Delay(100);
}
pSPIregs->CH_CFG &= ~(0x1); //SPI RX Channel OFF
pSPIregs->SLAVE_SEL |= (0x1); // NSSOUT 配置为未启动模式
return RealByteNum;
}
/*****************************************************************
*
函数名
: Delay
*
功能
: 延时
*
输入参数:
*
dwTime
*
输出参数:
*
返回值
: void
******************************************************************/
BOOL Delay( DWORD dwTime )
{
DWORD n,m;
for(n = 0; n<dwTime; n++)
for(m = 0; m<20300;m++);
return TRUE;
}
PACKET_COUNT 的值要设定好,这个值就是你的设置的位宽后的数据个数,每次收发数据重置寄存器