打印
[DemoCode下载]

M051 CEC 协议的实作

[复制链接]
120|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wanduzi|  楼主 | 2024-2-25 19:46 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
EC_M051_CEC_V1.00.zip (821.87 KB)
/**********************************************************************************
* [url=home.php?mod=space&uid=288409]@file[/url]    main.c
* [url=home.php?mod=space&uid=247401]@brief[/url]    M051 CEC sample code
*
* [url=home.php?mod=space&uid=536309]@NOTE[/url]                                                                                                
* Copyright(c) 2019 Nuvoton Technology Corp. All rights reserved.                                    
*                                                                                                     
***********************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include "M051Series.h"
#include    "Smpl_CEC.h"

#define PLLCON_SETTING      CLK_PLLCON_50MHz_HXT
#define PLL_CLOCK           50000000


/*---------------------------------------------------------------------------------------------------------
*CEC  command
*---------------------------------------------------------------------------------------------------------*/
#define Give_Physical_Address       0x83
#define Give_Device_Power_Status    0x8f
#define Set_Stream_Path             0x86
#define User_Control_Pressed        0x44
#define User_Control_Released       0x45
#define System_Audio_Mode_Request   0x70
#define Give_System_Audio_Mode_Status   0x7d
#define Active_Source               0x82
#define Get_CEC_Version             0x9f
#define Give_Device_VendorID        0x8c
#define Give_OSD_Name               0x46
#define Feature_Abort               0x00

#define Standby                     0x36




void UART0_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init UART                                                                                               */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Reset IP */
    SYS_ResetModule(UART0_RST);

    /* Configure UART0 and set UART0 Baudrate */
    UART_Open(UART0, 115200);
}
void SYS_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Enable IRC22M clock */
    CLK->PWRCON |= CLK_PWRCON_IRC22M_EN_Msk;

    /* Waiting for IRC22M clock ready */
    CLK_WaitClockReady(CLK_CLKSTATUS_IRC22M_STB_Msk);

    /* Switch HCLK clock source to HIRC */
    CLK->CLKSEL0 = CLK_CLKSEL0_HCLK_S_HIRC;

    /* Set PLL to Power-down mode and PLL_STB bit in CLKSTATUS register will be cleared by hardware.*/
    CLK->PLLCON |= CLK_PLLCON_PD_Msk;

    /* Enable external 12 MHz XTAL */
    CLK->PWRCON |= CLK_PWRCON_XTL12M_EN_Msk;

    /* Enable PLL and Set PLL frequency */
    CLK->PLLCON = PLLCON_SETTING;

    /* Waiting for clock ready */
    CLK_WaitClockReady(CLK_CLKSTATUS_PLL_STB_Msk | CLK_CLKSTATUS_XTL12M_STB_Msk);

    /* Switch HCLK clock source to PLL, STCLK to HCLK/2 */
    CLK->CLKSEL0 = CLK_CLKSEL0_STCLK_S_HXT | CLK_CLKSEL0_HCLK_S_PLL;

    /* Enable peripheral clock */
    CLK->APBCLK = CLK_APBCLK_UART0_EN_Msk | CLK_APBCLK_TMR3_EN_Msk;

    /* Peripheral clock source */
    CLK->CLKSEL1 = CLK_CLKSEL1_UART_S_PLL | CLK_CLKSEL1_TMR3_S_HXT;

    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate PllClock, SystemCoreClock and CycylesPerUs automatically. */
    SystemCoreClockUpdate();

    /*---------------------------------------------------------------------------------------------------------*/
    /* Init I/O Multi-function                                                                                 */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Set P3 multi-function pins for UART0 RXD, TXD and T1 */
    SYS->P3_MFP = SYS_MFP_P30_RXD0 | SYS_MFP_P31_TXD0 | SYS_MFP_P35_T1;
}

void TMR3_IRQHandler()
{
    TIMER3->TISR |= TIMER_TISR_TIF_Msk;
    CEC_TimerEvent();
}

void CEC_SetTimer(uint32_t  us)
{
    TIMER3->TCMPR = us * 12;
    TIMER3->TCSR |= TIMER_TCSR_CEN_Msk; //start count
}

