//=====================================================================
//文件名称：SPI.c
//功能概要：SPI底层驱动构件源文件
//版权所有：苏州大学飞思卡尔嵌入式中心(sumcu.suda.edu.cn)
//更新记录：2016-03-17  V2.2
//        2016-05-11  V3.0
//=====================================================================
#include "spi.h"


//=====================================================================
//函数名称：spi_init。
//功能说明：SPI初始化
//函数参数：No：模块号，KL36芯片取值为SPI_0、SPI_1
//       MSTR：SPI主从机选择，0选择为从机,1选择为主机。
//       BaudRate：波特率，可取12000、6000、4000、3000、1500、1000，单位：bps
//       CPOL：CPOL=0：高有效SPI时钟（低无效）；CPOL=1：低有效SPI时钟（高无效）
//       CPHA：CPHA=0相位为0； CPHA=1相位为1；
//函数返回：无
//=====================================================================
void spi_init(uint_8 No,uint_8 MSTR,uint_16 BaudRate,\
		uint_8 CPOL,uint_8 CPHA)
{
    uint_8 BaudRate_Mode;
    uint_8 BaudRate_High;
    uint_8 BaudRate_Low;
    if(No<SPI_0||No>SPI_1)   No=SPI_0;    //如果SPI号参数错误则强制选择 0号模块
    if(No==SPI_0)                         //初始化SPI0功能
    {
        BSET(SIM_SCGC4_SPI0_SHIFT,SIM_SCGC4);   //打开SPI0模块时钟。
        //引脚复用为SPI0功能
        PORTC_PCR4=(0|PORT_PCR_MUX(0x02));        //选择PTC4的SS功能
        PORTC_PCR5=(0|PORT_PCR_MUX(0x02));        //选择PTC5的SCK功能
        PORTC_PCR6=(0|PORT_PCR_MUX(0x02));        //选择PTC6的MOSI功能
        PORTC_PCR7=(0|PORT_PCR_MUX(0x02));        //选择PTC7的MIOS功能

        SPI0_C1=0x00;                           //SPI控制寄存器1清零
        BSET(SPI_C1_SPE_SHIFT,SPI0_C1);         //使能SPI模块

        //MSTR=1为主机模式；
        //MSTR=0为从机模式（因MSTR初始值为0，无需更改）
        (MSTR==1)?BSET(SPI_C1_MSTR_SHIFT,SPI0_C1):\
                       BSET(SPI_C1_SPIE_SHIFT,SPI0_C1);

        //时钟极性配置，CPOL=0，平时时钟为高电平，反之CPOL=1，平时时钟为低电平
        (0==CPOL)?BCLR(SPI_C1_CPOL_SHIFT,SPI0_C1):\
                        BSET(SPI_C1_CPOL_SHIFT,SPI0_C1);

        //时钟相位CPHA
        (0 == CPHA)?BCLR(SPI_C1_CPHA_SHIFT,SPI0_C1):\
                              BSET(SPI_C1_CPHA_SHIFT,SPI0_C1);

        ////SSOE为1,MODFEN为1，配置本模块为自动SS输出
        BSET(SPI_C1_SSOE_SHIFT,SPI0_C1);
        //对SPI0的C1寄存器配置为主机模式、从机选择自动模式并使能SPI0模块。
        SPI0_C2=0x00;
        if(MSTR == 1 )  //主机模式
            BSET(SPI_C2_MODFEN_SHIFT,SPI0_C2);
        SPI0_BR = 0x00U;//波特率寄存器清零
        //重新设置波特率
        BaudRate_High=0;
        BaudRate_Low=0;
        BaudRate_Mode=12000/BaudRate;
        while(BaudRate_Mode % 2 == 0)
        {
            BaudRate_Mode=BaudRate_Mode/2;
            BaudRate_Low++;
        }
        BaudRate_High=--BaudRate_Mode;
        SPI0_BR=BaudRate_High<<4;//数值赋给SPI0_BR的SPPR的D6D5D4位
        SPI0_BR|=BaudRate_Low;//赋值给SPI0_BR的SPR的 D2D1D0位

    }
     else         //初始化SPI1功能
    {
        BSET(SIM_SCGC4_SPI1_SHIFT,SIM_SCGC4);   //打开SPI1模块时钟。
        //引脚复用为SPI1功能
        PORTD_PCR4=(0|PORT_PCR_MUX(0x02));        //选择PTD4的SS功能
        PORTD_PCR5=(0|PORT_PCR_MUX(0x02));        //选择PTD5的SCK功能
        PORTD_PCR6=(0|PORT_PCR_MUX(0x02));        //选择PTD6的MOSI功能
        PORTD_PCR7=(0|PORT_PCR_MUX(0x02));        //选择PTD7的MIOS功能

        SPI1_C1=0x00;                     //SPI控制寄存器1清零
        BSET(SPI_C1_SPE_SHIFT,SPI1_C1);   //使能SPI模块
        //MSTR=1为主机模式；
        //MSTR=0为从机模式（因MSTR初始值为0，无需更改）
        (MSTR==1)?BSET(SPI_C1_MSTR_SHIFT,SPI1_C1):\
                                            BSET(SPI_C1_SPIE_SHIFT,SPI1_C1);

        //时钟极性配置，CPOL=0，平时时钟为高电平，反之CPOL=1，平时时钟为低电平
        (0 == CPOL)?BCLR(SPI_C1_CPOL_SHIFT,SPI1_C1):\
                                            BSET(SPI_C1_CPOL_SHIFT,SPI1_C1);

        //CPHA=0时钟信号的第一个边沿出现在8周期数据传输的第一个周期的中央；
        //CPHA=1时钟信号的第一个边沿出现在8周期数据传输的第一个周期的起点。
        (0 == CPHA)?BCLR(SPI_C1_CPHA_SHIFT,SPI1_C1): \
                                            BSET(SPI_C1_CPHA_SHIFT,SPI1_C1);

        BSET(SPI_C1_SSOE_SHIFT,SPI1_C1);//SSOE为1,MODFEN为1，配置本模块为自动SS输出
        //对SPI0的C1寄存器配置为主机模式、从机选择自动模式并使能SPI0模块。

//        BSET(SPI_C1_SPIE_SHIFT,SPI1_C1);  //开本模块的SPI中断
        SPI1_C2 = 0x00U;
        if(MSTR == 1 )  //主机模式
            BSET(SPI_C2_MODFEN_SHIFT,SPI1_C2);
        SPI1_BR = 0x00U;
        //重新设置波特率
        BaudRate_High=0;
        BaudRate_Low=0;
        BaudRate_Mode=12000/BaudRate;   //取除数用于寄存器中数据计算
        while(BaudRate_Mode % 2 == 0)
        {
            BaudRate_Mode=BaudRate_Mode/2;
            BaudRate_Low++;
        }
        BaudRate_High=--BaudRate_Mode;
        SPI1_BR=BaudRate_High<<4;//数值赋给SPI0_BR的SPPR的D6D5D4位
        SPI1_BR|=BaudRate_Low;//赋值给SPI0_BR的SPR的 D2D1D0位
    }
}

