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

#include "uart.h"

//串口1、2号地址映射
static const UART_MemMapPtr UART_ARR[] = {UART1_BASE_PTR, UART2_BASE_PTR};

//===========================================================================
//函数名称：uart_init
//功能概要：初始化uart模块                                                
//参数说明：uartNo:串口号：UART_0、UART_1、UART_2 
//         sysclk:串口时钟源:MCGIRCLK(4MHz)、MCGFLLCLK(48MHz)、BUSCLK(24MHz)                            
//         baud:波特率：300、600、1200、2400、4800、9600、19200、115200...
//函数返回：无
//说明：当参数为UART_0时，sel_clk只能选择MCGIR_CLK或MCGFLL_CLK，
//      若选择内部时钟MCGIR_CLK,波特率需小于19200； 当参数为UART_1或是UART_2时，
//      sel_clk只能选择BUS_CLK
//===========================================================================
void uart_init(uint_8 uartNo, uint_32 sel_clk, uint_32 baud)
{
    register uint_16 sbr;
    uint_8 temp;
    UART0_MemMapPtr uartch1 = UART0_BASE_PTR;
    UART_MemMapPtr uartch2;
    uint_32 clk_Khz;
    
    if(uartNo == UART_0) 
    {
        switch(sel_clk)
        {
        case MCGIRCLK://启用并选择UART0时钟源MCGIR_CLK        
            //启用内部快速时钟
            MCG_C1 |= MCG_C1_IRCLKEN_MASK|MCG_C1_IREFSTEN_MASK;
            MCG_SC |= MCG_SC_FCRDIV(0x0);  //内部4M快速参考时钟分频因子，
                                          //可将时钟分频在31.25Khz ~ 4Mhz
            MCG_C4 |= MCG_C4_FCTRIM(0xA);
            MCG_C2 |= MCG_C2_IRCS_MASK;
            while (!(MCG_S & MCG_S_IRCST_MASK));//内部参考时钟状态
            
            SIM_SOPT2 |= SIM_SOPT2_UART0SRC(0x3);  //UART0选择MCGIR_CLK=4000Khz时钟源
            break;
        case MCGFLLCLK:
            SIM_SOPT2 |= SIM_SOPT2_UART0SRC(1);   //UART0选择MCGFLL_CLK=48000Khz时钟源
            break;
        default:
            break;
        }
        SIM_SCGC4 |= SIM_SCGC4_UART0_MASK;//启动串口0时钟    

        //引脚复用为串口功能并启用串口模块时钟
        #if (UART_0_GROUP == 1)
        PORTA_PCR2 = PORT_PCR_MUX(0x2);    //复用UART0_TX
        PORTA_PCR1 = PORT_PCR_MUX(0x2);    //复用UART0_RX
        #endif

        #if (UART_0_GROUP == 2)
        PORTA_PCR2 = PORT_PCR_MUX(0x2);    //复用UART0_TX
        PORTD_PCR6 = PORT_PCR_MUX(0x3);    //复用UART0_RX
        #endif

        #if (UART_0_GROUP == 3)
        PORTB_PCR17 = PORT_PCR_MUX(0x3);   //复用UART0_TX
        PORTA_PCR1 = PORT_PCR_MUX(0x2);;   //复用UART0_RX
        #endif

        #if (UART_0_GROUP == 4)
        PORTB_PCR17 = PORT_PCR_MUX(0x3);   //复用UART0_TX
        PORTD_PCR6 = PORT_PCR_MUX(0x3);;   //复用UART0_RX
        #endif

        #if (UART_0_GROUP == 5)
        PORTD_PCR7 = PORT_PCR_MUX(0x3);    //复用UART0_TX
        PORTA_PCR1 = PORT_PCR_MUX(0x3);;   //复用UART0_RX
        #endif

        #if (UART_0_GROUP == 6)
        PORTD_PCR7 = PORT_PCR_MUX(0x3);    //复用UART0_TX
        PORTD_PCR6 = PORT_PCR_MUX(0x3);;   //复用UART0_RX
        #endif

        //暂时关闭串口发送与接收功能  
        uartch1->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK);
        //根据时钟源选择时钟频率
        if(MCGIRCLK == sel_clk)
            clk_Khz = MCGIR_CLK;
        else if (MCGFLLCLK == sel_clk)
            clk_Khz = MCGFLL_CLK;

        //配置串口工作模式:8位无校验模式
        sbr = (uint_16)((clk_Khz*1000)/(baud * 16));
        temp = UART_BDH_REG(uartch1) & ~(UART_BDH_SBR(0x1F));
        UART_BDH_REG(uartch1) = temp | UART_BDH_SBR(((sbr & 0x1F00) >> 8));
        UART_BDL_REG(uartch1) = (uint_8)(sbr & UART_BDL_SBR_MASK);
        UART0_C4 = 0x0F;
               
        //初始化控制寄存器、清标志位
        UART0_C1 = 0x00;
        UART0_C3 = 0x00;
        UART0_MA1 = 0x00;
        UART0_MA2 = 0x00;
        UART0_S1 |= 0x1F;
        UART0_S2 |= 0xC0;
            
        //启动发送接收
        uartch1->C2 |= (UART_C2_TE_MASK | UART_C2_RE_MASK);
    }
    else 
    {
        uartch2 = UART_ARR[uartNo - 1];
        switch(uartNo)
        {
        case UART_1:
            SIM_SCGC4 |= SIM_SCGC4_UART1_MASK; //启动串口1时钟

            #if (UART_1_GROUP == 1)
            PORTE_PCR0 = PORT_PCR_MUX(0x3);    //使能UART1_TXD
            PORTE_PCR1 = PORT_PCR_MUX(0x3);    //使能UART1_RXD
            #endif

            #if (UART_1_GROUP == 2)
            PORTA_PCR19 = PORT_PCR_MUX(0x3);   //使能UART1_TXD
            PORTE_PCR1 = PORT_PCR_MUX(0x3);    //使能UART1_RXD
            #endif

            break;
        case UART_2:
            SIM_SCGC4 |= SIM_SCGC4_UART2_MASK; //启动串口2时钟

            #if (UART_2_GROUP == 1)
            PORTE_PCR16 = PORT_PCR_MUX(0x3);   //使能UART2_TXD
            PORTE_PCR17 = PORT_PCR_MUX(0x3);   //使能UART2_RXD
            #endif

            #if (UART_2_GROUP == 2)
            PORTD_PCR5 = PORT_PCR_MUX(0x3);    //使能UART2_TXD
            PORTE_PCR17 = PORT_PCR_MUX(0x3);   //使能UART2_RXD
            #endif

            break;
        default://传参错误，返回
            break;
        }
        
        //暂时关闭串口发送与接收功能
        UART_C2_REG(uartch2) &= ~( UART_C2_TE_MASK | UART_C2_RE_MASK );

        //配置串口工作模式,8位无校验模式
        UART_C1_REG(uartch2) = 0;
        //配置串口波特率，UART1、2只能选择总线时钟BUS_CLK=24MHZ
        sbr = (uint_16)((BUS_CLK * 1000) / (baud * 16));
        temp = UART_BDH_REG(uartch2) & ~(UART_BDH_SBR(0x1F));
        UART_BDH_REG(uartch2) = temp | UART_BDH_SBR(((sbr & 0x1F00) >> 8));
        UART_BDL_REG(uartch2) = (uint_8)(sbr & UART_BDL_SBR_MASK);
        
        //初始化控制寄存器、清标志位
        uartch2->C1 = 0x00;
        uartch2->C3 = 0x00;
//        uartch2->S1 = 0x1F;
        uartch2->S2 = 0x00;  
        
        //启动发送接收
        UART_C2_REG(uartch2) |= ( UART_C2_TE_MASK | UART_C2_RE_MASK );
    }
}