void EINT1_IRQHandler()
{
    GPIO_CLR_INT_FLAG(P3, BIT3);

    NVIC_DisableIRQ(CECExtInt);//disable CEC int pin
    CEC_SetTimer(1000);

    if ((u8CECTRStatus == CECReceive) && (u8CECState == 1) && (u8CECTimerCNT == 9))
    {
        if (u8CECReAckFlag == 1)
            CEC_SetTimer(10);   //if reply ACK, timer interrupt need not wait 1ms
    }

    u8CECEIntStatus = 0xff;
    u8CECTRStatus = CECReceive;
}

void    ClearExtInt()
{
    if (CECExtInt == EINT1_IRQn)
        GPIO_CLR_INT_FLAG(P3, BIT3);

    if (CECExtInt == EINT0_IRQn)
        GPIO_CLR_INT_FLAG(P3, BIT2);
}

void CECSetReceive()        //CEC initial receive mode
{
    u8CECState = u8CECEIntStatus = u8CECTimerCNT = u8CECSubCNT =
                                                 u8CECEOM = 0;
    u8CECTRStatus = CECIdle;
    GPIO_SetMode(CECPort, CECPin, GPIO_PMD_INPUT);
    GPIO_SET_DEBOUNCE_TIME(GPIO_DBCLKSRC_HCLK, GPIO_DBCLKSEL_4);
    GPIO_ENABLE_DEBOUNCE(CECPort, CECPin);
    GPIO_EnableEINT1(P3, 3, GPIO_INT_FALLING);
    NVIC_EnableIRQ(EINT1_IRQn);
}
void InitialCEC()
{
    u8CECRetranCNT = 0;

    TIMER3->TCSR |= TIMER_TCSR_CRST_Msk;
    TIMER3->TCSR = TIMER_ONESHOT_MODE | TIMER_TCSR_IE_Msk | TIMER_TCSR_TDR_EN_Msk;
    TIMER3->TCMPR = 0xffffff;
    NVIC_EnableIRQ(TMR3_IRQn);      //enable timer interrupt
    CECSetReceive();
}

void UnInitialCEC()
{
    u8CECRetranCNT = 0;

    NVIC_DisableIRQ(TMR3_IRQn);     //disable timer interrupt
    GPIO_DisableInt(P3, 3);         //disable EXT1 interrupt
}

/**
* @brief This function is transfer data
* @param[in] DataLength, total data to be Tx
* [url=home.php?mod=space&uid=266161]@return[/url] none
* @note this functun is called when user want to Tx data, user must assure u8CECTRStatus is CECIdle then call this function,
* other wise will cause the protocal break down
*
*/
void SendData(uint8_t   DataLength)
{
    uint8_t u8Temp;
    u8CECState = u8CECEIntStatus = u8CECTimerCNT = u8CECSubCNT = u16CECAckFlag = u16CECAckCheckFlag =
                                                                             u8CECEOM = 0;
    u8CECTRStatus = CECtransmit;
    u8CECTxLength = u8CECTxRemain = DataLength;

    u8Temp = (au8CECTxData[0] >> 4) & 0x0f;

    if (u8Temp == (au8CECTxData[0] & 0x0f)) //dest=source,general call
        u16CECAckCheckFlag = 0;
    else
    {
        for (u8Temp = 0; u8Temp < DataLength; u8Temp++)
        {
            u16CECAckCheckFlag |= 0x8000 >> u8Temp;
        }
    }

    GPIO_SetMode(CECPort, CECPin, GPIO_PMD_OPEN_DRAIN);
    GPIO_DisableInt(P3, 3);         //disable EXT1 interrupt

    P33 = 1;    //CEC pin set high
    CEC_SetTimer(500);      //start check free time every 0.5ms, free time over than 5ms, you can send data
}



