- /**************************************************************************//**
- * @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;
- }