//===========================================================================
//函数名称：uart_send1
//参数说明：uartNo: 串口号:UART_0、UART_1、UART_2 
//          ch:要发送的字节
//函数返回：函数执行状态：0=正常；非0=异常。
//功能概要：串行发送1个字节
//===========================================================================
uint_8 uart_send1(uint_8 uartNo, uint_8 ch)
{
    uint_8 ret = 1;//默认返回错误
    uint_32 t;
    UART0_MemMapPtr uartch1=UART0_BASE_PTR; //获取UART0基地址
    UART_MemMapPtr uartch2 = UART_ARR[uartNo-1]; //获取UART1或者2基地址

    //参数有效性检查
    if(uartNo <= UART_2)
    {
        for (t = 0; t < 0xFBBB; t++)//查询指定次数
        {
            if(UART_0 == uartNo)  //判断使用的哪个串口
            {
                if ( (uartch1->S1) & UART_S1_TDRE_MASK )//判断发送缓冲区是否为空
                {
                    uartch1->D = ch;    //获取数据并发送
                    ret = 0;
                    break;             //跳出循环
                }
            }
            else
            {
                if ( (uartch2->S1) & UART_S1_TDRE_MASK )//判断发送缓冲区是否为空
                {
                    uartch2->D = ch;   //获取数据并发送
                    ret = 0;
                    break;             //跳出循环
                }
            }
        }
    }
    return ret;
}

//===========================================================================
//函数名称：uart_sendN
//参数说明：uartNo: 串口号:UART_0、UART_1、UART_2 
//          buff: 发送缓冲区
//          len:发送长度
//函数返回： 函数执行状态：0=正常；1=异常
//功能概要：串行 接收n个字节   
//===========================================================================
uint_8 uart_sendN (uint_8 uartNo ,uint_16 len ,uint_8* buff)
{
    uint_8 ret = 1;
    uint_16 i;
    if (uartNo <= UART_2 && buff != NULL)
    {
        for (i = 0; i < len; i++)
        {
            if (uart_send1(uartNo, buff[i])) //发送一个字节数据，失败则跳出循环
            {
                break;
            }
        }
        if (i < len)
            ret = 1; //发送失败
        else
            ret = 0; //发送成功
    }
    return ret;
}