/**
* @brief This function is send CEC command
* @param[in] CECCommand, command index
* @return none
* @note this functun is called when user want to send CEC command
*
*/
void SendCECCommand(uint8_t CECCommand)
{
    while (u8CECTRStatus != CECIdle);     //wait CEC bus enter idle state, then start transmit

    switch (CECCommand)
    {
        case    Standby:        //
            au8CECTxData[1] = Standby;
            u8CECTxLength = 2;                  //total data length should be send
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)        //waitting CEC data transfer over, customer can run their code, and check this flag in main loop
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        case    System_Audio_Mode_Request:      //
            au8CECTxData[1] = System_Audio_Mode_Request;
            au8CECTxData[2] = 0x20;    //this need the phisical address
            au8CECTxData[3] = 0x00;    //this need the phisical address
            u8CECTxLength = 4;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        case    Set_Stream_Path:        //
            au8CECTxData[0] |= 0xf;
            au8CECTxData[1] = Set_Stream_Path;
            au8CECTxData[2] = 0x20;    //this need the phisical address
            au8CECTxData[3] = 0x00;    //this need the phisical address
            u8CECTxLength = 4;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        case    Give_Device_Power_Status:
            au8CECTxData[1] = Give_Device_Power_Status;
            u8CECTxLength = 2;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        case    Give_Physical_Address:
            au8CECTxData[1] = Give_Physical_Address;
            u8CECTxLength = 2;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        case    User_Control_Released:
            au8CECTxData[1] = User_Control_Released;
            u8CECTxLength = 2;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        case    User_Control_Pressed:
            au8CECTxData[1] = User_Control_Pressed;
            au8CECTxData[2] = 0x21; //0x21,number1, is [UI Command],please refer the CEC table 27 UserControlCode
            u8CECTxLength = 3;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        case    Give_System_Audio_Mode_Status:
            au8CECTxData[1] = Give_System_Audio_Mode_Status;
            u8CECTxLength = 2;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        case    Give_OSD_Name:
            au8CECTxData[1] = Give_OSD_Name;
            u8CECTxLength = 2;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        case    Give_Device_VendorID:
            au8CECTxData[1] = Give_Device_VendorID;
            u8CECTxLength = 2;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        case    Get_CEC_Version:
            au8CECTxData[1] = Get_CEC_Version;
            u8CECTxLength = 2;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        case    Active_Source:
            au8CECTxData[1] = Active_Source;
            au8CECTxData[2] = 4;
            au8CECTxData[3] = 0;
            u8CECTxLength = 3;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
            break;

        default:
            break;
    }

}

/**
* @brief This function used to decode command from received data package
* @param[in] none
* @return none
* @note this functun is called when user received a CEC data package
*
*/
void CECDecoderCommand()
{
    while (u8CECTRStatus != CECIdle);

    if (u8CECLogicalAddr == (au8CECRxData[0] & 0xf))
    {
        if (au8CECRxData[1] == 0xff)   //abort message
        {
            u8CECSrcAddr = 4;
            u8CECDstAddr = (au8CECRxData[0] & 0xf0) >> 4;
            au8CECTxData[0] = 0;
            au8CECTxData[0] = (u8CECSrcAddr << 4) | u8CECDstAddr;

            au8CECTxData[1] = Feature_Abort; //feature abort
            au8CECTxData[2] = 0xff;    //abort reason
            au8CECTxData[3] = 4;   //
            u8CECTxLength = 4;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
        }

        if (au8CECRxData[1] == Give_Physical_Address) //Give phisical address command
        {
            u8CECSrcAddr = 4;
            u8CECDstAddr = 0xf;   //broadcast message
            au8CECTxData[0] = 0;
            au8CECTxData[0] = (u8CECSrcAddr << 4) | u8CECDstAddr;

            au8CECTxData[1] = 0x84; //report physical address
            au8CECTxData[2] = 0x20;    //physical address
            au8CECTxData[3] = 0x00;    //physical address
            au8CECTxData[4] = 0x4;     //device type
            u8CECTxLength = 5;
            SendData(u8CECTxLength);

            while (u8CECTRStatus != CECIdle)
                ;

            printf("ACKbit=:0x %x, \n", u16CECAckFlag);
        }

    }

}


int32_t main()
{
    uint32_t    i, j;

    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Init System, peripheral clock and multi-function I/O */
    SYS_Init();

    /* Lock protected registers */
    SYS_LockReg();

    UART0_Init();
    printf("CED demo \n");

    u8CECSrcAddr = 0x2;
    u8CECDstAddr = 0x3;

    GPIO_SetMode(P3, BIT3, GPIO_PMD_QUASI);


    for (i = 0; i < CECMaxPayload; i++)
        au8CECTxData[i] = 0;

    au8CECTxData[0] = (u8CECSrcAddr << 4) | u8CECDstAddr;

    for (i = 1; i < CECMaxPayload; i++)
        au8CECTxData[i] = u8CECSrcAddr;

    InitialCEC();

    u8CECLogicalAddr = u8CECSrcAddr;


    while (1)
    {
        if (u8CECTRStatus == CECIdle)
        {
            SendCECCommand(Standby);
        }

        for (i = 0; i < 1000; i++)
        {
            CLK_SysTickDelay(1000);

            if (u8CECGetData)       //received  CEC data from CEC line
            {
                u8CECGetData = 0;
                printf("Received:");

                for (j = 0; j < u8CECRxLength; j++)
                    printf("%x, ", au8CECRxData[j]);

                printf(" \n");
                CECDecoderCommand();        //decoder received CEC command

                for (j = 0; j < CECMaxPayload; j++)
                    au8CECRxData[j] = 0;
            }
        }

    }
}
/*  Copyright(c) 2019 Nuvoton Technology Corp. All rights reserved.     */