//=====================================================================
//函数名称：spi_send1.
//功能说明：SPI发送一字节数据。
//函数参数：No：模块号。 其取值为0或1
//       data：     需要发送的一字节数据。
//函数返回：0：发送失败；1：发送成功。
//=====================================================================
uint_8 spi_send1(uint_8 No,uint_8 data)
{
    uint_32 i;
    SPI_MemMapPtr baseadd=SPI_baseadd(No);
    while(!(SPI_S_REG(baseadd)&SPI_S_SPTEF_MASK));//等待发送缓冲区空闲
        SPI_DL_REG(baseadd)=data;//数据寄存器接收数据
    for(i=0;i<0xFFF0;i++)        //在一定时间内发送不能完成，则认为发送失败。
    {
        if(SPI_S_REG(baseadd)&SPI_S_SPTEF_MASK)//判断发送缓冲区是否接到数据
        {
            return(1);
        }
     }
    return(0);
}

//=====================================================================
//函数名称：spi_sendN.
//功能说明：SPI发送数据。
//函数参数：No：模块号。 其取值为0或1
//       n:     要发送的字节个数。范围为(1~255)
//       data[]:所发数组的首地址。
//函数返回：无。
//=====================================================================
void spi_sendN(uint_8 No,uint_8 n,uint_8 data[])
{
    SPI_MemMapPtr baseadd=SPI_baseadd(No);
    uint_32 k;
    for(k=0;k<n;k++)
    {
        //状态寄存器的SPTEF位不空
        while(!(SPI_S_REG(baseadd)&SPI_S_SPTEF_MASK));
        SPI_DL_REG(baseadd)=data[k];
           SPI_S_REG(baseadd) !=  SPI_S_SPTEF_MASK;    //清除SPTEF位
    }
}