//===========================================================================
//函数名称：uart_send_string
//参数说明：uartNo:UART模块号:UART_0、UART_1、UART_2 
//          buff:要发送的字符串的首地址
//函数返回： 函数执行状态：0=正常；非0=异常。
//功能概要：从指定UART端口发送一个以'\0'结束的字符串
//===========================================================================
uint_8 uart_send_string(uint_8 uartNo, void *buff)
{
    uint_8 ret = 1;
    uint_16 i;
    uint_8 *buff_ptr = (uint_8 *)buff;         //定义指针指向要发送字符串首地址

    if (uartNo <= UART_2 && buff_ptr != NULL)
    {
        for(i = 0; buff_ptr[i] != '\0'; i++)   //遍历字符串里的字符
        {
            if (uart_send1(uartNo,buff_ptr[i]))//发送指针对应的字符
            {
                break;  //发送失败
            }
        }
        if(buff_ptr[i] != '\0')
            ret = 1;    //发送失败
        else
            ret = 0;    //发送成功
    }
    return ret;
}

//===========================================================================
//函数名称：uart_re1
//参数说明：uartNo: 串口号:UART_0、UART_1、UART_2 
//         fp:接收返回字节的指针
//函数返回：接收成功标志:返回0，成功接收；返回1，接收失败
//功能概要：串行接收1个字节
//===========================================================================
uint_8 uart_re1 (uint_8 uartNo,uint_8* fp)
{
    uint_8 ret = 1;  //默认出错返回
    uint_32 t;
    UART0_MemMapPtr uartch1=UART0_BASE_PTR;    //获取UART0基地址
    UART_MemMapPtr uartch2 = UART_ARR[uartNo-1];//获取UART1或者2基地址

    //参数有效性检查
    if(uartNo <= UART_2 && fp != NULL)
    {
        for (t = 0; t < 0xFBBB; t++)//查询指定次数
        {
            if(UART_0 == uartNo)  //判断使用的哪个串口
            {
                //判断接收缓冲区是否满
                if ((uartch1->S1) & UART_S1_RDRF_MASK)
                {
                    *fp = uartch1->D; //获取数据 
                    ret = 0;
                    break;
                }
            }
            else
            {
                //判断接收缓冲区是否满
                if ((uartch2->S1) & UART_S1_RDRF_MASK )
                {
                    *fp = uartch2->D; //获取数据 
                    ret = 0;
                    break;
                }
            }
        }//end for
    }
    return ret;
}

//===========================================================================
//函数名称：uart_reN
//参数说明：uartNo: 串口号:UART_0、UART_1、UART_2                                                   
//          buff: 接收缓冲区指针
//          len:接收长度
//函数返回：函数执行状态 0=正常;非0=异常
//功能概要：串行 接收n个字节
//===========================================================================
uint_8 uart_reN (uint_8 uartNo ,uint_16 len ,uint_8* buff)
{
    uint_8 ret = 1;
    uint_16 i;
    uint_8 dat;  //接收到的数据
    if(uartNo <= UART_2 && buff != NULL)
    {
        //判断是否能接受数据
        for (i = 0; i < len; i++)
        {
            if(!uart_re1(uartNo, &dat))
                buff[i] = dat;//接受数据
            else
                break;
        }
        if (i < len)
            ret = 1; //接收失败
        else
            ret = 0; //接收成功
    }
    return ret;
}

//===========================================================================
//函数名称：uart_enable_re_int
//参数说明：uartNo: 串口号:UART_0、UART_1、UART_2 
//函数返回：无
//功能概要：开串口接收中断
//===========================================================================
void uart_enable_re_int(uint_8 uartNo)
{
    UART0_MemMapPtr uartch1= UART0_BASE_PTR;
    UART_MemMapPtr uartch2 = UART_ARR[uartNo-1];

    if(UART_0 == uartNo)
        uartch1->C2 |= UART_C2_RIE_MASK;        //开放UART接收中断
    else 
        uartch2->C2 |= UART_C2_RIE_MASK;        //开放UART接收中断
    NVIC_EnableIRQ(UART0_IRQ_NO + uartNo);      //开中断控制器IRQ中断
}

//===========================================================================
//函数名称：uart_disable_re_int
//参数说明：uartNo: 串口号 :UART_0、UART_1、UART_2 
//函数返回：无
//功能概要：关串口接收中断
//===========================================================================
void uart_disable_re_int(uint_8 uartNo)
{
    UART0_MemMapPtr uartch1=UART0_BASE_PTR; 
    UART_MemMapPtr uartch2 = UART_ARR[uartNo-1];

    if(UART_0 == uartNo)
        uartch1->C2 &= ~UART_C2_RIE_MASK;         //禁止UART接收中断
    else 
        uartch2->C2 &= ~UART_C2_RIE_MASK;         //禁止UART接收中断
    NVIC_DisableIRQ(UART0_IRQ_NO + uartNo);       //禁止中断控制器IRQ中断
}