使用特权

评论回复
沙发
wanduzi|  楼主 | 2024-2-25 19:46 | 只看该作者
/**************************************************************************//**
* @file    CEC_Lib.c
* @brief   CEC protocal stack
*          Transmit, receive and retransmit CEC data
* @note
* Copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
*
*****************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include "M051Series.h"
#include "Smpl_CEC.h"

uint8_t au8CECTxData[CECMaxPayload], au8CECRxData[CECMaxPayload];
//define
//au8CECTxData[0]--header
//au8CECTxData[1]--data1
//...

volatile uint8_t  u8CECTxLength;
uint8_t u8CECState, u8CECTRStatus, u8CECLogicalAddr, u8CECPhysicalAddr,
        u8CECTxRemain, u8CECRxLength, u8CECEOM, u8CECGetData;

uint8_t u8CECEIntStatus, u8CECTimerCNT, u8CECRetranCNT, u8CECSubCNT, u8CECSrcAddr, u8CECDstAddr;
uint8_t u8CECErrorFlag, u8CECReAckFlag;

uint16_t    u16CECAckFlag, u16CECAckCheckFlag;
//u16CECAckFlag define
//#define   HeadAck 0x8000
//#define   Data1Ack    0x4000
//#define   Data2Ack    0x2000
//#define   Data3Ack    0x1000
//......
//#define   Data15Ack   0x0001



/**
* @brief This function do all CEC protocal stack
* @param[in] none
* @return none
* @note this functun is called from Timer3 interrupt
*
*/

