summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorYuval Adam <yuv.adm@gmail.com>2014-03-16 14:41:11 +0200
committerYuval Adam <yuv.adm@gmail.com>2014-03-16 14:41:11 +0200
commit990090a4cc9070837d31e66b58d40f0c3d038741 (patch)
treecf1b905082c364e9b223e0c5058566103138dae5 /utils
parent7f4da522479c0f00126219f0c23b804c3a93d7a6 (diff)
Add usblib and utils
Diffstat (limited to 'utils')
-rw-r--r--utils/cmdline.c193
-rw-r--r--utils/cmdline.h137
-rw-r--r--utils/cpu_usage.c206
-rw-r--r--utils/cpu_usage.h57
-rw-r--r--utils/flash_pb.c493
-rw-r--r--utils/flash_pb.h58
-rw-r--r--utils/fswrapper.c860
-rw-r--r--utils/fswrapper.h142
-rw-r--r--utils/isqrt.c118
-rw-r--r--utils/isqrt.h55
-rw-r--r--utils/locator.c342
-rw-r--r--utils/locator.h61
-rw-r--r--utils/lwiplib.c1399
-rw-r--r--utils/lwiplib.h121
-rw-r--r--utils/ptpdlib.c56
-rw-r--r--utils/ptpdlib.h55
-rw-r--r--utils/random.c169
-rw-r--r--utils/random.h56
-rw-r--r--utils/ringbuf.c712
-rw-r--r--utils/ringbuf.h105
-rw-r--r--utils/scheduler.c310
-rw-r--r--utils/scheduler.h140
-rw-r--r--utils/sine.c126
-rw-r--r--utils/sine.h85
-rw-r--r--utils/smbus.c5173
-rw-r--r--utils/smbus.h463
-rw-r--r--utils/softi2c.c1321
-rw-r--r--utils/softi2c.h195
-rw-r--r--utils/softssi.c1297
-rw-r--r--utils/softssi.h280
-rw-r--r--utils/softuart.c2591
-rw-r--r--utils/softuart.h375
-rw-r--r--utils/speexlib.c377
-rw-r--r--utils/speexlib.h63
-rw-r--r--utils/spi_flash.c2484
-rw-r--r--utils/spi_flash.h166
-rw-r--r--utils/swupdate.c355
-rw-r--r--utils/swupdate.h66
-rw-r--r--utils/tftp.c710
-rw-r--r--utils/tftp.h215
-rw-r--r--utils/uartstdio.c1720
-rw-r--r--utils/uartstdio.h86
-rw-r--r--utils/ustdlib.c1826
-rw-r--r--utils/ustdlib.h82
-rw-r--r--utils/wavfile.c291
-rw-r--r--utils/wavfile.h97
46 files changed, 26289 insertions, 0 deletions
diff --git a/utils/cmdline.c b/utils/cmdline.c
new file mode 100644
index 0000000..c9f5971
--- /dev/null
+++ b/utils/cmdline.c
@@ -0,0 +1,193 @@
+//*****************************************************************************
+//
+// cmdline.c - Functions to help with processing command lines.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup cmdline_api
+//! @{
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include "utils/cmdline.h"
+
+//*****************************************************************************
+//
+// Defines the maximum number of arguments that can be parsed.
+//
+//*****************************************************************************
+#ifndef CMDLINE_MAX_ARGS
+#define CMDLINE_MAX_ARGS 8
+#endif
+
+//*****************************************************************************
+//
+// An array to hold the pointers to the command line arguments.
+//
+//*****************************************************************************
+static char *g_ppcArgv[CMDLINE_MAX_ARGS + 1];
+
+//*****************************************************************************
+//
+//! Process a command line string into arguments and execute the command.
+//!
+//! \param pcCmdLine points to a string that contains a command line that was
+//! obtained by an application by some means.
+//!
+//! This function will take the supplied command line string and break it up
+//! into individual arguments. The first argument is treated as a command and
+//! is searched for in the command table. If the command is found, then the
+//! command function is called and all of the command line arguments are passed
+//! in the normal argc, argv form.
+//!
+//! The command table is contained in an array named <tt>g_psCmdTable</tt>
+//! containing <tt>tCmdLineEntry</tt> structures which must be provided by the
+//! application. The array must be terminated with an entry whose \b pcCmd
+//! field contains a NULL pointer.
+//!
+//! \return Returns \b CMDLINE_BAD_CMD if the command is not found,
+//! \b CMDLINE_TOO_MANY_ARGS if there are more arguments than can be parsed.
+//! Otherwise it returns the code that was returned by the command function.
+//
+//*****************************************************************************
+int
+CmdLineProcess(char *pcCmdLine)
+{
+ char *pcChar;
+ uint_fast8_t ui8Argc;
+ bool bFindArg = true;
+ tCmdLineEntry *psCmdEntry;
+
+ //
+ // Initialize the argument counter, and point to the beginning of the
+ // command line string.
+ //
+ ui8Argc = 0;
+ pcChar = pcCmdLine;
+
+ //
+ // Advance through the command line until a zero character is found.
+ //
+ while(*pcChar)
+ {
+ //
+ // If there is a space, then replace it with a zero, and set the flag
+ // to search for the next argument.
+ //
+ if(*pcChar == ' ')
+ {
+ *pcChar = 0;
+ bFindArg = true;
+ }
+
+ //
+ // Otherwise it is not a space, so it must be a character that is part
+ // of an argument.
+ //
+ else
+ {
+ //
+ // If bFindArg is set, then that means we are looking for the start
+ // of the next argument.
+ //
+ if(bFindArg)
+ {
+ //
+ // As long as the maximum number of arguments has not been
+ // reached, then save the pointer to the start of this new arg
+ // in the argv array, and increment the count of args, argc.
+ //
+ if(ui8Argc < CMDLINE_MAX_ARGS)
+ {
+ g_ppcArgv[ui8Argc] = pcChar;
+ ui8Argc++;
+ bFindArg = false;
+ }
+
+ //
+ // The maximum number of arguments has been reached so return
+ // the error.
+ //
+ else
+ {
+ return(CMDLINE_TOO_MANY_ARGS);
+ }
+ }
+ }
+
+ //
+ // Advance to the next character in the command line.
+ //
+ pcChar++;
+ }
+
+ //
+ // If one or more arguments was found, then process the command.
+ //
+ if(ui8Argc)
+ {
+ //
+ // Start at the beginning of the command table, to look for a matching
+ // command.
+ //
+ psCmdEntry = &g_psCmdTable[0];
+
+ //
+ // Search through the command table until a null command string is
+ // found, which marks the end of the table.
+ //
+ while(psCmdEntry->pcCmd)
+ {
+ //
+ // If this command entry command string matches argv[0], then call
+ // the function for this command, passing the command line
+ // arguments.
+ //
+ if(!strcmp(g_ppcArgv[0], psCmdEntry->pcCmd))
+ {
+ return(psCmdEntry->pfnCmd(ui8Argc, g_ppcArgv));
+ }
+
+ //
+ // Not found, so advance to the next entry.
+ //
+ psCmdEntry++;
+ }
+ }
+
+ //
+ // Fall through to here means that no matching command was found, so return
+ // an error.
+ //
+ return(CMDLINE_BAD_CMD);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/cmdline.h b/utils/cmdline.h
new file mode 100644
index 0000000..42ab9ea
--- /dev/null
+++ b/utils/cmdline.h
@@ -0,0 +1,137 @@
+//*****************************************************************************
+//
+// cmdline.h - Prototypes for command line processing functions.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __CMDLINE_H__
+#define __CMDLINE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup cmdline_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if the command is not found.
+//
+//*****************************************************************************
+#define CMDLINE_BAD_CMD (-1)
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if there are too many arguments.
+//
+//*****************************************************************************
+#define CMDLINE_TOO_MANY_ARGS (-2)
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if there are too few arguments.
+//
+//*****************************************************************************
+#define CMDLINE_TOO_FEW_ARGS (-3)
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if an argument is invalid.
+//
+//*****************************************************************************
+#define CMDLINE_INVALID_ARG (-4)
+
+//*****************************************************************************
+//
+// Command line function callback type.
+//
+//*****************************************************************************
+typedef int (*pfnCmdLine)(int argc, char *argv[]);
+
+//*****************************************************************************
+//
+//! Structure for an entry in the command list table.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! A pointer to a string containing the name of the command.
+ //
+ const char *pcCmd;
+
+ //
+ //! A function pointer to the implementation of the command.
+ //
+ pfnCmdLine pfnCmd;
+
+ //
+ //! A pointer to a string of brief help text for the command.
+ //
+ const char *pcHelp;
+}
+tCmdLineEntry;
+
+//*****************************************************************************
+//
+//! This is the command table that must be provided by the application. The
+//! last element of the array must be a structure whose pcCmd field contains
+//! a NULL pointer.
+//
+//*****************************************************************************
+extern tCmdLineEntry g_psCmdTable[];
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern int CmdLineProcess(char *pcCmdLine);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CMDLINE_H__
diff --git a/utils/cpu_usage.c b/utils/cpu_usage.c
new file mode 100644
index 0000000..1adf020
--- /dev/null
+++ b/utils/cpu_usage.c
@@ -0,0 +1,206 @@
+//*****************************************************************************
+//
+// cpu_usage.c - Routines to determine the CPU utilization.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+#include <stdint.h>
+#include <stdbool.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/timer.h"
+#include "utils/cpu_usage.h"
+
+//*****************************************************************************
+//
+//! \addtogroup cpu_usage_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The peripheral identifier for the timer modules that could be used for
+// tracking CPU utilization.
+//
+//*****************************************************************************
+static uint32_t g_pui32CPUUsageTimerPeriph[6] =
+{
+ SYSCTL_PERIPH_TIMER0, SYSCTL_PERIPH_TIMER1, SYSCTL_PERIPH_TIMER2,
+ SYSCTL_PERIPH_TIMER3, SYSCTL_PERIPH_TIMER4, SYSCTL_PERIPH_TIMER5
+};
+
+//*****************************************************************************
+//
+// The base address of the timer modules that could be used for tracking CPU
+// utilization.
+//
+//*****************************************************************************
+static uint32_t g_pui32CPUUsageTimerBase[6] =
+{
+ TIMER0_BASE, TIMER1_BASE, TIMER2_BASE, TIMER3_BASE, TIMER4_BASE,
+ TIMER5_BASE
+};
+
+//*****************************************************************************
+//
+// The index of the timer module that will be used for tracking CPU
+// utilization.
+//
+//*****************************************************************************
+static uint32_t g_ui32CPUUsageTimer;
+
+//*****************************************************************************
+//
+// The number of processor clock ticks per timing period.
+//
+//*****************************************************************************
+static uint32_t g_ui32CPUUsageTicks;
+
+//*****************************************************************************
+//
+// The value of timer two on the previous timing period. This is used to
+// determine the number of clock ticks counted by the timer during the timing
+// period.
+//
+//*****************************************************************************
+static uint32_t g_ui32CPUUsagePrevious;
+
+//*****************************************************************************
+//
+//! Updates the CPU usage for the new timing period.
+//!
+//! This function, when called at the end of a timing period, will update the
+//! CPU usage.
+//!
+//! \return Returns the CPU usage percentage as a 16.16 fixed-point value.
+//
+//*****************************************************************************
+uint32_t
+CPUUsageTick(void)
+{
+ uint32_t ui32Value, ui32Usage;
+
+ //
+ // Get the current value of the timer.
+ //
+ ui32Value =
+ MAP_TimerValueGet(g_pui32CPUUsageTimerBase[g_ui32CPUUsageTimer],
+ TIMER_A);
+
+ //
+ // Based on the number of clock ticks accumulated by the timer during the
+ // previous timing period, compute the CPU usage as a 16.16 fixed-point
+ // value.
+ //
+ ui32Usage = ((((g_ui32CPUUsagePrevious - ui32Value) * 6400) /
+ g_ui32CPUUsageTicks) * 1024);
+
+ //
+ // Save the previous value of the timer.
+ //
+ g_ui32CPUUsagePrevious = ui32Value;
+
+ //
+ // Return the new CPU usage value.
+ //
+ return(ui32Usage);
+}
+
+//*****************************************************************************
+//
+//! Initializes the CPU usage measurement module.
+//!
+//! \param ui32ClockRate is the rate of the clock supplied to the timer module.
+//! \param ui32Rate is the number of times per second that CPUUsageTick() is
+//! called.
+//! \param ui32Timer is the index of the timer module to use.
+//!
+//! This function prepares the CPU usage measurement module for measuring the
+//! CPU usage of the application.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CPUUsageInit(uint32_t ui32ClockRate, uint32_t ui32Rate, uint32_t ui32Timer)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ui32ClockRate > ui32Rate);
+ ASSERT(ui32Timer < 6);
+
+ //
+ // Save the timer index.
+ //
+ g_ui32CPUUsageTimer = ui32Timer;
+
+ //
+ // Determine the number of system clocks per measurement period.
+ //
+ g_ui32CPUUsageTicks = ui32ClockRate / ui32Rate;
+
+ //
+ // Set the previous value of the timer to the initial timer value.
+ //
+ g_ui32CPUUsagePrevious = 0xffffffff;
+
+ //
+ // Enable peripheral clock gating.
+ //
+ MAP_SysCtlPeripheralClockGating(true);
+
+ //
+ // Enable the third timer while the processor is in run mode, but disable
+ // it in sleep mode. It will therefore count system clocks when the
+ // processor is running but not when it is sleeping.
+ //
+ MAP_SysCtlPeripheralEnable(g_pui32CPUUsageTimerPeriph[ui32Timer]);
+ MAP_SysCtlPeripheralSleepDisable(g_pui32CPUUsageTimerPeriph[ui32Timer]);
+
+ //
+ // Configure the third timer for 32-bit periodic operation.
+ //
+ MAP_TimerConfigure(g_pui32CPUUsageTimerBase[ui32Timer],
+ TIMER_CFG_PERIODIC);
+
+ //
+ // Set the load value for the third timer to the maximum value.
+ //
+ MAP_TimerLoadSet(g_pui32CPUUsageTimerBase[ui32Timer], TIMER_A, 0xffffffff);
+
+ //
+ // Enable the third timer. It will now count the number of system clocks
+ // during which the processor is executing code.
+ //
+ MAP_TimerEnable(g_pui32CPUUsageTimerBase[ui32Timer], TIMER_A);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/cpu_usage.h b/utils/cpu_usage.h
new file mode 100644
index 0000000..181ea2c
--- /dev/null
+++ b/utils/cpu_usage.h
@@ -0,0 +1,57 @@
+//*****************************************************************************
+//
+// cpu_usage.h - Prototypes for the CPU utilization routines.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __CPU_USAGE_H__
+#define __CPU_USAGE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototypes for the CPU utilization routines.
+//
+//*****************************************************************************
+extern uint32_t CPUUsageTick(void);
+extern void CPUUsageInit(uint32_t ui32ClockRate, uint32_t ui32Rate,
+ uint32_t ui32Timer);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CPU_USAGE_H__
diff --git a/utils/flash_pb.c b/utils/flash_pb.c
new file mode 100644
index 0000000..ac85830
--- /dev/null
+++ b/utils/flash_pb.c
@@ -0,0 +1,493 @@
+//*****************************************************************************
+//
+// flash_pb.c - Flash parameter block functions.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_flash.h"
+#include "inc/hw_types.h"
+#include "inc/hw_sysctl.h"
+#include "driverlib/debug.h"
+#include "driverlib/flash.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "utils/flash_pb.h"
+
+//*****************************************************************************
+//
+//! \addtogroup flash_pb_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The address of the beginning of the flash used for storing parameter blocks;
+// this must be the start of an erase block in the flash.
+//
+//*****************************************************************************
+static uint8_t *g_pui8FlashPBStart;
+
+//*****************************************************************************
+//
+// The address of the end of the flash used for storing parameter blocks; this
+// must be the start of an erase block in the flash, or the first location
+// after the end of the flash array if the last erase block is used for storing
+// parameters.
+//
+//*****************************************************************************
+static uint8_t *g_pui8FlashPBEnd;
+
+//*****************************************************************************
+//
+// The size of the parameter block when stored in flash; this must be a power
+// of two less than or equal to the flash erase sector size such that a single
+// flash sector contains an integral number of parameter blocks.
+//
+//*****************************************************************************
+static uint32_t g_ui32FlashPBSize;
+
+//*****************************************************************************
+//
+// The address of the most recent parameter block in flash.
+//
+//*****************************************************************************
+static uint8_t *g_pui8FlashPBCurrent;
+
+//*****************************************************************************
+//
+// The erase sector size of the current flash.
+//
+//*****************************************************************************
+#define FLASH_SECTOR_SIZE MAP_SysCtlFlashSectorSizeGet()
+
+//*****************************************************************************
+//
+//! Determines if the parameter block at the given address is valid.
+//!
+//! \param pui8Offset is the address of the parameter block to check.
+//!
+//! This function will compute the checksum of a parameter block in flash to
+//! determine if it is valid.
+//!
+//! \return Returns one if the parameter block is valid and zero if it is not.
+//
+//*****************************************************************************
+static uint32_t
+FlashPBIsValid(uint8_t *pui8Offset)
+{
+ uint32_t ui32Idx, ui32Sum;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pui8Offset != (void *)0);
+
+ //
+ // Loop through the bytes in the block, computing the checksum.
+ //
+ for(ui32Idx = 0, ui32Sum = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ ui32Sum += pui8Offset[ui32Idx];
+ }
+
+ //
+ // The checksum should be zero, so return a failure if it is not.
+ //
+ if((ui32Sum & 255) != 0)
+ {
+ return(0);
+ }
+
+ //
+ // If the sum is equal to the size * 255, then the block is all ones and
+ // should not be considered valid.
+ //
+ if((g_ui32FlashPBSize * 255) == ui32Sum)
+ {
+ return(0);
+ }
+
+ //
+ // This is a valid parameter block.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the address of the most recent parameter block.
+//!
+//! This function returns the address of the most recent parameter block that
+//! is stored in flash.
+//!
+//! \return Returns the address of the most recent parameter block, or NULL if
+//! there are no valid parameter blocks in flash.
+//
+//*****************************************************************************
+uint8_t *
+FlashPBGet(void)
+{
+ //
+ // See if there is a valid parameter block.
+ //
+ if(g_pui8FlashPBCurrent)
+ {
+ //
+ // Return the address of the most recent parameter block.
+ //
+ return(g_pui8FlashPBCurrent);
+ }
+
+ //
+ // There are no valid parameter blocks in flash, so return NULL.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Writes a new parameter block to flash.
+//!
+//! \param pui8Buffer is the address of the parameter block to be written to
+//! flash.
+//!
+//! This function will write a parameter block to flash. Saving the new
+//! parameter blocks involves three steps:
+//!
+//! - Setting the sequence number such that it is one greater than the sequence
+//! number of the latest parameter block in flash.
+//! - Computing the checksum of the parameter block.
+//! - Writing the parameter block into the storage immediately following the
+//! latest parameter block in flash; if that storage is at the start of an
+//! erase block, that block is erased first.
+//!
+//! By this process, there is always a valid parameter block in flash. If
+//! power is lost while writing a new parameter block, the checksum will not
+//! match and the partially written parameter block will be ignored. This is
+//! what makes this fault-tolerant.
+//!
+//! Another benefit of this scheme is that it provides wear leveling on the
+//! flash. Since multiple parameter blocks fit into each erase block of flash,
+//! and multiple erase blocks are used for parameter block storage, it takes
+//! quite a few parameter block saves before flash is re-written.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+FlashPBSave(uint8_t *pui8Buffer)
+{
+ uint8_t *pui8New;
+ uint32_t ui32Idx, ui32Sum;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pui8Buffer != (void *)0);
+
+ //
+ // See if there is a valid parameter block in flash.
+ //
+ if(g_pui8FlashPBCurrent)
+ {
+ //
+ // Set the sequence number to one greater than the most recent
+ // parameter block.
+ //
+ pui8Buffer[0] = g_pui8FlashPBCurrent[0] + 1;
+
+ //
+ // Try to write the new parameter block immediately after the most
+ // recent parameter block.
+ //
+ pui8New = g_pui8FlashPBCurrent + g_ui32FlashPBSize;
+ if(pui8New == g_pui8FlashPBEnd)
+ {
+ pui8New = g_pui8FlashPBStart;
+ }
+ }
+ else
+ {
+ //
+ // There is not a valid parameter block in flash, so set the sequence
+ // number of this parameter block to zero.
+ //
+ pui8Buffer[0] = 0;
+
+ //
+ // Try to write the new parameter block at the beginning of the flash
+ // space for parameter blocks.
+ //
+ pui8New = g_pui8FlashPBStart;
+ }
+
+ //
+ // Compute the checksum of the parameter block to be written.
+ //
+ for(ui32Idx = 0, ui32Sum = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ ui32Sum -= pui8Buffer[ui32Idx];
+ }
+
+ //
+ // Store the checksum into the parameter block.
+ //
+ pui8Buffer[1] += ui32Sum;
+
+ //
+ // Look for a location to store this parameter block. This infinite loop
+ // will be explicitly broken out of when a valid location is found.
+ //
+ while(1)
+ {
+ //
+ // See if this location is at the start of an erase block.
+ //
+ if(((uint32_t)pui8New & (FLASH_SECTOR_SIZE - 1)) == 0)
+ {
+ //
+ // Erase this block of the flash. This does not assume that the
+ // erase succeeded in case this block of the flash has become bad
+ // through too much use. Given the extremely low frequency that
+ // the parameter blocks are written, this will likely never fail.
+ // But, that assumption is not made in order to be safe.
+ //
+ MAP_FlashErase((uint32_t)pui8New);
+ }
+
+ //
+ // Loop through this portion of flash to see if is all ones (in other
+ // words, it is an erased portion of flash).
+ //
+ for(ui32Idx = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ if(pui8New[ui32Idx] != 0xff)
+ {
+ break;
+ }
+ }
+
+ //
+ // If all bytes in this portion of flash are ones, then break out of
+ // the loop since this is a good location for storing the parameter
+ // block.
+ //
+ if(ui32Idx == g_ui32FlashPBSize)
+ {
+ break;
+ }
+
+ //
+ // Increment to the next parameter block location.
+ //
+ pui8New += g_ui32FlashPBSize;
+ if(pui8New == g_pui8FlashPBEnd)
+ {
+ pui8New = g_pui8FlashPBStart;
+ }
+
+ //
+ // If every possible location has been checked and none are valid, then
+ // it will not be possible to write this parameter block. Simply
+ // return without writing it.
+ //
+ if((g_pui8FlashPBCurrent && (pui8New == g_pui8FlashPBCurrent)) ||
+ (!g_pui8FlashPBCurrent && (pui8New == g_pui8FlashPBStart)))
+ {
+ return;
+ }
+ }
+
+ //
+ // Write this parameter block to flash.
+ //
+ MAP_FlashProgram((uint32_t *)pui8Buffer, (uint32_t)pui8New,
+ g_ui32FlashPBSize);
+
+ //
+ // Compare the parameter block data to the data that should now be in
+ // flash. Return if any of the data does not compare, leaving the previous
+ // parameter block in flash as the most recent (since the current parameter
+ // block failed to properly program).
+ //
+ for(ui32Idx = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ if(pui8New[ui32Idx] != pui8Buffer[ui32Idx])
+ {
+ return;
+ }
+ }
+
+ //
+ // The new parameter block becomes the most recent parameter block.
+ //
+ g_pui8FlashPBCurrent = pui8New;
+}
+
+//*****************************************************************************
+//
+//! Initializes the flash parameter block.
+//!
+//! \param ui32Start is the address of the flash memory to be used for storing
+//! flash parameter blocks; this must be the start of an erase block in the
+//! flash.
+//! \param ui32End is the address of the end of flash memory to be used for
+//! storing flash parameter blocks; this must be the start of an erase block in
+//! the flash (the first block that is NOT part of the flash memory to be
+//! used), or the address of the first word after the flash array if the last
+//! block of flash is to be used.
+//! \param ui32Size is the size of the parameter block when stored in flash;
+//! this must be a power of two less than or equal to the flash erase block
+//! size (typically 1024).
+//!
+//! This function initializes a fault-tolerant, persistent storage mechanism
+//! for a parameter block for an application. The last several erase blocks
+//! of flash (as specified by \e ui32Start and \e ui32End are used for the
+//! storage; more than one erase block is required in order to be
+//! fault-tolerant.
+//!
+//! A parameter block is an array of bytes that contain the persistent
+//! parameters for the application. The only special requirement for the
+//! parameter block is that the first byte is a sequence number (explained
+//! in FlashPBSave()) and the second byte is a checksum used to validate the
+//! correctness of the data (the checksum byte is the byte such that the sum of
+//! all bytes in the parameter block is zero).
+//!
+//! The portion of flash for parameter block storage is split into N
+//! equal-sized regions, where each region is the size of a parameter block
+//! (\e ui32Size). Each region is scanned to find the most recent valid
+//! parameter block. The region that has a valid checksum and has the highest
+//! sequence number (with special consideration given to wrapping back to zero)
+//! is considered to be the current parameter block.
+//!
+//! In order to make this efficient and effective, three conditions must be
+//! met. The first is \e ui32Start and \e ui32End must be specified such that
+//! at least two erase blocks of flash are dedicated to parameter block
+//! storage. If not, fault tolerance can not be guaranteed since an erase of a
+//! single block will leave a window where there are no valid parameter blocks
+//! in flash. The second condition is that the size (\e ui32Size) of the
+//! parameter block must be an integral divisor of the size of an erase block
+//! of flash. If not, a parameter block will end up spanning between two erase
+//! blocks of flash, making it more difficult to manage. The final condition
+//! is that the size of the flash dedicated to parameter blocks (\e ui32End -
+//! \e ui32Start) divided by the parameter block size (\e ui32Size) must be
+//! less than or equal to 128. If not, it will not be possible in all cases to
+//! determine which parameter block is the most recent (specifically when
+//! dealing with the sequence number wrapping back to zero).
+//!
+//! When the microcontroller is initially programmed, the flash blocks used for
+//! parameter block storage are left in an erased state.
+//!
+//! This function must be called before any other flash parameter block
+//! functions are called.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+FlashPBInit(uint32_t ui32Start, uint32_t ui32End, uint32_t ui32Size)
+{
+ uint8_t *pui8Offset, *pui8Current;
+ uint8_t ui8One, ui8Two;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT((ui32Start % FLASH_SECTOR_SIZE) == 0);
+ ASSERT((ui32End % FLASH_SECTOR_SIZE) == 0);
+ ASSERT((FLASH_SECTOR_SIZE % ui32Size) == 0);
+
+ //
+ // Save the characteristics of the flash memory to be used for storing
+ // parameter blocks.
+ //
+ g_pui8FlashPBStart = (uint8_t *)ui32Start;
+ g_pui8FlashPBEnd = (uint8_t *)ui32End;
+ g_ui32FlashPBSize = ui32Size;
+
+ //
+ // Loop through the portion of flash memory used for storing parameter
+ // blocks.
+ //
+ for(pui8Offset = g_pui8FlashPBStart, pui8Current = 0;
+ pui8Offset < g_pui8FlashPBEnd; pui8Offset += g_ui32FlashPBSize)
+ {
+ //
+ // See if this is a valid parameter block (in other words, the checksum
+ // is correct).
+ //
+ if(FlashPBIsValid(pui8Offset))
+ {
+ //
+ // See if a valid parameter block has been previously found.
+ //
+ if(pui8Current != 0)
+ {
+ //
+ // Get the sequence numbers for the current and new parameter
+ // blocks.
+ //
+ ui8One = pui8Current[0];
+ ui8Two = pui8Offset[0];
+
+ //
+ // See if the sequence number for the new parameter block is
+ // greater than the current block. The comparison isn't
+ // straightforward since the one byte sequence number will wrap
+ // after 256 parameter blocks.
+ //
+ if(((ui8One > ui8Two) && ((ui8One - ui8Two) < 128)) ||
+ ((ui8Two > ui8One) && ((ui8Two - ui8One) > 128)))
+ {
+ //
+ // The new parameter block is older than the current
+ // parameter block, so skip the new parameter block and
+ // keep searching.
+ //
+ continue;
+ }
+ }
+
+ //
+ // The new parameter block is more recent than the current one, so
+ // make it the new current parameter block.
+ //
+ pui8Current = pui8Offset;
+ }
+ }
+
+ //
+ // Save the address of the most recent parameter block found. If no valid
+ // parameter blocks were found, this will be a NULL pointer.
+ //
+ g_pui8FlashPBCurrent = pui8Current;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/flash_pb.h b/utils/flash_pb.h
new file mode 100644
index 0000000..f68329d
--- /dev/null
+++ b/utils/flash_pb.h
@@ -0,0 +1,58 @@
+//*****************************************************************************
+//
+// flash_pb.h - Prototypes for the flash parameter block functions.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __FLASH_PB_H__
+#define __FLASH_PB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototype for the flash parameter block functions.
+//
+//*****************************************************************************
+extern uint8_t *FlashPBGet(void);
+extern void FlashPBSave(uint8_t *pui8Buffer);
+extern void FlashPBInit(uint32_t ui32Start, uint32_t ui32End,
+ uint32_t ui32Size);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __FLASH_PB_H__
diff --git a/utils/fswrapper.c b/utils/fswrapper.c
new file mode 100644
index 0000000..74e80af
--- /dev/null
+++ b/utils/fswrapper.c
@@ -0,0 +1,860 @@
+//*****************************************************************************
+//
+// fswrapper.c - File System Processing for lwIP Web Server Apps.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "httpserver_raw/fs.h"
+#include "httpserver_raw/fsdata.h"
+#include "fatfs/src/ff.h"
+#include "fatfs/src/diskio.h"
+#include "utils/fswrapper.h"
+#include "utils/lwiplib.h"
+#include "utils/ustdlib.h"
+
+//*****************************************************************************
+//
+//! \addtogroup fswrapper_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Static file system images for use with this module may be created using
+// the makefsfile.exe utility. Both position-independent (built using the -b
+// command line option to makefsfile) and position dependent file system images
+// may be used.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The index of the file system containing this file.
+ //
+ uint32_t ui32MountIndex;
+
+ //
+ // The FatFs file structure allocated if the target file is in the FAT
+ // file system.
+ //
+ FIL *psFATFile;
+}
+fs_wrapper_data;
+
+//*****************************************************************************
+//
+// A marker used to indicate that a passed filename cannot be mapped to any of
+// the configured mount points.
+//
+//*****************************************************************************
+#define BAD_MOUNT_INDEX 0xFFFFFFFF
+
+//*****************************************************************************
+//
+// This macro is used to extract pointers from the file descriptors. We
+// support files systems linked into the image as well as external, position
+// independent file system images and this macro allows us to use the same code
+// to extract pointers from file descriptors in each case.
+//
+//*****************************************************************************
+#define FS_POINTER(ptTree, ptValue, bPosInd) \
+ ((char *)((bPosInd) ? ((int8_t *)(ptTree) + (uint32_t)(ptValue)) : \
+ (int8_t *)(ptValue)))
+
+//*****************************************************************************
+//
+// The pointer to the mount point table and the number of entries in the
+// table.
+//
+//*****************************************************************************
+static fs_mount_data *g_psMountPoints = NULL;
+static uint32_t g_ui32NumMountPoints = 0;
+static uint32_t g_ui32DefaultMountIndex = BAD_MOUNT_INDEX;
+static bool g_bFatFsEnabled = false;
+
+//*****************************************************************************
+//
+// Given a filename, this function determine which of the configured mount
+// points it resides under. It returns the index of the mount point in the
+// g_psMountPoints array and also a pointer to the first character of the
+// filename with the mount point name (directory) stripped from it.
+//
+//*****************************************************************************
+static uint32_t
+fs_find_mount_index(const char *pcName, char **ppcFSFilename)
+{
+ uint32_t ui32Loop;
+ int iLenDirName;
+ int iLenMountName;
+ char *pcSlash;
+
+ //
+ // First extract the top level directory name which we need to match
+ // with the mount point name. For this to exist, the pcName string
+ // must start with a '/' character and must contain at least one more
+ // '/'.
+ //
+ if(pcName[0] == '/')
+ {
+ //
+ // The string starts with a '/'. Does it contain a second one?
+ //
+ pcSlash = strchr(pcName + 1, '/');
+
+ //
+ // Did we find another forward slash character?
+ //
+ if(pcSlash)
+ {
+ //
+ // Yes - the mount point name is between the start of the
+ // string and the slash we just found. How long is this string?
+ //
+ iLenDirName = (int)(pcSlash - (pcName + 1));
+ }
+ else
+ {
+ //
+ // The mount point name is the whole string.
+ //
+ iLenDirName = ustrlen(pcName + 1);
+ pcSlash = (char *)pcName + 1 + iLenDirName;
+ }
+
+ //
+ // Now figure out which, if any, of the mount points this matches.
+ //
+ for(ui32Loop = 0; ui32Loop < g_ui32NumMountPoints; ui32Loop++)
+ {
+ //
+ // Skip the default mount point if found.
+ //
+ if(!g_psMountPoints[ui32Loop].pcNamePrefix)
+ {
+ continue;
+ }
+
+ //
+ // How long is the name of this mount point?
+ //
+ iLenMountName = ustrlen(g_psMountPoints[ui32Loop].pcNamePrefix);
+
+ //
+ // Does the mount point name match the directory name extracted
+ // from the passed pcName?
+ //
+ if(iLenMountName == iLenDirName)
+ {
+ //
+ // The lengths match but are the strings the same?
+ //
+ if(!ustrncmp(g_psMountPoints[ui32Loop].pcNamePrefix,
+ pcName + 1, iLenDirName))
+ {
+ //
+ // Yes - we have a match. Set the stripped filename to
+ // the second '/' and return the mount point index.
+ //
+ *ppcFSFilename = pcSlash;
+ return(ui32Loop);
+ }
+ }
+ }
+ }
+
+ //
+ // If we drop out of the loop, we didn't find a specific mount point for
+ // this file so just return the filename passed and the default mount
+ // point.
+ //
+ *ppcFSFilename = (char *)pcName;
+
+ return(g_ui32DefaultMountIndex);
+}
+
+//*****************************************************************************
+//
+//! Initializes the file system wrapper.
+//!
+//! \param psMountPoints points to an array of fs_mount_data structures. Each
+//! element in the array maps a top level directory name to a particular
+//! file system image or to the FAT file system and a logical drive number.
+//! \param ui32NumMountPoints provides the number of populated elements in the
+//! \e psMountPoints array.
+//!
+//! This function should be called to initialize the file system wrapper and
+//! provide it with the information required to access the files in multiple
+//! file system images via a single filename space.
+//!
+//! Each entry in \e psMountPoints describes a top level directory in the
+//! unified namespace and indicates to fswrapper where the files for that
+//! directory can be found. Each entry can describe either a file system
+//! image in system memory or a logical disk handled via the FatFs file system
+//! driver.
+//!
+//! For example, consider the following 3 entry mount point table:
+//!
+//! \verbatim
+//! {
+//! { "internal", &g_pui8FSImage, 0, NULL, NULL },
+//! { "sdcard", NULL, 0, SDCardEnable, SDCardDisable },
+//! { NULL, &g_pui8FSDefault, 0, NULL, NULL}
+//! }
+//! \endverbatim
+//!
+//! Requests to open file ``/internal/index.html'' will be handled by
+//! attempting to open ``/index.html'' in the internal file system pointed to
+//! by \e g_pui8FSImage. Similarly, opening ``/sdcard/images/logo.gif'' will
+//! result in a call to the FAT f_open function requesting
+//! ``0:/images/logo.gif''. If a request to open ``index.htm'' is received,
+//! this is handled by attempting to open ``index.htm'' in the default internal
+//! file system image, \e g_pui8FSDefault.
+//!
+//! \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+fs_init(fs_mount_data *psMountPoints, uint32_t ui32NumMountPoints)
+{
+ uint32_t ui32Loop;
+
+ //
+ // Check for non-zero parameters in debug builds.
+ //
+ ASSERT(psMountPoints);
+ ASSERT(ui32NumMountPoints);
+
+ //
+ // Remember the mount point information we have been given.
+ //
+ if(psMountPoints && ui32NumMountPoints)
+ {
+ //
+ // Remember the information passed.
+ //
+ g_psMountPoints = psMountPoints;
+ g_ui32NumMountPoints = ui32NumMountPoints;
+
+ //
+ // Check to determine if any of the mount points refer to FAT file
+ // system drivers. We also hijack this loop to determine what the
+ // default mount point (if any) is.
+ //
+ g_bFatFsEnabled = false;
+ for(ui32Loop = 0; ui32Loop < g_ui32NumMountPoints; ui32Loop++)
+ {
+ //
+ // If the pui8FSImage field of a mount point structure is NULL,
+ // this implies that we are using the FAT file system for that
+ // node.
+ //
+ if(!g_psMountPoints[ui32Loop].pui8FSImage)
+ {
+ g_bFatFsEnabled = true;
+ }
+
+ //
+ // Does this entry describe the default mount point?
+ //
+ if(g_psMountPoints[ui32Loop].pcNamePrefix == NULL)
+ {
+ g_ui32DefaultMountIndex = ui32Loop;
+ }
+ }
+
+ return(true);
+ }
+ else
+ {
+ //
+ // Return an error due to being passed a bad parameter.
+ //
+ return(false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Provides a periodic tick for the file system.
+//!
+//! \param ui32TickMS is the number of milliseconds which have elapsed since
+//! the last time this function was called.
+//!
+//! Applications making use of the file system wrapper with underlying FatFs
+//! drives must call this function at least once every 10 milliseconds to
+//! provide a time reference for use by the file system. It is typically
+//! called in the context of the application's SysTick interrupt handler or
+//! from the handler of some other timer interrupt.
+//!
+//! If only binary file system images are in use, this function need not be
+//! called.
+//!
+//! \return None
+//
+//
+//*****************************************************************************
+void
+fs_tick(uint32_t ui32TickMS)
+{
+ static uint32_t ui32TickCounter = 0;
+
+ //
+ // Check if the file system has been enabled yet.
+ //
+ if(!g_bFatFsEnabled)
+ {
+ return;
+ }
+
+ //
+ // Increment the tick counter.
+ //
+ ui32TickCounter += ui32TickMS;
+
+ //
+ // Check to see if the FAT FS tick needs to run.
+ //
+ if(ui32TickCounter >= 10)
+ {
+ ui32TickCounter = 0;
+ disk_timerproc();
+ }
+}
+
+//*****************************************************************************
+//
+//! Opens a file.
+//!
+//! \param pcName points to a NULL terminated string containing the path and
+//! file name to open.
+//!
+//! This function opens a file and returns a handle allowing it to be read.
+//!
+//! \return Returns a valid file handle on success or NULL on failure.
+//
+//*****************************************************************************
+struct fs_file *
+fs_open(const char *pcName)
+{
+ const struct fsdata_file *psTree;
+ const struct fsdata_file *psEnd = NULL;
+ struct fs_file *psFile = NULL;
+ fs_wrapper_data *psWrapper;
+ FRESULT fresult = FR_OK;
+ bool bPosInd = false;
+ char *pcFSFilename;
+ char *pcFilename;
+ uint32_t ui32Length;
+
+ //
+ // Allocate memory for the file system structure.
+ //
+ psFile = mem_malloc(sizeof(struct fs_file));
+ if(NULL == psFile)
+ {
+ return(NULL);
+ }
+
+ //
+ // Allocate memory for our internal control structure.
+ //
+ psFile->pextension = mem_malloc(sizeof(fs_wrapper_data));
+ psWrapper = (fs_wrapper_data *)psFile->pextension;
+
+ if(NULL == psWrapper)
+ {
+ return(NULL);
+ }
+
+ //
+ // Find which mount point we need to use to satisfy this file open request.
+ //
+ psWrapper->ui32MountIndex = fs_find_mount_index(pcName, &pcFSFilename);
+ if(psWrapper->ui32MountIndex == BAD_MOUNT_INDEX)
+ {
+ //
+ // We can't map the mount index so return an error.
+ //
+ mem_free(psWrapper);
+ mem_free(psFile);
+ return(NULL);
+ }
+
+ //
+ // Enable access to the physical medium if we have been provided with
+ // a callback for this.
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnEnable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnEnable(psWrapper->ui32MountIndex);
+ }
+
+ //
+ // Are we opening a file on an internal file system image?
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pui8FSImage)
+ {
+ //
+ // Initialize the file system tree pointer to the root of the linked
+ // list for this mount point's file system image.
+ //
+ psTree = ((const struct fsdata_file *)
+ g_psMountPoints[psWrapper->ui32MountIndex].pui8FSImage);
+
+ //
+ // Which type of file system are we dealing with?
+ //
+ if(psTree->next == FILE_SYSTEM_MARKER)
+ {
+ //
+ // If we found the marker, this is a position independent file
+ // system image. Remember this and fix up the pointer to the
+ // first descriptor by skipping over the 4 byte marker and the
+ // 4 byte image size entry. We also keep track of where the file
+ // system image ends since this allows us to do a bit more error
+ // checking later.
+ //
+ bPosInd = true;
+ ui32Length = *(uint32_t *)((uint8_t *)psTree + 4);
+ psTree = (struct fsdata_file *)((int8_t *)psTree + 8);
+ psEnd = (struct fsdata_file *)((int8_t *)psTree + ui32Length);
+ }
+
+ //
+ // Begin processing the linked list, looking for the requested file
+ // name.
+ //
+ while(NULL != psTree)
+ {
+ //
+ // Compare the requested file "name" to the file name in the
+ // current node.
+ //
+ if(ustrncmp(pcFSFilename,
+ FS_POINTER(psTree, psTree->name, bPosInd),
+ psTree->len) == 0)
+ {
+ //
+ // Fill in the data pointer and length values from the
+ // linked list node.
+ //
+ psFile->data = FS_POINTER(psTree, psTree->data, bPosInd);
+ psFile->len = psTree->len;
+
+ //
+ // For now, we setup the read index to the end of the file,
+ // indicating that all data has been read. This indicates that
+ // all the data is currently available in a contiguous block
+ // of memory (which is always the case with an internal file
+ // system image).
+ //
+ psFile->index = psTree->len;
+
+ //
+ // We are not using a FAT file system file and don't need to
+ // remap the filename so set these pointers to NULL.
+ //
+ psWrapper->psFATFile = NULL;
+
+ //
+ // Exit the loop and return the file system pointer.
+ //
+ break;
+ }
+
+ //
+ // If we get here, we did not find the file at this node of the
+ // linked list. Get the next element in the list. We can't just
+ // assign psTree from psTree->next since this will give us the
+ // wrong pointer for a position independent image (where the values
+ // in the structure are offsets from the start of the file
+ // descriptor, not absolute pointers) but we do know that a 0 in
+ // the "next" field does indicate that this is the last file so we
+ // can use that info to force the loop to exit at the end.
+ //
+ if(psTree->next == 0)
+ {
+ psTree = NULL;
+ }
+ else
+ {
+ psTree = (struct fsdata_file *)FS_POINTER(psTree, psTree->next,
+ bPosInd);
+
+ //
+ // If this is a position independent file system image, we can
+ // also check that the new node is within the image. If it
+ // isn't, the image is corrupted to stop the search.
+ //
+ if(bPosInd && (psTree >= psEnd))
+ {
+ psTree = NULL;
+ }
+ }
+ }
+
+ //
+ // If we didn't find the file, ptTee will be NULL. Make sure we
+ // return a NULL pointer if this happens.
+ //
+ if(NULL == psTree)
+ {
+ mem_free(psFile->pextension);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ }
+ else
+ {
+ //
+ // This file is on the FAT file system.
+ //
+
+ //
+ // Allocate memory for the Fat File system handle.
+ //
+ psWrapper->psFATFile = mem_malloc(sizeof(FIL));
+ if(NULL == psWrapper->psFATFile)
+ {
+ mem_free(psFile->pextension);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ else
+ {
+ //
+ // Reformat the filename to start with the FAT logical drive
+ // number.
+ //
+ ui32Length = ustrlen(pcFSFilename) + 16;
+ pcFilename = mem_malloc(ui32Length);
+ if(!pcFilename)
+ {
+ //
+ // Can't allocate temporary storage for the reformatted
+ // filename!
+ //
+ mem_free(psWrapper->psFATFile);
+ mem_free(psFile->pextension);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ else
+ {
+ usnprintf(pcFilename, ui32Length, "%d:%s",
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ ui32DriveNum, pcFSFilename);
+ //
+ // Attempt to open the file on the Fat File System.
+ //
+ fresult = f_open(psWrapper->psFATFile, pcFilename, FA_READ);
+
+ //
+ // Free the filename storage
+ //
+ mem_free(pcFilename);
+
+ //
+ // Did we open the file correctly?
+ //
+ if(FR_OK == fresult)
+ {
+ //
+ // Yes - fill in the file structure to indicate that a
+ // FAT file is in use.
+ //
+ psFile->data = NULL;
+ psFile->len = 0;
+ psFile->index = 0;
+ }
+ else
+ {
+ //
+ // If we get here, we failed to find the file on the FAT
+ // file system so free up the FAT handle/object.
+ //
+ mem_free(psWrapper->psFATFile);
+ mem_free(psWrapper);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ }
+ }
+ }
+
+ //
+ // Disable access to the physical medium if we have been provided with
+ // a callback for this.
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnDisable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnDisable(psWrapper->ui32MountIndex);
+ }
+
+ return(psFile);
+}
+
+//*****************************************************************************
+//
+//! Closes a file.
+//!
+//! \param phFile is the handle of the file that is to be closed. This will
+//! have been returned by an earlier call to fs_open().
+//!
+//! This function closes the file identified by \e phFile and frees all
+//! resources associated with the file handle.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+fs_close(struct fs_file *phFile)
+{
+ fs_wrapper_data *psWrapper;
+
+ psWrapper = (fs_wrapper_data *)phFile->pextension;
+
+ //
+ // If a Fat file was opened, free its object.
+ //
+ if(psWrapper->psFATFile)
+ {
+ //
+ // Close the file.
+ //
+ f_close(psWrapper->psFATFile);
+
+ //
+ // Free the file object.
+ //
+ mem_free(psWrapper->psFATFile);
+ }
+
+ //
+ // Free our file wrapper control structure.
+ //
+ mem_free(phFile->pextension);
+
+ //
+ // Free the main file system object.
+ //
+ mem_free(phFile);
+}
+
+//*****************************************************************************
+//
+//! Reads data from an open file.
+//!
+//! \param phFile is the handle of the file which is to be read. This will
+//! have been returned by a previous call to fs_open().
+//! \param pcBuffer points to the first byte of the buffer into which the
+//! data read from the file will be copied. This buffer must be large enough
+//! to hold \e iCount bytes.
+//! \param iCount is the maximum number of bytes of data that are to be read
+//! from the file.
+//!
+//! This function reads the next block of data from the given file into a
+//! buffer and returns the number of bytes read or -1 if the end of the file
+//! has been reached.
+//!
+//! \return Returns the number of bytes read from the file or -1 if the end of
+//! the file has been reached and no more data is available.
+//
+//*****************************************************************************
+int
+fs_read(struct fs_file *phFile, char *pcBuffer, int iCount)
+{
+ int iAvailable, iRetcode;
+ fs_wrapper_data *psWrapper;
+
+ psWrapper = (fs_wrapper_data *)phFile->pextension;
+
+ //
+ // Call the application's enable function for this physical medium (if
+ // an enable function has been provided).
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnEnable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnEnable(psWrapper->ui32MountIndex);
+ }
+
+ //
+ // Check to see if a Fat File was opened and process it.
+ //
+ if(psWrapper->psFATFile)
+ {
+ uint32_t ui32BytesRead;
+ FRESULT fresult;
+
+ //
+ // Read the data.
+ //
+ fresult = f_read(psWrapper->psFATFile, pcBuffer, iCount,
+ (UINT*)&ui32BytesRead);
+ if((fresult != FR_OK) || (ui32BytesRead == 0))
+ {
+ iRetcode = -1;
+ }
+ else
+ {
+ iRetcode = (int)ui32BytesRead;
+ }
+ }
+ else
+ {
+ //
+ // We are reading a file from a file system image. Check to see if
+ // more data is available.
+ //
+ if(phFile->len == phFile->index)
+ {
+ //
+ // There is no remaining data. Return a -1 for EOF indication.
+ //
+ return(-1);
+ }
+
+ //
+ // Determine how much data we can copy. The minimum of the 'iCount'
+ // parameter or the available data in the file system buffer.
+ //
+ iAvailable = phFile->len - phFile->index;
+ if(iAvailable > iCount)
+ {
+ iAvailable = iCount;
+ }
+
+ //
+ // Copy the data.
+ //
+ memcpy(pcBuffer, phFile->data + phFile->index, iAvailable);
+ phFile->index += iAvailable;
+
+ //
+ // Return the count of data that we copied.
+ //
+ iRetcode = iAvailable;
+ }
+
+ //
+ // Call the application's disable function now that we have finished
+ // accessing the file.
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnDisable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnDisable(psWrapper->ui32MountIndex);
+ }
+
+ //
+ // Return the number of bytes read.
+ //
+ return(iRetcode);
+}
+
+//*****************************************************************************
+//
+//! Maps a path string containing mount point names to a path suitable for
+//! use in calls to the FatFs APIs.
+//!
+//! \param pcPath points to a string containing a path in the namespace
+//! defined by the mount information passed to fs_init().
+//! \param pcMapped points to a buffer into which the mapped path string will
+//! be written.
+//! \param iLen is the size, in bytes, of the buffer pointed to by pcMapped.
+//!
+//! This function may be used by applications which want to make use of FatFs
+//! functions which are not directly mapped by the fswrapper layer. A path
+//! in the namespace defined by the mount points passed to function fs_init()
+//! is translated to an equivalent path in the FatFs namespace and this may
+//! then be used in a direct call to functions such as f_opendir() or
+//! f_getfree().
+//!
+//! \return Returns \b true on success or \b false if fs_init() has not
+//! been called, if the path provided maps to an internal file system image
+//! rather than a FatFs logical drive or if the buffer pointed to by
+//! \e pcMapped is too small to fit the output string.
+//
+//*****************************************************************************
+bool
+fs_map_path(const char *pcPath, char *pcMapped, int iLen)
+{
+ char *pcFSFilename;
+ uint32_t ui32MountIndex;
+ int iCount;
+
+ //
+ // If no mount points have been defined, return an error.
+ //
+ if(!g_psMountPoints)
+ {
+ return(false);
+ }
+
+ //
+ // Find which mount point we need to use to satisfy this file open request.
+ //
+ ui32MountIndex = fs_find_mount_index(pcPath, &pcFSFilename);
+
+ //
+ // If we got a bad mount index or the index returned represents a mount
+ // point that is not in the FAT file system, return an error.
+ //
+ if((ui32MountIndex == BAD_MOUNT_INDEX) ||
+ (g_psMountPoints[ui32MountIndex].pui8FSImage))
+ {
+ //
+ // We can't map the mount index so return an error.
+ //
+ return(false);
+ }
+
+ //
+ // Now we can generate the FatFs namespace path string.
+ //
+ iCount = usnprintf(pcMapped, iLen, "%d:%s",
+ g_psMountPoints[ui32MountIndex].ui32DriveNum,
+ pcFSFilename);
+
+ //
+ // Tell the user how we got on. The count returned by usnprintf is the
+ // number of characters that should have been written, excluding the
+ // terminating NULL so we use this to check for overflow of the output
+ // buffer.
+ //
+ return((iLen >= (iCount + 1)) ? true : false);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/fswrapper.h b/utils/fswrapper.h
new file mode 100644
index 0000000..889cdd4
--- /dev/null
+++ b/utils/fswrapper.h
@@ -0,0 +1,142 @@
+//*****************************************************************************
+//
+// fswrapper.h - Public type definitons and function prototypes for the simple
+// file system wrapper module.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __FSWRAPPER_H__
+#define __FSWRAPPER_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup fswrapper_api
+//! @{
+//
+//*****************************************************************************
+
+typedef struct
+{
+ //
+ //! This string provides a pseudo-directory name that will be used to
+ //! identify this mount point in future calls to fs_open. If this string
+ //! is NULL, this indicates that this is the default file system which will
+ //! be used when any simple filename, not including a leading directory
+ //! name is passed or when the leading directory name is not found in the
+ //! list of mount points passed to fs_init.
+ //
+ const char *pcNamePrefix;
+
+ //
+ //! A pointer to the start of the file system image that is to be used to
+ //! satisfy requests for files whose name begins "/name" where
+ //! "name" is the string provided in the pcNamePrefix field. This pointer
+ //! may point to either a position-dependent or position-independent file
+ //! system image generated by the makefsfile executable or makefsdata
+ //! Perl script. If NULL, it is assumed that the FAT file system is to be
+ //! used and that the drive number provided in ui32DriveNum should be
+ //! substituted for "name" in the supplied filename before attempting to
+ //! open the FAT file.
+ //
+ uint8_t *pui8FSImage;
+
+ //
+ //! If this mount point describes a logical drive in the FAT file system,
+ //! this field indicates the drive number that is to be accessed. This
+ //! number will be substituted for the string provided in the pcNamePrefix
+ //! field in the filename passed to fs_open before that filename is passed
+ //! down to the FAT file system. For example, if pcNamePrefix is "sdcard"
+ //! and ui32DriveNum is 0, a call to fs_open passing
+ //! "/sdcard/images/logo.gif" will be passed to the FATfs f_open call as
+ //! "/0/images/logo.gif". This field is ignored if pui8FSImage is not NULL
+ //! (indicating that this mount point refers to a file system image rather
+ //! than the FAT file system).
+ //!
+ uint32_t ui32DriveNum;
+
+ //
+ //! This function pointer is called whenever a file is to be opened, read
+ //! or (for read/write file systems) written on this file system. If any
+ //! special setup is required to allow access to the physical medium (for
+ //! example, setting the SSI mode or clock frequency), the application may
+ //! use this callback to perform that initialization. If this field is
+ //! NULL, no callback will be made.
+ //
+ void (*pfnEnable)(uint32_t ui32FSIndex);
+
+ //
+ //! This callback is made after access to the physical medium has been
+ //! completed. An application may assume that no further access to the
+ //! medium will be made until a call to pfnEnable is made. If this field
+ //! is NULL, no callback will be made.
+ //
+ void (*pfnDisable)(uint32_t ui32FSIndex);
+}
+fs_mount_data;
+
+//*****************************************************************************
+//
+// This marker, "FIMG", is placed at the beginning of a position-independent
+// file system image to differentiate it from a position-dependent image.
+//
+//*****************************************************************************
+#define FILE_SYSTEM_MARKER ((const struct fsdata_file *)0x474D4946)
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public function prototypes
+//
+//*****************************************************************************
+extern bool fs_init(fs_mount_data *psMountPoints, uint32_t ui32NumMountPoints);
+extern void fs_tick(uint32_t ui32TickMS);
+extern struct fs_file *fs_open(const char *name);
+extern void fs_close(struct fs_file *file);
+extern int fs_read(struct fs_file *file, char *buffer, int count);
+extern bool fs_map_path(const char *pcPath, char *pcMapped, int iLen);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __FSWRAPPER_H__
diff --git a/utils/isqrt.c b/utils/isqrt.c
new file mode 100644
index 0000000..aa908f6
--- /dev/null
+++ b/utils/isqrt.c
@@ -0,0 +1,118 @@
+//*****************************************************************************
+//
+// isqrt.c - Integer square root.
+//
+// Copyright (c) 2005-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "utils/isqrt.h"
+
+//*****************************************************************************
+//
+//! \addtogroup isqrt_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Compute the integer square root of an integer.
+//!
+//! \param ui32Value is the value whose square root is desired.
+//!
+//! This function will compute the integer square root of the given input
+//! value. Since the value returned is also an integer, it is actually better
+//! defined as the largest integer whose square is less than or equal to the
+//! input value.
+//!
+//! \return Returns the square root of the input value.
+//
+//*****************************************************************************
+uint32_t
+isqrt(uint32_t ui32Value)
+{
+ uint32_t ui32Rem, ui32Root, ui32Idx;
+
+ //
+ // Initialize the remainder and root to zero.
+ //
+ ui32Rem = 0;
+ ui32Root = 0;
+
+ //
+ // Loop over the sixteen bits in the root.
+ //
+ for(ui32Idx = 0; ui32Idx < 16; ui32Idx++)
+ {
+ //
+ // Shift the root up by a bit to make room for the new bit that is
+ // about to be computed.
+ //
+ ui32Root <<= 1;
+
+ //
+ // Get two more bits from the input into the remainder.
+ //
+ ui32Rem = ((ui32Rem << 2) + (ui32Value >> 30));
+ ui32Value <<= 2;
+
+ //
+ // Make the test root be 2n + 1.
+ //
+ ui32Root++;
+
+ //
+ // See if the root is greater than the remainder.
+ //
+ if(ui32Root <= ui32Rem)
+ {
+ //
+ // Subtract the test root from the remainder.
+ //
+ ui32Rem -= ui32Root;
+
+ //
+ // Increment the root, setting the second LSB.
+ //
+ ui32Root++;
+ }
+ else
+ {
+ //
+ // The root is greater than the remainder, so the new bit of the
+ // root is actually zero.
+ //
+ ui32Root--;
+ }
+ }
+
+ //
+ // Return the computed root.
+ //
+ return(ui32Root >> 1);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/isqrt.h b/utils/isqrt.h
new file mode 100644
index 0000000..2d0de39
--- /dev/null
+++ b/utils/isqrt.h
@@ -0,0 +1,55 @@
+//*****************************************************************************
+//
+// isqrt.h - Prototype for the integer square root function.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __ISQRT_H__
+#define __ISQRT_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The prototype for the integer square root function.
+//
+//*****************************************************************************
+extern uint32_t isqrt(uint32_t ui32Value);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/utils/locator.c b/utils/locator.c
new file mode 100644
index 0000000..fb240b2
--- /dev/null
+++ b/utils/locator.c
@@ -0,0 +1,342 @@
+//*****************************************************************************
+//
+// locator.c - A device locator server using UDP in lwIP.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "utils/locator.h"
+#include "utils/lwiplib.h"
+
+//*****************************************************************************
+//
+//! \addtogroup locator_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// These defines are used to describe the device locator protocol.
+//
+//*****************************************************************************
+#define TAG_CMD 0xff
+#define TAG_STATUS 0xfe
+#define CMD_DISCOVER_TARGET 0x02
+
+//*****************************************************************************
+//
+// An array that contains the device locator response data. The format of the
+// data is as follows:
+//
+// Byte Description
+// -------- ------------------------
+// 0 TAG_STATUS
+// 1 packet length
+// 2 CMD_DISCOVER_TARGET
+// 3 board type
+// 4 board ID
+// 5..8 client IP address
+// 9..14 MAC address
+// 15..18 firmware version
+// 19..82 application title
+// 83 checksum
+//
+//*****************************************************************************
+static uint8_t g_pui8LocatorData[84];
+
+//*****************************************************************************
+//
+// This function is called by the lwIP TCP/IP stack when it receives a UDP
+// packet from the discovery port. It produces the response packet, which is
+// sent back to the querying client.
+//
+//*****************************************************************************
+static void
+LocatorReceive(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+ struct ip_addr *addr, u16_t port)
+{
+ uint8_t *pui8Data;
+ uint32_t ui32Idx;
+
+ //
+ // Validate the contents of the datagram.
+ //
+ pui8Data = p->payload;
+ if((p->len != 4) || (pui8Data[0] != TAG_CMD) || (pui8Data[1] != 4) ||
+ (pui8Data[2] != CMD_DISCOVER_TARGET) ||
+ (pui8Data[3] != ((0 - TAG_CMD - 4 - CMD_DISCOVER_TARGET) & 0xff)))
+ {
+ pbuf_free(p);
+ return;
+ }
+
+ //
+ // The incoming pbuf is no longer needed, so free it.
+ //
+ pbuf_free(p);
+
+ //
+ // Allocate a new pbuf for sending the response.
+ //
+ p = pbuf_alloc(PBUF_TRANSPORT, sizeof(g_pui8LocatorData), PBUF_RAM);
+ if(p == NULL)
+ {
+ return;
+ }
+
+ //
+ // Calculate and fill in the checksum on the response packet.
+ //
+ for(ui32Idx = 0, g_pui8LocatorData[sizeof(g_pui8LocatorData) - 1] = 0;
+ ui32Idx < (sizeof(g_pui8LocatorData) - 1); ui32Idx++)
+ {
+ g_pui8LocatorData[sizeof(g_pui8LocatorData) - 1] -=
+ g_pui8LocatorData[ui32Idx];
+ }
+
+ //
+ // Copy the response packet data into the pbuf.
+ //
+ pui8Data = p->payload;
+ for(ui32Idx = 0; ui32Idx < sizeof(g_pui8LocatorData); ui32Idx++)
+ {
+ pui8Data[ui32Idx] = g_pui8LocatorData[ui32Idx];
+ }
+
+ //
+ // Send the response.
+ //
+ udp_sendto(pcb, p, addr, port);
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+//! Initializes the locator service.
+//!
+//! This function prepares the locator service to handle device discovery
+//! requests. A UDP server is created and the locator response data is
+//! initialized to all empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorInit(void)
+{
+ uint32_t ui32Idx;
+ void *pcb;
+
+ //
+ // Clear out the response data.
+ //
+ for(ui32Idx = 0; ui32Idx < 84; ui32Idx++)
+ {
+ g_pui8LocatorData[ui32Idx] = 0;
+ }
+
+ //
+ // Fill in the header for the response data.
+ //
+ g_pui8LocatorData[0] = TAG_STATUS;
+ g_pui8LocatorData[1] = sizeof(g_pui8LocatorData);
+ g_pui8LocatorData[2] = CMD_DISCOVER_TARGET;
+
+ //
+ // Fill in the MAC address for the response data.
+ //
+ g_pui8LocatorData[9] = 0;
+ g_pui8LocatorData[10] = 0;
+ g_pui8LocatorData[11] = 0;
+ g_pui8LocatorData[12] = 0;
+ g_pui8LocatorData[13] = 0;
+ g_pui8LocatorData[14] = 0;
+
+ //
+ // Create a new UDP port for listening to device locator requests.
+ //
+ pcb = udp_new();
+ udp_recv(pcb, LocatorReceive, NULL);
+ udp_bind(pcb, IP_ADDR_ANY, 23);
+}
+
+//*****************************************************************************
+//
+//! Sets the board type in the locator response packet.
+//!
+//! \param ui32Type is the type of the board.
+//!
+//! This function sets the board type field in the locator response packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorBoardTypeSet(uint32_t ui32Type)
+{
+ //
+ // Save the board type in the response data.
+ //
+ g_pui8LocatorData[3] = ui32Type & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Sets the board ID in the locator response packet.
+//!
+//! \param ui32ID is the ID of the board.
+//!
+//! This function sets the board ID field in the locator response packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorBoardIDSet(uint32_t ui32ID)
+{
+ //
+ // Save the board ID in the response data.
+ //
+ g_pui8LocatorData[4] = ui32ID & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Sets the client IP address in the locator response packet.
+//!
+//! \param ui32IP is the IP address of the currently connected client.
+//!
+//! This function sets the IP address of the currently connected client in the
+//! locator response packet. The IP should be set to 0.0.0.0 if there is no
+//! client connected. It should never be set for devices that do not have a
+//! strict one-to-one mapping of client to server (for example, a web server).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorClientIPSet(uint32_t ui32IP)
+{
+ //
+ // Save the client IP address in the response data.
+ //
+ g_pui8LocatorData[5] = ui32IP & 0xff;
+ g_pui8LocatorData[6] = (ui32IP >> 8) & 0xff;
+ g_pui8LocatorData[7] = (ui32IP >> 16) & 0xff;
+ g_pui8LocatorData[8] = (ui32IP >> 24) & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Sets the MAC address in the locator response packet.
+//!
+//! \param pui8MACArray is the MAC address of the network interface.
+//!
+//! This function sets the MAC address of the network interface in the locator
+//! response packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorMACAddrSet(uint8_t *pui8MACArray)
+{
+ //
+ // Save the MAC address.
+ //
+ g_pui8LocatorData[9] = pui8MACArray[0];
+ g_pui8LocatorData[10] = pui8MACArray[1];
+ g_pui8LocatorData[11] = pui8MACArray[2];
+ g_pui8LocatorData[12] = pui8MACArray[3];
+ g_pui8LocatorData[13] = pui8MACArray[4];
+ g_pui8LocatorData[14] = pui8MACArray[5];
+}
+
+//*****************************************************************************
+//
+//! Sets the firmware version in the locator response packet.
+//!
+//! \param ui32Version is the version number of the device firmware.
+//!
+//! This function sets the version number of the device firmware in the locator
+//! response packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorVersionSet(uint32_t ui32Version)
+{
+ //
+ // Save the firmware version number in the response data.
+ //
+ g_pui8LocatorData[15] = ui32Version & 0xff;
+ g_pui8LocatorData[16] = (ui32Version >> 8) & 0xff;
+ g_pui8LocatorData[17] = (ui32Version >> 16) & 0xff;
+ g_pui8LocatorData[18] = (ui32Version >> 24) & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Sets the application title in the locator response packet.
+//!
+//! \param pcAppTitle is a pointer to the application title string.
+//!
+//! This function sets the application title in the locator response packet.
+//! The string is truncated at 64 characters if it is longer (without a
+//! terminating 0), and is zero-filled to 64 characters if it is shorter.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorAppTitleSet(const char *pcAppTitle)
+{
+ uint32_t ui32Count;
+
+ //
+ // Copy the application title string into the response data.
+ //
+ for(ui32Count = 0; (ui32Count < 64) && *pcAppTitle; ui32Count++)
+ {
+ g_pui8LocatorData[ui32Count + 19] = *pcAppTitle++;
+ }
+
+ //
+ // Zero-fill the remainder of the space in the response data (if any).
+ //
+ for(; ui32Count < 64; ui32Count++)
+ {
+ g_pui8LocatorData[ui32Count + 19] = 0;
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/locator.h b/utils/locator.h
new file mode 100644
index 0000000..0ef7979
--- /dev/null
+++ b/utils/locator.h
@@ -0,0 +1,61 @@
+//*****************************************************************************
+//
+// locator.h - Prototypes for the device locator server.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __LOCATOR_H__
+#define __LOCATOR_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern void LocatorInit(void);
+extern void LocatorBoardTypeSet(uint32_t ui32Type);
+extern void LocatorBoardIDSet(uint32_t ui32ID);
+extern void LocatorClientIPSet(uint32_t ui32IP);
+extern void LocatorMACAddrSet(uint8_t *pui8MACArray);
+extern void LocatorVersionSet(uint32_t ui32Version);
+extern void LocatorAppTitleSet(const char *pcAppTitle);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LOCATOR_H__
diff --git a/utils/lwiplib.c b/utils/lwiplib.c
new file mode 100644
index 0000000..89539bd
--- /dev/null
+++ b/utils/lwiplib.c
@@ -0,0 +1,1399 @@
+//*****************************************************************************
+//
+// lwiplib.c - lwIP TCP/IP Library Abstraction Layer.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Ensure that the lwIP compile time options are included first.
+//
+//*****************************************************************************
+#include <stdint.h>
+#include <stdbool.h>
+#include "utils/lwiplib.h"
+
+//*****************************************************************************
+//
+// Ensure that ICMP checksum offloading is enabled; otherwise the TM4C129
+// driver will not operate correctly.
+//
+//*****************************************************************************
+#ifndef LWIP_OFFLOAD_ICMP_CHKSUM
+#define LWIP_OFFLOAD_ICMP_CHKSUM 1
+#endif
+
+//*****************************************************************************
+//
+// Include lwIP high-level API code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/api/api_lib.c"
+#include "third_party/lwip-1.4.1/src/api/api_msg.c"
+#include "third_party/lwip-1.4.1/src/api/err.c"
+#include "third_party/lwip-1.4.1/src/api/netbuf.c"
+#include "third_party/lwip-1.4.1/src/api/netdb.c"
+#include "third_party/lwip-1.4.1/src/api/netifapi.c"
+#include "third_party/lwip-1.4.1/src/api/sockets.c"
+#include "third_party/lwip-1.4.1/src/api/tcpip.c"
+
+//*****************************************************************************
+//
+// Include the core lwIP TCP/IP stack code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/core/def.c"
+#include "third_party/lwip-1.4.1/src/core/dhcp.c"
+#include "third_party/lwip-1.4.1/src/core/dns.c"
+#include "third_party/lwip-1.4.1/src/core/init.c"
+#include "third_party/lwip-1.4.1/src/core/mem.c"
+#include "third_party/lwip-1.4.1/src/core/memp.c"
+#include "third_party/lwip-1.4.1/src/core/netif.c"
+#include "third_party/lwip-1.4.1/src/core/pbuf.c"
+#include "third_party/lwip-1.4.1/src/core/raw.c"
+#include "third_party/lwip-1.4.1/src/core/stats.c"
+#include "third_party/lwip-1.4.1/src/core/sys.c"
+#include "third_party/lwip-1.4.1/src/core/tcp.c"
+#include "third_party/lwip-1.4.1/src/core/tcp_in.c"
+#include "third_party/lwip-1.4.1/src/core/tcp_out.c"
+#include "third_party/lwip-1.4.1/src/core/timers.c"
+#include "third_party/lwip-1.4.1/src/core/udp.c"
+
+//*****************************************************************************
+//
+// Include the IPV4 code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/core/ipv4/autoip.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/icmp.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/igmp.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/inet.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/inet_chksum.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/ip.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/ip_addr.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/ip_frag.c"
+
+//*****************************************************************************
+//
+// Include the IPV6 code.
+// Note: Code is experimental and not ready for use.
+// References are included for completeness.
+//
+//*****************************************************************************
+#if 0
+#include "third_party/lwip-1.4.1/src/core/ipv6/icmp6.c"
+#include "third_party/lwip-1.4.1/src/core/ipv6/inet6.c"
+#include "third_party/lwip-1.4.1/src/core/ipv6/ip6.c"
+#include "third_party/lwip-1.4.1/src/core/ipv6/ip6_addr.c"
+#endif
+
+//*****************************************************************************
+//
+// Include the lwIP SNMP code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/core/snmp/asn1_dec.c"
+#include "third_party/lwip-1.4.1/src/core/snmp/asn1_enc.c"
+#include "third_party/lwip-1.4.1/src/core/snmp/mib2.c"
+#include "third_party/lwip-1.4.1/src/core/snmp/mib_structs.c"
+#include "third_party/lwip-1.4.1/src/core/snmp/msg_in.c"
+#include "third_party/lwip-1.4.1/src/core/snmp/msg_out.c"
+
+//*****************************************************************************
+//
+// Include the network interface code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/netif/etharp.c"
+
+//*****************************************************************************
+//
+// Include the network interface PPP code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/netif/ppp/auth.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/chap.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/chpms.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/fsm.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/ipcp.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/lcp.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/magic.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/md5.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/pap.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/ppp.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/ppp_oe.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/randm.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/vj.c"
+
+//*****************************************************************************
+//
+// Include Tiva-specific lwIP interface/porting layer code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/ports/tiva-tm4c129/perf.c"
+#include "third_party/lwip-1.4.1/ports/tiva-tm4c129/sys_arch.c"
+#include "third_party/lwip-1.4.1/ports/tiva-tm4c129/netif/tiva-tm4c129.c"
+
+//*****************************************************************************
+//
+//! \addtogroup lwiplib_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The lwIP Library abstration layer provides for a host callback function to
+// be called periodically in the lwIP context. This is the timer interval, in
+// ms, for this periodic callback. If the timer interval is defined to 0 (the
+// default value), then no periodic host callback is performed.
+//
+//*****************************************************************************
+#ifndef HOST_TMR_INTERVAL
+#define HOST_TMR_INTERVAL 0
+#else
+extern void lwIPHostTimerHandler(void);
+#endif
+
+//*****************************************************************************
+//
+// The link detect polling interval.
+//
+//*****************************************************************************
+#define LINK_TMR_INTERVAL 10
+
+//*****************************************************************************
+//
+// Set the PHY configuration to the default (internal) option if necessary.
+//
+//*****************************************************************************
+#ifndef EMAC_PHY_CONFIG
+#define EMAC_PHY_CONFIG (EMAC_PHY_TYPE_INTERNAL | \
+ EMAC_PHY_INT_MDIX_EN | \
+ EMAC_PHY_AN_100B_T_FULL_DUPLEX)
+#endif
+
+//*****************************************************************************
+//
+// Driverlib headers needed for this library module.
+//
+//*****************************************************************************
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_nvic.h"
+#include "driverlib/debug.h"
+#include "driverlib/emac.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#if !NO_SYS
+#if RTOS_FREERTOS
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+#endif
+#if ((RTOS_FREERTOS) < 1)
+ #error No RTOS is defined. Please define an RTOS.
+#endif
+#if ((RTOS_FREERTOS) > 1)
+ #error More than one RTOS defined. Please define only one RTOS at a time.
+#endif
+#endif
+
+//*****************************************************************************
+//
+// The lwIP network interface structure for the Tiva Ethernet MAC.
+//
+//*****************************************************************************
+static struct netif g_sNetIF;
+
+//*****************************************************************************
+//
+// The application's interrupt handler for hardware timer events from the MAC.
+//
+//*****************************************************************************
+tHardwareTimerHandler g_pfnTimerHandler;
+
+//*****************************************************************************
+//
+// The local time for the lwIP Library Abstraction layer, used to support the
+// Host and lwIP periodic callback functions.
+//
+//*****************************************************************************
+#if NO_SYS
+uint32_t g_ui32LocalTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the TCP timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS
+static uint32_t g_ui32TCPTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the HOST timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && HOST_TMR_INTERVAL
+static uint32_t g_ui32HostTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the ARP timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_ARP
+static uint32_t g_ui32ARPTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the AutoIP timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_AUTOIP
+static uint32_t g_ui32AutoIPTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the DHCP Coarse timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_DHCP
+static uint32_t g_ui32DHCPCoarseTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the DHCP Fine timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_DHCP
+static uint32_t g_ui32DHCPFineTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the IP Reassembly timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && IP_REASSEMBLY
+static uint32_t g_ui32IPReassemblyTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the IGMP timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_IGMP
+static uint32_t g_ui32IGMPTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the DNS timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_DNS
+static uint32_t g_ui32DNSTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the link detect timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && (LWIP_AUTOIP || LWIP_DHCP)
+static uint32_t g_ui32LinkTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The default IP address acquisition mode.
+//
+//*****************************************************************************
+static uint32_t g_ui32IPMode = IPADDR_USE_STATIC;
+
+//*****************************************************************************
+//
+// The most recently detected link state.
+//
+//*****************************************************************************
+#if LWIP_AUTOIP || LWIP_DHCP
+static bool g_bLinkActive = false;
+#endif
+
+//*****************************************************************************
+//
+// The IP address to be used. This is used during the initialization of the
+// stack and when the interface configuration is changed.
+//
+//*****************************************************************************
+static uint32_t g_ui32IPAddr;
+
+//*****************************************************************************
+//
+// The netmask to be used. This is used during the initialization of the stack
+// and when the interface configuration is changed.
+//
+//*****************************************************************************
+static uint32_t g_ui32NetMask;
+
+//*****************************************************************************
+//
+// The gateway address to be used. This is used during the initialization of
+// the stack and when the interface configuration is changed.
+//
+//*****************************************************************************
+static uint32_t g_ui32GWAddr;
+
+//*****************************************************************************
+//
+// The stack size for the interrupt task.
+//
+//*****************************************************************************
+#if !NO_SYS
+#define STACKSIZE_LWIPINTTASK 128
+#endif
+
+//*****************************************************************************
+//
+// The handle for the "queue" (semaphore) used to signal the interrupt task
+// from the interrupt handler.
+//
+//*****************************************************************************
+#if !NO_SYS
+static xQueueHandle g_pInterrupt;
+#endif
+
+//*****************************************************************************
+//
+// This task handles reading packets from the Ethernet controller and supplying
+// them to the TCP/IP thread.
+//
+//*****************************************************************************
+#if !NO_SYS
+static void
+lwIPInterruptTask(void *pvArg)
+{
+ //
+ // Loop forever.
+ //
+ while(1)
+ {
+ //
+ // Wait until the semaphore has been signaled.
+ //
+ while(xQueueReceive(g_pInterrupt, &pvArg, portMAX_DELAY) != pdPASS)
+ {
+ }
+
+ //
+ // Processes any packets waiting to be sent or received.
+ //
+ tivaif_interrupt(&g_sNetIF, (uint32_t)pvArg);
+
+ //
+ // Re-enable the Ethernet interrupts.
+ //
+ MAP_EMACIntEnable(EMAC0_BASE, (EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT |
+ EMAC_INT_TX_STOPPED |
+ EMAC_INT_RX_NO_BUFFER |
+ EMAC_INT_RX_STOPPED | EMAC_INT_PHY));
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+// This function performs a periodic check of the link status and responds
+// appropriately if it has changed.
+//
+//*****************************************************************************
+#if LWIP_AUTOIP || LWIP_DHCP
+static void
+lwIPLinkDetect(void)
+{
+ bool bHaveLink;
+ struct ip_addr ip_addr;
+ struct ip_addr net_mask;
+ struct ip_addr gw_addr;
+
+ //
+ // See if there is an active link.
+ //
+ bHaveLink = MAP_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & EPHY_BMSR_LINKSTAT;
+
+ //
+ // Return without doing anything else if the link state hasn't changed.
+ //
+ if(bHaveLink == g_bLinkActive)
+ {
+ return;
+ }
+
+ //
+ // Save the new link state.
+ //
+ g_bLinkActive = bHaveLink;
+
+ //
+ // Clear any address information from the network interface.
+ //
+ ip_addr.addr = 0;
+ net_mask.addr = 0;
+ gw_addr.addr = 0;
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+
+ //
+ // See if there is a link now.
+ //
+ if(bHaveLink)
+ {
+ //
+ // Start DHCP, if enabled.
+ //
+#if LWIP_DHCP
+ if(g_ui32IPMode == IPADDR_USE_DHCP)
+ {
+ dhcp_start(&g_sNetIF);
+ }
+#endif
+
+ //
+ // Start AutoIP, if enabled and DHCP is not.
+ //
+#if LWIP_AUTOIP
+ if(g_ui32IPMode == IPADDR_USE_AUTOIP)
+ {
+ autoip_start(&g_sNetIF);
+ }
+#endif
+ }
+ else
+ {
+ //
+ // Stop DHCP, if enabled.
+ //
+#if LWIP_DHCP
+ if(g_ui32IPMode == IPADDR_USE_DHCP)
+ {
+ dhcp_stop(&g_sNetIF);
+ }
+#endif
+
+ //
+ // Stop AutoIP, if enabled and DHCP is not.
+ //
+#if LWIP_AUTOIP
+ if(g_ui32IPMode == IPADDR_USE_AUTOIP)
+ {
+ autoip_stop(&g_sNetIF);
+ }
+#endif
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+// This function services all of the lwIP periodic timers, including TCP and
+// Host timers. This should be called from the lwIP context, which may be
+// the Ethernet interrupt (in the case of a non-RTOS system) or the lwIP
+// thread, in the event that an RTOS is used.
+//
+//*****************************************************************************
+#if NO_SYS
+static void
+lwIPServiceTimers(void)
+{
+ //
+ // Service the host timer.
+ //
+#if HOST_TMR_INTERVAL
+ if((g_ui32LocalTimer - g_ui32HostTimer) >= HOST_TMR_INTERVAL)
+ {
+ g_ui32HostTimer = g_ui32LocalTimer;
+ lwIPHostTimerHandler();
+ }
+#endif
+
+ //
+ // Service the ARP timer.
+ //
+#if LWIP_ARP
+ if((g_ui32LocalTimer - g_ui32ARPTimer) >= ARP_TMR_INTERVAL)
+ {
+ g_ui32ARPTimer = g_ui32LocalTimer;
+ etharp_tmr();
+ }
+#endif
+
+ //
+ // Service the TCP timer.
+ //
+#if LWIP_TCP
+ if((g_ui32LocalTimer - g_ui32TCPTimer) >= TCP_TMR_INTERVAL)
+ {
+ g_ui32TCPTimer = g_ui32LocalTimer;
+ tcp_tmr();
+ }
+#endif
+
+ //
+ // Service the AutoIP timer.
+ //
+#if LWIP_AUTOIP
+ if((g_ui32LocalTimer - g_ui32AutoIPTimer) >= AUTOIP_TMR_INTERVAL)
+ {
+ g_ui32AutoIPTimer = g_ui32LocalTimer;
+ autoip_tmr();
+ }
+#endif
+
+ //
+ // Service the DCHP Coarse Timer.
+ //
+#if LWIP_DHCP
+ if((g_ui32LocalTimer - g_ui32DHCPCoarseTimer) >= DHCP_COARSE_TIMER_MSECS)
+ {
+ g_ui32DHCPCoarseTimer = g_ui32LocalTimer;
+ dhcp_coarse_tmr();
+ }
+#endif
+
+ //
+ // Service the DCHP Fine Timer.
+ //
+#if LWIP_DHCP
+ if((g_ui32LocalTimer - g_ui32DHCPFineTimer) >= DHCP_FINE_TIMER_MSECS)
+ {
+ g_ui32DHCPFineTimer = g_ui32LocalTimer;
+ dhcp_fine_tmr();
+ }
+#endif
+
+ //
+ // Service the IP Reassembly Timer
+ //
+#if IP_REASSEMBLY
+ if((g_ui32LocalTimer - g_ui32IPReassemblyTimer) >= IP_TMR_INTERVAL)
+ {
+ g_ui32IPReassemblyTimer = g_ui32LocalTimer;
+ ip_reass_tmr();
+ }
+#endif
+
+ //
+ // Service the IGMP Timer
+ //
+#if LWIP_IGMP
+ if((g_ui32LocalTimer - g_ui32IGMPTimer) >= IGMP_TMR_INTERVAL)
+ {
+ g_ui32IGMPTimer = g_ui32LocalTimer;
+ igmp_tmr();
+ }
+#endif
+
+ //
+ // Service the DNS Timer
+ //
+#if LWIP_DNS
+ if((g_ui32LocalTimer - g_ui32DNSTimer) >= DNS_TMR_INTERVAL)
+ {
+ g_ui32DNSTimer = g_ui32LocalTimer;
+ dns_tmr();
+ }
+#endif
+
+ //
+ // Service the link timer.
+ //
+#if LWIP_AUTOIP || LWIP_DHCP
+ if((g_ui32LocalTimer - g_ui32LinkTimer) >= LINK_TMR_INTERVAL)
+ {
+ g_ui32LinkTimer = g_ui32LocalTimer;
+ lwIPLinkDetect();
+ }
+#endif
+}
+#endif
+
+//*****************************************************************************
+//
+// Handles the timeout for the host callback function timer when using a RTOS.
+//
+//*****************************************************************************
+#if !NO_SYS && HOST_TMR_INTERVAL
+static void
+lwIPPrivateHostTimer(void *pvArg)
+{
+ //
+ // Call the application-supplied host timer callback function.
+ //
+ lwIPHostTimerHandler();
+
+ //
+ // Re-schedule the host timer callback function timeout.
+ //
+ sys_timeout(HOST_TMR_INTERVAL, lwIPPrivateHostTimer, NULL);
+}
+#endif
+
+//*****************************************************************************
+//
+// Handles the timeout for the link detect timer when using a RTOS.
+//
+//*****************************************************************************
+#if !NO_SYS && (LWIP_AUTOIP || LWIP_DHCP)
+static void
+lwIPPrivateLinkTimer(void *pvArg)
+{
+ //
+ // Perform the link detection.
+ //
+ lwIPLinkDetect();
+
+ //
+ // Re-schedule the link detect timer timeout.
+ //
+ sys_timeout(LINK_TMR_INTERVAL, lwIPPrivateLinkTimer, NULL);
+}
+#endif
+
+//*****************************************************************************
+//
+// Completes the initialization of lwIP. This is directly called when not
+// using a RTOS and provided as a callback to the TCP/IP thread when using a
+// RTOS.
+//
+//*****************************************************************************
+static void
+lwIPPrivateInit(void *pvArg)
+{
+ struct ip_addr ip_addr;
+ struct ip_addr net_mask;
+ struct ip_addr gw_addr;
+
+ //
+ // If not using a RTOS, initialize the lwIP stack.
+ //
+#if NO_SYS
+ lwip_init();
+#endif
+
+ //
+ // If using a RTOS, create a queue (to be used as a semaphore) to signal
+ // the Ethernet interrupt task from the Ethernet interrupt handler.
+ //
+#if !NO_SYS
+#if RTOS_FREERTOS
+ g_pInterrupt = xQueueCreate(1, sizeof(void *));
+#endif
+#endif
+
+ //
+ // If using a RTOS, create the Ethernet interrupt task.
+ //
+#if !NO_SYS
+#if RTOS_FREERTOS
+ xTaskCreate(lwIPInterruptTask, (signed portCHAR *)"eth_int",
+ STACKSIZE_LWIPINTTASK, 0, tskIDLE_PRIORITY + 1,
+ 0);
+#endif
+#endif
+
+ //
+ // Setup the network address values.
+ //
+ if(g_ui32IPMode == IPADDR_USE_STATIC)
+ {
+ ip_addr.addr = htonl(g_ui32IPAddr);
+ net_mask.addr = htonl(g_ui32NetMask);
+ gw_addr.addr = htonl(g_ui32GWAddr);
+ }
+ else
+ {
+ ip_addr.addr = 0;
+ net_mask.addr = 0;
+ gw_addr.addr = 0;
+ }
+
+ //
+ // Create, configure and add the Ethernet controller interface with
+ // default settings. ip_input should be used to send packets directly to
+ // the stack when not using a RTOS and tcpip_input should be used to send
+ // packets to the TCP/IP thread's queue when using a RTOS.
+ //
+#if NO_SYS
+ netif_add(&g_sNetIF, &ip_addr, &net_mask, &gw_addr, NULL, tivaif_init,
+ ip_input);
+#else
+ netif_add(&g_sNetIF, &ip_addr, &net_mask, &gw_addr, NULL, tivaif_init,
+ tcpip_input);
+#endif
+ netif_set_default(&g_sNetIF);
+
+ //
+ // Bring the interface up.
+ //
+ netif_set_up(&g_sNetIF);
+
+ //
+ // Setup a timeout for the host timer callback function if using a RTOS.
+ //
+#if !NO_SYS && HOST_TMR_INTERVAL
+ sys_timeout(HOST_TMR_INTERVAL, lwIPPrivateHostTimer, NULL);
+#endif
+
+ //
+ // Setup a timeout for the link detect callback function if using a RTOS.
+ //
+#if !NO_SYS && (LWIP_AUTOIP || LWIP_DHCP)
+ sys_timeout(LINK_TMR_INTERVAL, lwIPPrivateLinkTimer, NULL);
+#endif
+}
+
+//*****************************************************************************
+//
+//! Initializes the lwIP TCP/IP stack.
+//!
+//! \param ui32SysClkHz is the current system clock rate in Hz.
+//! \param pui8MAC is a pointer to a six byte array containing the MAC
+//! address to be used for the interface.
+//! \param ui32IPAddr is the IP address to be used (static).
+//! \param ui32NetMask is the network mask to be used (static).
+//! \param ui32GWAddr is the Gateway address to be used (static).
+//! \param ui32IPMode is the IP Address Mode. \b IPADDR_USE_STATIC will force
+//! static IP addressing to be used, \b IPADDR_USE_DHCP will force DHCP with
+//! fallback to Link Local (Auto IP), while \b IPADDR_USE_AUTOIP will force
+//! Link Local only.
+//!
+//! This function performs initialization of the lwIP TCP/IP stack for the
+//! Ethernet MAC, including DHCP and/or AutoIP, as configured.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+lwIPInit(uint32_t ui32SysClkHz, const uint8_t *pui8MAC, uint32_t ui32IPAddr,
+ uint32_t ui32NetMask, uint32_t ui32GWAddr, uint32_t ui32IPMode)
+{
+ //
+ // Check the parameters.
+ //
+#if LWIP_DHCP && LWIP_AUTOIP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_DHCP) ||
+ (ui32IPMode == IPADDR_USE_AUTOIP));
+#elif LWIP_DHCP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_DHCP));
+#elif LWIP_AUTOIP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_AUTOIP));
+#else
+ ASSERT(ui32IPMode == IPADDR_USE_STATIC);
+#endif
+
+ //
+ // Enable the ethernet peripheral.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0);
+ MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0);
+
+ //
+ // Enable the internal PHY if it's present and we're being
+ // asked to use it.
+ //
+ if((EMAC_PHY_CONFIG & EMAC_PHY_TYPE_MASK) == EMAC_PHY_TYPE_INTERNAL)
+ {
+ //
+ // We've been asked to configure for use with the internal
+ // PHY. Is it present?
+ //
+ if(MAP_SysCtlPeripheralPresent(SYSCTL_PERIPH_EPHY0))
+ {
+ //
+ // Yes - enable and reset it.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0);
+ MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0);
+ }
+ else
+ {
+ //
+ // Internal PHY is not present on this part so hang here.
+ //
+ while(1)
+ {
+ }
+ }
+ }
+
+ //
+ // Wait for the MAC to come out of reset.
+ //
+ while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0))
+ {
+ }
+
+ //
+ // Configure for use with whichever PHY the user requires.
+ //
+ MAP_EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_CONFIG);
+
+ //
+ // Initialize the MAC and set the DMA mode.
+ //
+ MAP_EMACInit(EMAC0_BASE, ui32SysClkHz,
+ EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED,
+ 4, 4, 0);
+
+ //
+ // Set MAC configuration options.
+ //
+ MAP_EMACConfigSet(EMAC0_BASE, (EMAC_CONFIG_FULL_DUPLEX |
+ EMAC_CONFIG_CHECKSUM_OFFLOAD |
+ EMAC_CONFIG_7BYTE_PREAMBLE |
+ EMAC_CONFIG_IF_GAP_96BITS |
+ EMAC_CONFIG_USE_MACADDR0 |
+ EMAC_CONFIG_SA_FROM_DESCRIPTOR |
+ EMAC_CONFIG_BO_LIMIT_1024),
+ (EMAC_MODE_RX_STORE_FORWARD |
+ EMAC_MODE_TX_STORE_FORWARD |
+ EMAC_MODE_TX_THRESHOLD_64_BYTES |
+ EMAC_MODE_RX_THRESHOLD_64_BYTES), 0);
+
+ //
+ // Program the hardware with its MAC address (for filtering).
+ //
+ MAP_EMACAddrSet(EMAC0_BASE, 0, (uint8_t *)pui8MAC);
+
+ //
+ // Save the network configuration for later use by the private
+ // initialization.
+ //
+ g_ui32IPMode = ui32IPMode;
+ g_ui32IPAddr = ui32IPAddr;
+ g_ui32NetMask = ui32NetMask;
+ g_ui32GWAddr = ui32GWAddr;
+
+ //
+ // Initialize lwIP. The remainder of initialization is done immediately if
+ // not using a RTOS and it is deferred to the TCP/IP thread's context if
+ // using a RTOS.
+ //
+#if NO_SYS
+ lwIPPrivateInit(0);
+#else
+ tcpip_init(lwIPPrivateInit, 0);
+#endif
+}
+
+//*****************************************************************************
+//
+//! Registers an interrupt callback function to handle the IEEE-1588 timer.
+//!
+//! \param pfnTimerFunc points to a function which is called whenever the
+//! Ethernet MAC reports an interrupt relating to the IEEE-1588 hardware timer.
+//!
+//! This function allows an application to register a handler for all
+//! interrupts generated by the IEEE-1588 hardware timer in the Ethernet MAC.
+//! To allow minimal latency timer handling, the callback function provided
+//! will be called in interrupt context, regardless of whether or not lwIP is
+//! configured to operate with an RTOS. In an RTOS environment, the callback
+//! function is responsible for ensuring that all processing it performs is
+//! compatible with the low level interrupt context it is called in.
+//!
+//! The callback function takes two parameters. The first is the base address
+//! of the MAC reporting the timer interrupt and the second is the timer
+//! interrupt status as reported by EMACTimestampIntStatus(). Note that
+//! EMACTimestampIntStatus() causes the timer interrupt sources to be cleared
+//! so the application should not call EMACTimestampIntStatus() within the
+//! handler.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+lwIPTimerCallbackRegister(tHardwareTimerHandler pfnTimerFunc)
+{
+ //
+ // Remember the callback function address passed.
+ //
+ g_pfnTimerHandler = pfnTimerFunc;
+}
+
+//*****************************************************************************
+//
+//! Handles periodic timer events for the lwIP TCP/IP stack.
+//!
+//! \param ui32TimeMS is the incremental time for this periodic interrupt.
+//!
+//! This function will update the local timer by the value in \e ui32TimeMS.
+//! If the system is configured for use without an RTOS, an Ethernet interrupt
+//! will be triggered to allow the lwIP periodic timers to be serviced in the
+//! Ethernet interrupt.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#if NO_SYS
+void
+lwIPTimer(uint32_t ui32TimeMS)
+{
+ //
+ // Increment the lwIP Ethernet timer.
+ //
+ g_ui32LocalTimer += ui32TimeMS;
+
+ //
+ // Generate an Ethernet interrupt. This will perform the actual work
+ // of checking the lwIP timers and taking the appropriate actions. This is
+ // needed since lwIP is not re-entrant, and this allows all lwIP calls to
+ // be placed inside the Ethernet interrupt handler ensuring that all calls
+ // into lwIP are coming from the same context, preventing any reentrancy
+ // issues. Putting all the lwIP calls in the Ethernet interrupt handler
+ // avoids the use of mutexes to avoid re-entering lwIP.
+ //
+ HWREG(NVIC_SW_TRIG) |= INT_EMAC0 - 16;
+}
+#endif
+
+//*****************************************************************************
+//
+//! Handles Ethernet interrupts for the lwIP TCP/IP stack.
+//!
+//! This function handles Ethernet interrupts for the lwIP TCP/IP stack. At
+//! the lowest level, all receive packets are placed into a packet queue for
+//! processing at a higher level. Also, the transmit packet queue is checked
+//! and packets are drained and transmitted through the Ethernet MAC as needed.
+//! If the system is configured without an RTOS, additional processing is
+//! performed at the interrupt level. The packet queues are processed by the
+//! lwIP TCP/IP code, and lwIP periodic timers are serviced (as needed).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+lwIPEthernetIntHandler(void)
+{
+ uint32_t ui32Status;
+ uint32_t ui32TimerStatus;
+#if !NO_SYS
+ portBASE_TYPE xWake;
+#endif
+
+ //
+ // Read and Clear the interrupt.
+ //
+ ui32Status = MAP_EMACIntStatus(EMAC0_BASE, true);
+
+ //
+ // If the interrupt really came from the Ethernet and not our
+ // timer, clear it.
+ //
+ if(ui32Status)
+ {
+ MAP_EMACIntClear(EMAC0_BASE, ui32Status);
+ }
+
+ //
+ // Check to see whether a hardware timer interrupt has been reported.
+ //
+ if(ui32Status & EMAC_INT_TIMESTAMP)
+ {
+ //
+ // Yes - read and clear the timestamp interrupt status.
+ //
+ ui32TimerStatus = EMACTimestampIntStatus(EMAC0_BASE);
+
+ //
+ // If a timer interrupt handler has been registered, call it.
+ //
+ if(g_pfnTimerHandler)
+ {
+ g_pfnTimerHandler(EMAC0_BASE, ui32TimerStatus);
+ }
+ }
+
+ //
+ // The handling of the interrupt is different based on the use of a RTOS.
+ //
+#if NO_SYS
+ //
+ // No RTOS is being used. If a transmit/receive interrupt was active,
+ // run the low-level interrupt handler.
+ //
+ if(ui32Status)
+ {
+ tivaif_interrupt(&g_sNetIF, ui32Status);
+ }
+
+ //
+ // Service the lwIP timers.
+ //
+ lwIPServiceTimers();
+#else
+ //
+ // A RTOS is being used. Signal the Ethernet interrupt task.
+ //
+ xQueueSendFromISR(g_pInterrupt, (void *)&ui32Status, &xWake);
+
+ //
+ // Disable the Ethernet interrupts. Since the interrupts have not been
+ // handled, they are not asserted. Once they are handled by the Ethernet
+ // interrupt task, it will re-enable the interrupts.
+ //
+ MAP_EMACIntDisable(EMAC0_BASE, (EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT |
+ EMAC_INT_TX_STOPPED |
+ EMAC_INT_RX_NO_BUFFER |
+ EMAC_INT_RX_STOPPED | EMAC_INT_PHY));
+
+ //
+ // Potentially task switch as a result of the above queue write.
+ //
+#if RTOS_FREERTOS
+ if(xWake == pdTRUE)
+ {
+ portYIELD_FROM_ISR(true);
+ }
+#endif
+#endif
+}
+
+//*****************************************************************************
+//
+//! Returns the IP address for this interface.
+//!
+//! This function will read and return the currently assigned IP address for
+//! the Stellaris Ethernet interface.
+//!
+//! \return Returns the assigned IP address for this interface.
+//
+//*****************************************************************************
+uint32_t
+lwIPLocalIPAddrGet(void)
+{
+#if LWIP_AUTOIP || LWIP_DHCP
+ if(g_bLinkActive)
+ {
+ return((uint32_t)g_sNetIF.ip_addr.addr);
+ }
+ else
+ {
+ return(0xffffffff);
+ }
+#else
+ return((uint32_t)g_sNetIF.ip_addr.addr);
+#endif
+}
+
+//*****************************************************************************
+//
+//! Returns the network mask for this interface.
+//!
+//! This function will read and return the currently assigned network mask for
+//! the Stellaris Ethernet interface.
+//!
+//! \return the assigned network mask for this interface.
+//
+//*****************************************************************************
+uint32_t
+lwIPLocalNetMaskGet(void)
+{
+ return((uint32_t)g_sNetIF.netmask.addr);
+}
+
+//*****************************************************************************
+//
+//! Returns the gateway address for this interface.
+//!
+//! This function will read and return the currently assigned gateway address
+//! for the Stellaris Ethernet interface.
+//!
+//! \return the assigned gateway address for this interface.
+//
+//*****************************************************************************
+uint32_t
+lwIPLocalGWAddrGet(void)
+{
+ return((uint32_t)g_sNetIF.gw.addr);
+}
+
+//*****************************************************************************
+//
+//! Returns the local MAC/HW address for this interface.
+//!
+//! \param pui8MAC is a pointer to an array of bytes used to store the MAC
+//! address.
+//!
+//! This function will read the currently assigned MAC address into the array
+//! passed in \e pui8MAC.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+lwIPLocalMACGet(uint8_t *pui8MAC)
+{
+ MAP_EMACAddrGet(EMAC0_BASE, 0, pui8MAC);
+}
+
+//*****************************************************************************
+//
+// Completes the network configuration change. This is directly called when
+// not using a RTOS and provided as a callback to the TCP/IP thread when using
+// a RTOS.
+//
+//*****************************************************************************
+static void
+lwIPPrivateNetworkConfigChange(void *pvArg)
+{
+ uint32_t ui32IPMode;
+ struct ip_addr ip_addr;
+ struct ip_addr net_mask;
+ struct ip_addr gw_addr;
+
+ //
+ // Get the new address mode.
+ //
+ ui32IPMode = (uint32_t)pvArg;
+
+ //
+ // Setup the network address values.
+ //
+ if(ui32IPMode == IPADDR_USE_STATIC)
+ {
+ ip_addr.addr = htonl(g_ui32IPAddr);
+ net_mask.addr = htonl(g_ui32NetMask);
+ gw_addr.addr = htonl(g_ui32GWAddr);
+ }
+#if LWIP_DHCP || LWIP_AUTOIP
+ else
+ {
+ ip_addr.addr = 0;
+ net_mask.addr = 0;
+ gw_addr.addr = 0;
+ }
+#endif
+
+ //
+ // Switch on the current IP Address Aquisition mode.
+ //
+ switch(g_ui32IPMode)
+ {
+ //
+ // Static IP
+ //
+ case IPADDR_USE_STATIC:
+ {
+ //
+ // Set the new address parameters. This will change the address
+ // configuration in lwIP, and if necessary, will reset any links
+ // that are active. This is valid for all three modes.
+ //
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+
+ //
+ // If we are going to DHCP mode, then start the DHCP server now.
+ //
+#if LWIP_DHCP
+ if((ui32IPMode == IPADDR_USE_DHCP) && g_bLinkActive)
+ {
+ dhcp_start(&g_sNetIF);
+ }
+#endif
+
+ //
+ // If we are going to AutoIP mode, then start the AutoIP process
+ // now.
+ //
+#if LWIP_AUTOIP
+ if((ui32IPMode == IPADDR_USE_AUTOIP) && g_bLinkActive)
+ {
+ autoip_start(&g_sNetIF);
+ }
+#endif
+
+ //
+ // And we're done.
+ //
+ break;
+ }
+
+ //
+ // DHCP (with AutoIP fallback).
+ //
+#if LWIP_DHCP
+ case IPADDR_USE_DHCP:
+ {
+ //
+ // If we are going to static IP addressing, then disable DHCP and
+ // force the new static IP address.
+ //
+ if(ui32IPMode == IPADDR_USE_STATIC)
+ {
+ dhcp_stop(&g_sNetIF);
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+ }
+
+ //
+ // If we are going to AUTO IP addressing, then disable DHCP, set
+ // the default addresses, and start AutoIP.
+ //
+#if LWIP_AUTOIP
+ else if(ui32IPMode == IPADDR_USE_AUTOIP)
+ {
+ dhcp_stop(&g_sNetIF);
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+ if(g_bLinkActive)
+ {
+ autoip_start(&g_sNetIF);
+ }
+ }
+#endif
+ break;
+ }
+#endif
+
+ //
+ // AUTOIP
+ //
+#if LWIP_AUTOIP
+ case IPADDR_USE_AUTOIP:
+ {
+ //
+ // If we are going to static IP addressing, then disable AutoIP and
+ // force the new static IP address.
+ //
+ if(ui32IPMode == IPADDR_USE_STATIC)
+ {
+ autoip_stop(&g_sNetIF);
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+ }
+
+ //
+ // If we are going to DHCP addressing, then disable AutoIP, set the
+ // default addresses, and start dhcp.
+ //
+#if LWIP_DHCP
+ else if(ui32IPMode == IPADDR_USE_DHCP)
+ {
+ autoip_stop(&g_sNetIF);
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+ if(g_bLinkActive)
+ {
+ dhcp_start(&g_sNetIF);
+ }
+ }
+#endif
+ break;
+ }
+#endif
+ }
+
+ //
+ // Bring the interface up.
+ //
+ netif_set_up(&g_sNetIF);
+
+ //
+ // Save the new mode.
+ //
+ g_ui32IPMode = ui32IPMode;
+}
+
+//*****************************************************************************
+//
+//! Change the configuration of the lwIP network interface.
+//!
+//! \param ui32IPAddr is the new IP address to be used (static).
+//! \param ui32NetMask is the new network mask to be used (static).
+//! \param ui32GWAddr is the new Gateway address to be used (static).
+//! \param ui32IPMode is the IP Address Mode. \b IPADDR_USE_STATIC 0 will
+//! force static IP addressing to be used, \b IPADDR_USE_DHCP will force DHCP
+//! with fallback to Link Local (Auto IP), while \b IPADDR_USE_AUTOIP will
+//! force Link Local only.
+//!
+//! This function will evaluate the new configuration data. If necessary, the
+//! interface will be brought down, reconfigured, and then brought back up
+//! with the new configuration.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+lwIPNetworkConfigChange(uint32_t ui32IPAddr, uint32_t ui32NetMask,
+ uint32_t ui32GWAddr, uint32_t ui32IPMode)
+{
+ //
+ // Check the parameters.
+ //
+#if LWIP_DHCP && LWIP_AUTOIP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_DHCP) ||
+ (ui32IPMode == IPADDR_USE_AUTOIP));
+#elif LWIP_DHCP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_DHCP));
+#elif LWIP_AUTOIP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_AUTOIP));
+#else
+ ASSERT(ui32IPMode == IPADDR_USE_STATIC);
+#endif
+
+ //
+ // Save the network configuration for later use by the private network
+ // configuration change.
+ //
+ g_ui32IPAddr = ui32IPAddr;
+ g_ui32NetMask = ui32NetMask;
+ g_ui32GWAddr = ui32GWAddr;
+
+ //
+ // Complete the network configuration change. The remainder is done
+ // immediately if not using a RTOS and it is deferred to the TCP/IP
+ // thread's context if using a RTOS.
+ //
+#if NO_SYS
+ lwIPPrivateNetworkConfigChange((void *)ui32IPMode);
+#else
+ tcpip_callback(lwIPPrivateNetworkConfigChange, (void *)ui32IPMode);
+#endif
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/lwiplib.h b/utils/lwiplib.h
new file mode 100644
index 0000000..3a3f622
--- /dev/null
+++ b/utils/lwiplib.h
@@ -0,0 +1,121 @@
+//*****************************************************************************
+//
+// lwiplib.h - Prototypes for the lwIP library wrapper API.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __LWIPLIB_H__
+#define __LWIPLIB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// lwIP Options
+//
+//*****************************************************************************
+#include "lwip/opt.h"
+
+//*****************************************************************************
+//
+// Ensure that AUTOIP COOP option is configured correctly.
+//
+//*****************************************************************************
+#undef LWIP_DHCP_AUTOIP_COOP
+#define LWIP_DHCP_AUTOIP_COOP ((LWIP_DHCP) && (LWIP_AUTOIP))
+
+//*****************************************************************************
+//
+// lwIP API Header Files
+//
+//*****************************************************************************
+#include <stdint.h>
+#include "lwip/api.h"
+#include "lwip/netifapi.h"
+#include "lwip/tcp.h"
+#include "lwip/udp.h"
+#include "lwip/tcpip.h"
+#include "lwip/sockets.h"
+#include "lwip/mem.h"
+#include "lwip/stats.h"
+#include "lwip/def.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/timers.h"
+
+//*****************************************************************************
+//
+// IP Address Acquisition Modes
+//
+//*****************************************************************************
+#define IPADDR_USE_STATIC 0
+#define IPADDR_USE_DHCP 1
+#define IPADDR_USE_AUTOIP 2
+
+//*****************************************************************************
+//
+// Hardware timer interrupt callback function type (available only when running
+// on TM4C parts). This function is called in interrupt context whenever the
+// Ethernet MAC reports an interrupt from the IEEE-1588 timestamping
+// timer. The first parameter is the base address of the MAC and the second
+// is the interrupt status as reported via EthMACTimestampIntStatus.
+//
+//*****************************************************************************
+typedef void (* tHardwareTimerHandler)(uint32_t ui32Base,
+ uint32_t ui32IntStatus);
+
+//*****************************************************************************
+//
+// lwIP Abstraction Layer API
+//
+//*****************************************************************************
+extern void lwIPInit(uint32_t ui32SysClkHz, const uint8_t *pui8Mac,
+ uint32_t ui32IPAddr, uint32_t ui32NetMask,
+ uint32_t ui32GWAddr, uint32_t ui32IPMode);
+extern void lwIPTimerCallbackRegister(tHardwareTimerHandler pfnTimerFunc);
+extern void lwIPTimer(uint32_t ui32TimeMS);
+extern void lwIPEthernetIntHandler(void);
+extern uint32_t lwIPLocalIPAddrGet(void);
+extern uint32_t lwIPLocalNetMaskGet(void);
+extern uint32_t lwIPLocalGWAddrGet(void);
+extern void lwIPLocalMACGet(uint8_t *pui8Mac);
+extern void lwIPNetworkConfigChange(uint32_t ui32IPAddr, uint32_t ui32NetMask,
+ uint32_t ui32GWAddr, uint32_t ui32IPMode);
+extern uint32_t lwIPAcceptUDPPort(uint16_t ui16Port);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LWIPLIB_H__
diff --git a/utils/ptpdlib.c b/utils/ptpdlib.c
new file mode 100644
index 0000000..ec340d2
--- /dev/null
+++ b/utils/ptpdlib.c
@@ -0,0 +1,56 @@
+//*****************************************************************************
+//
+// ptpdlib.c - ptpd Library Abstraction Layer.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Include the necessary system header files.
+//
+//*****************************************************************************
+#include <limits.h>
+
+//*****************************************************************************
+//
+// Include the library source code header files next.
+//
+//*****************************************************************************
+#include "utils/ptpdlib.h"
+
+//*****************************************************************************
+//
+// Include ptpd library code.
+//
+//*****************************************************************************
+#include "ptpd-1.1.0/src/arith.c"
+#include "ptpd-1.1.0/src/bmc.c"
+#include "ptpd-1.1.0/src/protocol.c"
+
+//*****************************************************************************
+//
+// Include ptpd porting layer code.
+//
+//*****************************************************************************
+#include "ptpd-1.1.0/src/dep-tiva/ptpd_timer.c"
+#include "ptpd-1.1.0/src/dep-tiva/ptpd_servo.c"
+#include "ptpd-1.1.0/src/dep-tiva/ptpd_msg.c"
+#include "ptpd-1.1.0/src/dep-tiva/ptpd_net.c"
diff --git a/utils/ptpdlib.h b/utils/ptpdlib.h
new file mode 100644
index 0000000..5692877
--- /dev/null
+++ b/utils/ptpdlib.h
@@ -0,0 +1,55 @@
+//*****************************************************************************
+//
+// ptpdlib.h - Prototypes for the ptpd library wrapper API.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __PTPDLIB_H__
+#define __PTPDLIB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// ptpd API Header Files
+//
+//*****************************************************************************
+#include "ptpd-1.1.0/src/ptpd.h"
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __PTPDLIB_H__
diff --git a/utils/random.c b/utils/random.c
new file mode 100644
index 0000000..0588c44
--- /dev/null
+++ b/utils/random.c
@@ -0,0 +1,169 @@
+//*****************************************************************************
+//
+// random.c - Random number generator utilizing MD4 hash function of
+// environmental noise captured as the seed and a linear congruence
+// generator for the random numbers.
+//
+// Copyright (c) 2011-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "ustdlib.h"
+#include "random.h"
+
+//*****************************************************************************
+//
+//! \addtogroup random_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The pool of entropy that has been collected.
+//
+//*****************************************************************************
+static uint32_t g_pui32RandomEntropy[16];
+
+//*****************************************************************************
+//
+// The index of the next byte to be added to the entropy pool.
+//
+//*****************************************************************************
+static uint32_t g_ui32RandomIndex = 0;
+
+//*****************************************************************************
+//
+//! Add entropy to the pool.
+//!
+//! \param ui32Entropy is an 8-bit value that is added to the entropy pool
+//!
+//! This function allows the user application code to add entropy (random data)
+//! to the pool at any time.
+//!
+//! \return None
+//
+//*****************************************************************************
+void
+RandomAddEntropy(uint32_t ui32Entropy)
+{
+ //
+ // Add this byte to the entropy pool.
+ //
+ ((uint8_t *)g_pui32RandomEntropy)[g_ui32RandomIndex] = ui32Entropy & 0xff;
+
+ //
+ // Increment to the next byte of the entropy pool.
+ //
+ g_ui32RandomIndex = (g_ui32RandomIndex + 1) & 63;
+}
+
+//*****************************************************************************
+//
+//! Set the random number generator seed.
+//!
+//! Seed the random number generator by running a MD4 hash on the entropy pool.
+//! Note that the entropy pool may change from beneath us, but for the purposes
+//! of generating random numbers that is not a concern. Also, the MD4 hash was
+//! broken long ago, but since it is being used to generate random numbers
+//! instead of providing security this is not a concern.
+//!
+//! \return New seed value.
+//
+//*****************************************************************************
+uint32_t
+RandomSeed(void)
+{
+ uint32_t ui32A, ui32B, ui32C, ui32D, ui32Temp, ui32Idx;
+
+ //
+ // Initialize the digest.
+ //
+ ui32A = 0x67452301;
+ ui32B = 0xefcdab89;
+ ui32C = 0x98badcfe;
+ ui32D = 0x10325476;
+
+ //
+ // Perform the first round of operations.
+ //
+#define F(a, b, c, d, k, s) \
+ { \
+ ui32Temp = a + (d ^ (b & (c ^ d))) + g_pui32RandomEntropy[k]; \
+ a = (ui32Temp << s) | (ui32Temp >> (32 - s)); \
+ }
+ for(ui32Idx = 0; ui32Idx < 16; ui32Idx += 4)
+ {
+ F(ui32A, ui32B, ui32C, ui32D, ui32Idx + 0, 3);
+ F(ui32D, ui32A, ui32B, ui32C, ui32Idx + 1, 7);
+ F(ui32C, ui32D, ui32A, ui32B, ui32Idx + 2, 11);
+ F(ui32B, ui32C, ui32D, ui32A, ui32Idx + 3, 19);
+ }
+
+ //
+ // Perform the second round of operations.
+ //
+#define G(a, b, c, d, k, s) \
+ { \
+ ui32Temp = (a + ((b & c) | (b & d) | (c & d)) + \
+ g_pui32RandomEntropy[k] + 0x5a827999); \
+ a = (ui32Temp << s) | (ui32Temp >> (32 - s)); \
+ }
+ for(ui32Idx = 0; ui32Idx < 4; ui32Idx++)
+ {
+ G(ui32A, ui32B, ui32C, ui32D, ui32Idx + 0, 3);
+ G(ui32D, ui32A, ui32B, ui32C, ui32Idx + 4, 5);
+ G(ui32C, ui32D, ui32A, ui32B, ui32Idx + 8, 9);
+ G(ui32B, ui32C, ui32D, ui32A, ui32Idx + 12, 13);
+ }
+
+ //
+ // Perform the third round of operations.
+ //
+#define H(a, b, c, d, k, s) \
+ { \
+ ui32Temp = a + (b ^ c ^ d) + g_pui32RandomEntropy[k] + 0x6ed9eba1; \
+ a = (ui32Temp << s) | (ui32Temp >> (32 - s)); \
+ }
+ for(ui32Idx = 0; ui32Idx < 4; ui32Idx += 2)
+ {
+ H(ui32A, ui32B, ui32C, ui32D, ui32Idx + 0, 3);
+ H(ui32D, ui32A, ui32B, ui32C, ui32Idx + 8, 9);
+ H(ui32C, ui32D, ui32A, ui32B, ui32Idx + 4, 11);
+ H(ui32B, ui32C, ui32D, ui32A, ui32Idx + 12, 15);
+
+ if(ui32Idx == 2)
+ {
+ ui32Idx -= 3;
+ }
+ }
+
+ //
+ // Use the first word of the resulting digest as the random number seed.
+ //
+ return(ui32A + 0x67452301);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/random.h b/utils/random.h
new file mode 100644
index 0000000..a2c719e
--- /dev/null
+++ b/utils/random.h
@@ -0,0 +1,56 @@
+//*****************************************************************************
+//
+// random.h - Header for random number generation functions.
+//
+// Copyright (c) 2011-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __RANDOM_H__
+#define __RANDOM_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototypes for the random number generator functions.
+//
+//*****************************************************************************
+extern void RandomAddEntropy(uint32_t ui32Entropy);
+extern uint32_t RandomSeed(void);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __RANDOM_H__
diff --git a/utils/ringbuf.c b/utils/ringbuf.c
new file mode 100644
index 0000000..f489239
--- /dev/null
+++ b/utils/ringbuf.c
@@ -0,0 +1,712 @@
+//*****************************************************************************
+//
+// ringbuf.c - Ring buffer management utilities.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "utils/ringbuf.h"
+
+//*****************************************************************************
+//
+//! \addtogroup ringbuf_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Define NULL, if not already defined.
+//
+//*****************************************************************************
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+//*****************************************************************************
+//
+// Change the value of a variable atomically.
+//
+// \param pui32Val points to the index whose value is to be modified.
+// \param ui32Delta is the number of bytes to increment the index by.
+// \param ui32Size is the size of the buffer the index refers to.
+//
+// This function is used to increment a read or write buffer index that may be
+// written in various different contexts. It ensures that the
+// read/modify/write sequence is not interrupted and, hence, guards against
+// corruption of the variable. The new value is adjusted for buffer wrap.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+UpdateIndexAtomic(volatile uint32_t *pui32Val, uint32_t ui32Delta,
+ uint32_t ui32Size)
+{
+ bool bIntsOff;
+
+ //
+ // Turn interrupts off temporarily.
+ //
+ bIntsOff = IntMasterDisable();
+
+ //
+ // Update the variable value.
+ //
+ *pui32Val += ui32Delta;
+
+ //
+ // Correct for wrap. We use a loop here since we don't want to use a
+ // modulus operation with interrupts off but we don't want to fail in
+ // case ui32Delta is greater than ui32Size (which is extremely unlikely
+ // but...)
+ //
+ while(*pui32Val >= ui32Size)
+ {
+ *pui32Val -= ui32Size;
+ }
+
+ //
+ // Restore the interrupt state
+ //
+ if(!bIntsOff)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether the ring buffer whose pointers and size are provided
+//! is full or not.
+//!
+//! \param psRingBuf is the ring buffer object to empty.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! full. The structure 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.
+//
+//*****************************************************************************
+bool
+RingBufFull(tRingBufObject *psRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psRingBuf->ui32WriteIndex;
+ ui32Read = psRingBuf->ui32ReadIndex;
+
+ //
+ // Return the full status of the buffer.
+ //
+ return((((ui32Write + 1) % psRingBuf->ui32Size) == ui32Read) ? true :
+ false);
+}
+
+//*****************************************************************************
+//
+//! Determines whether the ring buffer whose pointers and size are provided
+//! is empty or not.
+//!
+//! \param psRingBuf is the ring buffer object to empty.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! empty. The structure 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.
+//
+//*****************************************************************************
+bool
+RingBufEmpty(tRingBufObject *psRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psRingBuf->ui32WriteIndex;
+ ui32Read = psRingBuf->ui32ReadIndex;
+
+ //
+ // Return the empty status of the buffer.
+ //
+ return((ui32Write == ui32Read) ? true : false);
+}
+
+//*****************************************************************************
+//
+//! Empties the ring buffer.
+//!
+//! \param psRingBuf is the ring buffer object to empty.
+//!
+//! Discards all data from the ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufFlush(tRingBufObject *psRingBuf)
+{
+ bool bIntsOff;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Set the Read/Write pointers to be the same. Do this with interrupts
+ // disabled to prevent the possibility of corruption of the read index.
+ //
+ bIntsOff = IntMasterDisable();
+ psRingBuf->ui32ReadIndex = psRingBuf->ui32WriteIndex;
+ if(!bIntsOff)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+//! Returns number of bytes stored in ring buffer.
+//!
+//! \param psRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of bytes stored in the ring buffer.
+//!
+//! \return Returns the number of bytes stored in the ring buffer.
+//
+//*****************************************************************************
+uint32_t
+RingBufUsed(tRingBufObject *psRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psRingBuf->ui32WriteIndex;
+ ui32Read = psRingBuf->ui32ReadIndex;
+
+ //
+ // Return the number of bytes contained in the ring buffer.
+ //
+ return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
+ (psRingBuf->ui32Size - (ui32Read - ui32Write)));
+}
+
+//*****************************************************************************
+//
+//! Returns number of bytes available in a ring buffer.
+//!
+//! \param psRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of bytes available in the ring buffer.
+//!
+//! \return Returns the number of bytes available in the ring buffer.
+//
+//*****************************************************************************
+uint32_t
+RingBufFree(tRingBufObject *psRingBuf)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Return the number of bytes available in the ring buffer.
+ //
+ return((psRingBuf->ui32Size - 1) - RingBufUsed(psRingBuf));
+}
+
+//*****************************************************************************
+//
+//! Returns number of contiguous bytes of data stored in ring buffer ahead of
+//! the current read pointer.
+//!
+//! \param psRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of contiguous bytes of data available in
+//! the ring buffer ahead of the current read pointer. This represents the
+//! largest block of data which does not straddle the buffer wrap.
+//!
+//! \return Returns the number of contiguous bytes available.
+//
+//*****************************************************************************
+uint32_t
+RingBufContigUsed(tRingBufObject *psRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psRingBuf->ui32WriteIndex;
+ ui32Read = psRingBuf->ui32ReadIndex;
+
+ //
+ // Return the number of contiguous bytes available.
+ //
+ return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
+ (psRingBuf->ui32Size - ui32Read));
+}
+
+//*****************************************************************************
+//
+//! Returns number of contiguous free bytes available in a ring buffer.
+//!
+//! \param psRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of contiguous free bytes ahead of the
+//! current write pointer in the ring buffer.
+//!
+//! \return Returns the number of contiguous bytes available in the ring
+//! buffer.
+//
+//*****************************************************************************
+uint32_t
+RingBufContigFree(tRingBufObject *psRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psRingBuf->ui32WriteIndex;
+ ui32Read = psRingBuf->ui32ReadIndex;
+
+ //
+ // Return the number of contiguous bytes available.
+ //
+ if(ui32Read > ui32Write)
+ {
+ //
+ // The read pointer is above the write pointer so the amount of free
+ // space is the difference between the two indices minus 1 to account
+ // for the buffer full condition (write index one behind read index).
+ //
+ return((ui32Read - ui32Write) - 1);
+ }
+ else
+ {
+ //
+ // If the write pointer is above the read pointer, the amount of free
+ // space is the size of the buffer minus the write index. We need to
+ // add a special-case adjustment if the read index is 0 since we need
+ // to leave 1 byte empty to ensure we can tell the difference between
+ // the buffer being full and empty.
+ //
+ return(psRingBuf->ui32Size - ui32Write - ((ui32Read == 0) ? 1 : 0));
+ }
+}
+
+//*****************************************************************************
+//
+//! Return size in bytes of a ring buffer.
+//!
+//! \param psRingBuf is the ring buffer object to check.
+//!
+//! This function returns the size of the ring buffer.
+//!
+//! \return Returns the size in bytes of the ring buffer.
+//
+//*****************************************************************************
+uint32_t
+RingBufSize(tRingBufObject *psRingBuf)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Return the number of bytes available in the ring buffer.
+ //
+ return(psRingBuf->ui32Size);
+}
+
+//*****************************************************************************
+//
+//! Reads a single byte of data from a ring buffer.
+//!
+//! \param psRingBuf points to the ring buffer to be written to.
+//!
+//! This function reads a single byte of data from a ring buffer.
+//!
+//! \return The byte read from the ring buffer.
+//
+//*****************************************************************************
+uint8_t
+RingBufReadOne(tRingBufObject *psRingBuf)
+{
+ uint8_t ui8Temp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(RingBufUsed(psRingBuf) != 0);
+
+ //
+ // Write the data byte.
+ //
+ ui8Temp = psRingBuf->pui8Buf[psRingBuf->ui32ReadIndex];
+
+ //
+ // Increment the read index.
+ //
+ UpdateIndexAtomic(&psRingBuf->ui32ReadIndex, 1, psRingBuf->ui32Size);
+
+ //
+ // Return the character read.
+ //
+ return(ui8Temp);
+}
+
+//*****************************************************************************
+//
+//! Reads data from a ring buffer.
+//!
+//! \param psRingBuf points to the ring buffer to be read from.
+//! \param pui8Data points to where the data should be stored.
+//! \param ui32Length is the number of bytes to be read.
+//!
+//! This function reads a sequence of bytes from a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufRead(tRingBufObject *psRingBuf, uint8_t *pui8Data, uint32_t ui32Length)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+ ASSERT(pui8Data != NULL);
+ ASSERT(ui32Length != 0);
+
+ //
+ // Verify that data is available in the buffer.
+ //
+ ASSERT(ui32Length <= RingBufUsed(psRingBuf));
+
+ //
+ // Read the data from the ring buffer.
+ //
+ for(ui32Temp = 0; ui32Temp < ui32Length; ui32Temp++)
+ {
+ pui8Data[ui32Temp] = RingBufReadOne(psRingBuf);
+ }
+}
+
+//*****************************************************************************
+//
+//! Remove bytes from the ring buffer by advancing the read index.
+//!
+//! \param psRingBuf points to the ring buffer from which bytes are to be
+//! removed.
+//! \param ui32NumBytes is the number of bytes to be removed from the buffer.
+//!
+//! This function advances the ring buffer read index by a given number of
+//! bytes, removing that number of bytes of data from the buffer. If
+//! \e ui32NumBytes is larger than the number of bytes currently in the buffer,
+//! the buffer is emptied.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufAdvanceRead(tRingBufObject *psRingBuf, uint32_t ui32NumBytes)
+{
+ uint32_t ui32Count;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Make sure that we are not being asked to remove more data than is
+ // there to be removed.
+ //
+ ui32Count = RingBufUsed(psRingBuf);
+ ui32Count = (ui32Count < ui32NumBytes) ? ui32Count : ui32NumBytes;
+
+ //
+ // Advance the buffer read index by the required number of bytes.
+ //
+ UpdateIndexAtomic(&psRingBuf->ui32ReadIndex, ui32Count,
+ psRingBuf->ui32Size);
+}
+
+//*****************************************************************************
+//
+//! Add bytes to the ring buffer by advancing the write index.
+//!
+//! \param psRingBuf points to the ring buffer to which bytes have been added.
+//! \param ui32NumBytes is the number of bytes added to the buffer.
+//!
+//! This function should be used by clients who wish to add data to the buffer
+//! directly rather than via calls to RingBufWrite() or RingBufWriteOne(). It
+//! advances the write index by a given number of bytes. If the
+//! \e ui32NumBytes parameter is larger than the amount of free space in the
+//! buffer, the read pointer will be advanced to cater for the addition. Note
+//! that this will result in some of the oldest data in the buffer being
+//! discarded.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufAdvanceWrite(tRingBufObject *psRingBuf,
+ uint32_t ui32NumBytes)
+{
+ uint32_t ui32Count;
+ bool bIntsOff;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Make sure we were not asked to add a silly number of bytes.
+ //
+ ASSERT(ui32NumBytes <= psRingBuf->ui32Size);
+
+ //
+ // Determine how much free space we currently think the buffer has.
+ //
+ ui32Count = RingBufFree(psRingBuf);
+
+ //
+ // Advance the buffer write index by the required number of bytes and
+ // check that we have not run past the read index. Note that we must do
+ // this within a critical section (interrupts disabled) to prevent
+ // race conditions that could corrupt one or other of the indices.
+ //
+ bIntsOff = IntMasterDisable();
+
+ //
+ // Update the write pointer.
+ //
+ psRingBuf->ui32WriteIndex += ui32NumBytes;
+
+ //
+ // Check and correct for wrap.
+ //
+ if(psRingBuf->ui32WriteIndex >= psRingBuf->ui32Size)
+ {
+ psRingBuf->ui32WriteIndex -= psRingBuf->ui32Size;
+ }
+
+ //
+ // Did the client add more bytes than the buffer had free space for?
+ //
+ if(ui32Count < ui32NumBytes)
+ {
+ //
+ // Yes - we need to advance the read pointer to ahead of the write
+ // pointer to discard some of the oldest data.
+ //
+ psRingBuf->ui32ReadIndex = psRingBuf->ui32WriteIndex + 1;
+
+ //
+ // Correct for buffer wrap if necessary.
+ //
+ if(psRingBuf->ui32ReadIndex >= psRingBuf->ui32Size)
+ {
+ psRingBuf->ui32ReadIndex -= psRingBuf->ui32Size;
+ }
+ }
+
+ //
+ // Restore interrupts if we turned them off earlier.
+ //
+ if(!bIntsOff)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+//! Writes a single byte of data to a ring buffer.
+//!
+//! \param psRingBuf points to the ring buffer to be written to.
+//! \param ui8Data is the byte to be written.
+//!
+//! This function writes a single byte of data into a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufWriteOne(tRingBufObject *psRingBuf, uint8_t ui8Data)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(RingBufFree(psRingBuf) != 0);
+
+ //
+ // Write the data byte.
+ //
+ psRingBuf->pui8Buf[psRingBuf->ui32WriteIndex] = ui8Data;
+
+ //
+ // Increment the write index.
+ //
+ UpdateIndexAtomic(&psRingBuf->ui32WriteIndex, 1, psRingBuf->ui32Size);
+}
+
+//*****************************************************************************
+//
+//! Writes data to a ring buffer.
+//!
+//! \param psRingBuf points to the ring buffer to be written to.
+//! \param pui8Data points to the data to be written.
+//! \param ui32Length is the number of bytes to be written.
+//!
+//! This function write a sequence of bytes into a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufWrite(tRingBufObject *psRingBuf, uint8_t *pui8Data,
+ uint32_t ui32Length)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+ ASSERT(pui8Data != NULL);
+ ASSERT(ui32Length != 0);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(ui32Length <= RingBufFree(psRingBuf));
+
+ //
+ // Write the data into the ring buffer.
+ //
+ for(ui32Temp = 0; ui32Temp < ui32Length; ui32Temp++)
+ {
+ RingBufWriteOne(psRingBuf, pui8Data[ui32Temp]);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initialize a ring buffer object.
+//!
+//! \param psRingBuf points to the ring buffer to be initialized.
+//! \param pui8Buf points to the data buffer to be used for the ring buffer.
+//! \param ui32Size is the size of the buffer in bytes.
+//!
+//! This function initializes a ring buffer object, preparing it to store data.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufInit(tRingBufObject *psRingBuf, uint8_t *pui8Buf,
+ uint32_t ui32Size)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+ ASSERT(pui8Buf != NULL);
+ ASSERT(ui32Size != 0);
+
+ //
+ // Initialize the ring buffer object.
+ //
+ psRingBuf->ui32Size = ui32Size;
+ psRingBuf->pui8Buf = pui8Buf;
+ psRingBuf->ui32WriteIndex = psRingBuf->ui32ReadIndex = 0;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/ringbuf.h b/utils/ringbuf.h
new file mode 100644
index 0000000..9b1ff56
--- /dev/null
+++ b/utils/ringbuf.h
@@ -0,0 +1,105 @@
+//*****************************************************************************
+//
+// ringbuf.h - Defines and Macros for the ring buffer utilities.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __RINGBUF_H__
+#define __RINGBUF_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure used for encapsulating all the items associated with a
+// ring buffer.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The ring buffer size.
+ //
+ uint32_t ui32Size;
+
+ //
+ // The ring buffer write index.
+ //
+ volatile uint32_t ui32WriteIndex;
+
+ //
+ // The ring buffer read index.
+ //
+ volatile uint32_t ui32ReadIndex;
+
+ //
+ // The ring buffer.
+ //
+ uint8_t *pui8Buf;
+
+}
+tRingBufObject;
+
+//*****************************************************************************
+//
+// API Function prototypes
+//
+//*****************************************************************************
+extern bool RingBufFull(tRingBufObject *psRingBuf);
+extern bool RingBufEmpty(tRingBufObject *psRingBuf);
+extern void RingBufFlush(tRingBufObject *psRingBuf);
+extern uint32_t RingBufUsed(tRingBufObject *psRingBuf);
+extern uint32_t RingBufFree(tRingBufObject *psRingBuf);
+extern uint32_t RingBufContigUsed(tRingBufObject *psRingBuf);
+extern uint32_t RingBufContigFree(tRingBufObject *psRingBuf);
+extern uint32_t RingBufSize(tRingBufObject *psRingBuf);
+extern uint8_t RingBufReadOne(tRingBufObject *psRingBuf);
+extern void RingBufRead(tRingBufObject *psRingBuf, uint8_t *pui8Data,
+ uint32_t ui32Length);
+extern void RingBufWriteOne(tRingBufObject *psRingBuf, uint8_t ui8Data);
+extern void RingBufWrite(tRingBufObject *psRingBuf, uint8_t *pui8Data,
+ uint32_t ui32Length);
+extern void RingBufAdvanceWrite(tRingBufObject *psRingBuf,
+ uint32_t ui32NumBytes);
+extern void RingBufAdvanceRead(tRingBufObject *psRingBuf,
+ uint32_t ui32NumBytes);
+extern void RingBufInit(tRingBufObject *psRingBuf, uint8_t *pui8Buf,
+ uint32_t ui32Size);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __RINGBUF_H__
diff --git a/utils/scheduler.c b/utils/scheduler.c
new file mode 100644
index 0000000..bb66c4e
--- /dev/null
+++ b/utils/scheduler.c
@@ -0,0 +1,310 @@
+//*****************************************************************************
+//
+// scheduler.c - A simple task scheduler
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "inc/hw_ints.h"
+#include "driverlib/systick.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/debug.h"
+#include "utils/scheduler.h"
+
+//*****************************************************************************
+//
+//! \addtogroup scheduler_api
+//! @{
+//
+//*****************************************************************************
+
+static volatile uint32_t g_ui32SchedulerTickCount;
+
+//*****************************************************************************
+//
+//! Handles the SysTick interrupt on behalf of the scheduler module.
+//!
+//! Applications using the scheduler module must ensure that this function is
+//! hooked to the SysTick interrupt vector.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SchedulerSysTickIntHandler(void)
+{
+ g_ui32SchedulerTickCount++;
+}
+
+//*****************************************************************************
+//
+//! Initializes the task scheduler.
+//!
+//! \param ui32TicksPerSecond sets the basic frequency of the SysTick interrupt
+//! used by the scheduler to determine when to run the various task functions.
+//!
+//! This function must be called during application startup to configure the
+//! SysTick timer. This is used by the scheduler module to determine when each
+//! of the functions provided in the g_psSchedulerTable array is called.
+//!
+//! The caller is responsible for ensuring that SchedulerSysTickIntHandler()
+//! has previously been installed in the SYSTICK vector in the vector table
+//! and must also ensure that interrupts are enabled at the CPU level.
+//!
+//! Note that this call does not start the scheduler calling the configured
+//! functions. All function calls are made in the context of later calls to
+//! SchedulerRun(). This call merely configures the SysTick interrupt that is
+//! used by the scheduler to determine what the current system time is.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SchedulerInit(uint32_t ui32TicksPerSecond)
+{
+ ASSERT(ui32TicksPerSecond);
+
+ //
+ // Configure SysTick for a periodic interrupt.
+ //
+ SysTickPeriodSet(SysCtlClockGet() / ui32TicksPerSecond);
+ SysTickEnable();
+ SysTickIntEnable();
+}
+
+//*****************************************************************************
+//
+//! Instructs the scheduler to update its task table and make calls to
+//! functions needing called.
+//!
+//! This function must be called periodically by the client to allow the
+//! scheduler to make calls to any configured task functions if it is their
+//! time to be called. The call must be made at least as frequently as the
+//! most frequent task configured in the g_psSchedulerTable array.
+//!
+//! Although the scheduler makes use of the SysTick interrupt, all calls to
+//! functions configured in \e g_psSchedulerTable are made in the context of
+//! SchedulerRun().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SchedulerRun(void)
+{
+ uint32_t ui32Loop;
+ tSchedulerTask *pi16Task;
+
+ //
+ // Loop through each task in the task table.
+ //
+ for(ui32Loop = 0; ui32Loop < g_ui32SchedulerNumTasks; ui32Loop++)
+ {
+ //
+ // Get a pointer to the task information.
+ //
+ pi16Task = &g_psSchedulerTable[ui32Loop];
+
+ //
+ // Is this task active and, if so, is it time to call it's function?
+ //
+ if(pi16Task->bActive &&
+ (SchedulerElapsedTicksGet(pi16Task->ui32LastCall) >=
+ pi16Task->ui32FrequencyTicks))
+ {
+ //
+ // Remember the timestamp at which we make the function call.
+ //
+ pi16Task->ui32LastCall = g_ui32SchedulerTickCount;
+
+ //
+ // Call the task function, passing the provided parameter.
+ //
+ pi16Task->pfnFunction(pi16Task->pvParam);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Enables a task and allows the scheduler to call it periodically.
+//!
+//! \param ui32Index is the index of the task which is to be enabled in the
+//! global \e g_psSchedulerTable array.
+//! \param bRunNow is \b true if the task is to be run on the next call to
+//! SchedulerRun() or \b false if one whole period is to elapse before the task
+//! is run.
+//!
+//! This function marks one of the configured tasks as enabled and causes
+//! SchedulerRun() to call that task periodically. The caller may choose to
+//! have the enabled task run for the first time on the next call to
+//! SchedulerRun() or to wait one full task period before making the first
+//! call.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SchedulerTaskEnable(uint32_t ui32Index, bool bRunNow)
+{
+ //
+ // Is the task index passed valid?
+ //
+ if(ui32Index < g_ui32SchedulerNumTasks)
+ {
+ //
+ // Yes - mark the task as active.
+ //
+ g_psSchedulerTable[ui32Index].bActive = true;
+
+ //
+ // Set the last call time to ensure that the function is called either
+ // next time the scheduler is run or after the desired number of ticks
+ // depending upon the value of the bRunNow parameter.
+ //
+ if(bRunNow)
+ {
+ //
+ // Cause the task to run on the next call to SchedulerRun().
+ //
+ g_psSchedulerTable[ui32Index].ui32LastCall =
+ (g_ui32SchedulerTickCount -
+ g_psSchedulerTable[ui32Index].ui32FrequencyTicks);
+ }
+ else
+ {
+ //
+ // Cause the task to run after one full time period.
+ //
+ g_psSchedulerTable[ui32Index].ui32LastCall =
+ g_ui32SchedulerTickCount;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Disables a task and prevents the scheduler from calling it.
+//!
+//! \param ui32Index is the index of the task which is to be disabled in the
+//! global \e g_psSchedulerTable array.
+//!
+//! This function marks one of the configured tasks as inactive and prevents
+//! SchedulerRun() from calling it. The task may be reenabled by calling
+//! SchedulerTaskEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SchedulerTaskDisable(uint32_t ui32Index)
+{
+ //
+ // Is the task index passed valid?
+ //
+ if(ui32Index < g_ui32SchedulerNumTasks)
+ {
+ //
+ // Yes - mark the task as inactive.
+ //
+ g_psSchedulerTable[ui32Index].bActive = false;
+ }
+}
+
+//*****************************************************************************
+//
+//! Returns the current system time in ticks since power on.
+//!
+//! This function may be called by a client to retrieve the current system
+//! time. The value returned is a count of ticks elapsed since the system
+//! last booted.
+//!
+//! \return Tick count since last boot.
+//
+//*****************************************************************************
+uint32_t
+SchedulerTickCountGet(void)
+{
+ return(g_ui32SchedulerTickCount);
+}
+
+//*****************************************************************************
+//
+//! Returns the number of ticks elapsed since the provided tick count.
+//!
+//! \param ui32TickCount is the tick count from which to determine the elapsed
+//! time.
+//!
+//! This function may be called by a client to determine how much time has
+//! passed since a particular tick count provided in the \e ui32TickCount
+//! parameter. This function takes into account wrapping of the global tick
+//! counter and assumes that the provided tick count always represents a time
+//! in the past. The returned value will, of course, be wrong if the tick
+//! counter has wrapped more than once since the passed \e ui32TickCount. As a
+//! result, please do not use this function if you are dealing with timeouts
+//! of 497 days or longer (assuming you use a 10mS tick period).
+//!
+//! \return The number of ticks elapsed since the provided tick count.
+//
+//*****************************************************************************
+uint32_t
+SchedulerElapsedTicksGet(uint32_t ui32TickCount)
+{
+ //
+ // Determine the calculation based upon whether the global tick count has
+ // wrapped since the passed ui32TickCount.
+ //
+ return(SchedulerElapsedTicksCalc(ui32TickCount, g_ui32SchedulerTickCount));
+}
+
+//*****************************************************************************
+//
+//! Returns the number of ticks elapsed between two times.
+//!
+//! \param ui32TickStart is the system tick count for the start of the period.
+//! \param ui32TickEnd is the system tick count for the end of the period.
+//!
+//! This function may be called by a client to determine the number of ticks
+//! which have elapsed between provided starting and ending tick counts. The
+//! function takes into account wrapping cases where the end tick count is
+//! lower than the starting count assuming that the ending tick count always
+//! represents a later time than the starting count.
+//!
+//! \return The number of ticks elapsed between the provided start and end
+//! counts.
+//
+//*****************************************************************************
+uint32_t
+SchedulerElapsedTicksCalc(uint32_t ui32TickStart, uint32_t ui32TickEnd)
+{
+ return((ui32TickEnd > ui32TickStart) ? (ui32TickEnd - ui32TickStart) :
+ ((0xFFFFFFFF - ui32TickStart) + ui32TickEnd + 1));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/scheduler.h b/utils/scheduler.h
new file mode 100644
index 0000000..79ae1e2
--- /dev/null
+++ b/utils/scheduler.h
@@ -0,0 +1,140 @@
+//*****************************************************************************
+//
+// scheduler.h - Public header for the simple timed function scheduler module.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+#ifndef __SCHEDULER_H__
+#define __SCHEDULER_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup scheduler_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototype of a function that the scheduler can call periodically.
+//
+//*****************************************************************************
+typedef void (*tSchedulerFunction)(void *pvParam);
+
+//*****************************************************************************
+//
+//! The structure defining a function which the scheduler will call
+//! periodically.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! A pointer to the function which is to be called periodically by the
+ //! scheduler.
+ //
+ void (*pfnFunction)(void *);
+
+ //
+ //! The parameter which is to be passed to this function when it is called.
+ //
+ void *pvParam;
+
+ //
+ //! The frequency the function is to be called expressed in terms of system
+ //! ticks. If this value is 0, the function will be called on every call
+ //! to SchedulerRun.
+ //
+ uint32_t ui32FrequencyTicks;
+
+ //
+ //! Tick count when this function was last called. This field is updated
+ //! by the scheduler.
+ //
+ uint32_t ui32LastCall;
+
+ //
+ //! A flag indicating whether or not this task is active. If true, the
+ //! function will be called periodically. If false, the function is
+ //! disabled and will not be called.
+ //
+ bool bActive;
+}
+tSchedulerTask;
+
+//*****************************************************************************
+//
+//! This global table must be populated by the client and contains information
+//! on each function that the scheduler is to call.
+//
+//*****************************************************************************
+extern tSchedulerTask g_psSchedulerTable[];
+
+//*****************************************************************************
+//
+//! This global variable must be exported by the client. It must contain the
+//! number of entries in the g_psSchedulerTable array.
+//
+//*****************************************************************************
+extern uint32_t g_ui32SchedulerNumTasks;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public function prototypes
+//
+//*****************************************************************************
+extern void SchedulerSysTickIntHandler(void);
+extern void SchedulerInit(uint32_t ui32TicksPerSecond);
+extern void SchedulerRun(void);
+extern void SchedulerTaskEnable(uint32_t ui32Index, bool bRunNow);
+extern void SchedulerTaskDisable(uint32_t ui32Index);
+extern uint32_t SchedulerTickCountGet(void);
+extern uint32_t SchedulerElapsedTicksGet(uint32_t ui32TickCount);
+extern uint32_t SchedulerElapsedTicksCalc(uint32_t ui32TickStart,
+ uint32_t ui32TickEnd);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ SCHEDULER_H_
diff --git a/utils/sine.c b/utils/sine.c
new file mode 100644
index 0000000..52cd222
--- /dev/null
+++ b/utils/sine.c
@@ -0,0 +1,126 @@
+//*****************************************************************************
+//
+// sine.c - Fixed point sine trigonometric function.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "utils/sine.h"
+
+//*****************************************************************************
+//
+//! \addtogroup sine_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// A table of the value of the sine function for the first ninety degrees with
+// 129 entries (that is, [0] = 0 degrees, [128] = 90 degrees). Each entry is
+// in 0.16 fixed point notation.
+//
+//*****************************************************************************
+static const uint16_t g_pui16FixedSineTable[] =
+{
+ 0x0000, 0x0324, 0x0648, 0x096C, 0x0C8F, 0x0FB2, 0x12D5, 0x15F6, 0x1917,
+ 0x1C37, 0x1F56, 0x2273, 0x2590, 0x28AA, 0x2BC4, 0x2EDB, 0x31F1, 0x3505,
+ 0x3817, 0x3B26, 0x3E33, 0x413E, 0x4447, 0x474D, 0x4A50, 0x4D50, 0x504D,
+ 0x5347, 0x563E, 0x5931, 0x5C22, 0x5F0E, 0x61F7, 0x64DC, 0x67BD, 0x6A9B,
+ 0x6D74, 0x7049, 0x7319, 0x75E5, 0x78AD, 0x7B70, 0x7E2E, 0x80E7, 0x839C,
+ 0x864B, 0x88F5, 0x8B9A, 0x8E39, 0x90D3, 0x9368, 0x95F6, 0x987F, 0x9B02,
+ 0x9D7F, 0x9FF6, 0xA267, 0xA4D2, 0xA736, 0xA994, 0xABEB, 0xAE3B, 0xB085,
+ 0xB2C8, 0xB504, 0xB73A, 0xB968, 0xBB8F, 0xBDAE, 0xBFC7, 0xC1D8, 0xC3E2,
+ 0xC5E4, 0xC7DE, 0xC9D1, 0xCBBB, 0xCD9F, 0xCF7A, 0xD14D, 0xD318, 0xD4DB,
+ 0xD695, 0xD848, 0xD9F2, 0xDB94, 0xDD2D, 0xDEBE, 0xE046, 0xE1C5, 0xE33C,
+ 0xE4AA, 0xE60F, 0xE76B, 0xE8BF, 0xEA09, 0xEB4B, 0xEC83, 0xEDB2, 0xEED8,
+ 0xEFF5, 0xF109, 0xF213, 0xF314, 0xF40B, 0xF4FA, 0xF5DE, 0xF6BA, 0xF78B,
+ 0xF853, 0xF912, 0xF9C7, 0xFA73, 0xFB14, 0xFBAC, 0xFC3B, 0xFCBF, 0xFD3A,
+ 0xFDAB, 0xFE13, 0xFE70, 0xFEC4, 0xFF0E, 0xFF4E, 0xFF84, 0xFFB1, 0xFFD3,
+ 0xFFEC, 0xFFFB, 0xFFFF
+};
+
+//*****************************************************************************
+//
+//! Computes an approximation of the sine of the input angle.
+//!
+//! \param ui32Angle is an angle expressed as a 0.32 fixed-point value that is
+//! the percentage of the way around a circle.
+//!
+//! This function computes the sine for the given input angle. The angle is
+//! specified in 0.32 fixed point format, and is therefore always between 0 and
+//! 360 degrees, inclusive of 0 and exclusive of 360.
+//!
+//! \return Returns the sine of the angle, in 16.16 fixed point format.
+//
+//*****************************************************************************
+int32_t
+sine(uint32_t ui32Angle)
+{
+ uint32_t ui32Idx;
+
+ //
+ // Add 0.5 to the angle. Since only the upper 9 bits are used to compute
+ // the sine value, adding one to the tenth bit is 0.5 from the point of
+ // view of the sine table.
+ //
+ ui32Angle += 0x00400000;
+
+ //
+ // Get the index into the sine table from bits 30:23.
+ //
+ ui32Idx = (ui32Angle >> 23) & 255;
+
+ //
+ // If bit 30 is set, the angle is between 90 and 180 or 270 and 360. In
+ // these cases, the sine value is decreasing from one instead of increasing
+ // from zero. The indexing into the table needs to be reversed.
+ //
+ if(ui32Angle & 0x40000000)
+ {
+ ui32Idx = 256 - ui32Idx;
+ }
+
+ //
+ // Get the value of the sine.
+ //
+ ui32Idx = g_pui16FixedSineTable[ui32Idx];
+
+ //
+ // If bit 31 is set, the angle is between 180 and 360. In this case, the
+ // sine value is negative; otherwise it is positive.
+ //
+ if(ui32Angle & 0x80000000)
+ {
+ return(0 - ui32Idx);
+ }
+ else
+ {
+ return(ui32Idx);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/sine.h b/utils/sine.h
new file mode 100644
index 0000000..c3f8c51
--- /dev/null
+++ b/utils/sine.h
@@ -0,0 +1,85 @@
+//*****************************************************************************
+//
+// sine.h - Prototypes for the fixed point sine trigonometric function.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SINE_H__
+#define __SINE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup sine_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Computes an approximation of the cosine of the input angle.
+//!
+//! \param ui32Angle is an angle expressed as a 0.32 fixed-point value that is
+//! the percentage of the way around a circle.
+//!
+//! This function computes the cosine for the given input angle. The angle is
+//! specified in 0.32 fixed point format, and is therefore always between 0 and
+//! 360 degrees, inclusive of 0 and exclusive of 360.
+//!
+//! \return Returns the cosine of the angle, in 16.16 fixed point format.
+//
+//*****************************************************************************
+#define cosine(ui32Angle) sine((ui32Angle) + 0x40000000)
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototype for the fixed point sine function.
+//
+//*****************************************************************************
+extern int32_t sine(uint32_t ui32Angle);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SINE_H__
diff --git a/utils/smbus.c b/utils/smbus.c
new file mode 100644
index 0000000..8ed9c3a
--- /dev/null
+++ b/utils/smbus.c
@@ -0,0 +1,5173 @@
+//*****************************************************************************
+//
+// smbus.c - SMBus protocol layer API.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_i2c.h"
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/i2c.h"
+#include "driverlib/sw_crc.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/udma.h"
+#include "utils/smbus.h"
+
+//*****************************************************************************
+//
+//! \addtogroup smbus_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states for the master and slave interrupt handler state machines.
+//
+//*****************************************************************************
+#define SMBUS_STATE_IDLE 0
+#define SMBUS_STATE_SLAVE_POST_COMMAND 1
+#define SMBUS_STATE_WRITE_BLOCK_SIZE 2
+#define SMBUS_STATE_WRITE_NEXT 3
+#define SMBUS_STATE_WRITE_FINAL 4
+#define SMBUS_STATE_WRITE_DONE 5
+#define SMBUS_STATE_READ_ONE 6
+#define SMBUS_STATE_READ_FIRST 7
+#define SMBUS_STATE_READ_BLOCK_SIZE 8
+#define SMBUS_STATE_READ_NEXT 9
+#define SMBUS_STATE_READ_FINAL 10
+#define SMBUS_STATE_READ_WAIT 11
+#define SMBUS_STATE_READ_PEC 12
+#define SMBUS_STATE_READ_DONE 13
+#define SMBUS_STATE_READ_ERROR_STOP 14
+
+//*****************************************************************************
+//
+// Status flags for various instance-specific tasks.
+//
+//*****************************************************************************
+#define FLAG_PEC 0
+#define FLAG_PROCESS_CALL 1
+#define FLAG_BLOCK_TRANSFER 2
+#define FLAG_TRANSFER_IN_PROGRESS 3
+#define FLAG_RAW_I2C 4
+#define FLAG_ADDRESS_RESOLVED 5
+#define FLAG_ADDRESS_VALID 6
+#define FLAG_ARP 7
+//*****************************************************************************
+//
+//! Enables Packet Error Checking (PEC).
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables the transmission and checking of a PEC byte in SMBus
+//! transactions.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusPECEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the PEC flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 1;
+}
+
+//*****************************************************************************
+//
+//! Disables Packet Error Checking (PEC).
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function disables the transmission and checking of a PEC byte in SMBus
+//! transactions.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusPECDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the PEC flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the ARP flag in the configuration structure.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sets the Address Resolution Protocol (ARP) flag in the
+//! configuration structure. This flag can be used to track the state of a
+//! device during the ARP process.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the ARP flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ARP) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the ARP flag in the configuration structure.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function clears the Address Resolution Protocol (ARP) flag in the
+//! configuration structure. This flag can be used to track the state of a
+//! device during the ARP process.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the ARP flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ARP) = 0;
+}
+
+//*****************************************************************************
+//
+//! Returns the number of bytes in the receive buffer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function returns the number of bytes in the active receive buffer.
+//! It can be used to determine how many bytes have been received in the slave
+//! receive or master block read configurations.
+//!
+//! \return Number of bytes in the buffer.
+//
+//*****************************************************************************
+uint8_t
+SMBusRxPacketSizeGet(tSMBus *psSMBus)
+{
+ //
+ // Return the number of bytes received.
+ //
+ return(psSMBus->ui8RxIndex);
+}
+
+//*****************************************************************************
+//
+//! Returns the state of an SMBus transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function returns the status of an SMBus transaction. It can be used
+//! to determine whether a transfer is ongoing or complete.
+//!
+//! \return Returns \b SMBUS_TRANSFER_IN_PROGRESS if transfer is ongoing, or
+//! \b SMBUS_TRANSFER_COMPLETE if transfer has completed.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusStatusGet(tSMBus *psSMBus)
+{
+ //
+ // Check to see if there is an ongoing transfer.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS))
+ {
+ //
+ // If the flag is set, return in progress status.
+ //
+ return(SMBUS_TRANSFER_IN_PROGRESS);
+ }
+
+ //
+ // If the transfer complete flag is cleared, transfer is done.
+ //
+ else
+ {
+ //
+ // If the flag isn't set, return complete status.
+ //
+ return(SMBUS_TRANSFER_COMPLETE);
+ }
+}
+
+//*****************************************************************************
+//
+//! Encodes a UDID structure and address into SMBus-transferable byte order.
+//!
+//! \param pUDID specifies the structure to encode.
+//! \param ui8Address specifies the address to send with the UDID (byte 17).
+//! \param pui8Data specifies the location of the destination data buffer.
+//!
+//! This function takes a tSMBusUDID structure and re-orders the bytes so that
+//! it can be transferred on the bus. The destination data buffer must contain
+//! at least 17 bytes.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPUDIDPacketEncode(tSMBusUDID *pUDID, uint8_t ui8Address,
+ uint8_t *pui8Data)
+{
+ //
+ // Place data from the UDID structure and address into the data buffer
+ // using the correct MSB->LSB + address order.
+ //
+ pui8Data[0] = pUDID->ui8DeviceCapabilities;
+ pui8Data[1] = pUDID->ui8Version;
+ pui8Data[2] = (uint8_t)((pUDID->ui16VendorID & 0xff00) >> 8);
+ pui8Data[3] = (uint8_t)(pUDID->ui16VendorID & 0x00ff);
+ pui8Data[4] = (uint8_t)((pUDID->ui16DeviceID & 0xff00) >> 8);
+ pui8Data[5] = (uint8_t)(pUDID->ui16DeviceID & 0x00ff);
+ pui8Data[6] = (uint8_t)((pUDID->ui16Interface & 0xff00) >> 8);
+ pui8Data[7] = (uint8_t)(pUDID->ui16Interface & 0x00ff);
+ pui8Data[8] = (uint8_t)((pUDID->ui16SubSystemVendorID & 0xff00) >> 8);
+ pui8Data[9] = (uint8_t)(pUDID->ui16SubSystemVendorID & 0x00ff);
+ pui8Data[10] = (uint8_t)((pUDID->ui16SubSystemDeviceID & 0xff00) >> 8);
+ pui8Data[11] = (uint8_t)(pUDID->ui16SubSystemDeviceID & 0x00ff);
+ pui8Data[12] = (uint8_t)((pUDID->ui32VendorSpecificID & 0xff000000) >>
+ 24);
+ pui8Data[13] = (uint8_t)((pUDID->ui32VendorSpecificID & 0x00ff0000) >>
+ 16);
+ pui8Data[14] = (uint8_t)((pUDID->ui32VendorSpecificID & 0x0000ff00) >>
+ 8);
+ pui8Data[15] = (uint8_t)(pUDID->ui32VendorSpecificID & 0x000000ff);
+ pui8Data[16] = ui8Address;
+}
+
+//*****************************************************************************
+//
+//! Decodes an SMBus packet into a UDID structure and address.
+//!
+//! \param pUDID specifies the structure that is updated with new data.
+//! \param pui8Address specifies the location of the variable that holds the
+//! the address sent with the UDID (byte 17).
+//! \param pui8Data specifies the location of the source data.
+//!
+//! This function takes a data buffer and decodes it into a tSMBusUDID
+//! structure and an address variable. It is assumed that there are 17 bytes
+//! in the data buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPUDIDPacketDecode(tSMBusUDID *pUDID, uint8_t *pui8Address,
+ uint8_t *pui8Data)
+{
+ //
+ // Populate the UDID structure with data from the input data buffer.
+ //
+ pUDID->ui8DeviceCapabilities = pui8Data[0];
+ pUDID->ui8Version = pui8Data[1];
+ pUDID->ui16VendorID = (uint16_t)((pui8Data[2] << 8) | pui8Data[3]);
+ pUDID->ui16DeviceID = (uint16_t)((pui8Data[4] << 8) | pui8Data[5]);
+ pUDID->ui16Interface = (uint16_t)((pui8Data[6] << 8) | pui8Data[7]);
+ pUDID->ui16SubSystemVendorID = (uint16_t)((pui8Data[8] << 8) |
+ pui8Data[9]);
+ pUDID->ui16SubSystemDeviceID = (uint16_t)((pui8Data[10] << 8) |
+ pui8Data[11]);
+ pUDID->ui32VendorSpecificID = (uint32_t)((pui8Data[12] << 24) |
+ (pui8Data[13] << 16) |
+ (pui8Data[14] << 8) |
+ pui8Data[15]);
+
+ //
+ // Populate the address.
+ //
+ *pui8Address = pui8Data[16];
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Quick Command transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param bData is the value of the single data bit sent to the slave.
+//!
+//! Quick Command is an SMBus protocol that sends a single data bit using the
+//! I2C R/S bit. This function issues a single I2C transfer with the slave
+//! address and data bit.
+//!
+//! This protocol does not support PEC. The PEC flag is explicitly cleared
+//! within this function, so if PEC is enabled prior to calling it, it must
+//! be re-enabled afterwards.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterQuickCommand(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ bool bData)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // This protocol does NOT support PEC, so the flag must be cleared. If
+ // PEC is needed again after this transaction, it should be explicitly
+ // enabled again.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, bData);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_QUICK_COMMAND);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Host Notify transfer to the SMBus Host.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8OwnSlaveAddress specifies the peripheral's own slave address.
+//! \param pui8Data is a pointer to the two byte data payload.
+//!
+//! The Host Notify protocol is used by SMBus slaves to alert the bus Host
+//! about an event. Most slave devices that operate in this environment only
+//! become a bus master when this packet type is used. Host Notify always
+//! sends two data bytes to the host along with the peripheral's own slave
+//! address so that the Host knows which peripheral requested the Host's
+//! attention.
+//!
+//! This protocol does not support PEC. The PEC flag is explicitly cleared
+//! within this function, so if PEC is enabled prior to calling it, it must
+//! be re-enabled afterwards.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterHostNotify(tSMBus *psSMBus, uint8_t ui8OwnSlaveAddress,
+ uint8_t *pui8Data)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = SMBUS_ADR_HOST;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = 2;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // This protocol does NOT support PEC, so the flag must be cleared. If
+ // PEC is needed again after this transaction, it should be explicitly
+ // enabled again.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, ui8OwnSlaveAddress);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Send Byte transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Data is the data byte to send to the slave.
+//!
+//! The Send Byte protocol is a basic SMBus protocol that sends a single data
+//! byte to the slave. Unlike most of the other SMBus protocols, Send Byte
+//! does not send a ``command'' byte before the data payload and is intended
+//! for basic communication.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteSend(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Data)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Data;
+ psSMBus->pui8TxBuffer = &ui8Data;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the data byte on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, ui8Data);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the data to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->pui8TxBuffer[0],
+ 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+ }
+ else
+ {
+ //
+ // Update the state machine. Since it's the only byte being sent,
+ // the state machine's next state is idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_SINGLE_SEND);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Receive Byte transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the location to store the received data
+//! byte.
+//!
+//! The Receive Byte protocol is a basic SMBus protocol that receives a single
+//! data byte from the slave. Unlike most of the other SMBus protocols,
+//! Receive Byte does not send a ``command'' byte before the data payload and
+//! is intended for basic communication.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteReceive(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8RxSize = 1;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // set the R/S bit to '1' for the CRC calculation.
+ //
+ ui8TempData = ((psSMBus->ui8TargetSlaveAddress << 1) & 0xfe) | 1;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the read operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_START);
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the read operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Write Byte or Write Word transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data payload.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function supports both the Write Byte and Write Word protocols. The
+//! amount of data to send is user defined, but limited to 1 or 2 bytes.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 2, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteWordWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 2 bytes are requested, indicate error.
+ //
+ if(ui8Size > 2)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = ui8Size;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+ else
+ {
+ //
+ // If only one byte to send, move to the final state.
+ //
+ if(ui8Size == 1)
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+ }
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Read Byte or Read Word transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8Data is a pointer to the receive data buffer.
+//! \param ui8Size is the number of bytes to receive from the slave.
+//!
+//! This function supports both the Read Byte and Read Word protocols. The
+//! amount of data to receive is user defined, but limited to 1 or 2 bytes.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 2, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteWordRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 2 bytes are requested, indicate error.
+ //
+ if(ui8Size > 2)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = ui8Size;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // set the R/S bit to '1' for the CRC calculation.
+ //
+ ui8TempData = psSMBus->ui8TargetSlaveAddress << 1;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ if(psSMBus->ui8RxSize == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+ }
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ONE;
+ }
+ }
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Block Write transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function supports the Block Write protocol. The amount of data sent
+//! to the slave is user defined, but limited to 32 bytes per the SMBus spec.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 32, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterBlockWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 32 bytes are requested, indicate error.
+ //
+ if(ui8Size > 32)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = ui8Size;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+
+ //
+ // Clear the process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the size to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8TxSize, 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+ }
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Write the first byte of the data.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_BLOCK_SIZE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Block Read transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8Data is a pointer to the receive data buffer.
+//!
+//! This function supports the Block Read protocol. The amount of data read
+//! is defined by the slave device, but should never exceed 32 bytes per the
+//! SMBus spec. The receive size is the first data byte returned by the slave,
+//! so this function assumes a size of 3 until the actual number is sent by
+//! the slave. In the application interrupt handler, SMBusRxPacketSizeGet()
+//! can be used to obtain the amount of data sent by the slave.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterBlockRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the block transfer flag..
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+
+ //
+ // Clear the process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Initially set the RX size to 3 to make the state machine work.
+ // The slave will respond with the actual size of the transfer in the
+ // first byte and that data will replace this initial value.
+ //
+ psSMBus->ui8RxSize = 3;
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // set the R/S bit to '1' for the CRC calculation.
+ //
+ ui8TempData = psSMBus->ui8TargetSlaveAddress << 1;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Process Call transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8TxData is a pointer to the transmit data buffer.
+//! \param pui8RxData is a pointer to the receive data buffer.
+//!
+//! This function supports the Process Call protocol. The amount of data sent
+//! to and received from the slave is fixed to 2 bytes per direction (2 sent,
+//! 2 received).
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterProcessCall(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8TxData,
+ uint8_t *pui8RxData)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8TxData;
+ psSMBus->pui8RxBuffer = pui8RxData;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8TxSize = 2;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = 2;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the process call flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+
+ //
+ // Clear the block transfer and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+ }
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Block Process Call transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8TxData is a pointer to the transmit data buffer.
+//! \param ui8TxSize is the number of bytes to send to the slave.
+//! \param pui8RxData is a pointer to the receive data buffer.
+//!
+//! This function supports the Block Write/Block Read Process Call protocol.
+//! The amount of data sent to the slave is user defined but limited to 32 data
+//! bytes. The amount of data read is defined by the slave device, but should
+//! never exceed 32 bytes per the SMBus spec. The receive size is the first
+//! data byte returned by the slave, so the actual size is populated in
+//! SMBusMasterISRProcess(). In the application interrupt handler,
+//! SMBusRxPacketSizeGet() can be used to obtain the amount of data sent by
+//! the slave.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8TxSize is greater than 32, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterBlockProcessCall(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8TxData,
+ uint8_t ui8TxSize, uint8_t *pui8RxData)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 32 bytes are requested, indicate error.
+ //
+ if(ui8TxSize > 32)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8TxData;
+ psSMBus->pui8RxBuffer = pui8RxData;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8TxSize = ui8TxSize;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = 3;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the process call and block transfer flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+
+ //
+ // Clear the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the size to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8TxSize, 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+ }
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_BLOCK_SIZE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a ``raw'' I2C write transfer to a slave device.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function sends a user-defined number of bytes to an I2C slave without
+//! using an SMBus protocol. The data size is only limited to the size of the
+//! ui8Size variable, which is an unsigned character (8 bits, value of 255).
+//!
+//! Because this function uses ``raw'' I2C, PEC is not supported.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterI2CWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data, uint8_t ui8Size)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = ui8Size;
+ psSMBus->ui8TxIndex = 1;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+
+ //
+ // PEC is not supported by raw I2C transfers, so force it to be disabled.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Clear the block transfer and process call flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+
+ //
+ // Set the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the first byte on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->pui8TxBuffer[0]);
+
+ //
+ // Choose what to do based on the transmit size.
+ //
+ if(ui8Size == 1)
+ {
+ //
+ // Update the state machine. Since it's the only byte being sent,
+ // the state machine's next state is idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_SINGLE_SEND);
+ }
+ else if(ui8Size == 2)
+ {
+ //
+ // If there are only 2 bytes to send just jump to the final write
+ // state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a ``raw'' I2C read transfer to a slave device.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the receive data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function receives a user-defined number of bytes from an I2C slave
+//! without using an SMBus protocol. The data size is only limited to the size
+//! of the ui8Size variable, which is an unsigned character (8 bits, value of
+//! 255).
+//!
+//! Because this function uses ``raw'' I2C, PEC is not supported.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterI2CRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data, uint8_t ui8Size)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = ui8Size;
+
+ //
+ // PEC is not supported by raw I2C transfers, so force it to be disabled.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Clear the block transfer and process call flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+
+ //
+ // Set the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Choose what to do based on the receive size.
+ //
+ if(ui8Size == 1)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+ }
+ else if(ui8Size == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+
+ if(ui8Size == 1)
+ {
+ //
+ // Start the single receive.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+ }
+ else
+ {
+ //
+ // Start the burst receive.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_START);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a ``raw'' I2C write-read transfer to a slave device.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8TxData is a pointer to the transmit data buffer.
+//! \param ui8TxSize is the number of bytes to send to the slave.
+//! \param pui8RxData is a pointer to the receive data buffer.
+//! \param ui8RxSize is the number of bytes to receive from the slave.
+//!
+//! This function initiates a write-read transfer to an I2C slave without using
+//! an SMBus protocol. The user-defined number of bytes is written to the
+//! slave first, followed by the reception of the user-defined number of bytes.
+//! The transmit and receive data sizes are only limited to the size of the
+//! ui8TxSize and ui8RxSize variables, which are unsigned characters (8 bits,
+//! value of 255).
+//!
+//! Because this function uses ``raw'' I2C, PEC is not supported.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterI2CWriteRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8TxData, uint8_t ui8TxSize,
+ uint8_t *pui8RxData, uint8_t ui8RxSize)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->pui8TxBuffer = pui8TxData;
+ psSMBus->pui8RxBuffer = pui8RxData;
+ psSMBus->ui8TxIndex = 1;
+ psSMBus->ui8TxSize = ui8TxSize;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = ui8RxSize;
+
+ //
+ // PEC is not supported by raw I2C transfers, so force it to be disabled.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Set the process call flag. Even though this is technically not an SMBus
+ // process call, this flag is used in the interrupt state machine for
+ // the bus turn around.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+
+ //
+ // Set the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Write the first byte of the data.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->pui8TxBuffer[0]);
+
+ //
+ // Choose what to do based on the transmit size.
+ //
+ if(ui8TxSize == 1)
+ {
+ //
+ // Move to the read first state for the turn around.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+ }
+ else if(ui8TxSize == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``general'' Get UDID packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the receive data buffer.
+//!
+//! This function sends a ``general'' Get UDID packet, used during Address
+//! Resolution Protocol (ARP). Since SMBus requires that data bytes be
+//! transmitted in a certain order, the raw data in the pui8Data needs to be
+//! treated as such. To put the data in a known order, use
+//! SMBusARPUDIDPacketDecode().
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPGetUDIDGen(tSMBus *psSMBus, uint8_t *pui8Data)
+{
+ //
+ // Use the block read protocol to receive the UDID.
+ //
+ return(SMBusMasterBlockRead(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_ARP_GET_UDID, pui8Data));
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``directed'' Get UDID packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the receive data buffer.
+//!
+//! This function sends a ``directed'' Get UDID packet, used during Address
+//! Resolution Protocol (ARP). A directed packet differs from a general packet
+//! in that it targets a specific slave device. Since SMBus requires that data
+//! bytes be transmitted in a certain order, the raw data in the pui8Data needs
+//! to be treated as such. To put the data in a known order, use
+//! SMBusARPUDIDPacketDecode().
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPGetUDIDDir(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data)
+{
+ //
+ // Use the block read protocol to receive the UDID.
+ //
+ return(SMBusMasterBlockRead(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ (ui8TargetAddress << 1 | 1), pui8Data));
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``general'' Reset Device packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends a ``general'' Reset Device packet, used during Address
+//! Resolution Protocol (ARP). This packet is used by an ARP Master to force
+//! all non-PSA (Persistent Slave Address), ARP-capable devices to return to
+//! their initial state. This packet also tells the devices to clear their
+//! Address Resolved (AR) and Address Valid (AV) flags.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPResetDeviceGen(tSMBus *psSMBus)
+{
+ //
+ // Use the Send Byte protocol to send the packet.
+ //
+ return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_ARP_RESET_DEVICE));
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``directed'' Reset Device packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends a ``directed'' Reset Device packet, used during Address
+//! Resolution Protocol (ARP). This packet is used by an ARP Master to force
+//! a specific non-PSA (Persistent Slave Address), ARP-capable device to return
+//! to its initial state. This packet also tells the device to clear its
+//! Address Resolved (AR) and Address Valid (AV) flags.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPResetDeviceDir(tSMBus *psSMBus, uint8_t ui8TargetAddress)
+{
+ //
+ // Use the Send Byte protocol to send the packet.
+ //
+ return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ (ui8TargetAddress << 1)));
+}
+
+//*****************************************************************************
+//
+//! Sends an ARP Assign Address packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the transmit data buffer. This buffer
+//! should be correctly formatted using SMBusARPUDIDPacketEncode() and
+//! should contain the UDID data and the address for the slave.
+//!
+//! This function sends an Assign Address packet, used during Address
+//! Resolution Protocol (ARP). Because SMBus requires data bytes be sent out
+//! MSB first, the UDID and target address should be formatted correctly by the
+//! application or using SMBusARPUDIDPacketEncode() and placed into a data
+//! buffer pointed to by pui8Data.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPAssignAddress(tSMBus *psSMBus, uint8_t *pui8Data)
+{
+ //
+ // Use the Block Write protocol to send the packet.
+ //
+ return(SMBusMasterBlockWrite(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_ARP_ASSIGN_ADDRESS, pui8Data, 17));
+}
+
+//*****************************************************************************
+//
+//! Sends a Notify ARP Master packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the transmit data buffer. The data payload
+//! should be 0x0000 for this packet.
+//!
+//! This function sends a Notify ARP Master packet, used during Address
+//! Resolution Protocol (ARP). This packet is used by a slave to indicate
+//! to the ARP Master that it needs attention.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPNotifyMaster(tSMBus *psSMBus, uint8_t *pui8Data)
+{
+ //
+ // Use the Host Notify protocol to send the packet.
+ //
+ return(SMBusMasterHostNotify(psSMBus, (SMBUS_ADR_DEFAULT_DEVICE << 1),
+ pui8Data));
+}
+
+//*****************************************************************************
+//
+//! Sends a Prepare to ARP packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends a Prepare to ARP packet, used during Address Resolution
+//! Protocol (ARP). This packet is used by an ARP Master to alert devices on
+//! the bus that ARP is about to begin. All ARP-capable devices must
+//! acknowledge all bytes in this packet and clear their Address Resolved (AR)
+//! flag.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPPrepareToARP(tSMBus *psSMBus)
+{
+ //
+ // Use the Send Byte protocol to send the packet.
+ //
+ return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_PREPARE_TO_ARP));
+}
+
+//*****************************************************************************
+//
+//! Master ISR processing function for the SMBus application.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function must be called in the application interrupt service routine
+//! (ISR) to process SMBus master interrupts.
+//!
+//! \return Returns \b SMBUS_TIMEOUT if a bus timeout is detected,
+//! \b SMBUS_ARB_LOST if I2C bus arbitration lost is detected,
+//! \b SMBUS_ADDR_ACK_ERROR if the address phase of a transfer results in a
+//! NACK, \b SMBUS_DATA_ACK_ERROR if the data phase of a transfer results in a
+//! NACK, \b SMBUS_DATA_SIZE_ERROR if a receive buffer overrun is detected or
+//! if a transmit operation tries to write more data than is allowed,
+//! \b SMBUS_MASTER_ERROR if an unknown error occurs, \b SMBUS_PEC_ERROR if the
+//! received PEC byte does not match the locally calculated value, or
+//! \b SMBUS_OK if processing finished successfully.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterIntProcess(tSMBus *psSMBus)
+{
+ uint32_t ui32IntStatus;
+ uint32_t ui32ErrorStatus;
+ uint8_t ui8TempData;
+
+ //
+ // Determine which interrupt made us get here.
+ //
+ ui32IntStatus = MAP_I2CMasterIntStatusEx(psSMBus->ui32I2CBase, true);
+
+ //
+ // Check for the timeout interrupt. Since the peripheral will
+ // automatically issue a stop, just clear the interrupt and return.
+ //
+ if(ui32IntStatus & I2C_MASTER_INT_TIMEOUT)
+ {
+ //
+ // Clear all pending interrupts and wait for the bus to become
+ // free so we can issue a STOP.
+ //
+ MAP_I2CMasterIntClearEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_TIMEOUT |
+ I2C_MASTER_INT_DATA);
+
+ //
+ // Clear the transfer in progress flag. New transactions will
+ // be aborted until the bus is free.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_TIMEOUT);
+ }
+ else
+ {
+ //
+ // Clear the data interrupt.
+ //
+ MAP_I2CMasterIntClearEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_DATA);
+ }
+
+ //
+ // Read the master interrupt status bits.
+ //
+ ui32ErrorStatus = HWREG(psSMBus->ui32I2CBase + I2C_O_MCS);
+
+ //
+ // Check for arbitration lost.
+ //
+ if(ui32ErrorStatus & I2C_MCS_ARBLST)
+ {
+ //
+ // Put the state machine back in the idle state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_ARB_LOST);
+ }
+
+ //
+ // Check for an error.
+ //
+ if(ui32ErrorStatus & I2C_MCS_ERROR)
+ {
+ //
+ // Put the state machine back in the idle state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Check to see if the bus is free. There are two interrupts when a
+ // NACK happens, and the bus should only be free during the second
+ // interrupt. During the first interrupt (when the bus is busy),
+ // generate the necessary STOP condition.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ //
+ // Issue a STOP.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
+ }
+ else
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+ }
+
+ //
+ // Check for ACK errors.
+ //
+ if(ui32ErrorStatus & I2C_MCS_ADRACK)
+ {
+ //
+ // Return to caller.
+ //
+ return(SMBUS_ADDR_ACK_ERROR);
+ }
+ else if(ui32ErrorStatus & I2C_MCS_DATACK)
+ {
+ //
+ // Return to caller.
+ //
+ return(SMBUS_DATA_ACK_ERROR);
+ }
+ else
+ {
+ //
+ // Return to caller. Should never get here.
+ //
+ return(SMBUS_MASTER_ERROR);
+ }
+ }
+
+ //
+ // If no error conditions, determine what to do based on the state.
+ //
+ switch(psSMBus->ui8MasterState)
+ {
+ //
+ // The idle state. This state should only be reached after the last
+ // byte of a master transmit.
+ //
+ case SMBUS_STATE_IDLE:
+ {
+ //
+ // If the peripheral is not busy clear the transfer in progress
+ // flag. This means that the peripheral has given up the bus,
+ // most likely due to the end of a transmit operation.
+ //
+ if(!MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // When using a block write, the transfer size must be sent before the
+ // data payload.
+ //
+ case SMBUS_STATE_WRITE_BLOCK_SIZE:
+ {
+ //
+ // Write the block write size to the data register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8TxSize);
+
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // The next data byte is from the data payload.
+ //
+ if((psSMBus->ui8TxSize == 1) &&
+ !(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC)))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+ //
+ // The state for the middle of a burst write.
+ //
+ case SMBUS_STATE_WRITE_NEXT:
+ {
+ //
+ // Write the next byte to the data register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++]);
+
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // Determine the next state based on the values of the PEC and
+ // process call flags.
+ //
+
+ //
+ // If PEC is active and process call is not active.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // If a process call, there is no PEC byte on the transmit.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
+ {
+ //
+ // Check to see if the TX index is equal to size minus 1.
+ //
+ if(psSMBus->ui8TxIndex == (psSMBus->ui8TxSize - 1))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // If the TX index is the same as the size, we're done.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+ }
+
+ //
+ // If PEC is not used, regardless of whether this is a process
+ // call.
+ //
+ else
+ {
+ //
+ // Check to see if the TX index is equal to the size minus 1.
+ //
+ if(psSMBus->ui8TxIndex == (psSMBus->ui8TxSize - 1))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the final write of a burst sequence.
+ //
+ case SMBUS_STATE_WRITE_FINAL:
+ {
+ //
+ // Determine what data to write to the data register based
+ // on the values of the PEC and process call flags.
+ //
+ //
+ // If PEC is active, write the PEC byte to the data register.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // If a process call is active, send data, not CRC.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
+ {
+ //
+ // Write the final byte from TX buffer to the data
+ // register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->pui8TxBuffer[psSMBus->
+ ui8TxIndex++]);
+ }
+ else
+ {
+ //
+ // Write the calculated CRC (PEC) byte to the data
+ // register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->ui8CalculatedCRC);
+ }
+ }
+ else
+ {
+ //
+ // Write the final byte from TX buffer to the data register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->pui8TxBuffer[psSMBus->
+ ui8TxIndex++]);
+ }
+
+ //
+ // If a process call is active, send out the repeated start to
+ // begin the RX portion.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
+ {
+ //
+ // Move to the read first "turnaround" state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+ }
+ else
+ {
+ //
+ // Finish the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_FINISH);
+
+ //
+ // Since we end the transaction after the last byte is sent,
+ // the next state is idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for a single byte read.
+ //
+ case SMBUS_STATE_READ_ONE:
+ {
+ //
+ // Put the I2C master into receive mode.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Perform a single byte read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the start of a burst read.
+ //
+ case SMBUS_STATE_READ_FIRST:
+ {
+ //
+ // Put the I2C master into receive mode.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Handle the case where PEC is used.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the target address and R/S bit to the running CRC
+ // calculation.
+ //
+ ui8TempData =
+ ((psSMBus->ui8TargetSlaveAddress << 1) & 0xfe) | 1;
+
+ //
+ // Update the calculated CRC value in the configuration
+ // structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC, &ui8TempData, 1);
+
+ //
+ // Set the next state in the state machine.
+ //
+ if(psSMBus->ui8RxSize > 1)
+ {
+ //
+ // If this is a block transfer, the next state is to read
+ // back the number of bytes that the slave will be sending.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_BLOCK_SIZE;
+ }
+
+ //
+ // For every other case...
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ //
+ // If 1 byte remains, move to the final read state.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // Set the next state in the state machine.
+ //
+ if(psSMBus->ui8RxSize > 2)
+ {
+ //
+ // If this is a block transfer, the next state is to read
+ // back the number of bytes that the slave will be sending.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_BLOCK_SIZE;
+ }
+
+ //
+ // For every other case...
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ //
+ // If 2 bytes remain, move to the final read state.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+
+ //
+ // Start the burst receive.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_START);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the size of a block read.
+ //
+ case SMBUS_STATE_READ_BLOCK_SIZE:
+ {
+ //
+ // Update the RX size with the data byte.
+ //
+ psSMBus->ui8RxSize = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If more than 32 bytes are going to be sent, error.
+ //
+ if((psSMBus->ui8RxSize > 32) || (psSMBus->ui8RxSize == 0))
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;
+
+ //
+ // If too many or too few bytes, error.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+
+ //
+ // Break from this case.
+ //
+ break;
+ }
+
+ //
+ // If PEC is enabled, add the size byte to the calculation and
+ // add one to the size variable to account for the extra PEC byte.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Calculate the new CRC and update configuration structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8RxSize, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ switch(psSMBus->ui8RxSize)
+ {
+ //
+ // 1 byte remaining.
+ //
+ case 1:
+ {
+ //
+ // If only one byte remains and PEC, go to the second
+ // to last byte state.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+
+ //
+ // If only one byte remains and no PEC, end the burst
+ // transfer.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+ }
+
+ //
+ // This switch is done.
+ //
+ break;
+ }
+
+ //
+ // 2 bytes remaining.
+ //
+ case 2:
+ {
+ //
+ // If two bytes and PEC remain, move to read next
+ // state.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+
+ //
+ // If two bytes remain, move to the final read state.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+
+ //
+ // This switch is done.
+ //
+ break;
+ }
+
+ //
+ // For every other situation (in other words, remaining bytes
+ // is greater than 2).
+ //
+ default:
+ {
+ //
+ // If more than 2 bytes to read, move to the next byte
+ // state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+
+ //
+ // This switch is done.
+ //
+ break;
+ }
+ }
+
+ //
+ // Determine how to step the I2C state machine.
+ //
+ if((psSMBus->ui8RxSize == 1) &&
+ !HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // If exactly 1 byte remains, read the byte and send a STOP.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_FINISH);
+ }
+ else
+ {
+ //
+ // Otherwise, continue the burst read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_CONT);
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the middle of a burst read.
+ //
+ case SMBUS_STATE_READ_NEXT:
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
+ {
+ //
+ // Dummy read of data register.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If too many or too few bytes, error.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;
+
+ //
+ // Break from this case.
+ //
+ break;
+ }
+
+ //
+ // Read the received character.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] =
+ MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Continue the burst read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_CONT);
+
+ //
+ // If PEC is enabled, add the received byte to the calculation.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Calculate the new CRC and update configuration structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex],
+ 1);
+
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+
+ //
+ // If there is 1 byte remaining, make next state be the
+ // end of burst read state.
+ //
+ if((psSMBus->ui8RxSize - psSMBus->ui8RxIndex) == 1)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+
+ //
+ // If there are two bytes remaining, make next state be the
+ // end of burst read state.
+ //
+ if((psSMBus->ui8RxSize - psSMBus->ui8RxIndex) == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the end of a burst read.
+ //
+ case SMBUS_STATE_READ_FINAL:
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
+ {
+ //
+ // Dummy read of data register.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If too many or too few bytes, error.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;
+
+ //
+ // Break from this case.
+ //
+ break;
+ }
+
+ //
+ // Read the received character.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] =
+ MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+
+ //
+ // Finish the burst read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // If PEC is enabled, add the received byte to the calculation.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Calculate the new CRC and update configuration structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex],
+ 1);
+ }
+
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // This state is for the final read of a single or burst read.
+ //
+ case SMBUS_STATE_READ_WAIT:
+ {
+ //
+ // Read the received byte.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If PEC is enabled, check the value that just came in to see
+ // if it matches.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex > psSMBus->ui8RxSize)
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Store the received CRC byte.
+ //
+ psSMBus->ui8ReceivedCRC = ui8TempData;
+
+ //
+ // If the CRC doesn't match, send a NACK and indicate the
+ // failure to the application.
+ //
+ if(psSMBus->ui8ReceivedCRC != psSMBus->ui8CalculatedCRC)
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_PEC_ERROR);
+ }
+ }
+ else
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Read the received byte.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] = ui8TempData;
+
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // This state is for a transaction that needed to end due to a
+ // size error.
+ //
+ case SMBUS_STATE_READ_ERROR_STOP:
+ {
+ //
+ // Dummy read the received byte.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // The state machine is now idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+ }
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Enables the appropriate master interrupts for stack processing.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables the I2C interrupts used by the SMBus master. Both
+//! the peripheral-level and NVIC-level interrupts are enabled.
+//! SMBusMasterInit() must be called before this function because this function
+//! relies on the I2C base address being defined.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusMasterIntEnable(tSMBus *psSMBus)
+{
+ //
+ // Enable the master interrupts.
+ //
+ MAP_I2CMasterIntEnableEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_DATA |
+ I2C_MASTER_INT_TIMEOUT);
+
+ //
+ // Enable the interrupt in the NVIC.
+ //
+ switch(psSMBus->ui32I2CBase)
+ {
+ case I2C0_BASE:
+ {
+ MAP_IntEnable(INT_I2C0);
+ break;
+ }
+
+ case I2C1_BASE:
+ {
+ MAP_IntEnable(INT_I2C1);
+ break;
+ }
+
+ case I2C2_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C129);
+ }
+ break;
+ }
+
+ case I2C3_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C129);
+ }
+ break;
+ }
+
+ case I2C4_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C129);
+ }
+ break;
+ }
+
+ case I2C5_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C129);
+ }
+ break;
+ }
+
+ case I2C6_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C6_TM4C129);
+ }
+ break;
+ }
+
+ case I2C7_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C7_TM4C129);
+ }
+ break;
+ }
+
+ case I2C8_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C8_TM4C129);
+ }
+ break;
+ }
+
+ case I2C9_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C9_TM4C129);
+ }
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes an I2C master peripheral for SMBus functionality.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui32I2CBase specifies the base address of the I2C master peripheral.
+//! \param ui32SMBusClock specifies the system clock speed of the MCU.
+//!
+//! This function initializes an I2C peripheral for SMBus master use. The
+//! instance-specific configuration structure is initialized to a set of known
+//! values and the I2C peripheral is configured for 100kHz use, which is
+//! required by the SMBus specification.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusMasterInit(tSMBus *psSMBus, uint32_t ui32I2CBase,
+ uint32_t ui32SMBusClock)
+{
+ //
+ // Initialize the configuration structure.
+ //
+ psSMBus->pUDID = 0;
+ psSMBus->ui32I2CBase = ui32I2CBase;
+ psSMBus->ui16Flags = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ psSMBus->ui8OwnSlaveAddress = 0;
+ psSMBus->ui8TargetSlaveAddress = 0;
+ psSMBus->ui8CurrentCommand = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+
+ //
+ // Enable and initialize the I2C master module Using the system clock.
+ // The I2C transfer rate will always be 100kHz since fast mode is not
+ // supported by SMBus.
+ //
+ MAP_I2CMasterInitExpClk(psSMBus->ui32I2CBase, ui32SMBusClock, false);
+
+ //
+ // Configure bus timeout to 25ms. 12-bit value for 25ms is 0x9C4 (2500
+ // clocks), so round upper 8 bits to 0x9C. Each clock is 10us since
+ // 100kHz I2C is required for SMBus.
+ //
+ MAP_I2CMasterTimeoutSet(psSMBus->ui32I2CBase, 0x9C);
+}
+
+//*****************************************************************************
+//
+//! Slave ISR processing function for the SMBus application.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function must be called in the application interrupt service routine
+//! (ISR) to process SMBus slave interrupts.
+//!
+//! If manual acknowledge is enabled using SMBusSlaveManualACKEnable(), this
+//! function processes the data byte, but does not send the ACK/NACK value. In
+//! this case, the user application is responsible for sending the acknowledge
+//! bit based on the return code of this function.
+//!
+//! When receiving a Quick Command from the master, the slave has some set-up
+//! requirements. When the master sends the R/S (data) bit as '0', nothing
+//! additional needs to be done in the slave and SMBusSlaveIntProcess() returns
+//! \b SMBUS_SLAVE_QCMD_0. However, when the master sends the R/S (data) bit
+//! as '1', the slave must write the data register with data containing a '1'
+//! in bit 7. This means that when receiving a Quick Command, the slave must
+//! set up the TX buffer to either have 1 data byte with bit 7 set to '1' or
+//! set up the TX buffer to be zero length. In the case where 1 data byte is
+//! put in the TX buffer, SMBusSlaveIntProcess() returns \b SMBUS_OK the first
+//! time its called and \b SMBUS_SLAVE_QCMD_0 the second. In the case where
+//! the TX buffer has no data, SMBusSlaveIntProcess() will return
+//! \b SMBUS_SLAVE_ERROR the first time its called, and \b SMBUS_SLAVE_QCMD_1
+//! the second time.
+//!
+//! \return Returns \b SMBUS_SLAVE_FIRST_BYTE if the first byte (typically the
+//! SMBus command) has been received; \b SMBUS_SLAVE_NOT_READY if the slave's
+//! transmit buffer is not yet initialized when the master requests data from
+//! the slave; \b SMBUS_DATA_SIZE_ERROR if during a master block write, the
+//! size sent by the master is greater than the amount of available space in
+//! the receive buffer; \b SMBUS_SLAVE_ERROR if a buffer overrun is detected
+//! during a slave receive operation or if data is sent and was not expected;
+//! \b SMBUS_SLAVE_QCMD_0 if a Quick Command was received with data '0';
+//! \b SMBUS_SLAVE_QCMD_1 if a Quick Command was received with data '1';
+//! \b SMBUS_TRANSFER_COMPLETE if a STOP is detected on the bus, marking the
+//! end of a transfer; \b SMBUS_PEC_ERROR if the received PEC byte does not
+//! match the locally calculated value; or \b SMBUS_OK if processing finished
+//! successfully.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusSlaveIntProcess(tSMBus *psSMBus)
+{
+ uint32_t ui32InterruptStatus;
+ uint32_t ui32SlaveStatus = 0;
+ uint8_t ui8CRCTemp;
+ uint8_t ui8DataTemp;
+
+ //
+ // Determine which interrupt was asserted.
+ //
+ ui32InterruptStatus = I2CSlaveIntStatusEx(psSMBus->ui32I2CBase, true);
+
+ //
+ // Check the status register.
+ //
+ ui32SlaveStatus = I2CSlaveStatus(psSMBus->ui32I2CBase);
+
+ //
+ // Check for the START interrupt.
+ //
+ if(ui32InterruptStatus & I2C_SLAVE_INT_START)
+ {
+ //
+ // Clear the interrupt.
+ //
+ I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_START);
+
+
+ //
+ // This interrupt is not supported outside of using the FIFO.
+ //
+ return(SMBUS_OK);
+ }
+
+ //
+ // Check for the STOP interrupt.
+ //
+ if(ui32InterruptStatus & I2C_SLAVE_INT_STOP)
+ {
+ //
+ // Make sure the transfer in progress flag is cleared. In the case
+ // of Quick Command, it should never be set, so this is safe.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Clear the interrupt.
+ //
+ I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_STOP);
+
+ //
+ // Check to see if a Quick Command was sent.
+ //
+ if(ui32SlaveStatus & 0x10)
+ {
+ //
+ // Make sure the TX/RX index is 0. If not, we should not be here.
+ // Other data should not have been sent or received during a Quick
+ // Command.
+ //
+ if((psSMBus->ui8RxIndex != 0) || (psSMBus->ui8TxIndex != 0))
+ {
+ //
+ // Return an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+
+ //
+ // Tell caller a Quick Command has occurred and the data value.
+ //
+ if(ui32SlaveStatus & 0x20)
+ {
+ return(SMBUS_SLAVE_QCMD_1);
+ }
+ else
+ {
+ return(SMBUS_SLAVE_QCMD_0);
+ }
+ }
+
+ //
+ // Move to the idle state.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;
+
+ //
+ // Return end of transfer.
+ //
+ return(SMBUS_TRANSFER_COMPLETE);
+ }
+
+ //
+ // Check for the DATA interrupt.
+ //
+ if(ui32InterruptStatus & I2C_SLAVE_INT_DATA)
+ {
+ //
+ // Clear the I2C interrupt.
+ //
+ I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_DATA);
+
+ //
+ // Make sure that at least one of the relevant status bits is set.
+ //
+ if(!(ui32SlaveStatus & 0x07))
+ {
+ //
+ // No status bits were set - this is bad. Should never get here.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+
+ //
+ // Every time this interrupt occurs, a transfer is in progress. Make
+ // sure the flag is set appropriately.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Handle the request type.
+ //
+ switch((ui32SlaveStatus & 0x07))
+ {
+ //
+ // The first byte after the slave's own address has been received.
+ // This is almost always the command byte in SMBus. The only
+ // exception is when the Send Byte protocol is used by the master.
+ //
+ case I2C_SLAVE_ACT_RREQ_FBR:
+ {
+ //
+ // Check which slave address was called out. Set the active
+ // address to the matched address.
+ //
+ if(I2CSlaveStatus(psSMBus->ui32I2CBase) & I2C_SCSR_OAR2SEL)
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR2) & 0x7f;
+ }
+ else
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR);
+ }
+
+ //
+ // If raw I2C, data goes into buffer.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C))
+ {
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
+ I2CSlaveDataGet(psSMBus->ui32I2CBase);
+ }
+
+ //
+ // Read the first byte into the ui8CurrentCommand member.
+ //
+ else
+ {
+ psSMBus->ui8CurrentCommand =
+ I2CSlaveDataGet(psSMBus->ui32I2CBase);
+ }
+
+ //
+ // If PEC is enabled, add the address to the CRC calculation.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the address to the CRC calculation. In this case
+ // R/S will always be 0. Also, this is the start of the
+ // CRC calculation, so the initial value is 0.
+ //
+ ui8CRCTemp = psSMBus->ui8OwnSlaveAddress << 1;
+
+ //
+ // Calculate new CRC.
+ //
+ psSMBus->ui8CalculatedCRC = Crc8CCITT(0, &ui8CRCTemp, 1);
+
+ //
+ // Add the data byte (ui8CurrentCommand) to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_SLAVE_POST_COMMAND;
+
+ //
+ // Actions for this case are complete.
+ //
+ return(SMBUS_SLAVE_FIRST_BYTE);
+ }
+
+ //
+ // A data byte other than the first data byte has been received.
+ //
+ case I2C_SLAVE_ACT_RREQ:
+ {
+ //
+ // Determine what to do based on the current state.
+ //
+ switch(psSMBus->ui8SlaveState)
+ {
+ //
+ // Receive first post-command byte.
+ //
+ case SMBUS_STATE_SLAVE_POST_COMMAND:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Check if this is a block transfer.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ //
+ // Make sure there is enough space in the buffer.
+ // If not, NACK. If there is, overwrite the
+ // current size with the size sent by the master.
+ //
+ if(ui8DataTemp > psSMBus->ui8RxSize)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ //
+ // Indicate a size error.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+ else
+ {
+ //
+ // Update the size.
+ //
+ psSMBus->ui8RxSize = ui8DataTemp;
+
+ //
+ // Check to see if PEC is enabled.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // If there is no data to receive and no PEC, nothing
+ // to do. Software should never get here.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ //
+ // Report an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+ else
+ {
+ //
+ // Put the data in the buffer.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
+ ui8DataTemp;
+
+ //
+ // If this is the last data byte.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_PEC;
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_DONE;
+ }
+ }
+
+ //
+ // All other cases.
+ //
+ else
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ //
+ // Actions for this case are complete.
+ //
+ break;
+ }
+
+ //
+ // Read the next byte into the buffer.
+ //
+ case SMBUS_STATE_READ_NEXT:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If there is no data to receive and no PEC, nothing
+ // to do. Software should never get here.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ //
+ // Report an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+ else
+ {
+ //
+ // Put the data in the buffer.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
+ ui8DataTemp;
+
+ //
+ // If this is the last data byte.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Update the state machine.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_PROCESS_CALL))
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_DONE;
+ }
+ else
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_PEC;
+ }
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_DONE;
+ }
+ }
+
+ //
+ // All other cases.
+ //
+ else
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ break;
+ }
+
+ //
+ // Read the PEC byte and compare it.
+ //
+ case SMBUS_STATE_READ_PEC:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Compare PEC.
+ //
+ if(psSMBus->ui8CalculatedCRC != ui8DataTemp)
+ {
+ //
+ // Indicate PEC error.
+ //
+ return(SMBUS_PEC_ERROR);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ break;
+ }
+
+ //
+ // No more data to receive. If we get here, read data
+ // into a dummy variable and NACK.
+ //
+ case SMBUS_STATE_READ_DONE:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Report an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+ }
+
+ //
+ // Actions for this case are complete.
+ //
+ break;
+ }
+
+ //
+ // The master has requested that the slave transmit data back to
+ // master.
+ //
+ case I2C_SLAVE_ACT_TREQ:
+ {
+ //
+ // Initialize temporary variable that stores transmit byte to
+ // 0xff. If data is not set by another condition, the 0xff
+ // carries through. This happens if ui8TxIndex is equal to or
+ // greater than ui8TxSize.
+ //
+ ui8DataTemp = 0xff;
+
+ //
+ // Determine what to do based on the current state.
+ //
+ switch(psSMBus->ui8SlaveState)
+ {
+ //
+ // The state machine is currently idle, or if the last
+ // state was SMBUS_STATE_SLAVE_POST_COMMAND or
+ // SMBUS_READ_DONE, this is the first byte transmitted. In
+ // the case of slave post command, this means that the
+ // command was received followed by a repeated start (with
+ // R/S = 1). In the case of read next, this means that a
+ // raw I2C master transmit changed direction with a
+ // repeated start and is now a master receive. In the case
+ // of read done, this means that a previous master transmit
+ // was finished (non-command followed by a repeated start).
+ //
+ case SMBUS_STATE_IDLE:
+ case SMBUS_STATE_SLAVE_POST_COMMAND:
+ case SMBUS_STATE_READ_NEXT:
+ case SMBUS_STATE_READ_DONE:
+ {
+ //
+ // Check which slave address was called out. Set the
+ // active address to the matched address.
+ //
+ if(I2CSlaveStatus(psSMBus->ui32I2CBase) &
+ I2C_SCSR_OAR2SEL)
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ (HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR2) &
+ 0x7f);
+ }
+ else
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR);
+ }
+
+ //
+ // Check to see if the TX buffer is populated. If not,
+ // return not ready without writing to the data
+ // register.
+ //
+ if(psSMBus->ui8TxSize == 0)
+ {
+ return(SMBUS_SLAVE_NOT_READY);
+ }
+
+ //
+ // Is this a block transfer?
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ //
+ // The first byte to send is the size.
+ //
+ ui8DataTemp = psSMBus->ui8TxSize;
+ }
+ else
+ {
+ //
+ // Is there data to send?
+ //
+ if(psSMBus->ui8TxIndex < psSMBus->ui8TxSize)
+ {
+ //
+ // Set the transmit data to the next item in
+ // the buffer.
+ //
+ ui8DataTemp =
+ psSMBus->pui8TxBuffer[psSMBus->
+ ui8TxIndex++];
+ }
+ else
+ {
+ //
+ // Send 0xff per spec.
+ //
+ ui8DataTemp = 0xff;
+ }
+ }
+
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Start calculating the CRC with the address.
+ //
+ ui8CRCTemp =
+ (psSMBus->ui8OwnSlaveAddress << 1) | 1;
+
+ //
+ // Add the address and R/S bit to the CRC.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8CRCTemp, 1);
+
+ //
+ // Add the data byte to the CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Move to the next state.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ //
+ // Final byte is the CRC byte.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // All other cases, move to the next byte
+ // state.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_NEXT;
+ }
+ }
+ else
+ {
+ //
+ // Move to the next state.
+ //
+ switch(psSMBus->ui8TxSize - psSMBus->ui8TxIndex)
+ {
+ //
+ // If all of the data has been sent, move to
+ // the done state.
+ //
+ case 0:
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_DONE;
+
+ break;
+ }
+
+ //
+ // If 1 left, move to the final byte state.
+ //
+ case 1:
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+
+ break;
+ }
+
+ //
+ // All other cases, move to the next byte
+ // state.
+ //
+ default:
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_NEXT;
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The first byte has already been sent, handle the rest.
+ //
+ case SMBUS_STATE_WRITE_NEXT:
+ {
+ //
+ // Set the transmit data to the next item in the
+ // buffer.
+ //
+ ui8DataTemp =
+ psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];
+
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the byte to the CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Check if it's time to move to the next state.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ //
+ // Final byte is the CRC byte.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // Move to the next state.
+ //
+ if((psSMBus->ui8TxSize - psSMBus->ui8TxIndex) == 1)
+ {
+ //
+ // If only 1 byte remains, move to the final
+ // state.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // Write the final byte, whether PEC or data.
+ //
+ case SMBUS_STATE_WRITE_FINAL:
+ {
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Send the CRC byte.
+ //
+ ui8DataTemp = psSMBus->ui8CalculatedCRC;
+ }
+ else
+ {
+ //
+ // Send the last data byte.
+ //
+ ui8DataTemp =
+ psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // Move to the write done state.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_DONE;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // All data has been sent, send 0xff.
+ //
+ case SMBUS_STATE_WRITE_DONE:
+ {
+ //
+ // Send 0xff because there is no more data to send.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, 0xff);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+ }
+
+ //
+ // Actions for this case are complete.
+ //
+ break;
+ }
+ }
+
+ //
+ // Return OK status.
+ //
+ return(SMBUS_OK);
+ }
+
+ //
+ // Return OK. Should never get here.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Sends data outside of the interrupt processing function.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends data outside the interrupt processing function, and
+//! should only be used when SMBusSlaveIntProcess() returns
+//! \b SMBUS_SLAVE_NOT_READY. At this point, the application should set up the
+//! transfer and call this function (it assumes that the transmit buffer has
+//! already been populated when called). When called, this function updates
+//! the slave state machine as if SMBusSlaveIntProcess() were called.
+//!
+//! \return Returns \b SMBUS_SLAVE_NOT_READY if the slave's transmit buffer is
+//! not yet initialized (ui8TxSize is 0), or \b SMBUS_OK if processing finished
+//! successfully.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusSlaveDataSend(tSMBus *psSMBus)
+{
+ uint8_t ui8CRCTemp;
+ uint8_t ui8DataTemp;
+
+ //
+ // Check to see if the TX buffer is populated. If not,
+ // return not ready without writing to the data register.
+ //
+ if(psSMBus->ui8TxSize == 0)
+ {
+ return(SMBUS_SLAVE_NOT_READY);
+ }
+
+ //
+ // Is this a block transfer?
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ //
+ // The first byte to send is the size.
+ //
+ ui8DataTemp = psSMBus->ui8TxSize;
+ }
+ else
+ {
+ //
+ // Is there data to send?
+ //
+ if(psSMBus->ui8TxIndex < psSMBus->ui8TxSize)
+ {
+ //
+ // Set the transmit data to the next item in
+ // the buffer.
+ //
+ ui8DataTemp = psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];
+ }
+ else
+ {
+ //
+ // Send 0xff per spec. Should not get here.
+ //
+ ui8DataTemp = 0xff;
+ }
+ }
+
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Start calculating the CRC with the address.
+ //
+ ui8CRCTemp = (psSMBus->ui8OwnSlaveAddress << 1) | 1;
+
+ //
+ // Add the address and R/S bit to the CRC.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8CRCTemp, 1);
+
+ //
+ // Add the data byte to the CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Move to the next state.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ //
+ // Final byte is the CRC byte.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // All other cases, move to the next byte state.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_NEXT;
+ }
+ }
+ else
+ {
+ //
+ // Move to the next state.
+ //
+ switch(psSMBus->ui8TxSize - psSMBus->ui8TxIndex)
+ {
+ //
+ // If all of the data has been sent, move to the
+ // done state.
+ //
+ case 0:
+ {
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_DONE;
+
+ break;
+ }
+
+ //
+ // If 1 left, move to the final byte state.
+ //
+ case 1:
+ {
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_FINAL;
+
+ break;
+ }
+
+ //
+ // All other cases, move to the next byte state.
+ //
+ default:
+ {
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_NEXT;
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Set the address and size of the slave transmit buffer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes in the buffer.
+//!
+//! This function sets the address and size of the slave transmit buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveTxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ //
+ // Set the trasmit buffer.
+ //
+ psSMBus->pui8TxBuffer = pui8Data;
+
+ //
+ // Set the size.
+ //
+ psSMBus->ui8TxSize = ui8Size;
+}
+
+//*****************************************************************************
+//
+//! Set the address and size of the slave receive buffer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the receive data buffer.
+//! \param ui8Size is the number of bytes in the buffer.
+//!
+//! This function sets the address and size of the slave receive buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveRxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ //
+ // Set the receive buffer.
+ //
+ psSMBus->pui8RxBuffer = pui8Data;
+
+ //
+ // Set the size.
+ //
+ psSMBus->ui8RxSize = ui8Size;
+}
+
+//*****************************************************************************
+//
+//! Get the current command byte.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Returns the current value of the ui8CurrentCommand variable in the SMBus
+//! configuration structure. This can be used to help the user application
+//! set up the SMBus slave transmit and receive buffers.
+//!
+//! \return None.
+//
+//*****************************************************************************
+uint8_t
+SMBusSlaveCommandGet(tSMBus *psSMBus)
+{
+ //
+ // Return the current command.
+ //
+ return(psSMBus->ui8CurrentCommand);
+}
+
+//*****************************************************************************
+//
+//! Sets the process call flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Sets the process call flag in the configuration structure so that the SMBus
+//! slave can respond correctly to a Process Call request. This flag must be
+//! set prior to the data portion of the packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveProcessCallEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the process call flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Clears the process call flag in the configuration structure. The user
+//! application can either call this function to clear the flag, or use
+//! SMBusSlaveTransferInit() to clear out all transfer-specific flags.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveProcessCallDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the block transfer flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Sets the block transfer flag in the configuration structure so that the
+//! SMBus slave can respond correctly to a Block Write or Block Read request.
+//! This flag must be set prior to the data portion of the packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveBlockTransferEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the block transfer flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Clears the block transfer flag in the configuration structure. The user
+//! application can either call this function to clear the flag, or use
+//! SMBusSlaveTransferInit() to clear out all transfer-specific flags.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveBlockTransferDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the ``raw'' I2C flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Sets the raw I2C flag in the configuration structure so that the
+//! SMBus slave can respond correctly to raw I2C (non-SMBus protocol) requests.
+//! This flag must be set prior to the transfer, and is a global setting.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveI2CEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the ``raw'' I2C flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Clears the raw I2C flag in the configuration structure. This flag is a
+//! global setting similar to the PEC flag and cannot be cleared using
+//! SMBusSlaveTransferInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveI2CDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the value of the AR (Address Resolved) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param bValue is the value to set the flag.
+//!
+//! This function allows the application to set the value of the AR flag. All
+//! SMBus slaves must support the AR and AV flags. On POR, the AR flag is
+//! cleared. It is also cleared when a slave receives the ARP Reset Device
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveARPFlagARSet(tSMBus *psSMBus, bool bValue)
+{
+ //
+ // Set the block address resolved flag to the desired value.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_RESOLVED) = bValue;
+}
+
+//*****************************************************************************
+//
+//! Returns the current value of the AR (Address Resolved) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This returns the value of the AR (Address Resolved) flag.
+//!
+//! \return Returns \b true if set, \b false if cleared.
+//
+//*****************************************************************************
+bool
+SMBusSlaveARPFlagARGet(tSMBus *psSMBus)
+{
+ //
+ // Get the value of the block address resolved flag.
+ //
+ return(HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_RESOLVED));
+}
+
+//*****************************************************************************
+//
+//! Sets the value of the AV (Address Valid) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param bValue is the value to set the flag.
+//!
+//! This function allows the application to set the value of the AV flag. All
+//! SMBus slaves must support the AR and AV flags. On POR, the AV flag is
+//! cleared. It is also cleared when a slave receives the ARP Reset Device
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveARPFlagAVSet(tSMBus *psSMBus, bool bValue)
+{
+ //
+ // Set the block address valid flag to the desired value.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_VALID) = bValue;
+}
+
+//*****************************************************************************
+//
+//! Returns the current value of the AV (Address Valid) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This returns the value of the AV (Address Valid) flag.
+//!
+//! \return Returns \b true if set, or \b false if cleared.
+//
+//*****************************************************************************
+bool
+SMBusSlaveARPFlagAVGet(tSMBus *psSMBus)
+{
+ //
+ // Get the value of the block address valid flag.
+ //
+ return(HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_VALID));
+}
+
+//*****************************************************************************
+//
+//! Sets up the SMBus slave for a new transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function is used to re-initialize the configuration structure for a
+//! new transfer. Once a transfer is complete and the data has been processed,
+//! unused flags, states, the data buffers and buffer indexes should be reset
+//! to a known state before a new transfer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveTransferInit(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer, process call and transfer in progress flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Set the configuration structure to a known, zeroed state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;
+ psSMBus->ui8CurrentCommand = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the value of the ACK bit when using manual acknowledgement.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param bACK specifies whether to ACK (\b true) or NACK (\b false).
+//!
+//! This function sets the value of the ACK bit. In order for the ACK bit to
+//! take effect, manual acknowledgement must be enabled on the slave using
+//! SMBusSlaveManualACKEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveACKSend(tSMBus *psSMBus, bool bACK)
+{
+ //
+ // Send ACK or NACK based on the value of bACK.
+ //
+ if(bACK)
+ {
+ I2CSlaveACKValueSet(psSMBus->ui32I2CBase, true);
+ }
+ else
+ {
+ I2CSlaveACKValueSet(psSMBus->ui32I2CBase, false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Enables manual acknowledgement for the SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables manual acknowledge capability in the slave. If the
+//! application requires that the slave NACK on a bad command or a bad PEC
+//! calculation, manual acknowledgement allows this to happen.
+//!
+//! In the case of responding to a bad command with a NACK, the application
+//! should use SMBusSlaveACKSend() to ACK/NACK the command. The slave ISR
+//! should check for the SMBUS_SLAVE_FIRST_BYTE return code from
+//! SMBusSlaveISRProcess() and ACK/NACK accordingly. All other cases should be
+//! handled in the application based on the return code of
+//! SMBusSlaveISRProcess().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveManualACKEnable(tSMBus *psSMBus)
+{
+ //
+ // Enable manual acknowledge.
+ //
+ I2CSlaveACKOverride(psSMBus->ui32I2CBase, true);
+}
+
+//*****************************************************************************
+//
+//! Disables manual acknowledgement for the SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function disables manual acknowledge capability in the slave. When
+//! manual acknowledgement is disabled, the slave automatically ACKs every
+//! byte sent by the master.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveManualACKDisable(tSMBus *psSMBus)
+{
+ //
+ // Disable manual acknowledge.
+ //
+ I2CSlaveACKOverride(psSMBus->ui32I2CBase, false);
+}
+
+//*****************************************************************************
+//
+//! Returns the manual acknowledgement status of the SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function returns the state of the I2C ACKOEN bit in the I2CSACKCTL
+//! register. This feature is disabled out of reset and must be enabled
+//! using SMBusSlaveManualACKEnable().
+//!
+//! \return Returns \b true if manual acknowledge is enabled, or \b false if
+//! manual acknowledge is disabled.
+//
+//*****************************************************************************
+bool
+SMBusSlaveManualACKStatusGet(tSMBus *psSMBus)
+{
+ //
+ // Return the value of the bit.
+ //
+ return(HWREG(psSMBus->ui32I2CBase + I2C_O_SACKCTL) & 0x1);
+}
+
+//*****************************************************************************
+//
+//! Determine whether primary or secondary slave address has been requested by
+//! the master.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Tells the caller whether the I2C slave address requested by the master or
+//! SMBus Host is the primary or secondary I2C slave address of the peripheral.
+//! The primary is defined as the address programmed into I2CSOAR, and the
+//! secondary as the address programmed into I2CSOAR2.
+//!
+//! \return Returns \b SMBUS_SLAVE_ADDR_PRIMARY if the primary address is
+//! called out or \b SMBUS_SLAVE_ADDR_SECONDARY if the secondary address is
+//! called out.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusSlaveIntAddressGet(tSMBus *psSMBus)
+{
+ //
+ // Determine whether the primary or secondary address was called out.
+ //
+ if(I2CSlaveStatus(psSMBus->ui32I2CBase) & I2C_SCSR_OAR2SEL)
+ {
+ return(SMBUS_SLAVE_ADDR_SECONDARY);
+ }
+ else
+ {
+ return(SMBUS_SLAVE_ADDR_PRIMARY);
+ }
+}
+
+//*****************************************************************************
+//
+//! Enables the appropriate slave interrupts for stack processing.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables the I2C interrupts used by the SMBus slave. Both
+//! the peripheral-level and NVIC-level interrupts are enabled.
+//! SMBusSlaveInit() must be called before this function because this function
+//! relies on the I2C base address being defined.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveIntEnable(tSMBus *psSMBus)
+{
+ //
+ // Enable the slave interrupts.
+ //
+ I2CSlaveIntEnableEx(psSMBus->ui32I2CBase,
+ I2C_SLAVE_INT_DATA | I2C_SLAVE_INT_STOP);
+
+ //
+ // Enable the interrupt in the NVIC.
+ //
+ switch(psSMBus->ui32I2CBase)
+ {
+ case I2C0_BASE:
+ {
+ MAP_IntEnable(INT_I2C0);
+ break;
+ }
+
+ case I2C1_BASE:
+ {
+ MAP_IntEnable(INT_I2C1);
+ break;
+ }
+
+ case I2C2_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C129);
+ }
+ break;
+ }
+
+ case I2C3_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C129);
+ }
+ break;
+ }
+
+ case I2C4_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C129);
+ }
+ break;
+ }
+
+ case I2C5_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C129);
+ }
+ break;
+ }
+
+ case I2C6_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C6_TM4C129);
+ }
+ break;
+ }
+
+ case I2C7_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C7_TM4C129);
+ }
+ break;
+ }
+
+ case I2C8_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C8_TM4C129);
+ }
+ break;
+ }
+
+ case I2C9_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C9_TM4C129);
+ }
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the slave address for an SMBus slave peripheral.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8AddressNum specifies which address (primary or secondary)
+//! \param ui8SlaveAddress is the address of the slave.
+//!
+//! This function sets the slave address. Both the primary and secondary
+//! addresses can be set using this function. To set the primary address
+//! (stored in I2CSOAR), ui8AddressNum should be '0'. To set the secondary
+//! address (stored in I2CSOAR2), ui8AddressNum should be '1'.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveAddressSet(tSMBus *psSMBus, uint8_t ui8AddressNum,
+ uint8_t ui8SlaveAddress)
+{
+ //
+ // Write the slave address.
+ //
+ I2CSlaveAddressSet(psSMBus->ui32I2CBase, ui8AddressNum, ui8SlaveAddress);
+}
+
+//*****************************************************************************
+//
+//! Sets a slave's UDID structure.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pUDID is a pointer to the UDID configuration for the slave. This
+//! is only needed if the slave is on a bus that uses ARP.
+//!
+//! This function sets the UDID for a slave instance.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveUDIDSet(tSMBus *psSMBus, tSMBusUDID *pUDID)
+{
+ psSMBus->pUDID = pUDID;
+}
+
+//*****************************************************************************
+//
+//! Initializes an I2C slave peripheral for SMBus functionality.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui32I2CBase specifies the base address of the I2C slave peripheral.
+//!
+//! This function initializes an I2C peripheral for SMBus slave use. The
+//! instance-specific configuration structure is initialized to a set of known
+//! values and the I2C peripheral is configured based on the input arguments.
+//!
+//! The default configuration of the SMBus slave uses automatic
+//! acknowledgement. If manual acknowledgement is required, call
+//! SMBusSlaveManualACKEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveInit(tSMBus *psSMBus, uint32_t ui32I2CBase)
+{
+ //
+ // Initialize the configuration structure.
+ //
+ psSMBus->pUDID = 0;
+ psSMBus->ui32I2CBase = ui32I2CBase;
+ psSMBus->ui16Flags = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;
+ psSMBus->ui8OwnSlaveAddress = 0;
+ psSMBus->ui8TargetSlaveAddress = 0;
+ psSMBus->ui8CurrentCommand = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+
+ //
+ // Enable the I2C slave module. The slave is always enabled because the
+ // SMBus spec requires that all devices respond whne their slave address
+ // is put on the bus.
+ //
+ I2CSlaveEnable(psSMBus->ui32I2CBase);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/smbus.h b/utils/smbus.h
new file mode 100644
index 0000000..c483025
--- /dev/null
+++ b/utils/smbus.h
@@ -0,0 +1,463 @@
+//*****************************************************************************
+//
+// smbus.h - Prototypes for the SMBus driver.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SMBUS_H__
+#define __SMBUS_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup smbus_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure holds the SMBus Unique Device ID (UDID). For detailed
+//! information, please refer to the SMBus Specification.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Device capabilities field. This 8-bit field reports generic SMBus
+ //! capabilities such as address type for ARP.
+ //
+ uint8_t ui8DeviceCapabilities;
+
+ //
+ //! Version Revision field. This 8-bit field reports UDID revision
+ //! information as well as some vendor-specific things such as silicon
+ //! revision.
+ //
+ uint8_t ui8Version;
+
+ //
+ //! Vendor ID. This 16-bit field contains the manufacturer's ID as
+ //! assigned by the SBS Implementers' Forum of the PCI SIG.
+ //
+ uint16_t ui16VendorID;
+
+ //
+ //! Device ID. This 16-bit field contains the device ID assigned by the
+ //! device manufacturer.
+ //
+ uint16_t ui16DeviceID;
+
+ //
+ //! Interface. This 16-bit field identifies the protocol layer interfaces
+ //! supported over the SMBus connection.
+ //
+ uint16_t ui16Interface;
+
+ //
+ //! Subsystem Vendor ID. This 16-bit field holds additional information
+ //! that may be derived from the vendor ID or other information.
+ //
+ uint16_t ui16SubSystemVendorID;
+
+ //
+ //! Subsystem Device ID. This 16-bit field holds additional information
+ //! that may be derived from the device ID or other information.
+ //
+ uint16_t ui16SubSystemDeviceID;
+
+ //
+ //! Vendor-specific ID. This 32-bit field contains a unique number that
+ //! can be assigned per device by the manufacturer.
+ //
+ uint32_t ui32VendorSpecificID;
+}
+tSMBusUDID;
+
+//*****************************************************************************
+//
+//! This structure contains the state of a single instance of an SMBus module.
+//! Master and slave instances require unique configuration structures.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The SMBus Unique Device ID (UDID) for this SMBus instance. If
+ //! operating as a host, master-only, or on a bus that does not use Address
+ //! Resolution Protocol (ARP), this is not required. This member can be
+ //! set via a direct structure access or using the SMBusSlaveInit
+ //! function. For detailed information about the UDID, refer to the SMBus
+ //! spec.
+ //
+ tSMBusUDID *pUDID;
+
+ //
+ //! The base address of the I2C master peripheral. This member can be set
+ //! via a direct structure access or using the SMBusMasterInit or
+ //! SMBusSlaveInit functions.
+ //
+ uint32_t ui32I2CBase;
+
+ //
+ //! The address of the data buffer used for transmit operations. For
+ //! master operations, this member is set by the SMBusMasterxxxx functions
+ //! that pass a buffer pointer (for example, SMBusMasterBlockWrite). For
+ //! slave operations, this member can be set via direct structure access or
+ //! using the SMBusSlaveTxBufferSet function.
+ //
+ uint8_t *pui8TxBuffer;
+
+ //
+ //! The address of the data buffer used for receive operations. For master
+ //! operations, this member is set by the SMBusMasterxxxx functions that
+ //! pass a buffer pointer (for example, SMBusMasterBlockRead). For slave
+ //! operations, this member can be set via direct structure access or using
+ //! the SMBusSlaveRxBufferSet function.
+ //
+ uint8_t *pui8RxBuffer;
+
+ //
+ //! The amount of data to transmit from pui8TxBuffer. For master
+ //! operations this member is set by the SMBusMasterxxxx functions either
+ //! via an input argument (example SMBusMasterByteWordWrite) or explicitly
+ //! (example SMBusMasterSendByte). In master mode, this member should not
+ //! be accessed or modified by the application. For slave operations, this
+ //! member can be set via direct structure access of using the
+ //! SMBusSlaveTxBufferSet function.
+ //
+ uint8_t ui8TxSize;
+
+ //
+ //! The current index in the transmit buffer. This member should not be
+ //! accessed or modified by the application.
+ //
+ uint8_t ui8TxIndex;
+
+ //
+ //! The amount of data to receive into pui8RxBuffer. For master
+ //! operations, this member is set by the SMBusMasterxxxx functions either
+ //! via an input argument (example SMBusMasterByteWordRead), explicitly
+ //! (example SMBusMasterReceiveByte), or by the slave (example
+ //! SMBusMasterBlockRead). In master mode, this member should not be
+ //! accessed or modified by the application. For slave operations, this
+ //! member can be set via direct structure access of using the
+ //! SMBusSlaveRxBufferSet function.
+ //
+ uint8_t ui8RxSize;
+
+ //
+ //! The current index in the receive buffer. This member should not be
+ //! accessed or modified by the application.
+ //
+ uint8_t ui8RxIndex;
+
+ //
+ //! The active slave address of the I2C peripheral on the device.
+ //! When using dual address in slave mode, the active address is store
+ //! here. In master mode, this member is not used. This member is updated
+ //! as requests come in from the master.
+ //
+ uint8_t ui8OwnSlaveAddress;
+
+ //
+ //! The address of the targeted slave device. In master mode, this member
+ //! is set by the ui8TargetSlaveAddress argument in the SMBusMasterxxxx
+ //! transfer functions. In slave mode, it is not used. This member should
+ //! not be modified by the application.
+ //
+ uint8_t ui8TargetSlaveAddress;
+
+ //
+ //! The last used command. In master mode, this member is set by the
+ //! ui8Command argument in the SMBusMasterxxxx transfer functions. In
+ //! slave mode, the first received byte will always be considered the
+ //! command. This member should not be modified by the application.
+ //
+ uint8_t ui8CurrentCommand;
+
+ //
+ //! The running CRC calculation used for transfers that require Packet
+ //! Error Checking (PEC). This member is updated by the SMBus software and
+ //! should not be modified by the application.
+ //
+ uint8_t ui8CalculatedCRC;
+
+ //
+ //! The received CRC calculation used for transfers that require Packet
+ //! Error Checking (PEC). This member is updated by the SMBus software and
+ //! should not be modified by the application.
+ //
+ uint8_t ui8ReceivedCRC;
+
+ //
+ //! The current state of the SMBusMasterISRProcess state machine. This
+ //! member should not be accessed or modified by the application.
+ //
+ uint8_t ui8MasterState;
+
+ //
+ //! The current state of the SMBusSlaveISRProcess state machine. This
+ //! member should not be accessed or modified by the application.
+ //
+ uint8_t ui8SlaveState;
+
+ //
+ //! Flags used for various items in the SMBus state machines for different
+ //! transaction types and status.
+ //!
+ //! FLAG_PEC can be modified via the SMBusPECEnable or SMBusPECDisable
+ //! functions or via direct structure access.
+ //!
+ //! FLAG_BLOCK_TRANSFER can be set via the SMBusSlaveBlockTransferEnable
+ //! function and is cleared automatically by the SMBusSlaveTransferInit
+ //! function or manually using the SMBusSlaveBlockTransferDisable function.
+ //!
+ //! FLAG_RAW_I2C can be modified via the SMBusSlaveI2CEnable or
+ //! SMBusSlaveI2CDisable functions or via direct structure access.
+ //!
+ //! FLAG_TRANSFER_IN_PROGRESS should not be modified by the application,
+ //! but can be read via the SMBusStatusGet function.
+ //!
+ //! FLAG_PROCESS_CALL can be set via the SMBusSlaveProcessCallEnable
+ //! function and is cleared automatically by the SMBusSlaveTransferInit
+ //! function or manually using the SMBusSlaveProcessCallDisable function.
+ //!
+ //! FLAG_ADDRESS_RESOLVED is only used by an SMBus Slave that supports ARP.
+ //! This flag can be modified via the SMBusSlaveARPFlagARSet function and
+ //! read via SMBusSlaveARPFlagARGet. It can also be modified by direct
+ //! structure access.
+ //!
+ //! FLAG_ADDRESS_VALID is only used by an SMBus Slave that supports ARP.
+ //! This flag can be modified via the SMBusSlaveARPFlagAVSet function and
+ //! read via SMBusSlaveARPFlagAVGet. It can also be modified by direct
+ //! structure access.
+ //!
+ //! FLAG_ARP is used to indicate that ARP is currently active. This flag
+ //! is not used by the SMBus stack and can (optionally) be used by the
+ //! application to keep track of the ARP session.
+ //
+ uint16_t ui16Flags;
+}
+tSMBus;
+
+//*****************************************************************************
+//
+// ! Return codes.
+//
+//*****************************************************************************
+typedef enum
+{
+ SMBUS_OK = 0, // General "OK" return code
+ SMBUS_TIMEOUT, // Master detected bus timeout from slave
+ SMBUS_PERIPHERAL_BUSY, // The I2C peripheral is currently in use
+ SMBUS_BUS_BUSY, // The I2C bus is currently in use
+ SMBUS_ARB_LOST, // Bus arbitration was lost (master mode)
+ SMBUS_ADDR_ACK_ERROR, // In master mode, the address was NAK'd
+ SMBUS_DATA_ACK_ERROR, // Data transfer was NAK'd by receiver
+ SMBUS_PEC_ERROR, // PEC mismatch occurred
+ SMBUS_DATA_SIZE_ERROR, // Data size error has occurred
+ SMBUS_MASTER_ERROR, // Error occurred in the master ISR
+ SMBUS_SLAVE_ERROR, // Error occurred in the slave ISR
+ SMBUS_SLAVE_QCMD_0, // Slave transaction is Quick Command with
+ // data value 0.
+ SMBUS_SLAVE_QCMD_1, // Slave transaction is Quick Command with
+ // data value 1.
+ SMBUS_SLAVE_FIRST_BYTE, // The first byte has been received
+ SMBUS_SLAVE_ADDR_PRIMARY, // Primary address was detected
+ SMBUS_SLAVE_ADDR_SECONDARY, // Secondary address was detected
+ SMBUS_TRANSFER_IN_PROGRESS, // A transfer is currently in progress
+ SMBUS_TRANSFER_COMPLETE, // The last active transfer is complete
+ SMBUS_SLAVE_NOT_READY, // A slave transmit has been requested, but is
+ // not ready (TX buffer not set).
+ SMBUS_FIFO_ERROR, // A master receive operation did not receive
+ // enough data from the slave.
+}
+tSMBusStatus;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// ARP Commands
+//
+//*****************************************************************************
+#define SMBUS_CMD_PREPARE_TO_ARP 0x01
+#define SMBUS_CMD_ARP_RESET_DEVICE 0x02
+#define SMBUS_CMD_ARP_GET_UDID 0x03
+#define SMBUS_CMD_ARP_ASSIGN_ADDRESS 0x04
+
+//*****************************************************************************
+//
+// Fixed addresses defined by the SMBus specification.
+//
+//*****************************************************************************
+#define SMBUS_ADR_HOST 0x08
+#define SMBUS_ADR_SMART_BATTERY_CHARGER 0x09
+#define SMBUS_ADR_SMART_BATTERY_SELECTOR 0x0A
+#define SMBUS_ADR_SMART_BATTERY 0x0B
+#define SMBUS_ADR_DEFAULT_DEVICE 0x61
+
+//*****************************************************************************
+//
+// API Function prototypes
+//
+//*****************************************************************************
+extern void SMBusPECEnable(tSMBus *psSMBus);
+extern void SMBusPECDisable(tSMBus *psSMBus);
+extern void SMBusARPEnable(tSMBus *psSMBus);
+extern void SMBusARPDisable(tSMBus *psSMBus);
+extern tSMBusStatus SMBusStatusGet(tSMBus *psSMBus);
+extern void SMBusARPUDIDPacketEncode(tSMBusUDID *pUDID,
+ uint8_t ui8Address,
+ uint8_t *pui8Data);
+extern void SMBusARPUDIDPacketDecode(tSMBusUDID *pUDID,
+ uint8_t *pui8Address,
+ uint8_t *pui8Data);
+extern uint8_t SMBusRxPacketSizeGet(tSMBus *psSMBus);
+extern void SMBusUDIDDataGet(tSMBus *psSMBus, tSMBusUDID *pUDID);
+extern tSMBusStatus SMBusMasterQuickCommand(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ bool bData);
+extern tSMBusStatus SMBusMasterByteSend(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Data);
+extern tSMBusStatus SMBusMasterByteReceive(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterByteWordWrite(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern tSMBusStatus SMBusMasterBlockWrite(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern tSMBusStatus SMBusMasterByteWordRead(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern tSMBusStatus SMBusMasterBlockRead(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterProcessCall(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8TxData,
+ uint8_t *pui8RxData);
+extern tSMBusStatus SMBusMasterBlockProcessCall(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8TxData,
+ uint8_t ui8TxSize,
+ uint8_t *pui8RxData);
+extern tSMBusStatus SMBusMasterHostNotify(tSMBus *psSMBus,
+ uint8_t ui8OwnSlaveAddress,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterI2CWrite(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern tSMBusStatus SMBusMasterI2CRead(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern tSMBusStatus SMBusMasterI2CWriteRead(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t *pui8TxData,
+ uint8_t ui8TxSize,
+ uint8_t *pui8RxData,
+ uint8_t ui8RxSize);
+extern tSMBusStatus SMBusMasterARPGetUDIDGen(tSMBus *psSMBus,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterARPGetUDIDDir(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterARPResetDeviceGen(tSMBus *psSMBus);
+extern tSMBusStatus SMBusMasterARPResetDeviceDir(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress);
+extern tSMBusStatus SMBusMasterARPAssignAddress(tSMBus *psSMBus,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterARPNotifyMaster(tSMBus *psSMBus,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterARPPrepareToARP(tSMBus *psSMBus);
+extern tSMBusStatus SMBusMasterIntProcess(tSMBus *psSMBus);
+extern void SMBusMasterIntEnable(tSMBus *psSMBus);
+extern void SMBusMasterInit(tSMBus *psSMBus, uint32_t ui32I2CBase,
+ uint32_t ui32SMBusClock);
+extern void SMBusSlaveTxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern void SMBusSlaveRxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern uint8_t SMBusSlaveCommandGet(tSMBus *psSMBus);
+extern void SMBusSlaveProcessCallEnable(tSMBus *psSMBus);
+extern void SMBusSlaveProcessCallDisable(tSMBus *psSMBus);
+extern void SMBusSlaveBlockTransferEnable(tSMBus *psSMBus);
+extern void SMBusSlaveBlockTransferDisable(tSMBus *psSMBus);
+extern void SMBusSlaveI2CEnable(tSMBus *psSMBus);
+extern void SMBusSlaveI2CDisable(tSMBus *psSMBus);
+extern void SMBusSlaveARPFlagARSet(tSMBus *psSMBus, bool bValue);
+extern bool SMBusSlaveARPFlagARGet(tSMBus *psSMBus);
+extern void SMBusSlaveARPFlagAVSet(tSMBus *psSMBus, bool bValue);
+extern bool SMBusSlaveARPFlagAVGet(tSMBus *psSMBus);
+extern void SMBusSlaveTransferInit(tSMBus *psSMBus);
+extern tSMBusStatus SMBusSlaveIntProcess(tSMBus *psSMBus);
+extern tSMBusStatus SMBusSlaveDataSend(tSMBus *psSMBus);
+extern void SMBusSlaveACKSend(tSMBus *psSMBus, bool bACK);
+extern void SMBusSlaveManualACKEnable(tSMBus *psSMBus);
+extern void SMBusSlaveManualACKDisable(tSMBus *psSMBus);
+extern bool SMBusSlaveManualACKStatusGet(tSMBus *psSMBus);
+extern tSMBusStatus SMBusSlaveIntAddressGet(tSMBus *psSMBus);
+extern void SMBusSlaveIntEnable(tSMBus *psSMBus);
+extern void SMBusSlaveUDIDSet(tSMBus *psSMBus, tSMBusUDID *pUDID);
+extern void SMBusSlaveAddressSet(tSMBus *psSMBus, uint8_t ui8AddressNum,
+ uint8_t ui8SlaveAddress);
+extern void SMBusSlaveInit(tSMBus *psSMBus, uint32_t ui32I2CBase);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SMBUS_H__
diff --git a/utils/softi2c.c b/utils/softi2c.c
new file mode 100644
index 0000000..ab3e5a6
--- /dev/null
+++ b/utils/softi2c.c
@@ -0,0 +1,1321 @@
+//*****************************************************************************
+//
+// softi2c.c - Driver for the SoftI2C.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup softi2c_api
+//! @{
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/gpio.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "utils/softi2c.h"
+
+//*****************************************************************************
+//
+// The states in the SoftI2C state machine. The code depends upon the fact
+// that the value of STATE_X1 is exactly one greater than STATE_X0 (for any
+// value of X and for any following digit)...however there is no dependence on
+// the values of STATE_Xn and STATE_Yn.
+//
+//*****************************************************************************
+#define SOFTI2C_STATE_IDLE 0
+#define SOFTI2C_STATE_START0 1
+#define SOFTI2C_STATE_START1 2
+#define SOFTI2C_STATE_START2 3
+#define SOFTI2C_STATE_START3 4
+#define SOFTI2C_STATE_START4 5
+#define SOFTI2C_STATE_START5 6
+#define SOFTI2C_STATE_START6 7
+#define SOFTI2C_STATE_START7 8
+#define SOFTI2C_STATE_ADDR0 9
+#define SOFTI2C_STATE_ADDR1 10
+#define SOFTI2C_STATE_ADDR2 11
+#define SOFTI2C_STATE_ADDR3 12
+#define SOFTI2C_STATE_SEND0 13
+#define SOFTI2C_STATE_SEND1 14
+#define SOFTI2C_STATE_SEND2 15
+#define SOFTI2C_STATE_SEND3 16
+#define SOFTI2C_STATE_RECV0 17
+#define SOFTI2C_STATE_RECV1 18
+#define SOFTI2C_STATE_RECV2 19
+#define SOFTI2C_STATE_RECV3 20
+#define SOFTI2C_STATE_STOP0 21
+#define SOFTI2C_STATE_STOP1 22
+#define SOFTI2C_STATE_STOP2 23
+#define SOFTI2C_STATE_STOP3 24
+#define SOFTI2C_STATE_STOP4 25
+
+//*****************************************************************************
+//
+// The flags in the SoftI2C ui8Flags structure member. The first four flags,
+// RUN, START, STOP, and ACK, must match with the definitions of the
+// SOFTI2C_CMD_* commands in softi2c.h.
+//
+//*****************************************************************************
+#define SOFTI2C_FLAG_RUN 0
+#define SOFTI2C_FLAG_START 1
+#define SOFTI2C_FLAG_STOP 2
+#define SOFTI2C_FLAG_ACK 3
+#define SOFTI2C_FLAG_ADDR_ACK 5
+#define SOFTI2C_FLAG_DATA_ACK 6
+#define SOFTI2C_FLAG_RECEIVE 7
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! This function performs the periodic, time-based updates to the SoftI2C
+//! module. The transmission and reception of data over the SoftI2C link is
+//! performed by the state machine in this function.
+//!
+//! This function must be called at four times the desired SoftI2C clock rate.
+//! For example, to run the SoftI2C clock at 10 KHz, this function must be
+//! called at a 40 KHz rate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CTimerTick(tSoftI2C *psI2C)
+{
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(psI2C->ui8State)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTI2C_STATE_IDLE:
+ {
+ //
+ // See if the START flag is set, indicating that a start condition
+ // should be generated.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_START) == 1)
+ {
+ //
+ // Based on the current state of the SCL and SDA pins, pick the
+ // appropriate place within the state machine to begin the
+ // start/repeated-start signalling.
+ //
+ if(HWREG(psI2C->ui32SCLGPIO) != 0)
+ {
+ psI2C->ui8State = SOFTI2C_STATE_START4;
+ }
+ else if(HWREG(psI2C->ui32SDAGPIO) == 0)
+ {
+ psI2C->ui8State = SOFTI2C_STATE_START0;
+ }
+ else
+ {
+ psI2C->ui8State = SOFTI2C_STATE_START2;
+ }
+ }
+
+ //
+ // Otherwise, see if the RUN flag is set, indicating that a data
+ // byte should be transferred.
+ //
+ else if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RUN) == 1)
+ {
+ //
+ // Start the transfer from the first bit.
+ //
+ psI2C->ui8CurrentBit = 0;
+
+ //
+ // See if a byte should be sent or received.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RECEIVE) == 0)
+ {
+ //
+ // A byte should be sent.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_SEND0;
+ }
+ else
+ {
+ //
+ // A byte should be received. Clear out the receive data
+ // buffer in preparation for receiving the new byte.
+ //
+ psI2C->ui8Data = 0;
+ psI2C->ui8State = SOFTI2C_STATE_RECV0;
+ }
+ }
+
+ //
+ // Otherwise, see if the STOP flag is set, indicating that a stop
+ // condition should be generated.
+ //
+ else if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Generate a stop condition.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // See if the SoftI2C state machine has left the idle state.
+ //
+ if(psI2C->ui8State != SOFTI2C_STATE_IDLE)
+ {
+ //
+ // The address and data ACK error flags should be cleared; they
+ // will be set if appropriate while the current command is
+ // being executed.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_ADDR_ACK) = 0;
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_DATA_ACK) = 0;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The beginning of the start condition sequence when SDA and SCL are
+ // low. SDA must be driven high prior to driving SCL high so that a
+ // repeated-start is generated, instead of a stop then start.
+ //
+ case SOFTI2C_STATE_START0:
+ {
+ //
+ // Set SDA high.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 255;
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_START1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // Each of these states exists only to provide some timing delay in
+ // order to conform with the signalling requirements of I2C. This
+ // depends upon STATE_Xn and STATE_X(n+1) being consecutively numbered.
+ //
+ case SOFTI2C_STATE_START1:
+ case SOFTI2C_STATE_START3:
+ case SOFTI2C_STATE_START5:
+ case SOFTI2C_STATE_STOP1:
+ case SOFTI2C_STATE_STOP3:
+ {
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, SCL must be driven high. This depends upon
+ // STATE_Xn and STATE_X(n+1) being consecutively numbered.
+ //
+ case SOFTI2C_STATE_START2:
+ case SOFTI2C_STATE_ADDR1:
+ case SOFTI2C_STATE_SEND1:
+ case SOFTI2C_STATE_RECV1:
+ case SOFTI2C_STATE_STOP2:
+ {
+ //
+ // Set SCL high.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 255;
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, SDA must be driven low. This depends upon
+ // STATE_Xn and STATE_X(n+1) being consecutively numbered.
+ //
+ case SOFTI2C_STATE_START4:
+ case SOFTI2C_STATE_STOP0:
+ {
+ //
+ // Set SDA low.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 0;
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low.
+ //
+ case SOFTI2C_STATE_START6:
+ {
+ //
+ // Set SCL low.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 0;
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_START7;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the start condition has been generated.
+ //
+ case SOFTI2C_STATE_START7:
+ {
+ //
+ // Start with the first bit of the address.
+ //
+ psI2C->ui8CurrentBit = 0;
+
+ //
+ // Advance to the address output state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_ADDR0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the next bit of the slave address must be sent.
+ //
+ case SOFTI2C_STATE_ADDR0:
+ {
+ //
+ // See if this is one of the first seven bits of the address phase.
+ //
+ if(psI2C->ui8CurrentBit < 7)
+ {
+ //
+ // Write the next bit of the slave address to SDA.
+ //
+ HWREG(psI2C->ui32SDAGPIO) =
+ ((psI2C->ui8SlaveAddr &
+ (1 << (6 - psI2C->ui8CurrentBit))) ? 255 : 0);
+ }
+
+ //
+ // Otherwise, see if this is the eight bit of the address phase
+ // (which is the read/not write bit).
+ //
+ else if(psI2C->ui8CurrentBit == 7)
+ {
+ //
+ // Write the read/not write bit to SDA.
+ //
+ HWREG(psI2C->ui32SDAGPIO) =
+ (HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RECEIVE) ?
+ 255 : 0);
+ }
+
+ //
+ // Otherwise, this is the ninth bit of the address phase (in other
+ // words, the ACK bit).
+ //
+ else
+ {
+ //
+ // Change the SDA GPIO into an input so that the ACK or NAK
+ // provided by the slave can be read.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_IN);
+ }
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_ADDR1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, wait until SCL has gone high (it has been
+ // released by the SoftI2C master, but may be held low by the slave).
+ // This depends upon STATE_Xn and STATE_X(n+1) being consecutively
+ // numbered.
+ //
+ case SOFTI2C_STATE_ADDR2:
+ case SOFTI2C_STATE_SEND2:
+ case SOFTI2C_STATE_RECV2:
+ {
+ //
+ // See if SCL has gone high.
+ //
+ if(HWREG(psI2C->ui32SCLGPIO) != 0)
+ {
+ //
+ // Advance to the next state now that SCL has gone high.
+ //
+ psI2C->ui8State++;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low. If on the ninth bit of the
+ // address transfer, the ACK/NAK status is read from the slave.
+ //
+ case SOFTI2C_STATE_ADDR3:
+ {
+ //
+ // See if this is the ninth bit of the address phase (in other
+ // words, the ACK bit).
+ //
+ if(psI2C->ui8CurrentBit == 8)
+ {
+ //
+ // See if the SDA line is high.
+ //
+ if(HWREG(psI2C->ui32SDAGPIO) != 0)
+ {
+ //
+ // Since the SDA line is high, the address byte has not
+ // been ACKed by any slave.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_ADDR_ACK) = 1;
+ }
+
+ //
+ // Change the SDA GPIO back into an output.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+
+ //
+ // The start phase (start or repeated-start, plus the address
+ // byte) have completed, so clear the START flag.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_START) = 0;
+
+ //
+ // See if the RUN flag is set, indicating that a data byte
+ // should be transferred as well.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RUN) == 1)
+ {
+ //
+ // Reset the current bit to zero for the start of the data
+ // phase.
+ //
+ psI2C->ui8CurrentBit = 0;
+
+ //
+ // See if the data byte is being sent or received.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags),
+ SOFTI2C_FLAG_RECEIVE) == 0)
+ {
+ //
+ // The data byte is being sent, so advance to the data
+ // send state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_SEND0;
+ }
+ else
+ {
+ //
+ // The data byte is being received, so clear the data
+ // buffer and advance to the data receive state.
+ //
+ psI2C->ui8Data = 0;
+ psI2C->ui8State = SOFTI2C_STATE_RECV0;
+ }
+ }
+
+ //
+ // Otherwise, see if the STOP flag is set, indicating that a
+ // stop condition should be generated.
+ //
+ else if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Advance to the stop state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // Otherwise, go to the idle state.
+ //
+ else
+ {
+ //
+ // Since the requested operations have completed, set the
+ // SoftI2C ``interrupt''.
+ //
+ psI2C->ui8IntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_IDLE;
+ }
+ }
+
+ //
+ // Otherwise, the next bit of the address should be transferred.
+ //
+ else
+ {
+ //
+ // Increment the bit count.
+ //
+ psI2C->ui8CurrentBit++;
+
+ //
+ // Advance to the address tranfer state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_ADDR0;
+ }
+
+ //
+ // Set SCL low.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the next bit of the data byte must be sent.
+ //
+ case SOFTI2C_STATE_SEND0:
+ {
+ //
+ // See if this is one of the first eight bits of the data phase.
+ //
+ if(psI2C->ui8CurrentBit < 8)
+ {
+ //
+ // Write the next bit of the data byte to SDA.
+ //
+ HWREG(psI2C->ui32SDAGPIO) =
+ ((psI2C->ui8Data &
+ (1 << (7 - psI2C->ui8CurrentBit))) ? 255 : 0);
+ }
+
+ //
+ // Otherwise, this is the ninth bit of the data phase (in other
+ // words, the ACK bit).
+ //
+ else
+ {
+ //
+ // Change the SDA GPIO into an input so that the ACK or NAK
+ // provided by the slave can be read.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_IN);
+ }
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_SEND1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low. If on the ninth bit of the
+ // data transfer, the ACK/NAK status is read from the slave.
+ //
+ case SOFTI2C_STATE_SEND3:
+ {
+ //
+ // See if this is the ninth bit of the data phase (in other words,
+ // the ACK bit).
+ //
+ if(psI2C->ui8CurrentBit == 8)
+ {
+ //
+ // See if the SDA line is high.
+ //
+ if(HWREG(psI2C->ui32SDAGPIO) != 0)
+ {
+ //
+ // Since the SDA line is high, the data byte has not been
+ // ACKed by the slave.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_DATA_ACK) = 1;
+ }
+
+ //
+ // Change the SDA GPIO back into an output.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+
+ //
+ // The data phase has completed, so clear the RUN flag.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RUN) = 0;
+
+ //
+ // See if the STOP flag is set, indicating that a stop
+ // condition should be generated.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Advance to the stop state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // Otherwise, go to the idle state.
+ //
+ else
+ {
+ //
+ // Since the requested operations have completed, set the
+ // SoftI2C ``interrupt''.
+ //
+ psI2C->ui8IntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_IDLE;
+ }
+ }
+
+ //
+ // Otherwise, the next bit of the data should be transferred.
+ //
+ else
+ {
+ //
+ // Increment the bit count.
+ //
+ psI2C->ui8CurrentBit++;
+
+ //
+ // Advance to the data transmit state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_SEND0;
+ }
+
+ //
+ // Set SCL low.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the next bit of the data byte must be received.
+ //
+ case SOFTI2C_STATE_RECV0:
+ {
+ //
+ // See if this is the first bit of the data phase.
+ //
+ if(psI2C->ui8CurrentBit == 0)
+ {
+ //
+ // Change the SDA GPIO into an input so that the data provided
+ // by the slave can be read.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_IN);
+ }
+
+ //
+ // Otherwise, see if this is the ninth bit of the data phase (in
+ // other words, the ACK bit).
+ //
+ else if(psI2C->ui8CurrentBit == 8)
+ {
+ //
+ // Change the SDA GPIO into an output so that the ACK bit can
+ // be driven to the slave.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+
+ //
+ // See if this byte should be ACKed or NAKed.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_ACK) == 1)
+ {
+ //
+ // Drive SDA low to ACK the data byte.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 0;
+ }
+ else
+ {
+ //
+ // Allow SDA to get pulled high to NAK the data byte.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 255;
+ }
+ }
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_RECV1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low. For the first eight bits of
+ // the data transfer, the data bits are read from the slave.
+ //
+ case SOFTI2C_STATE_RECV3:
+ {
+ //
+ // See if this is the ninth bit of the data phase (in other words,
+ // the ACK bit).
+ //
+ if(psI2C->ui8CurrentBit == 8)
+ {
+ //
+ // The data phase has completed, so clear the RUN flag.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RUN) = 0;
+
+ //
+ // See if the STOP flag is set, indicating that a stop
+ // condition should be generated.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Advance to the stop state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // Otherwise, go to the idle state.
+ //
+ else
+ {
+ //
+ // Since the requested operations have completed, set the
+ // SoftI2C ``interrupt''.
+ //
+ psI2C->ui8IntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_IDLE;
+ }
+ }
+
+ //
+ // Otherwise, the next bit of the data should be transferred.
+ //
+ else
+ {
+ //
+ // Read the next bit of data from the SDA line.
+ //
+ psI2C->ui8Data |= (HWREG(psI2C->ui32SDAGPIO) ?
+ (1 << (7 - psI2C->ui8CurrentBit)) : 0);
+
+ //
+ // Increment the bit count.
+ //
+ psI2C->ui8CurrentBit++;
+
+ //
+ // Advance to the data receive state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_RECV0;
+ }
+
+ //
+ // Set SCL low.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SDA must be driven high to create the stop condition.
+ //
+ case SOFTI2C_STATE_STOP4:
+ {
+ //
+ // Set SDA high to create the stop condition.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 255;
+
+ //
+ // The stop condition has been generated, so clear the STOP flag.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_STOP) = 0;
+
+ //
+ // Since the requested operations have completed, set the SoftI2C
+ // ``interrupt''.
+ //
+ psI2C->ui8IntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_IDLE;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the I2C peripheral.
+ //
+ while(((psI2C->ui8IntStatus & psI2C->ui8IntMask) != 0) &&
+ (psI2C->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ psI2C->pfnIntCallback();
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! This function initializes operation of the SoftI2C module. After
+//! successful initialization of the SoftI2C module, the software I2C bus is in
+//! the idle state.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CInit(tSoftI2C *psI2C)
+{
+ //
+ // Configure the SCL pin.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SCLGPIO & 0xfffff000,
+ (psI2C->ui32SCLGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+ MAP_GPIOPadConfigSet(psI2C->ui32SCLGPIO & 0xfffff000,
+ (psI2C->ui32SCLGPIO & 0x00000fff) >> 2,
+ GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_OD);
+
+ //
+ // Set the SCL pin high.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 255;
+
+ //
+ // Configure the SDA pin.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+ MAP_GPIOPadConfigSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_OD);
+
+ //
+ // Set the SDA pin high.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 255;
+
+ //
+ // The ``interrupt'' is not asserted at the start.
+ //
+ psI2C->ui8IntStatus = 0;
+
+ //
+ // There are no flags at the start.
+ //
+ psI2C->ui8Flags = 0;
+
+ //
+ // Start the SoftI2C state machine in the idle state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_IDLE;
+}
+
+//*****************************************************************************
+//
+//! Sets the callback used by the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param pfnCallback is a pointer to the callback function.
+//!
+//! This function sets the address of the callback function that is called when
+//! there is an ``interrupt'' produced by the SoftI2C module.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CCallbackSet(tSoftI2C *psI2C, void (*pfnCallback)(void))
+{
+ //
+ // Save the callback function address.
+ //
+ psI2C->pfnIntCallback = pfnCallback;
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftI2C SCL signal.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftI2C SCL signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CSCLGPIOSet(tSoftI2C *psI2C, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the SCL signal.
+ //
+ psI2C->ui32SCLGPIO = ui32Base + (ui8Pin << 2);
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftI2C SDA signal.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftI2C SDA signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CSDAGPIOSet(tSoftI2C *psI2C, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the SDA signal.
+ //
+ psI2C->ui32SDAGPIO = ui32Base + (ui8Pin << 2);
+}
+
+//*****************************************************************************
+//
+//! Enables the SoftI2C ``interrupt''.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! Enables the SoftI2C ``interrupt'' source.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CIntEnable(tSoftI2C *psI2C)
+{
+ //
+ // Enable the master interrupt.
+ //
+ psI2C->ui8IntMask = 1;
+}
+
+//*****************************************************************************
+//
+//! Disables the SoftI2C ``interrupt''.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! Disables the SoftI2C ``interrupt'' source.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CIntDisable(tSoftI2C *psI2C)
+{
+ //
+ // Disable the master interrupt.
+ //
+ psI2C->ui8IntMask = 0;
+}
+
+//*****************************************************************************
+//
+//! Gets the current SoftI2C ``interrupt'' status.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param bMasked is \b false if the raw ``interrupt'' status is requested and
+//! \b true if the masked ``interrupt'' status is requested.
+//!
+//! This returns the ``interrupt'' status for the SoftI2C module. Either the
+//! raw ``interrupt'' status or the status of ``interrupts'' that are allowed
+//! to reflect to the processor can be returned.
+//!
+//! \return The current interrupt status, returned as \b true if active
+//! or \b false if not active.
+//
+//*****************************************************************************
+bool
+SoftI2CIntStatus(tSoftI2C *psI2C, bool bMasked)
+{
+ //
+ // Return either the interrupt status or the raw interrupt status as
+ // requested.
+ //
+ if(bMasked)
+ {
+ return((psI2C->ui8IntStatus & psI2C->ui8IntMask) ? true : false);
+ }
+ else
+ {
+ return(psI2C->ui8IntStatus ? true : false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Clears the SoftI2C ``interrupt''.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! The SoftI2C ``interrupt'' source is cleared, so that it no longer asserts.
+//! This function must be called in the ``interrupt'' handler to keep it from
+//! being called again immediately on exit.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CIntClear(tSoftI2C *psI2C)
+{
+ //
+ // Clear the SoftI2C interrupt source.
+ //
+ psI2C->ui8IntStatus = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the address that the SoftI2C module places on the bus.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param ui8SlaveAddr 7-bit slave address
+//! \param bReceive flag indicating the type of communication with the slave.
+//!
+//! This function sets the address that the SoftI2C module places on the bus
+//! when initiating a transaction. When the \e bReceive parameter is set to
+//! \b true, the address indicates that the SoftI2C moudle is initiating a read
+//! from the slave; otherwise the address indicates that the SoftI2C module is
+//! initiating a write to the slave.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CSlaveAddrSet(tSoftI2C *psI2C, uint8_t ui8SlaveAddr,
+ bool bReceive)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(!(ui8SlaveAddr & 0x80));
+
+ //
+ // Set the address of the slave with which the master will communicate.
+ //
+ psI2C->ui8SlaveAddr = ui8SlaveAddr;
+
+ //
+ // Set a flag to indicate if this is a transmit or receive.
+ //
+ if(bReceive)
+ {
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RECEIVE) = 1;
+ }
+ else
+ {
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RECEIVE) = 0;
+ }
+}
+
+//*****************************************************************************
+//
+//! Indicates whether or not the SoftI2C module is busy.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! This function returns an indication of whether or not the SoftI2C module is
+//! busy transmitting or receiving data.
+//!
+//! \return Returns \b true if the SoftI2C module is busy; otherwise, returns
+//! \b false.
+//
+//*****************************************************************************
+bool
+SoftI2CBusy(tSoftI2C *psI2C)
+{
+ //
+ // Return the busy status.
+ //
+ if(psI2C->ui8State != SOFTI2C_STATE_IDLE)
+ {
+ return(true);
+ }
+ else
+ {
+ return(false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Controls the state of the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param ui32Cmd command to be issued to the SoftI2C module.
+//!
+//! This function is used to control the state of the SoftI2C module send and
+//! receive operations. The \e ui8Cmd parameter can be one of the following
+//! values:
+//!
+//! - \b SOFTI2C_CMD_SINGLE_SEND
+//! - \b SOFTI2C_CMD_SINGLE_RECEIVE
+//! - \b SOFTI2C_CMD_BURST_SEND_START
+//! - \b SOFTI2C_CMD_BURST_SEND_CONT
+//! - \b SOFTI2C_CMD_BURST_SEND_FINISH
+//! - \b SOFTI2C_CMD_BURST_SEND_ERROR_STOP
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_START
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_CONT
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_FINISH
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_ERROR_STOP
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CControl(tSoftI2C *psI2C, uint32_t ui32Cmd)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ui32Cmd == SOFTI2C_CMD_SINGLE_SEND) ||
+ (ui32Cmd == SOFTI2C_CMD_SINGLE_RECEIVE) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_SEND_START) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_SEND_CONT) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_SEND_FINISH) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_SEND_ERROR_STOP) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_RECEIVE_START) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_RECEIVE_CONT) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_RECEIVE_FINISH) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_RECEIVE_ERROR_STOP));
+
+ //
+ // Send the command.
+ //
+ psI2C->ui8Flags = (psI2C->ui8Flags & 0xf0) | ui32Cmd;
+}
+
+//*****************************************************************************
+//
+//! Gets the error status of the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! This function is used to obtain the error status of the SoftI2C module send
+//! and receive operations.
+//!
+//! \return Returns the error status, as one of \b SOFTI2C_ERR_NONE,
+//! \b SOFTI2C_ERR_ADDR_ACK, or \b SOFTI2C_ERR_DATA_ACK.
+//
+//*****************************************************************************
+uint32_t
+SoftI2CErr(tSoftI2C *psI2C)
+{
+ //
+ // If the SoftI2C is busy, there is no error to report.
+ //
+ if(psI2C->ui8State != SOFTI2C_STATE_IDLE)
+ {
+ return(SOFTI2C_ERR_NONE);
+ }
+
+ //
+ // Return any errors that may have occurred.
+ //
+ return((HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_ADDR_ACK) ?
+ SOFTI2C_ERR_ADDR_ACK : 0) |
+ (HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_DATA_ACK) ?
+ SOFTI2C_ERR_DATA_ACK : 0));
+}
+
+//*****************************************************************************
+//
+//! Transmits a byte from the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param ui8Data data to be transmitted from the SoftI2C module.
+//!
+//! This function places the supplied data into SoftI2C module in preparation
+//! for being transmitted via an appropriate call to SoftI2CControl().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CDataPut(tSoftI2C *psI2C, uint8_t ui8Data)
+{
+ //
+ // Write the byte.
+ //
+ psI2C->ui8Data = ui8Data;
+}
+
+//*****************************************************************************
+//
+//! Receives a byte that has been sent to the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! This function reads a byte of data from the SoftI2C module that was
+//! received as a result of an appropriate call to SoftI2CControl().
+//!
+//! \return Returns the byte received by the SoftI2C module, cast as an
+//! uint32_t.
+//
+//*****************************************************************************
+uint32_t
+SoftI2CDataGet(tSoftI2C *psI2C)
+{
+ //
+ // Read a byte.
+ //
+ return(psI2C->ui8Data);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/softi2c.h b/utils/softi2c.h
new file mode 100644
index 0000000..0ac876a
--- /dev/null
+++ b/utils/softi2c.h
@@ -0,0 +1,195 @@
+//*****************************************************************************
+//
+// softi2c.h - Defines and macros for the SoftI2C.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SOFTI2C_H__
+#define __SOFTI2C_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup softi2c_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure contains the state of a single instance of a SoftI2C module.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The address of the callback function that is called to simulate the
+ //! interrupts that would be produced by a hardware I2C implementation.
+ //! This address can be set via a direct structure access or using the
+ //! SoftI2CCallbackSet function.
+ //
+ void (*pfnIntCallback)(void);
+
+ //
+ //! The address of the GPIO pin to be used for the SCL signal. This member
+ //! can be set via a direct structure access or using the SoftI2CSCLGPIOSet
+ //! function.
+ //
+ uint32_t ui32SCLGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the SDA signal. This member
+ //! can be set via a direct structure access or using the SoftI2CSDAGPIOSet
+ //! function.
+ ///
+ uint32_t ui32SDAGPIO;
+
+ //
+ //! The flags that control the operation of the SoftI2C module. This
+ //! member should not be accessed or modified by the application.
+ //
+ uint8_t ui8Flags;
+
+ //
+ //! The slave address that is currently being accessed. This member should
+ //! not be accessed or modified by the application.
+ //
+ uint8_t ui8SlaveAddr;
+
+ //
+ //! The data that is currently being transmitted or received. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8Data;
+
+ //
+ //! The current state of the SoftI2C state machine. This member should not
+ //! be accessed or modified by the application.
+ //
+ uint8_t ui8State;
+
+ //
+ //! The number of bits that have been transmitted and received in the
+ //! current frame. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint8_t ui8CurrentBit;
+
+ //
+ //! The set of virtual interrupts that should be sent to the callback
+ //! function. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint8_t ui8IntMask;
+
+ //
+ //! The set of virtual interrupts that are currently asserted. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8IntStatus;
+}
+tSoftI2C;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// SoftI2C commands.
+//
+//*****************************************************************************
+#define SOFTI2C_CMD_SINGLE_SEND 0x00000007
+#define SOFTI2C_CMD_SINGLE_RECEIVE \
+ 0x00000007
+#define SOFTI2C_CMD_BURST_SEND_START \
+ 0x00000003
+#define SOFTI2C_CMD_BURST_SEND_CONT \
+ 0x00000001
+#define SOFTI2C_CMD_BURST_SEND_FINISH \
+ 0x00000005
+#define SOFTI2C_CMD_BURST_SEND_ERROR_STOP \
+ 0x00000004
+#define SOFTI2C_CMD_BURST_RECEIVE_START \
+ 0x0000000b
+#define SOFTI2C_CMD_BURST_RECEIVE_CONT \
+ 0x00000009
+#define SOFTI2C_CMD_BURST_RECEIVE_FINISH \
+ 0x00000005
+#define SOFTI2C_CMD_BURST_RECEIVE_ERROR_STOP \
+ 0x00000004
+
+//*****************************************************************************
+//
+// SoftI2C error status.
+//
+//*****************************************************************************
+#define SOFTI2C_ERR_NONE 0x00000000
+#define SOFTI2C_ERR_ADDR_ACK 0x00000004
+#define SOFTI2C_ERR_DATA_ACK 0x00000008
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern bool SoftI2CBusy(tSoftI2C *psI2C);
+extern void SoftI2CCallbackSet(tSoftI2C *psI2C, void (*pfnCallback)(void));
+extern void SoftI2CControl(tSoftI2C *psI2C, uint32_t ui32Cmd);
+extern uint32_t SoftI2CDataGet(tSoftI2C *psI2C);
+extern void SoftI2CDataPut(tSoftI2C *psI2C, uint8_t ui8Data);
+extern uint32_t SoftI2CErr(tSoftI2C *psI2C);
+extern void SoftI2CInit(tSoftI2C *psI2C);
+extern void SoftI2CIntClear(tSoftI2C *psI2C);
+extern void SoftI2CIntDisable(tSoftI2C *psI2C);
+extern void SoftI2CIntEnable(tSoftI2C *psI2C);
+extern bool SoftI2CIntStatus(tSoftI2C *psI2C, bool bMasked);
+extern void SoftI2CSCLGPIOSet(tSoftI2C *psI2C, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftI2CSDAGPIOSet(tSoftI2C *psI2C, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftI2CSlaveAddrSet(tSoftI2C *psI2C, uint8_t ui8SlaveAddr,
+ bool bReceive);
+extern void SoftI2CTimerTick(tSoftI2C *psI2C);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFTI2C_H__
diff --git a/utils/softssi.c b/utils/softssi.c
new file mode 100644
index 0000000..d2a155c
--- /dev/null
+++ b/utils/softssi.c
@@ -0,0 +1,1297 @@
+//*****************************************************************************
+//
+// softssi.c - Driver for the SoftSSI.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup softssi_api
+//! @{
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/gpio.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "utils/softssi.h"
+
+//*****************************************************************************
+//
+// The states in the SoftSSI state machine.
+//
+//*****************************************************************************
+#define SOFTSSI_STATE_IDLE 0
+#define SOFTSSI_STATE_START 1
+#define SOFTSSI_STATE_IN 2
+#define SOFTSSI_STATE_OUT 3
+#define SOFTSSI_STATE_STOP1 4
+#define SOFTSSI_STATE_STOP2 5
+
+//*****************************************************************************
+//
+// The flags in the SoftSSI ui8Flags structure member.
+//
+//*****************************************************************************
+#define SOFTSSI_FLAG_ENABLE 0x80
+#define SOFTSSI_FLAG_SPH 0x02
+#define SOFTSSI_FLAG_SPO 0x01
+
+//*****************************************************************************
+//
+//! Sets the configuration of a SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui8Protocol specifes the data transfer protocol.
+//! \param ui8Bits specifies the number of bits transferred per frame.
+//!
+//! This function configures the data format of a SoftSSI module. The
+//! \e ui8Protocol parameter can be one of the following values:
+//! \b SOFTSSI_FRF_MOTO_MODE_0, \b SOFTSSI_FRF_MOTO_MODE_1,
+//! \b SOFTSSI_FRF_MOTO_MODE_2, or \b SOFTSSI_FRF_MOTO_MODE_3. These frame
+//! formats imply the following polarity and phase configurations:
+//!
+//! <pre>
+//! Polarity Phase Mode
+//! 0 0 SOFTSSI_FRF_MOTO_MODE_0
+//! 0 1 SOFTSSI_FRF_MOTO_MODE_1
+//! 1 0 SOFTSSI_FRF_MOTO_MODE_2
+//! 1 1 SOFTSSI_FRF_MOTO_MODE_3
+//! </pre>
+//!
+//! The \e ui8Bits parameter defines the width of the data transfers, and can
+//! be a value between 4 and 16, inclusive.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIConfigSet(tSoftSSI *psSSI, uint8_t ui8Protocol,
+ uint8_t ui8Bits)
+{
+ //
+ // See if a GPIO pin has been set for Fss.
+ //
+ if(psSSI->ui32FssGPIO != 0)
+ {
+ //
+ // Configure the Fss pin.
+ //
+ MAP_GPIOPinTypeGPIOOutput(psSSI->ui32FssGPIO & 0xfffff000,
+ (psSSI->ui32FssGPIO & 0x00000fff) >> 2);
+
+ //
+ // Set the Fss pin high.
+ //
+ HWREG(psSSI->ui32FssGPIO) = 255;
+ }
+
+ //
+ // Configure the Clk pin.
+ //
+ MAP_GPIOPinTypeGPIOOutput(psSSI->ui32ClkGPIO & 0xfffff000,
+ (psSSI->ui32ClkGPIO & 0x00000fff) >> 2);
+
+ //
+ // Set the Clk pin high or low based on the configured clock polarity.
+ //
+ if((ui8Protocol & SOFTSSI_FLAG_SPO) == 0)
+ {
+ HWREG(psSSI->ui32ClkGPIO) = 0;
+ }
+ else
+ {
+ HWREG(psSSI->ui32ClkGPIO) = 255;
+ }
+
+ //
+ // Configure the Tx pin and set it low.
+ //
+ MAP_GPIOPinTypeGPIOOutput(psSSI->ui32TxGPIO & 0xfffff000,
+ (psSSI->ui32TxGPIO & 0x00000fff) >> 2);
+ HWREG(psSSI->ui32TxGPIO) = 0;
+
+ //
+ // See if a GPIO pin has been set for Rx.
+ //
+ if(psSSI->ui32RxGPIO != 0)
+ {
+ //
+ // Configure the Rx pin.
+ //
+ MAP_GPIOPinTypeGPIOInput(psSSI->ui32RxGPIO & 0xfffff000,
+ (psSSI->ui32RxGPIO & 0x00000fff) >> 2);
+ }
+
+ //
+ // Make sure that the transmit and receive FIFOs are empty.
+ //
+ psSSI->ui16TxBufferRead = 0;
+ psSSI->ui16TxBufferWrite = 0;
+ psSSI->ui16RxBufferRead = 0;
+ psSSI->ui16RxBufferWrite = 0;
+
+ //
+ // Save the frame protocol.
+ //
+ psSSI->ui8Flags = ui8Protocol;
+
+ //
+ // Save the number of data bits.
+ //
+ psSSI->ui8Bits = ui8Bits;
+
+ //
+ // Since the FIFOs are empty, the transmit FIFO "interrupt" is asserted.
+ //
+ psSSI->ui8IntStatus = SOFTSSI_TXFF;
+
+ //
+ // Reset the idle counter.
+ //
+ psSSI->ui8IdleCount = 0;
+
+ //
+ // Disable the SoftSSI module.
+ //
+ psSSI->ui8Flags &= ~(SOFTSSI_FLAG_ENABLE);
+
+ //
+ // Start the SoftSSI state machine in the idle state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_IDLE;
+}
+
+//*****************************************************************************
+//
+//! Handles the assertion/deassertion of the transmit FIFO ``interrupt''.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function is used to determine when to assert or deassert the transmit
+//! FIFO ``interrupt''.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftSSITxInt(tSoftSSI *psSSI)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the number of words left in the transmit FIFO.
+ //
+ if(psSSI->ui16TxBufferRead > psSSI->ui16TxBufferWrite)
+ {
+ ui16Temp = (psSSI->ui16TxBufferLen + psSSI->ui16TxBufferWrite -
+ psSSI->ui16TxBufferRead);
+ }
+ else
+ {
+ ui16Temp = psSSI->ui16TxBufferWrite - psSSI->ui16TxBufferRead;
+ }
+
+ //
+ // If the transmit FIFO is now half full or less, generate a transmit FIFO
+ // "interrupt". Otherwise, clear the transmit FIFO "interrupt".
+ //
+ if(ui16Temp <= (psSSI->ui16TxBufferLen / 2))
+ {
+ psSSI->ui8IntStatus |= SOFTSSI_TXFF;
+ }
+ else
+ {
+ psSSI->ui8IntStatus &= ~(SOFTSSI_TXFF);
+ }
+}
+
+//*****************************************************************************
+//
+//! Handles the assertion/deassertion of the receive FIFO ``interrupt''.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function is used to determine when to assert or deassert the receive
+//! FIFO ``interrupt''.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftSSIRxInt(tSoftSSI *psSSI)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the number of words in the receive FIFO.
+ //
+ if(psSSI->ui16RxBufferRead > psSSI->ui16RxBufferWrite)
+ {
+ ui16Temp = (psSSI->ui16RxBufferLen + psSSI->ui16RxBufferWrite -
+ psSSI->ui16RxBufferRead);
+ }
+ else
+ {
+ ui16Temp = psSSI->ui16RxBufferWrite - psSSI->ui16RxBufferRead;
+ }
+
+ //
+ // If the receive FIFO is now half full or more, generate a receive FIFO
+ // "interrupt". Otherwise, clear the receive FIFO "interrupt".
+ //
+ if(ui16Temp >= (psSSI->ui16RxBufferLen / 2))
+ {
+ psSSI->ui8IntStatus |= SOFTSSI_RXFF;
+ }
+ else
+ {
+ psSSI->ui8IntStatus &= ~(SOFTSSI_RXFF);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function performs the periodic, time-based updates to the SoftSSI
+//! module. The transmission and reception of data over the SoftSSI link is
+//! performed by the state machine in this function.
+//!
+//! This function must be called at twice the desired SoftSSI clock rate. For
+//! example, to run the SoftSSI clock at 10 KHz, this function must be called
+//! at a 20 KHz rate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSITimerTick(tSoftSSI *psSSI)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(psSSI->ui8State)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTSSI_STATE_IDLE:
+ {
+ //
+ // See if the SoftSSI module is enabled and there is data in the
+ // transmit FIFO.
+ //
+ if(((psSSI->ui8Flags & SOFTSSI_FLAG_ENABLE) != 0) &&
+ (psSSI->ui16TxBufferRead != psSSI->ui16TxBufferWrite))
+ {
+ //
+ // Assert the Fss signal if it is configured.
+ //
+ if(psSSI->ui32FssGPIO != 0)
+ {
+ HWREG(psSSI->ui32FssGPIO) = 0;
+ }
+
+ //
+ // Move to the start state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_START;
+ }
+
+ //
+ // Otherwise, see if there is data in the receive FIFO.
+ //
+ else if((psSSI->ui16RxBufferRead != psSSI->ui16RxBufferWrite) &&
+ (psSSI->ui8IdleCount != 64))
+ {
+ //
+ // Increment the idle counter.
+ //
+ psSSI->ui8IdleCount++;
+
+ //
+ // See if the idle counter has become large enough to trigger
+ // a timeout "interrupt".
+ //
+ if(psSSI->ui8IdleCount == 64)
+ {
+ //
+ // Trigger the receive timeout "interrupt".
+ //
+ psSSI->ui8IntStatus |= SOFTSSI_RXTO;
+ }
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The start machine is in the transfer start state.
+ //
+ case SOFTSSI_STATE_START:
+ {
+ //
+ // Get the next word to transfer from the transmit FIFO.
+ //
+ psSSI->ui16TxData =
+ (psSSI->pui16TxBuffer[psSSI->ui16TxBufferRead] <<
+ (16 - psSSI->ui8Bits));
+
+ //
+ // Initialize the receive buffer to zero.
+ //
+ psSSI->ui16RxData = 0;
+
+ //
+ // Initialize the count of bits tranferred.
+ //
+ psSSI->ui8CurrentBit = 0;
+
+ //
+ // Write the first bit of the transmit word to the Tx pin.
+ //
+ HWREG(psSSI->ui32TxGPIO) =
+ (psSSI->ui16TxData & 0x8000) ? 255 : 0;
+
+ //
+ // Shift to the next bit of the transmit word.
+ //
+ psSSI->ui16TxData <<= 1;
+
+ //
+ // If in SPI mode 1 or 3, then the Clk signal needs to be toggled.
+ //
+ if((psSSI->ui8Flags & SOFTSSI_FLAG_SPH) != 0)
+ {
+ HWREG(psSSI->ui32ClkGPIO) ^= 255;
+ }
+
+ //
+ // Move to the data input state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_IN;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the data input state.
+ //
+ case SOFTSSI_STATE_IN:
+ {
+ //
+ // Read the next bit from the Rx signal if it is configured.
+ //
+ if(psSSI->ui32RxGPIO != 0)
+ {
+ psSSI->ui16RxData = ((psSSI->ui16RxData << 1) |
+ (HWREG(psSSI->ui32RxGPIO) ? 1 : 0));
+ }
+
+ //
+ // Toggle the Clk signal.
+ //
+ HWREG(psSSI->ui32ClkGPIO) ^= 255;
+
+ //
+ // Increment the number of bits transferred.
+ //
+ psSSI->ui8CurrentBit++;
+
+ //
+ // See if the entire word has been transferred.
+ //
+ if(psSSI->ui8CurrentBit != psSSI->ui8Bits)
+ {
+ //
+ // There are more bits to transfer, so move to the data output
+ // state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_OUT;
+ }
+ else
+ {
+ //
+ // Increment the transmit read pointer, removing the word that
+ // was just transferred from the transmit FIFO.
+ //
+ psSSI->ui16TxBufferRead++;
+ if(psSSI->ui16TxBufferRead == psSSI->ui16TxBufferLen)
+ {
+ psSSI->ui16TxBufferRead = 0;
+ }
+
+ //
+ // See if a transmit FIFO "interrupt" needs to be asserted.
+ //
+ SoftSSITxInt(psSSI);
+
+ //
+ // Determine the new value for the receive FIFO write pointer.
+ //
+ ui16Temp = psSSI->ui16RxBufferWrite + 1;
+ if(ui16Temp >= psSSI->ui16RxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+
+ //
+ // See if there is space in the receive FIFO for the word that
+ // was just received.
+ //
+ if(ui16Temp == psSSI->ui16RxBufferRead)
+ {
+ //
+ // The receive FIFO is full, so generate a receive FIFO
+ // overrun "interrupt".
+ //
+ psSSI->ui8IntStatus |= SOFTSSI_RXOR;
+ }
+ else
+ {
+ //
+ // Store the new word into the receive FIFO.
+ //
+ psSSI->pui16RxBuffer[psSSI->ui16RxBufferWrite] =
+ psSSI->ui16RxData;
+
+ //
+ // Save the new receive FIFO write pointer.
+ //
+ psSSI->ui16RxBufferWrite = ui16Temp;
+
+ //
+ // See if a receive FIFO "interrupt" needs to be asserted.
+ //
+ SoftSSIRxInt(psSSI);
+ }
+
+ //
+ // See if the next word should be transmitted immediately.
+ // This will occur when there is data in the transmit FIFO, the
+ // SoftSSI module is enabled, and the SoftSSI module is in SPI
+ // mode 1 or 3.
+ //
+ if(((psSSI->ui8Flags & SOFTSSI_FLAG_ENABLE) != 0) &&
+ ((psSSI->ui8Flags & SOFTSSI_FLAG_SPH) != 0) &&
+ (psSSI->ui16TxBufferRead != psSSI->ui16TxBufferWrite))
+ {
+ //
+ // Get the next word to transfer from the transmit FIFO.
+ //
+ psSSI->ui16TxData =
+ (psSSI->pui16TxBuffer[psSSI->ui16TxBufferRead] <<
+ (16 - psSSI->ui8Bits));
+
+ //
+ // Initialize the receive buffer to zero.
+ //
+ psSSI->ui16RxData = 0;
+
+ //
+ // Initialize the count of bits tranferred.
+ //
+ psSSI->ui8CurrentBit = 0;
+
+ //
+ // Move to the data output state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_OUT;
+ }
+ else
+ {
+ //
+ // The next word should not be transmitted immediately, so
+ // move to the first step of the stop state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_STOP1;
+ }
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the data output state.
+ //
+ case SOFTSSI_STATE_OUT:
+ {
+ //
+ // Write the next bit of the transmit word to the Tx pin.
+ //
+ HWREG(psSSI->ui32TxGPIO) = (psSSI->ui16TxData & 0x8000) ? 255 : 0;
+
+ //
+ // Toggle the Clk signal.
+ //
+ HWREG(psSSI->ui32ClkGPIO) ^= 255;
+
+ //
+ // Shift to the next bit of the transmit word.
+ //
+ psSSI->ui16TxData <<= 1;
+
+ //
+ // Move to the data input state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_IN;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the first step of the stop state.
+ //
+ case SOFTSSI_STATE_STOP1:
+ {
+ //
+ // Set the Tx pin low.
+ //
+ HWREG(psSSI->ui32TxGPIO) = 0;
+
+ //
+ // If in SPI mode 1 or 3, then the Clk signal needs to be toggled.
+ //
+ if((psSSI->ui8Flags & SOFTSSI_FLAG_SPH) == 0)
+ {
+ HWREG(psSSI->ui32ClkGPIO) ^= 255;
+ }
+
+ //
+ // Move to the second step of the stop state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_STOP2;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the second step of the stop state.
+ //
+ case SOFTSSI_STATE_STOP2:
+ {
+ //
+ // Deassert the Fss signal if it is configured.
+ //
+ if(psSSI->ui32FssGPIO != 0)
+ {
+ HWREG(psSSI->ui32FssGPIO) = 255;
+ }
+
+ //
+ // Move to the idle state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_IDLE;
+
+ //
+ // Reset the idle counter.
+ //
+ psSSI->ui8IdleCount = 0;
+
+ //
+ // See if the end of transfer "interrupt" should be generated.
+ //
+ if(psSSI->ui16TxBufferRead == psSSI->ui16TxBufferWrite)
+ {
+ psSSI->ui8IntStatus |= SOFTSSI_TXEOT;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the SSI peripheral.
+ //
+ while(((psSSI->ui8IntStatus & psSSI->ui8IntMask) != 0) &&
+ (psSSI->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ psSSI->pfnIntCallback();
+ }
+}
+
+//*****************************************************************************
+//
+//! Enables the SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function enables operation of the SoftSSI module. The SoftSSI module
+//! must be configured before it is enabled.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIEnable(tSoftSSI *psSSI)
+{
+ //
+ // Enable the SoftSSI module.
+ //
+ psSSI->ui8Flags |= SOFTSSI_FLAG_ENABLE;
+}
+
+//*****************************************************************************
+//
+//! Disables the SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function disables operation of the SoftSSI module. If a data transfer
+//! is in progress, it is finished before the module is fully disabled.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIDisable(tSoftSSI *psSSI)
+{
+ //
+ // Disable the SoftSSI module.
+ //
+ psSSI->ui8Flags &= ~(SOFTSSI_FLAG_ENABLE);
+}
+
+//*****************************************************************************
+//
+//! Enables individual SoftSSI ``interrupt'' sources.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32IntFlags is a bit mask of the ``interrupt'' sources to be
+//! enabled.
+//!
+//! Enables the indicated SoftSSI ``interrupt'' sources. Only the sources that
+//! are enabled can be reflected to the callback function; disabled sources do
+//! not result in a callback. The \e ui32IntFlags parameter can be any of the
+//! \b SOFTSSI_TXEOT, \b SOFTSSI_TXFF, \b SOFTSSI_RXFF, \b SOFTSSI_RXTO, or
+//! \b SOFTSSI_RXOR values.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIIntEnable(tSoftSSI *psSSI, uint32_t ui32IntFlags)
+{
+ //
+ // Enable the specified "interrupts".
+ //
+ psSSI->ui8IntMask |= ui32IntFlags;
+}
+
+//*****************************************************************************
+//
+//! Disables individual SoftSSI ``interrupt'' sources.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32IntFlags is a bit mask of the ``interrupt'' sources to be
+//! disabled.
+//!
+//! Disables the indicated SoftSSI ``interrupt'' sources. The \e ui32IntFlags
+//! parameter can be any of the \b SOFTSSI_TXEOT, \b SOFTSSI_TXFF,
+//! \b SOFTSSI_RXFF, \b SOFTSSI_RXTO, or \b SOFTSSI_RXOR values.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIIntDisable(tSoftSSI *psSSI, uint32_t ui32IntFlags)
+{
+ //
+ // Disable the specified "interrupts".
+ //
+ psSSI->ui8IntMask &= ~(ui32IntFlags);
+}
+
+//*****************************************************************************
+//
+//! Gets the current ``interrupt'' status.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param bMasked is \b false if the raw ``interrupt'' status is required or
+//! \b true if the masked ``interrupt'' status is required.
+//!
+//! This function returns the ``interrupt'' status for the SoftSSI module.
+//! Either the raw ``interrupt'' status or the status of ``interrupts'' that
+//! are allowed to reflect to the callback can be returned.
+//!
+//! \return The current ``interrupt'' status, enumerated as a bit field of
+//! \b SOFTSSI_TXEOT, \b SOFTSSI_TXFF, \b SOFTSSI_RXFF, \b SOFTSSI_RXTO, and
+//! \b SOFTSSI_RXOR.
+//
+//*****************************************************************************
+uint32_t
+SoftSSIIntStatus(tSoftSSI *psSSI, bool bMasked)
+{
+ //
+ // Return either the "interrupt" status or the raw "interrupt" status as
+ // requested.
+ //
+ if(bMasked)
+ {
+ return(psSSI->ui8IntStatus & psSSI->ui8IntMask);
+ }
+ else
+ {
+ return(psSSI->ui8IntStatus);
+ }
+}
+
+//*****************************************************************************
+//
+//! Clears SoftSSI ``interrupt'' sources.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32IntFlags is a bit mask of the ``interrupt'' sources to be
+//! cleared.
+//!
+//! The specified SoftSSI ``interrupt'' sources are cleared so that they no
+//! longer assert. This function must be called in the ``interrupt'' handler
+//! to keep the ``interrupt'' from being recognized again immediately upon
+//! exit. The \e ui32IntFlags parameter is the logical OR of any of the
+//! \b SOFTSSI_TXEOT, \b SOFTSSI_RXTO, and \b SOFTSSI_RXOR values.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIIntClear(tSoftSSI *psSSI, uint32_t ui32IntFlags)
+{
+ //
+ // Clear the requested "interrupt" sources.
+ //
+ psSSI->ui8IntStatus &= ~(ui32IntFlags) | SOFTSSI_TXFF | SOFTSSI_RXFF;
+}
+
+//*****************************************************************************
+//
+//! Determines if there is any data in the receive FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function determines if there is any data available to be read from the
+//! receive FIFO.
+//!
+//! \return Returns \b true if there is data in the receive FIFO or \b false
+//! if there is no data in the receive FIFO.
+//
+//*****************************************************************************
+bool
+SoftSSIDataAvail(tSoftSSI *psSSI)
+{
+ //
+ // Return the availability of data.
+ //
+ return((psSSI->ui16RxBufferRead == psSSI->ui16RxBufferWrite) ? false :
+ true);
+}
+
+//*****************************************************************************
+//
+//! Determines if there is any space in the transmit FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function determines if there is space available in the transmit FIFO.
+//!
+//! \return Returns \b true if there is space available in the transmit FIFO or
+//! \b false if there is no space available in the transmit FIFO.
+//
+//*****************************************************************************
+bool
+SoftSSISpaceAvail(tSoftSSI *psSSI)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ ui16Temp = psSSI->ui16TxBufferWrite + 1;
+ if(ui16Temp == psSSI->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+
+ //
+ // Return the availability of space.
+ //
+ return((psSSI->ui16TxBufferRead == ui16Temp) ? false : true);
+}
+
+//*****************************************************************************
+//
+//! Puts a data element into the SoftSSI transmit FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Data is the data to be transmitted over the SoftSSI interface.
+//!
+//! This function places the supplied data into the transmit FIFO of the
+//! specified SoftSSI module.
+//!
+//! \note The upper 32 - N bits of the \e ui32Data are discarded, where N is
+//! the data width as configured by SoftSSIConfigSet(). For example, if the
+//! interface is configured for 8-bit data width, the upper 24 bits of
+//! \e ui32Data are discarded.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIDataPut(tSoftSSI *psSSI, uint32_t ui32Data)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Wait until there is space.
+ //
+ ui16Temp = psSSI->ui16TxBufferWrite + 1;
+ if(ui16Temp == psSSI->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+ while(ui16Temp == *(volatile uint16_t *)(&(psSSI->ui16TxBufferRead)))
+ {
+ }
+
+ //
+ // Write the data to the SoftSSI.
+ //
+ psSSI->pui16TxBuffer[psSSI->ui16TxBufferWrite] = ui32Data;
+ psSSI->ui16TxBufferWrite = ui16Temp;
+
+ //
+ // See if a transmit FIFO "interrupt" needs to be cleared.
+ //
+ SoftSSITxInt(psSSI);
+}
+
+//*****************************************************************************
+//
+//! Puts a data element into the SoftSSI transmit FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Data is the data to be transmitted over the SoftSSI interface.
+//!
+//! This function places the supplied data into the transmit FIFO of the
+//! specified SoftSSI module. If there is no space in the FIFO, then this
+//! function returns a zero.
+//!
+//! \note The upper 32 - N bits of the \e ui32Data are discarded, where N is
+//! the data width as configured by SoftSSIConfigSet(). For example, if the
+//! interface is configured for 8-bit data width, the upper 24 bits of
+//! \e ui32Data are discarded.
+//!
+//! \return Returns the number of elements written to the SSI transmit FIFO.
+//
+//*****************************************************************************
+int32_t
+SoftSSIDataPutNonBlocking(tSoftSSI *psSSI, uint32_t ui32Data)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ ui16Temp = psSSI->ui16TxBufferWrite + 1;
+ if(ui16Temp == psSSI->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+
+ //
+ // Check for space to write.
+ //
+ if(ui16Temp != psSSI->ui16TxBufferRead)
+ {
+ psSSI->pui16TxBuffer[psSSI->ui16TxBufferWrite] = ui32Data;
+ psSSI->ui16TxBufferWrite = ui16Temp;
+ SoftSSITxInt(psSSI);
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets a data element from the SoftSSI receive FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param pui32Data is a pointer to a storage location for data that was
+//! received over the SoftSSI interface.
+//!
+//! This function gets received data from the receive FIFO of the specified
+//! SoftSSI module and places that data into the location specified by the
+//! \e pui32Data parameter.
+//!
+//! \note Only the lower N bits of the value written to \e pui32Data contain
+//! valid data, where N is the data width as configured by SoftSSIConfigSet().
+//! For example, if the interface is configured for 8-bit data width, only the
+//! lower 8 bits of the value written to \e pui32Data contain valid data.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIDataGet(tSoftSSI *psSSI, uint32_t *pui32Data)
+{
+ //
+ // Wait until there is data to be read.
+ //
+ while(psSSI->ui16RxBufferRead ==
+ *(volatile uint16_t *)(&(psSSI->ui16RxBufferWrite)))
+ {
+ }
+
+ //
+ // Read data from SoftSSI.
+ //
+ *pui32Data = psSSI->pui16RxBuffer[psSSI->ui16RxBufferRead];
+ psSSI->ui16RxBufferRead++;
+ if(psSSI->ui16RxBufferRead == psSSI->ui16RxBufferLen)
+ {
+ psSSI->ui16RxBufferRead = 0;
+ }
+
+ //
+ // See if a receive FIFO "interrupt" needs to be cleared.
+ //
+ SoftSSIRxInt(psSSI);
+}
+
+//*****************************************************************************
+//
+//! Gets a data element from the SoftSSI receive FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param pui32Data is a pointer to a storage location for data that was
+//! received over the SoftSSI interface.
+//!
+//! This function gets received data from the receive FIFO of the specified
+//! SoftSSI module and places that data into the location specified by the
+//! \e ui32Data parameter. If there is no data in the FIFO, then this function
+//! returns a zero.
+//!
+//! \note Only the lower N bits of the value written to \e pui32Data contain
+//! valid data, where N is the data width as configured by SoftSSIConfigSet().
+//! For example, if the interface is configured for 8-bit data width, only the
+//! lower 8 bits of the value written to \e pui32Data contain valid data.
+//!
+//! \return Returns the number of elements read from the SoftSSI receive FIFO.
+//
+//*****************************************************************************
+int32_t
+SoftSSIDataGetNonBlocking(tSoftSSI *psSSI, uint32_t *pui32Data)
+{
+ //
+ // Check for data to read.
+ //
+ if(psSSI->ui16RxBufferRead != psSSI->ui16RxBufferWrite)
+ {
+ *pui32Data = psSSI->pui16RxBuffer[psSSI->ui16RxBufferRead];
+ psSSI->ui16RxBufferRead++;
+ if(psSSI->ui16RxBufferRead == psSSI->ui16RxBufferLen)
+ {
+ psSSI->ui16RxBufferRead = 0;
+ }
+ SoftSSIRxInt(psSSI);
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether the SoftSSI transmitter is busy or not.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! Allows the caller to determine whether all transmitted bytes have cleared
+//! the transmitter. If \b false is returned, then the transmit FIFO is empty
+//! and all bits of the last transmitted word have left the shift register.
+//!
+//! \return Returns \b true if the SoftSSI is transmitting or \b false if all
+//! transmissions are complete.
+//
+//*****************************************************************************
+bool
+SoftSSIBusy(tSoftSSI *psSSI)
+{
+ //
+ // Determine if the SSI is busy.
+ //
+ return(((psSSI->ui8State == SOFTSSI_STATE_IDLE) &&
+ (((psSSI->ui8Flags & SOFTSSI_FLAG_ENABLE) == 0) ||
+ (psSSI->ui16TxBufferRead == psSSI->ui16TxBufferWrite))) ? false :
+ true);
+}
+
+//*****************************************************************************
+//
+//! Sets the callback used by the SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param pfnCallback is a pointer to the callback function.
+//!
+//! This function sets the address of the callback function that is called when
+//! there is an ``interrupt'' produced by the SoftSSI module.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSICallbackSet(tSoftSSI *psSSI, void (*pfnCallback)(void))
+{
+ //
+ // Save the callback function address.
+ //
+ psSSI->pfnIntCallback = pfnCallback;
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Fss signal.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Fss signal.
+//! If there is not a GPIO pin allocated for Fss, the SoftSSI module does not
+//! assert/deassert the Fss signal, leaving it to the application either to do
+//! manually or to not do at all if the slave device has Fss tied to ground.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIFssGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Fss signal.
+ //
+ if(ui32Base == 0)
+ {
+ psSSI->ui32FssGPIO = 0;
+ }
+ else
+ {
+ psSSI->ui32FssGPIO = ui32Base + (ui8Pin << 2);
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Clk signal.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Clk signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIClkGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Clk signal.
+ //
+ psSSI->ui32ClkGPIO = ui32Base + (ui8Pin << 2);
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Tx signal.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Tx signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSITxGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Tx signal.
+ //
+ psSSI->ui32TxGPIO = ui32Base + (ui8Pin << 2);
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Rx signal.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Rx signal. If
+//! there is not a GPIO pin allocated for Rx, the SoftSSI module does not read
+//! data from the slave device.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIRxGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Rx signal.
+ //
+ if(ui32Base == 0)
+ {
+ psSSI->ui32RxGPIO = 0;
+ }
+ else
+ {
+ psSSI->ui32RxGPIO = ui32Base + (ui8Pin << 2);
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the transmit FIFO buffer for a SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param pui16TxBuffer is the address of the transmit FIFO buffer.
+//! \param ui16Len is the size, in 16-bit half-words, of the transmit FIFO
+//! buffer.
+//!
+//! This function sets the address and size of the transmit FIFO buffer and
+//! also resets the read and write pointers, marking the transmit FIFO as
+//! empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSITxBufferSet(tSoftSSI *psSSI, uint16_t *pui16TxBuffer,
+ uint16_t ui16Len)
+{
+ //
+ // Save the transmit FIFO buffer address and length.
+ //
+ psSSI->pui16TxBuffer = pui16TxBuffer;
+ psSSI->ui16TxBufferLen = ui16Len;
+
+ //
+ // Reset the transmit FIFO read and write pointers.
+ //
+ psSSI->ui16TxBufferRead = 0;
+ psSSI->ui16TxBufferWrite = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the receive FIFO buffer for a SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param pui16RxBuffer is the address of the receive FIFO buffer.
+//! \param ui16Len is the size, in 16-bit half-words, of the receive FIFO
+//! buffer.
+//!
+//! This function sets the address and size of the receive FIFO buffer and also
+//! resets the read and write pointers, marking the receive FIFO as empty.
+//! When the buffer pointer and length are configured as zero, all data
+//! received from the slave device is discarded. This capability is useful
+//! when there is no GPIO pin allocated for the Rx signal.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIRxBufferSet(tSoftSSI *psSSI, uint16_t *pui16RxBuffer,
+ uint16_t ui16Len)
+{
+ //
+ // Save the receive FIFO buffer address and length.
+ //
+ psSSI->pui16RxBuffer = pui16RxBuffer;
+ psSSI->ui16RxBufferLen = ui16Len;
+
+ //
+ // Reset the receive FIFO read and write pointers.
+ //
+ psSSI->ui16RxBufferRead = 0;
+ psSSI->ui16RxBufferWrite = 0;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/softssi.h b/utils/softssi.h
new file mode 100644
index 0000000..72ee068
--- /dev/null
+++ b/utils/softssi.h
@@ -0,0 +1,280 @@
+//*****************************************************************************
+//
+// softssi.h - Defines and macros for the SoftSSI.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SOFTSSI_H__
+#define __SOFTSSI_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup softssi_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure contains the state of a single instance of a SoftSSI module.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The address of the callback function that is called to simulate the
+ //! interrupts that would be produced by a hardware SSI implementation.
+ //! This address can be set via a direct structure access or using the
+ //! SoftSSICallbackSet function.
+ //
+ void (*pfnIntCallback)(void);
+
+ //
+ //! The address of the GPIO pin to be used for the Fss signal. If this
+ //! member is zero, the Fss signal is not generated. This member can be
+ //! set via a direct structure access or using the SoftSSIFssGPIOSet
+ //! function.
+ ///
+ uint32_t ui32FssGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the Clk signal. This member
+ //! can be set via a direct structure access or using the SoftSSIClkGPIOSet
+ //! function.
+ //
+ uint32_t ui32ClkGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the Tx signal. This member
+ //! can be set via a direct structure access or using the SoftSSITxGPIOSet
+ //! function.
+ //
+ uint32_t ui32TxGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the Rx signal. If this
+ //! member is zero, the Rx signal is not read. This member can be set via
+ //! a direct structure access or using the SoftSSIRxGPIOSet function.
+ //
+ uint32_t ui32RxGPIO;
+
+ //
+ //! The address of the data buffer used for the transmit FIFO. This member
+ //! can be set via a direct structure access or using the
+ //! SoftSSITxBufferSet function.
+ //
+ uint16_t *pui16TxBuffer;
+
+ //
+ //! The address of the data buffer used for the receive FIFO. This member
+ //! can be set via a direct structure access or using the
+ //! SoftSSIRxBufferSet function.
+ //
+ uint16_t *pui16RxBuffer;
+
+ //
+ //! The length of the transmit FIFO. This member can be set via a direct
+ //! structure access or using the SoftSSITxBufferSet function.
+ //
+ uint16_t ui16TxBufferLen;
+
+ //
+ //! The index into the transmit FIFO of the next word to be transmitted.
+ //! This member should be initialized to zero, but should not be accessed
+ //! or modified by the application.
+ //
+ uint16_t ui16TxBufferRead;
+
+ //
+ //! The index into the transmit FIFO of the next location to store data
+ //! into the FIFO. This member should be initialized to zero, but should
+ //! not be accessed or modified by the application.
+ //
+ uint16_t ui16TxBufferWrite;
+
+ //
+ //! The length of the receive FIFO. This member can be set via a direct
+ //! structure access or using the SoftSSIRxBufferSet function.
+ //
+ uint16_t ui16RxBufferLen;
+
+ //
+ //! The index into the receive FIFO of the next word to be read from the
+ //! FIFO. This member should be initialized to zero, but should not be
+ //! accessed or modified by the application.
+ //
+ uint16_t ui16RxBufferRead;
+
+ //
+ //! The index into the receive FIFO of the location to store the next word
+ //! received. This member should be initialized to zero, but should not be
+ //! accessed or modified by the application.
+ //
+ uint16_t ui16RxBufferWrite;
+
+ //
+ //! The word that is currently being transmitted. This member should not
+ //! be accessed or modified by the application.
+ //
+ uint16_t ui16TxData;
+
+ //
+ //! The word that is currently being received. This member should not be
+ //! accessed or modified by the application.
+ //
+ uint16_t ui16RxData;
+
+ //
+ //! The flags that control the operation of the SoftSSI module. This
+ //! member should not be accessed or modified by the application.
+ //
+ uint8_t ui8Flags;
+
+ //
+ //! The number of data bits in each SoftSSI frame, which also specifies the
+ //! width of each data item in the transmit and receive FIFOs. This member
+ //! can be set via a direct structure access or using the SoftSSIConfigSet
+ //! function.
+ //
+ uint8_t ui8Bits;
+
+ //
+ //! The current state of the SoftSSI state machine. This member should not
+ //! be accessed or modified by the application.
+ //
+ uint8_t ui8State;
+
+ //
+ //! The number of bits that have been transmitted and received in the
+ //! current frame. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint8_t ui8CurrentBit;
+
+ //
+ //! The set of virtual interrupts that should be sent to the callback
+ //! function. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint8_t ui8IntMask;
+
+ //
+ //! The set of virtual interrupts that are currently asserted. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8IntStatus;
+
+ //
+ //! The number of tick counts that the SoftSSI module has been idle with
+ //! data stored in the receive FIFO, which is used to generate the receive
+ //! timeout interrupt. This member should not be accessed or modified by
+ //! the application.
+ //
+ uint8_t ui8IdleCount;
+}
+tSoftSSI;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftSSIIntEnable, SoftSSIIntDisable, and
+// SoftSSIIntClear as the ui32IntFlags parameter, and returned by
+// SoftSSIIntStatus.
+//
+//*****************************************************************************
+#define SOFTSSI_TXEOT 0x00000010 // TX end of transmit
+#define SOFTSSI_TXFF 0x00000008 // TX FIFO half full or less
+#define SOFTSSI_RXFF 0x00000004 // RX FIFO half full or more
+#define SOFTSSI_RXTO 0x00000002 // RX timeout
+#define SOFTSSI_RXOR 0x00000001 // RX overrun
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftSSIConfigSet.
+//
+//*****************************************************************************
+#define SOFTSSI_FRF_MOTO_MODE_0 0x00000000 // Moto fmt, polarity 0, phase 0
+#define SOFTSSI_FRF_MOTO_MODE_1 0x00000002 // Moto fmt, polarity 0, phase 1
+#define SOFTSSI_FRF_MOTO_MODE_2 0x00000001 // Moto fmt, polarity 1, phase 0
+#define SOFTSSI_FRF_MOTO_MODE_3 0x00000003 // Moto fmt, polarity 1, phase 1
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern bool SoftSSIBusy(tSoftSSI *psSSI);
+extern void SoftSSICallbackSet(tSoftSSI *psSSI, void (*pfnCallback)(void));
+extern void SoftSSIClkGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftSSIConfigSet(tSoftSSI *psSSI, uint8_t ui8Protocol,
+ uint8_t ui8Bits);
+extern bool SoftSSIDataAvail(tSoftSSI *psSSI);
+extern void SoftSSIDataGet(tSoftSSI *psSSI, uint32_t *pui32Data);
+extern int32_t SoftSSIDataGetNonBlocking(tSoftSSI *psSSI, uint32_t *pui32Data);
+extern void SoftSSIDataPut(tSoftSSI *psSSI, uint32_t ui32Data);
+extern int32_t SoftSSIDataPutNonBlocking(tSoftSSI *psSSI, uint32_t ui32Data);
+extern void SoftSSIDisable(tSoftSSI *psSSI);
+extern void SoftSSIEnable(tSoftSSI *psSSI);
+extern void SoftSSIFssGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftSSIIntClear(tSoftSSI *psSSI, uint32_t ui32IntFlags);
+extern void SoftSSIIntDisable(tSoftSSI *psSSI, uint32_t ui32IntFlags);
+extern void SoftSSIIntEnable(tSoftSSI *psSSI, uint32_t ui32IntFlags);
+extern uint32_t SoftSSIIntStatus(tSoftSSI *psSSI, bool bMasked);
+extern void SoftSSIRxBufferSet(tSoftSSI *psSSI, uint16_t *pui16RxBuffer,
+ uint16_t ui16Len);
+extern void SoftSSIRxGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern bool SoftSSISpaceAvail(tSoftSSI *psSSI);
+extern void SoftSSITimerTick(tSoftSSI *psSSI);
+extern void SoftSSITxBufferSet(tSoftSSI *psSSI, uint16_t *pui16TxBuffer,
+ uint16_t ui16Len);
+extern void SoftSSITxGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base,
+ uint8_t ui8Pin);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFTSSI_H__
diff --git a/utils/softuart.c b/utils/softuart.c
new file mode 100644
index 0000000..d4aa3b3
--- /dev/null
+++ b/utils/softuart.c
@@ -0,0 +1,2591 @@
+//*****************************************************************************
+//
+// softuart.c - Driver for the SoftUART.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup softuart_api
+//! @{
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "inc/hw_uart.h"
+#include "driverlib/debug.h"
+#include "driverlib/gpio.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/uart.h"
+#include "utils/softuart.h"
+
+//*****************************************************************************
+//
+// The states in the SoftUART transmit state machine. The code depends upon
+// the fact that the value of TXSTATE_DATA_n is n + 1, and that TXSTATE_DATA_0
+// is 1.
+//
+//*****************************************************************************
+#define SOFTUART_TXSTATE_IDLE 0
+#define SOFTUART_TXSTATE_DATA_0 1
+#define SOFTUART_TXSTATE_DATA_1 2
+#define SOFTUART_TXSTATE_DATA_2 3
+#define SOFTUART_TXSTATE_DATA_3 4
+#define SOFTUART_TXSTATE_DATA_4 5
+#define SOFTUART_TXSTATE_DATA_5 6
+#define SOFTUART_TXSTATE_DATA_6 7
+#define SOFTUART_TXSTATE_DATA_7 8
+#define SOFTUART_TXSTATE_START 9
+#define SOFTUART_TXSTATE_PARITY 10
+#define SOFTUART_TXSTATE_STOP_0 11
+#define SOFTUART_TXSTATE_STOP_1 12
+#define SOFTUART_TXSTATE_BREAK 13
+
+//*****************************************************************************
+//
+// The states of the SoftUART receive state machine. The code depends upon the
+// the fact that the value of RXSTATE_DATA_n is n, and that RXSTATE_DATA_0 is
+// 0.
+//
+//*****************************************************************************
+#define SOFTUART_RXSTATE_DATA_0 0
+#define SOFTUART_RXSTATE_DATA_1 1
+#define SOFTUART_RXSTATE_DATA_2 2
+#define SOFTUART_RXSTATE_DATA_3 3
+#define SOFTUART_RXSTATE_DATA_4 4
+#define SOFTUART_RXSTATE_DATA_5 5
+#define SOFTUART_RXSTATE_DATA_6 6
+#define SOFTUART_RXSTATE_DATA_7 7
+#define SOFTUART_RXSTATE_IDLE 8
+#define SOFTUART_RXSTATE_PARITY 9
+#define SOFTUART_RXSTATE_STOP_0 10
+#define SOFTUART_RXSTATE_STOP_1 11
+#define SOFTUART_RXSTATE_BREAK 12
+#define SOFTUART_RXSTATE_DELAY 13
+
+//*****************************************************************************
+//
+// The flags in the SoftUART ui8Flags structure member.
+//
+//*****************************************************************************
+#define SOFTUART_FLAG_ENABLE 0x01
+#define SOFTUART_FLAG_TXBREAK 0x02
+
+//*****************************************************************************
+//
+// The flags in the SoftUART ui8RxFlags structure member.
+//
+//*****************************************************************************
+#define SOFTUART_RXFLAG_OE 0x08
+#define SOFTUART_RXFLAG_BE 0x04
+#define SOFTUART_RXFLAG_PE 0x02
+#define SOFTUART_RXFLAG_FE 0x01
+
+//*****************************************************************************
+//
+// Additional internal configuration stored in the SoftUART ui16Config
+// structure member.
+//
+//*****************************************************************************
+#define SOFTUART_CONFIG_BASE_M 0x00ff
+#define SOFTUART_CONFIG_EXT_M 0xff00
+#define SOFTUART_CONFIG_TXLVL_M 0x0700
+#define SOFTUART_CONFIG_TXLVL_1 0x0000
+#define SOFTUART_CONFIG_TXLVL_2 0x0100
+#define SOFTUART_CONFIG_TXLVL_4 0x0200
+#define SOFTUART_CONFIG_TXLVL_6 0x0300
+#define SOFTUART_CONFIG_TXLVL_7 0x0400
+#define SOFTUART_CONFIG_RXLVL_M 0x3800
+#define SOFTUART_CONFIG_RXLVL_1 0x0000
+#define SOFTUART_CONFIG_RXLVL_2 0x0800
+#define SOFTUART_CONFIG_RXLVL_4 0x1000
+#define SOFTUART_CONFIG_RXLVL_6 0x1800
+#define SOFTUART_CONFIG_RXLVL_7 0x2000
+
+//*****************************************************************************
+//
+// The odd parity of each possible data byte. The odd parity of N can be found
+// by looking at bit N % 32 of word N / 32.
+//
+//*****************************************************************************
+static uint32_t g_pui32ParityOdd[] =
+{
+ 0x69969669, 0x96696996, 0x96696996, 0x69969669,
+ 0x96696996, 0x69969669, 0x69969669, 0x96696996
+};
+
+//*****************************************************************************
+//
+//! Initializes the SoftUART module.
+//!
+//! \param psUART specifies the soft UART data structure.
+//!
+//! This function initializes the data structure for the SoftUART module,
+//! putting it into the default configuration.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTInit(tSoftUART *psUART)
+{
+ //
+ // Clear the SoftUART data structure.
+ //
+ memset(psUART, 0, sizeof(tSoftUART));
+
+ //
+ // Set the default transmit and receive buffer interrupt level.
+ //
+ psUART->ui16Config = SOFTUART_CONFIG_TXLVL_4 | SOFTUART_CONFIG_RXLVL_4;
+}
+
+//*****************************************************************************
+//
+//! Sets the configuration of a SoftUART module.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32Config is the data format for the port (number of data bits,
+//! number of stop bits, and parity).
+//!
+//! This function configures the SoftUART for operation in the specified data
+//! format, as specified in the \e ui32Config parameter.
+//!
+//! The \e ui32Config parameter is the logical OR of three values: the number
+//! of data bits, the number of stop bits, and the parity.
+//! \b SOFTUART_CONFIG_WLEN_8, \b SOFTUART_CONFIG_WLEN_7,
+//! \b SOFTUART_CONFIG_WLEN_6, and \b SOFTUART_CONFIG_WLEN_5 select from eight
+//! to five data bits per byte (respectively). \b SOFTUART_CONFIG_STOP_ONE and
+//! \b SOFTUART_CONFIG_STOP_TWO select one or two stop bits (respectively).
+//! \b SOFTUART_CONFIG_PAR_NONE, \b SOFTUART_CONFIG_PAR_EVEN,
+//! \b SOFTUART_CONFIG_PAR_ODD, \b SOFTUART_CONFIG_PAR_ONE, and
+//! \b SOFTUART_CONFIG_PAR_ZERO select the parity mode (no parity bit, even
+//! parity bit, odd parity bit, parity bit always one, and parity bit always
+//! zero, respectively).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTConfigSet(tSoftUART *psUART, uint32_t ui32Config)
+{
+ //
+ // See if a GPIO pin has been set for Tx.
+ //
+ if(psUART->ui32TxGPIO != 0)
+ {
+ //
+ // Configure the Tx pin.
+ //
+ MAP_GPIOPinTypeGPIOOutput(psUART->ui32TxGPIO & 0xfffff000,
+ (psUART->ui32TxGPIO & 0x00000fff) >> 2);
+
+ //
+ // Set the Tx pin high.
+ //
+ HWREG(psUART->ui32TxGPIO) = 255;
+ }
+
+ //
+ // See if a GPIO pin has been set for Rx.
+ //
+ if(psUART->ui32RxGPIOPort != 0)
+ {
+ //
+ // Configure the Rx pin.
+ //
+ MAP_GPIOPinTypeGPIOInput(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+
+ //
+ // Set the Rx pin to generate an interrupt on the next falling edge.
+ //
+ MAP_GPIOIntTypeSet(psUART->ui32RxGPIOPort, psUART->ui8RxPin,
+ GPIO_FALLING_EDGE);
+
+ //
+ // Enable the Rx pin interrupt.
+ //
+ GPIOIntClear(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+ GPIOIntEnable(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+ }
+
+ //
+ // Make sure that the transmit and receive buffers are empty.
+ //
+ psUART->ui16TxBufferRead = 0;
+ psUART->ui16TxBufferWrite = 0;
+ psUART->ui16RxBufferRead = 0;
+ psUART->ui16RxBufferWrite = 0;
+
+ //
+ // Save the data format.
+ //
+ psUART->ui16Config = ((psUART->ui16Config & SOFTUART_CONFIG_EXT_M) |
+ (ui32Config & SOFTUART_CONFIG_BASE_M));
+
+ //
+ // Enable the SoftUART module.
+ //
+ psUART->ui8Flags |= SOFTUART_FLAG_ENABLE;
+
+ //
+ // The next value to be written to the Tx pin is one since the SoftUART is
+ // idle.
+ //
+ psUART->ui8TxNext = 255;
+
+ //
+ // Start the SoftUART state machines in the idle state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_IDLE;
+ psUART->ui8RxState = SOFTUART_RXSTATE_IDLE;
+}
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftUART transmitter.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function performs the periodic, time-based updates to the SoftUART
+//! transmitter. The transmission of data from the SoftUART is performed by
+//! the state machine in this function.
+//!
+//! This function must be called at the desired SoftUART baud rate. For
+//! example, to run the SoftUART at 115,200 baud, this function must be called
+//! at a 115,200 Hz rate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTTxTimerTick(tSoftUART *psUART)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Write the next value to the Tx data line. This value was computed on
+ // the previous timer tick, which helps to reduce the jitter on the Tx
+ // edges (which is important since a UART connection does not contain a
+ // clock signal).
+ //
+ HWREG(psUART->ui32TxGPIO) = psUART->ui8TxNext;
+
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(psUART->ui8TxState)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTUART_TXSTATE_IDLE:
+ {
+ //
+ // See if the SoftUART module is enabled.
+ //
+ if(!(psUART->ui8Flags & SOFTUART_FLAG_ENABLE))
+ {
+ //
+ // The SoftUART module is not enabled, so do nothing and stay
+ // in the idle state.
+ //
+ break;
+ }
+
+ //
+ // See if the break signal should be asserted.
+ //
+ else if(psUART->ui8Flags & SOFTUART_FLAG_TXBREAK)
+ {
+ //
+ // The data line should be driven low while in the break state.
+ //
+ psUART->ui8TxNext = 0;
+
+ //
+ // Move to the break state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_BREAK;
+ }
+
+ //
+ // Otherwise, see if there is data in the transmit buffer.
+ //
+ else if(psUART->ui16TxBufferRead != psUART->ui16TxBufferWrite)
+ {
+ //
+ // The data line should be driven low to indicate a start bit.
+ //
+ psUART->ui8TxNext = 0;
+
+ //
+ // Move to the start bit state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_START;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the start bit state.
+ //
+ case SOFTUART_TXSTATE_START:
+ {
+ //
+ // Get the next byte to be transmitted.
+ //
+ psUART->ui8TxData = psUART->pui8TxBuffer[psUART->ui16TxBufferRead];
+
+ //
+ // The next value to be written to the data line is the LSB of the
+ // next data byte.
+ //
+ psUART->ui8TxNext = (psUART->ui8TxData & 1) ? 255 : 0;
+
+ //
+ // Move to the data bit 0 state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_DATA_0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte must be output.
+ // This depends upon TXSTATE_DATA_n and TXSTATE_DATA_(n+1) being
+ // consecutively numbered.
+ //
+ case SOFTUART_TXSTATE_DATA_0:
+ case SOFTUART_TXSTATE_DATA_1:
+ case SOFTUART_TXSTATE_DATA_2:
+ case SOFTUART_TXSTATE_DATA_3:
+ {
+ //
+ // The next value to be written to the data line is the next bit of
+ // the data byte.
+ //
+ psUART->ui8TxNext =
+ (psUART->ui8TxData & (1 << psUART->ui8TxState)) ? 255 : 0;
+
+ //
+ // Advance to the next state.
+ //
+ psUART->ui8TxState++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte must be output.
+ // Additionally, based on the configuration of the SoftUART, this bit
+ // might be the last data bit of the data byte. This depends upon
+ // TXSTATE_DATA_n and TXSTATE_DATA_(n+1) being consecutively numbered.
+ //
+ case SOFTUART_TXSTATE_DATA_4:
+ case SOFTUART_TXSTATE_DATA_5:
+ case SOFTUART_TXSTATE_DATA_6:
+ case SOFTUART_TXSTATE_DATA_7:
+ {
+ //
+ // See if the bit that was just transferred is the last bit of the
+ // data byte (based on the configuration of the SoftUART).
+ //
+ if(((psUART->ui16Config & SOFTUART_CONFIG_WLEN_MASK) >>
+ SOFTUART_CONFIG_WLEN_S) ==
+ (psUART->ui8TxState - SOFTUART_TXSTATE_DATA_4))
+ {
+ //
+ // See if parity is enabled.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) !=
+ SOFTUART_CONFIG_PAR_NONE)
+ {
+ //
+ // See if the parity is set to one.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ONE)
+ {
+ //
+ // The next value to be written to the data line is
+ // one.
+ //
+ psUART->ui8TxNext = 255;
+ }
+
+ //
+ // Otherwise, see if the parity is set to zero.
+ //
+ else if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ZERO)
+ {
+ //
+ // The next value to be written to the data line is
+ // zero.
+ //
+ psUART->ui8TxNext = 0;
+ }
+
+ //
+ // Otherwise, there is either even or odd parity.
+ //
+ else
+ {
+ //
+ // Find the odd parity for the data byte.
+ //
+ psUART->ui8TxNext =
+ ((g_pui32ParityOdd[psUART->ui8TxData >> 5] &
+ (1 << (psUART->ui8TxData & 31))) ? 255 : 0);
+
+ //
+ // If the parity is set to even, then invert the
+ // parity just computed (making it even parity).
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_EVEN)
+ {
+ psUART->ui8TxNext ^= 255;
+ }
+ }
+
+ //
+ // Advance to the parity state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_PARITY;
+ }
+
+ //
+ // Parity is not enabled.
+ //
+ else
+ {
+ //
+ // The next value to write to the data line is the stop
+ // bit.
+ //
+ psUART->ui8TxNext = 255;
+
+ //
+ // See if there are one or two stop bits.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_STOP_0;
+ }
+ else
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_STOP_1;
+ }
+ }
+ }
+
+ //
+ // Otherwise, there are more data bits to transfer.
+ //
+ else
+ {
+ //
+ // The next value to be written to the data line is the next
+ // bit of the data byte.
+ //
+ psUART->ui8TxNext =
+ (psUART->ui8TxData & (1 << psUART->ui8TxState)) ? 255 : 0;
+
+ //
+ // Advance to the next state.
+ //
+ psUART->ui8TxState++;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the parity bit state.
+ //
+ case SOFTUART_TXSTATE_PARITY:
+ {
+ //
+ // The next value to write to the data line is the stop bit.
+ //
+ psUART->ui8TxNext = 255;
+
+ //
+ // See if there are one or two stop bits.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_STOP_0;
+ }
+ else
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_STOP_1;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the two stop bits state.
+ //
+ case SOFTUART_TXSTATE_STOP_0:
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_STOP_1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the one stop bit state.
+ //
+ case SOFTUART_TXSTATE_STOP_1:
+ {
+ //
+ // The data byte has been completely transferred, so advance the
+ // read pointer.
+ //
+ psUART->ui16TxBufferRead++;
+ if(psUART->ui16TxBufferRead == psUART->ui16TxBufferLen)
+ {
+ psUART->ui16TxBufferRead = 0;
+ }
+
+ //
+ // Determine the number of characters in the transmit buffer.
+ //
+ if(psUART->ui16TxBufferRead > psUART->ui16TxBufferWrite)
+ {
+ ui32Temp = (psUART->ui16TxBufferLen -
+ (psUART->ui16TxBufferRead -
+ psUART->ui16TxBufferWrite));
+ }
+ else
+ {
+ ui32Temp = (psUART->ui16TxBufferWrite -
+ psUART->ui16TxBufferRead);
+ }
+
+ //
+ // If the transmit buffer fullness just crossed the programmed
+ // level, generate a transmit "interrupt".
+ //
+ if(ui32Temp == psUART->ui16TxBufferLevel)
+ {
+ psUART->ui16IntStatus |= SOFTUART_INT_TX;
+ }
+
+ //
+ // See if the SoftUART module is enabled.
+ //
+ if(!(psUART->ui8Flags & SOFTUART_FLAG_ENABLE))
+ {
+ //
+ // The SoftUART module is not enabled, so do advance to the
+ // idle state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_IDLE;
+ }
+
+ //
+ // See if the break signal should be asserted.
+ //
+ else if(psUART->ui8Flags & SOFTUART_FLAG_TXBREAK)
+ {
+ //
+ // The data line should be driven low while in the break state.
+ //
+ psUART->ui8TxNext = 0;
+
+ //
+ // Move to the break state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_BREAK;
+ }
+
+ //
+ // Otherwise, see if there is data in the transmit buffer.
+ //
+ else if(psUART->ui16TxBufferRead != psUART->ui16TxBufferWrite)
+ {
+ //
+ // The data line should be driven low to indicate a start bit.
+ //
+ psUART->ui8TxNext = 0;
+
+ //
+ // Move to the start bit state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_START;
+ }
+
+ //
+ // Otherwise, there is nothing to do.
+ //
+ else
+ {
+ //
+ // Assert the end of transmission "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_EOT;
+
+ //
+ // Advance to the idle state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_IDLE;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the break state.
+ //
+ case SOFTUART_TXSTATE_BREAK:
+ {
+ //
+ // See if the break should be deasserted.
+ //
+ if(!(psUART->ui8Flags & SOFTUART_FLAG_ENABLE) ||
+ !(psUART->ui8Flags & SOFTUART_FLAG_TXBREAK))
+ {
+ //
+ // The data line should be driven high to indicate it is idle.
+ //
+ psUART->ui8TxNext = 255;
+
+ //
+ // Advance to the idle state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_IDLE;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the UART peripheral.
+ //
+ while(((psUART->ui16IntStatus & psUART->ui16IntMask) != 0) &&
+ (psUART->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ psUART->pfnIntCallback();
+ }
+}
+
+//*****************************************************************************
+//
+//! Handles the assertion of the receive ``interrupt''.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function is used to determine when to assert the receive ``interrupt''
+//! as a result of writing data into the receive buffer (when characters are
+//! received from the Rx pin).
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTRxWriteInt(tSoftUART *psUART)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Determine the number of characters in the receive buffer.
+ //
+ if(psUART->ui16RxBufferWrite > psUART->ui16RxBufferRead)
+ {
+ ui32Temp = psUART->ui16RxBufferWrite - psUART->ui16RxBufferRead;
+ }
+ else
+ {
+ ui32Temp = (psUART->ui16RxBufferLen + psUART->ui16RxBufferWrite -
+ psUART->ui16RxBufferRead);
+ }
+
+ //
+ // If the receive buffer fullness just crossed the programmed level,
+ // generate a receive "interrupt".
+ //
+ if(ui32Temp == psUART->ui16RxBufferLevel)
+ {
+ psUART->ui16IntStatus |= SOFTUART_INT_RX;
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftUART receiver.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param bEdgeInt should be \b true if this function is being called because
+//! of a GPIO edge interrupt and \b false if it is being called because of a
+//! timer interrupt.
+//!
+//! This function performs the periodic, time-based updates to the SoftUART
+//! receiver. The reception of data to the SoftUART is performed by the state
+//! machine in this function.
+//!
+//! This function must be called by the GPIO interrupt handler, and then
+//! periodically at the desired SoftUART baud rate. For example, to run the
+//! SoftUART at 115,200 baud, this function must be called at a 115,200 Hz
+//! rate.
+//!
+//! \return Returns \b SOFTUART_RXTIMER_NOP if the receive timer should
+//! continue to operate or \b SOFTUART_RXTIMER_END if it should be stopped.
+//
+//*****************************************************************************
+uint32_t
+SoftUARTRxTick(tSoftUART *psUART, bool bEdgeInt)
+{
+ uint32_t ui32PinState, ui32Temp, ui32Ret;
+
+ //
+ // Read the current state of the Rx data line.
+ //
+ ui32PinState = MAP_GPIOPinRead(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+
+ //
+ // The default return code inidicates that the receive timer does not need
+ // to be stopped.
+ //
+ ui32Ret = SOFTUART_RXTIMER_NOP;
+
+ //
+ // See if this is an edge interrupt while delaying for the receive timeout
+ // interrupt.
+ //
+ if(bEdgeInt && (psUART->ui8RxState == SOFTUART_RXSTATE_DELAY))
+ {
+ //
+ // The receive timeout has been cancelled since the next character has
+ // started, so go to the idle state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(psUART->ui8RxState)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTUART_RXSTATE_IDLE:
+ {
+ //
+ // The falling edge of the start bit was just sampled, so disable
+ // the GPIO edge interrupt since the remainder of the character
+ // will be read using a timer tick.
+ //
+ GPIOIntClear(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+ GPIOIntDisable(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+
+ //
+ // Clear the receive data buffer.
+ //
+ psUART->ui8RxData = 0;
+
+ //
+ // Clear all reception errors other than overrun (which is cleared
+ // only when the first character after the overrun is written into
+ // the receive buffer), and set the break error (which is cleared
+ // if any non-zero bits are read during this character).
+ //
+ psUART->ui8RxFlags = ((psUART->ui8RxFlags & SOFTUART_RXFLAG_OE) |
+ SOFTUART_RXFLAG_BE);
+
+ //
+ // Advance to the first data bit state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_DATA_0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte is read. This
+ // depends upon RXSTATE_DATA_n and RXSTATE_DATA_(n+1) being
+ // consecutively numbered.
+ //
+ case SOFTUART_RXSTATE_DATA_0:
+ case SOFTUART_RXSTATE_DATA_1:
+ case SOFTUART_RXSTATE_DATA_2:
+ case SOFTUART_RXSTATE_DATA_3:
+ {
+ //
+ // See if the Rx pin is high.
+ //
+ if(ui32PinState != 0)
+ {
+ //
+ // Set this bit of the received character.
+ //
+ psUART->ui8RxData |= 1 << psUART->ui8RxState;
+
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // Advance to the next state.
+ //
+ psUART->ui8RxState++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte is read.
+ // Additionally, based on the configuration of the SoftUART, this bit
+ // might be the last bit of the data byte. This depends upon
+ // RXSTATE_DATA_n and RXSTATE_DATA_(n+1) being consecutively numbered.
+ //
+ case SOFTUART_RXSTATE_DATA_4:
+ case SOFTUART_RXSTATE_DATA_5:
+ case SOFTUART_RXSTATE_DATA_6:
+ case SOFTUART_RXSTATE_DATA_7:
+ {
+ //
+ // See if the Rx pin is high.
+ //
+ if(ui32PinState != 0)
+ {
+ //
+ // Set this bit of the received character.
+ //
+ psUART->ui8RxData |= 1 << psUART->ui8RxState;
+
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // See if the bit that was just transferred is the last bit of the
+ // data byte (based on the configuration of the SoftUART).
+ //
+ if(((psUART->ui16Config & SOFTUART_CONFIG_WLEN_MASK) >>
+ SOFTUART_CONFIG_WLEN_S) ==
+ (psUART->ui8RxState - SOFTUART_RXSTATE_DATA_4))
+ {
+ //
+ // See if parity is enabled.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) !=
+ SOFTUART_CONFIG_PAR_NONE)
+ {
+ //
+ // Advance to the parity state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_PARITY;
+ }
+
+ //
+ // Otherwise, see if there are one or two stop bits.
+ //
+ else if((psUART->ui16Config & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_STOP_0;
+ }
+
+ //
+ // Otherwise, advance to the one stop bit state.
+ //
+ else
+ {
+ psUART->ui8RxState = SOFTUART_RXSTATE_STOP_1;
+ }
+ }
+
+ //
+ // Otherwise, there are more bits to receive.
+ //
+ else
+ {
+ //
+ // Advance to the next state.
+ //
+ psUART->ui8RxState++;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the parity bit state.
+ //
+ case SOFTUART_RXSTATE_PARITY:
+ {
+ //
+ // See if the parity is set to one.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ONE)
+ {
+ //
+ // Set the expected parity to one.
+ //
+ ui32Temp = psUART->ui8RxPin;
+ }
+
+ //
+ // Otherwise, see if the parity is set to zero.
+ //
+ else if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ZERO)
+ {
+ //
+ // Set the expected parity to zero.
+ //
+ ui32Temp = 0;
+ }
+
+ //
+ // Otherwise, there is either even or odd parity.
+ //
+ else
+ {
+ //
+ // Find the odd parity for the data byte.
+ //
+ ui32Temp = ((g_pui32ParityOdd[psUART->ui8RxData >> 5] &
+ (1 << (psUART->ui8RxData & 31))) ?
+ psUART->ui8RxPin : 0);
+
+ //
+ // If the parity is set to even, then invert the parity just
+ // computed (making it even parity).
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_EVEN)
+ {
+ ui32Temp ^= psUART->ui8RxPin;
+ }
+ }
+
+ //
+ // See if the pin state matches the expected parity.
+ //
+ if(ui32PinState != ui32Temp)
+ {
+ //
+ // The parity does not match, so set the parity error flag.
+ //
+ psUART->ui8RxFlags |= SOFTUART_RXFLAG_PE;
+ }
+
+ //
+ // See if the Rx pin is high.
+ //
+ if(ui32PinState != 0)
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // See if there are one or two stop bits.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_STOP_0;
+ }
+ else
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_STOP_1;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the two stop bits state.
+ //
+ case SOFTUART_RXSTATE_STOP_0:
+ {
+ //
+ // See if the Rx pin is low.
+ //
+ if(ui32PinState == 0)
+ {
+ //
+ // Since the Rx pin is low, there is a framing error.
+ //
+ psUART->ui8RxFlags |= SOFTUART_RXFLAG_FE;
+ }
+ else
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // Advance to the one stop bit state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_STOP_1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the one stop bit state.
+ //
+ case SOFTUART_RXSTATE_STOP_1:
+ {
+ //
+ // See if the Rx pin is low.
+ //
+ if(ui32PinState == 0)
+ {
+ //
+ // Since the Rx pin is low, there is a framing error.
+ //
+ psUART->ui8RxFlags |= SOFTUART_RXFLAG_FE;
+ }
+ else
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // See if the break error is still asserted (meaning that every bit
+ // received was zero).
+ //
+ if(psUART->ui8RxFlags & SOFTUART_RXFLAG_BE)
+ {
+ //
+ // Since every bit was zero, advance to the break state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_BREAK;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // Compute the value of the write pointer advanced by one.
+ //
+ ui32Temp = psUART->ui16RxBufferWrite + 1;
+ if(ui32Temp == psUART->ui16RxBufferLen)
+ {
+ ui32Temp = 0;
+ }
+
+ //
+ // See if there is space in the receive buffer.
+ //
+ if(ui32Temp == psUART->ui16RxBufferRead)
+ {
+ //
+ // Set the overrun error flag. This will remain set until a
+ // new character can be placed into the receive buffer, which
+ // will then be given this status.
+ //
+ psUART->ui8RxFlags |= SOFTUART_RXFLAG_OE;
+
+ //
+ // Set the receive overrun "interrupt" and status if it is not
+ // already set.
+ //
+ if(!(psUART->ui8RxStatus & SOFTUART_RXERROR_OVERRUN))
+ {
+ psUART->ui8RxStatus |= SOFTUART_RXERROR_OVERRUN;
+ psUART->ui16IntStatus |= SOFTUART_INT_OE;
+ }
+ }
+
+ //
+ // Otherwise, there is space in the receive buffer.
+ //
+ else
+ {
+ //
+ // Write this data byte, along with the receive flags, into the
+ // receive buffer.
+ //
+ psUART->pui16RxBuffer[psUART->ui16RxBufferWrite] =
+ psUART->ui8RxData | (psUART->ui8RxFlags << 8);
+
+ //
+ // Advance the write pointer.
+ //
+ psUART->ui16RxBufferWrite = ui32Temp;
+
+ //
+ // Clear the receive flags, most importantly the overrun flag
+ // since it was just written into the receive buffer.
+ //
+ psUART->ui8RxFlags = 0;
+
+ //
+ // Assert the receive "interrupt" if appropriate.
+ //
+ SoftUARTRxWriteInt(psUART);
+ }
+
+ //
+ // See if this character had a parity error.
+ //
+ if(psUART->ui8RxFlags & SOFTUART_RXFLAG_PE)
+ {
+ //
+ // Assert the parity error "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_PE;
+ }
+
+ //
+ // See if this character had a framing error.
+ //
+ if(psUART->ui8RxFlags & SOFTUART_RXFLAG_FE)
+ {
+ //
+ // Assert the framing error "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_FE;
+ }
+
+ //
+ // Enable the falling edge interrupt on the Rx pin so that the next
+ // start bit can be detected.
+ //
+ GPIOIntClear(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+ GPIOIntEnable(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+
+ //
+ // Advance to the receive timeout delay state.
+ //
+ psUART->ui8RxData = 0;
+ psUART->ui8RxState = SOFTUART_RXSTATE_DELAY;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the break state.
+ //
+ case SOFTUART_RXSTATE_BREAK:
+ {
+ //
+ // See if the Rx pin is high.
+ //
+ if(ui32PinState != 0)
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // Compute the value of the write pointer advanced by one.
+ //
+ ui32Temp = psUART->ui16RxBufferWrite + 1;
+ if(ui32Temp == psUART->ui16RxBufferLen)
+ {
+ ui32Temp = 0;
+ }
+
+ //
+ // See if there is space in the receive buffer.
+ //
+ if(ui32Temp == psUART->ui16RxBufferRead)
+ {
+ //
+ // Set the overrun error flag. This will remain set until a
+ // new character can be placed into the receive buffer, which
+ // will then be given this status.
+ //
+ psUART->ui8RxFlags |= SOFTUART_RXFLAG_OE;
+
+ //
+ // Set the receive overrun "interrupt" and status if it is not
+ // already set.
+ //
+ if(!(psUART->ui8RxStatus & SOFTUART_RXERROR_OVERRUN))
+ {
+ psUART->ui8RxStatus |= SOFTUART_RXERROR_OVERRUN;
+ psUART->ui16IntStatus |= SOFTUART_INT_OE;
+ }
+ }
+
+ //
+ // Otherwise, there is space in the receive buffer.
+ //
+ else
+ {
+ //
+ // Write this data byte, along with the receive flags, into the
+ // receive buffer.
+ //
+ psUART->pui16RxBuffer[psUART->ui16RxBufferWrite] =
+ psUART->ui8RxData | (psUART->ui8RxFlags << 8);
+
+ //
+ // Advance the write pointer.
+ //
+ psUART->ui16RxBufferWrite = ui32Temp;
+
+ //
+ // Clear the receive flags, most importantly the overrun flag
+ // since it was just written into the receive buffer.
+ //
+ psUART->ui8RxFlags = 0;
+
+ //
+ // Assert the receive "interrupt" if appropriate.
+ //
+ SoftUARTRxWriteInt(psUART);
+ }
+
+ //
+ // See if this was a break error.
+ //
+ if(psUART->ui8RxFlags & SOFTUART_RXFLAG_BE)
+ {
+ //
+ // Assert the break error "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_BE;
+ }
+
+ //
+ // See if this character had a parity error.
+ //
+ if(psUART->ui8RxFlags & SOFTUART_RXFLAG_PE)
+ {
+ //
+ // Assert the parity error "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_PE;
+ }
+
+ //
+ // Assert the framing error "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_FE;
+
+ //
+ // Enable the falling edge interrupt on the Rx pin so that the next
+ // start bit can be detected.
+ //
+ GPIOIntClear(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+ GPIOIntEnable(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+
+ //
+ // Advance to the receive timeout delay state.
+ //
+ psUART->ui8RxData = 0;
+ psUART->ui8RxState = SOFTUART_RXSTATE_DELAY;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the receive timeout delay state.
+ //
+ case SOFTUART_RXSTATE_DELAY:
+ {
+ //
+ // See if the receive timeout has expired.
+ //
+ if(psUART->ui8RxData++ == 32)
+ {
+ //
+ // Assert the receive timeout "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_RT;
+
+ //
+ // Tell the caller that the receive timer can be disabled.
+ //
+ ui32Ret = SOFTUART_RXTIMER_END;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the UART peripheral.
+ //
+ while(((psUART->ui16IntStatus & psUART->ui16IntMask) != 0) &&
+ (psUART->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ psUART->pfnIntCallback();
+ }
+
+ //
+ // Return to the caller.
+ //
+ return(ui32Ret);
+}
+
+//*****************************************************************************
+//
+//! Sets the type of parity.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32Parity specifies the type of parity to use.
+//!
+//! Sets the type of parity to use for transmitting and expect when receiving.
+//! The \e ui32Parity parameter must be one of \b SOFTUART_CONFIG_PAR_NONE,
+//! \b SOFTUART_CONFIG_PAR_EVEN, \b SOFTUART_CONFIG_PAR_ODD,
+//! \b SOFTUART_CONFIG_PAR_ONE, or \b SOFTUART_CONFIG_PAR_ZERO. The last two
+//! allow direct control of the parity bit; it is always either one or zero
+//! based on the mode.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTParityModeSet(tSoftUART *psUART, uint32_t ui32Parity)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ui32Parity == SOFTUART_CONFIG_PAR_NONE) ||
+ (ui32Parity == SOFTUART_CONFIG_PAR_EVEN) ||
+ (ui32Parity == SOFTUART_CONFIG_PAR_ODD) ||
+ (ui32Parity == SOFTUART_CONFIG_PAR_ONE) ||
+ (ui32Parity == SOFTUART_CONFIG_PAR_ZERO));
+
+ //
+ // Set the parity mode.
+ //
+ psUART->ui16Config =
+ (psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) | ui32Parity;
+}
+
+//*****************************************************************************
+//
+//! Gets the type of parity currently being used.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function gets the type of parity used for transmitting data and
+//! expected when receiving data.
+//!
+//! \return Returns the current parity settings, specified as one of
+//! \b SOFTUART_CONFIG_PAR_NONE, \b SOFTUART_CONFIG_PAR_EVEN,
+//! \b SOFTUART_CONFIG_PAR_ODD, \b SOFTUART_CONFIG_PAR_ONE, or
+//! \b SOFTUART_CONFIG_PAR_ZERO.
+//
+//*****************************************************************************
+uint32_t
+SoftUARTParityModeGet(tSoftUART *psUART)
+{
+ //
+ // Return the current parity setting.
+ //
+ return(psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK);
+}
+
+//*****************************************************************************
+//
+//! Sets the transmit ``interrupt'' buffer level.
+//!
+//! \param psUART specifies the soft UART data structure.
+//!
+//! This function computes the transmit buffer level at which the transmit
+//! ``interrupt'' is generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTTxLevelSet(tSoftUART *psUART)
+{
+ //
+ // Determine the transmit buffer "interrupt" fullness setting.
+ //
+ switch(psUART->ui16Config & SOFTUART_CONFIG_TXLVL_M)
+ {
+ //
+ // The transmit "interrupt" should be generated when the buffer is 1/8
+ // full.
+ //
+ case SOFTUART_CONFIG_TXLVL_1:
+ {
+ //
+ // Set the transmit buffer level to 1/8 of the buffer length.
+ //
+ psUART->ui16TxBufferLevel = psUART->ui16TxBufferLen / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 1/4
+ // (2/8) full.
+ //
+ case SOFTUART_CONFIG_TXLVL_2:
+ {
+ //
+ // Set the transmit buffer level to 1/4 of the buffer length.
+ //
+ psUART->ui16TxBufferLevel = psUART->ui16TxBufferLen / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 1/2
+ // (4/8) full.
+ //
+ case SOFTUART_CONFIG_TXLVL_4:
+ {
+ //
+ // Set the transmit buffer level to 1/2 of the buffer length.
+ //
+ psUART->ui16TxBufferLevel = psUART->ui16TxBufferLen / 2;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 3/4
+ // (6/8) full.
+ //
+ case SOFTUART_CONFIG_TXLVL_6:
+ {
+ //
+ // Set the transmit buffer level to 3/4 of the buffer length.
+ //
+ psUART->ui16TxBufferLevel = (psUART->ui16TxBufferLen * 3) / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 7/8
+ // full.
+ //
+ case SOFTUART_CONFIG_TXLVL_7:
+ {
+ //
+ // Set the transmit buffer level to 7/8 of the buffer length.
+ //
+ psUART->ui16TxBufferLevel = (psUART->ui16TxBufferLen * 7) / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the receive ``interrupt'' buffer level.
+//!
+//! \param psUART specifies the soft UART data structure.
+//!
+//! This function computes the receive buffer level at which the receive
+//! ``interrupt'' is generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTRxLevelSet(tSoftUART *psUART)
+{
+ //
+ // Determine the receive buffer "interrupt" fullness setting.
+ //
+ switch(psUART->ui16Config & SOFTUART_CONFIG_RXLVL_M)
+ {
+ //
+ // The receive "interrupt" should be generated when the buffer is 1/8
+ // full.
+ //
+ case SOFTUART_CONFIG_RXLVL_1:
+ {
+ //
+ // Set the receive buffer level to 1/8 of the buffer length.
+ //
+ psUART->ui16RxBufferLevel = psUART->ui16RxBufferLen / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 1/4
+ // (2/8) full.
+ //
+ case SOFTUART_CONFIG_RXLVL_2:
+ {
+ //
+ // Set the receive buffer level to 1/4 of the buffer length.
+ //
+ psUART->ui16RxBufferLevel = psUART->ui16RxBufferLen / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 1/2
+ // (4/8) full.
+ //
+ case SOFTUART_CONFIG_RXLVL_4:
+ {
+ //
+ // Set the receive buffer level to 1/2 of the buffer length.
+ //
+ psUART->ui16RxBufferLevel = psUART->ui16RxBufferLen / 2;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 3/4
+ // (6/8) full.
+ //
+ case SOFTUART_CONFIG_RXLVL_6:
+ {
+ //
+ // Set the receive buffer level to 3/4 of the buffer length.
+ //
+ psUART->ui16RxBufferLevel = (psUART->ui16RxBufferLen * 3) / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 7/8
+ // full.
+ //
+ case SOFTUART_CONFIG_RXLVL_7:
+ {
+ //
+ // Set the receive buffer level to 7/8 of the buffer length.
+ //
+ psUART->ui16RxBufferLevel = (psUART->ui16RxBufferLen * 7) / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the buffer level at which ``interrupts'' are generated.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32TxLevel is the transmit buffer ``interrupt'' level, specified as
+//! one of \b UART_FIFO_TX1_8, \b UART_FIFO_TX2_8, \b UART_FIFO_TX4_8,
+//! \b UART_FIFO_TX6_8, or \b UART_FIFO_TX7_8.
+//! \param ui32RxLevel is the receive buffer ``interrupt'' level, specified as
+//! one of \b UART_FIFO_RX1_8, \b UART_FIFO_RX2_8, \b UART_FIFO_RX4_8,
+//! \b UART_FIFO_RX6_8, or \b UART_FIFO_RX7_8.
+//!
+//! This function sets the buffer level at which transmit and receive
+//! ``interrupts'' are generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTFIFOLevelSet(tSoftUART *psUART, uint32_t ui32TxLevel,
+ uint32_t ui32RxLevel)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ui32TxLevel == SOFTUART_FIFO_TX1_8) ||
+ (ui32TxLevel == SOFTUART_FIFO_TX2_8) ||
+ (ui32TxLevel == SOFTUART_FIFO_TX4_8) ||
+ (ui32TxLevel == SOFTUART_FIFO_TX6_8) ||
+ (ui32TxLevel == SOFTUART_FIFO_TX7_8));
+ ASSERT((ui32RxLevel == SOFTUART_FIFO_RX1_8) ||
+ (ui32RxLevel == SOFTUART_FIFO_RX2_8) ||
+ (ui32RxLevel == SOFTUART_FIFO_RX4_8) ||
+ (ui32RxLevel == SOFTUART_FIFO_RX6_8) ||
+ (ui32RxLevel == SOFTUART_FIFO_RX7_8));
+
+ //
+ // Save the buffer "interrupt" levels.
+ //
+ psUART->ui16Config = ((psUART->ui16Config & SOFTUART_CONFIG_BASE_M) |
+ ((ui32TxLevel | ui32RxLevel) << 8));
+
+ //
+ // Compute the new buffer "interrupt" levels.
+ //
+ SoftUARTTxLevelSet(psUART);
+ SoftUARTRxLevelSet(psUART);
+}
+
+//*****************************************************************************
+//
+//! Gets the buffer level at which ``interrupts'' are generated.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param pui32TxLevel is a pointer to storage for the transmit buffer level,
+//! returned as one of \b UART_FIFO_TX1_8, \b UART_FIFO_TX2_8,
+//! \b UART_FIFO_TX4_8, \b UART_FIFO_TX6_8, or \b UART_FIFO_TX7_8.
+//! \param pui32RxLevel is a pointer to storage for the receive buffer level,
+//! returned as one of \b UART_FIFO_RX1_8, \b UART_FIFO_RX2_8,
+//! \b UART_FIFO_RX4_8, \b UART_FIFO_RX6_8, or \b UART_FIFO_RX7_8.
+//!
+//! This function gets the buffer level at which transmit and receive
+//! ``interrupts'' are generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTFIFOLevelGet(tSoftUART *psUART, uint32_t *pui32TxLevel,
+ uint32_t *pui32RxLevel)
+{
+ //
+ // Extract the transmit and receive buffer levels.
+ //
+ *pui32TxLevel = (psUART->ui16Config & SOFTUART_CONFIG_TXLVL_M) >> 8;
+ *pui32RxLevel = (psUART->ui16Config & SOFTUART_CONFIG_RXLVL_M) >> 8;
+}
+
+//*****************************************************************************
+//
+//! Gets the current configuration of a UART.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param pui32Config is a pointer to storage for the data format.
+//!
+//! Returns the data format of the SoftUART. The data format returned in
+//! \e pui32Config is enumerated the same as the \e ui32Config parameter of
+//! SoftUARTConfigSet().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTConfigGet(tSoftUART *psUART, uint32_t *pui32Config)
+{
+ //
+ // Get the data format.
+ //
+ *pui32Config = psUART->ui16Config & SOFTUART_CONFIG_BASE_M;
+}
+
+//*****************************************************************************
+//
+//! Enables the SoftUART.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function enables the SoftUART, allowing data to be transmitted and
+//! received.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTEnable(tSoftUART *psUART)
+{
+ //
+ // Enable the SoftUART.
+ //
+ psUART->ui8Flags |= SOFTUART_FLAG_ENABLE;
+}
+
+//*****************************************************************************
+//
+//! Disables the SoftUART.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function disables the SoftUART after waiting for it to become idle.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTDisable(tSoftUART *psUART)
+{
+ //
+ // Wait for end of TX.
+ //
+ while(SoftUARTBusy(psUART))
+ {
+ }
+
+ //
+ // Disable the SoftUART.
+ //
+ psUART->ui8Flags &= ~(SOFTUART_FLAG_ENABLE);
+}
+
+//*****************************************************************************
+//
+//! Determines if there are any characters in the receive buffer.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function returns a flag indicating whether or not there is data
+//! available in the receive buffer.
+//!
+//! \return Returns \b true if there is data in the receive buffer or \b false
+//! if there is no data in the receive buffer.
+//
+//*****************************************************************************
+bool
+SoftUARTCharsAvail(tSoftUART *psUART)
+{
+ //
+ // Return the availability of characters.
+ //
+ return((psUART->ui16RxBufferRead == psUART->ui16RxBufferWrite) ? false :
+ true);
+}
+
+//*****************************************************************************
+//
+//! Determines if there is any space in the transmit buffer.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function returns a flag indicating whether or not there is space
+//! available in the transmit buffer.
+//!
+//! \return Returns \b true if there is space available in the transmit buffer
+//! or \b false if there is no space available in the transmit buffer.
+//
+//*****************************************************************************
+bool
+SoftUARTSpaceAvail(tSoftUART *psUART)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ ui16Temp = psUART->ui16TxBufferWrite + 1;
+ if(ui16Temp == psUART->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+
+ //
+ // Return the availability of space.
+ //
+ return((psUART->ui16TxBufferRead == ui16Temp) ? false : true);
+}
+
+//*****************************************************************************
+//
+//! Handles the deassertion of the receive ``interrupts''.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function is used to determine when to deassert the receive
+//! ``interrupt'' as a result of reading data from the receive buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTRxReadInt(tSoftUART *psUART)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Determine the number of characters in the receive buffer.
+ //
+ if(psUART->ui16RxBufferWrite > psUART->ui16RxBufferRead)
+ {
+ ui32Temp = psUART->ui16RxBufferWrite - psUART->ui16RxBufferRead;
+ }
+ else
+ {
+ ui32Temp = (psUART->ui16RxBufferLen + psUART->ui16RxBufferWrite -
+ psUART->ui16RxBufferRead);
+ }
+
+ //
+ // See if the number of characters in the receive buffer have dropped below
+ // the receive trigger level.
+ //
+ if(ui32Temp < psUART->ui16RxBufferLevel)
+ {
+ //
+ // Deassert the receive "interrupt".
+ //
+ psUART->ui16IntStatus &= ~(SOFTUART_INT_RX);
+ }
+
+ //
+ // See if the receive buffer is now empty.
+ //
+ if(ui32Temp == 0)
+ {
+ //
+ // Deassert the receive timeout "interrupt".
+ //
+ psUART->ui16IntStatus &= ~(SOFTUART_INT_RT);
+ }
+}
+
+//*****************************************************************************
+//
+//! Receives a character from the specified port.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! Gets a character from the receive buffer for the specified port.
+//!
+//! \return Returns the character read from the specified port, cast as a
+//! \e int32_t. A \b -1 is returned if there are no characters present in the
+//! receive buffer. The SoftUARTCharsAvail() function should be called before
+//! attempting to call this function.
+//
+//*****************************************************************************
+int32_t
+SoftUARTCharGetNonBlocking(tSoftUART *psUART)
+{
+ int32_t i32Temp;
+
+ //
+ // See if there are any characters in the receive buffer.
+ //
+ if(psUART->ui16RxBufferRead != psUART->ui16RxBufferWrite)
+ {
+ //
+ // Read the next character.
+ //
+ i32Temp = psUART->pui16RxBuffer[psUART->ui16RxBufferRead];
+ psUART->ui16RxBufferRead++;
+ if(psUART->ui16RxBufferRead == psUART->ui16RxBufferLen)
+ {
+ psUART->ui16RxBufferRead = 0;
+ }
+
+ //
+ // Deassert the receive "interrupt(s)" if appropriate.
+ //
+ SoftUARTRxReadInt(psUART);
+
+ //
+ // Set the receive status to match this character.
+ //
+ psUART->ui8RxStatus =
+ ((psUART->ui8RxStatus & SOFTUART_RXERROR_OVERRUN) |
+ ((i32Temp >> 8) & ~(SOFTUART_RXERROR_OVERRUN)));
+
+ //
+ // Return this character.
+ //
+ return(i32Temp);
+ }
+ else
+ {
+ //
+ // There are no characters, so return a failure.
+ //
+ return(-1);
+ }
+}
+
+//*****************************************************************************
+//
+//! Waits for a character from the specified port.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! Gets a character from the receive buffer for the specified port. If there
+//! are no characters available, this function waits until a character is
+//! received before returning.
+//!
+//! \return Returns the character read from the specified port, cast as a
+//! \e int32_t.
+//
+//*****************************************************************************
+int32_t
+SoftUARTCharGet(tSoftUART *psUART)
+{
+ int32_t i32Temp;
+
+ //
+ // Wait until a int8_t is available.
+ //
+ while(psUART->ui16RxBufferRead ==
+ *(volatile uint16_t *)(&(psUART->ui16RxBufferWrite)))
+ {
+ }
+
+ //
+ // Read the next character.
+ //
+ i32Temp = psUART->pui16RxBuffer[psUART->ui16RxBufferRead];
+ psUART->ui16RxBufferRead++;
+ if(psUART->ui16RxBufferRead == psUART->ui16RxBufferLen)
+ {
+ psUART->ui16RxBufferRead = 0;
+ }
+
+ //
+ // Deassert the receive "interrupt(s)" if appropriate.
+ //
+ SoftUARTRxReadInt(psUART);
+
+ //
+ // Set the receive status to match this character.
+ //
+ psUART->ui8RxStatus = ((psUART->ui8RxStatus & SOFTUART_RXERROR_OVERRUN) |
+ ((i32Temp >> 8) & ~(SOFTUART_RXERROR_OVERRUN)));
+
+ //
+ // Return this character.
+ //
+ return(i32Temp);
+}
+
+//*****************************************************************************
+//
+//! Sends a character to the specified port.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui8Data is the character to be transmitted.
+//!
+//! Writes the character \e ui8Data to the transmit buffer for the specified
+//! port. This function does not block, so if there is no space available,
+//! then a \b false is returned, and the application must retry the function
+//! later.
+//!
+//! \return Returns \b true if the character was successfully placed in the
+//! transmit buffer or \b false if there was no space available in the
+//! transmit buffer.
+//
+//*****************************************************************************
+bool
+SoftUARTCharPutNonBlocking(tSoftUART *psUART, uint8_t ui8Data)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ ui16Temp = psUART->ui16TxBufferWrite + 1;
+ if(ui16Temp == psUART->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+
+ //
+ // See if there is space in the transmit buffer.
+ //
+ if(ui16Temp != psUART->ui16TxBufferRead)
+ {
+ //
+ // Write this character to the transmit buffer.
+ //
+ psUART->pui8TxBuffer[psUART->ui16TxBufferWrite] = ui8Data;
+ psUART->ui16TxBufferWrite = ui16Temp;
+
+ //
+ // Success.
+ //
+ return(true);
+ }
+ else
+ {
+ //
+ // There is no space in the transmit buffer, so return a failure.
+ //
+ return(false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Waits to send a character from the specified port.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui8Data is the character to be transmitted.
+//!
+//! Sends the character \e ui8Data to the transmit buffer for the specified
+//! port. If there is no space available in the transmit buffer, this function
+//! waits until there is space available before returning.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTCharPut(tSoftUART *psUART, uint8_t ui8Data)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Wait until space is available.
+ //
+ ui16Temp = psUART->ui16TxBufferWrite + 1;
+ if(ui16Temp == psUART->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+ while(ui16Temp == *(volatile uint16_t *)(&(psUART->ui16TxBufferRead)))
+ {
+ }
+
+ //
+ // Send the int8_t.
+ //
+ psUART->pui8TxBuffer[psUART->ui16TxBufferWrite] = ui8Data;
+ psUART->ui16TxBufferWrite = ui16Temp;
+}
+
+//*****************************************************************************
+//
+//! Causes a BREAK to be sent.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param bBreakState controls the output level.
+//!
+//! Calling this function with \e bBreakState set to \b true asserts a break
+//! condition on the SoftUART. Calling this function with \e bBreakState set
+//! to \b false removes the break condition. For proper transmission of a
+//! break command, the break must be asserted for at least two complete frames.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTBreakCtl(tSoftUART *psUART, bool bBreakState)
+{
+ //
+ // Set the break condition as requested.
+ //
+ if(bBreakState)
+ {
+ psUART->ui8Flags |= SOFTUART_FLAG_TXBREAK;
+ }
+ else
+ {
+ psUART->ui8Flags &= ~(SOFTUART_FLAG_TXBREAK);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether the UART transmitter is busy or not.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! Allows the caller to determine whether all transmitted bytes have cleared
+//! the transmitter hardware. If \b false is returned, the transmit buffer is
+//! empty and all bits of the last transmitted character, including all stop
+//! bits, have left the hardware shift register.
+//!
+//! \return Returns \b true if the UART is transmitting or \b false if all
+//! transmissions are complete.
+//
+//*****************************************************************************
+bool
+SoftUARTBusy(tSoftUART *psUART)
+{
+ //
+ // Determine if the UART is busy.
+ //
+ return(((psUART->ui8TxState == SOFTUART_TXSTATE_IDLE) &&
+ (((psUART->ui8Flags & SOFTUART_FLAG_ENABLE) == 0) ||
+ (psUART->ui16TxBufferRead == psUART->ui16TxBufferWrite))) ?
+ false : true);
+}
+
+//*****************************************************************************
+//
+//! Enables individual SoftUART ``interrupt'' sources.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32IntFlags is the bit mask of the ``interrupt'' sources to be
+//! enabled.
+//!
+//! Enables the indicated SoftUART ``interrupt'' sources. Only the sources
+//! that are enabled can be reflected to the SoftUART callback.
+//!
+//! The \e ui32IntFlags parameter is the logical OR of any of the following:
+//!
+//! - \b SOFTUART_INT_OE - Overrun Error ``interrupt''
+//! - \b SOFTUART_INT_BE - Break Error ``interrupt''
+//! - \b SOFTUART_INT_PE - Parity Error ``interrupt''
+//! - \b SOFTUART_INT_FE - Framing Error ``interrupt''
+//! - \b SOFTUART_INT_RT - Receive Timeout ``interrupt''
+//! - \b SOFTUART_INT_TX - Transmit ``interrupt''
+//! - \b SOFTUART_INT_RX - Receive ``interrupt''
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTIntEnable(tSoftUART *psUART, uint32_t ui32IntFlags)
+{
+ //
+ // Enable the specified interrupts.
+ //
+ psUART->ui16IntMask |= ui32IntFlags;
+}
+
+//*****************************************************************************
+//
+//! Disables individual SoftUART ``interrupt'' sources.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32IntFlags is the bit mask of the ``interrupt'' sources to be
+//! disabled.
+//!
+//! Disables the indicated SoftUART ``interrupt'' sources. Only the sources
+//! that are enabled can be reflected to the SoftUART callback.
+//!
+//! The \e ui32IntFlags parameter has the same definition as the
+//! \e ui32IntFlags parameter to SoftUARTIntEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTIntDisable(tSoftUART *psUART, uint32_t ui32IntFlags)
+{
+ //
+ // Disable the specified interrupts.
+ //
+ psUART->ui16IntMask &= ~(ui32IntFlags);
+}
+
+//*****************************************************************************
+//
+//! Gets the current SoftUART ``interrupt'' status.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param bMasked is \b false if the raw ``interrupt'' status is required and
+//! \b true if the masked ``interrupt'' status is required.
+//!
+//! This returns the ``interrupt'' status for the SoftUART. Either the raw
+//! ``interrupt'' status or the status of ``interrupts'' that are allowed to
+//! reflect to the SoftUART callback can be returned.
+//!
+//! \return Returns the current ``interrupt'' status, enumerated as a bit field
+//! of values described in SoftUARTIntEnable().
+//
+//*****************************************************************************
+uint32_t
+SoftUARTIntStatus(tSoftUART *psUART, bool bMasked)
+{
+ //
+ // Return either the interrupt status or the raw interrupt status as
+ // requested.
+ //
+ if(bMasked)
+ {
+ return(psUART->ui16IntStatus & psUART->ui16IntMask);
+ }
+ else
+ {
+ return(psUART->ui16IntStatus);
+ }
+}
+
+//*****************************************************************************
+//
+//! Clears SoftUART ``interrupt'' sources.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32IntFlags is a bit mask of the ``interrupt'' sources to be
+//! cleared.
+//!
+//! The specified SoftUART ``interrupt'' sources are cleared, so that they no
+//! longer assert. This function must be called in the callback function to
+//! keep the ``interrupt'' from being recognized again immediately upon exit.
+//!
+//! The \e ui32IntFlags parameter has the same definition as the
+//! \e ui32IntFlags parameter to SoftUARTIntEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTIntClear(tSoftUART *psUART, uint32_t ui32IntFlags)
+{
+ //
+ // Clear the requested interrupt sources.
+ //
+ psUART->ui16IntStatus &= ~(ui32IntFlags);
+}
+
+//*****************************************************************************
+//
+//! Gets current receiver errors.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function returns the current state of each of the 4 receiver error
+//! sources. The returned errors are equivalent to the four error bits
+//! returned via the previous call to SoftUARTCharGet() or
+//! SoftUARTCharGetNonBlocking() with the exception that the overrun error is
+//! set immediately when the overrun occurs rather than when a character is
+//! next read.
+//!
+//! \return Returns a logical OR combination of the receiver error flags,
+//! \b SOFTUART_RXERROR_FRAMING, \b SOFTUART_RXERROR_PARITY,
+//! \b SOFTUART_RXERROR_BREAK and \b SOFTUART_RXERROR_OVERRUN.
+//
+//*****************************************************************************
+uint32_t
+SoftUARTRxErrorGet(tSoftUART *psUART)
+{
+ //
+ // Return the current value of the receive status.
+ //
+ return(psUART->ui8RxStatus);
+}
+
+//*****************************************************************************
+//
+//! Clears all reported receiver errors.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function is used to clear all receiver error conditions reported via
+//! SoftUARTRxErrorGet(). If using the overrun, framing error, parity error or
+//! break interrupts, this function must be called after clearing the interrupt
+//! to ensure that later errors of the same type trigger another interrupt.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTRxErrorClear(tSoftUART *psUART)
+{
+ //
+ // Clear any receive error status.
+ //
+ psUART->ui8RxStatus = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the callback used by the SoftUART module.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param pfnCallback is a pointer to the callback function.
+//!
+//! This function sets the address of the callback function that is called when
+//! there is an ``interrupt'' produced by the SoftUART module.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTCallbackSet(tSoftUART *psUART, void (*pfnCallback)(void))
+{
+ //
+ // Save the callback function address.
+ //
+ psUART->pfnIntCallback = pfnCallback;
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftUART Tx signal.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used when the SoftUART must assert
+//! the Tx signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTTxGPIOSet(tSoftUART *psUART, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Tx signal.
+ //
+ if(ui32Base == 0)
+ {
+ psUART->ui32TxGPIO = 0;
+ }
+ else
+ {
+ psUART->ui32TxGPIO = ui32Base + (ui8Pin << 2);
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftUART Rx signal.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used when the SoftUART must sample
+//! the Rx signal. If there is not a GPIO pin allocated for Rx, the SoftUART
+//! module will not read data from the slave device.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTRxGPIOSet(tSoftUART *psUART, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Rx signal.
+ //
+ if(ui32Base == 0)
+ {
+ psUART->ui32RxGPIOPort = 0;
+ psUART->ui8RxPin = 0;
+ }
+ else
+ {
+ psUART->ui32RxGPIOPort = ui32Base;
+ psUART->ui8RxPin = ui8Pin;
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the transmit buffer for a SoftUART module.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param pui8TxBuffer is the address of the transmit buffer.
+//! \param ui16Len is the size, in 8-bit bytes, of the transmit buffer.
+//!
+//! This function sets the address and size of the transmit buffer. It also
+//! resets the read and write pointers, marking the transmit buffer as empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTTxBufferSet(tSoftUART *psUART, uint8_t *pui8TxBuffer, uint16_t ui16Len)
+{
+ //
+ // Save the transmit buffer address and length.
+ //
+ psUART->pui8TxBuffer = pui8TxBuffer;
+ psUART->ui16TxBufferLen = ui16Len;
+
+ //
+ // Reset the transmit buffer read and write pointers.
+ //
+ psUART->ui16TxBufferRead = 0;
+ psUART->ui16TxBufferWrite = 0;
+
+ //
+ // Compute the new buffer "interrupt" level.
+ //
+ SoftUARTTxLevelSet(psUART);
+}
+
+//*****************************************************************************
+//
+//! Sets the receive buffer for a SoftUART module.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param pui16RxBuffer is the address of the receive buffer.
+//! \param ui16Len is the size, in 16-bit half-words, of the receive buffer.
+//!
+//! This function sets the address and size of the receive buffer. It also
+//! resets the read and write pointers, marking the receive buffer as empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTRxBufferSet(tSoftUART *psUART, uint16_t *pui16RxBuffer,
+ uint16_t ui16Len)
+{
+ //
+ // Save the receive buffer address and length.
+ //
+ psUART->pui16RxBuffer = pui16RxBuffer;
+ psUART->ui16RxBufferLen = ui16Len;
+
+ //
+ // Reset the receive read and write pointers.
+ //
+ psUART->ui16RxBufferRead = 0;
+ psUART->ui16RxBufferWrite = 0;
+
+ //
+ // Compute the new buffer "interrupt" level.
+ //
+ SoftUARTRxLevelSet(psUART);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/softuart.h b/utils/softuart.h
new file mode 100644
index 0000000..d9184d7
--- /dev/null
+++ b/utils/softuart.h
@@ -0,0 +1,375 @@
+//*****************************************************************************
+//
+// softuart.h - Defines and macros for the SoftUART.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SOFTUART_H__
+#define __SOFTUART_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup softuart_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure contains the state of a single instance of a SoftUART
+//! module.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The address of the callback function that is called to simulate the
+ //! interrupts that would be produced by a hardware UART implementation.
+ //! This address can be set via a direct structure access or using the
+ //! SoftUARTCallbackSet function.
+ //
+ void (*pfnIntCallback)(void);
+
+ //
+ //! The address of the GPIO pin to be used for the Tx signal. This member
+ //! can be set via a direct structure access or using the SoftUARTTxGPIOSet
+ //! function.
+ //
+ uint32_t ui32TxGPIO;
+
+ //
+ //! The address of the GPIO port to be used for the Rx signal. This member
+ //! can be set via a direct structure access or using the SoftUARTRxGPIOSet
+ //! function.
+ //
+ uint32_t ui32RxGPIOPort;
+
+ //
+ //! The address of the data buffer used for the transmit buffer. This
+ //! member can be set via a direct structure access or using the
+ //! SoftUARTTxBufferSet function.
+ //
+ uint8_t *pui8TxBuffer;
+
+ //
+ //! The address of the data buffer used for the receive buffer. This
+ //! member can be set via a direct structure access or using the
+ //! SoftUARTRxBufferSet function.
+ //
+ uint16_t *pui16RxBuffer;
+
+ //
+ //! The length of the transmit buffer. This member can be set via a direct
+ //! structure access or using the SoftUARTTxBufferSet function.
+ //
+ uint16_t ui16TxBufferLen;
+
+ //
+ //! The index into the transmit buffer of the next character to be
+ //! transmitted. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint16_t ui16TxBufferRead;
+
+ //
+ //! The index into the transmit buffer of the next location to store a
+ //! character into the buffer. This member should not be accessed or
+ //! modified by the application.
+ //
+ uint16_t ui16TxBufferWrite;
+
+ //
+ //! The transmit buffer level at which the transmit interrupt is asserted.
+ //! This member should not be accessed or modified by the application.
+ //
+ uint16_t ui16TxBufferLevel;
+
+ //
+ //! The length of the receive buffer. This member can be set via a direct
+ //! structure access or using the SoftUARTRxBufferSet function.
+ //
+ uint16_t ui16RxBufferLen;
+
+ //
+ //! The index into the receive buffer of the next character to be read from
+ //! the buffer. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint16_t ui16RxBufferRead;
+
+ //
+ //! The index into the receive buffer of the lcoation to store the next
+ //! character received. This member should not be accessed or modified by
+ //! the application.
+ //
+ uint16_t ui16RxBufferWrite;
+
+ //
+ //! The receive buffer level at which the receive interrupt is asserted.
+ //! This member should not be accessed or modified by the application.
+ //
+ uint16_t ui16RxBufferLevel;
+
+ //
+ //! The set of virtual interrupts that are currently asserted. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint16_t ui16IntStatus;
+
+ //
+ //! The set of virtual interrupts that should be sent to the callback
+ //! function. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint16_t ui16IntMask;
+
+ //
+ //! The configuration of the SoftUART module. This member can be set via
+ //! the SoftUARTConfigSet and SoftUARTFIFOLevelSet functions.
+ //
+ uint16_t ui16Config;
+
+ //
+ //! The flags that control the operation of the SoftUART module. This
+ //! member should not be be accessed or modified by the application.
+ //
+ uint8_t ui8Flags;
+
+ //
+ //! The current state of the SoftUART transmit state machine. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8TxState;
+
+ //
+ //! The value that is written to the Tx pin at the start of the next
+ //! transmit timer tick. This member should not be accessed or modified
+ //! by the application.
+ //
+ uint8_t ui8TxNext;
+
+ //
+ //! The character that is currently be sent via the Tx pin. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8TxData;
+
+ //
+ //! The GPIO pin to be used for the Rx signal. This member can be set via
+ //! a direct structure access or using the SoftUARTRxGPIOSet function.
+ //
+ uint8_t ui8RxPin;
+
+ //
+ //! The current state of the SoftUART receive state machine. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8RxState;
+
+ //
+ //! The character that is currently being received via the Rx pin. This
+ //! member should not be accessed or modified by the application.
+ //
+ uint8_t ui8RxData;
+
+ //
+ //! The flags that indicate any errors that have occurred during the
+ //! reception of the current character via the Rx pin. This member should
+ //! not be accessed or modified by the application.
+ //
+ uint8_t ui8RxFlags;
+
+ //
+ //! The receive error status. This member should only be accessed via the
+ //! SoftUARTRxErrorGet and SoftURATRxErrorClear functions.
+ //
+ uint8_t ui8RxStatus;
+}
+tSoftUART;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTIntEnable(), SoftUARTIntDisable(), and
+// SoftUARTIntClear() as the ui32IntFlags parameter, and returned from
+// SoftUARTIntStatus().
+//
+//*****************************************************************************
+#define SOFTUART_INT_EOT 0x800 // End of transmission interrupt
+#define SOFTUART_INT_OE 0x400 // Overrun error interrupt
+#define SOFTUART_INT_BE 0x200 // Break error interrupt
+#define SOFTUART_INT_PE 0x100 // Parity error interrupt
+#define SOFTUART_INT_FE 0x080 // Framing error interrupt
+#define SOFTUART_INT_RT 0x040 // Receive timeout interrupt
+#define SOFTUART_INT_TX 0x020 // Transmit interrupt
+#define SOFTUART_INT_RX 0x010 // Receive interrupt
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTConfigSet() as the ui32Config parameter
+// and returned by SoftUARTConfigGet() in the pui32Config parameter.
+// Additionally, the UART_CONFIG_PAR_* subset can be passed to
+// SoftUARTParityModeSet() as the ui32Parity parameter, and are returned by
+// SoftUARTParityModeGet().
+//
+//*****************************************************************************
+#define SOFTUART_CONFIG_WLEN_MASK \
+ 0x00000060 // Mask for extracting word length
+#define SOFTUART_CONFIG_WLEN_8 0x00000060 // 8 bit data
+#define SOFTUART_CONFIG_WLEN_7 0x00000040 // 7 bit data
+#define SOFTUART_CONFIG_WLEN_6 0x00000020 // 6 bit data
+#define SOFTUART_CONFIG_WLEN_5 0x00000000 // 5 bit data
+#define SOFTUART_CONFIG_STOP_MASK \
+ 0x00000008 // Mask for extracting stop bits
+#define SOFTUART_CONFIG_STOP_ONE \
+ 0x00000000 // One stop bit
+#define SOFTUART_CONFIG_STOP_TWO \
+ 0x00000008 // Two stop bits
+#define SOFTUART_CONFIG_PAR_MASK \
+ 0x00000086 // Mask for extracting parity
+#define SOFTUART_CONFIG_PAR_NONE \
+ 0x00000000 // No parity
+#define SOFTUART_CONFIG_PAR_EVEN \
+ 0x00000006 // Even parity
+#define SOFTUART_CONFIG_PAR_ODD 0x00000002 // Odd parity
+#define SOFTUART_CONFIG_PAR_ONE 0x00000082 // Parity bit is one
+#define SOFTUART_CONFIG_PAR_ZERO \
+ 0x00000086 // Parity bit is zero
+#define SOFTUART_CONFIG_WLEN_S 5
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTFIFOLevelSet() as the ui32TxLevel
+// parameter and returned by SoftUARTFIFOLevelGet() in the pui32TxLevel.
+//
+//*****************************************************************************
+#define SOFTUART_FIFO_TX1_8 0x00000000 // Transmit interrupt at 1/8 Full
+#define SOFTUART_FIFO_TX2_8 0x00000001 // Transmit interrupt at 1/4 Full
+#define SOFTUART_FIFO_TX4_8 0x00000002 // Transmit interrupt at 1/2 Full
+#define SOFTUART_FIFO_TX6_8 0x00000003 // Transmit interrupt at 3/4 Full
+#define SOFTUART_FIFO_TX7_8 0x00000004 // Transmit interrupt at 7/8 Full
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTFIFOLevelSet() as the ui32RxLevel
+// parameter and returned by SoftUARTFIFOLevelGet() in the pui32RxLevel.
+//
+//*****************************************************************************
+#define SOFTUART_FIFO_RX1_8 0x00000000 // Receive interrupt at 1/8 Full
+#define SOFTUART_FIFO_RX2_8 0x00000008 // Receive interrupt at 1/4 Full
+#define SOFTUART_FIFO_RX4_8 0x00000010 // Receive interrupt at 1/2 Full
+#define SOFTUART_FIFO_RX6_8 0x00000018 // Receive interrupt at 3/4 Full
+#define SOFTUART_FIFO_RX7_8 0x00000020 // Receive interrupt at 7/8 Full
+
+//*****************************************************************************
+//
+// Values returned from SoftUARTRxErrorGet().
+//
+//*****************************************************************************
+#define SOFTUART_RXERROR_OVERRUN \
+ 0x00000008 // An overrun error occurred
+#define SOFTUART_RXERROR_BREAK 0x00000004 // A break was received
+#define SOFTUART_RXERROR_PARITY 0x00000002 // A parity error occurred
+#define SOFTUART_RXERROR_FRAMING \
+ 0x00000001 // A framing error occurred
+
+//*****************************************************************************
+//
+// Values returned from SoftUARTRxTick().
+//
+//*****************************************************************************
+#define SOFTUART_RXTIMER_NOP 0 // The timer should continue to run
+#define SOFTUART_RXTIMER_END 1 // The timer should be stopped
+
+//*****************************************************************************
+//
+// API Function prototypes
+//
+//*****************************************************************************
+extern void SoftUARTInit(tSoftUART *psUART);
+extern void SoftUARTParityModeSet(tSoftUART *psUART, uint32_t ui32Parity);
+extern uint32_t SoftUARTParityModeGet(tSoftUART *psUART);
+extern void SoftUARTFIFOLevelSet(tSoftUART *psUART, uint32_t ui32TxLevel,
+ uint32_t ui32RxLevel);
+extern void SoftUARTFIFOLevelGet(tSoftUART *psUART, uint32_t *pui32TxLevel,
+ uint32_t *pui32RxLevel);
+extern void SoftUARTConfigSet(tSoftUART *psUART, uint32_t ui32Config);
+extern void SoftUARTConfigGet(tSoftUART *psUART, uint32_t *pui32Config);
+extern void SoftUARTEnable(tSoftUART *psUART);
+extern void SoftUARTDisable(tSoftUART *psUART);
+extern void SoftUARTFIFOEnable(tSoftUART *psUART);
+extern void SoftUARTFIFODisable(tSoftUART *psUART);
+extern bool SoftUARTCharsAvail(tSoftUART *psUART);
+extern bool SoftUARTSpaceAvail(tSoftUART *psUART);
+extern int32_t SoftUARTCharGetNonBlocking(tSoftUART *psUART);
+extern int32_t SoftUARTCharGet(tSoftUART *psUART);
+extern bool SoftUARTCharPutNonBlocking(tSoftUART *psUART,
+ uint8_t ui8Data);
+extern void SoftUARTCharPut(tSoftUART *psUART, uint8_t ui8Data);
+extern void SoftUARTBreakCtl(tSoftUART *psUART, bool bBreakState);
+extern bool SoftUARTBusy(tSoftUART *psUART);
+extern void SoftUARTIntEnable(tSoftUART *psUART, uint32_t ui32IntFlags);
+extern void SoftUARTIntDisable(tSoftUART *psUART, uint32_t ui32IntFlags);
+extern uint32_t SoftUARTIntStatus(tSoftUART *psUART, bool bMasked);
+extern void SoftUARTIntClear(tSoftUART *psUART, uint32_t ui32IntFlags);
+extern uint32_t SoftUARTRxErrorGet(tSoftUART *psUART);
+extern void SoftUARTRxErrorClear(tSoftUART *psUART);
+extern uint32_t SoftUARTRxTick(tSoftUART *psUART, bool bEdgeInt);
+extern void SoftUARTTxIntModeSet(tSoftUART *psUART, uint32_t ui32Mode);
+extern uint32_t SoftUARTTxIntModeGet(tSoftUART *psUART);
+extern void SoftUARTTxTimerTick(tSoftUART *psUART);
+extern void SoftUARTCallbackSet(tSoftUART *psUART, void (*pfnCallback)(void));
+extern void SoftUARTTxGPIOSet(tSoftUART *psUART, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftUARTRxGPIOSet(tSoftUART *psUART, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftUARTTxBufferSet(tSoftUART *psUART, uint8_t *pui8TxBuffer,
+ uint16_t ui16Len);
+extern void SoftUARTRxBufferSet(tSoftUART *psUART, uint16_t *pui16RxBuffer,
+ uint16_t ui16Len);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFTUART_H__
diff --git a/utils/speexlib.c b/utils/speexlib.c
new file mode 100644
index 0000000..3a58ebc
--- /dev/null
+++ b/utils/speexlib.c
@@ -0,0 +1,377 @@
+//*****************************************************************************
+//
+// speexlib.c - interface to the speex coder/encoder library.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "third_party/speex-1.2rc1/include/speex/speex.h"
+#include "third_party/speex-1.2rc1/include/speex/speex_header.h"
+#include "utils/speexlib.h"
+#include "driverlib/debug.h"
+
+//*****************************************************************************
+//
+// The private structure that is used by the speex encoder or decoder for
+// holding all state information for an encoder or decoder.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Holds the state of the decoder.
+ //
+ void *pvState;
+
+ //
+ // Holds bits so they can be read and written to by the Speex routines
+ //
+ SpeexBits sBits;
+
+ //
+ // Holds the header information for the current file.
+ //
+ SpeexHeader sHeader;
+
+ //
+ // The current Segment table for the stream.
+ //
+ uint8_t pui8SegTable[256];
+
+ //
+ // The size of the current Segment table.
+ //
+ uint8_t ui8SegTableSize;
+
+ //
+ // The current active page in a segment.
+ //
+ uint8_t ui8PageCurrent;
+
+ //
+ // Current state flags.
+ //
+ uint32_t ui32Flags;
+}
+tSpeexInstance;
+
+//*****************************************************************************
+//
+// The decoder and encoder instance data.
+//
+//*****************************************************************************
+tSpeexInstance g_sSpeexDecoder, g_sSpeexEncoder;
+
+//*****************************************************************************
+//
+//! Initialize the decoder's state to prepare for decoding new frames.
+//!
+//! This function will initializes the decoder so that it is prepared to start
+//! receiving frames to decode.
+//!
+//! \return This function returns 0.
+//
+//*****************************************************************************
+int32_t
+SpeexDecodeInit(void)
+{
+ int iTemp;
+
+ //
+ // Clear out the flags for this instance.
+ //
+ g_sSpeexDecoder.ui32Flags = 0;
+
+ //
+ // Create a new decoder state in narrow band mode.
+ //
+ g_sSpeexDecoder.pvState = speex_decoder_init(&speex_nb_mode);
+
+ //
+ // Disable enhanced decoding to reduce processing requirements.
+ //
+ iTemp = 0;
+ speex_decoder_ctl(g_sSpeexDecoder.pvState, SPEEX_SET_ENH, &iTemp);
+
+ //
+ // Initialization of the structure that holds the bits.
+ //
+ speex_bits_init(&g_sSpeexDecoder.sBits);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function returns the current frame size from the decoder.
+//!
+//! This function queries the decoder for the current decode frame size in byte
+//! and returns it to the caller.
+//!
+//! \return The current decoder frame size.
+//
+//*****************************************************************************
+int32_t
+SpeexDecodeFrameSizeGet(void)
+{
+ int iFrameSize;
+
+ //
+ // Return 0 if the wrong request is made.
+ //
+ iFrameSize = 0;
+
+ //
+ // Query the decoder for the current frame size.
+ //
+ speex_decoder_ctl(g_sSpeexDecoder.pvState, SPEEX_GET_FRAME_SIZE,
+ &iFrameSize);
+
+ return(iFrameSize);
+}
+
+//*****************************************************************************
+//
+//! This function decodes a single frame of Speex encoded audio.
+//!
+//! \param pui8InBuffer is the buffer that contains the Speex encoded audio.
+//! \param ui32InSize is the number of valid bytes in the \e pui8InBuffer
+//! buffer.
+//! \param pui8OutBuffer is a pointer to the buffer to store decoded audio.
+//! \param ui32OutSize is the size of the buffer pointed to by the
+//! \e pui8OutBuffer pointer.
+//!
+//! This function will take a buffer of Speex encoded audio and decode it into
+//! raw PCM audio. The \e pui16InBuffer parameter should contain a single
+//! frame encoded Speex audio. The \e pui8OutBuffer will contain the decoded
+//! audio after returning from this function.
+//!
+//! \return This function returns the number of decoded bytes in the
+//! \e pui8OutBuffer buffer.
+//
+//*****************************************************************************
+int32_t
+SpeexDecode(uint8_t *pui8InBuffer, uint32_t ui32InSize, uint8_t *pui8OutBuffer,
+ uint32_t ui32OutSize)
+{
+ int32_t i32Bytes;
+
+ //
+ // Read in the bit stream to the Speex library.
+ //
+ speex_bits_read_from(&g_sSpeexDecoder.sBits, (char *)pui8InBuffer,
+ ui32InSize);
+
+ //
+ // Decode one frame of data.
+ //
+ i32Bytes = speex_decode_int(g_sSpeexDecoder.pvState,
+ &g_sSpeexDecoder.sBits,
+ (int16_t *)pui8OutBuffer);
+
+ return(i32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function sets the current quality setting for the Speex encoder.
+//!
+//! \param iQuality is the new Quality setting to use for the Speex encoder.
+//!
+//! This function will use the \e iQuality setting as the new quality setting
+//! for the Speex encoder.
+//!
+//! \return This function returns 0.
+//
+//*****************************************************************************
+int32_t
+SpeexEncodeQualitySet(int iQuality)
+{
+ //
+ // Set the current encoder quality setting.
+ //
+ speex_encoder_ctl(g_sSpeexEncoder.pvState, SPEEX_SET_QUALITY, &iQuality);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function returns the current frame size from the encoder.
+//!
+//! This function queries the encoder for the current encode frame size in byte
+//! and returns it to the caller.
+//!
+//! \return The current encoder frame size.
+//
+//*****************************************************************************
+int32_t
+SpeexEncodeFrameSizeGet(void)
+{
+ int iFrameSize;
+
+ //
+ // Return 0 if the wrong request is made.
+ //
+ iFrameSize = 0;
+
+ //
+ // Query the encoder for the current frame size.
+ //
+ speex_encoder_ctl(g_sSpeexEncoder.pvState, SPEEX_GET_FRAME_SIZE,
+ &iFrameSize);
+
+ return(iFrameSize);
+}
+
+//*****************************************************************************
+//
+//! Initialize the encoder's state to prepare for encoding new frames.
+//!
+//! \param iSampleRate is the sample rate of the incoming audio.
+//! \param iComplexity is the complexity setting for the encoder.
+//! \param iQuality is the quality setting for the encoder.
+//!
+//! This function will initializes the encoder by setting the sample rate,
+//! complexity and quality settings. The \e iComplexity and \e iQuality
+//! settings are explained further in the Speex documentation.
+//!
+//! \return This function returns 0.
+//
+//*****************************************************************************
+int32_t
+SpeexEncodeInit(int iSampleRate, int iComplexity, int iQuality)
+{
+ const SpeexMode *psMode;
+
+ //
+ // Clear out the flags for this instance.
+ //
+ g_sSpeexEncoder.ui32Flags = 0;
+
+ //
+ // Read out the current encoder mode.
+ //
+ psMode = speex_lib_get_mode(SPEEX_MODEID_NB);
+
+ //
+ // Create a new decoder state in narrow band mode.
+ //
+ g_sSpeexEncoder.pvState = speex_encoder_init(psMode);
+
+ //
+ // Initialize the bit stream.
+ //
+ speex_bits_init(&g_sSpeexEncoder.sBits);
+
+ //
+ // Set the quality.
+ //
+ SpeexEncodeQualitySet(iQuality);
+
+ //
+ // Set the complexity and sample rate for the encoder.
+ //
+ speex_encoder_ctl(g_sSpeexEncoder.pvState, SPEEX_SET_COMPLEXITY,
+ &iComplexity);
+ speex_encoder_ctl(g_sSpeexEncoder.pvState, SPEEX_SET_SAMPLING_RATE,
+ &iSampleRate);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Encode a single frame of speex encoded audio.
+//!
+//! \param pui16InBuffer is the buffer that contains the raw PCM audio.
+//! \param ui32InSize is the number of valid bytes in the \e pui16InBuffer
+//! buffer.
+//! \param pui8OutBuffer is a pointer to the buffer to store the encoded audio.
+//! \param ui32OutSize is the size of the buffer pointed to by the
+//! \e pui8OutBuffer pointer.
+//!
+//! This function will take a buffer of PCM audio and encode it into a frame
+//! of speex compressed audio. The \e pui16InBuffer parameter should contain
+//! a single frame of PCM audio. The \e pui8OutBuffer will contain the encoded
+//! audio after returning from this function.
+//!
+//! \return This function returns the number of encoded bytes in the
+//! \e pui8OutBuffer parameter.
+//
+//*****************************************************************************
+int32_t
+SpeexEncode(int16_t *pui16InBuffer, uint32_t ui32InSize,
+ uint8_t *pui8OutBuffer, uint32_t ui32OutSize)
+{
+ int32_t i32Bytes;
+
+ //
+ // Reset the bit stream before encoding a new frame.
+ //
+ speex_bits_reset(&g_sSpeexEncoder.sBits);
+
+ //
+ // Encode a single frame.
+ //
+ speex_encode_int(g_sSpeexEncoder.pvState, pui16InBuffer,
+ &g_sSpeexEncoder.sBits);
+
+ //
+ // Read the PCM data from the encoded bit stream.
+ //
+ i32Bytes = speex_bits_write(&g_sSpeexEncoder.sBits, (char *)pui8OutBuffer,
+ ui32OutSize);
+
+ //
+ // Return the number of bytes in the PCM data.
+ //
+ return(i32Bytes);
+}
+
+//*****************************************************************************
+//
+// This is called by speex in the event of a fatal error.
+//
+//*****************************************************************************
+void
+_speex_fatal(const int8_t *str, const int8_t *file, int line)
+{
+ ASSERT(0);
+ while(1)
+ {
+ }
+}
+
+//*****************************************************************************
+//
+// Speex wrapper for putc so that it does not use any file writing library
+// functions. The speex library uses some file access for debug printing, this
+// will disable this feature.
+//
+//*****************************************************************************
+void
+_speex_putc(int ch, void *file)
+{
+}
diff --git a/utils/speexlib.h b/utils/speexlib.h
new file mode 100644
index 0000000..5b3f712
--- /dev/null
+++ b/utils/speexlib.h
@@ -0,0 +1,63 @@
+//*****************************************************************************
+//
+// speexlib.h - interface to the speex coder/encoder library.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SPEEXLIB_H__
+#define __SPEEXLIB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototypes.
+//
+//*****************************************************************************
+extern int32_t SpeexEncodeInit(int iSampleRate, int iComplexity, int iQuality);
+extern int32_t SpeexEncode(int16_t *pui16InBuffer, uint32_t ui32InSize,
+ uint8_t *pui8OutBuffer, uint32_t ui32OutSize);
+extern int32_t SpeexEncodeQualitySet(int iQuality);
+extern int32_t SpeexEncodeFrameSizeGet(void);
+extern int32_t SpeexDecodeFrameSizeGet(void);
+extern int32_t SpeexDecodeInit(void);
+extern int32_t SpeexDecode(uint8_t *pui8InBuffer, uint32_t ui32InSize,
+ uint8_t *pui8OutBuffer, uint32_t ui32OutSize);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SPEEXLIB_H__
diff --git a/utils/spi_flash.c b/utils/spi_flash.c
new file mode 100644
index 0000000..6e5b24a
--- /dev/null
+++ b/utils/spi_flash.c
@@ -0,0 +1,2484 @@
+//*****************************************************************************
+//
+// spi_flash.c - Driver for a SPI flash that supports the "Intel" SPI flash
+// command set, capable of utilizing Bi-SPI and Quad-SPI.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_ssi.h"
+#include "inc/hw_types.h"
+#include "inc/hw_udma.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/ssi.h"
+#include "driverlib/udma.h"
+#include "utils/spi_flash.h"
+
+//*****************************************************************************
+//
+//! \addtogroup spi_flash_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The commands that can be sent to the SPI flash. This is the "generic"
+// command set that is supported by a wide number of SPI flashes.
+//
+//*****************************************************************************
+#define CMD_WRSR 0x01 // Write status register
+#define CMD_PP 0x02 // Page program
+#define CMD_READ 0x03 // Read data
+#define CMD_WRDI 0x04 // Disable writes
+#define CMD_RDSR 0x05 // Read status register
+#define CMD_WREN 0x06 // Enable writes
+#define CMD_FREAD 0x0b // Fast read data
+#define CMD_SE 0x20 // Sector erase (4K)
+#define CMD_DREAD 0x3b // 1 in 2 out read data
+#define CMD_BE32 0x52 // Block erase (32K)
+#define CMD_QREAD 0x6b // 1 in 4 out read data
+#define CMD_RDID 0x9f // Read JEDEC ID
+#define CMD_CE 0xc7 // Chip erase
+#define CMD_BE64 0xd8 // Block erase (64K)
+
+//*****************************************************************************
+//
+// The states for the SPI flash interrupt handler state machine.
+//
+//*****************************************************************************
+#define STATE_IDLE 0
+#define STATE_CMD 1
+#define STATE_ADDR1 2
+#define STATE_ADDR2 3
+#define STATE_ADDR3 4
+#define STATE_READ_DUMMY 5
+#define STATE_READ_DATA_SETUP 6
+#define STATE_READ_DATA 7
+#define STATE_READ_DATA_DMA 8
+#define STATE_READ_DATA_END 9
+#define STATE_WRITE_DATA_SETUP 10
+#define STATE_WRITE_DATA 11
+#define STATE_WRITE_DATA_DMA 12
+#define STATE_WRITE_DATA_END 13
+
+//*****************************************************************************
+//
+//! Handles SSI module interrupts for the SPI flash driver.
+//!
+//! \param pState is a pointer to the SPI flash driver instance data.
+//!
+//! This function handles SSI module interrupts that are generated as a result
+//! of SPI flash driver operations. This must be called by the application in
+//! response to the SSI module interrupt when using the SPIFlashxxxNonBlocking
+//! APIs.
+//!
+//! \return Returns \b SPI_FLASH_IDLE if there is no transfer in progress,
+//! \b SPI_FLASH_WORKING is the requested transfer is still in progress, or
+//! \b SPI_FLASH_DONE if the requested transfer has completed.
+//
+//*****************************************************************************
+uint32_t
+SPIFlashIntHandler(tSPIFlashState *pState)
+{
+ uint32_t ui32Data, ui32Count;
+
+ //
+ // Set the write count to four. This is the maximum number of bytes that
+ // will be written into the SSI transmit FIFO in the interrupt handler.
+ // Writing more might be possible but makes the latency of handling future
+ // SSI interrupt critical to preventing receive FIFO overruns.
+ //
+ ui32Count = 4;
+
+ //
+ // Get the set of asserted and unmasked SSI module interrupts. Only some
+ // of these are directly handled; the others are implicitly handled via the
+ // operation of the state machine.
+ //
+ ui32Data = HWREG(pState->ui32Base + SSI_O_MIS);
+
+ //
+ // See if the uDMA transmit complete interrupt has asserted.
+ //
+ if(ui32Data & SSI_MIS_DMATXMIS)
+ {
+ //
+ // Determine the size of the uDMA transfer based on the number of bytes
+ // left to write.
+ //
+ if(pState->ui32WriteCount > 1024)
+ {
+ //
+ // There are more than 1024 bytes left to transfer, so the uDMA
+ // transfer that just completed was for a full 1024 bytes.
+ //
+ pState->ui32WriteCount -= 1024;
+
+ //
+ // If a page program is being performed, then the data buffer
+ // pointer needs to be incremented as well.
+ //
+ if(pState->ui16Cmd == CMD_PP)
+ {
+ //
+ // Increment the data buffer pointer.
+ //
+ pState->pui8Buffer += 1024;
+
+ //
+ // See if there is more than one byte left to transfer.
+ //
+ if(pState->ui32WriteCount > 1)
+ {
+ //
+ // Configure the uDMA to transmit the next portion of the
+ // data buffer.
+ //
+ uDMAChannelTransferSet(pState->ui32TxChannel,
+ UDMA_MODE_BASIC,
+ pState->pui8Buffer,
+ (void *)(pState->ui32Base +
+ SSI_O_DR),
+ (pState->ui32WriteCount > 1024) ?
+ 1024 : pState->ui32WriteCount - 1);
+
+ //
+ // Enable the uDMA transmit channel.
+ //
+ uDMAChannelEnable(pState->ui32TxChannel);
+ }
+ }
+ }
+ else
+ {
+ //
+ // There are 1024 or less bytes left to transfer, so the uDMA
+ // transfer that just copmleted was for one less than the remaining
+ // transfer count. If a page program is being performed, then the
+ // data buffer pointer needs to be incremented.
+ //
+ if(pState->ui16Cmd == CMD_PP)
+ {
+ pState->pui8Buffer += (pState->ui32WriteCount - 1);
+ }
+
+ //
+ // Set the remaining transfer count to 1. The final byte will be
+ // transferred with PIO since the end of frame flag needs to be set
+ // first.
+ //
+ pState->ui32WriteCount = 1;
+ }
+
+ //
+ // Clear the uDMA transmit complete interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC;
+ }
+
+ //
+ // See if the uDMA receive complete interrupt has asserted.
+ //
+ if(ui32Data & SSI_MIS_DMARXMIS)
+ {
+ //
+ // Determine the size of the uDMA transfer based on the number of bytes
+ // left to read.
+ //
+ if(pState->ui32ReadCount >= 1024)
+ {
+ //
+ // There are 1024 or more bytes left to transfer, so the uDMA
+ // transfer that just completed was for a full 1024 bytes.
+ //
+ pState->ui32ReadCount -= 1024;
+ if(pState->ui32WriteCount != 0)
+ {
+ pState->ui32WriteCount -= 1024;
+ }
+
+ //
+ // The data buffer pointer needs to be incremented as well.
+ //
+ pState->pui8Buffer += 1024;
+
+ //
+ // See if there is additional data to transfer.
+ //
+ if(pState->ui32ReadCount != 0)
+ {
+ //
+ // Configure the transmit uDMA if there is more than one byte
+ // left to write.
+ //
+ if(pState->ui32WriteCount > 1)
+ {
+ //
+ // Configure the uDMA to transmit the next portion of the
+ // data buffer.
+ //
+ uDMAChannelTransferSet(pState->ui32TxChannel,
+ UDMA_MODE_BASIC, pState->pui8Buffer,
+ (void *)(pState->ui32Base +
+ SSI_O_DR),
+ (pState->ui32WriteCount > 1024) ?
+ 1024 : pState->ui32WriteCount - 1);
+
+ //
+ // Enable the uDMA transmit channel.
+ //
+ uDMAChannelEnable(pState->ui32TxChannel);
+ }
+
+ //
+ // Configure the uDMA to receive the next portion of the data
+ // buffer.
+ //
+ uDMAChannelTransferSet(pState->ui32RxChannel, UDMA_MODE_BASIC,
+ (void *)(pState->ui32Base + SSI_O_DR),
+ pState->pui8Buffer,
+ (pState->ui32ReadCount >= 1024) ?
+ 1024 : pState->ui32ReadCount);
+
+ //
+ // Enable the uDMA receive channel.
+ //
+ uDMAChannelEnable(pState->ui32RxChannel);
+
+ //
+ // If this is the final receive uDMA buffer and there is a
+ // transmit uDMA buffer associated, enable the DMA transmit
+ // interrupt.
+ //
+ if((pState->ui32ReadCount <= 1024) &&
+ (pState->ui32WriteCount > 1))
+ {
+ HWREG(pState->ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC;
+ HWREG(pState->ui32Base + SSI_O_IM) = SSI_IM_DMATXIM;
+ }
+ }
+ }
+ else
+ {
+ //
+ // There are less than 1024 bytes left to transfer, so the uDMA
+ // transfer that copmleted was for the remaining transfer count.
+ //
+ pState->ui32ReadCount = 0;
+ }
+
+ //
+ // Clear the uDMA receive complete interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_ICR) = SSI_ICR_DMARXIC;
+ }
+
+ //
+ // Drain the receive FIFO is not using uDMA.
+ //
+ if(!pState->bUseDMA)
+ {
+ //
+ // Loop while there is more data in the receive FIFO and more data to
+ // be read.
+ //
+ while((pState->ui32ReadCount != 0) &&
+ (MAP_SSIDataGetNonBlocking(pState->ui32Base, &ui32Data) != 0))
+ {
+ //
+ // Save this byte into the data buffer.
+ //
+ *(pState->pui8Buffer)++ = ui32Data & 0xff;
+
+ //
+ // Decrement the read count.
+ //
+ pState->ui32ReadCount--;
+ }
+ }
+
+ //
+ // The SPI flash state machine. Loop forever; the state machine will
+ // explicitly return to the caller when there is no further work that can
+ // be done without stalling.
+ //
+ while(1)
+ {
+ //
+ // Determine the current state.
+ //
+ switch(pState->ui16State)
+ {
+ //
+ // The state machine is idle.
+ //
+ case STATE_IDLE:
+ {
+ //
+ // Return indicating that the state machine is idle. This
+ // should never happen since no further interrupts should occur
+ // once the transfer has completed and the state machine goes
+ // into the idle state.
+ //
+ return(SPI_FLASH_IDLE);
+ }
+
+ //
+ // The state machine is in the command state.
+ //
+ case STATE_CMD:
+ {
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(pState->ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Attempt to write the command byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base,
+ pState->ui16Cmd) == 0)
+ {
+ //
+ // The command byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+ else
+ {
+ //
+ // The command byte has been written, so move to the first
+ // address byte state.
+ //
+ pState->ui16State = STATE_ADDR1;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the first address byte state.
+ //
+ case STATE_ADDR1:
+ {
+ //
+ // Attempt to write the first address byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base,
+ (pState->ui32Addr >> 16) &
+ 0xff) == 0)
+ {
+ //
+ // The first address byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+ else
+ {
+ //
+ // The first address byte has been written, so move to the
+ // second address byte state.
+ //
+ pState->ui16State = STATE_ADDR2;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the second address byte state.
+ //
+ case STATE_ADDR2:
+ {
+ //
+ // Attempt to write the second address byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base,
+ (pState->ui32Addr >> 8) & 0xff) ==
+ 0)
+ {
+ //
+ // The second address byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+ else
+ {
+ //
+ // The second address byte has been written, so move to the
+ // third address byte state.
+ //
+ pState->ui16State = STATE_ADDR3;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the third address byte state.
+ //
+ case STATE_ADDR3:
+ {
+ //
+ // Attempt to write the third address byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base,
+ pState->ui32Addr & 0xff) == 0)
+ {
+ //
+ // The third address byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+ else
+ {
+ //
+ // The third address byte has been written, so determine
+ // the next state based on the command byte.
+ //
+ if(pState->ui16Cmd == CMD_PP)
+ {
+ //
+ // A page program is being performed, so move to the
+ // write data setup state.
+ //
+ pState->ui16State = STATE_WRITE_DATA_SETUP;
+ }
+ else if(pState->ui16Cmd == CMD_READ)
+ {
+ //
+ // A read is being performed, so move to the read data
+ // setup state.
+ //
+ pState->ui16State = STATE_READ_DATA_SETUP;
+ }
+ else
+ {
+ //
+ // The other forms of read (fast read, dual read, and
+ // quad read) all require a dummy byte. Move to the
+ // dummy byte state.
+ //
+ pState->ui16State = STATE_READ_DUMMY;
+ }
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the dummy byte state.
+ //
+ case STATE_READ_DUMMY:
+ {
+ //
+ // Attempt to write the dummy byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base, 0) == 0)
+ {
+ //
+ // THe dummy byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+ else
+ {
+ //
+ // The dummy byte has been written, so move to the read
+ // data setup state.
+ //
+ pState->ui16State = STATE_READ_DATA_SETUP;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the read data setup state.
+ //
+ case STATE_READ_DATA_SETUP:
+ {
+ //
+ // Set the SSI module into the appropriate mode based on the
+ // command byte.
+ //
+ if(pState->ui16Cmd == CMD_DREAD)
+ {
+ //
+ // Bi-SPI read mode is used for the dual read command.
+ //
+ MAP_SSIAdvModeSet(pState->ui32Base, SSI_ADV_MODE_BI_READ);
+ }
+ else if(pState->ui16Cmd == CMD_QREAD)
+ {
+ //
+ // Quad-SPI read mode is used for the quad read command.
+ //
+ MAP_SSIAdvModeSet(pState->ui32Base,
+ SSI_ADV_MODE_QUAD_READ);
+ }
+ else
+ {
+ //
+ // Advanced read/write mode is used for the read and fast
+ // read commands.
+ //
+ MAP_SSIAdvModeSet(pState->ui32Base,
+ SSI_ADV_MODE_READ_WRITE);
+ }
+
+ //
+ // See if a single byte is being transferred.
+ //
+ if(pState->ui32ReadCount == 1)
+ {
+ //
+ // Disable the use of uDMA.
+ //
+ pState->bUseDMA = false;
+
+ //
+ // Move to the read data end state to transfer the single
+ // byte. This uses PIO even if uDMA has been requested.
+ //
+ pState->ui16State = STATE_READ_DATA_END;
+ }
+
+ //
+ // See if uDMA has been requested for this transfer.
+ //
+ else if(!pState->bUseDMA || (pState->ui32ReadCount < 4))
+ {
+ //
+ // Disable the use of uDMA.
+ //
+ pState->bUseDMA = false;
+
+ //
+ // Move to the read data state.
+ //
+ pState->ui16State = STATE_READ_DATA;
+ }
+
+ //
+ // This transfer should use uDMA.
+ //
+ else
+ {
+ //
+ // If the transfer is larger than 1024 bytes, enable the
+ // uDMA receive complete interrupt which will be used to
+ // move to the next block of the transfer. Otherwise,
+ // enable the uDMA transmit complete interrupt which will
+ // be used to complete the transaction.
+ //
+ if(pState->ui32ReadCount > 1024)
+ {
+ HWREG(pState->ui32Base + SSI_O_IM) = SSI_IM_DMARXIM;
+ }
+ else
+ {
+ HWREG(pState->ui32Base + SSI_O_IM) = SSI_IM_DMATXIM;
+ }
+
+ //
+ // Disable the uDMA channels.
+ //
+ HWREG(UDMA_ENACLR) = ((1 << pState->ui32TxChannel) |
+ (1 << pState->ui32RxChannel));
+
+ //
+ // Configure the attributes for the transmit uDMA channel.
+ //
+ HWREG(UDMA_USEBURSTSET) = ((1 << pState->ui32TxChannel) |
+ (1 << pState->ui32RxChannel));
+ HWREG(UDMA_ALTCLR) = ((1 << pState->ui32TxChannel) |
+ (1 << pState->ui32RxChannel));
+ HWREG(UDMA_PRIOCLR) = 1 << pState->ui32TxChannel;
+ HWREG(UDMA_PRIOSET) = 1 << pState->ui32RxChannel;
+ HWREG(UDMA_REQMASKCLR) = ((1 << pState->ui32TxChannel) |
+ (1 << pState->ui32RxChannel));
+
+ //
+ // Configure the control parameters of the uDMA channels.
+ //
+ uDMAChannelControlSet(pState->ui32TxChannel,
+ UDMA_SRC_INC_NONE |
+ UDMA_DST_INC_NONE |
+ UDMA_SIZE_8 | UDMA_ARB_2);
+ uDMAChannelControlSet(pState->ui32RxChannel,
+ UDMA_SRC_INC_NONE |
+ UDMA_DST_INC_8 |
+ UDMA_SIZE_8 | UDMA_ARB_4);
+
+ //
+ // Configure the uDMA receive channel to transfer the first
+ // portion of the data buffer.
+ //
+ uDMAChannelTransferSet(pState->ui32RxChannel,
+ UDMA_MODE_BASIC,
+ (void *)(pState->ui32Base +
+ SSI_O_DR),
+ pState->pui8Buffer,
+ (pState->ui32ReadCount >= 1024) ?
+ 1024 : pState->ui32ReadCount);
+
+ //
+ // Enable the uDMA receive channel.
+ //
+ uDMAChannelEnable(pState->ui32RxChannel);
+
+ //
+ // Configure the uDMA channel to transfer the dummy bytes
+ // for the first portion of the data buffer. The last
+ // dummy byte will not be included since it must be treated
+ // special.
+ //
+ uDMAChannelTransferSet(pState->ui32TxChannel,
+ UDMA_MODE_BASIC,
+ pState->pui8Buffer,
+ (void *)(pState->ui32Base +
+ SSI_O_DR),
+ (pState->ui32WriteCount > 1024) ?
+ 1024 : pState->ui32WriteCount - 1);
+
+ //
+ // Enable the uDMA transmit channel.
+ //
+ uDMAChannelEnable(pState->ui32TxChannel);
+
+ //
+ // Clear any previously pending uDMA completion interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_ICR) = SSI_ICR_DMARXIC;
+
+ //
+ // Enable uDMA transmit and receive in the SSI module.
+ //
+ MAP_SSIDMAEnable(pState->ui32Base,
+ SSI_DMA_TX | SSI_DMA_RX);
+
+ //
+ // Move to the uDMA data read state.
+ //
+ pState->ui16State = STATE_READ_DATA_DMA;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the read data state.
+ //
+ case STATE_READ_DATA:
+ {
+ //
+ // Loop while there is more than one byte left to write.
+ //
+ while(pState->ui32WriteCount != 1)
+ {
+ //
+ // Dummy bytes are written into the FIFO in order to
+ // trigger the read operation. Attempt to write another
+ // dummy byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base, 0) == 0)
+ {
+ //
+ // The dummy byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // Decrement the count of dummy bytes to write.
+ //
+ pState->ui32WriteCount--;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Move to the read data end state.
+ //
+ pState->ui16State = STATE_READ_DATA_END;
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the uDMA read data state.
+ //
+ case STATE_READ_DATA_DMA:
+ {
+ //
+ // See if the write count is greater than one.
+ //
+ if(pState->ui32WriteCount > 1)
+ {
+ //
+ // Return indicating that the transfer is still in
+ // progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // Disable uDMA transmit in the SSI module.
+ //
+ MAP_SSIDMADisable(pState->ui32Base, SSI_DMA_TX);
+
+ //
+ // Enable the uDMA receive done and FIFO transmit interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) =
+ SSI_IM_DMARXIM | SSI_IM_TXIM;
+
+ //
+ // Move to the read data end state.
+ //
+ pState->ui16State = STATE_READ_DATA_END;
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the data read end state.
+ //
+ case STATE_READ_DATA_END:
+ {
+ //
+ // See if the final dummy byte still needs to be written.
+ //
+ if(pState->ui32WriteCount != 0)
+ {
+ //
+ // Attempt to write the final dummy byte into the FIFO and
+ // mark it as the end of the frame.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIAdvDataPutFrameEndNonBlocking(pState->ui32Base,
+ 0) == 0)
+ {
+ //
+ // The dummy byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // The write portion of the transfer has completed.
+ //
+ pState->ui32WriteCount = 0;
+
+ //
+ // Disable the transmit interrupt now that the write
+ // write portion of the transfer has completed.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) &= ~(SSI_IM_TXIM);
+ }
+
+ //
+ // Return indicating that the transfer is still in progress if
+ // there are still data bytes to be read.
+ //
+ if(pState->ui32ReadCount != 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // Disable uDMA receive in the SSI module.
+ //
+ MAP_SSIDMADisable(pState->ui32Base, SSI_DMA_RX);
+
+ //
+ // The transfer is complete, so disable all interrupts.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) = 0;
+
+ //
+ // Move to the idle state.
+ //
+ pState->ui16State = STATE_IDLE;
+
+ //
+ // Return indicating that the transfer has completed.
+ //
+ return(SPI_FLASH_DONE);
+ }
+
+ //
+ // The state machine is in the write data setup state.
+ //
+ case STATE_WRITE_DATA_SETUP:
+ {
+ //
+ // See if a single data byte is being transferred.
+ //
+ if(pState->ui32WriteCount == 1)
+ {
+ //
+ // Disable the use of uDMA.
+ //
+ pState->bUseDMA = false;
+
+ //
+ // Move to the write data end state to transfer the single
+ // byte. This uses PIO even if uDMA has been requested.
+ //
+ pState->ui16State = STATE_WRITE_DATA_END;
+ }
+
+ //
+ // See if uDMA has been requested for this transfer.
+ //
+ else if(!pState->bUseDMA || (pState->ui32WriteCount < 4))
+ {
+ //
+ // Disable the use of uDMA.
+ //
+ pState->bUseDMA = false;
+
+ //
+ // uDMA is not being used, so move to the write data state.
+ //
+ pState->ui16State = STATE_WRITE_DATA;
+ }
+
+ //
+ // This transfer should use uDMA.
+ //
+ else
+ {
+ //
+ // Enable the uDMA transmit complete interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) = SSI_IM_DMATXIM;
+
+ //
+ // Disable the transmit uDMA channel.
+ //
+ HWREG(UDMA_ENACLR) = 1 << pState->ui32TxChannel;
+
+ //
+ // Configure the attributes for the transmit uDMA channel.
+ //
+ HWREG(UDMA_USEBURSTSET) = 1 << pState->ui32TxChannel;
+ HWREG(UDMA_ALTCLR) = 1 << pState->ui32TxChannel;
+ HWREG(UDMA_PRIOCLR) = 1 << pState->ui32TxChannel;
+ HWREG(UDMA_REQMASKCLR) = 1 << pState->ui32TxChannel;
+
+ //
+ // Configure the control parameters of the uDMA channel.
+ //
+ uDMAChannelControlSet(pState->ui32TxChannel,
+ UDMA_SRC_INC_8 |
+ UDMA_DST_INC_NONE |
+ UDMA_SIZE_8 | UDMA_ARB_4);
+
+ //
+ // Configure the uDMA channel to transfer the next portion
+ // of the data buffer. The last byte in the buffer will
+ // not be included since it must be treated special.
+ //
+ uDMAChannelTransferSet(pState->ui32TxChannel,
+ UDMA_MODE_BASIC,
+ pState->pui8Buffer,
+ (void *)(pState->ui32Base +
+ SSI_O_DR),
+ (pState->ui32WriteCount > 1024) ?
+ 1024 : pState->ui32WriteCount - 1);
+
+ //
+ // Enable the uDMA transmit channel.
+ //
+ uDMAChannelEnable(pState->ui32TxChannel);
+ HWREG(pState->ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC;
+
+ //
+ // Enable uDMA in the SSI module.
+ //
+ MAP_SSIDMAEnable(pState->ui32Base, SSI_DMA_TX);
+
+ //
+ // Move to the uDMA data write state.
+ //
+ pState->ui16State = STATE_WRITE_DATA_DMA;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the write data state.
+ //
+ case STATE_WRITE_DATA:
+ {
+ //
+ // Loop while there is more than one byte left to write.
+ //
+ while(pState->ui32WriteCount != 1)
+ {
+ //
+ // Attempt to write the next data byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base,
+ *(pState->pui8Buffer)) == 0)
+ {
+ //
+ // The next data byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // Increment the buffer pointer and decrement the byte
+ // count.
+ //
+ pState->pui8Buffer++;
+ pState->ui32WriteCount--;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Move to the write data end state.
+ //
+ pState->ui16State = STATE_WRITE_DATA_END;
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the uDMA write data state.
+ //
+ case STATE_WRITE_DATA_DMA:
+ {
+ //
+ // See if the write count is greater than one.
+ //
+ if(pState->ui32WriteCount > 1)
+ {
+ //
+ // Return indicating that the transfer is still in
+ // progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // Disable uDMA in the SSI module.
+ //
+ MAP_SSIDMADisable(pState->ui32Base, SSI_DMA_TX);
+
+ //
+ // Disable the uDMA transmit complete interrupt and enable the
+ // FIFO interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) = SSI_IM_TXIM;
+
+ //
+ // Move to the write data end state.
+ //
+ pState->ui16State = STATE_WRITE_DATA_END;
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the write data end state.
+ //
+ case STATE_WRITE_DATA_END:
+ {
+ //
+ // Attempt to write the final data byte into the FIFO.
+ //
+ if(MAP_SSIAdvDataPutFrameEndNonBlocking(pState->ui32Base,
+ *(pState->pui8Buffer)) ==
+ 0)
+ {
+ //
+ // The final data byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // The transfer is complete, so disable all interrupts.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) = 0;
+
+ //
+ // Move to the idle state.
+ //
+ pState->ui16State = STATE_IDLE;
+
+ //
+ // Return indicating that the transfer has completed.
+ //
+ return(SPI_FLASH_DONE);
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the SPI flash driver.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Clock is the rate of the clock supplied to the SSI module.
+//! \param ui32BitRate is the SPI clock rate.
+//!
+//! This function configures the SSI module for use by the SPI flash driver.
+//! The SSI module will be placed into the correct mode of operation to allow
+//! communication with the SPI flash. This function must be called prior to
+//! calling the remaining SPI flash driver APIs. It can be called at a later
+//! point to reconfigure the SSI module, such as to increase the SPI clock rate
+//! once it has been determined that it is safe to use a higher speed clock.
+//!
+//! It is the responsibility of the caller to enable the SSI module and
+//! configure the pins that it will utilize.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashInit(uint32_t ui32Base, uint32_t ui32Clock, uint32_t ui32BitRate)
+{
+ //
+ // Configure the SPI module.
+ //
+ MAP_SSIConfigSetExpClk(ui32Base, ui32Clock, SSI_FRF_MOTO_MODE_0,
+ SSI_MODE_MASTER, ui32BitRate, 8);
+
+ //
+ // Enable the advanced mode of operation, defaulting to read/write mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);
+
+ //
+ // Enable the frame hold feature.
+ //
+ MAP_SSIAdvFrameHoldEnable(ui32Base);
+
+ //
+ // Enable the SPI module.
+ //
+ MAP_SSIEnable(ui32Base);
+}
+
+//*****************************************************************************
+//
+//! Writes the SPI flash status register.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui8Status is the value to write to the status register.
+//!
+//! This function writes the SPI flash status register. This uses the 0x01 SPI
+//! flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashWriteStatus(uint32_t ui32Base, uint8_t ui8Status)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the write status register command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_WRSR);
+
+ //
+ // Send the new status register value, marking this byte as the end of the
+ // frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, ui8Status);
+}
+
+//*****************************************************************************
+//
+//! Programs the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to be programmed.
+//! \param pui8Data is a pointer to the data to be programmed.
+//! \param ui32Count is the number of bytes to be programmed.
+//!
+//! This function programs data into the SPI flash, using PIO mode. This
+//! function will not return until the entire program command has been written
+//! into the SSI transmit FIFO. This uses the 0x02 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashPageProgram(uint32_t ui32Base, uint32_t ui32Addr,
+ const uint8_t *pui8Data, uint32_t ui32Count)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the page program command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_PP);
+
+ //
+ // Send the address of the first byte to program.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIDataPut(ui32Base, ui32Addr & 0xff);
+
+ //
+ // Loop while there is more than one data byte left to be sent.
+ //
+ while(ui32Count-- != 1)
+ {
+ //
+ // Send the next data byte.
+ //
+ MAP_SSIDataPut(ui32Base, *pui8Data++);
+ }
+
+ //
+ // Send the last data byte, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, *pui8Data);
+}
+
+//*****************************************************************************
+//
+//! Programs the SPI flash in the background.
+//!
+//! \param pState is a pointer to the SPI flash state structure.
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to be programmed.
+//! \param pui8Data is a pointer to the data to be programmed.
+//! \param ui32Count is the number of bytes to be programmed.
+//! \param bUseDMA is \b true if uDMA should be used and \b false otherwise.
+//! \param ui32TxChannel is the uDMA channel to be used for writing to the SSI
+//! module.
+//!
+//! This function programs data into the SPI flash, using either interrupts or
+//! uDMA to transfer the data. This function will return immediately and send
+//! the data in the background. In order for this to complete successfully,
+//! several conditions must be satisfied:
+//!
+//! - Prior to calling this function:
+//! - The SSI module must be enabled in SysCtl.
+//! - The SSI pins must be configured for use by the SSI module.
+//! - The SSI module interrupt must be enabled in NVIC.
+//! - The uDMA module must be enabled in SysCtl and the control table set (if
+//! using uDMA).
+//! - The uDMA channels must be assigned to the SSI module.
+//!
+//! - After calling this function:
+//! - The interrupt handler for the SSI module must call
+//! SPIFlashIntHandler(), passing the same pState structure pointer that
+//! was supplied to this function.
+//! - No other SPI flash operation can be called until this operation has
+//! completed.
+//!
+//! Completion of the programming operation is indicated when
+//! SPIFlashIntHandler() returns \b SPI_FLASH_DONE.
+//!
+//! Like SPIFlashPageProgram(), this uses the 0x02 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashPageProgramNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, const uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel)
+{
+ //
+ // Save the parameters of this program operation to the state structure.
+ //
+ pState->ui32Base = ui32Base;
+ pState->ui16Cmd = CMD_PP;
+ pState->ui16State = STATE_CMD;
+ pState->ui32Addr = ui32Addr;
+ pState->pui8Buffer = (uint8_t *)pui8Data;
+ pState->ui32ReadCount = 0;
+ pState->ui32WriteCount = ui32Count;
+ pState->bUseDMA = bUseDMA;
+ pState->ui32TxChannel = ui32TxChannel & 0x1f;
+
+ //
+ // Enable the SSI transmit interrupt. This will start the transfer. If
+ // uDMA is being used, the uDMA-related interrupt will be enabled at the
+ // appropriate time by the interrupt handler.
+ //
+ HWREG(ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC;
+ HWREG(ui32Base + SSI_O_IM) = SSI_IM_TXIM;
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//!
+//! This function reads data from the SPI flash, using PIO mode. This function
+//! will not return until the read has completed. This uses the 0x03 SPI flash
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashRead(uint32_t ui32Base, uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the read command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_READ);
+
+ //
+ // Send the address of the first byte to read.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIDataPut(ui32Base, ui32Addr & 0xff);
+
+ //
+ // Set the SSI module into read/write mode. In this mode, dummy writes are
+ // required in order to make the transfer occur; the SPI flash will ignore
+ // the data.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);
+
+ //
+ // See if there is a single byte to be read.
+ //
+ if(ui32Count == 1)
+ {
+ //
+ // Perform a single dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+ }
+ else
+ {
+ //
+ // Perform a dummy write to prime the loop.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Loop while there is more than one byte left to be read.
+ //
+ while(--ui32Count != 1)
+ {
+ //
+ // Perform a dummy write to keep the transmit FIFO from going
+ // empty.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into
+ // the data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Perform the final dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Read the final data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash in the background.
+//!
+//! \param pState is a pointer to the SPI flash state structure.
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//! \param bUseDMA is \b true if uDMA should be used and \b false otherwise.
+//! \param ui32TxChannel is the uDMA channel to be used for writing to the SSI
+//! module.
+//! \param ui32RxChannel is the uDMA channel to be used for reading from the
+//! SSI module.
+//!
+//! This function reads data from the SPI flash, using either interrupts or
+//! uDMA to transfer the data. This function will return immediately and read
+//! the data in the background. In order for this to complete successfully,
+//! several conditions must be satisfied:
+//!
+//! - Prior to calling this function:
+//! - The SSI module must be enabled in SysCtl.
+//! - The SSI pins must be configured for use by the SSI module.
+//! - The SSI module interrupt must be enabled in NVIC.
+//! - The uDMA module must be enabled in SysCtl and the control table set (if
+//! using uDMA).
+//! - The uDMA channels must be assigned to the SSI module.
+//!
+//! - After calling this function:
+//! - The interrupt handler for the SSI module must call
+//! SPIFlashIntHandler(), passing the same pState structure pointer that
+//! was supplied to this function.
+//! - No other SPI flash operation can be called until this operation has
+//! completed.
+//!
+//! Completion of the read operation is indicated when SPIFlashIntHandler()
+//! returns \b SPI_FLASH_DONE.
+//!
+//! Like SPIFlashRead(), this uses the 0x03 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashReadNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel, uint32_t ui32RxChannel)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Save the parameters of this read operation to the state structure.
+ //
+ pState->ui32Base = ui32Base;
+ pState->ui16Cmd = CMD_READ;
+ pState->ui16State = STATE_CMD;
+ pState->ui32Addr = ui32Addr;
+ pState->pui8Buffer = pui8Data;
+ pState->ui32ReadCount = ui32Count;
+ pState->ui32WriteCount = ui32Count;
+ pState->bUseDMA = bUseDMA;
+ pState->ui32TxChannel = ui32TxChannel & 0x1f;
+ pState->ui32RxChannel = ui32RxChannel & 0x1f;
+
+ //
+ // Enable the SSI transmit and receive interrupts. This will start the
+ // transfer. If uDMA is being used, the uDMA-related interrupts will be
+ // enabled at the appropriate time by the interrupt handler.
+ //
+ HWREG(ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC | SSI_ICR_DMARXIC;
+ HWREG(ui32Base + SSI_O_IM) = SSI_IM_TXIM | SSI_IM_RXIM | SSI_IM_RTIM;
+}
+
+//*****************************************************************************
+//
+//! Disables SPI flash write operations.
+//!
+//! \param ui32Base is the SSI module base address.
+//!
+//! This function sets the SPI flash to disallow program and erase operations.
+//! This uses the 0x04 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashWriteDisable(uint32_t ui32Base)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the write disable command, marking this byte as the end of the
+ // frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, CMD_WRDI);
+}
+
+//*****************************************************************************
+//
+//! Reads the SPI flash status register.
+//!
+//! \param ui32Base is the SSI module base address.
+//!
+//! This function reads the SPI flash status register. This uses the 0x05 SPI
+//! flash command.
+//!
+//! \return Returns the value of the SPI flash status register.
+//
+//*****************************************************************************
+uint8_t
+SPIFlashReadStatus(uint32_t ui32Base)
+{
+ uint32_t ui32Data;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Data) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the write status register command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_RDSR);
+
+ //
+ // Set the SSI module into read/write mode. In this mode, dummy writes are
+ // required in order to make the transfer occur; the SPI flash will ignore
+ // the data.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);
+
+ //
+ // Perform a single dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the value of the status register.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Data);
+
+ //
+ // Return the status register value.
+ //
+ return(ui32Data & 0xff);
+}
+
+//*****************************************************************************
+//
+//! Enables SPI flash write operations.
+//!
+//! \param ui32Base is the SSI module base address.
+//!
+//! This function sets the SPI flash to allow program and erase operations.
+//! This must be done prior to each SPI flash program or erase operation; the
+//! SPI flash will automatically disable program and erase operations once a
+//! program or erase operation has completed. This uses the 0x06 SPI flash
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashWriteEnable(uint32_t ui32Base)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the write enable command, marking this byte as the end of the
+ // frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, CMD_WREN);
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using the fast read command.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//!
+//! This function reads data from the SPI flash with the fast read command,
+//! using PIO mode. The fast read command allows the SPI flash to be read at
+//! a higher SPI clock rate because of the addition of a dummy cycle during the
+//! command setup. This function will not return until the read has completed.
+//! This uses the 0x0b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashFastRead(uint32_t ui32Base, uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the fast read command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_FREAD);
+
+ //
+ // Send the address of the first byte to read.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIDataPut(ui32Base, ui32Addr & 0xff);
+
+ //
+ // Send a dummy byte.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Set the SSI module into read/write mode. In this mode, dummy writes are
+ // required in order to make the transfer occur; the SPI flash will ignore
+ // the data.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);
+
+ //
+ // See if there is a single byte to be read.
+ //
+ if(ui32Count == 1)
+ {
+ //
+ // Perform a single dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+ }
+ else
+ {
+ //
+ // Perform a dummy write to prime the loop.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Loop while there is more than one byte left to be read.
+ //
+ while(--ui32Count != 1)
+ {
+ //
+ // Perform a dummy write to keep the transmit FIFO from going
+ // empty.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into
+ // the data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Perform the final dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Read the final data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using the fast read command in the
+//! background.
+//!
+//! \param pState is a pointer to the SPI flash state structure.
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//! \param bUseDMA is \b true if uDMA should be used and \b false otherwise.
+//! \param ui32TxChannel is the uDMA channel to be used for writing to the SSI
+//! module.
+//! \param ui32RxChannel is the uDMA channel to be used for reading from the
+//! SSI module.
+//!
+//! This function reads data from the SPI flash with the fast read command,
+//! using either interrupts or uDMA to transfer the data. The fast read
+//! command allows the SPI flash to be read at a higher SPI clock rate because
+//! of the addition of a dummy cycle during the command setup. This function
+//! will return immediately and read the data in the background. In order for
+//! this to complete successfully, several conditions must be satisfied:
+//!
+//! - Prior to calling this function:
+//! - The SSI module must be enabled in SysCtl.
+//! - The SSI pins must be configured for use by the SSI module.
+//! - The SSI module interrupt must be enabled in NVIC.
+//! - The uDMA module must be enabled in SysCtl and the control table set (if
+//! using uDMA).
+//! - The uDMA channels must be assigned to the SSI module.
+//!
+//! - After calling this function:
+//! - The interrupt handler for the SSI module must call
+//! SPIFlashIntHandler(), passing the same pState structure pointer that
+//! was supplied to this function.
+//! - No other SPI flash operation can be called until this operation has
+//! completed.
+//!
+//! Completion of the read operation is indicated when SPIFlashIntHandler()
+//! returns \b SPI_FLASH_DONE.
+//!
+//! Like SPIFlashFastRead(), this uses the 0x0b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashFastReadNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel, uint32_t ui32RxChannel)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Save the parameters of this read operation to the state structure.
+ //
+ pState->ui32Base = ui32Base;
+ pState->ui16Cmd = CMD_FREAD;
+ pState->ui16State = STATE_CMD;
+ pState->ui32Addr = ui32Addr;
+ pState->pui8Buffer = pui8Data;
+ pState->ui32ReadCount = ui32Count;
+ pState->ui32WriteCount = ui32Count;
+ pState->bUseDMA = bUseDMA;
+ pState->ui32TxChannel = ui32TxChannel & 0x1f;
+ pState->ui32RxChannel = ui32RxChannel & 0x1f;
+
+ //
+ // Enable the SSI transmit and receive interrupts. This will start the
+ // transfer. If uDMA is being used, the uDMA-related interrupts will be
+ // enabled at the appropriate time by the interrupt handler.
+ //
+ HWREG(ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC | SSI_ICR_DMARXIC;
+ HWREG(ui32Base + SSI_O_IM) = SSI_IM_TXIM | SSI_IM_RXIM | SSI_IM_RTIM;
+}
+
+//*****************************************************************************
+//
+//! Erases a 4 KB sector of the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to erase.
+//!
+//! This function erases a sector of the SPI flash. Each sector is 4 KB with a
+//! 4 KB alignment; the SPI flash will ignore the lower ten bits of the address
+//! provided. The sector erase command is issued by this function;
+//! SPIFlashReadStatus() must be used to query the SPI flash to determine when
+//! the sector erase operation has completed. This uses the 0x20 SPI flash
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashSectorErase(uint32_t ui32Base, uint32_t ui32Addr)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the sector erase command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_SE);
+
+ //
+ // Send the address of the sector to be erased, marking the last byte of
+ // the address as the end of the frame.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, ui32Addr & 0xff);
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using Bi-SPI.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//!
+//! This function reads data from the SPI flash with Bi-SPI, using PIO mode.
+//! This function will not return until the read has completed. This uses the
+//! 0x3b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashDualRead(uint32_t ui32Base, uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the dual read command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_DREAD);
+
+ //
+ // Send the address of the first byte to read.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIDataPut(ui32Base, ui32Addr & 0xff);
+
+ //
+ // Send a dummy byte.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Set the SSI module into Bi-SPI read mode. In this mode, dummy writes
+ // are required in order to make the transfer occur; the SSI module will
+ // ignore the data (the SPI flash will never see the dummy data since
+ // Bi-SPI read mode is a uni-directional input mode).
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_BI_READ);
+
+ //
+ // See if there is a single byte to be read.
+ //
+ if(ui32Count == 1)
+ {
+ //
+ // Perform a single dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+ }
+ else
+ {
+ //
+ // Perform a dummy write to prime the loop.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Loop while there is more than one byte left to be read.
+ //
+ while(--ui32Count != 1)
+ {
+ //
+ // Perform a dummy write to keep the transmit FIFO from going
+ // empty.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into
+ // the data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Perform the final dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Read the final data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using Bi-SPI in the background.
+//!
+//! \param pState is a pointer to the SPI flash state structure.
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//! \param bUseDMA is \b true if uDMA should be used and \b false otherwise.
+//! \param ui32TxChannel is the uDMA channel to be used for writing to the SSI
+//! module.
+//! \param ui32RxChannel is the uDMA channel to be used for reading from the
+//! SSI module.
+//!
+//! This function reads data from the SPI flash with Bi-SPI, using either
+//! interrupts or uDMA to transfer the data. This function will return
+//! immediately and read the data in the background. In order for this to
+//! complete successfully, several conditions must be satisfied:
+//!
+//! - Prior to calling this function:
+//! - The SSI module must be enabled in SysCtl.
+//! - The SSI pins must be configured for use by the SSI module.
+//! - The SSI module interrupt must be enabled in NVIC.
+//! - The uDMA module must be enabled in SysCtl and the control table set (if
+//! using uDMA).
+//! - The uDMA channels must be assigned to the SSI module.
+//!
+//! - After calling this function:
+//! - The interrupt handler for the SSI module must call
+//! SPIFlashIntHandler(), passing the same pState structure pointer that
+//! was supplied to this function.
+//! - No other SPI flash operation can be called until this operation has
+//! completed.
+//!
+//! Completion of the read operation is indicated when SPIFlashIntHandler()
+//! returns \b SPI_FLASH_DONE.
+//!
+//! Like SPIFLashDualRead(), this uses the 0x3b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashDualReadNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel, uint32_t ui32RxChannel)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Save the parameters of this read operation to the state structure.
+ //
+ pState->ui32Base = ui32Base;
+ pState->ui16Cmd = CMD_DREAD;
+ pState->ui16State = STATE_CMD;
+ pState->ui32Addr = ui32Addr;
+ pState->pui8Buffer = pui8Data;
+ pState->ui32ReadCount = ui32Count;
+ pState->ui32WriteCount = ui32Count;
+ pState->bUseDMA = bUseDMA;
+ pState->ui32TxChannel = ui32TxChannel & 0x1f;
+ pState->ui32RxChannel = ui32RxChannel & 0x1f;
+
+ //
+ // Enable the SSI transmit and receive interrupts. This will start the
+ // transfer. If uDMA is being used, the uDMA-related interrupts will be
+ // enabled at the appropriate time by the interrupt handler.
+ //
+ HWREG(ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC | SSI_ICR_DMARXIC;
+ HWREG(ui32Base + SSI_O_IM) = SSI_IM_TXIM | SSI_IM_RXIM | SSI_IM_RTIM;
+}
+
+//*****************************************************************************
+//
+//! Erases a 32 KB block of the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to erase.
+//!
+//! This function erases a 32 KB block of the SPI flash. Each 32 KB block has
+//! a 32 KB alignment; the SPI flash will ignore the lower 15 bits of the
+//! address provided. The 32 KB block erase command is issued by this
+//! function; SPIFlashReadStatus() must be used to query the SPI flash to
+//! determine when the 32 KB block erase operation has completed. This uses
+//! the 0x52 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashBlockErase32(uint32_t ui32Base, uint32_t ui32Addr)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the 32 KB block erase command command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_BE32);
+
+ //
+ // Send the address of the 32 KB block to be erased, marking the last byte
+ // of the address as the end of the frame.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, ui32Addr & 0xff);
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using Quad-SPI.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//!
+//! This function reads data from the SPI flash with Quad-SPI, using PIO mode.
+//! This function will not return until the read has completed. This uses the
+//! 0x6b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashQuadRead(uint32_t ui32Base, uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the quad read command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_QREAD);
+
+ //
+ // Send the address of the first byte to read.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIDataPut(ui32Base, ui32Addr & 0xff);
+
+ //
+ // Send a dummy byte.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Set the SSI module into Quad-SPI read mode. In this mode, dummy writes
+ // are required in order to make the transfer occur; the SSI module will
+ // ignore the data (the SPI flash will never see the dummy data since
+ // Quad-SPI read mode is a uni-directional input mode).
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_QUAD_READ);
+
+ //
+ // See if there is a single byte to be read.
+ //
+ if(ui32Count == 1)
+ {
+ //
+ // Perform a single dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+ }
+ else
+ {
+ //
+ // Perform a dummy write to prime the loop.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Loop while there is more than one byte left to be read.
+ //
+ while(--ui32Count != 1)
+ {
+ //
+ // Perform a dummy write to keep the transmit FIFO from going
+ // empty.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into
+ // the data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Perform the final dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Read the final data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using Quad-SPI in the background.
+//!
+//! \param pState is a pointer to the SPI flash state structure.
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//! \param bUseDMA is \b true if uDMA should be used and \b false otherwise.
+//! \param ui32TxChannel is the uDMA channel to be used for writing to the SSI
+//! module.
+//! \param ui32RxChannel is the uDMA channel to be used for reading from the
+//! SSI module.
+//!
+//! This function reads data from the SPI flash with Quad-SPI, using either
+//! interrupts or uDMA to transfer the data. This function will return
+//! immediately and read the data in the background. In order for this to
+//! complete successfully, several conditions must be satisfied:
+//!
+//! - Prior to calling this function:
+//! - The SSI module must be enabled in SysCtl.
+//! - The SSI pins must be configured for use by the SSI module.
+//! - The SSI module interrupt must be enabled in NVIC.
+//! - The uDMA module must be enabled in SysCtl and the control table set (if
+//! using uDMA).
+//! - The uDMA channels must be assigned to the SSI module.
+//!
+//! - After calling this function:
+//! - The interrupt handler for the SSI module must call
+//! SPIFlashIntHandler(), passing the same pState structure pointer that
+//! was supplied to this function.
+//! - No other SPI flash operation can be called until this operation has
+//! completed.
+//!
+//! Completion of the read operation is indicated when SPIFlashIntHandler()
+//! returns \b SPI_FLASH_DONE.
+//!
+//! Like SPIFlashQuadRead(), this uses the 0x6b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashQuadReadNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel, uint32_t ui32RxChannel)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Save the parameters of this read operation to the state structure.
+ //
+ pState->ui32Base = ui32Base;
+ pState->ui16Cmd = CMD_QREAD;
+ pState->ui16State = STATE_CMD;
+ pState->ui32Addr = ui32Addr;
+ pState->pui8Buffer = pui8Data;
+ pState->ui32ReadCount = ui32Count;
+ pState->ui32WriteCount = ui32Count;
+ pState->bUseDMA = bUseDMA;
+ pState->ui32TxChannel = ui32TxChannel & 0x1f;
+ pState->ui32RxChannel = ui32RxChannel & 0x1f;
+
+ //
+ // Enable the SSI transmit and receive interrupts. This will start the
+ // transfer. If uDMA is being used, the uDMA-related interrupts will be
+ // enabled at the appropriate time by the interrupt handler.
+ //
+ HWREG(ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC | SSI_ICR_DMARXIC;
+ HWREG(ui32Base + SSI_O_IM) = SSI_IM_TXIM | SSI_IM_RXIM | SSI_IM_RTIM;
+}
+
+//*****************************************************************************
+//
+//! Reads the manufacturer and device IDs from the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param pui8ManufacturerID is a pointer to the location into which to store
+//! the manufacturer ID.
+//! \param pui16DeviceID is a pointer to the location into which to store the
+//! device ID.
+//!
+//! This function reads the manufacturer and device IDs from the SPI flash.
+//! These values can be used to identify the SPI flash that is attached, as
+//! well as determining if a SPI flash is attached (if the \b SSIRx pin is
+//! pulled up or down, either using the pad's weak pull up/down or using an
+//! external resistor, which will cause the returned IDs to be either all zeros
+//! or all ones if the SPI flash is not attached). This uses the 0x9f SPI
+//! flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashReadID(uint32_t ui32Base, uint8_t *pui8ManufacturerID,
+ uint16_t *pui16DeviceID)
+{
+ uint32_t ui32Data1, ui32Data2;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Data1) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the read ID command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_RDID);
+
+ //
+ // Set the SSI module into read/write mode. In this mode, dummy writes are
+ // required in order to make the transfer occur; the SPI flash will ignore
+ // the data.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);
+
+ //
+ // Send three dummy bytes, marking the last as the end of the frame.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+ MAP_SSIDataPut(ui32Base, 0);
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the first returned data byte, which contains the manufacturer ID.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Data1);
+ *pui8ManufacturerID = ui32Data1 & 0xff;
+
+ //
+ // Read the remaining two data bytes, which contain the device ID.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Data1);
+ MAP_SSIDataGet(ui32Base, &ui32Data2);
+ *pui16DeviceID = ((ui32Data1 & 0xff) << 8) | (ui32Data2 & 0xff);
+}
+
+//*****************************************************************************
+//
+//! Erases the entire SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//!
+//! This command erase the entire SPI flash. The chip erase command is issued
+//! by this function; SPIFlashReadStatus() must be used to query the SPI flash
+//! to determine when the chip erase operation has completed. This uses the
+//! 0xc7 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashChipErase(uint32_t ui32Base)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the chip erase command, marking this byte as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, CMD_CE);
+}
+
+//*****************************************************************************
+//
+//! Erases a 64 KB block of the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to erase.
+//!
+//! This function erases a 64 KB block of the SPI flash. Each 64 KB block has
+//! a 64 KB alignment; the SPI flash will ignore the lower 16 bits of the
+//! address provided. The 64 KB block erase command is issued by this
+//! function; SPIFlashReadStatus() must be used to query the SPI flash to
+//! determine when the 64 KB block erase operation has completed. This uses
+//! the 0xd8 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashBlockErase64(uint32_t ui32Base, uint32_t ui32Addr)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the 64 KB block erase command command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_BE64);
+
+ //
+ // Send the address of the 64 KB block to be erased, marking the last byte
+ // of the address as the end of the frame.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, ui32Addr & 0xff);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/spi_flash.h b/utils/spi_flash.h
new file mode 100644
index 0000000..59311fb
--- /dev/null
+++ b/utils/spi_flash.h
@@ -0,0 +1,166 @@
+//*****************************************************************************
+//
+// spi_flash.h - Prototypes for the SPI flash driver.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SPI_FLASH_H__
+#define __SPI_FLASH_H__
+
+//*****************************************************************************
+//
+//! \addtogroup spi_flash_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The state structure used when performing non-blocking SPI flash operations.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The base address of the SSI module that is being used.
+ //
+ uint32_t ui32Base;
+
+ //
+ //! The command that is being send to the SPI flash.
+ //
+ uint16_t ui16Cmd;
+
+ //
+ //! The current state of the SPI flash state machine.
+ //
+ uint16_t ui16State;
+
+ //
+ //! The SPI flash address associated with the command.
+ //
+ uint32_t ui32Addr;
+
+ //
+ //! A pointer to the data buffer that is being read or written.
+ //
+ uint8_t *pui8Buffer;
+
+ //
+ //! The count of bytes left to be read.
+ //
+ uint32_t ui32ReadCount;
+
+ //
+ //! The count of bytes left to be written.
+ //
+ uint32_t ui32WriteCount;
+
+ //
+ //! A flag that is true if uDMA used be used for the transfer.
+ //
+ bool bUseDMA;
+
+ //
+ //! The uDMA channel to use for transmitting when using uDMA for the
+ //! transfer.
+ //
+ uint32_t ui32TxChannel;
+
+ //
+ //! The uDMA channel to use for receiving when using uDMA for the transfer.
+ //
+ uint32_t ui32RxChannel;
+}
+tSPIFlashState;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The possible return values from the SPI flash interrupt handler.
+//
+//*****************************************************************************
+#define SPI_FLASH_IDLE 0
+#define SPI_FLASH_WORKING 1
+#define SPI_FLASH_DONE 3
+
+//*****************************************************************************
+//
+// Prototypes.
+//
+//*****************************************************************************
+extern uint32_t SPIFlashIntHandler(tSPIFlashState *pState);
+extern void SPIFlashInit(uint32_t ui32Base, uint32_t ui32Clock,
+ uint32_t ui32BitRate);
+extern void SPIFlashWriteStatus(uint32_t ui32Base, uint8_t ui8Status);
+extern void SPIFlashPageProgram(uint32_t ui32Base, uint32_t ui32Addr,
+ const uint8_t *pui8Data, uint32_t ui32Count);
+extern void SPIFlashPageProgramNonBlocking(tSPIFlashState *pState,
+ uint32_t ui32Base,
+ uint32_t ui32Addr,
+ const uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel);
+extern void SPIFlashRead(uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count);
+extern void SPIFlashReadNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel,
+ uint32_t ui32RxChannel);
+extern void SPIFlashWriteDisable(uint32_t ui32Base);
+extern uint8_t SPIFlashReadStatus(uint32_t ui32Base);
+extern void SPIFlashWriteEnable(uint32_t ui32Base);
+extern void SPIFlashFastRead(uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count);
+extern void SPIFlashFastReadNonBlocking(tSPIFlashState *pState,
+ uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count,
+ bool bUseDMA, uint32_t ui32TxChannel,
+ uint32_t ui32RxChannel);
+extern void SPIFlashSectorErase(uint32_t ui32Base, uint32_t ui32Addr);
+extern void SPIFlashDualRead(uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count);
+extern void SPIFlashDualReadNonBlocking(tSPIFlashState *pState,
+ uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count,
+ bool bUseDMA, uint32_t ui32TxChannel,
+ uint32_t ui32RxChannel);
+extern void SPIFlashBlockErase32(uint32_t ui32Base, uint32_t ui32Addr);
+extern void SPIFlashQuadRead(uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count);
+extern void SPIFlashQuadReadNonBlocking(tSPIFlashState *pState,
+ uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count,
+ bool bUseDMA, uint32_t ui32TxChannel,
+ uint32_t ui32RxChannel);
+extern void SPIFlashReadID(uint32_t ui32Base, uint8_t *pui8ManufacturerID,
+ uint16_t *pui16DeviceID);
+extern void SPIFlashChipErase(uint32_t ui32Base);
+extern void SPIFlashBlockErase64(uint32_t ui32Base, uint32_t ui32Addr);
+
+#endif // __SPI_FLASH_H__
diff --git a/utils/swupdate.c b/utils/swupdate.c
new file mode 100644
index 0000000..edd523b
--- /dev/null
+++ b/utils/swupdate.c
@@ -0,0 +1,355 @@
+//*****************************************************************************
+//
+// swupdate.c - A module wrapping the Ethernet bootloader software update
+// functionality.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_nvic.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "driverlib/flash.h"
+#include "driverlib/rom.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/systick.h"
+#include "utils/lwiplib.h"
+#include "utils/swupdate.h"
+
+//*****************************************************************************
+//
+//! \addtogroup swupdate_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The UDP port used to send the remote firmware update request signal. This
+// is the well-known port associated with "discard" function and is also used
+// by some Wake-On-LAN implementations.
+//
+//*****************************************************************************
+#define MPACKET_PORT 9
+
+//*****************************************************************************
+//
+// The length of the various parts of the remote firmware update request magic
+// packet and its total length. This contains a 6 byte header followed by 4
+// copies of the target MAC address.
+//
+//*****************************************************************************
+#define MPACKET_HEADER_LEN 6
+#define MPACKET_MAC_REP 4
+#define MPACKET_MAC_LEN 6
+#define MPACKET_LEN (MPACKET_HEADER_LEN + \
+ (MPACKET_MAC_REP * MPACKET_MAC_LEN))
+
+//*****************************************************************************
+//
+// The marker byte used at the start of the magic packet. This is repeated
+// MPACKET_HEADER_LEN times.
+//
+//*****************************************************************************
+#define MPACKET_MARKER 0xAA
+
+//*****************************************************************************
+//
+// The callback function which is used to determine whether or not the
+// application wants to allow a remotely-requested firmware update.
+//
+//*****************************************************************************
+tSoftwareUpdateRequested g_pfnUpdateCallback = NULL;
+
+//*****************************************************************************
+//
+// A pointer to the remote firmware update signal PCB data structure.
+//
+//*****************************************************************************
+static struct udp_pcb *g_psMagicPacketPCB = NULL;
+
+//*****************************************************************************
+//
+// The MAC address for this board.
+//
+//*****************************************************************************
+static uint8_t g_pui8MACAddr[6];
+
+//*****************************************************************************
+//
+// Receives a UDP port 9 packet from lwIP.
+//
+// \param arg is not used in this implementation.
+// \param pcb is the pointer to the UDB control structure.
+// \param p is the pointer to the PBUF structure containing the packet data.
+// \param addr is the source (remote) IP address for this packet.
+// \param port is the source (remote) port for this packet.
+//
+// This function is called when the lwIP TCP/IP stack has an incoming
+// UDP packet to be processed on the remote firmware update signal port.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SoftwareUpdateUDPReceive(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+ struct ip_addr *addr, u16_t port)
+{
+ int8_t *pi8Data = p->payload;
+ uint32_t ui32Loop, ui32MACLoop;
+
+ //
+ // Check that the packet length is what we expect. If not, ignore the
+ // packet.
+ //
+ if(p->len == MPACKET_LEN)
+ {
+ //
+ // The length matches so now look for the 6 byte header
+ //
+ for(ui32Loop = 0; ui32Loop < MPACKET_HEADER_LEN; ui32Loop++)
+ {
+ //
+ // Does this header byte match the expected marker?
+ //
+ if((*pi8Data & 0x000000FF)!= MPACKET_MARKER)
+ {
+ //
+ // No - free the buffer and return - this is not a packet
+ // we are interested in.
+ //
+ pbuf_free(p);
+ return;
+ }
+ else
+ {
+ //
+ // Byte matched so move on to the next one.
+ //
+ pi8Data++;
+ }
+ }
+ }
+ else
+ {
+ //
+ // No - free the buffer and return - this is not a packet
+ // we are interested in.
+ //
+ pbuf_free(p);
+ return;
+ }
+
+ //
+ // If we get here, the packet length and header markers indicate
+ // that this is a remote firmware update request. Now check that it
+ // is for us and that it contains the required number of copies of
+ // the MAC address.
+ //
+
+ //
+ // Loop through each of the expected MAC address copies.
+ //
+ for(ui32Loop = 0; ui32Loop < MPACKET_MAC_REP; ui32Loop++)
+ {
+ //
+ // Loop through each byte of the MAC address in this
+ // copy.
+ //
+ for(ui32MACLoop = 0; ui32MACLoop < MPACKET_MAC_LEN; ui32MACLoop++)
+ {
+ //
+ // Does the payload MAC address byte match what we expect?
+ //
+ if((*pi8Data & 0x000000FF) != g_pui8MACAddr[ui32MACLoop])
+ {
+ //
+ // No match - free the packet and return.
+ //
+ pbuf_free(p);
+ return;
+ }
+ else
+ {
+ //
+ // Byte matched so move on to the next one.
+ //
+ pi8Data++;
+ }
+ }
+ }
+
+ //
+ // Free the pbuf since we are finished with it now.
+ //
+ pbuf_free(p);
+
+ //
+ // If we get this far, we've received a valid remote firmare update
+ // request targetted at this board. Signal this to the application
+ // if we have a valid callback pointer.
+ //
+ if(g_pfnUpdateCallback)
+ {
+ g_pfnUpdateCallback();
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the remote Ethernet software update notification feature.
+//!
+//! \param pfnCallback is a pointer to a function which will be called whenever
+//! a remote firmware update request is received. If the application wishes
+//! to allow the update to go ahead, it must call SoftwareUpdateBegin() from
+//! non-interrupt context after the callback is received. Note that the
+//! callback will most likely be made in interrupt context so it is not safe
+//! to call SoftwareUpdateBegin() from within the callback itself.
+//!
+//! This function may be used on Ethernet-enabled parts to support
+//! remotely-signaled firmware updates over Ethernet. The LM Flash Programmer
+//! (LMFlash.exe) application sends a magic packet to UDP port 9 whenever the
+//! user requests an Ethernet-based firmware update. This packet consists of
+//! 6 bytes of 0xAA followed by the target MAC address repeated 4 times.
+//! This function starts listening on UDP port 9 and, if a magic packet
+//! matching the MAC address of this board is received, makes a call to the
+//! provided callback function to indicate that an update has been requested.
+//!
+//! The callback function provided here will typically be called in the context
+//! of the lwIP Ethernet interrupt handler. It is not safe to call
+//! SoftwareUpdateBegin() in this context so the application should use the
+//! callback to signal code running in a non-interrupt context to perform the
+//! update if it is to be allowed.
+//!
+//! UDP port 9 is chosen for this function since this is the well-known port
+//! associated with ``discard'' operation. In other words, any other system
+//! receiving the magic packet will simply ignore it. The actual magic packet
+//! used is modeled on Wake-On-LAN which uses a similar structure (6 bytes of
+//! 0xFF followed by 16 repetitions of the target MAC address). Some
+//! Wake-On-LAN implementations also use UDP port 9 for their signaling.
+//!
+//! \note Applications using this function must initialize the lwIP stack prior
+//! to making this call and must ensure that the lwIPTimer() function is called
+//! periodically. lwIP UDP must be enabled in lwipopts.h to ensure that the
+//! magic packets can be received.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftwareUpdateInit(tSoftwareUpdateRequested pfnCallback)
+{
+ uint32_t ui32User0, ui32User1;
+
+ //
+ // Remember the callback function pointer we have been given.
+ //
+ g_pfnUpdateCallback = pfnCallback;
+
+ //
+ // Get the MAC address from the user registers in NV ram.
+ //
+ FlashUserGet(&ui32User0, &ui32User1);
+
+ //
+ // Convert the 24/24 split MAC address from NV ram into a MAC address
+ // array.
+ //
+ g_pui8MACAddr[0] = ui32User0 & 0xff;
+ g_pui8MACAddr[1] = (ui32User0 >> 8) & 0xff;
+ g_pui8MACAddr[2] = (ui32User0 >> 16) & 0xff;
+ g_pui8MACAddr[3] = ui32User1 & 0xff;
+ g_pui8MACAddr[4] = (ui32User1 >> 8) & 0xff;
+ g_pui8MACAddr[5] = (ui32User1 >> 16) & 0xff;
+
+ //
+ // Set up a UDP PCB to allow us to receive the magic packets sent from
+ // LMFlash. These may be sent to port 9 from any port on the source
+ // machine so we do not call udp_connect here (since this causes lwIP to
+ // filter any packet that did not originate from port 9 too).
+ //
+ g_psMagicPacketPCB = udp_new();
+ udp_recv(g_psMagicPacketPCB, SoftwareUpdateUDPReceive, NULL);
+ udp_bind(g_psMagicPacketPCB, IP_ADDR_ANY, MPACKET_PORT);
+}
+
+//*****************************************************************************
+//
+//! Passes control to the bootloader and initiates a remote software update
+//! over Ethernet.
+//!
+//! This function passes control to the bootloader and initiates an update of
+//! the main application firmware image via BOOTP across Ethernet. This
+//! function may only be used on parts supporting Ethernet and in cases where
+//! the Ethernet boot loader is in use alongside the main application image.
+//! It must not be called in interrupt context.
+//!
+//! Applications wishing to make use of this function must be built to
+//! operate with the bootloader. If this function is called on a system
+//! which does not include the bootloader, the results are unpredictable.
+//!
+//! \note It is not safe to call this function from within the callback
+//! provided on the initial call to SoftwareUpdateInit(). The application
+//! must use the callback to signal a pending update (assuming the update is to
+//! be permitted) to some other code running in a non-interrupt context.
+//!
+//! \return Never returns.
+//
+//*****************************************************************************
+void
+SoftwareUpdateBegin(uint32_t ui32SysClock)
+{
+ //
+ // Disable all processor interrupts. Instead of disabling them
+ // one at a time (and possibly missing an interrupt if new sources
+ // are added), a direct write to NVIC is done to disable all
+ // peripheral interrupts.
+ //
+ HWREG(NVIC_DIS0) = 0xffffffff;
+ HWREG(NVIC_DIS1) = 0xffffffff;
+ HWREG(NVIC_DIS2) = 0xffffffff;
+ HWREG(NVIC_DIS3) = 0xffffffff;
+ HWREG(NVIC_DIS4) = 0xffffffff;
+
+ //
+ // Also disable the SysTick interrupt.
+ //
+ SysTickIntDisable();
+ SysTickDisable();
+
+ //
+ // Return control to the boot loader. This is a call to the SVC
+ // handler in the flashed-based boot loader, or to the ROM if configured.
+ //
+#if ((defined ROM_UpdateEthernet) && !(defined USE_FLASH_BOOT_LOADER))
+ ROM_UpdateEMAC(ui32SysClock);
+#else
+ (*((void (*)(void))(*(uint32_t *)0x2c)))();
+#endif
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/swupdate.h b/utils/swupdate.h
new file mode 100644
index 0000000..1cd44db
--- /dev/null
+++ b/utils/swupdate.h
@@ -0,0 +1,66 @@
+//*****************************************************************************
+//
+// swupdate.h - Prototypes for the bootloader software update module.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SWUPDATE_H__
+#define __SWUPDATE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// This function pointer represents the callback made to the application in
+// cases where a remote host requests a software update be performed. The
+// application should use this to trigger a call to SoftwareUpdateBegin from
+// a non-interrupt context.
+//
+//*****************************************************************************
+typedef void (*tSoftwareUpdateRequested)(void);
+
+//*****************************************************************************
+//
+// Public function prototypes.
+//
+//*****************************************************************************
+extern void SoftwareUpdateInit(tSoftwareUpdateRequested pfnCallback);
+extern void SoftwareUpdateBegin(uint32_t ui32SysClock);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SWUPDATE_H__
diff --git a/utils/tftp.c b/utils/tftp.c
new file mode 100644
index 0000000..674c307
--- /dev/null
+++ b/utils/tftp.c
@@ -0,0 +1,710 @@
+//*****************************************************************************
+//
+// tftp.c - A very simple lwIP TFTP server.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "utils/uartstdio.h"
+#include "utils/lwiplib.h"
+#include "utils/ustdlib.h"
+
+//*****************************************************************************
+//
+//! \addtogroup tftp_api
+//! @{
+//
+//*****************************************************************************
+#include "utils/tftp.h"
+
+//*****************************************************************************
+//
+// The TFTP commands.
+//
+//*****************************************************************************
+#define TFTP_RRQ 1
+#define TFTP_WRQ 2
+#define TFTP_DATA 3
+#define TFTP_ACK 4
+#define TFTP_ERROR 5
+
+//*****************************************************************************
+//
+// The UDP port for the TFTP server.
+//
+//*****************************************************************************
+#define TFTP_PORT 69
+
+//*****************************************************************************
+//
+// Application connection notification callback.
+//
+//*****************************************************************************
+static tTFTPRequest g_pfnRequest;
+
+//*****************************************************************************
+//
+// Close the TFTP connection and free associated resources.
+//
+//*****************************************************************************
+static void
+TFTPClose(tTFTPConnection *psTFTP)
+{
+ //
+ // Tell the application we are closing the connection.
+ //
+ if(psTFTP->pfnClose)
+ {
+ psTFTP->pfnClose(psTFTP);
+ }
+
+ //
+ // Close the underlying UDP connection.
+ //
+ udp_remove(psTFTP->psPCB);
+
+ //
+ // Free the instance data structure.
+ //
+ mem_free(psTFTP);
+}
+
+//*****************************************************************************
+//
+// Sends a TFTP error packet.
+//
+//*****************************************************************************
+static void
+TFTPErrorSend(tTFTPConnection *psTFTP, tTFTPError eError)
+{
+ uint32_t ui32Length;
+ uint8_t *pui8Data;
+ struct pbuf *p;
+
+ //
+ // How big is this packet going to be?
+ //
+ ui32Length = 5 + strlen(psTFTP->pcErrorString);
+
+ //
+ // Allocate a pbuf for this data packet.
+ //
+ p = pbuf_alloc(PBUF_TRANSPORT, ui32Length, PBUF_RAM);
+ if(!p)
+ {
+ return;
+ }
+
+ //
+ // Get a pointer to the data packet.
+ //
+ pui8Data = (uint8_t *)p->payload;
+
+ //
+ // Fill in the packet.
+ //
+ pui8Data[0] = (TFTP_ERROR >> 8) & 0xff;
+ pui8Data[1] = TFTP_ERROR & 0xff;
+ pui8Data[2] = ((uint32_t)eError >> 8) & 0xff;
+ pui8Data[3] = (uint32_t)eError & 0xff;
+ memcpy(&pui8Data[4], psTFTP->pcErrorString, ui32Length - 5);
+
+ //
+ // Send the data packet.
+ //
+ udp_send(psTFTP->psPCB, p);
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+// Sends a TFTP data packet.
+//
+//*****************************************************************************
+static void
+TFTPDataSend(tTFTPConnection *psTFTP)
+{
+ uint32_t ui32Length;
+ uint8_t *pui8Data;
+ tTFTPError eError;
+ struct pbuf *p;
+
+ //
+ // Determine the number of bytes to place into this packet.
+ //
+ if(psTFTP->ui32DataRemaining < (psTFTP->ui32BlockNum * TFTP_BLOCK_SIZE))
+ {
+ ui32Length = psTFTP->ui32DataRemaining & (TFTP_BLOCK_SIZE - 1);
+ }
+ else
+ {
+ ui32Length = TFTP_BLOCK_SIZE;
+ }
+
+ //
+ // Allocate a pbuf for this data packet.
+ //
+ p = pbuf_alloc(PBUF_TRANSPORT, ui32Length + 4, PBUF_RAM);
+ if(!p)
+ {
+ return;
+ }
+
+ //
+ // Get a pointer to the data packet.
+ //
+ pui8Data = (uint8_t *)p->payload;
+
+ //
+ // Fill in the packet header.
+ //
+ pui8Data[0] = (TFTP_DATA >> 8) & 0xff;
+ pui8Data[1] = TFTP_DATA & 0xff;
+ pui8Data[2] = (psTFTP->ui32BlockNum >> 8) & 0xff;
+ pui8Data[3] = psTFTP->ui32BlockNum & 0xff;
+
+ //
+ // Ask the application to provide the data we need.
+ //
+ psTFTP->pui8Data = pui8Data + 4;
+ psTFTP->ui32DataLength = ui32Length;
+ eError = psTFTP->pfnGetData(psTFTP);
+
+ //
+ // Send the data packet or, if an error was reported, send an error.
+ //
+ if(eError == TFTP_OK)
+ {
+ udp_send(psTFTP->psPCB, p);
+ }
+ else
+ {
+ TFTPErrorSend(psTFTP, eError);
+ TFTPClose(psTFTP);
+ }
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+// Send an ACK packet back to the TFTP client.
+//
+//*****************************************************************************
+static void
+TFTPDataAck(tTFTPConnection *psTFTP)
+{
+ uint8_t *pui8Data;
+ struct pbuf *p;
+
+ //
+ // Allocate a pbuf for this data packet.
+ //
+ p = pbuf_alloc(PBUF_TRANSPORT, 4, PBUF_RAM);
+ if(!p)
+ {
+ return;
+ }
+
+ //
+ // Get a pointer to the data packet.
+ //
+ pui8Data = (uint8_t *)p->payload;
+
+ //
+ // Fill in the packet header.
+ //
+ pui8Data[0] = (TFTP_ACK >> 8) & 0xff;
+ pui8Data[1] = TFTP_ACK & 0xff;
+ pui8Data[2] = (psTFTP->ui32BlockNum >> 8) & 0xff;
+ pui8Data[3] = psTFTP->ui32BlockNum & 0xff;
+
+ //
+ // Send the data packet.
+ //
+ udp_send(psTFTP->psPCB, p);
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+// Handles datagrams received from the TFTP data connection.
+//
+//*****************************************************************************
+static void
+TFTPDataRecv(void *arg, struct udp_pcb *upcb, struct pbuf *p,
+ struct ip_addr *addr, u16_t port)
+{
+ uint8_t *pui8Data;
+ uint32_t ui32Block;
+ struct pbuf *pBuf;
+ tTFTPConnection *psTFTP;
+ tTFTPError eRetcode;
+
+ //
+ // Initialize our return code.
+ //
+ eRetcode = TFTP_ERR_NOT_DEFINED;
+
+ //
+ // Get a pointer to the connection instance data.
+ //
+ psTFTP = (tTFTPConnection *)arg;
+
+ //
+ // Get a pointer to the TFTP packet.
+ //
+ pui8Data = (uint8_t *)(p->payload);
+
+ //
+ // If this is an ACK packet, send back the next block to satisfy an
+ // ongoing GET (read) request.
+ //
+ if((pui8Data[0] == ((TFTP_ACK >> 8) & 0xff)) &&
+ (pui8Data[1] == (TFTP_ACK & 0xff)))
+ {
+ //
+ // Extract the block number from the acknowledge.
+ //
+ ui32Block = (pui8Data[2] << 8) + pui8Data[3];
+
+ //
+ // DEBUG ONLY!
+ //
+ UARTprintf("ACK %d\n", ui32Block);
+
+ //
+ // See if there is more data to be sent. Note that we need the "<="
+ // here to ensure that we send back a zero length packet in the case
+ // that the file is a multiple of 512 bytes (in other words, the last
+ // packet of valid data was a full packet).
+ //
+ if((ui32Block * TFTP_BLOCK_SIZE) <= psTFTP->ui32DataRemaining)
+ {
+ //
+ // Send the next block of the file.
+ //
+ psTFTP->ui32BlockNum = ui32Block + 1;
+ TFTPDataSend(psTFTP);
+ }
+ else
+ {
+ //
+ // The transfer is complete, so close the data connection.
+ //
+ TFTPClose(psTFTP);
+ psTFTP = NULL;
+ }
+ }
+ else
+ {
+ //
+ // If this is a DATA packet, get the payload and write it to the
+ // appropriate location in the serial flash.
+ //
+ if((pui8Data[0] == ((TFTP_DATA >> 8) & 0xff)) &&
+ (pui8Data[1] == (TFTP_DATA & 0xff)))
+ {
+ //
+ // This is a data packet. Extract the block number from the packet
+ // and set the offset within the block (stored in
+ // ui32DataRemaining) to zero.
+ //
+ psTFTP->ui32BlockNum = (pui8Data[2] << 8) + pui8Data[3];
+ psTFTP->ui32DataRemaining = 0;
+ psTFTP->ui32DataLength = p->len - 4;
+
+ //
+ // Pass the data back to the application for handling. Remember
+ // that the data may be stored across several pbufs in the chain.
+ // We can't assume it is in a contiguous block.
+ //
+ psTFTP->pui8Data = pui8Data + 4;
+ pBuf = p;
+
+ //
+ // Keep writing until we run out of data.
+ //
+ while(pBuf)
+ {
+ //
+ // Pass this block to the application.
+ //
+ eRetcode = psTFTP->pfnPutData(psTFTP);
+
+ //
+ // Was the data written successfully?
+ //
+ if(eRetcode != TFTP_OK)
+ {
+ //
+ // No - drop out.
+ //
+ break;
+ }
+
+ //
+ // Update the offset so that it is correct for the next pbuf
+ // in the chain.
+ //
+ psTFTP->ui32DataRemaining += psTFTP->ui32DataLength;
+
+ //
+ // Move to the next pbuf in the chain
+ //
+ pBuf = pBuf->next;
+ if(pBuf)
+ {
+ psTFTP->pui8Data = pBuf->payload;
+ psTFTP->ui32DataLength = pBuf->len;
+ }
+ }
+
+ //
+ // If we get here and there was an error reported, pass the error
+ // back to the TFTP client.
+ //
+ if(psTFTP && (eRetcode != TFTP_OK))
+ {
+ //
+ // Send the error code to the client.
+ //
+ TFTPErrorSend(psTFTP, eRetcode);
+
+ //
+ // Close the connection.
+ //
+ TFTPClose(psTFTP);
+ psTFTP = NULL;
+ }
+ else
+ {
+ //
+ // Acknowledge this block.
+ //
+ TFTPDataAck(psTFTP);
+
+ //
+ // Is the transfer finished?
+ //
+ if(p->tot_len < (TFTP_BLOCK_SIZE + 4))
+ {
+ //
+ // We got a short packet so the transfer is complete.
+ // Close the connection.
+ //
+ TFTPClose(psTFTP);
+ psTFTP = NULL;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Is the client reporting an error?
+ //
+ if((pui8Data[0] == ((TFTP_ERROR >> 8) & 0xff)) &&
+ (pui8Data[1] == (TFTP_ERROR & 0xff)))
+ {
+ //
+ // Yes - we got an error so close the connection.
+ //
+ TFTPClose(psTFTP);
+ psTFTP = NULL;
+ }
+ }
+ }
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+// Parses the request string to determine the transfer mode, netascii, octet or
+// mail, for this request.
+//
+//*****************************************************************************
+static tTFTPMode
+TFTPModeGet(uint8_t *pui8Request, uint32_t ui32Len)
+{
+ uint32_t ui32Loop, ui32Max;
+
+ //
+ // Look for the first zero after the start of the filename string (skipping
+ // the first two bytes of the request packet).
+ //
+ for(ui32Loop = 2; ui32Loop < ui32Len; ui32Loop++)
+ {
+ if(pui8Request[ui32Loop] == (uint8_t)0)
+ {
+ break;
+ }
+ }
+
+ //
+ // Skip past the zero.
+ //
+ ui32Loop++;
+
+ //
+ // Did we run off the end of the string?
+ //
+ if(ui32Loop >= ui32Len)
+ {
+ //
+ // Yes - this appears to be an invalid request.
+ //
+ return(TFTP_MODE_INVALID);
+ }
+
+ //
+ // How much data do we have left to look for the mode string?
+ //
+ ui32Max = ui32Len - ui32Loop;
+
+ //
+ // Now determine which of the modes this request asks for. Is it ASCII?
+ //
+ if(!ustrncasecmp("netascii", (char *)&pui8Request[ui32Loop], ui32Max))
+ {
+ //
+ // This is an ASCII file transfer.
+ //
+ return(TFTP_MODE_NETASCII);
+ }
+
+ //
+ // Binary transfer?
+ //
+ if(!ustrncasecmp("octet", (char *)&pui8Request[ui32Loop], ui32Max))
+ {
+ //
+ // This is a binary file transfer.
+ //
+ return(TFTP_MODE_OCTET);
+ }
+
+ //
+ // All other strings are invalid or obsolete ("mail" for example).
+ //
+ return(TFTP_MODE_INVALID);
+}
+
+//*****************************************************************************
+//
+// Handles datagrams received on the TFTP server port.
+//
+//*****************************************************************************
+static void
+TFTPRecv(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr,
+ u16_t port)
+{
+ uint8_t *pui8Data;
+ bool bGetRequest;
+ tTFTPMode eMode;
+ tTFTPError eRetcode;
+ tTFTPConnection *psTFTP;
+
+ //
+ // Get a pointer to the TFTP packet.
+ //
+ pui8Data = (uint8_t *)(p->payload);
+
+ //
+ // Is this a read (GET) request?
+ //
+ if((pui8Data[0] == ((TFTP_RRQ >> 8) & 0xff)) &&
+ (pui8Data[1] == (TFTP_RRQ & 0xff)))
+ {
+ //
+ // Yes - remember that this is a GET request.
+ //
+ bGetRequest = true;
+ }
+
+ //
+ // Is this a write (PUT) request?
+ //
+ else if((pui8Data[0] == ((TFTP_WRQ >> 8) & 0xff)) &&
+ (pui8Data[1] == (TFTP_WRQ & 0xff)))
+ {
+ //
+ // Yes - remember that this is a PUT request.
+ //
+ bGetRequest = false;
+ }
+ else
+ {
+ //
+ // The request is neither GET nor PUT so just ignore it.
+ //
+ pbuf_free(p);
+ return;
+ }
+
+ //
+ // What is the mode for this request?
+ //
+ eMode = TFTPModeGet(pui8Data, p->len);
+
+ //
+ // Was the transfer mode valid?
+ //
+ if(eMode != TFTP_MODE_INVALID)
+ {
+ //
+ // The transfer mode is valid so allocate a new connection instance
+ // and pass this to the client to have it tell us how to proceed.
+ //
+ psTFTP = (tTFTPConnection *)mem_malloc(sizeof(tTFTPConnection));
+
+ //
+ // If we can't allocate the connection instance, all we can do is
+ // ignore the datagram.
+ //
+ if(!psTFTP)
+ {
+ pbuf_free(p);
+ return;
+ }
+
+ //
+ // Clear out the structure and initialize a few fields.
+ //
+ memset(psTFTP, 0, sizeof(tTFTPConnection));
+ psTFTP->pcErrorString = "Unknown error";
+
+ //
+ // Yes - create the new UDP connection and set things up to
+ // handle this request.
+ //
+ psTFTP->psPCB = udp_new();
+ udp_recv(psTFTP->psPCB, TFTPDataRecv, psTFTP);
+ udp_connect(psTFTP->psPCB, addr, port);
+
+ //
+ // Ask the application if it wants to proceed with this request.
+ //
+ eRetcode = g_pfnRequest(psTFTP, bGetRequest, (int8_t *)(pui8Data + 2),
+ eMode);
+
+ //
+ // Does it want to go on?
+ //
+ if(eRetcode == TFTP_OK)
+ {
+ //
+ // Yes - what kind of request is this?
+ //
+ if(bGetRequest)
+ {
+ //
+ // For a GET request, we send back the first block of data.
+ //
+ psTFTP->ui32BlockNum = 1;
+ TFTPDataSend(psTFTP);
+ }
+ else
+ {
+ //
+ // For a PUT request, we acknowledge the transfer which tells
+ // the TFTP client that it can start sending us data.
+ //
+ psTFTP->ui32BlockNum = 0;
+ TFTPDataAck(psTFTP);
+ }
+ }
+ else
+ {
+ //
+ // The application indicated that there was an error. Send the
+ // error report and close the connection.
+ //
+ TFTPErrorSend(psTFTP, eRetcode);
+ TFTPClose(psTFTP);
+ psTFTP = NULL;
+ }
+ }
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+//! Initializes the TFTP server module.
+//!
+//! \param pfnRequest - A pointer to the function which the server will call
+//! whenever a new incoming TFTP request is received. This function must
+//! determine whether the request can be handled and return a value telling the
+//! server whether to continue processing the request or ignore it.
+//!
+//! This function initializes the lwIP TFTP server and starts listening for
+//! incoming requests from clients. It must be called after the network stack
+//! is initialized using a call to lwIPInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+TFTPInit(tTFTPRequest pfnRequest)
+{
+ void *pcb;
+
+ //
+ // Remember the application's notification callback.
+ //
+ g_pfnRequest = pfnRequest;
+
+ //
+ // Start listening for incoming TFTP requests.
+ //
+ pcb = udp_new();
+ udp_recv(pcb, TFTPRecv, NULL);
+ udp_bind(pcb, IP_ADDR_ANY, TFTP_PORT);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/tftp.h b/utils/tftp.h
new file mode 100644
index 0000000..b02b8ea
--- /dev/null
+++ b/utils/tftp.h
@@ -0,0 +1,215 @@
+//*****************************************************************************
+//
+// tftp.h - Public function prototypes and globals related to the lwIP TFTP
+// server.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __TFTP_H__
+#define __TFTP_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup tftp_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! TFTP error codes. Note that this enum is mapped so that all positive
+//! values match the TFTP protocol-defined error codes.
+//
+//*****************************************************************************
+typedef enum
+{
+ TFTP_OK = -1,
+ TFTP_ERR_NOT_DEFINED = 0,
+ TFTP_FILE_NOT_FOUND = 1,
+ TFTP_ACCESS_VIOLATION = 2,
+ TFTP_DISK_FULL = 3,
+ TFTP_ILLEGAL_OP = 4,
+ TFTP_UNKNOWN_TID = 5,
+ TFTP_FILE_EXISTS = 6,
+ TFTP_NO_SUCH_USER = 7
+}
+tTFTPError;
+
+//*****************************************************************************
+//
+//! TFTP file transfer modes. This enum contains members defining ASCII
+//! text transfer mode (TFTP_MODE_NETASCII), binary transfer mode
+//! (TFTP_MODE_OCTET) and a marker for an invalid mode (TFTP_MODE_INVALID).
+//
+//*****************************************************************************
+typedef enum
+{
+ TFTP_MODE_NETASCII,
+ TFTP_MODE_OCTET,
+ TFTP_MODE_INVALID
+}
+tTFTPMode;
+
+//*****************************************************************************
+//
+//! Data transfer under TFTP is performed using fixed-size blocks. This label
+//! defines the size of a block of TFTP data.
+//
+//*****************************************************************************
+#define TFTP_BLOCK_SIZE 512
+
+//*****************************************************************************
+//
+// Callback function prototypes passed to TFTPInit. These functions receive
+// notification of incoming GET and PUT requests, allowing the client to decide
+// whether to accept the request or not.
+//
+//*****************************************************************************
+struct _tTFTPConnection;
+
+typedef tTFTPError (*tTFTPRequest)(struct _tTFTPConnection *psTFTP, bool bGet,
+ int8_t *pui8FileName, tTFTPMode eMode);
+typedef tTFTPError (*tTFTPTransfer)(struct _tTFTPConnection *psTFTP);
+typedef void (*tTFTPClose)(struct _tTFTPConnection *psTFTP);
+
+//*****************************************************************************
+//
+//! The TFTP connection control structure. This is passed to a client on all
+//! callbacks relating to a given TFTP connection. Depending upon the
+//! callback, the client may need to fill in values to various fields or use
+//! field values to determine where to transfer data from or to.
+//
+//*****************************************************************************
+typedef struct _tTFTPConnection
+{
+ //
+ //! Pointer to the start of the buffer into which GET data should be copied
+ //! or from which PUT data should be read.
+ //
+ uint8_t *pui8Data;
+
+ //
+ //! The length of the data requested in response to a single pfnGetData
+ //! callback or the size of the received data for a pfnPutData callback.
+ //
+ uint32_t ui32DataLength;
+
+ //
+ //! Count of remaining bytes to send during a GET request or the byte
+ //! offset within a block during a PUT request. The application must set
+ //! this field to the size of the requested file during the tTFTPRequest
+ // callback if a GET request is to be accepted.
+ //
+ uint32_t ui32DataRemaining;
+
+ //
+ //! Application function which is called whenever more data is required to
+ //! satisfy a GET request. The function must copy ui32DataLength bytes
+ //! into the buffer pointed to by pui8Data.
+ //
+ tTFTPTransfer pfnGetData;
+
+ //
+ //! Application function which is called whenever a packet of file data is
+ //! received during a PUT request. The function must save the data to the
+ //! target file using ui32BlockNum and ui32DataRemaining to indicate the
+ //! position of the data in the file, and return an appropriate error code.
+ //! Note that several calls to this function may be made for a given
+ //! received TFTP block since the underlying networking stack may have
+ //! split the TFTP packet between several packets and a callback is made
+ //! for each of these. This avoids the need for a 512 byte buffer. The
+ //! ui32DataRemaining is used in these cases to indicate the offset of the
+ //! data within the current block.
+ //
+ tTFTPTransfer pfnPutData;
+
+ //
+ //! Application function which is called when the TFTP connection is to
+ //! be closed. The function should tidy up and free any resources
+ //! associated with the connection prior to returning.
+ //
+ tTFTPClose pfnClose;
+
+ //
+ //! This field may be used by the client to store an application-specific
+ //! pointer that will be accessible on all callbacks from the TFTP module
+ //! relating to this connection.
+ //
+ uint8_t *pui8User;
+
+ //
+ //! Pointer to an error string which the client must fill in if reporting
+ //! an error. This string will be sent to the TFTP client in any case
+ //! where pfnPutData or pfnGetData return a value other than TFTP_OK.
+ //
+ char *pcErrorString;
+
+ //
+ //! A pointer to the underlying UDP connection. Applications must not
+ //! modify this field.
+ //
+ struct udp_pcb *psPCB;
+
+ //
+ //! The current block number for an ongoing TFTP transfer. Applications
+ //! may read this value to determine which data to return on a pfnGetData
+ //! callback or where to write incoming data on a pfnPutData callback but
+ //! must not modify it.
+ //
+ uint32_t ui32BlockNum;
+}
+tTFTPConnection;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public function prototypes.
+//
+//*****************************************************************************
+extern void TFTPInit(tTFTPRequest pfnRequest);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __TFTP_H__
diff --git a/utils/uartstdio.c b/utils/uartstdio.c
new file mode 100644
index 0000000..8ec2eaa
--- /dev/null
+++ b/utils/uartstdio.c
@@ -0,0 +1,1720 @@
+//*****************************************************************************
+//
+// uartstdio.c - Utility driver to provide simple UART console functions.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdarg.h>
+#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 bool g_bDisableEcho;
+
+//*****************************************************************************
+//
+// Output ring buffer. Buffer is full if g_ui32UARTTxReadIndex is one ahead of
+// g_ui32UARTTxWriteIndex. Buffer is empty if the two indices are the same.
+//
+//*****************************************************************************
+static unsigned char g_pcUARTTxBuffer[UART_TX_BUFFER_SIZE];
+static volatile uint32_t g_ui32UARTTxWriteIndex = 0;
+static volatile uint32_t g_ui32UARTTxReadIndex = 0;
+
+//*****************************************************************************
+//
+// Input ring buffer. Buffer is full if g_ui32UARTTxReadIndex is one ahead of
+// g_ui32UARTTxWriteIndex. Buffer is empty if the two indices are the same.
+//
+//*****************************************************************************
+static unsigned char g_pcUARTRxBuffer[UART_RX_BUFFER_SIZE];
+static volatile uint32_t g_ui32UARTRxWriteIndex = 0;
+static volatile uint32_t g_ui32UARTRxReadIndex = 0;
+
+//*****************************************************************************
+//
+// Macros to determine number of free and used bytes in the transmit buffer.
+//
+//*****************************************************************************
+#define TX_BUFFER_USED (GetBufferCount(&g_ui32UARTTxReadIndex, \
+ &g_ui32UARTTxWriteIndex, \
+ UART_TX_BUFFER_SIZE))
+#define TX_BUFFER_FREE (UART_TX_BUFFER_SIZE - TX_BUFFER_USED)
+#define TX_BUFFER_EMPTY (IsBufferEmpty(&g_ui32UARTTxReadIndex, \
+ &g_ui32UARTTxWriteIndex))
+#define TX_BUFFER_FULL (IsBufferFull(&g_ui32UARTTxReadIndex, \
+ &g_ui32UARTTxWriteIndex, \
+ 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_ui32UARTRxReadIndex, \
+ &g_ui32UARTRxWriteIndex, \
+ UART_RX_BUFFER_SIZE))
+#define RX_BUFFER_FREE (UART_RX_BUFFER_SIZE - RX_BUFFER_USED)
+#define RX_BUFFER_EMPTY (IsBufferEmpty(&g_ui32UARTRxReadIndex, \
+ &g_ui32UARTRxWriteIndex))
+#define RX_BUFFER_FULL (IsBufferFull(&g_ui32UARTRxReadIndex, \
+ &g_ui32UARTRxWriteIndex, \
+ 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 uint32_t g_ui32Base = 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 uint32_t g_ui32UARTBase[3] =
+{
+ UART0_BASE, UART1_BASE, UART2_BASE
+};
+
+#ifdef UART_BUFFERED
+//*****************************************************************************
+//
+// The list of possible interrupts for the console UART.
+//
+//*****************************************************************************
+static const uint32_t g_ui32UARTInt[3] =
+{
+ INT_UART0, INT_UART1, INT_UART2
+};
+
+//*****************************************************************************
+//
+// The port number in use.
+//
+//*****************************************************************************
+static uint32_t g_ui32PortNum;
+#endif
+
+//*****************************************************************************
+//
+// The list of UART peripherals.
+//
+//*****************************************************************************
+static const uint32_t g_ui32UARTPeriph[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 pui32Read points to the read index for the buffer.
+//! \param pui32Write points to the write index for the buffer.
+//! \param ui32Size 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 bool
+IsBufferFull(volatile uint32_t *pui32Read,
+ volatile uint32_t *pui32Write, uint32_t ui32Size)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ ui32Write = *pui32Write;
+ ui32Read = *pui32Read;
+
+ return((((ui32Write + 1) % ui32Size) == ui32Read) ? true : false);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Determines whether the ring buffer whose pointers and size are provided
+//! is empty or not.
+//!
+//! \param pui32Read points to the read index for the buffer.
+//! \param pui32Write 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 bool
+IsBufferEmpty(volatile uint32_t *pui32Read,
+ volatile uint32_t *pui32Write)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ ui32Write = *pui32Write;
+ ui32Read = *pui32Read;
+
+ return((ui32Write == ui32Read) ? true : false);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Determines the number of bytes of data contained in a ring buffer.
+//!
+//! \param pui32Read points to the read index for the buffer.
+//! \param pui32Write points to the write index for the buffer.
+//! \param ui32Size 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 uint32_t
+GetBufferCount(volatile uint32_t *pui32Read,
+ volatile uint32_t *pui32Write, uint32_t ui32Size)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ ui32Write = *pui32Write;
+ ui32Read = *pui32Read;
+
+ return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
+ (ui32Size - (ui32Read - ui32Write)));
+}
+#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(uint32_t ui32Base)
+{
+ //
+ // 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_ui32UARTInt[g_ui32PortNum]);
+
+ //
+ // Yes - take some characters out of the transmit buffer and feed
+ // them to the UART transmit FIFO.
+ //
+ while(MAP_UARTSpaceAvail(ui32Base) && !TX_BUFFER_EMPTY)
+ {
+ MAP_UARTCharPutNonBlocking(ui32Base,
+ g_pcUARTTxBuffer[g_ui32UARTTxReadIndex]);
+ ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxReadIndex);
+ }
+
+ //
+ // Reenable the UART interrupt.
+ //
+ MAP_IntEnable(g_ui32UARTInt[g_ui32PortNum]);
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+//! Configures the UART console.
+//!
+//! \param ui32PortNum is the number of UART port to use for the serial console
+//! (0-2)
+//! \param ui32Baud is the bit rate that the UART is to be configured to use.
+//! \param ui32SrcClock is the frequency of the source clock for the UART
+//! module.
+//!
+//! This function will configure the specified serial port to be used as a
+//! serial console. The serial parameters are set to the baud rate
+//! specified by the \e ui32Baud parameter and use 8 bit, no parity, and 1 stop
+//! bit.
+//!
+//! This function must be called prior to using any of the other UART console
+//! functions: UARTprintf() or UARTgets(). This function assumes that the
+//! caller has previously configured the relevant UART pins for operation as a
+//! UART rather than as GPIOs.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UARTStdioConfig(uint32_t ui32PortNum, uint32_t ui32Baud, uint32_t ui32SrcClock)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ui32PortNum == 0) || (ui32PortNum == 1) ||
+ (ui32PortNum == 2));
+
+#ifdef UART_BUFFERED
+ //
+ // In buffered mode, we only allow a single instance to be opened.
+ //
+ ASSERT(g_ui32Base == 0);
+#endif
+
+ //
+ // Check to make sure the UART peripheral is present.
+ //
+ if(!MAP_SysCtlPeripheralPresent(g_ui32UARTPeriph[ui32PortNum]))
+ {
+ return;
+ }
+
+ //
+ // Select the base address of the UART.
+ //
+ g_ui32Base = g_ui32UARTBase[ui32PortNum];
+
+ //
+ // Enable the UART peripheral for use.
+ //
+ MAP_SysCtlPeripheralEnable(g_ui32UARTPeriph[ui32PortNum]);
+
+ //
+ // Configure the UART for 115200, n, 8, 1
+ //
+ MAP_UARTConfigSetExpClk(g_ui32Base, ui32SrcClock, ui32Baud,
+ (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_ui32Base, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
+
+ //
+ // Flush both the buffers.
+ //
+ UARTFlushRx();
+ UARTFlushTx(true);
+
+ //
+ // Remember which interrupt we are dealing with.
+ //
+ g_ui32PortNum = ui32PortNum;
+
+ //
+ // 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_ui32Base, 0xFFFFFFFF);
+ MAP_UARTIntEnable(g_ui32Base, UART_INT_RX | UART_INT_RT);
+ MAP_IntEnable(g_ui32UARTInt[ui32PortNum]);
+#endif
+
+ //
+ // Enable the UART operation.
+ //
+ MAP_UARTEnable(g_ui32Base);
+}
+
+//*****************************************************************************
+//
+//! Writes a string of characters to the UART output.
+//!
+//! \param pcBuf points to a buffer containing the string to transmit.
+//! \param ui32Len 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 ui32Len 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 ui32Len 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, uint32_t ui32Len)
+{
+#ifdef UART_BUFFERED
+ unsigned int uIdx;
+
+ //
+ // Check for valid arguments.
+ //
+ ASSERT(pcBuf != 0);
+ ASSERT(g_ui32Base != 0);
+
+ //
+ // Send the characters
+ //
+ for(uIdx = 0; uIdx < ui32Len; 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_ui32UARTTxWriteIndex] = '\r';
+ ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
+ }
+ else
+ {
+ //
+ // Buffer is full - discard remaining characters and return.
+ //
+ break;
+ }
+ }
+
+ //
+ // Send the character to the UART output.
+ //
+ if(!TX_BUFFER_FULL)
+ {
+ g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = pcBuf[uIdx];
+ ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
+ }
+ 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_ui32Base);
+ MAP_UARTIntEnable(g_ui32Base, 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_ui32Base != 0);
+ ASSERT(pcBuf != 0);
+
+ //
+ // Send the characters
+ //
+ for(uIdx = 0; uIdx < ui32Len; 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_ui32Base, '\r');
+ }
+
+ //
+ // Send the character to the UART output.
+ //
+ MAP_UARTCharPut(g_ui32Base, 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 ui32Len 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, uint32_t ui32Len)
+{
+#ifdef UART_BUFFERED
+ uint32_t ui32Count = 0;
+ int8_t cChar;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pcBuf != 0);
+ ASSERT(ui32Len != 0);
+ ASSERT(g_ui32Base != 0);
+
+ //
+ // Adjust the length back by 1 to leave space for the trailing
+ // null terminator.
+ //
+ ui32Len--;
+
+ //
+ // 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_ui32UARTRxReadIndex];
+ ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex);
+
+ //
+ // 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(ui32Count < ui32Len)
+ {
+ //
+ // Store the character in the caller supplied buffer.
+ //
+ pcBuf[ui32Count] = cChar;
+
+ //
+ // Increment the count of characters received.
+ //
+ ui32Count++;
+ }
+ }
+ }
+
+ //
+ // Add a null termination to the string.
+ //
+ pcBuf[ui32Count] = 0;
+
+ //
+ // Return the count of int8_ts in the buffer, not counting the trailing 0.
+ //
+ return(ui32Count);
+#else
+ uint32_t ui32Count = 0;
+ int8_t cChar;
+ static int8_t bLastWasCR = 0;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pcBuf != 0);
+ ASSERT(ui32Len != 0);
+ ASSERT(g_ui32Base != 0);
+
+ //
+ // Adjust the length back by 1 to leave space for the trailing
+ // null terminator.
+ //
+ ui32Len--;
+
+ //
+ // Process characters until a newline is received.
+ //
+ while(1)
+ {
+ //
+ // Read the next character from the console.
+ //
+ cChar = MAP_UARTCharGet(g_ui32Base);
+
+ //
+ // See if the backspace key was pressed.
+ //
+ if(cChar == '\b')
+ {
+ //
+ // If there are any characters already in the buffer, then delete
+ // the last.
+ //
+ if(ui32Count)
+ {
+ //
+ // Rub out the previous character.
+ //
+ UARTwrite("\b \b", 3);
+
+ //
+ // Decrement the number of characters in the buffer.
+ //
+ ui32Count--;
+ }
+
+ //
+ // 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(ui32Count < ui32Len)
+ {
+ //
+ // Store the character in the caller supplied buffer.
+ //
+ pcBuf[ui32Count] = cChar;
+
+ //
+ // Increment the count of characters received.
+ //
+ ui32Count++;
+
+ //
+ // Reflect the character back to the user.
+ //
+ MAP_UARTCharPut(g_ui32Base, cChar);
+ }
+ }
+
+ //
+ // Add a null termination to the string.
+ //
+ pcBuf[ui32Count] = 0;
+
+ //
+ // Send a CRLF pair to the terminal to end the line.
+ //
+ UARTwrite("\r\n", 2);
+
+ //
+ // Return the count of int8_ts in the buffer, not counting the trailing 0.
+ //
+ return(ui32Count);
+#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_ui32UARTRxReadIndex];
+ ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex);
+
+ //
+ // 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_ui32Base));
+#endif
+}
+
+//*****************************************************************************
+//
+//! A simple UART based vprintf function supporting \%c, \%d, \%p, \%s, \%u,
+//! \%x, and \%X.
+//!
+//! \param pcString is the format string.
+//! \param vaArgP is a variable argument list pointer whose content will depend
+//! upon the format string passed in \e pcString.
+//!
+//! This function is very similar to the C library <tt>vprintf()</tt> function.
+//! All of its output will be sent to the UART. Only the following formatting
+//! characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i 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, \%i, \%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 in the variable arguments list 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
+UARTvprintf(const char *pcString, va_list vaArgP)
+{
+ uint32_t ui32Idx, ui32Value, ui32Pos, ui32Count, ui32Base, ui32Neg;
+ char *pcStr, pcBuf[16], cFill;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pcString != 0);
+
+ //
+ // Loop while there are more characters in the string.
+ //
+ while(*pcString)
+ {
+ //
+ // Find the first non-% character, or the end of the string.
+ //
+ for(ui32Idx = 0;
+ (pcString[ui32Idx] != '%') && (pcString[ui32Idx] != '\0');
+ ui32Idx++)
+ {
+ }
+
+ //
+ // Write this portion of the string.
+ //
+ UARTwrite(pcString, ui32Idx);
+
+ //
+ // Skip the portion of the string that was written.
+ //
+ pcString += ui32Idx;
+
+ //
+ // See if the next character is a %.
+ //
+ if(*pcString == '%')
+ {
+ //
+ // Skip the %.
+ //
+ pcString++;
+
+ //
+ // Set the digit count to zero, and the fill character to space
+ // (in other words, to the defaults).
+ //
+ ui32Count = 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') && (ui32Count == 0))
+ {
+ cFill = '0';
+ }
+
+ //
+ // Update the digit count.
+ //
+ ui32Count *= 10;
+ ui32Count += pcString[-1] - '0';
+
+ //
+ // Get the next character.
+ //
+ goto again;
+ }
+
+ //
+ // Handle the %c command.
+ //
+ case 'c':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ui32Value = va_arg(vaArgP, uint32_t);
+
+ //
+ // Print out the character.
+ //
+ UARTwrite((char *)&ui32Value, 1);
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %d and %i commands.
+ //
+ case 'd':
+ case 'i':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ui32Value = va_arg(vaArgP, uint32_t);
+
+ //
+ // Reset the buffer position.
+ //
+ ui32Pos = 0;
+
+ //
+ // If the value is negative, make it positive and indicate
+ // that a minus sign is needed.
+ //
+ if((int32_t)ui32Value < 0)
+ {
+ //
+ // Make the value positive.
+ //
+ ui32Value = -(int32_t)ui32Value;
+
+ //
+ // Indicate that the value is negative.
+ //
+ ui32Neg = 1;
+ }
+ else
+ {
+ //
+ // Indicate that the value is positive so that a minus
+ // sign isn't inserted.
+ //
+ ui32Neg = 0;
+ }
+
+ //
+ // Set the base to 10.
+ //
+ ui32Base = 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(ui32Idx = 0; pcStr[ui32Idx] != '\0'; ui32Idx++)
+ {
+ }
+
+ //
+ // Write the string.
+ //
+ UARTwrite(pcStr, ui32Idx);
+
+ //
+ // Write any required padding spaces
+ //
+ if(ui32Count > ui32Idx)
+ {
+ ui32Count -= ui32Idx;
+ while(ui32Count--)
+ {
+ UARTwrite(" ", 1);
+ }
+ }
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %u command.
+ //
+ case 'u':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ui32Value = va_arg(vaArgP, uint32_t);
+
+ //
+ // Reset the buffer position.
+ //
+ ui32Pos = 0;
+
+ //
+ // Set the base to 10.
+ //
+ ui32Base = 10;
+
+ //
+ // Indicate that the value is positive so that a minus sign
+ // isn't inserted.
+ //
+ ui32Neg = 0;
+
+ //
+ // Convert the value to ASCII.
+ //
+ goto convert;
+ }
+
+ //
+ // Handle the %x and %X commands. Note that they are treated
+ // identically; in other words, %X will use lower case letters
+ // for a-f instead of the upper case letters it should use. We
+ // also alias %p to %x.
+ //
+ case 'x':
+ case 'X':
+ case 'p':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ui32Value = va_arg(vaArgP, uint32_t);
+
+ //
+ // Reset the buffer position.
+ //
+ ui32Pos = 0;
+
+ //
+ // Set the base to 16.
+ //
+ ui32Base = 16;
+
+ //
+ // Indicate that the value is positive so that a minus sign
+ // isn't inserted.
+ //
+ ui32Neg = 0;
+
+ //
+ // Determine the number of digits in the string version of
+ // the value.
+ //
+convert:
+ for(ui32Idx = 1;
+ (((ui32Idx * ui32Base) <= ui32Value) &&
+ (((ui32Idx * ui32Base) / ui32Base) == ui32Idx));
+ ui32Idx *= ui32Base, ui32Count--)
+ {
+ }
+
+ //
+ // If the value is negative, reduce the count of padding
+ // characters needed.
+ //
+ if(ui32Neg)
+ {
+ ui32Count--;
+ }
+
+ //
+ // If the value is negative and the value is padded with
+ // zeros, then place the minus sign before the padding.
+ //
+ if(ui32Neg && (cFill == '0'))
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ pcBuf[ui32Pos++] = '-';
+
+ //
+ // The minus sign has been placed, so turn off the
+ // negative flag.
+ //
+ ui32Neg = 0;
+ }
+
+ //
+ // Provide additional padding at the beginning of the
+ // string conversion if needed.
+ //
+ if((ui32Count > 1) && (ui32Count < 16))
+ {
+ for(ui32Count--; ui32Count; ui32Count--)
+ {
+ pcBuf[ui32Pos++] = cFill;
+ }
+ }
+
+ //
+ // If the value is negative, then place the minus sign
+ // before the number.
+ //
+ if(ui32Neg)
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ pcBuf[ui32Pos++] = '-';
+ }
+
+ //
+ // Convert the value into a string.
+ //
+ for(; ui32Idx; ui32Idx /= ui32Base)
+ {
+ pcBuf[ui32Pos++] =
+ g_pcHex[(ui32Value / ui32Idx) % ui32Base];
+ }
+
+ //
+ // Write the string.
+ //
+ UARTwrite(pcBuf, ui32Pos);
+
+ //
+ // 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;
+ }
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! 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 <tt>fprintf()</tt> function.
+//! All of its output will be sent to the UART. Only the following formatting
+//! characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i 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, \%i, \%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, ...)
+{
+ va_list vaArgP;
+
+ //
+ // Start the varargs processing.
+ //
+ va_start(vaArgP, pcString);
+
+ UARTvprintf(pcString, vaArgP);
+
+ //
+ // We're finished with the varargs now.
+ //
+ 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;
+ uint32_t ui32ReadIndex;
+
+ //
+ // How many characters are there in the receive buffer?
+ //
+ iAvail = (int)RX_BUFFER_USED;
+ ui32ReadIndex = g_ui32UARTRxReadIndex;
+
+ //
+ // Check all the unread characters looking for the one passed.
+ //
+ for(iCount = 0; iCount < iAvail; iCount++)
+ {
+ if(g_pcUARTRxBuffer[ui32ReadIndex] == 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(ui32ReadIndex);
+ }
+ }
+
+ //
+ // 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)
+{
+ uint32_t ui32Int;
+
+ //
+ // Temporarily turn off interrupts.
+ //
+ ui32Int = MAP_IntMasterDisable();
+
+ //
+ // Flush the receive buffer.
+ //
+ g_ui32UARTRxReadIndex = 0;
+ g_ui32UARTRxWriteIndex = 0;
+
+ //
+ // If interrupts were enabled when we turned them off, turn them
+ // back on again.
+ //
+ if(!ui32Int)
+ {
+ MAP_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(bool bDiscard)
+{
+ uint32_t ui32Int;
+
+ //
+ // Should the remaining data be discarded or transmitted?
+ //
+ if(bDiscard)
+ {
+ //
+ // The remaining data should be discarded, so temporarily turn off
+ // interrupts.
+ //
+ ui32Int = MAP_IntMasterDisable();
+
+ //
+ // Flush the transmit buffer.
+ //
+ g_ui32UARTTxReadIndex = 0;
+ g_ui32UARTTxWriteIndex = 0;
+
+ //
+ // If interrupts were enabled when we turned them off, turn them
+ // back on again.
+ //
+ if(!ui32Int)
+ {
+ MAP_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(bool 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)
+{
+ uint32_t ui32Ints;
+ int8_t cChar;
+ int32_t i32Char;
+ static bool bLastWasCR = false;
+
+ //
+ // Get and clear the current interrupt source(s)
+ //
+ ui32Ints = MAP_UARTIntStatus(g_ui32Base, true);
+ MAP_UARTIntClear(g_ui32Base, ui32Ints);
+
+ //
+ // Are we being interrupted because the TX FIFO has space available?
+ //
+ if(ui32Ints & UART_INT_TX)
+ {
+ //
+ // Move as many bytes as we can into the transmit FIFO.
+ //
+ UARTPrimeTransmit(g_ui32Base);
+
+ //
+ // If the output buffer is empty, turn off the transmit interrupt.
+ //
+ if(TX_BUFFER_EMPTY)
+ {
+ MAP_UARTIntDisable(g_ui32Base, UART_INT_TX);
+ }
+ }
+
+ //
+ // Are we being interrupted due to a received character?
+ //
+ if(ui32Ints & (UART_INT_RX | UART_INT_RT))
+ {
+ //
+ // Get all the available characters from the UART.
+ //
+ while(MAP_UARTCharsAvail(g_ui32Base))
+ {
+ //
+ // Read a character
+ //
+ i32Char = MAP_UARTCharGetNonBlocking(g_ui32Base);
+ cChar = (unsigned char)(i32Char & 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_ui32UARTRxWriteIndex == 0)
+ {
+ g_ui32UARTRxWriteIndex = UART_RX_BUFFER_SIZE - 1;
+ }
+ else
+ {
+ g_ui32UARTRxWriteIndex--;
+ }
+ }
+
+ //
+ // 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_ui32UARTRxWriteIndex] =
+ (unsigned char)(i32Char & 0xFF);
+ ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxWriteIndex);
+
+ //
+ // If echo is enabled, write the character to the transmit
+ // buffer so that the user gets some immediate feedback.
+ //
+ if(!g_bDisableEcho)
+ {
+ UARTwrite((const char *)&cChar, 1);
+ }
+ }
+ }
+
+ //
+ // If we wrote anything to the transmit buffer, make sure it actually
+ // gets transmitted.
+ //
+ UARTPrimeTransmit(g_ui32Base);
+ MAP_UARTIntEnable(g_ui32Base, UART_INT_TX);
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/uartstdio.h b/utils/uartstdio.h
new file mode 100644
index 0000000..fbadabc
--- /dev/null
+++ b/utils/uartstdio.h
@@ -0,0 +1,86 @@
+//*****************************************************************************
+//
+// uartstdio.h - Prototypes for the UART console functions.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __UARTSTDIO_H__
+#define __UARTSTDIO_H__
+
+#include <stdarg.h>
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// If built for buffered operation, the following labels define the sizes of
+// the transmit and receive buffers respectively.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+#ifndef UART_RX_BUFFER_SIZE
+#define UART_RX_BUFFER_SIZE 128
+#endif
+#ifndef UART_TX_BUFFER_SIZE
+#define UART_TX_BUFFER_SIZE 1024
+#endif
+#endif
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern void UARTStdioConfig(uint32_t ui32Port, uint32_t ui32Baud,
+ uint32_t ui32SrcClock);
+extern int UARTgets(char *pcBuf, uint32_t ui32Len);
+extern unsigned char UARTgetc(void);
+extern void UARTprintf(const char *pcString, ...);
+extern void UARTvprintf(const char *pcString, va_list vaArgP);
+extern int UARTwrite(const char *pcBuf, uint32_t ui32Len);
+#ifdef UART_BUFFERED
+extern int UARTPeek(unsigned char ucChar);
+extern void UARTFlushTx(bool bDiscard);
+extern void UARTFlushRx(void);
+extern int UARTRxBytesAvail(void);
+extern int UARTTxBytesFree(void);
+extern void UARTEchoSet(bool bEnable);
+#endif
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __UARTSTDIO_H__
diff --git a/utils/ustdlib.c b/utils/ustdlib.c
new file mode 100644
index 0000000..0fa6f05
--- /dev/null
+++ b/utils/ustdlib.c
@@ -0,0 +1,1826 @@
+//*****************************************************************************
+//
+// ustdlib.c - Simple standard library functions.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "driverlib/debug.h"
+#include "utils/ustdlib.h"
+
+//*****************************************************************************
+//
+//! \addtogroup ustdlib_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// A mapping from an integer between 0 and 15 to its ASCII character
+// equivalent.
+//
+//*****************************************************************************
+static const char * const g_pcHex = "0123456789abcdef";
+
+//*****************************************************************************
+//
+//! Copies a certain number of characters from one string to another.
+//!
+//! \param s1 is a pointer to the destination buffer into which characters
+//! are to be copied.
+//! \param s2 is a pointer to the string from which characters are to be
+//! copied.
+//! \param n is the number of characters to copy to the destination buffer.
+//!
+//! This function copies at most \e n characters from the string pointed to
+//! by \e s2 into the buffer pointed to by \e s1. If the end of \e s2 is found
+//! before \e n characters have been copied, remaining characters in \e s1
+//! will be padded with zeroes until \e n characters have been written. Note
+//! that the destination string will only be NULL terminated if the number of
+//! characters to be copied is greater than the length of \e s2.
+//!
+//! \return Returns \e s1.
+//
+//*****************************************************************************
+char *
+ustrncpy(char * restrict s1, const char * restrict s2, size_t n)
+{
+ size_t count;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(s1);
+ ASSERT(s2);
+
+ //
+ // Start at the beginning of the source string.
+ //
+ count = 0;
+
+ //
+ // Copy the source string until we run out of source characters or
+ // destination space.
+ //
+ while(n && s2[count])
+ {
+ s1[count] = s2[count];
+ count++;
+ n--;
+ }
+
+ //
+ // Pad the destination if we are not yet done.
+ //
+ while(n)
+ {
+ s1[count++] = (char)0;
+ n--;
+ }
+
+ //
+ // Pass the destination pointer back to the caller.
+ //
+ return(s1);
+}
+
+//*****************************************************************************
+//
+//! A simple vsnprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and
+//! \%X.
+//!
+//! \param s points to the buffer where the converted string is stored.
+//! \param n is the size of the buffer.
+//! \param format is the format string.
+//! \param arg is the list of optional arguments, which depend on the
+//! contents of the format string.
+//!
+//! This function is very similar to the C library <tt>vsnprintf()</tt>
+//! function. Only the following formatting characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i 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 \%d, \%i, \%p, \%s, \%u, \%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 format 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.
+//!
+//! The \e n parameter limits the number of characters that will be
+//! stored in the buffer pointed to by \e s to prevent the possibility of
+//! a buffer overflow. The buffer size should be large enough to hold the
+//! expected converted output string, including the null termination character.
+//!
+//! The function will return the number of characters that would be converted
+//! as if there were no limit on the buffer size. Therefore it is possible for
+//! the function to return a count that is greater than the specified buffer
+//! size. If this happens, it means that the output was truncated.
+//!
+//! \return Returns the number of characters that were to be stored, not
+//! including the NULL termination character, regardless of space in the
+//! buffer.
+//
+//*****************************************************************************
+int
+uvsnprintf(char * restrict s, size_t n, const char * restrict format,
+ va_list arg)
+{
+ unsigned long ulIdx, ulValue, ulCount, ulBase, ulNeg;
+ char *pcStr, cFill;
+ int iConvertCount = 0;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(s);
+ ASSERT(n);
+ ASSERT(format);
+
+ //
+ // Adjust buffer size limit to allow one space for null termination.
+ //
+ if(n)
+ {
+ n--;
+ }
+
+ //
+ // Initialize the count of characters converted.
+ //
+ iConvertCount = 0;
+
+ //
+ // Loop while there are more characters in the format string.
+ //
+ while(*format)
+ {
+ //
+ // Find the first non-% character, or the end of the string.
+ //
+ for(ulIdx = 0; (format[ulIdx] != '%') && (format[ulIdx] != '\0');
+ ulIdx++)
+ {
+ }
+
+ //
+ // Write this portion of the string to the output buffer. If there are
+ // more characters to write than there is space in the buffer, then
+ // only write as much as will fit in the buffer.
+ //
+ if(ulIdx > n)
+ {
+ ustrncpy(s, format, n);
+ s += n;
+ n = 0;
+ }
+ else
+ {
+ ustrncpy(s, format, ulIdx);
+ s += ulIdx;
+ n -= ulIdx;
+ }
+
+ //
+ // Update the conversion count. This will be the number of characters
+ // that should have been written, even if there was not room in the
+ // buffer.
+ //
+ iConvertCount += ulIdx;
+
+ //
+ // Skip the portion of the format string that was written.
+ //
+ format += ulIdx;
+
+ //
+ // See if the next character is a %.
+ //
+ if(*format == '%')
+ {
+ //
+ // Skip the %.
+ //
+ format++;
+
+ //
+ // Set the digit count to zero, and the fill character to space
+ // (that is, 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(*format++)
+ {
+ //
+ // 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((format[-1] == '0') && (ulCount == 0))
+ {
+ cFill = '0';
+ }
+
+ //
+ // Update the digit count.
+ //
+ ulCount *= 10;
+ ulCount += format[-1] - '0';
+
+ //
+ // Get the next character.
+ //
+ goto again;
+ }
+
+ //
+ // Handle the %c command.
+ //
+ case 'c':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(arg, unsigned long);
+
+ //
+ // Copy the character to the output buffer, if there is
+ // room. Update the buffer size remaining.
+ //
+ if(n != 0)
+ {
+ *s++ = (char)ulValue;
+ n--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %d and %i commands.
+ //
+ case 'd':
+ case 'i':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(arg, unsigned long);
+
+ //
+ // 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
+ // negative 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(arg, char *);
+
+ //
+ // Determine the length of the string.
+ //
+ for(ulIdx = 0; pcStr[ulIdx] != '\0'; ulIdx++)
+ {
+ }
+
+ //
+ // Update the convert count to include any padding that
+ // should be necessary (regardless of whether we have space
+ // to write it or not).
+ //
+ if(ulCount > ulIdx)
+ {
+ iConvertCount += (ulCount - ulIdx);
+ }
+
+ //
+ // Copy the string to the output buffer. Only copy as much
+ // as will fit in the buffer. Update the output buffer
+ // pointer and the space remaining.
+ //
+ if(ulIdx > n)
+ {
+ ustrncpy(s, pcStr, n);
+ s += n;
+ n = 0;
+ }
+ else
+ {
+ ustrncpy(s, pcStr, ulIdx);
+ s += ulIdx;
+ n -= ulIdx;
+
+ //
+ // Write any required padding spaces assuming there is
+ // still space in the buffer.
+ //
+ if(ulCount > ulIdx)
+ {
+ ulCount -= ulIdx;
+ if(ulCount > n)
+ {
+ ulCount = n;
+ }
+ n = -ulCount;
+
+ while(ulCount--)
+ {
+ *s++ = ' ';
+ }
+ }
+ }
+
+ //
+ // Update the conversion count. This will be the number of
+ // characters that should have been written, even if there
+ // was not room in the buffer.
+ //
+ iConvertCount += ulIdx;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %u command.
+ //
+ case 'u':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(arg, unsigned long);
+
+ //
+ // 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; that is, %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(arg, unsigned long);
+
+ //
+ // 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 && (n != 0) && (cFill == '0'))
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ *s++ = '-';
+ n--;
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+
+ //
+ // The minus sign has been placed, so turn off the
+ // negative flag.
+ //
+ ulNeg = 0;
+ }
+
+ //
+ // See if there are more characters in the specified field
+ // width than there are in the conversion of this value.
+ //
+ if((ulCount > 1) && (ulCount < 65536))
+ {
+ //
+ // Loop through the required padding characters.
+ //
+ for(ulCount--; ulCount; ulCount--)
+ {
+ //
+ // Copy the character to the output buffer if there
+ // is room.
+ //
+ if(n != 0)
+ {
+ *s++ = cFill;
+ n--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+ }
+ }
+
+ //
+ // If the value is negative, then place the minus sign
+ // before the number.
+ //
+ if(ulNeg && (n != 0))
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ *s++ = '-';
+ n--;
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+ }
+
+ //
+ // Convert the value into a string.
+ //
+ for(; ulIdx; ulIdx /= ulBase)
+ {
+ //
+ // Copy the character to the output buffer if there is
+ // room.
+ //
+ if(n != 0)
+ {
+ *s++ = g_pcHex[(ulValue / ulIdx) % ulBase];
+ n--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+ }
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %% command.
+ //
+ case '%':
+ {
+ //
+ // Simply write a single %.
+ //
+ if(n != 0)
+ {
+ *s++ = format[-1];
+ n--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle all other commands.
+ //
+ default:
+ {
+ //
+ // Indicate an error.
+ //
+ if(n >= 5)
+ {
+ ustrncpy(s, "ERROR", 5);
+ s += 5;
+ n -= 5;
+ }
+ else
+ {
+ ustrncpy(s, "ERROR", n);
+ s += n;
+ n = 0;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount += 5;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Null terminate the string in the buffer.
+ //
+ *s = 0;
+
+ //
+ // Return the number of characters in the full converted string.
+ //
+ return(iConvertCount);
+}
+
+//*****************************************************************************
+//
+//! A simple sprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and \%X.
+//!
+//! \param s is the buffer where the converted string is stored.
+//! \param format 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 <tt>sprintf()</tt> function.
+//! Only the following formatting characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i 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 \%d, \%i, \%p, \%s, \%u, \%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 zeros instead of spaces.
+//!
+//! The type of the arguments after \e format 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.
+//!
+//! The caller must ensure that the buffer \e s is large enough to hold the
+//! entire converted string, including the null termination character.
+//!
+//! \return Returns the count of characters that were written to the output
+//! buffer, not including the NULL termination character.
+//
+//*****************************************************************************
+int
+usprintf(char * restrict s, const char *format, ...)
+{
+ va_list arg;
+ int ret;
+
+ //
+ // Start the varargs processing.
+ //
+ va_start(arg, format);
+
+ //
+ // Call vsnprintf to perform the conversion. Use a large number for the
+ // buffer size.
+ //
+ ret = uvsnprintf(s, 0xffff, format, arg);
+
+ //
+ // End the varargs processing.
+ //
+ va_end(arg);
+
+ //
+ // Return the conversion count.
+ //
+ return(ret);
+}
+
+//*****************************************************************************
+//
+//! A simple snprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and
+//! \%X.
+//!
+//! \param s is the buffer where the converted string is stored.
+//! \param n is the size of the buffer.
+//! \param format 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 <tt>sprintf()</tt> function.
+//! Only the following formatting characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i 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 \%d, \%i, \%p, \%s, \%u, \%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 zeros instead of spaces.
+//!
+//! The type of the arguments after \e format 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.
+//!
+//! The function will copy at most \e n - 1 characters into the buffer
+//! \e s. One space is reserved in the buffer for the null termination
+//! character.
+//!
+//! The function will return the number of characters that would be converted
+//! as if there were no limit on the buffer size. Therefore it is possible for
+//! the function to return a count that is greater than the specified buffer
+//! size. If this happens, it means that the output was truncated.
+//!
+//! \return Returns the number of characters that were to be stored, not
+//! including the NULL termination character, regardless of space in the
+//! buffer.
+//
+//*****************************************************************************
+int
+usnprintf(char * restrict s, size_t n, const char * restrict format, ...)
+{
+ va_list arg;
+ int ret;
+
+ //
+ // Start the varargs processing.
+ //
+ va_start(arg, format);
+
+ //
+ // Call vsnprintf to perform the conversion.
+ //
+ ret = uvsnprintf(s, n, format, arg);
+
+ //
+ // End the varargs processing.
+ //
+ va_end(arg);
+
+ //
+ // Return the conversion count.
+ //
+ return(ret);
+}
+
+//*****************************************************************************
+//
+// This array contains the number of days in a year at the beginning of each
+// month of the year, in a non-leap year.
+//
+//*****************************************************************************
+static const time_t g_psDaysToMonth[12] =
+{
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+};
+
+//*****************************************************************************
+//
+//! Converts from seconds to calendar date and time.
+//!
+//! \param timer is the number of seconds.
+//! \param tm is a pointer to the time structure that is filled in with the
+//! broken down date and time.
+//!
+//! This function converts a number of seconds since midnight GMT on January 1,
+//! 1970 (traditional Unix epoch) into the equivalent month, day, year, hours,
+//! minutes, and seconds representation.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ulocaltime(time_t timer, struct tm *tm)
+{
+ time_t temp, months;
+
+ //
+ // Extract the number of seconds, converting time to the number of minutes.
+ //
+ temp = timer / 60;
+ tm->tm_sec = timer - (temp * 60);
+ timer = temp;
+
+ //
+ // Extract the number of minutes, converting time to the number of hours.
+ //
+ temp = timer / 60;
+ tm->tm_min = timer - (temp * 60);
+ timer = temp;
+
+ //
+ // Extract the number of hours, converting time to the number of days.
+ //
+ temp = timer / 24;
+ tm->tm_hour = timer - (temp * 24);
+ timer = temp;
+
+ //
+ // Compute the day of the week.
+ //
+ tm->tm_wday = (timer + 4) % 7;
+
+ //
+ // Compute the number of leap years that have occurred since 1968, the
+ // first leap year before 1970. For the beginning of a leap year, cut the
+ // month loop below at March so that the leap day is classified as February
+ // 29 followed by March 1, instead of March 1 followed by another March 1.
+ //
+ timer += 366 + 365;
+ temp = timer / ((4 * 365) + 1);
+ if((timer - (temp * ((4 * 365) + 1))) > (31 + 28))
+ {
+ temp++;
+ months = 12;
+ }
+ else
+ {
+ months = 2;
+ }
+
+ //
+ // Extract the year.
+ //
+ tm->tm_year = ((timer - temp) / 365) + 68;
+ timer -= ((tm->tm_year - 68) * 365) + temp;
+
+ //
+ // Extract the month.
+ //
+ for(temp = 0; temp < months; temp++)
+ {
+ if(g_psDaysToMonth[temp] > timer)
+ {
+ break;
+ }
+ }
+ tm->tm_mon = temp - 1;
+
+ //
+ // Extract the day of the month.
+ //
+ tm->tm_mday = timer - g_psDaysToMonth[temp - 1] + 1;
+}
+
+//*****************************************************************************
+//
+//! Compares two time structures and determines if one is greater than,
+//! less than, or equal to the other.
+//!
+//! \param t1 is the first time structure to compare.
+//! \param t2 is the second time structure to compare.
+//!
+//! This function compares two time structures and returns a signed number
+//! to indicate the result of the comparison. If the time represented by
+//! \e t1 is greater than the time represented by \e t2 then a positive
+//! number is returned. Likewise if \e t1 is less than \e t2 then a
+//! negative number is returned. If the two times are equal then the function
+//! returns 0.
+//!
+//! \return Returns 0 if the two times are equal, +1 if \e t1 is greater
+//! than \e t2, and -1 if \e t1 is less than \e t2.
+//
+//*****************************************************************************
+static int
+ucmptime(struct tm *t1, struct tm *t2)
+{
+ //
+ // Compare each field in descending signficance to determine if
+ // greater than, less than, or equal.
+ //
+ if(t1->tm_year > t2->tm_year)
+ {
+ return(1);
+ }
+ else if(t1->tm_year < t2->tm_year)
+ {
+ return(-1);
+ }
+ else if(t1->tm_mon > t2->tm_mon)
+ {
+ return(1);
+ }
+ else if(t1->tm_mon < t2->tm_mon)
+ {
+ return(-1);
+ }
+ else if(t1->tm_mday > t2->tm_mday)
+ {
+ return(1);
+ }
+ else if(t1->tm_mday < t2->tm_mday)
+ {
+ return(-1);
+ }
+ else if(t1->tm_hour > t2->tm_hour)
+ {
+ return(1);
+ }
+ else if(t1->tm_hour < t2->tm_hour)
+ {
+ return(-1);
+ }
+ else if(t1->tm_min > t2->tm_min)
+ {
+ return(1);
+ }
+ else if(t1->tm_min < t2->tm_min)
+ {
+ return(-1);
+ }
+ else if(t1->tm_sec > t2->tm_sec)
+ {
+ return(1);
+ }
+ else if(t1->tm_sec < t2->tm_sec)
+ {
+ return(-1);
+ }
+ else
+ {
+ //
+ // Reaching this branch of the conditional means that all of the
+ // fields are equal, and thus the two times are equal.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Converts calendar date and time to seconds.
+//!
+//! \param timeptr is a pointer to the time structure that is filled in with
+//! the broken down date and time.
+//!
+//! This function converts the date and time represented by the \e timeptr
+//! structure pointer to the number of seconds since midnight GMT on January 1,
+//! 1970 (traditional Unix epoch).
+//!
+//! \return Returns the calendar time and date as seconds. If the conversion
+//! was not possible then the function returns (uint32_t)(-1).
+//
+//*****************************************************************************
+time_t
+umktime(struct tm *timeptr)
+{
+ struct tm sTimeGuess;
+ unsigned long ulTimeGuess = 0x80000000;
+ unsigned long ulAdjust = 0x40000000;
+ int iSign;
+
+ //
+ // Seed the binary search with the first guess.
+ //
+ ulocaltime(ulTimeGuess, &sTimeGuess);
+ iSign = ucmptime(timeptr, &sTimeGuess);
+
+ //
+ // While the time is not yet found, execute a binary search.
+ //
+ while(iSign && ulAdjust)
+ {
+ //
+ // Adjust the time guess up or down depending on the result of the
+ // last compare.
+ //
+ ulTimeGuess = ((iSign > 0) ? (ulTimeGuess + ulAdjust) :
+ (ulTimeGuess - ulAdjust));
+ ulAdjust /= 2;
+
+ //
+ // Compare the new time guess against the time pointed at by the
+ // function parameters.
+ //
+ ulocaltime(ulTimeGuess, &sTimeGuess);
+ iSign = ucmptime(timeptr, &sTimeGuess);
+ }
+
+ //
+ // If the above loop was exited with iSign == 0, that means that the
+ // time in seconds was found, so return that value to the caller.
+ //
+ if(iSign == 0)
+ {
+ return(ulTimeGuess);
+ }
+
+ //
+ // Otherwise the time could not be converted so return an error.
+ //
+ else
+ {
+ return((unsigned long)-1);
+ }
+}
+
+//*****************************************************************************
+//
+//! Converts a string into its numeric equivalent.
+//!
+//! \param nptr is a pointer to the string containing the integer.
+//! \param endptr is a pointer that will be set to the first character past
+//! the integer in the string.
+//! \param base is the radix to use for the conversion; can be zero to
+//! auto-select the radix or between 2 and 16 to explicitly specify the radix.
+//!
+//! This function is very similar to the C library <tt>strtoul()</tt> function.
+//! It scans a string for the first token (that is, non-white space) and
+//! converts the value at that location in the string into an integer value.
+//!
+//! \return Returns the result of the conversion.
+//
+//*****************************************************************************
+unsigned long
+ustrtoul(const char * restrict nptr, const char ** restrict endptr, int base)
+{
+ unsigned long ulRet, ulDigit, ulNeg, ulValid;
+ const char *pcPtr;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(nptr);
+ ASSERT((base == 0) || ((base > 1) && (base <= 16)));
+
+ //
+ // Initially, the result is zero.
+ //
+ ulRet = 0;
+ ulNeg = 0;
+ ulValid = 0;
+
+ //
+ // Skip past any leading white space.
+ //
+ pcPtr = nptr;
+ while((*pcPtr == ' ') || (*pcPtr == '\t'))
+ {
+ pcPtr++;
+ }
+
+ //
+ // Take a leading + or - from the value.
+ //
+ if(*pcPtr == '-')
+ {
+ ulNeg = 1;
+ pcPtr++;
+ }
+ else if(*pcPtr == '+')
+ {
+ pcPtr++;
+ }
+
+ //
+ // See if the radix was not specified, or is 16, and the value starts with
+ // "0x" or "0X" (to indicate a hex value).
+ //
+ if(((base == 0) || (base == 16)) && (*pcPtr == '0') &&
+ ((pcPtr[1] == 'x') || (pcPtr[1] == 'X')))
+ {
+ //
+ // Skip the leading "0x".
+ //
+ pcPtr += 2;
+
+ //
+ // Set the radix to 16.
+ //
+ base = 16;
+ }
+
+ //
+ // See if the radix was not specified.
+ //
+ if(base == 0)
+ {
+ //
+ // See if the value starts with "0".
+ //
+ if(*pcPtr == '0')
+ {
+ //
+ // Values that start with "0" are assumed to be radix 8.
+ //
+ base = 8;
+ }
+ else
+ {
+ //
+ // Otherwise, the values are assumed to be radix 10.
+ //
+ base = 10;
+ }
+ }
+
+ //
+ // Loop while there are more valid digits to consume.
+ //
+ while(1)
+ {
+ //
+ // See if this character is a number.
+ //
+ if((*pcPtr >= '0') && (*pcPtr <= '9'))
+ {
+ //
+ // Convert the character to its integer equivalent.
+ //
+ ulDigit = *pcPtr++ - '0';
+ }
+
+ //
+ // Otherwise, see if this character is an upper case letter.
+ //
+ else if((*pcPtr >= 'A') && (*pcPtr <= 'Z'))
+ {
+ //
+ // Convert the character to its integer equivalent.
+ //
+ ulDigit = *pcPtr++ - 'A' + 10;
+ }
+
+ //
+ // Otherwise, see if this character is a lower case letter.
+ //
+ else if((*pcPtr >= 'a') && (*pcPtr <= 'z'))
+ {
+ //
+ // Convert the character to its integer equivalent.
+ //
+ ulDigit = *pcPtr++ - 'a' + 10;
+ }
+
+ //
+ // Otherwise, this is not a valid character.
+ //
+ else
+ {
+ //
+ // Stop converting this value.
+ //
+ break;
+ }
+
+ //
+ // See if this digit is valid for the chosen radix.
+ //
+ if(ulDigit >= base)
+ {
+ //
+ // Since this was not a valid digit, move the pointer back to the
+ // character that therefore should not have been consumed.
+ //
+ pcPtr--;
+
+ //
+ // Stop converting this value.
+ //
+ break;
+ }
+
+ //
+ // Add this digit to the converted value.
+ //
+ ulRet *= base;
+ ulRet += ulDigit;
+
+ //
+ // Since a digit has been added, this is now a valid result.
+ //
+ ulValid = 1;
+ }
+
+ //
+ // Set the return string pointer to the first character not consumed.
+ //
+ if(endptr)
+ {
+ *endptr = ulValid ? pcPtr : nptr;
+ }
+
+ //
+ // Return the converted value.
+ //
+ return(ulNeg ? (0 - ulRet) : ulRet);
+}
+
+//*****************************************************************************
+//
+// An array of the value of ten raised to the power-of-two exponents. This is
+// used for converting the decimal exponent into the floating-point value of
+// 10^exp.
+//
+//*****************************************************************************
+static const float g_pfExponents[] =
+{
+ 1.0e+01,
+ 1.0e+02,
+ 1.0e+04,
+ 1.0e+08,
+ 1.0e+16,
+ 1.0e+32,
+};
+
+//*****************************************************************************
+//
+//! Converts a string into its floating-point equivalent.
+//!
+//! \param nptr is a pointer to the string containing the floating-point
+//! value.
+//! \param endptr is a pointer that will be set to the first character past
+//! the floating-point value in the string.
+//!
+//! This function is very similar to the C library <tt>strtof()</tt> function.
+//! It scans a string for the first token (that is, non-white space) and
+//! converts the value at that location in the string into a floating-point
+//! value.
+//!
+//! \return Returns the result of the conversion.
+//
+//*****************************************************************************
+float
+ustrtof(const char *nptr, const char **endptr)
+{
+ unsigned long ulNeg, ulExp, ulExpNeg, ulValid, ulIdx;
+ float fRet, fDigit, fExp;
+ const char *pcPtr;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(nptr);
+
+ //
+ // Initially, the result is zero.
+ //
+ fRet = 0;
+ ulNeg = 0;
+ ulValid = 0;
+
+ //
+ // Skip past any leading white space.
+ //
+ pcPtr = nptr;
+ while((*pcPtr == ' ') || (*pcPtr == '\t'))
+ {
+ pcPtr++;
+ }
+
+ //
+ // Take a leading + or - from the value.
+ //
+ if(*pcPtr == '-')
+ {
+ ulNeg = 1;
+ pcPtr++;
+ }
+ else if(*pcPtr == '+')
+ {
+ pcPtr++;
+ }
+
+ //
+ // Loop while there are valid digits to consume.
+ //
+ while((*pcPtr >= '0') && (*pcPtr <= '9'))
+ {
+ //
+ // Add this digit to the converted value.
+ //
+ fRet *= 10;
+ fRet += *pcPtr++ - '0';
+
+ //
+ // Since a digit has been added, this is now a valid result.
+ //
+ ulValid = 1;
+ }
+
+ //
+ // See if the next character is a period and the character after that is a
+ // digit, indicating the start of the fractional portion of the value.
+ //
+ if((*pcPtr == '.') && (pcPtr[1] >= '0') && (pcPtr[1] <= '9'))
+ {
+ //
+ // Skip the period.
+ //
+ pcPtr++;
+
+ //
+ // Loop while there are valid fractional digits to consume.
+ //
+ fDigit = 0.1;
+ while((*pcPtr >= '0') && (*pcPtr <= '9'))
+ {
+ //
+ // Add this digit to the converted value.
+ //
+ fRet += (*pcPtr++ - '0') * fDigit;
+ fDigit /= (float)10.0;
+
+ //
+ // Since a digit has been added, this is now a valid result.
+ //
+ ulValid = 1;
+ }
+ }
+
+ //
+ // See if the next character is an "e" and a valid number has been
+ // converted, indicating the start of the exponent.
+ //
+ if(((pcPtr[0] == 'e') || (pcPtr[0] == 'E')) && (ulValid == 1) &&
+ (((pcPtr[1] >= '0') && (pcPtr[1] <= '9')) ||
+ (((pcPtr[1] == '+') || (pcPtr[1] == '-')) &&
+ (pcPtr[2] >= '0') && (pcPtr[2] <= '9'))))
+ {
+ //
+ // Skip the "e".
+ //
+ pcPtr++;
+
+ //
+ // Take a leading + or - from the exponenet.
+ //
+ ulExpNeg = 0;
+ if(*pcPtr == '-')
+ {
+ ulExpNeg = 1;
+ pcPtr++;
+ }
+ else if(*pcPtr == '+')
+ {
+ pcPtr++;
+ }
+
+ //
+ // Loop while there are valid digits in the exponent.
+ //
+ ulExp = 0;
+ while((*pcPtr >= '0') && (*pcPtr <= '9'))
+ {
+ //
+ // Add this digit to the converted value.
+ //
+ ulExp *= 10;
+ ulExp += *pcPtr++ - '0';
+ }
+
+ //
+ // Raise ten to the power of the exponent. Do this via binary
+ // decomposition; for each binary bit set in the exponent, multiply the
+ // floating-point representation by ten raised to that binary value
+ // (extracted from the table above).
+ //
+ fExp = 1;
+ for(ulIdx = 0; ulIdx < 7; ulIdx++)
+ {
+ if(ulExp & (1 << ulIdx))
+ {
+ fExp *= g_pfExponents[ulIdx];
+ }
+ }
+
+ //
+ // If the exponent is negative, then the exponent needs to be inverted.
+ //
+ if(ulExpNeg == 1)
+ {
+ fExp = 1 / fExp;
+ }
+
+ //
+ // Multiply the result by the computed exponent value.
+ //
+ fRet *= fExp;
+ }
+
+ //
+ // Set the return string pointer to the first character not consumed.
+ //
+ if(endptr)
+ {
+ *endptr = ulValid ? pcPtr : nptr;
+ }
+
+ //
+ // Return the converted value.
+ //
+ return(ulNeg ? (0 - fRet) : fRet);
+}
+
+//*****************************************************************************
+//
+//! Returns the length of a null-terminated string.
+//!
+//! \param s is a pointer to the string whose length is to be found.
+//!
+//! This function is very similar to the C library <tt>strlen()</tt> function.
+//! It determines the length of the null-terminated string passed and returns
+//! this to the caller.
+//!
+//! This implementation assumes that single byte character strings are passed
+//! and will return incorrect values if passed some UTF-8 strings.
+//!
+//! \return Returns the length of the string pointed to by \e s.
+//
+//*****************************************************************************
+size_t
+ustrlen(const char *s)
+{
+ size_t len;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(s);
+
+ //
+ // Initialize the length.
+ //
+ len = 0;
+
+ //
+ // Step throug the string looking for a zero character (marking its end).
+ //
+ while(s[len])
+ {
+ //
+ // Zero not found so move on to the next character.
+ //
+ len++;
+ }
+
+ return(len);
+}
+
+//*****************************************************************************
+//
+//! Finds a substring within a string.
+//!
+//! \param s1 is a pointer to the string that will be searched.
+//! \param s2 is a pointer to the substring that is to be found within
+//! \e s1.
+//!
+//! This function is very similar to the C library <tt>strstr()</tt> function.
+//! It scans a string for the first instance of a given substring and returns
+//! a pointer to that substring. If the substring cannot be found, a NULL
+//! pointer is returned.
+//!
+//! \return Returns a pointer to the first occurrence of \e s2 within
+//! \e s1 or NULL if no match is found.
+//
+//*****************************************************************************
+char *
+ustrstr(const char *s1, const char *s2)
+{
+ size_t n;
+
+ //
+ // Get the length of the string to be found.
+ //
+ n = ustrlen(s2);
+
+ //
+ // Loop while we have not reached the end of the string.
+ //
+ while(*s1)
+ {
+ //
+ // Check to see if the substring appears at this position.
+ //
+ if(ustrncmp(s2, s1, n) == 0)
+ {
+ //
+ // It does so return the pointer.
+ //
+ return((char *)s1);
+ }
+
+ //
+ // Move to the next position in the string being searched.
+ //
+ s1++;
+ }
+
+ //
+ // We reached the end of the string without finding the substring so
+ // return NULL.
+ //
+ return((char *)0);
+}
+
+//*****************************************************************************
+//
+//! Compares two strings without regard to case.
+//!
+//! \param s1 points to the first string to be compared.
+//! \param s2 points to the second string to be compared.
+//! \param n is the maximum number of characters to compare.
+//!
+//! This function is very similar to the C library <tt>strncasecmp()</tt>
+//! function. It compares at most \e n characters of two strings without
+//! regard to case. The comparison ends if a terminating NULL character is
+//! found in either string before \e n characters are compared. In this case,
+//! the shorter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
+//! than \e s2 and 1 if \e s1 is greater than \e s2.
+//
+//*****************************************************************************
+int
+ustrncasecmp(const char *s1, const char *s2, size_t n)
+{
+ char c1, c2;
+
+ //
+ // Loop while there are more characters to compare.
+ //
+ while(n)
+ {
+ //
+ // If we reached a NULL in both strings, they must be equal so
+ // we end the comparison and return 0
+ //
+ if(!*s1 && !*s2)
+ {
+ return(0);
+ }
+
+ //
+ // Lower case the characters at the current position before we compare.
+ //
+ c1 = (((*s1 >= 'A') && (*s1 <= 'Z')) ? (*s1 + ('a' - 'A')) : *s1);
+ c2 = (((*s2 >= 'A') && (*s2 <= 'Z')) ? (*s2 + ('a' - 'A')) : *s2);
+
+ //
+ // Compare the two characters and, if different, return the relevant
+ // return code.
+ //
+ if(c2 < c1)
+ {
+ return(1);
+ }
+ if(c1 < c2)
+ {
+ return(-1);
+ }
+
+ //
+ // Move on to the next character.
+ //
+ s1++;
+ s2++;
+ n--;
+ }
+
+ //
+ // If we fall out, the strings must be equal for at least the first n
+ // characters so return 0 to indicate this.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Compares two strings without regard to case.
+//!
+//! \param s1 points to the first string to be compared.
+//! \param s2 points to the second string to be compared.
+//!
+//! This function is very similar to the C library <tt>strcasecmp()</tt>
+//! function. It compares two strings without regard to case. The comparison
+//! ends if a terminating NULL character is found in either string. In this
+//! case, the int16_ter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
+//! than \e s2 and 1 if \e s1 is greater than \e s2.
+//
+//*****************************************************************************
+int
+ustrcasecmp(const char *s1, const char *s2)
+{
+ //
+ // Just let ustrncasecmp() handle this.
+ //
+ return(ustrncasecmp(s1, s2, (size_t)-1));
+}
+
+//*****************************************************************************
+//
+//! Compares two strings.
+//!
+//! \param s1 points to the first string to be compared.
+//! \param s2 points to the second string to be compared.
+//! \param n is the maximum number of characters to compare.
+//!
+//! This function is very similar to the C library <tt>strncmp()</tt> function.
+//! It compares at most \e n characters of two strings taking case into
+//! account. The comparison ends if a terminating NULL character is found in
+//! either string before \e n characters are compared. In this case, the
+//! int16_ter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
+//! than \e s2 and 1 if \e s1 is greater than \e s2.
+//
+//*****************************************************************************
+int
+ustrncmp(const char *s1, const char *s2, size_t n)
+{
+ //
+ // Loop while there are more characters.
+ //
+ while(n)
+ {
+ //
+ // If we reached a NULL in both strings, they must be equal so we end
+ // the comparison and return 0
+ //
+ if(!*s1 && !*s2)
+ {
+ return(0);
+ }
+
+ //
+ // Compare the two characters and, if different, return the relevant
+ // return code.
+ //
+ if(*s2 < *s1)
+ {
+ return(1);
+ }
+ if(*s1 < *s2)
+ {
+ return(-1);
+ }
+
+ //
+ // Move on to the next character.
+ //
+ s1++;
+ s2++;
+ n--;
+ }
+
+ //
+ // If we fall out, the strings must be equal for at least the first n
+ // characters so return 0 to indicate this.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Compares two strings.
+//!
+//! \param s1 points to the first string to be compared.
+//! \param s2 points to the second string to be compared.
+//!
+//! This function is very similar to the C library <tt>strcmp()</tt>
+//! function. It compares two strings, taking case into account. The
+//! comparison ends if a terminating NULL character is found in either string.
+//! In this case, the int16_ter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
+//! than \e s2 and 1 if \e s1 is greater than \e s2.
+//
+//*****************************************************************************
+int
+ustrcmp(const char *s1, const char *s2)
+{
+ //
+ // Pass this on to ustrncmp.
+ //
+ return(ustrncmp(s1, s2, (size_t)-1));
+}
+
+//*****************************************************************************
+//
+// Random Number Generator Seed Value
+//
+//*****************************************************************************
+static unsigned int g_iRandomSeed = 1;
+
+//*****************************************************************************
+//
+//! Set the random number generator seed.
+//!
+//! \param seed is the new seed value to use for the random number
+//! generator.
+//!
+//! This function is very similar to the C library <tt>srand()</tt> function.
+//! It will set the seed value used in the <tt>urand()</tt> function.
+//!
+//! \return None
+//
+//*****************************************************************************
+void
+usrand(unsigned int seed)
+{
+ g_iRandomSeed = seed;
+}
+
+//*****************************************************************************
+//
+//! Generate a new (pseudo) random number
+//!
+//! This function is very similar to the C library <tt>rand()</tt> function.
+//! It will generate a pseudo-random number sequence based on the seed value.
+//!
+//! \return A pseudo-random number will be returned.
+//
+//*****************************************************************************
+int
+urand(void)
+{
+ //
+ // Generate a new pseudo-random number with a linear congruence random
+ // number generator. This new random number becomes the seed for the next
+ // random number.
+ //
+ g_iRandomSeed = (g_iRandomSeed * 1664525) + 1013904223;
+
+ //
+ // Return the new random number.
+ //
+ return((int)g_iRandomSeed);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/ustdlib.h b/utils/ustdlib.h
new file mode 100644
index 0000000..b9227f9
--- /dev/null
+++ b/utils/ustdlib.h
@@ -0,0 +1,82 @@
+//*****************************************************************************
+//
+// ustdlib.h - Prototypes for simple standard library functions.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __USTDLIB_H__
+#define __USTDLIB_H__
+
+//*****************************************************************************
+//
+// Include the standard C headers upon which these replacements are based.
+//
+//*****************************************************************************
+#include <stdarg.h>
+#include <time.h>
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern void ulocaltime(time_t timer, struct tm *tm);
+extern time_t umktime(struct tm *timeptr);
+extern int urand(void);
+extern int usnprintf(char * restrict s, size_t n, const char * restrict format,
+ ...);
+extern int usprintf(char * restrict s, const char * restrict format, ...);
+extern void usrand(unsigned int seed);
+extern int ustrcasecmp(const char *s1, const char *s2);
+extern int ustrcmp(const char *s1, const char *s2);
+extern size_t ustrlen(const char *s);
+extern int ustrncasecmp(const char *s1, const char *s2, size_t n);
+extern int ustrncmp(const char *s1, const char *s2, size_t n);
+extern char *ustrncpy(char * restrict s1, const char * restrict s2, size_t n);
+extern char *ustrstr(const char *s1, const char *s2);
+extern float ustrtof(const char * restrict nptr,
+ const char ** restrict endptr);
+extern unsigned long int ustrtoul(const char * restrict nptr,
+ const char ** restrict endptr, int base);
+extern int uvsnprintf(char * restrict s, size_t n,
+ const char * restrict format, va_list arg);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USTDLIB_H__
diff --git a/utils/wavfile.c b/utils/wavfile.c
new file mode 100644
index 0000000..b2ce150
--- /dev/null
+++ b/utils/wavfile.c
@@ -0,0 +1,291 @@
+//******************************************************************************
+//
+// wavfile.c - This file supports reading audio data from a .wav file and
+// reading the file format.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//******************************************************************************
+
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "third_party/fatfs/src/ff.h"
+#include "third_party/fatfs/src/diskio.h"
+#include "wavfile.h"
+
+//******************************************************************************
+//
+// The flag values for the ui32Flags member of the tWavFile structure.
+//
+//******************************************************************************
+#define WAV_FLAG_FILEOPEN 0x00000001
+
+//******************************************************************************
+//
+// Basic wav file RIFF header information used to open and read a wav file.
+//
+//******************************************************************************
+#define RIFF_CHUNK_ID_RIFF 0x46464952
+#define RIFF_CHUNK_ID_FMT 0x20746d66
+#define RIFF_CHUNK_ID_DATA 0x61746164
+#define RIFF_TAG_WAVE 0x45564157
+#define RIFF_FORMAT_UNKNOWN 0x0000
+#define RIFF_FORMAT_PCM 0x0001
+#define RIFF_FORMAT_MSADPCM 0x0002
+#define RIFF_FORMAT_IMAADPCM 0x0011
+
+//******************************************************************************
+//
+// This function returns the format of a wav file that has been opened with
+// the WavOpen() function.
+//
+// \param psWavData is the structure that was passed to the WavOpen() function.
+// \param psWavHeader is the structure to fill with the format of the wav file.
+//
+// This function is used to get the audio format of a file that was opened
+// with the WavOpen() function. The \e psWavData parameter should be the
+// same structure that was passed to the WavOpen() function. The
+// \e psWavHeader function will be filled with the format of the open file if
+// the \e psWavData is a valid open file. If this function is called with
+// an invalid \e psWavData then the results will be undetermined.
+//
+// \return None.
+//
+//******************************************************************************
+void
+WavGetFormat(tWavFile *psWavData, tWavHeader *psWavHeader)
+{
+ //
+ // Only return data if the file is open.
+ //
+ psWavHeader->ui32DataSize = psWavData->sWavHeader.ui32DataSize;
+ psWavHeader->ui16NumChannels = psWavData->sWavHeader.ui16NumChannels;
+ psWavHeader->ui32SampleRate = psWavData->sWavHeader.ui32SampleRate;
+ psWavHeader->ui32AvgByteRate = psWavData->sWavHeader.ui32AvgByteRate;
+ psWavHeader->ui16BitsPerSample = psWavData->sWavHeader.ui16BitsPerSample;
+}
+
+//******************************************************************************
+//
+// This function is called to open and determine if a file is a valid .wav
+// file.
+//
+// \param pcFileName is the null terminated string for the file to open.
+// \param psWavData is the structure used to hold the file state information.
+//
+// This function is used to open a file and determine if it is a valid .wav
+// file. The \e pcFileName will be opened and read to look for a valid .wav
+// file header and prepared for calling the WavRead() or WavGetFormat()
+// functions. When an application is done with the .wav file it should call
+// the WavClose() function to free up the file. The function will return
+// zero if the function successfully opened a .wav file and a non-zero value
+// indicates that the file was a valid .wav file or the file could not be
+// opened.
+//
+// \return A value of zero indicates that the file was successfully opened and
+// any other value indicates that the file was not opened.
+//
+//******************************************************************************
+int
+WavOpen(const char *pcFileName, tWavFile *psWavData)
+{
+ unsigned char pucBuffer[16];
+ uint32_t *pui32Buffer;
+ uint16_t *pui16Buffer;
+ uint32_t ui32ChunkSize;
+ uint32_t ui32Count;
+
+ //
+ // Create some local pointers using in parsing values.
+ //
+ pui32Buffer = (uint32_t *)pucBuffer;
+ pui16Buffer = (uint16_t *)pucBuffer;
+
+ //
+ // Open the file as read only.
+ //
+ if(f_open(&psWavData->i16File, pcFileName, FA_READ) != FR_OK)
+ {
+ return(-1);
+ }
+
+ //
+ // File is open.
+ //
+ psWavData->ui32Flags = WAV_FLAG_FILEOPEN;
+
+ //
+ // Read the first 12 bytes.
+ //
+ if(f_read(&psWavData->i16File, pucBuffer, 12, (UINT *)&ui32Count) != FR_OK)
+ {
+ return(-1);
+ }
+
+ //
+ // Look for RIFF tag.
+ //
+ if((pui32Buffer[0] != RIFF_CHUNK_ID_RIFF) ||
+ (pui32Buffer[2] != RIFF_TAG_WAVE))
+ {
+ return(-1);
+ }
+
+ //
+ // Read the next chunk header.
+ //
+ if(f_read(&psWavData->i16File, pucBuffer, 8, (UINT *)&ui32Count) != FR_OK)
+ {
+ return(-1);
+ }
+
+ //
+ // Now look for the RIFF ID format tag.
+ //
+ if(pui32Buffer[0] != RIFF_CHUNK_ID_FMT)
+ {
+ return(-1);
+ }
+
+ //
+ // Read the format chunk size and insure that it is 16.
+ //
+ ui32ChunkSize = pui32Buffer[1];
+
+ if(ui32ChunkSize > 16)
+ {
+ return(-1);
+ }
+
+ //
+ // Read the next chunk header.
+ //
+ if(f_read(&psWavData->i16File, pucBuffer, ui32ChunkSize,
+ (UINT *)&ui32Count) != FR_OK)
+ {
+ return(-1);
+ }
+
+ //
+ // Save the audio format data so that it can be returned later if
+ // requested.
+ //
+ psWavData->sWavHeader.ui16Format = pui16Buffer[0];
+ psWavData->sWavHeader.ui16NumChannels = pui16Buffer[1];
+ psWavData->sWavHeader.ui32SampleRate = pui32Buffer[1];
+ psWavData->sWavHeader.ui32AvgByteRate = pui32Buffer[2];
+ psWavData->sWavHeader.ui16BitsPerSample = pui16Buffer[7];
+
+ //
+ // Only mono and stereo supported.
+ //
+ if(psWavData->sWavHeader.ui16NumChannels > 2)
+ {
+ return(-1);
+ }
+
+ //
+ // Read the next chunk header.
+ //
+ if(f_read(&psWavData->i16File, pucBuffer, 8, (UINT *)&ui32Count) != FR_OK)
+ {
+ return(-1);
+ }
+
+ //
+ // Now make sure that the file has a data chunk.
+ //
+ if(pui32Buffer[0] != RIFF_CHUNK_ID_DATA)
+ {
+ return(-1);
+ }
+
+ //
+ // Save the size of the data.
+ //
+ psWavData->sWavHeader.ui32DataSize = pui32Buffer[1];
+
+ return(0);
+}
+
+//******************************************************************************
+//
+// This is used to close a .wav file that was opened with WavOpen().
+//
+// \param psWavData is the file structure that was passed into the WavOpen()
+// function.
+//
+// This function should be called when a function has completed using a .wav
+// file that was opened with the WavOpen() function. This will free up any
+// file system data that is held while the file is open.
+//
+// \return None.
+//
+//******************************************************************************
+void
+WavClose(tWavFile *psWavData)
+{
+ if(psWavData->ui32Flags & WAV_FLAG_FILEOPEN)
+ {
+ //
+ // Close out the file.
+ //
+ f_close(&psWavData->i16File);
+
+ //
+ // Mark file as no longer open.
+ //
+ psWavData->ui32Flags &= ~WAV_FLAG_FILEOPEN;
+ }
+}
+
+//******************************************************************************
+//
+// This function is used to read audio data from a file that was opened with
+// the WavOpen() function.
+//
+// \param psWavData is the file structure that was passed into the WavOpen()
+// function.
+// \param pucBuffer is the buffer to read data into.
+// \param ui32Size is the amount of data to read in bytes.
+//
+//
+// This function handles reading data from a .wav file that was opened with
+// the WavOpen() function. The function will return the actual number of
+// of bytes read from the file.
+//
+// \return This function returns the number of bytes read from the file.
+//
+//******************************************************************************
+uint16_t
+WavRead(tWavFile *psWavData, unsigned char *pucBuffer, uint32_t ui32Size)
+{
+ uint32_t ui32Count;
+
+ //
+ // Read in another buffer from the file.
+ //
+ if(f_read(&psWavData->i16File, pucBuffer, ui32Size,
+ (UINT *)&ui32Count) != FR_OK)
+ {
+ return(0);
+ }
+
+ return(ui32Count);
+}
diff --git a/utils/wavfile.h b/utils/wavfile.h
new file mode 100644
index 0000000..f044301
--- /dev/null
+++ b/utils/wavfile.h
@@ -0,0 +1,97 @@
+//*****************************************************************************
+//
+// wavfile.h - This file supports reading audio data from a .wav file and
+// reading the file format.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef WAVEFILE_H_
+#define WAVEFILE_H_
+
+//*****************************************************************************
+//
+// The wav file header information.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Sample rate in bytes per second.
+ //
+ uint32_t ui32SampleRate;
+
+ //
+ // The average byte rate for the wav file.
+ //
+ uint32_t ui32AvgByteRate;
+
+ //
+ // The size of the wav data in the file.
+ //
+ uint32_t ui32DataSize;
+
+ //
+ // The number of bits per sample.
+ //
+ uint16_t ui16BitsPerSample;
+
+ //
+ // The wav file format.
+ //
+ uint16_t ui16Format;
+
+ //
+ // The number of audio channels.
+ //
+ uint16_t ui16NumChannels;
+}
+tWavHeader;
+
+//*****************************************************************************
+//
+// The structure used to hold the wav file state.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The wav files header information
+ //
+ tWavHeader sWavHeader;
+
+ //
+ // The file information for the current file.
+ //
+ FIL i16File;
+
+ //
+ // Current state flags, a combination of the WAV_FLAG_* values.
+ //
+ uint32_t ui32Flags;
+} tWavFile;
+
+void WavGetFormat(tWavFile *psWavData, tWavHeader *psWaveHeader);
+int WavOpen(const char *pcFileName, tWavFile *psWavData);
+void WavClose(tWavFile *psWavData);
+uint16_t WavRead(tWavFile *psWavData, unsigned char *pucBuffer,
+ uint32_t ui32Size);
+
+#endif