//=====================================================================
//函数名称：spi_receive1.
//功能说明：SPI接收一个字节的数据
//函数参数：No：模块号。 其取值为0或1
//函数返回：接收到的数据。
//=====================================================================
uint_8 spi_receive1(uint_8 No)
{
    SPI_MemMapPtr baseadd=SPI_baseadd(No);
    while(!(SPI_S_REG(baseadd)& SPI_S_SPRF_MASK));    //检测SPI是否收到了数据。
        return SPI_DL_REG(baseadd);
}

//=====================================================================
//函数名称：spi_receiveN.
//功能说明：SPI接收数据。当n=1时，就是接受一个字节的数据……
//函数参数：No：模块号。 其取值为0或1
//          n:    要发送的字节个数。范围为(1~255),
//       data[]:接收到的数据存放的首地址。
//函数返回：1：接收成功,其他情况：失败。
//=====================================================================
uint_8 spi_receiveN(uint_8 No,uint_8 n,uint_8 data[])
{
    SPI_MemMapPtr baseadd=SPI_baseadd(No);
    uint_32 m=0;
    while(m<n)
    {
        if(SPI_S_REG(baseadd)&SPI_S_SPRF_MASK)
        {
             data[m]=SPI_DL_REG(baseadd);
                 m++;
        }
    }
    return(1);
}

//=====================================================================
//函数名称：spi_enable_re_int
//功能说明：打开SPI接收中断。
//函数参数：No：模块号。 其取值为0或1。
//函数返回：无。
//=====================================================================
void spi_enable_re_int(uint_8 No)
{
    enable_irq (No+10);
}

//=====================================================================
//函数名称：spi_disable_re_int
//功能说明：关闭SPI接收中断。
//函数参数：No：模块号。 其取值为0或1。
//函数返回：无。
//=====================================================================
void spi_disable_re_int(uint_8 No)
{
    disable_irq (No+10);
}

//============================================================================
//文件名称：spi.c
//功能概要：KW01 spi底层驱动程序源文件
//版权所有：苏州大学飞思卡尔嵌入式中心(sumcu.suda.edu.cn)
//版    本：V3.0(WYH),20140909
//============================================================================

//无线模块专用
//============================================================================
//函数名称：MKW01Drv_SpiInit()
//函数返回：val
//参数说明：addr：无线模块寄存器地址
//功能概要：读取无线模块寄存器
//============================================================================
void MKW01Drv_SPI0_Init()
{
    /* Enable Reset PORT clock */
    SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK;//(1<<13); /*Reset Radio Clock Gate Control enable*/

    //使能复位引脚，复位引脚E30复用GPIO功能,【输出】RF硬件复位，
    //以便于软件取得完全控制，否则无法启动MCU（它会一直检测REST_RF是否被拉高）
    PORTE_PCR30 &= ~PORT_PCR_MUX_MASK;
    PORTE_PCR30 |= PORT_PCR_MUX(1);//复用GPIO功能
    GPIOE_PDDR |= (1<<30);//输出

    /* 使能SPI端口时钟 */
    SIM_SCGC5 |= (1<<11);         /*SPI Port Clock Gate Control enable*/

    /* 打开SPI0时钟门*/
    SIM_SCGC4 |=  (1<<22);        /*SPI Clock Gate Control enable*/

    /*初始化化SPI控制寄存器*/
    PORTD_PCR0&= ~PORT_PCR_MUX_MASK;      //D0----PCS
    PORTD_PCR0|= PORT_PCR_MUX(1);         //PTD0 作为从机选择线
    GPIOD_PDDR|=(1<<0);                   //引脚定义为输出

    PORTC_PCR5  &= ~PORT_PCR_MUX_MASK;    //C5----SCK
    PORTC_PCR5  |= PORT_PCR_MUX(2);
    PORTC_PCR6 &= ~PORT_PCR_MUX_MASK;     //C6----MOSI
    PORTC_PCR6 |= PORT_PCR_MUX(2);
    PORTC_PCR7 &= ~PORT_PCR_MUX_MASK;     //C7----MISO
    PORTC_PCR7 |= PORT_PCR_MUX(2);

    //保持射频芯片处于复位状态（即E口的30号脚数据输出寄存器始终置1，即输出高电平，复位RF）
    MKW01DRV_ASSERTRESET(); //Keep Radio in reset

    /* Initialize the SPI peripheral base address */
    SPI0_BASE_PTR->C1 = CSPIC1_INIT;//控制寄存器1
    SPI0_BASE_PTR->C2 = CSPIC2_INIT;//控制寄存器2
    SPI0_BR = CSPIBR_INIT;
    SPI0_BASE_PTR->C1 |= (uint_8)(SPI_C1_SPE_MASK | SPI_C1_MSTR_MASK) ; //enable SPI system
    SPIS_DUMMYREAD;
    DEASSERTSS;
}