void CEC_TimerEvent()
{
uint8_t u8Temp;

    if (u8CECTRStatus == CECtransmit) //  CEC in trasmit process
    {
        switch (u8CECState)
        {
            case    0:          //check bus free time for 5bit data period
                if (P33 == 1)
                {
                    CEC_SetTimer(500);
                    u8CECTimerCNT++;

                    if (u8CECTimerCNT > 24)
                    {
                        CEC_SetTimer(3700);
                        u8CECState = 1;
                        u8CECTimerCNT = 0;
                        P33 = 0; //CECpin low, start bit
                    }
                }
                else
                {
                    CECSetReceive();
                    CEC_SetTimer(5000); //check if data need retransmit
                    u8CECTimerCNT = 0;
                    //printf("send fail, turn to receiver  \n");
                }

                break;

            case    1:      //send head and check arbitration
            {
                if (u8CECTimerCNT == 0)
                {
                    P33 = 1; //start bit high level

                    for (u8Temp = 20; u8Temp >0; u8Temp--);

                    if (P33 == 0) //start bit arbitration lost
                    {
                        //printf("start bit arbitration lost  \n");
                        CECSetReceive();        //turn to receive mode
                        CEC_SetTimer(5000); //check if data need retransmit
                        return;
                    }
                    else
                    {
                        CEC_SetTimer(800);      //start bit ,high level  0.8 ms
                        u8CECTimerCNT++;
                        u8CECSubCNT = 0;
                    }
                }
                else if (u8CECTimerCNT < 9)   //send head data
                {
                    if (u8CECSubCNT == 0)
                    {
                        P33 = 0; //data bit start

                        if (au8CECTxData[0] & (0x80 >> (u8CECTimerCNT - 1)))
                            CEC_SetTimer(600);//bit 1, low level 0.6ms
                        else
                            CEC_SetTimer(1500);//bit 0, low level 1.5ms

                        u8CECSubCNT = 1;
                        //printf("head bit :%d   \n",u8CECTimerCNT);
                    }
                    else
                    {
                        P33 = 1; //CECpin high

                        for (u8Temp = 30; u8Temp >0; u8Temp--);

                        if (P33 == 0) //arbitration lost
                        {
                            printf("head bit :%d arbitration lost  \n", u8CECTimerCNT);
                            //u8CECTxLength=0;    //arbitration lost ,stop tran
                            CECSetReceive();        //turn to receive mode
                            CEC_SetTimer(15000);//must wait 15ms then retrans, check if data need retransmit
                            return;
                        }
                        else
                        {
                            if (au8CECTxData[0] & (0x80 >> (u8CECTimerCNT - 1)))
                                CEC_SetTimer(1790);//bit 1, high level 1.8 ms
                            else
                                CEC_SetTimer(890);//bit 0, high level 0.9 ms

                            u8CECTimerCNT++;
                            u8CECSubCNT = 0;
                        }

                    }
                }
                else if (u8CECTimerCNT == 9)  //EOM bit
                {

                    if (u8CECSubCNT == 0) //EOM bit low level
                    {
                        P33 = 0; //EOM bit start

                        if (u8CECTxRemain > 1)
                            CEC_SetTimer(1500);//bit 0, low level 1.5ms
                        else
                            CEC_SetTimer(600);//bit 1, low level 0.6ms

                        u8CECSubCNT = 1;
                    }
                    else
                    {
                        P33 = 1; //EOM bit start

                        if (u8CECTxRemain > 1)
                            CEC_SetTimer(900);//bit 0, high level 0.9ms
                        else
                            CEC_SetTimer(1800);//bit 1, high level 1.8ms

                        u8CECSubCNT = 0;
                        u8CECTimerCNT++;
                    }
                }
                else if (u8CECTimerCNT == 10)     //ACK bit
                {
                    if (u8CECSubCNT == 0)
                    {
                        CEC_SetTimer(600);
                        P33 = 0; //ACK bit low level
                        u8CECSubCNT = 1;
                    }
                    else if (u8CECSubCNT == 1)
                    {
                        CEC_SetTimer(400);
                        P33 = 1; //ACK bit high level
                        u8CECSubCNT = 2;
                    }
                    else if (u8CECSubCNT == 2)     //check ack bit at 1ms positon
                    {
                        CEC_SetTimer(1400);

                        if (P33 == 0) //get ack bit
                        {
                            u16CECAckFlag |= 0x8000;
                        }

                        u8CECSubCNT = 0;
                        u8CECTimerCNT = 0;
                        u8CECState = 2;
                        u8CECTxRemain--;
                    }

                }

            }
            break;

            case    2:      //transmit all data
            {
                if (u8CECTxRemain)
                {
                    if (u8CECTimerCNT < 8)
                    {
                        if (u8CECSubCNT == 0)
                        {
                            P33 = 0; //data bit start

                            if (au8CECTxData[u8CECTxLength - u8CECTxRemain] & (0x80 >> u8CECTimerCNT))
                                CEC_SetTimer(600);//bit 1, low level 0.6ms
                            else
                                CEC_SetTimer(1500);//bit 0, low level 1.5ms

                            u8CECSubCNT = 1;
                        }
                        else
                        {
                            P33 = 1; //CECpin high

                            if (au8CECTxData[u8CECTxLength - u8CECTxRemain] & (0x80 >> u8CECTimerCNT))
                                CEC_SetTimer(1800);//bit 1, high level 1.8 ms
                            else
                                CEC_SetTimer(900);//bit 0, high level 0.9 ms

                            u8CECTimerCNT++;
                            u8CECSubCNT = 0;
                        }
                    }
                    else if (u8CECTimerCNT == 8)  //EOM bit
                    {
                        if (u8CECSubCNT == 0) //EOM bit low level
                        {
                            P33 = 0; //EOM bit start

                            if (u8CECTxRemain > 1)
                                CEC_SetTimer(1500);//bit 0, low level 1.5ms
                            else
                                CEC_SetTimer(600);//bit 1, low level 0.6ms

                            u8CECSubCNT = 1;
                        }
                        else
                        {
                            P33 = 1; //EOM bit start

                            if (u8CECTxRemain > 1)
                                CEC_SetTimer(900);//bit 0, high level 0.9ms
                            else
                                CEC_SetTimer(1800);//bit 1, high level 1.8ms

                            u8CECSubCNT = 0;
                            u8CECTimerCNT++;
                        }
                    }
                    else if (u8CECTimerCNT == 9)  //ACK bit
                    {
                        if (u8CECSubCNT == 0)
                        {
                            CEC_SetTimer(600);
                            P33 = 0; //ACK bit low level
                            u8CECSubCNT = 1;
                        }
                        else if (u8CECSubCNT == 1)
                        {
                            CEC_SetTimer(400);
                            P33 = 1; //ACK bit high level
                            u8CECSubCNT = 2;
                        }
                        else if (u8CECSubCNT == 2)     //check ack bit at 1ms positon
                        {
                            CEC_SetTimer(1400);

                            if (P33 == 0) //get ack bit
                            {
                                u16CECAckFlag |= 0x8000 >> (u8CECTxLength - u8CECTxRemain);
                            }

                            u8CECSubCNT = 0;
                            u8CECTimerCNT = 0;
                            u8CECTxRemain--;
                        }

                    }
                }
                else    //all data transmit out
                {
                    if (u16CECAckFlag != u16CECAckCheckFlag)  //check ack, if not match, retransmit data
                    {
                        if (((au8CECTxData[0] >> 4) & 0x0f) == (au8CECTxData[0] & 0x0f))
                        {
                            //check general call, no need retransmit
                            u8CECTxLength = u8CECRetranCNT = 0;
                            CECSetReceive();        //turn to receive mode
                            return;
                        }
                        else
                        {
                            u8CECRetranCNT++;

                            //printf("retrans :%d times  \n", u8CECRetranCNT);
                            if (u8CECRetranCNT > 4)   //retrans fail 5 times, abort transmit!
                            {
                                u8CECTxLength = u8CECRetranCNT = 0;
                                CECSetReceive();        //turn to receive mode
                                return;
                            }

                            SendData(u8CECTxLength);
                            //CECSetReceive();
                            //CEC_SetTimer(3000);   //check if data need retransmit
                        }
                    }
                    else
                    {
                        u8CECTxLength = u8CECRetranCNT = 0;
                        CECSetReceive();        //turn to receive mode
                        return;
                    }
                }
            }
            break;
        }

    }
    else if (u8CECTRStatus == CECReceive)
    {
        if (u8CECEIntStatus == 0)
        {
            CECSetReceive();    //timer is not trigged by ext int, it's means last trigger is a noise
            CEC_SetTimer(5000); //check if data need transmit
            //printf("Noise trigger, checked 1\n");
            return;
        }

        switch (u8CECState)
        {
            case    0:      //receive check start bit
            {
                if (u8CECTimerCNT < 5)
                {
                    if (P33 == 1)
                    {
                        //it's noise,not start bit
                        //printf("Noise trigger, checked2: %d \n",u8CECTimerCNT);
                        CECSetReceive();
                        return;
                    }
                    else
                    {
                        u8CECTimerCNT++;

                        if (u8CECTimerCNT == 5)
                            CEC_SetTimer(1100);
                        else
                            CEC_SetTimer(500);
                    }

                }
                else if (u8CECTimerCNT == 5)
                {
                    if (P33 == 0)
                    {
                        //it's noise,not start bit
                        //printf("Noise trigger, checked 3\n");
                        CECSetReceive();
                        return;
                    }
                    else
                    {
                        u8CECTimerCNT = u8CECRxLength = u8CECErrorFlag = 0;
                        u8CECState = 1;
                        NVIC_EnableIRQ(CECExtInt);  //enable ext int check
                        u8CECEIntStatus = 0;      //check if the timer is trigged from ext int
                        CEC_SetTimer(1000000);      //for safe,
                        //printf("Get start bit\n");
                    }
                }
            }
            break;

            case    1:
            {
                if (u8CECErrorFlag == 0xff)
                {           //user can add error process here:
                    /*                  u8CECState=2;
                                        u8CECErrorFlag=u8CECTimerCNT=u8CECSubCNT=u8CECRxLength=0;
                                        //NVIC_DisableIRQ(CECExtInt);   //enable ext int check
                                        GPIO_SetMode(CECPort, CECPin, GPIO_PMD_OPEN_DRAIN);
                                        P33=0;  //CECpin low, for ACK bit
                                        CEC_SetTimer(3600); //force low time 3.4~3.8ms, ack bit timming error
                                        //printf("bit timing error  \n");
                    */
                }

                if (u8CECTimerCNT < 8)
                {
                    if (P33 == 1)
                        au8CECRxData[u8CECRxLength] |= 0x80 >> u8CECTimerCNT;      //get high CEC bit
                    else
                        au8CECRxData[u8CECRxLength] &= ~(0x80 >> u8CECTimerCNT);   //get low CEC bit

                    u8CECTimerCNT++;

                    NVIC_EnableIRQ(CECExtInt);  //enable ext int check
                    u8CECEIntStatus = 0;      //check if the timer is trigged from ext int
                    CEC_SetTimer(2000);
                }
                else if (u8CECTimerCNT == 8)  //EOM proc
                {
                    if (P33 == 1) //check end of message
                        u8CECEOM = 1;
                    else
                        u8CECEOM = 0;

                    if (u8CECLogicalAddr == (au8CECRxData[0] & 0xf)) //check dest address, if equal, receiver will reply ACK
                        u8CECReAckFlag = u8CECSubCNT = 1;    //flag for ACK
                    else
                        u8CECReAckFlag = u8CECSubCNT = 0;    //flag for NOACK

                    u8CECTimerCNT = 9;
                    NVIC_EnableIRQ(CECExtInt);  //enable ext int check
                    u8CECEIntStatus = 0;      //check if the timer is trigged from ext int
                    CEC_SetTimer(1000000);

                    //printf("received:%d data:%d  \n",u8CECRxLength,au8CECRxData[u8CECRxLength]);
                    u8CECRxLength++;
                }
                else if (u8CECTimerCNT == 9) //ACK process
                {
                    if (u8CECSubCNT == 0)
                    {
                        if (u8CECEOM == 1)
                        {
                            u8CECGetData = 1; //receive finished

                            if (u8CECTxLength)
                            {
                                SendData(u8CECTxLength);  //goto transmit mode
                                CEC_SetTimer(10000);    //delay for safe, long delay for ACK bit finish
                            }
                            else
                                CECSetReceive();        //trun receive state

                            //printf("Get data 1  \n");
                        }
                        else
                        {
                            NVIC_EnableIRQ(CECExtInt);  //enable ext int check
                            u8CECEIntStatus = 0;      //check if the timer is trigged from ext int
                            CEC_SetTimer(1000000);
                            u8CECTimerCNT = u8CECSubCNT = 0; //keep receive other data
                        }
                    }
                    else if (u8CECSubCNT == 1)
                    {
                        GPIO_SetMode(CECPort, CECPin, GPIO_PMD_OPEN_DRAIN);
                        P33 = 0; //CECpin low, for ACK bit
                        CEC_SetTimer(1400);     //ack low 1.5ms, after TCL test, this need set 1300
                        u8CECEIntStatus = 0xff;
                        u8CECSubCNT = 2;
                    }
                    else if (u8CECSubCNT == 2)
                    {
                        P33 = 1; //CECpin high, for ACK bit
                        CEC_SetTimer(300);      //should be 900,but it will mask next falling edge, so set 300
                        u8CECEIntStatus = 0xff;
                        u8CECSubCNT = 3;
                    }
                    else if (u8CECSubCNT == 3)
                    {
                        //followed 2 line clear ACK high caused Ext pending int, must do!
                        ClearExtInt();
                        NVIC_ClearPendingIRQ(CECExtInt);
                        GPIO_SetMode(CECPort, CECPin, GPIO_PMD_INPUT);

                        if (u8CECEOM == 1)
                        {
                            u8CECGetData = 1; //receive finished

                            if (u8CECTxLength)
                            {
                                SendData(u8CECTxLength);  //goto transmit mode
                                CEC_SetTimer(7000); //delay for safe
                            }
                            else
                                CECSetReceive();

                            //printf("Get data 2  \n");
                        }
                        else
                        {
                            NVIC_EnableIRQ(CECExtInt);  //enable ext int check
                            u8CECEIntStatus = 0;      //check if the timer is trigged from ext int
                            CEC_SetTimer(1000000);
                            u8CECTimerCNT = u8CECSubCNT = 0; //keep receive other data
                            //printf("keep receive  \n");
                        }
                    }

                }
            }
            break;

            case    2:
            {
                /*  printf("low level keeped 3.6ms  \n");
                    ClearExtInt();
                    NVIC_ClearPendingIRQ(CECExtInt);
                    GPIO_SetMode(CECPort, CECPin, GPIO_PMD_INPUT);
                    if(u8CECTxLength)
                        {
                        SendData(u8CECTxLength);  //go to transmit mode
                        CEC_SetTimer(10000);    //delay for safe, long delay for ACK bit finish
                        }
                    else
                        CECSetReceive();        //go to receive state
                */
            }

            default:
                break;

        }
    }
    else if (u8CECTRStatus == CECIdle) // if transmit failed, it will goto receive mode, if there is not any siginal for a certain time,it will goto transmit mode again
    {
        if (u8CECTxLength > 0)
            SendData(u8CECTxLength);  //goto transmit mode
        else
            CECSetReceive();        //go to receive state
    }

    return;
}
















































































































