Serial Peripheral Interface驱动



#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 的值要设定好,这个值就是你的设置的位宽后的数据个数,每次收发数据重置寄存器








你可能感兴趣的:(Serial Peripheral Interface驱动)