//!
//! This example shows how to setup an interrupt on PWM0. This example
//! demonstrates how to setup an interrupt on the PWM when the PWM timer is
//! equal to the configurable PWM0LOAD register.
//!
//! This example uses the following peripherals and I/O signals. You must
//! review these and change as needed for your own board:
//! - GPIO Port D peripheral (for PWM0 pin)
//! - PWM0 - PD0
//!
//! The following UART signals are configured only for displaying console
//! messages for this example. These are not required for operation of the
//! PWM.
//! - UART0 peripheral
//! - GPIO Port A peripheral (for UART0 pins)
//! - UART0RX - PA0
//! - UART0TX - PA1
//!
//! This example uses the following interrupt handlers. To use this example
//! in your own application you must add these interrupt handlers to your
//! vector table.
//! - INT_PWM0 - PWM0IntHandler
//
//*****************************************************************************
//*****************************************************************************
//
// This function sets up UART0 to be used for a console to display information
// as the example is running.
//
//*****************************************************************************
void
InitConsole(void)
{
//
// Enable GPIO port A which is used for UART0 pins.
// TODO: change this to whichever GPIO port you are using.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
//
// Configure the pin muxing for UART0 functions on port A0 and A1.
// This step is not necessary if your part does not support pin muxing.
// TODO: change this to select the port/pin you are using.
//
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
//
// Select the alternate (UART) function for these pins.
// TODO: change this to select the port/pin you are using.
//
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
//
// Initialize the UART for console I/O.
//
UARTStdioInit(0);
}
//*****************************************************************************
//
// Prints out 5x "." with a second delay after each print. This function will
// then backspace, clear the previously printed dots, backspace again so you
// continuously printout on the same line. The purpose of this function is to
// indicate to the user that the program is running.
//
//*****************************************************************************
void
PrintRunningDots(void)
{
UARTprintf(". ");
SysCtlDelay(SysCtlClockGet() / 3);
UARTprintf(". ");
SysCtlDelay(SysCtlClockGet() / 3);
UARTprintf(". ");
SysCtlDelay(SysCtlClockGet() / 3);
UARTprintf(". ");
SysCtlDelay(SysCtlClockGet() / 3);
UARTprintf(". ");
SysCtlDelay(SysCtlClockGet() / 3);
UARTprintf("\b\b\b\b\b\b\b\b\b\b");
UARTprintf(" ");
UARTprintf("\b\b\b\b\b\b\b\b\b\b");
SysCtlDelay(SysCtlClockGet() / 3);
}
//*****************************************************************************
//
// The interrupt handler for the for PWM0 interrupts.
//
//*****************************************************************************
void
PWM0IntHandler(void)
{
//
// Clear the PWM0 LOAD interrupt flag. This flag gets set when the PWM
// counter gets reloaded.
//
PWMGenIntClear(PWM_BASE, PWM_GEN_0, PWM_INT_CNT_LOAD);
//
// If the duty cycle is less or equal to 75% then add 0.1% to the duty
// cycle. Else, reset the duty cycle to 0.1% cycles. Note that 64 is
// 0.01% of the period (64000 cycles).
//
if((PWMPulseWidthGet(PWM_BASE, PWM_OUT_0) + 64) <=
((PWMGenPeriodGet(PWM_BASE, PWM_GEN_0) * 3) / 4))
{
PWMPulseWidthSet(PWM_BASE, PWM_OUT_0,
PWMPulseWidthGet(PWM_BASE, PWM_OUT_0) + 64);
}
else
{
PWMPulseWidthSet(PWM_BASE, PWM_OUT_0, 64);
}
}
//*****************************************************************************
//
// Configure PWM0 for a load interrupt. This interrupt will trigger everytime
// the PWM0 counter gets reloaded. In the interrupt, 0.1% will be added to
// the current duty cycle. This will continue until a duty cycle of 75% is
// received, then the duty cycle will get reset to 0.1%.
//
//*****************************************************************************
int
main(void)
{
//
// Set the clocking to run directly from the external crystal/oscillator.
// TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
// crystal on your board.
//
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_6MHZ);
//
// Set the PWM clock to the system clock.
//
SysCtlPWMClockSet(SYSCTL_PWMDIV_1);
//
// Set up the serial console to use for displaying messages. This is
// just for this example program and is not needed for PWM0 operation.
//
InitConsole();
//
// Display the setup on the console.
//
UARTprintf("PWM ->\n");
UARTprintf(" Module: PWM0\n");
UARTprintf(" Pin: PD0\n");
UARTprintf(" Duty Cycle: Variable -> ");
UARTprintf("0.1%% to 75%% in 0.1%% increments.\n");
UARTprintf(" Features: ");
UARTprintf("Variable pulse-width done using a reload interrupt.\n\n");
UARTprintf("Generating PWM on PWM0 (PD0) -> ");
//
// The PWM peripheral must be enabled for use.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM);
//
// For this example PWM0 is used with PortD Pin0. The actual port and pins
// used may be different on your part, consult the data sheet for more
// information. GPIO port D needs to be enabled so these pins can be used.
// TODO: change this to whichever GPIO port you are using.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
//
// Configure the GPIO pin muxing to select PWM00 functions for these pins.
// This step selects which alternate function is available for these pins.
// This is necessary if your part supports GPIO pin function muxing.
// Consult the data sheet to see which functions are allocated per pin.
// TODO: change this to select the port/pin you are using.
//
GPIOPinConfigure(GPIO_PD0_PWM0);
//
// Configure the PWM function for this pin.
// Consult the data sheet to see which functions are allocated per pin.
// TODO: change this to select the port/pin you are using.
//
GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_0);
//
// Configure the PWM0 to count down without synchronization.
//
PWMGenConfigure(PWM_BASE, PWM_GEN_0, PWM_GEN_MODE_DOWN |
PWM_GEN_MODE_NO_SYNC);
//
// Set the PWM period to 250Hz. To calculate the appropriate parameter
// use the following equation: N = (1 / f) * SysClk. Where N is the
// function parameter, f is the desired frequency, and SysClk is the
// system clock frequency.
// In this case you get: (1 / 250Hz) * 16MHz = 64000 cycles. Note that
// the maximum period you can set is 2^16.
//
PWMGenPeriodSet(PWM_BASE, PWM_GEN_0, 64000);
//
// For this example the PWM0 duty cycle will be variable. The duty cycle
// will start at 0.1% (0.01 * 64000 cycles = 640 cycles) and will increase
// to 75% (0.5 * 64000 cycles = 32000 cycles). After a duty cycle of 75%
// is reached, it is reset to 0.1%. This dynamic adjustment of the pulse
// width is done in the PWM0 load interrupt, which increases the duty
// cycle by 0.1% everytime the reload interrupt is received.
//
PWMPulseWidthSet(PWM_BASE, PWM_OUT_0, 64);
//
// Enable processor interrupts.
//
IntMasterEnable();
//
// Allow PWM0 generated interrupts. This configuration is done to
// differentiate fault interrupts from other PWM0 related interrupts.
//
PWMIntEnable(PWM_BASE, PWM_INT_GEN_0);
//
// Enable the PWM0 LOAD interrupt on PWM0.
//
PWMGenIntTrigEnable(PWM_BASE, PWM_GEN_0, PWM_INT_CNT_LOAD);
//
// Enable the PWM0 interrupts on the processor (NVIC).
//
IntEnable(INT_PWM0);
//
// Enable the PWM0 output signal (PD0).
//
PWMOutputState(PWM_BASE, PWM_OUT_0_BIT, true);
//
// Enables the PWM generator block.
//
PWMGenEnable(PWM_BASE, PWM_GEN_0);
//
// Loop forever while the PWM signals are generated and PWM0 interrupts
// get received.
//
while(1)
{
//
// Print out indication on the console that the program is running.
//
PrintRunningDots();
}
}
*************************************************
uartstdio.c
************************************************
//*****************************************************************************
//
// uartstdio.c - Utility driver to provide simple UART console functions.
//
//
//*****************************************************************************
#include
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_uart.h"
#include "driverlib/debug.h"
#include "driverlib/interrupt.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
//*****************************************************************************
//
//! \addtogroup uartstdio_api
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// If buffered mode is defined, set aside RX and TX buffers and read/write
// pointers to control them.
//
//*****************************************************************************
#ifdef UART_BUFFERED
//*****************************************************************************
//
// This global controls whether or not we are echoing characters back to the
// transmitter. By default, echo is enabled but if using this module as a
// convenient method of implementing a buffered serial interface over which
// you will be running an application protocol, you are likely to want to
// disable echo by calling UARTEchoSet(false).
//
//*****************************************************************************
static tBoolean g_bDisableEcho;
//*****************************************************************************
//
// Output ring buffer. Buffer is full if g_ulUARTTxReadIndex is one ahead of
// g_ulUARTTxWriteIndex. Buffer is empty if the two indices are the same.
//
//*****************************************************************************
static unsigned char g_pcUARTTxBuffer[UART_TX_BUFFER_SIZE];
static volatile unsigned long g_ulUARTTxWriteIndex = 0;
static volatile unsigned long g_ulUARTTxReadIndex = 0;
//*****************************************************************************
//
// Input ring buffer. Buffer is full if g_ulUARTTxReadIndex is one ahead of
// g_ulUARTTxWriteIndex. Buffer is empty if the two indices are the same.
//
//*****************************************************************************
static unsigned char g_pcUARTRxBuffer[UART_RX_BUFFER_SIZE];
static volatile unsigned long g_ulUARTRxWriteIndex = 0;
static volatile unsigned long g_ulUARTRxReadIndex = 0;
//*****************************************************************************
//
// Macros to determine number of free and used bytes in the transmit buffer.
//
//*****************************************************************************
#define TX_BUFFER_USED (GetBufferCount(&g_ulUARTTxReadIndex, \
&g_ulUARTTxWriteIndex, \
UART_TX_BUFFER_SIZE))
#define TX_BUFFER_FREE (UART_TX_BUFFER_SIZE - TX_BUFFER_USED)
#define TX_BUFFER_EMPTY (IsBufferEmpty(&g_ulUARTTxReadIndex, \
&g_ulUARTTxWriteIndex))
#define TX_BUFFER_FULL (IsBufferFull(&g_ulUARTTxReadIndex, \
&g_ulUARTTxWriteIndex, \
UART_TX_BUFFER_SIZE))
#define ADVANCE_TX_BUFFER_INDEX(Index) \
(Index) = ((Index) + 1) % UART_TX_BUFFER_SIZE
//*****************************************************************************
//
// Macros to determine number of free and used bytes in the receive buffer.
//
//*****************************************************************************
#define RX_BUFFER_USED (GetBufferCount(&g_ulUARTRxReadIndex, \
&g_ulUARTRxWriteIndex, \
UART_RX_BUFFER_SIZE))
#define RX_BUFFER_FREE (UART_RX_BUFFER_SIZE - RX_BUFFER_USED)
#define RX_BUFFER_EMPTY (IsBufferEmpty(&g_ulUARTRxReadIndex, \
&g_ulUARTRxWriteIndex))
#define RX_BUFFER_FULL (IsBufferFull(&g_ulUARTRxReadIndex, \
&g_ulUARTRxWriteIndex, \
UART_RX_BUFFER_SIZE))
#define ADVANCE_RX_BUFFER_INDEX(Index) \
(Index) = ((Index) + 1) % UART_RX_BUFFER_SIZE
#endif
//*****************************************************************************
//
// The base address of the chosen UART.
//
//*****************************************************************************
static unsigned long g_ulBase = 0;
//*****************************************************************************
//
// A mapping from an integer between 0 and 15 to its ASCII character
// equivalent.
//
//*****************************************************************************
static const char * const g_pcHex = "0123456789abcdef";
//*****************************************************************************
//
// The list of possible base addresses for the console UART.
//
//*****************************************************************************
static const unsigned long g_ulUARTBase[3] =
{
UART0_BASE, UART1_BASE, UART2_BASE
};
#ifdef UART_BUFFERED
//*****************************************************************************
//
// The list of possible interrupts for the console UART.
//
//*****************************************************************************
static const unsigned long g_ulUARTInt[3] =
{
INT_UART0, INT_UART1, INT_UART2
};
//*****************************************************************************
//
// The port number in use.
//
//*****************************************************************************
static unsigned long g_ulPortNum;
#endif
//*****************************************************************************
//
// The list of UART peripherals.
//
//*****************************************************************************
static const unsigned long g_ulUARTPeriph[3] =
{
SYSCTL_PERIPH_UART0, SYSCTL_PERIPH_UART1, SYSCTL_PERIPH_UART2
};
//*****************************************************************************
//
//! Determines whether the ring buffer whose pointers and size are provided
//! is full or not.
//!
//! \param pulRead points to the read index for the buffer.
//! \param pulWrite points to the write index for the buffer.
//! \param ulSize is the size of the buffer in bytes.
//!
//! This function is used to determine whether or not a given ring buffer is
//! full. The structure of the code is specifically to ensure that we do not
//! see warnings from the compiler related to the order of volatile accesses
//! being undefined.
//!
//! \return Returns \b true if the buffer is full or \b false otherwise.
//
//*****************************************************************************
#ifdef UART_BUFFERED
static tBoolean
IsBufferFull(volatile unsigned long *pulRead,
volatile unsigned long *pulWrite, unsigned long ulSize)
{
unsigned long ulWrite;
unsigned long ulRead;
ulWrite = *pulWrite;
ulRead = *pulRead;
return((((ulWrite + 1) % ulSize) == ulRead) ? true : false);
}
#endif
//*****************************************************************************
//
//! Determines whether the ring buffer whose pointers and size are provided
//! is empty or not.
//!
//! \param pulRead points to the read index for the buffer.
//! \param pulWrite points to the write index for the buffer.
//!
//! This function is used to determine whether or not a given ring buffer is
//! empty. The structure of the code is specifically to ensure that we do not
//! see warnings from the compiler related to the order of volatile accesses
//! being undefined.
//!
//! \return Returns \b true if the buffer is empty or \b false otherwise.
//
//*****************************************************************************
#ifdef UART_BUFFERED
static tBoolean
IsBufferEmpty(volatile unsigned long *pulRead,
volatile unsigned long *pulWrite)
{
unsigned long ulWrite;
unsigned long ulRead;
ulWrite = *pulWrite;
ulRead = *pulRead;
return((ulWrite == ulRead) ? true : false);
}
#endif
//*****************************************************************************
//
//! Determines the number of bytes of data contained in a ring buffer.
//!
//! \param pulRead points to the read index for the buffer.
//! \param pulWrite points to the write index for the buffer.
//! \param ulSize is the size of the buffer in bytes.
//!
//! This function is used to determine how many bytes of data a given ring
//! buffer currently contains. The structure of the code is specifically to
//! ensure that we do not see warnings from the compiler related to the order
//! of volatile accesses being undefined.
//!
//! \return Returns the number of bytes of data currently in the buffer.
//
//*****************************************************************************
#ifdef UART_BUFFERED
static unsigned long
GetBufferCount(volatile unsigned long *pulRead,
volatile unsigned long *pulWrite, unsigned long ulSize)
{
unsigned long ulWrite;
unsigned long ulRead;
ulWrite = *pulWrite;
ulRead = *pulRead;
return((ulWrite >= ulRead) ? (ulWrite - ulRead) :
(ulSize - (ulRead - ulWrite)));
}
#endif
//*****************************************************************************
//
// Take as many bytes from the transmit buffer as we have space for and move
// them into the UART transmit FIFO.
//
//*****************************************************************************
#ifdef UART_BUFFERED
static void
UARTPrimeTransmit(unsigned long ulBase)
{
//
// Do we have any data to transmit?
//
if(!TX_BUFFER_EMPTY)
{
//
// Disable the UART interrupt. If we don't do this there is a race
// condition which can cause the read index to be corrupted.
//
MAP_IntDisable(g_ulUARTInt[g_ulPortNum]);
//
// Yes - take some characters out of the transmit buffer and feed
// them to the UART transmit FIFO.
//
while(MAP_UARTSpaceAvail(ulBase) && !TX_BUFFER_EMPTY)
{
MAP_UARTCharPutNonBlocking(ulBase,
g_pcUARTTxBuffer[g_ulUARTTxReadIndex]);
ADVANCE_TX_BUFFER_INDEX(g_ulUARTTxReadIndex);
}
//
// Reenable the UART interrupt.
//
MAP_IntEnable(g_ulUARTInt[g_ulPortNum]);
}
}
#endif
//*****************************************************************************
//
//! Initializes the UART console.
//!
//! \param ulPortNum is the number of UART port to use for the serial console
//! (0-2)
//!
//! This function will initialize the specified serial port to be used as a
//! serial console. The serial parameters will be set to 115200, 8-N-1.
//! An application wishing to use a different baud rate may call
//! UARTStdioInitExpClk() instead of this function.
//!
//! This function or UARTStdioInitExpClk() must be called prior to using any
//! of the other UART console functions: UARTprintf() or UARTgets(). In order
//! for this function to work correctly, SysCtlClockSet() must be called prior
//! to calling this function.
//!
//! It is assumed that the caller has previously configured the relevant UART
//! pins for operation as a UART rather than as GPIOs.
//!
//! \return None.
//
//*****************************************************************************
void
UARTStdioInit(unsigned long ulPortNum)
{
//
// Pass this call on to the version of the function allowing the baud rate
// to be specified.
//
UARTStdioInitExpClk(ulPortNum, 115200);
}
//*****************************************************************************
//
//! Initializes the UART console and allows the baud rate to be selected.
//!
//! \param ulPortNum is the number of UART port to use for the serial console
//! (0-2)
//! \param ulBaud is the bit rate that the UART is to be configured to use.
//!
//! This function will initialize the specified serial port to be used as a
//! serial console. The serial parameters will be set to 8-N-1 and the bit
//! rate set according to the value of the \e ulBaud parameter.
//!
//! This function or UARTStdioInit() must be called prior to using any of the
//! other UART console functions: UARTprintf() or UARTgets(). In order for
//! this function to work correctly, SysCtlClockSet() must be called prior to
//! calling this function. An application wishing to use 115,200 baud may call
//! UARTStdioInit() instead of this function but should not call both
//! functions.
//!
//! It is assumed that the caller has previously configured the relevant UART
//! pins for operation as a UART rather than as GPIOs.
//!
//! \return None.
//
//*****************************************************************************
void
UARTStdioInitExpClk(unsigned long ulPortNum, unsigned long ulBaud)
{
//
// Check the arguments.
//
ASSERT((ulPortNum == 0) || (ulPortNum == 1) ||
(ulPortNum == 2));
#ifdef UART_BUFFERED
//
// In buffered mode, we only allow a single instance to be opened.
//
ASSERT(g_ulBase == 0);
#endif
//
// Check to make sure the UART peripheral is present.
//
if(!MAP_SysCtlPeripheralPresent(g_ulUARTPeriph[ulPortNum]))
{
return;
}
//
// Select the base address of the UART.
//
g_ulBase = g_ulUARTBase[ulPortNum];
//
// Enable the UART peripheral for use.
//
MAP_SysCtlPeripheralEnable(g_ulUARTPeriph[ulPortNum]);
//
// Configure the UART for 115200, n, 8, 1
//
MAP_UARTConfigSetExpClk(g_ulBase, MAP_SysCtlClockGet(), ulBaud,
(UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE |
UART_CONFIG_WLEN_8));
#ifdef UART_BUFFERED
//
// Set the UART to interrupt whenever the TX FIFO is almost empty or
// when any character is received.
//
MAP_UARTFIFOLevelSet(g_ulBase, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
//
// Flush both the buffers.
//
UARTFlushRx();
UARTFlushTx(true);
//
// Remember which interrupt we are dealing with.
//
g_ulPortNum = ulPortNum;
//
// We are configured for buffered output so enable the master interrupt
// for this UART and the receive interrupts. We don't actually enable the
// transmit interrupt in the UART itself until some data has been placed
// in the transmit buffer.
//
MAP_UARTIntDisable(g_ulBase, 0xFFFFFFFF);
MAP_UARTIntEnable(g_ulBase, UART_INT_RX | UART_INT_RT);
MAP_IntEnable(g_ulUARTInt[ulPortNum]);
#endif
//
// Enable the UART operation.
//
MAP_UARTEnable(g_ulBase);
}
//*****************************************************************************
//
//! Writes a string of characters to the UART output.
//!
//! \param pcBuf points to a buffer containing the string to transmit.
//! \param ulLen is the length of the string to transmit.
//!
//! This function will transmit the string to the UART output. The number of
//! characters transmitted is determined by the \e ulLen parameter. This
//! function does no interpretation or translation of any characters. Since
//! the output is sent to a UART, any LF (/n) characters encountered will be
//! replaced with a CRLF pair.
//!
//! Besides using the \e ulLen parameter to stop transmitting the string, if a
//! null character (0) is encountered, then no more characters will be
//! transmitted and the function will return.
//!
//! In non-buffered mode, this function is blocking and will not return until
//! all the characters have been written to the output FIFO. In buffered mode,
//! the characters are written to the UART transmit buffer and the call returns
//! immediately. If insufficient space remains in the transmit buffer,
//! additional characters are discarded.
//!
//! \return Returns the count of characters written.
//
//*****************************************************************************
int
UARTwrite(const char *pcBuf, unsigned long ulLen)
{
#ifdef UART_BUFFERED
unsigned int uIdx;
//
// Check for valid arguments.
//
ASSERT(pcBuf != 0);
ASSERT(g_ulBase != 0);
//
// Send the characters
//
for(uIdx = 0; uIdx < ulLen; uIdx++)
{
//
// If the character to the UART is \n, then add a \r before it so that
// \n is translated to \n\r in the output.
//
if(pcBuf[uIdx] == '\n')
{
if(!TX_BUFFER_FULL)
{
g_pcUARTTxBuffer[g_ulUARTTxWriteIndex] = '\r';
ADVANCE_TX_BUFFER_INDEX(g_ulUARTTxWriteIndex);
}
else
{
//
// Buffer is full - discard remaining characters and return.
//
break;
}
}
//
// Send the character to the UART output.
//
if(!TX_BUFFER_FULL)
{
g_pcUARTTxBuffer[g_ulUARTTxWriteIndex] = pcBuf[uIdx];
ADVANCE_TX_BUFFER_INDEX(g_ulUARTTxWriteIndex);
}
else
{
//
// Buffer is full - discard remaining characters and return.
//
break;
}
}
//
// If we have anything in the buffer, make sure that the UART is set
// up to transmit it.
//
if(!TX_BUFFER_EMPTY)
{
UARTPrimeTransmit(g_ulBase);
MAP_UARTIntEnable(g_ulBase, UART_INT_TX);
}
//
// Return the number of characters written.
//
return(uIdx);
#else
unsigned int uIdx;
//
// Check for valid UART base address, and valid arguments.
//
ASSERT(g_ulBase != 0);
ASSERT(pcBuf != 0);
//
// Send the characters
//
for(uIdx = 0; uIdx < ulLen; uIdx++)
{
//
// If the character to the UART is \n, then add a \r before it so that
// \n is translated to \n\r in the output.
//
if(pcBuf[uIdx] == '\n')
{
MAP_UARTCharPut(g_ulBase, '\r');
}
//
// Send the character to the UART output.
//
MAP_UARTCharPut(g_ulBase, pcBuf[uIdx]);
}
//
// Return the number of characters written.
//
return(uIdx);
#endif
}
//*****************************************************************************
//
//! A simple UART based get string function, with some line processing.
//!
//! \param pcBuf points to a buffer for the incoming string from the UART.
//! \param ulLen is the length of the buffer for storage of the string,
//! including the trailing 0.
//!
//! This function will receive a string from the UART input and store the
//! characters in the buffer pointed to by \e pcBuf. The characters will
//! continue to be stored until a termination character is received. The
//! termination characters are CR, LF, or ESC. A CRLF pair is treated as a
//! single termination character. The termination characters are not stored in
//! the string. The string will be terminated with a 0 and the function will
//! return.
//!
//! In both buffered and unbuffered modes, this function will block until
//! a termination character is received. If non-blocking operation is required
//! in buffered mode, a call to UARTPeek() may be made to determine whether
//! a termination character already exists in the receive buffer prior to
//! calling UARTgets().
//!
//! Since the string will be null terminated, the user must ensure that the
//! buffer is sized to allow for the additional null character.
//!
//! \return Returns the count of characters that were stored, not including
//! the trailing 0.
//
//*****************************************************************************
int
UARTgets(char *pcBuf, unsigned long ulLen)
{
#ifdef UART_BUFFERED
unsigned long ulCount = 0;
char cChar;
//
// Check the arguments.
//
ASSERT(pcBuf != 0);
ASSERT(ulLen != 0);
ASSERT(g_ulBase != 0);
//
// Adjust the length back by 1 to leave space for the trailing
// null terminator.
//
ulLen--;
//
// Process characters until a newline is received.
//
while(1)
{
//
// Read the next character from the receive buffer.
//
if(!RX_BUFFER_EMPTY)
{
cChar = g_pcUARTRxBuffer[g_ulUARTRxReadIndex];
ADVANCE_RX_BUFFER_INDEX(g_ulUARTRxReadIndex);
//
// See if a newline or escape character was received.
//
if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
{
//
// Stop processing the input and end the line.
//
break;
}
//
// Process the received character as long as we are not at the end
// of the buffer. If the end of the buffer has been reached then
// all additional characters are ignored until a newline is
// received.
//
if(ulCount < ulLen)
{
//
// Store the character in the caller supplied buffer.
//
pcBuf[ulCount] = cChar;
//
// Increment the count of characters received.
//
ulCount++;
}
}
}
//
// Add a null termination to the string.
//
pcBuf[ulCount] = 0;
//
// Return the count of chars in the buffer, not counting the trailing 0.
//
return(ulCount);
#else
unsigned long ulCount = 0;
char cChar;
static char bLastWasCR = 0;
//
// Check the arguments.
//
ASSERT(pcBuf != 0);
ASSERT(ulLen != 0);
ASSERT(g_ulBase != 0);
//
// Adjust the length back by 1 to leave space for the trailing
// null terminator.
//
ulLen--;
//
// Process characters until a newline is received.
//
while(1)
{
//
// Read the next character from the console.
//
cChar = MAP_UARTCharGet(g_ulBase);
//
// See if the backspace key was pressed.
//
if(cChar == '\b')
{
//
// If there are any characters already in the buffer, then delete
// the last.
//
if(ulCount)
{
//
// Rub out the previous character.
//
UARTwrite("\b \b", 3);
//
// Decrement the number of characters in the buffer.
//
ulCount--;
}
//
// Skip ahead to read the next character.
//
continue;
}
//
// If this character is LF and last was CR, then just gobble up the
// character because the EOL processing was taken care of with the CR.
//
if((cChar == '\n') && bLastWasCR)
{
bLastWasCR = 0;
continue;
}
//
// See if a newline or escape character was received.
//
if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
{
//
// If the character is a CR, then it may be followed by a LF which
// should be paired with the CR. So remember that a CR was
// received.
//
if(cChar == '\r')
{
bLastWasCR = 1;
}
//
// Stop processing the input and end the line.
//
break;
}
//
// Process the received character as long as we are not at the end of
// the buffer. If the end of the buffer has been reached then all
// additional characters are ignored until a newline is received.
//
if(ulCount < ulLen)
{
//
// Store the character in the caller supplied buffer.
//
pcBuf[ulCount] = cChar;
//
// Increment the count of characters received.
//
ulCount++;
//
// Reflect the character back to the user.
//
MAP_UARTCharPut(g_ulBase, cChar);
}
}
//
// Add a null termination to the string.
//
pcBuf[ulCount] = 0;
//
// Send a CRLF pair to the terminal to end the line.
//
UARTwrite("\r\n", 2);
//
// Return the count of chars in the buffer, not counting the trailing 0.
//
return(ulCount);
#endif
}
//*****************************************************************************
//
//! Read a single character from the UART, blocking if necessary.
//!
//! This function will receive a single character from the UART and store it at
//! the supplied address.
//!
//! In both buffered and unbuffered modes, this function will block until a
//! character is received. If non-blocking operation is required in buffered
//! mode, a call to UARTRxAvail() may be made to determine whether any
//! characters are currently available for reading.
//!
//! \return Returns the character read.
//
//*****************************************************************************
unsigned char
UARTgetc(void)
{
#ifdef UART_BUFFERED
unsigned char cChar;
//
// Wait for a character to be received.
//
while(RX_BUFFER_EMPTY)
{
//
// Block waiting for a character to be received (if the buffer is
// currently empty).
//
}
//
// Read a character from the buffer.
//
cChar = g_pcUARTRxBuffer[g_ulUARTRxReadIndex];
ADVANCE_RX_BUFFER_INDEX(g_ulUARTRxReadIndex);
//
// Return the character to the caller.
//
return(cChar);
#else
//
// Block until a character is received by the UART then return it to
// the caller.
//
return(MAP_UARTCharGet(g_ulBase));
#endif
}
//*****************************************************************************
//
//! A simple UART based printf function supporting \%c, \%d, \%p, \%s, \%u,
//! \%x, and \%X.
//!
//! \param pcString is the format string.
//! \param ... are the optional arguments, which depend on the contents of the
//! format string.
//!
//! This function is very similar to the C library fprintf() function.
//! All of its output will be sent to the UART. Only the following formatting
//! characters are supported:
//!
//! - \%c to print a character
//! - \%d to print a decimal value
//! - \%s to print a string
//! - \%u to print an unsigned decimal value
//! - \%x to print a hexadecimal value using lower case letters
//! - \%X to print a hexadecimal value using lower case letters (not upper case
//! letters as would typically be used)
//! - \%p to print a pointer as a hexadecimal value
//! - \%\% to print out a \% character
//!
//! For \%s, \%d, \%u, \%p, \%x, and \%X, an optional number may reside
//! between the \% and the format character, which specifies the minimum number
//! of characters to use for that value; if preceded by a 0 then the extra
//! characters will be filled with zeros instead of spaces. For example,
//! ``\%8d'' will use eight characters to print the decimal value with spaces
//! added to reach eight; ``\%08d'' will use eight characters as well but will
//! add zeroes instead of spaces.
//!
//! The type of the arguments after \e pcString must match the requirements of
//! the format string. For example, if an integer was passed where a string
//! was expected, an error of some kind will most likely occur.
//!
//! \return None.
//
//*****************************************************************************
void
UARTprintf(const char *pcString, ...)
{
unsigned long ulIdx, ulValue, ulPos, ulCount, ulBase, ulNeg;
char *pcStr, pcBuf[16], cFill;
va_list vaArgP;
//
// Check the arguments.
//
ASSERT(pcString != 0);
//
// Start the varargs processing.
//
va_start(vaArgP, pcString);
//
// Loop while there are more characters in the string.
//
while(*pcString)
{
//
// Find the first non-% character, or the end of the string.
//
for(ulIdx = 0; (pcString[ulIdx] != '%') && (pcString[ulIdx] != '\0');
ulIdx++)
{
}
//
// Write this portion of the string.
//
UARTwrite(pcString, ulIdx);
//
// Skip the portion of the string that was written.
//
pcString += ulIdx;
//
// See if the next character is a %.
//
if(*pcString == '%')
{
//
// Skip the %.
//
pcString++;
//
// Set the digit count to zero, and the fill character to space
// (i.e. to the defaults).
//
ulCount = 0;
cFill = ' ';
//
// It may be necessary to get back here to process more characters.
// Goto's aren't pretty, but effective. I feel extremely dirty for
// using not one but two of the beasts.
//
again:
//
// Determine how to handle the next character.
//
switch(*pcString++)
{
//
// Handle the digit characters.
//
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
//
// If this is a zero, and it is the first digit, then the
// fill character is a zero instead of a space.
//
if((pcString[-1] == '0') && (ulCount == 0))
{
cFill = '0';
}
//
// Update the digit count.
//
ulCount *= 10;
ulCount += pcString[-1] - '0';
//
// Get the next character.
//
goto again;
}
//
// Handle the %c command.
//
case 'c':
{
//
// Get the value from the varargs.
//
ulValue = va_arg(vaArgP, unsigned long);
//
// Print out the character.
//
UARTwrite((char *)&ulValue, 1);
//
// This command has been handled.
//
break;
}
//
// Handle the %d command.
//
case 'd':
{
//
// Get the value from the varargs.
//
ulValue = va_arg(vaArgP, unsigned long);
//
// Reset the buffer position.
//
ulPos = 0;
//
// If the value is negative, make it positive and indicate
// that a minus sign is needed.
//
if((long)ulValue < 0)
{
//
// Make the value positive.
//
ulValue = -(long)ulValue;
//
// Indicate that the value is negative.
//
ulNeg = 1;
}
else
{
//
// Indicate that the value is positive so that a minus
// sign isn't inserted.
//
ulNeg = 0;
}
//
// Set the base to 10.
//
ulBase = 10;
//
// Convert the value to ASCII.
//
goto convert;
}
//
// Handle the %s command.
//
case 's':
{
//
// Get the string pointer from the varargs.
//
pcStr = va_arg(vaArgP, char *);
//
// Determine the length of the string.
//
for(ulIdx = 0; pcStr[ulIdx] != '\0'; ulIdx++)
{
}
//
// Write the string.
//
UARTwrite(pcStr, ulIdx);
//
// Write any required padding spaces
//
if(ulCount > ulIdx)
{
ulCount -= ulIdx;
while(ulCount--)
{
UARTwrite(" ", 1);
}
}
//
// This command has been handled.
//
break;
}
//
// Handle the %u command.
//
case 'u':
{
//
// Get the value from the varargs.
//
ulValue = va_arg(vaArgP, unsigned long);
//
// Reset the buffer position.
//
ulPos = 0;
//
// Set the base to 10.
//
ulBase = 10;
//
// Indicate that the value is positive so that a minus sign
// isn't inserted.
//
ulNeg = 0;
//
// Convert the value to ASCII.
//
goto convert;
}
//
// Handle the %x and %X commands. Note that they are treated
// identically; i.e. %X will use lower case letters for a-f
// instead of the upper case letters is should use. We also
// alias %p to %x.
//
case 'x':
case 'X':
case 'p':
{
//
// Get the value from the varargs.
//
ulValue = va_arg(vaArgP, unsigned long);
//
// Reset the buffer position.
//
ulPos = 0;
//
// Set the base to 16.
//
ulBase = 16;
//
// Indicate that the value is positive so that a minus sign
// isn't inserted.
//
ulNeg = 0;
//
// Determine the number of digits in the string version of
// the value.
//
convert:
for(ulIdx = 1;
(((ulIdx * ulBase) <= ulValue) &&
(((ulIdx * ulBase) / ulBase) == ulIdx));
ulIdx *= ulBase, ulCount--)
{
}
//
// If the value is negative, reduce the count of padding
// characters needed.
//
if(ulNeg)
{
ulCount--;
}
//
// If the value is negative and the value is padded with
// zeros, then place the minus sign before the padding.
//
if(ulNeg && (cFill == '0'))
{
//
// Place the minus sign in the output buffer.
//
pcBuf[ulPos++] = '-';
//
// The minus sign has been placed, so turn off the
// negative flag.
//
ulNeg = 0;
}
//
// Provide additional padding at the beginning of the
// string conversion if needed.
//
if((ulCount > 1) && (ulCount < 16))
{
for(ulCount--; ulCount; ulCount--)
{
pcBuf[ulPos++] = cFill;
}
}
//
// If the value is negative, then place the minus sign
// before the number.
//
if(ulNeg)
{
//
// Place the minus sign in the output buffer.
//
pcBuf[ulPos++] = '-';
}
//
// Convert the value into a string.
//
for(; ulIdx; ulIdx /= ulBase)
{
pcBuf[ulPos++] = g_pcHex[(ulValue / ulIdx) % ulBase];
}
//
// Write the string.
//
UARTwrite(pcBuf, ulPos);
//
// This command has been handled.
//
break;
}
//
// Handle the %% command.
//
case '%':
{
//
// Simply write a single %.
//
UARTwrite(pcString - 1, 1);
//
// This command has been handled.
//
break;
}
//
// Handle all other commands.
//
default:
{
//
// Indicate an error.
//
UARTwrite("ERROR", 5);
//
// This command has been handled.
//
break;
}
}
}
}
//
// End the varargs processing.
//
va_end(vaArgP);
}
//*****************************************************************************
//
//! Returns the number of bytes available in the receive buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to determine the number
//! of bytes of data currently available in the receive buffer.
//!
//! \return Returns the number of available bytes.
//
//*****************************************************************************
#if defined(UART_BUFFERED) || defined(DOXYGEN)
int
UARTRxBytesAvail(void)
{
return(RX_BUFFER_USED);
}
#endif
#if defined(UART_BUFFERED) || defined(DOXYGEN)
//*****************************************************************************
//
//! Returns the number of bytes free in the transmit buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to determine the amount
//! of space currently available in the transmit buffer.
//!
//! \return Returns the number of free bytes.
//
//*****************************************************************************
int
UARTTxBytesFree(void)
{
return(TX_BUFFER_FREE);
}
#endif
//*****************************************************************************
//
//! Looks ahead in the receive buffer for a particular character.
//!
//! \param ucChar is the character that is to be searched for.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to look ahead in the
//! receive buffer for a particular character and report its position if found.
//! It is typically used to determine whether a complete line of user input is
//! available, in which case ucChar should be set to CR ('\\r') which is used
//! as the line end marker in the receive buffer.
//!
//! \return Returns -1 to indicate that the requested character does not exist
//! in the receive buffer. Returns a non-negative number if the character was
//! found in which case the value represents the position of the first instance
//! of \e ucChar relative to the receive buffer read pointer.
//
//*****************************************************************************
#if defined(UART_BUFFERED) || defined(DOXYGEN)
int
UARTPeek(unsigned char ucChar)
{
int iCount;
int iAvail;
unsigned long ulReadIndex;
//
// How many characters are there in the receive buffer?
//
iAvail = (int)RX_BUFFER_USED;
ulReadIndex = g_ulUARTRxReadIndex;
//
// Check all the unread characters looking for the one passed.
//
for(iCount = 0; iCount < iAvail; iCount++)
{
if(g_pcUARTRxBuffer[ulReadIndex] == ucChar)
{
//
// We found it so return the index
//
return(iCount);
}
else
{
//
// This one didn't match so move on to the next character.
//
ADVANCE_RX_BUFFER_INDEX(ulReadIndex);
}
}
//
// If we drop out of the loop, we didn't find the character in the receive
// buffer.
//
return(-1);
}
#endif
//*****************************************************************************
//
//! Flushes the receive buffer.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to discard any data
//! received from the UART but not yet read using UARTgets().
//!
//! \return None.
//
//*****************************************************************************
#if defined(UART_BUFFERED) || defined(DOXYGEN)
void
UARTFlushRx(void)
{
unsigned long ulInt;
//
// Temporarily turn off interrupts.
//
ulInt = IntMasterDisable();
//
// Flush the receive buffer.
//
g_ulUARTRxReadIndex = 0;
g_ulUARTRxWriteIndex = 0;
//
// If interrupts were enabled when we turned them off, turn them
// back on again.
//
if(!ulInt)
{
IntMasterEnable();
}
}
#endif
//*****************************************************************************
//
//! Flushes the transmit buffer.
//!
//! \param bDiscard indicates whether any remaining data in the buffer should
//! be discarded (\b true) or transmitted (\b false).
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to flush the transmit
//! buffer, either discarding or transmitting any data received via calls to
//! UARTprintf() that is waiting to be transmitted. On return, the transmit
//! buffer will be empty.
//!
//! \return None.
//
//*****************************************************************************
#if defined(UART_BUFFERED) || defined(DOXYGEN)
void
UARTFlushTx(tBoolean bDiscard)
{
unsigned long ulInt;
//
// Should the remaining data be discarded or transmitted?
//
if(bDiscard)
{
//
// The remaining data should be discarded, so temporarily turn off
// interrupts.
//
ulInt = IntMasterDisable();
//
// Flush the transmit buffer.
//
g_ulUARTTxReadIndex = 0;
g_ulUARTTxWriteIndex = 0;
//
// If interrupts were enabled when we turned them off, turn them
// back on again.
//
if(!ulInt)
{
IntMasterEnable();
}
}
else
{
//
// Wait for all remaining data to be transmitted before returning.
//
while(!TX_BUFFER_EMPTY)
{
}
}
}
#endif
//*****************************************************************************
//
//! Enables or disables echoing of received characters to the transmitter.
//!
//! \param bEnable must be set to \b true to enable echo or \b false to
//! disable it.
//!
//! This function, available only when the module is built to operate in
//! buffered mode using \b UART_BUFFERED, may be used to control whether or not
//! received characters are automatically echoed back to the transmitter. By
//! default, echo is enabled and this is typically the desired behavior if
//! the module is being used to support a serial command line. In applications
//! where this module is being used to provide a convenient, buffered serial
//! interface over which application-specific binary protocols are being run,
//! however, echo may be undesirable and this function can be used to disable
//! it.
//!
//! \return None.
//
//*****************************************************************************
#if defined(UART_BUFFERED) || defined(DOXYGEN)
void
UARTEchoSet(tBoolean bEnable)
{
g_bDisableEcho = !bEnable;
}
#endif
//*****************************************************************************
//
//! Handles UART interrupts.
//!
//! This function handles interrupts from the UART. It will copy data from the
//! transmit buffer to the UART transmit FIFO if space is available, and it
//! will copy data from the UART receive FIFO to the receive buffer if data is
//! available.
//!
//! \return None.
//
//*****************************************************************************
#if defined(UART_BUFFERED) || defined(DOXYGEN)
void
UARTStdioIntHandler(void)
{
unsigned long ulInts;
char cChar;
long lChar;
static tBoolean bLastWasCR = false;
//
// Get and clear the current interrupt source(s)
//
ulInts = MAP_UARTIntStatus(g_ulBase, true);
MAP_UARTIntClear(g_ulBase, ulInts);
//
// Are we being interrupted because the TX FIFO has space available?
//
if(ulInts & UART_INT_TX)
{
//
// Move as many bytes as we can into the transmit FIFO.
//
UARTPrimeTransmit(g_ulBase);
//
// If the output buffer is empty, turn off the transmit interrupt.
//
if(TX_BUFFER_EMPTY)
{
MAP_UARTIntDisable(g_ulBase, UART_INT_TX);
}
}
//
// Are we being interrupted due to a received character?
//
if(ulInts & (UART_INT_RX | UART_INT_RT))
{
//
// Get all the available characters from the UART.
//
while(MAP_UARTCharsAvail(g_ulBase))
{
//
// Read a character
//
lChar = MAP_UARTCharGetNonBlocking(g_ulBase);
cChar = (unsigned char)(lChar & 0xFF);
//
// If echo is disabled, we skip the various text filtering
// operations that would typically be required when supporting a
// command line.
//
if(!g_bDisableEcho)
{
//
// Handle backspace by erasing the last character in the buffer.
//
if(cChar == '\b')
{
//
// If there are any characters already in the buffer, then
// delete the last.
//
if(!RX_BUFFER_EMPTY)
{
//
// Rub out the previous character on the users terminal.
//
UARTwrite("\b \b", 3);
//
// Decrement the number of characters in the buffer.
//
if(g_ulUARTRxWriteIndex == 0)
{
g_ulUARTRxWriteIndex = UART_RX_BUFFER_SIZE - 1;
}
else
{
g_ulUARTRxWriteIndex--;
}
}
//
// Skip ahead to read the next character.
//
continue;
}
//
// If this character is LF and last was CR, then just gobble up
// the character since we already echoed the previous CR and we
// don't want to store 2 characters in the buffer if we don't
// need to.
//
if((cChar == '\n') && bLastWasCR)
{
bLastWasCR = false;
continue;
}
//
// See if a newline or escape character was received.
//
if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
{
//
// If the character is a CR, then it may be followed by an
// LF which should be paired with the CR. So remember that
// a CR was received.
//
if(cChar == '\r')
{
bLastWasCR = 1;
}
//
// Regardless of the line termination character received,
// put a CR in the receive buffer as a marker telling
// UARTgets() where the line ends. We also send an
// additional LF to ensure that the local terminal echo
// receives both CR and LF.
//
cChar = '\r';
UARTwrite("\n", 1);
}
}
//
// If there is space in the receive buffer, put the character
// there, otherwise throw it away.
//
if(!RX_BUFFER_FULL)
{
//
// Store the new character in the receive buffer
//
g_pcUARTRxBuffer[g_ulUARTRxWriteIndex] =
(unsigned char)(lChar & 0xFF);
ADVANCE_RX_BUFFER_INDEX(g_ulUARTRxWriteIndex);
//
// If echo is enabled, write the character to the transmit
// buffer so that the user gets some immediate feedback.
//
if(!g_bDisableEcho)
{
UARTwrite(&cChar, 1);
}
}
}
//
// If we wrote anything to the transmit buffer, make sure it actually
// gets transmitted.
//
UARTPrimeTransmit(g_ulBase);
MAP_UARTIntEnable(g_ulBase, UART_INT_TX);
}
}
#endif
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************