使用特权

评论回复
板凳
wanduzi|  楼主 | 2024-2-25 19:47 | 只看该作者
/**************************************************************************//**
* @file     Smpl_CEC.h
* @brief    M051 CEC driver header file
*
* @note
* Copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include "M051Series.h"

#ifndef __CEC_H__
#define __CEC_H__


void InitialCEC(void);      //initialize CEC used resource, inlcude: timer0, GPIO
void CEC_TimerEvent(void);

#define CECPort P3
#define CECPin  3
#define CECTimer    TIMER3
#define CECExtInt   EINT1_IRQn

//define CEC states
#define CECIdle 0
#define CECReceive  1
#define CECtransmit 2

//define flow control status
#define CECNewSend      0
#define CECPreSendFail  1


#define CECMaxPayload       16
extern uint8_t  au8CECTxData[CECMaxPayload], au8CECRxData[CECMaxPayload];
//define
//au8CECTxData[0]--header
//au8CECTxData[1]--data1
//...

extern volatile uint8_t  u8CECTxLength;
extern uint8_t  u8CECState, u8CECTRStatus, u8CECLogicalAddr, u8CECPhysicalAddr,
       u8CECTxRemain, u8CECRxLength, u8CECEOM, u8CECGetData;

extern uint8_t  u8CECEIntStatus, u8CECTimerCNT, u8CECRetranCNT, u8CECSubCNT, u8CECSrcAddr, u8CECDstAddr;
extern uint8_t  u8CECErrorFlag, u8CECReAckFlag;

extern uint16_t u16CECAckFlag, u16CECAckCheckFlag;
//u16CECAckFlag define
//#define   HeadAck 0x8000
//#define   Data1Ack    0x4000
//#define   Data2Ack    0x2000
//#define   Data3Ack    0x1000
//......
//#define   Data15Ack   0x0001


void CEC_SetTimer(uint32_t  us);

void    ClearExtInt(void);


void CECSetReceive(void);       //CEC initial receive mode

void SendData(uint8_t   DataLength);

#endif //__CEC_H__
/*** (C) COPYRIGHT 2019 Nuvoton Technology Corp. ***/

