MotorControlModuleSDFM_TMS3.../Projects/epwm_test/Freemaster/PE_freemaster_serial.c
2023-08-23 16:31:55 +03:00

713 lines
21 KiB
C

/******************************************************************************
*
* Freescale Semiconductor Inc.
* (c) Copyright 2004-2007 Freescale Semiconductor, Inc.
* (c) Copyright 2001-2004 Motorola, Inc.
* ALL RIGHTS RESERVED.
*
****************************************************************************//*!
*
* @file PE_freemaster_serial.c
*
* @brief FreeMASTER SCI communication routines
*
* @version 1.1.18.0
*
* @date Oct-22-2007
*
*******************************************************************************/
#include "PE_freemaster.h"
#include "PE_freemaster_private.h"
#include "PE_freemaster_protocol.h"
//#include "include.h"
extern void FMSTR_SCI_PUTCHAR(char _data);
extern char FMSTR_SCI_GETCHAR(void);
extern void FMSTR_SCI_RE(void);
extern void FMSTR_SCI_RD(void);
extern void FMSTR_SCI_TE(void);
extern void FMSTR_SCI_TD(void);
extern FMSTR_SCISR FMSTR_SCI_RDCLRSR(void);
#if FMSTR_USE_SCI || FMSTR_USE_JTAG
/***********************************
* local variables
***********************************/
/* FreeMASTER communication buffer (in/out) plus the STS and LEN bytes */
static FMSTR_BCHR pcm_pCommBuffer[FMSTR_COMM_BUFFER_SIZE+3];
/* FreeMASTER runtime flags */
/*lint -e{960} using union */
static volatile union
{
FMSTR_FLAGS all;
struct
{
unsigned bTxActive : 1; /* response is being transmitted */
unsigned bTxWaitTC : 1; /* response sent, wait for transmission complete */
unsigned bTxLastCharSOB : 1; /* last transmitted char was equal to SOB */
unsigned bRxLastCharSOB : 1; /* last received character was SOB */
unsigned bRxMsgLengthNext : 1; /* expect the length byte next time */
unsigned bJtagRIEPending : 1; /* JTAG RIE bit failed to be set, try again later */
} flg;
} pcm_wFlags;
/* receive and transmit buffers and counters */
static FMSTR_SIZE8 pcm_nTxTodo; /* transmission to-do counter (0 when tx is idle) */
static FMSTR_SIZE8 pcm_nRxTodo; /* reception to-do counter (0 when rx is idle) */
static FMSTR_BPTR pcm_pTxBuff; /* pointer to next byte to transmit */
static FMSTR_BPTR pcm_pRxBuff; /* pointer to next free place in RX buffer */
static FMSTR_BCHR pcm_nRxCheckSum; /* checksum of data being received */
/* SHORT_INTR receive queue (circular buffer) */
#if FMSTR_SHORT_INTR
static FMSTR_BCHR pcm_pRQueueBuffer[FMSTR_COMM_RQUEUE_SIZE];
static FMSTR_BPTR pcm_pRQueueRP; /* SHORT_INTR queue read-pointer */
static FMSTR_BPTR pcm_pRQueueWP; /* SHORT_INTR queue write-pointer */
#endif
#if FMSTR_USE_JTAG
static FMSTR_U32 pcm_wJtagTxData; /* four bytes buffer to be sent over JTAG (LSB first) */
static FMSTR_SIZE8 pcm_wJtagTxCtr; /* counter of bytes in pcm_wJtagTxData */
#endif
/***********************************
* local function prototypes
***********************************/
static void FMSTR_Listen(void);
static void FMSTR_SendError(FMSTR_BCHR nErrCode);
static void FMSTR_Tx(void);
static void FMSTR_Rx(FMSTR_BCHR nRxChar);
//static void FMSTR_RxQueue(FMSTR_BCHR nRxChar);
//static void FMSTR_RxDequeue(void);
/*lint -esym(752,FMSTR_RxQueue) this may be unreferenced in some cases */
/*lint -esym(752,FMSTR_RxDequeue) this may be unreferenced in some cases */
/**************************************************************************//*!
*
* @brief Serial communication initialization
*
******************************************************************************/
void FMSTR_InitSerial(void)
{
/* initialize all state variables */
pcm_wFlags.all = 0U;
pcm_nTxTodo = 0U;
pcm_nRxTodo = 0U;
#if FMSTR_SHORT_INTR
pcm_pRQueueRP = pcm_pRQueueBuffer;
pcm_pRQueueWP = pcm_pRQueueBuffer;
#endif
/* start listening for commands */
FMSTR_Listen();
}
/**************************************************************************//*!
*
* @brief Start listening on a serial line
*
* Reset the receiver machine and start listening on a serial line
*
******************************************************************************/
static void FMSTR_Listen(void)
{
pcm_nRxTodo = 0U;
/* disable transmitter state machine */
pcm_wFlags.flg.bTxActive = 0U;
pcm_wFlags.flg.bTxWaitTC = 0U;
/* disable transmitter, enable receiver (enables single-wire connection) */
#if FMSTR_USE_SCI
FMSTR_SCI_TD();
FMSTR_SCI_RE();
#endif
}
/**************************************************************************//*!
*
* @brief Send response of given error code (no data)
*
* @param nErrCode - error code to be sent
*
******************************************************************************/
static void FMSTR_SendError(FMSTR_BCHR nErrCode)
{
/* fill & send single-byte response */
*pcm_pCommBuffer = nErrCode;
FMSTR_SendResponse(pcm_pCommBuffer, 1U);
}
/**************************************************************************//*!
*
* @brief Finalize transmit buffer before transmitting
*
* @param nLength - response length (1 for status + data length)
*
*
* This Function takes the data already prepared in the transmit buffer
* (inlcuding the status byte). It computes the check sum and kicks on tx.
*
******************************************************************************/
void FMSTR_SendResponse(FMSTR_BPTR pResponse, FMSTR_SIZE8 nLength)
{
FMSTR_U16 chSum = 0U;
FMSTR_U8 i, c;
/* remeber the buffer to be sent */
pcm_pTxBuff = pResponse;
/* status byte and data are already there, compute checksum only */
for (i=0U; i<nLength; i++)
{
c = 0U;
pResponse = FMSTR_ValueFromBuffer8(&c, pResponse);
/* add character to checksum */
chSum += c;
/* prevent saturation to happen on DSP platforms */
chSum &= 0xffU;
}
/* store checksum after the message */
pResponse = FMSTR_ValueToBuffer8(pResponse, (FMSTR_U8) (((FMSTR_U16)~(chSum)) + 1U));
/* send the message and the checksum and the SOB */
pcm_nTxTodo = (FMSTR_SIZE8) (nLength + 1U);
/* now transmitting the response */
pcm_wFlags.flg.bTxActive = 1U;
pcm_wFlags.flg.bTxWaitTC = 0U;
/* do not replicate the initial SOB */
pcm_wFlags.flg.bTxLastCharSOB = 0U;
#if FMSTR_USE_SCI
{
/*lint -esym(550, dummySR) */
volatile FMSTR_SCISR dummySR;
/* disable receiver, enable transmitter (single-wire communication) */
FMSTR_SCI_RD();
FMSTR_SCI_TE();
/* kick on the SCI transmission (also clears TX Empty flag on some platforms) */
// dummySR = FMSTR_SCI_GETSR();
FMSTR_SCI_PUTCHAR(FMSTR_SOB);
}
#elif FMSTR_USE_JTAG
/* kick on the JTAG transmission */
pcm_wJtagTxData = FMSTR_SOB;
pcm_wJtagTxCtr = 1U;
/* send the next two bytes immediatelly (we can be sure there are two bytes) */
FMSTR_Tx();
FMSTR_Tx();
/* send the third byte (if any) or flush the 32bit JTAG word */
FMSTR_Tx();
#endif
/* TX interrupt enable, RX interrupt disable */
#if FMSTR_LONG_INTR || FMSTR_SHORT_INTR
#if FMSTR_USE_SCI
FMSTR_SCI_DRXI();
FMSTR_SCI_ETXI();
#elif FMSTR_USE_JTAG
#if FMSTR_USE_JTAG_TXFIX
/* in TX-bugfix mode, keep the RX interrupt enabled as it */
/* is used as "able-to-TX" notification from the PC */
FMSTR_JTAG_ERXI();
#else
/* otherwise, JTAG is very same as the SCI */
FMSTR_JTAG_DRXI();
FMSTR_JTAG_ETXI();
#endif
#endif
#endif
}
/**************************************************************************//*!
*
* @brief Output buffer transmission
*
* This function sends one character of the transmit buffer. It handles
* replicating of the SOB characted inside the message body.
*
******************************************************************************/
static void FMSTR_Tx(void)
{
FMSTR_U8 ch = 0U;
if (pcm_nTxTodo)
{
/* fetch & send character ready to transmit */
/*lint -e{534} ignoring return value */
FMSTR_ValueFromBuffer8(&ch, pcm_pTxBuff);
#if FMSTR_USE_SCI
/* just put the byte into the SCI transmit buffer */
FMSTR_SCI_PUTCHAR((FMSTR_U8) ch);
#elif FMSTR_USE_JTAG
/* put byte to 32bit JTAG buffer */
pcm_wJtagTxData = (pcm_wJtagTxData << 8) | ch;
/* another byte */
pcm_wJtagTxCtr++;
/* all four bytes ready? */
if(pcm_wJtagTxCtr & 0x4U)
{
FMSTR_JTAG_PUTDWORD(pcm_wJtagTxData);
pcm_wJtagTxCtr = 0U;
}
#endif
/* SOB replication? */
if (ch != FMSTR_SOB || pcm_wFlags.flg.bTxLastCharSOB)
{
/* no, advance tx buffer pointer */
pcm_nTxTodo--;
pcm_pTxBuff = FMSTR_SkipInBuffer(pcm_pTxBuff, 1U);
pcm_wFlags.flg.bTxLastCharSOB = 0U;
}
else
{
/* yes, repeat the SOB next time */
pcm_wFlags.flg.bTxLastCharSOB = 1U;
}
}
#if FMSTR_USE_JTAG
/* on JTAG, the some bytes may still be pending in a 32bit buffer */
else if(pcm_wJtagTxCtr > 0U)
{
/* add padding bytes */
while(!(pcm_wJtagTxCtr & 4U))
{
pcm_wJtagTxData = (pcm_wJtagTxData << 8U) | 0xffU;
pcm_wJtagTxCtr++;
}
/* send the word just completed */
FMSTR_JTAG_PUTDWORD(pcm_wJtagTxData);
/* done, bTxActive will be deactivated next time */
pcm_wJtagTxCtr = 0U;
}
#endif
/* transmission finished, start listening again */
else
{
/* when SCI TX buffering is enabled, we must first wait until all
characters are physically transmitted (before disabling transmitter) */
#if FMSTR_USE_SCI && FMSTR_SCI_HAS_TXQUEUE
pcm_wFlags.flg.bTxWaitTC = 1;
/* wait for SCI TC interrupt */
#if FMSTR_SHORT_INTR || FMSTR_LONG_INTR
FMSTR_SCI_ETCI();
#endif
#else
/* start listening immediatelly */
FMSTR_Listen();
#endif
}
}
/**************************************************************************//*!
*
* @brief Handle received character
*
* @param nRxChar The character to be processed
*
* Handle the character received and -if the message is complete- call the
* protocol decode routine.
*
******************************************************************************/
static void FMSTR_Rx(FMSTR_BCHR nRxChar)
{
/* first, handle the replicated SOB characters */
if(nRxChar == FMSTR_SOB)
{
/* this is the 2nd byte of replicated SOB char */
if(pcm_wFlags.flg.bRxLastCharSOB)
{
/* join the two SOBs into one 0x2b character and continue processing */
pcm_wFlags.flg.bRxLastCharSOB = 0U;
}
/* this is either the first byte of replicated SOB or a */
/* real Start-of-Block mark - we will decide next time in FMSTR_Rx */
else
{
pcm_wFlags.flg.bRxLastCharSOB = 1U;
return;
}
}
/* we have got a common character preceeded by the SOB - */
/* this is the command code! */
if(pcm_wFlags.flg.bRxLastCharSOB)
{
/* reset reciving process */
pcm_pRxBuff = pcm_pCommBuffer;
*pcm_pRxBuff++ = nRxChar;
/* start computing the checksum */
pcm_nRxCheckSum = nRxChar;
pcm_nRxTodo = 0U;
/* fast command? */
if((nRxChar & FMSTR_FASTCMD) == FMSTR_FASTCMD)
{
/* there will be no length information */
pcm_wFlags.flg.bRxMsgLengthNext = 0U;
/* as it is encoded in the command byte directly */
pcm_nRxTodo = (FMSTR_SIZE8)
(((((FMSTR_SIZE8)nRxChar) & FMSTR_FASTCMD_DATALEN_MASK) >> FMSTR_FASTCMD_DATALEN_SHIFT) + 1U);
}
/* standard command */
else
{
/* the message length will come in next byte */
pcm_wFlags.flg.bRxMsgLengthNext = 1U;
}
/* command code stored & processed */
pcm_wFlags.flg.bRxLastCharSOB = 0U;
return;
}
/* we are waiting for the length byte */
if(pcm_wFlags.flg.bRxMsgLengthNext)
{
/* this byte, total data length and the checksum */
pcm_nRxTodo = (FMSTR_SIZE8) (1U + ((FMSTR_SIZE8)nRxChar) + 1U);
/* now read the data bytes */
pcm_wFlags.flg.bRxMsgLengthNext = 0U;
}
/* waiting for a data byte? */
if(pcm_nRxTodo)
{
/* add this byte to checksum */
pcm_nRxCheckSum += nRxChar;
/* was it the last byte of the message (checksum)? */
if(!--pcm_nRxTodo)
{
/* receive buffer overflow? */
if(pcm_pRxBuff == NULL)
{
FMSTR_SendError(FMSTR_STC_CMDTOOLONG);
}
/* checksum error? */
else if((pcm_nRxCheckSum & 0xffU) != 0U)
{
FMSTR_SendError(FMSTR_STC_CMDCSERR);
}
/* message is okay */
else
{
/* do decode now! */
FMSTR_ProtocolDecoder(pcm_pCommBuffer);
}
}
/* not the last character yet */
else
{
/* is there still a space in the buffer? */
if(pcm_pRxBuff)
{
/*lint -e{946} pointer arithmetic is okay here (same array) */
if(pcm_pRxBuff < (pcm_pCommBuffer + FMSTR_COMM_BUFFER_SIZE))
{
/* store byte */
*pcm_pRxBuff++ = nRxChar;
}
/* buffer is full! */
else
{
/* NULL rx pointer means buffer overflow - but we still need */
/* to receive all message characters (for the single-wire mode) */
/* so keep "receiving" - but throw away all characters from now */
pcm_pRxBuff = NULL;
}
}
}
}
}
/*******************************************************************************
*
* @brief Routine to quick-receive a character (put to a queue only)
*
* This function puts received character into a queue and exits as soon as possible.
*
*******************************************************************************/
#if FMSTR_SHORT_INTR
static void FMSTR_RxQueue(FMSTR_BCHR nRxChar)
{
/* future value of write pointer */
FMSTR_BPTR wpnext = pcm_pRQueueWP + 1;
/*lint -e{946} pointer arithmetic is okay here (same array) */
if(wpnext >= (pcm_pRQueueBuffer + FMSTR_COMM_RQUEUE_SIZE))
{
wpnext = pcm_pRQueueBuffer;
}
/* any space in queue? */
if(wpnext != pcm_pRQueueRP)
{
*pcm_pRQueueWP = (FMSTR_U8) nRxChar;
pcm_pRQueueWP = wpnext;
}
}
#endif /* FMSTR_SHORT_INTR */
/*******************************************************************************
*
* @brief Late processing of queued characters
*
* This function takes the queued characters and calls FMSTR_Rx() for each of them,
* just like as the characters would be received from SCI one by one.
*
*******************************************************************************/
#if FMSTR_SHORT_INTR
static void FMSTR_RxDequeue(void)
{
FMSTR_BCHR nChar = 0U;
/* get all queued characters */
while(pcm_pRQueueRP != pcm_pRQueueWP)
{
nChar = *pcm_pRQueueRP++;
/*lint -e{946} pointer arithmetic is okay here (same array) */
if(pcm_pRQueueRP >= (pcm_pRQueueBuffer + FMSTR_COMM_RQUEUE_SIZE))
{
pcm_pRQueueRP = pcm_pRQueueBuffer;
}
/* emulate the SCI receive event */
if(!pcm_wFlags.flg.bTxActive)
{
FMSTR_Rx(nChar);
}
}
}
#endif /* FMSTR_SHORT_INTR */
/**************************************************************************//*!
*
* @brief Handle SCI communication (both TX and RX)
*
* This function checks the SCI flags and calls the Rx and/or Tx functions
*
* @note This function can be called either from SCI ISR or from the polling routine
*
******************************************************************************/
#if FMSTR_USE_SCI
void FMSTR_ProcessSCI(void)
{
/* read & clear status */
FMSTR_SCISR wSciSR = FMSTR_SCI_RDCLRSR();
/* transmitter active and empty? */
if (pcm_wFlags.flg.bTxActive)
{
/* able to accept another character? */
if(wSciSR & FMSTR_SCISR_TDRE)
{
FMSTR_Tx();
}
/* read-out and ignore any received character (loopback) */
if(wSciSR & FMSTR_SCISR_RDRF)
{
/*lint -esym(550, nRxChar) */
volatile FMSTR_U16 nRxChar;
nRxChar = FMSTR_SCI_GETCHAR();
}
}
/* transmitter not active, able to receive */
else
{
/* data byte received? */
if (wSciSR & FMSTR_SCISR_RDRF)
{
FMSTR_BCHR nRxChar = 0U;
nRxChar = (FMSTR_BCHR) FMSTR_SCI_GETCHAR();
FMSTR_Rx(nRxChar);
// FMSTR_Tx();
}
}
}
#endif
/**************************************************************************//*!
*
* @brief Handle JTAG communication (both TX and RX)
*
* This function checks the JTAG flags and calls the Rx and/or Tx functions
*
* @note This function can be called either from JTAG ISR or from the polling routine
*
******************************************************************************/
#if FMSTR_USE_JTAG
void FMSTR_ProcessJTAG(void)
{
/* read & clear status */
register FMSTR_U16 wJtagSR = FMSTR_JTAG_GETSR();
/* transmitter active? */
if (pcm_wFlags.flg.bTxActive)
{
/* able to transmit a new character? (TX must be empty = read-out by PC) */
if(!(wJtagSR & FMSTR_JTAG_OTXRXSR_TDF))
{
#if FMSTR_USE_JTAG_TXFIX
/* if TDF bit is useless due to silicon bug, use the RX flag */
/* instead (PC sends us a dummy word to kick the RX flag on) */
if(wJtagSR & FMSTR_JTAG_OTXRXSR_RDF)
#endif
{
/* send one byte always */
FMSTR_Tx();
/* try to fill-up the full 32bit JTAG word */
while(pcm_wFlags.flg.bTxActive && pcm_wJtagTxCtr)
{
FMSTR_Tx();
}
}
}
/* ignore (read-out) the JTAG-received word */
if(wJtagSR & FMSTR_JTAG_OTXRXSR_RDF)
{
/*lint -esym(550, nRxWord) */
volatile FMSTR_U16 nRxWord;
nRxWord = FMSTR_JTAG_GETWORD();
}
}
/* transmitter not active */
else
{
/* JTAG 32bit word (four bytes) received? */
if(wJtagSR & FMSTR_JTAG_OTXRXSR_RDF)
{
register FMSTR_U32 nRxDWord;
FMSTR_INDEX i;
nRxDWord = FMSTR_JTAG_GETDWORD();
/* process all bytes, MSB first */
for(i=0; i<4; i++)
{
#if FMSTR_SHORT_INTR
FMSTR_RxQueue((FMSTR_BCHR)((nRxDWord >> 24U) & 0xffU));
#else
FMSTR_Rx((FMSTR_BCHR)((nRxDWord >> 24U) & 0xffU));
/* ignore the rest if previous bytes triggered a transmission */
/* (i.e. the packet was complete and only filled-up to 32bit word) */
if(pcm_wFlags.flg.bTxActive)
{
break;
}
#endif
/* next byte of 32bit word */
nRxDWord = nRxDWord << 8;
}
}
}
}
#endif
/*******************************************************************************
*
* @brief API: Main "Polling" call from the application main loop
*
* This function either handles all the SCI communictaion (polling-only mode =
* FMSTR_POLL_DRIVEN) or decodes messages received on the background by SCI interrupt
* (short-interrupt mode = FMSTR_SHORT_INTR).
*
* In the JTAG interrupt-driven mode (both short and long), this function also checks
* if setting the JTAG RIE bit failed recently. This may happen because of the
* RIE is held low by the EONCE hardware until the EONCE is first accessed from host.
* FMSTR_Init (->FMSTR_Listen) is often called while the PC-side FreeMASTER is still
* turned off. So really, the JTAG is not enabled by this time and RIE bit is not set.
* This problem is detected (see how bJtagRIEPending is set above in FSMTR_Listen)
* and it is tried to be fixed periodically here in FMSTR_Poll.
*
*******************************************************************************/
void FMSTR_Poll(void)
{
FMSTR_ProcessSCI();
}
#else /* FMSTR_USE_SCI || FMSTR_USE_JTAG */
/* Empty implementation of communication functions
Without a SCI and JTAG the FreeMASTER driver still passes the compilation,
but no communication is supported. The user may imlement his own communication
protocol and use FreeMASTER by calling FMSTR_ProtocolDecoder and
overriding the FMSTR_SendResponse calls
*/
void FMSTR_SendResponse(FMSTR_BPTR pResponse, FMSTR_SIZE8 nLength)
{
FMSTR_UNUSED(pResponse);
FMSTR_UNUSED(nLength);
}
void FMSTR_Poll(void)
{
}
/*lint -efile(766, PE_freemaster_protocol.h) include file is not used in this case */
#endif /* FMSTR_USE_SCI || FMSTR_USE_JTAG */