//============================================================================
//函数名称：MKW01Drv_ReadRegister
//函数返回：val
//参数说明：addr：无线模块寄存器地址
//功能概要：读取无线模块寄存器
//============================================================================
uint_8 MKW01Drv_ReadRegister(uint_8 addr)
{
    uint_8 val;
    uint_32 CCR;

    CCR = IntDisableAll();//关中断

    SPIS_DUMMYREAD;  //空读SPI0状态寄存器
    ASSERTSS;       //片选，配置C口的第4号脚的清输出寄存器为1，则清除对应数据输出寄存器PDOR的位
    SPI0_BASE_PTR->DL = (unsigned char)(addr);
    WAIT_SPITX_BUFFER_EMPTY; //等待SPI0发送缓冲区为空
    SPID_DUMMYREAD;    //空读SPI0数据寄存器
    SPI0_BASE_PTR->DL = 0x00;
    WAIT_SPITX_BUFFER_EMPTY;  //等待SPI0发送缓冲区为空
    SPID_DUMMYREAD;     //空读SPI0数据寄存器
    WAIT_SPIRX_BUFFER_FULL;   //等待接收缓冲区为满   （保证主机已将数据发出，并且从机收到）
    val = SPI0_BASE_PTR->DL;   //读取数据寄存器中的值
    DEASSERTSS;      //片选，配置C口的PDOR寄存器第4位为1
    IntRestoreAll(CCR);  //开中断
    return val;
}

//============================================================================
//函数名称：MKW01Drv_WriteRegister
//函数返回：无
//参数说明：addr：无线模块寄存器地址；val：待写入的值
//功能概要：设置无线模块寄存器
//============================================================================
void MKW01Drv_WriteRegister(uint_8 addr, uint_8 val)
{
    uint_32 CCR;
    CCR = IntDisableAll();
    SPIS_DUMMYREAD;
    ASSERTSS;                    //从机片选信号（低电压选中从机，）
    SPI0_BASE_PTR->DL = (unsigned char)(addr | 0x80);
    WAIT_SPITX_BUFFER_EMPTY;      //等待，直到发送缓冲区为空
    SPID_DUMMYREAD;
    SPI0_BASE_PTR->DL = (unsigned char)(val);
    WAIT_SPITX_BUFFER_EMPTY;     //等待，直到发送缓冲区为空
    SPID_DUMMYREAD;
    WAIT_SPIRX_BUFFER_FULL;    //等待，直到移位缓冲区接收到从机发来的数据，这可以用来保证TX发送的数据已被从机已经接收到
    DEASSERTSS;
    IntRestoreAll(CCR);
}

//============================================================================
//函数名称：MKW01Drv_WriteRegisterFast
//函数返回：不安全的函数,只有在禁止中断时才可使用
//参数说明：addr：无线模块寄存器地址；val：待写入的值
//功能概要：设置无线模块寄存器
//============================================================================
void MKW01Drv_WriteRegisterFast(uint_8 addr, uint_8 val)
{
    SPIS_DUMMYREAD;
    ASSERTSS;
    SPI0_BASE_PTR->DL = (unsigned char)(addr | 0x80);  // 写目的地址
    WAIT_SPITX_BUFFER_EMPTY;                        //等待发送缓冲区为空
    SPID_DUMMYREAD;
//    SPI0_BASE_PTR->DL = (unsigned char)(val);    //写数据
    WAIT_SPITX_BUFFER_EMPTY;
    SPID_DUMMYREAD;
    WAIT_SPIRX_BUFFER_FULL;                        //等待，直到移位缓冲区接收到从机发来的数据，这可以用来保证TX发送的数据已被从机已经接收到
    DEASSERTSS;
}

