550 lines
15 KiB
C
550 lines
15 KiB
C
/** @file sci.c
|
|
* @brief SCI Driver Implementation File
|
|
* @date 29.May.2013
|
|
* @version 03.05.02
|
|
*
|
|
*/
|
|
|
|
/* (c) Texas Instruments 2009-2013, All rights reserved. */
|
|
|
|
/* USER CODE BEGIN (0) */
|
|
/* USER CODE END */
|
|
|
|
#include "sci.h"
|
|
|
|
/* USER CODE BEGIN (1) */
|
|
/* USER CODE END */
|
|
/** @struct g_sciTransfer
|
|
* @brief Interrupt mode globals
|
|
*
|
|
*/
|
|
static struct g_sciTransfer
|
|
{
|
|
uint32 mode;
|
|
uint32 length;
|
|
uint8 * data;
|
|
} g_sciTransfer_t[2U];
|
|
|
|
|
|
/** @fn void sciInit(void)
|
|
* @brief Initializes the SCI Driver
|
|
*
|
|
* This function initializes the SCI module.
|
|
*/
|
|
void sciInit(void)
|
|
{
|
|
/* USER CODE BEGIN (2) */
|
|
/* USER CODE END */
|
|
|
|
|
|
/** @b initialize @b SCILIN */
|
|
|
|
/** - bring SCI out of reset */
|
|
scilinREG->GCR0 = 1U;
|
|
|
|
/** - Disable all interrupts */
|
|
scilinREG->CLRINT = 0xFFFFFFFFU;
|
|
scilinREG->CLRINTLVL = 0xFFFFFFFFU;
|
|
|
|
/** - global control 1 */
|
|
scilinREG->GCR1 = (1U << 25U) /* enable transmit */
|
|
| (1U << 24U) /* enable receive */
|
|
| (1U << 5U) /* internal clock (device has no clock pin) */
|
|
| ((1U-1U) << 4U) /* number of stop bits */
|
|
| (0U << 3U) /* even parity, otherwise odd */
|
|
| (0U << 2U) /* enable parity */
|
|
| (1U << 1U); /* asynchronous timing mode */
|
|
|
|
/** - set baudrate */
|
|
scilinREG->BRS = 53U; /* baudrate */
|
|
|
|
/** - transmission length */
|
|
scilinREG->FORMAT = 8U - 1U; /* length */
|
|
|
|
/** - set SCI pins functional mode */
|
|
scilinREG->FUN = (1U << 2U) /* tx pin */
|
|
| (1U << 1U) /* rx pin */
|
|
| (0U); /* clk pin */
|
|
|
|
/** - set SCI pins default output value */
|
|
scilinREG->DOUT = (0U << 2U) /* tx pin */
|
|
| (0U << 1U) /* rx pin */
|
|
| (0U); /* clk pin */
|
|
|
|
/** - set SCI pins output direction */
|
|
scilinREG->DIR = (0U << 2U) /* tx pin */
|
|
| (0U << 1U) /* rx pin */
|
|
| (0U); /* clk pin */
|
|
|
|
/** - set SCI pins open drain enable */
|
|
scilinREG->ODR = (0U << 2U) /* tx pin */
|
|
| (0U << 1U) /* rx pin */
|
|
| (0U); /* clk pin */
|
|
|
|
/** - set SCI pins pullup/pulldown enable */
|
|
scilinREG->PD = (0U << 2U) /* tx pin */
|
|
| (0U << 1U) /* rx pin */
|
|
| (0U); /* clk pin */
|
|
|
|
/** - set SCI pins pullup/pulldown select */
|
|
scilinREG->PSL = (1U << 2U) /* tx pin */
|
|
| (1U << 1U) /* rx pin */
|
|
| (1U); /* clk pin */
|
|
|
|
/** - set interrupt level */
|
|
scilinREG->SETINTLVL = (0U << 26U) /* Framing error */
|
|
| (0U << 25U) /* Overrun error */
|
|
| (0U << 24U) /* Parity error */
|
|
| (0U << 9U) /* Receive */
|
|
| (0U << 8U) /* Transmit */
|
|
| (0U << 1U) /* Wakeup */
|
|
| (0U); /* Break detect */
|
|
|
|
/** - set interrupt enable */
|
|
scilinREG->SETINT = (0U << 26U) /* Framing error */
|
|
| (0U << 25U) /* Overrun error */
|
|
| (0U << 24U) /* Parity error */
|
|
| (1U << 9U) /* Receive */
|
|
| (0U << 1U) /* Wakeup */
|
|
| (0U); /* Break detect */
|
|
|
|
/** - initialize global transfer variables */
|
|
g_sciTransfer_t[1U].mode = 0U << 8U;
|
|
g_sciTransfer_t[1U].length = 0U;
|
|
|
|
/** - Finaly start SCILIN */
|
|
scilinREG->GCR1 |= (1U << 7U);
|
|
|
|
/* USER CODE BEGIN (3) */
|
|
/* USER CODE END */
|
|
}
|
|
|
|
|
|
/** @fn void sciSetFunctional(sciBASE_t *sci, uint32 port)
|
|
* @brief Change functional behavior of pins at runtime.
|
|
* @param[in] sci - sci module base address
|
|
* @param[in] port - Value to write to FUN register
|
|
*
|
|
* Change the value of the PCFUN register at runtime, this allows to
|
|
* dynamically change the functionality of the SCI pins between functional
|
|
* and GIO mode.
|
|
*/
|
|
void sciSetFunctional(sciBASE_t *sci, uint32 port)
|
|
{
|
|
/* USER CODE BEGIN (4) */
|
|
/* USER CODE END */
|
|
|
|
sci->FUN = port;
|
|
|
|
/* USER CODE BEGIN (5) */
|
|
/* USER CODE END */
|
|
}
|
|
|
|
|
|
/** @fn void sciSetBaudrate(sciBASE_t *sci, uint32 baud)
|
|
* @brief Change baudrate at runtime.
|
|
* @param[in] sci - sci module base address
|
|
* @param[in] baud - baudrate in Hz
|
|
*
|
|
* Change the SCI baudrate at runtime.
|
|
*/
|
|
void sciSetBaudrate(sciBASE_t *sci, uint32 baud)
|
|
{
|
|
float64 vclk = 100.000 * 1000000.0;
|
|
uint32 f = ((sci->GCR1 & 2U) == 2U) ? 16U : 1U;
|
|
|
|
/* USER CODE BEGIN (6) */
|
|
/* USER CODE END */
|
|
|
|
/*SAFETYMCUSW 96 S MR:6.1 <REVIEWED> "Calculations including int and float cannot be avoided" */
|
|
sci->BRS = ((uint32)((vclk /(f*baud) + 0.5)) - 1U) & 0x00FFFFFFU;
|
|
|
|
/* USER CODE BEGIN (7) */
|
|
/* USER CODE END */
|
|
}
|
|
|
|
|
|
/** @fn uint32 sciIsTxReady(sciBASE_t *sci)
|
|
* @brief Check if Tx buffer empty
|
|
* @param[in] sci - sci module base address
|
|
*
|
|
* @return The TX ready flag
|
|
*
|
|
* Checks to see if the Tx buffer ready flag is set, returns
|
|
* 0 is flags not set otherwise will return the Tx flag itself.
|
|
*/
|
|
uint32 sciIsTxReady(sciBASE_t *sci)
|
|
{
|
|
/* USER CODE BEGIN (8) */
|
|
/* USER CODE END */
|
|
|
|
return sci->FLR & SCI_TX_INT;
|
|
}
|
|
|
|
|
|
/** @fn void sciSendByte(sciBASE_t *sci, uint8 byte)
|
|
* @brief Send Byte
|
|
* @param[in] sci - sci module base address
|
|
* @param[in] byte - byte to transfer
|
|
*
|
|
* Sends a single byte in polling mode, will wait in the
|
|
* routine until the transmit buffer is empty before sending
|
|
* the byte. Use sciIsTxReady to check for Tx buffer empty
|
|
* before calling sciSendByte to avoid waiting.
|
|
*/
|
|
void sciSendByte(sciBASE_t *sci, uint8 byte)
|
|
{
|
|
/* USER CODE BEGIN (9) */
|
|
/* USER CODE END */
|
|
|
|
while ((sci->FLR & SCI_TX_INT) == 0U)
|
|
{
|
|
} /* Wait */
|
|
sci->TD = byte;
|
|
|
|
/* USER CODE BEGIN (10) */
|
|
/* USER CODE END */
|
|
}
|
|
|
|
|
|
/** @fn void sciSend(sciBASE_t *sci, uint32 length, uint8 * data)
|
|
* @brief Send Data
|
|
* @param[in] sci - sci module base address
|
|
* @param[in] length - number of data words to transfer
|
|
* @param[in] data - pointer to data to send
|
|
*
|
|
* Send a block of data pointed to by 'data' and 'length' bytes
|
|
* long. If interrupts have been enabled the data is sent using
|
|
* interrupt mode, otherwise polling mode is used. In interrupt
|
|
* mode transmission of the first byte is started and the routine
|
|
* returns immediately, sciSend must not be called again until the
|
|
* transfer is complete, when the sciNotification callback will
|
|
* be called. In polling mode, sciSend will not return until
|
|
* the transfer is complete.
|
|
*
|
|
* @note if data word is less than 8 bits, then the data must be left
|
|
* aligned in the data byte.
|
|
*/
|
|
void sciSend(sciBASE_t *sci, uint32 length, uint8 * data)
|
|
{
|
|
uint32 index = sci == sciREG ? 0U : 1U;
|
|
|
|
/* USER CODE BEGIN (11) */
|
|
/* USER CODE END */
|
|
|
|
if ((g_sciTransfer_t[index].mode & SCI_TX_INT) != 0U)
|
|
{
|
|
/* we are in interrupt mode */
|
|
|
|
g_sciTransfer_t[index].length = length;
|
|
g_sciTransfer_t[index].data = data;
|
|
|
|
/* start transmit by sending first byte */
|
|
sci->TD = *g_sciTransfer_t[index].data++ ;
|
|
sci->SETINT = SCI_TX_INT;
|
|
}
|
|
else
|
|
{
|
|
/* send the data */
|
|
while (length-- > 0U)
|
|
{
|
|
while ((sci->FLR & SCI_TX_INT) == 0U)
|
|
{
|
|
} /* Wait */
|
|
sci->TD = *data++;
|
|
}
|
|
}
|
|
|
|
/* USER CODE BEGIN (12) */
|
|
/* USER CODE END */
|
|
}
|
|
|
|
|
|
/** @fn uint32 sciIsRxReady(sciBASE_t *sci)
|
|
* @brief Check if Rx buffer full
|
|
* @param[in] sci - sci module base address
|
|
*
|
|
* @return The Rx ready flag
|
|
*
|
|
* Checks to see if the Rx buffer full flag is set, returns
|
|
* 0 is flags not set otherwise will return the Rx flag itself.
|
|
*/
|
|
uint32 sciIsRxReady(sciBASE_t *sci)
|
|
{
|
|
/* USER CODE BEGIN (13) */
|
|
/* USER CODE END */
|
|
|
|
return sci->FLR & SCI_RX_INT;
|
|
}
|
|
|
|
/** @fn uint32 sciIsIdleDetected(sciBASE_t *sci)
|
|
* @brief Check if Idle Period is Detected
|
|
* @param[in] sci - sci module base address
|
|
*
|
|
* @return The Idle flag
|
|
*
|
|
* Checks to see if the SCI Idle flag is set, returns 0 is flags
|
|
* not set otherwise will return the Ilde flag itself.
|
|
*/
|
|
uint32 sciIsIdleDetected(sciBASE_t *sci)
|
|
{
|
|
/* USER CODE BEGIN (14) */
|
|
/* USER CODE END */
|
|
|
|
return sci->FLR & SCI_IDLE;
|
|
}
|
|
|
|
|
|
/** @fn uint32 sciRxError(sciBASE_t *sci)
|
|
* @brief Return Rx Error flags
|
|
* @param[in] sci - sci module base address
|
|
*
|
|
* @return The Rx error flags
|
|
*
|
|
* Returns the Rx framing, overrun and parity errors flags,
|
|
* also clears the error flags before returning.
|
|
*/
|
|
uint32 sciRxError(sciBASE_t *sci)
|
|
{
|
|
uint32 status = sci->FLR & (SCI_FE_INT | SCI_OE_INT |SCI_PE_INT);
|
|
|
|
/* USER CODE BEGIN (15) */
|
|
/* USER CODE END */
|
|
|
|
sci->FLR = SCI_FE_INT | SCI_OE_INT | SCI_PE_INT;
|
|
return status;
|
|
}
|
|
|
|
|
|
/** @fn uint32 sciReceiveByte(sciBASE_t *sci)
|
|
* @brief Receive Byte
|
|
* @param[in] sci - sci module base address
|
|
*
|
|
* @return Received byte
|
|
*
|
|
* Receives a single byte in polling mode. If there is
|
|
* not a byte in the receive buffer the routine will wait
|
|
* until one is received. Use sciIsRxReady to check to
|
|
* see if the buffer is full to avoid waiting.
|
|
*/
|
|
uint32 sciReceiveByte(sciBASE_t *sci)
|
|
{
|
|
/* USER CODE BEGIN (16) */
|
|
/* USER CODE END */
|
|
|
|
while ((sci->FLR & SCI_RX_INT) == 0U)
|
|
{
|
|
} /* Wait */
|
|
|
|
return (sci->RD & 0x000000FFU);
|
|
}
|
|
|
|
|
|
/** @fn void sciReceive(sciBASE_t *sci, uint32 length, uint8 * data)
|
|
* @brief Receive Data
|
|
* @param[in] sci - sci module base address
|
|
* @param[in] length - number of data words to transfer
|
|
* @param[in] data - pointer to data buffer
|
|
*
|
|
* Receive a block of 'length' bytes long and place it into the
|
|
* data buffer pointed to by 'data'. If interrupts have been
|
|
* enabled the data is received using interrupt mode, otherwise
|
|
* polling mode is used. In interrupt mode receive is setup and
|
|
* the routine returns immediately, sciReceive must not be called
|
|
* again until the transfer is complete, when the sciNotification
|
|
* callback will be called. In polling mode, sciReceive will not
|
|
* return until the transfer is complete.
|
|
*/
|
|
void sciReceive(sciBASE_t *sci, uint32 length, uint8 * data)
|
|
{
|
|
/* USER CODE BEGIN (17) */
|
|
/* USER CODE END */
|
|
|
|
if ((sci->SETINT & SCI_RX_INT) == SCI_RX_INT)
|
|
{
|
|
/* we are in interrupt mode */
|
|
uint32 index = sci == sciREG ? 0U : 1U;
|
|
|
|
/* clear error flags */
|
|
sci->FLR = SCI_FE_INT | SCI_OE_INT | SCI_PE_INT;
|
|
|
|
g_sciTransfer_t[index].length = length;
|
|
g_sciTransfer_t[index].data = data;
|
|
}
|
|
else
|
|
{
|
|
while (length-- > 0U)
|
|
{
|
|
while ((sci->FLR & SCI_RX_INT) == 0U)
|
|
{
|
|
} /* Wait */
|
|
*data++ = (uint8)(sci->RD & 0x000000FFU);
|
|
}
|
|
}
|
|
/* USER CODE BEGIN (18) */
|
|
/* USER CODE END */
|
|
}
|
|
|
|
/** @fn void sciEnableLoopback(sciBASE_t *sci, loopBackType_t Loopbacktype)
|
|
* @brief Enable Loopback mode for self test
|
|
* @param[in] sci - sci module base address
|
|
* @param[in] Loopbacktype - Digital or Analog
|
|
*
|
|
* This function enables the Loopback mode for self test.
|
|
*/
|
|
void sciEnableLoopback(sciBASE_t *sci, loopBackType_t Loopbacktype)
|
|
{
|
|
/* USER CODE BEGIN (19) */
|
|
/* USER CODE END */
|
|
|
|
/* Clear Loopback incase enabled already */
|
|
sci->IODFTCTRL = 0U;
|
|
|
|
/* Enable Loopback either in Analog or Digital Mode */
|
|
sci->IODFTCTRL = 0x00000A00U
|
|
| (Loopbacktype << 1U);
|
|
|
|
/* USER CODE BEGIN (20) */
|
|
/* USER CODE END */
|
|
}
|
|
|
|
/** @fn void sciDisableLoopback(sciBASE_t *sci)
|
|
* @brief Enable Loopback mode for self test
|
|
* @param[in] sci - sci module base address
|
|
*
|
|
* This function disable the Loopback mode.
|
|
*/
|
|
void sciDisableLoopback(sciBASE_t *sci)
|
|
{
|
|
/* USER CODE BEGIN (21) */
|
|
/* USER CODE END */
|
|
|
|
/* Disable Loopback Mode */
|
|
sci->IODFTCTRL = 0x00000500U;
|
|
|
|
/* USER CODE BEGIN (22) */
|
|
/* USER CODE END */
|
|
}
|
|
|
|
/** @fn sciEnableNotification(sciBASE_t *sci, uint32 flags)
|
|
* @brief Enable interrupts
|
|
* @param[in] sci - sci module base address
|
|
* @param[in] flags - Interrupts to be enabled, can be ored value of:
|
|
* SCI_FE_INT - framing error,
|
|
* SCI_OE_INT - overrun error,
|
|
* SCI_PE_INT - parity error,
|
|
* SCI_RX_INT - receive buffer ready,
|
|
* SCI_TX_INT - transmit buffer ready,
|
|
* SCI_WAKE_INT - wakeup,
|
|
* SCI_BREAK_INT - break detect
|
|
*/
|
|
void sciEnableNotification(sciBASE_t *sci, uint32 flags)
|
|
{
|
|
uint32 index = sci == sciREG ? 0U : 1U;
|
|
|
|
/* USER CODE BEGIN (23) */
|
|
/* USER CODE END */
|
|
|
|
g_sciTransfer_t[index].mode |= (flags & SCI_TX_INT);
|
|
sci->SETINT = (flags & (~(SCI_TX_INT)));
|
|
|
|
/* USER CODE BEGIN (24) */
|
|
/* USER CODE END */
|
|
}
|
|
|
|
|
|
/** @fn sciDisableNotification(sciBASE_t *sci, uint32 flags)
|
|
* @brief Disable interrupts
|
|
* @param[in] sci - sci module base address
|
|
* @param[in] flags - Interrupts to be disabled, can be ored value of:
|
|
* SCI_FE_INT - framing error,
|
|
* SCI_OE_INT - overrun error,
|
|
* SCI_PE_INT - parity error,
|
|
* SCI_RX_INT - receive buffer ready,
|
|
* SCI_TX_INT - transmit buffer ready,
|
|
* SCI_WAKE_INT - wakeup,
|
|
* SCI_BREAK_INT - break detect
|
|
*/
|
|
void sciDisableNotification(sciBASE_t *sci, uint32 flags)
|
|
{
|
|
uint32 index = sci == sciREG ? 0U : 1U;
|
|
|
|
/* USER CODE BEGIN (25) */
|
|
/* USER CODE END */
|
|
|
|
g_sciTransfer_t[index].mode &= ~(flags & SCI_TX_INT);
|
|
sci->CLRINT = (flags & (~SCI_TX_INT));
|
|
|
|
/* USER CODE BEGIN (26) */
|
|
/* USER CODE END */
|
|
}
|
|
|
|
/** @fn void linHighLevelInterrupt(void)
|
|
* @brief Level 0 Interrupt for SCILIN
|
|
*/
|
|
void linHighLevelInterrupt(void)
|
|
{
|
|
uint32 vec = scilinREG->INTVECT0;
|
|
|
|
/* USER CODE BEGIN (35) */
|
|
/* USER CODE END */
|
|
|
|
switch (vec)
|
|
{
|
|
case 1U:
|
|
sciNotification(scilinREG, SCI_WAKE_INT);
|
|
break;
|
|
case 3U:
|
|
sciNotification(scilinREG, SCI_PE_INT);
|
|
break;
|
|
case 6U:
|
|
sciNotification(scilinREG, SCI_FE_INT);
|
|
break;
|
|
case 7U:
|
|
sciNotification(scilinREG, SCI_BREAK_INT);
|
|
break;
|
|
case 9U:
|
|
sciNotification(scilinREG, SCI_OE_INT);
|
|
break;
|
|
|
|
case 11U:
|
|
/* receive */
|
|
{ uint32 byte = (scilinREG->RD & 0x000000FFU);
|
|
|
|
if (g_sciTransfer_t[1U].length > 0U)
|
|
{
|
|
*g_sciTransfer_t[1U].data++ = byte;
|
|
g_sciTransfer_t[1U].length--;
|
|
if (g_sciTransfer_t[1U].length == 0U)
|
|
{
|
|
sciNotification(scilinREG, SCI_RX_INT);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 12U:
|
|
/* transmit */
|
|
if (--g_sciTransfer_t[1U].length > 0U)
|
|
{
|
|
scilinREG->TD = *g_sciTransfer_t[1U].data++;
|
|
}
|
|
else
|
|
{
|
|
scilinREG->CLRINT = SCI_TX_INT;
|
|
sciNotification(scilinREG, SCI_TX_INT);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* phantom interrupt, clear flags and return */
|
|
scilinREG->FLR = ~scilinREG->SETINTLVL & 0x07000303U;
|
|
break;
|
|
}
|
|
/* USER CODE BEGIN (36) */
|
|
/* USER CODE END */
|
|
}
|
|
/* USER CODE BEGIN (37) */
|
|
/* USER CODE END */
|
|
|