使用特权

评论回复
地板
wanduzi|  楼主 | 2024-2-25 19:47 | 只看该作者
此范例程序使用P3.3以及timer3实现CEC协议。用户可以在P3.3接上拉电阻再接到HDMI总线中的CEC控制线上,然后就可以发送命令到CEC总线上的其他设备,也可以接收其他设备发送的CEC命令,如果地址匹配MCU会自动回复应答信号给发送设备

使用特权

评论回复
5
wanduzi|  楼主 | 2024-2-25 19:48 | 只看该作者
CEC总线拥有类似I2C总线的仲裁功能,所以我们要将CEC管脚配置为开漏输出并且要接上拉电阻,这样才可以将MCU管脚接到HDMI总线的CEC控制线上

使用特权

评论回复
6
jiekou001| | 2024-2-26 17:19 | 只看该作者
CEC总线是做什么的?

使用特权

评论回复
7
jiekou001| | 2024-2-26 17:19 | 只看该作者
怎么看着像单线协议啊

使用特权

评论回复
8
jiekou001| | 2024-2-26 17:21 | 只看该作者
是这个吗?
CEC(Consumer Electronics Control)是一套完整的单总线协议,电子设备可以借着CEC信号让使用可控制HDMI接口上所连接的装置,比如单键播放(One Touth Play),系统待机(System Standby),可以实现由单一遥控器控制所有HDMI连接的装置。最多可以控制15个设备。允许HDMI设备在没有用户干扰情况下互相命令控制。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

129

主题

1655

帖子

3

粉丝