📄 ui_serial.c
字号:
//*****************************************************************************
//
// ui_serial.c - A simple control interface utilizing a UART.
//
// Copyright (c) 2006-2008 Luminary Micro, Inc. All rights reserved.
//
// Software License Agreement
//
// Luminary Micro, Inc. (LMI) is supplying this software for use solely and
// exclusively on LMI's microcontroller products.
//
// The software is owned by LMI and/or its suppliers, and is protected under
// applicable copyright laws. All rights are reserved. You may not combine
// this software with "viral" open-source software in order to form a larger
// program. Any use in violation of the foregoing restrictions may subject
// the user to criminal sanctions under applicable laws, as well as to civil
// liability for the breach of the terms and conditions of this license.
//
// THIS SOFTWARE IS PROVIDED "AS IS". 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.
// LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 716 of the BLDC motor application.
//
//*****************************************************************************
#include "../../DriverLib/hw_ints.h"
#include "../../DriverLib/hw_memmap.h"
#include "../../DriverLib/hw_types.h"
#include "../../DriverLib/src/gpio.h"
#include "../../DriverLib/src/interrupt.h"
#include "../../DriverLib/src/sysctl.h"
#include "../../DriverLib/src/uart.h"
#include "commands.h"
#include "ui_serial.h"
//*****************************************************************************
//
//! \page ui_serial_intro Introduction
//!
//! A generic, packet-based serial protocol is utilized for communicating with
//! the motor drive board. This provides a method to control the motor drive,
//! adjust its parameters, and retrieve real-time performance data. The serial
//! interface is run at 115,200 baud, with an 8-N-1 data format. Some of the
//! factors that influenced the design of this protocol include:
//!
//! - The same serial protocol should be used for all motor drive boards,
//! regardless of the motor type (that is, AC induction, stepper, and
//! so on).
//! - The protocol should make reasonable attempts to protect against invalid
//! commands being acted upon.
//! - It should be possible to connect to a running motor drive board and lock
//! on to the real-time data stream without having to restart the data
//! stream.
//!
//! The code for handling the serial protocol is contained in
//! <tt>ui_serial.c</tt>, with <tt>ui_serial.h</tt> containing the definitions
//! for the structures, functions, and variables exported to the remainder
//! of the application. The file <tt>commands.h</tt> contains the definitions
//! for the commands, parameters, real-time data items, and responses that are
//! used in the serial protocol.
//!
//! \section cmf Command Message Format
//!
//! Commands are sent to the motor drive with the following format:
//!
//! \verbatim
//! {tag} {length} {command} {optional command data byte(s)} {checksum}
//! \endverbatim
//!
//! - The {tag} byte is 0xff.
//!
//! - The {length} byte contains the overall length of the command packet,
//! starting with the {tag} and ending with the {checksum}. The maximum
//! packet length is 255 bytes.
//!
//! - The {command} byte is the command being sent. Based on the command,
//! there may be optional command data bytes that follow.
//!
//! - The {checksum} byte is the value such that the sum of all bytes in the
//! command packet (including the checksum) will be zero. This is used to
//! validate a command packet and allow the target to synchronize with the
//! command stream being sent by the host.
//!
//! For example, the 0x01 command with no data bytes would be sent as
//! follows:
//!
//! \verbatim
//! 0xff 0x04 0x01 0xfc
//! \endverbatim
//!
//! And the 0x02 command with two data bytes (0xab and 0xcd) would be sent as
//! follows:
//!
//! \verbatim
//! 0xff 0x06 0x02 0xab 0xcd 0x81
//! \endverbatim
//!
//! \section smf Status Message Format
//!
//! Status messages are sent from the motor drive with the following format:
//!
//! \verbatim
//! {tag} {length} {data bytes} {checksum}
//! \endverbatim
//!
//! - The {tag} byte is 0xfe for command responses and 0xfd for real-time data.
//!
//! - The {length} byte contains the overall length of the status packet,
//! starting with the {tag} byte and ending with the {checksum}.
//!
//! - The contents of the data bytes are dependent upon the tag byte.
//!
//! - The {checksum} is the value such that the sum of all bytes in the status
//! packet (including the checksum) will be zero. This is used to validate a
//! status packet and allow the user interface to synchronize with the status
//! stream being sent by the target.
//!
//! For command responses ({tag} = 0xfe), the first data byte is the command
//! that is being responded to. The remaining bytes are the response, and are
//! dependent upon the command.
//!
//! For real-time data messages ({tag} = 0xfd), each real-time data item is
//! transmitted as a little-endian value (for example, for a 16-bit value, the
//! lower 8 bits first then the upper 8 bits). The data items are in the same
//! order as returned by the data item list (#CMD_GET_DATA_ITEMS) regardless of
//! the order that they were enabled.
//!
//! For example, if data items 1, 5, and 17 were enabled, and each was two
//! bytes in length, there would be 6 data bytes in the packet:
//!
//! \verbatim
//! 0xfd 0x09 {d1[0:7]} {d1[8:15]} {d5[0:7]} {d5[8:15]} {d17[0:7]}
//! {d17[8:15]} {checksum}
//! \endverbatim
//!
//! \section pi Parameter Interpretation
//!
//! The size and units of the parameters are dependent upon the motor drive;
//! the units are not conveyed in the serial protocol. Each parameter value is
//! transmitted in little endian format. Not all parameters are necessarily
//! supported by a motor drive, only those that are appropriate.
//!
//! \section itta Interface To The Application
//!
//! The serial protocol handler takes care of all the serial communications and
//! command interpretation. A set of functions provided by the application and
//! an array of structures that describe the parameters and real-time data
//! items supported by the motor drive. The functions are used when an
//! application-specific action needs to take place as a result of the serial
//! communication (such as starting the motor drive). The structures are used
//! to handle the parameters and real-time data items of the motor drive.
//
//*****************************************************************************
//*****************************************************************************
//
//! \defgroup ui_serial_api Definitions
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
//! The size of the UART transmit buffer. This should be appropriately sized
//! such that the maximum burst of output data can be contained in this buffer.
//! This value should be a power of two in order to make the modulo arithmetic
//! be fast (that is, an AND instead of a divide).
//
//*****************************************************************************
#ifndef UISERIAL_MAX_XMIT
#define UISERIAL_MAX_XMIT 64
#endif
//*****************************************************************************
//
//! The size of the UART receive buffer. This should be appropriately sized
//! such that the maximum size command packet can be contained in this buffer.
//! This value should be a power of two in order to make the modulo arithmetic
//! be fast (that is, an AND instead of a divide).
//
//*****************************************************************************
#ifndef UISERIAL_MAX_RECV
#define UISERIAL_MAX_RECV 64
#endif
//*****************************************************************************
//
//! A buffer to contain data received from the UART. A packet is processed out
//! of this buffer once the entire packet is contained within the buffer.
//
//*****************************************************************************
static unsigned char g_pucUISerialReceive[UISERIAL_MAX_RECV];
//*****************************************************************************
//
//! The offset of the next byte to be read from g_pucUISerialReceive.
//
//*****************************************************************************
static unsigned long g_ulUISerialReceiveRead;
//*****************************************************************************
//
//! The offset of the next byte to be written to g_pucUISerialReceive.
//
//*****************************************************************************
static unsigned long g_ulUISerialReceiveWrite;
//*****************************************************************************
//
//! A buffer to contain data to be written to the UART.
//
//*****************************************************************************
static unsigned char g_pucUISerialTransmit[UISERIAL_MAX_XMIT];
//*****************************************************************************
//
//! The offset of the next byte to be read from g_pucUISerialTransmit.
//
//*****************************************************************************
static unsigned long g_ulUISerialTransmitRead;
//*****************************************************************************
//
//! The offset of the next byte to be written to g_pucUISerialTransmit.
//
//*****************************************************************************
static unsigned long g_ulUISerialTransmitWrite;
//*****************************************************************************
//
//! A buffer used to construct status packets before they are written to the
//! UART and/or g_pucUISerialTransmit.
//
//*****************************************************************************
static unsigned char g_pucUISerialResponse[UISERIAL_MAX_XMIT];
//*****************************************************************************
//
//! A buffer used to construct real-time data packets before they are written
//! to the UART and/or g_pucUISerialTransmit.
//
//*****************************************************************************
static unsigned char g_pucUISerialData[UISERIAL_MAX_XMIT];
//*****************************************************************************
//
//! A boolean that is true when the real-time data stream is enabled.
//
//*****************************************************************************
static tBoolean g_bEnableRealTimeData;
//*****************************************************************************
//
//! A bit array that contains a flag for each real-time data item. When the
//! corresponding flag is set, that real-time data item is enabled in the
//! real-time data stream; when the flag is clear, that real-time data item is
//! not part of the real-time data stream.
//
//*****************************************************************************
static unsigned long g_pulUIRealTimeData[(DATA_NUM_ITEMS + 31) / 32];
//*****************************************************************************
//
//! Transmits a packet to the UART.
//!
//! \param pucBuffer is a pointer to the packet to be transmitted.
//!
//! This function will send a packet via the UART. It will compute the
//! checksum of the packet (based on the length in the second byte) and place
//! it at the end of the packet before sending the packet. If
//! g_pucUISerialTransmit is empty and there is space in the UART's FIFO, as
//! much of the packet as will fit will be written directly to the UART's FIFO.
//! The remainder of the packet will be buffered for later transmission when
//! space becomes available in the UART's FIFO (which will then be written by
//! the UART interrupt handler).
//!
//! \return Returns \b true if the entire packet fit into the combination of
//! the UART's FIFO and g_pucUISerialTransmit, and \b false otherwise.
//
//*****************************************************************************
static tBoolean
UISerialTransmit(unsigned char *pucBuffer)
{
unsigned long ulIdx, ulSum, ulLength;
//
// Compute the checksum for this packet and put it at the end.
//
for(ulIdx = 0, ulSum = 0, ulLength = pucBuffer[1]; ulIdx < (ulLength - 1);
ulIdx++)
{
ulSum -= pucBuffer[ulIdx];
}
pucBuffer[ulLength - 1] = ulSum;
//
// See if the transmit buffer is empty.
//
if(g_ulUISerialTransmitRead == g_ulUISerialTransmitWrite)
{
//
// Loop while there is more data to transmit and space in the UART
// FIFO.
//
while(ulLength && UARTSpaceAvail(UART0_BASE))
{
//
// Write the next character.
//
UARTCharPut(UART0_BASE, *pucBuffer++);
//
// Decrement the count of characters to send.
//
ulLength--;
}
}
//
// Loop while there are more characters to send and there is more space in
// the transmit buffer.
//
while(ulLength && (((g_ulUISerialTransmitWrite + 1) % UISERIAL_MAX_XMIT) !=
g_ulUISerialTransmitRead))
{
//
// Write the next character to the transmit buffer.
//
g_pucUISerialTransmit[g_ulUISerialTransmitWrite] = *pucBuffer++;
//
// Increment the transmit buffer write pointer.
//
g_ulUISerialTransmitWrite =
(g_ulUISerialTransmitWrite + 1) % UISERIAL_MAX_XMIT;
//
// Decrement the count of characters to send.
//
ulLength--;
}
//
// Return an error if there are characters to be sent that would not fit
// into the transmit buffer.
//
if(ulLength)
{
return(false);
}
else
{
return(true);
}
}
//*****************************************************************************
//
//! Finds a parameter by ID.
//!
//! \param ucID is the ID of the parameter to locate.
//!
//! This function searches the list of parameters looking for one that matches
//! the provided ID.
//!
//! \return Returns the index of the parameter found, or 0xffff.ffff if the
//! parameter does not exist in the parameter list.
//
//*****************************************************************************
static unsigned long
UISerialFindParameter(unsigned char ucID)
{
unsigned long ulIdx;
//
// Loop through the parameters.
//
for(ulIdx = 0; ulIdx < g_ulUINumParameters; ulIdx++)
{
//
// See if this parameter matches the search ID.
//
if(g_sUIParameters[ulIdx].ucID == ucID)
{
//
// Since this parameter matches, return its index.
//
return(ulIdx);
}
}
//
// The parameter could not be located, so return a failure.
//
return(0xffffffff);
}
//*****************************************************************************
//
//! Performs range checking on the value of a parameter.
//!
//! \param ulIdx is the index of the parameter to check.
//!
//! This function will perform range checking on the value of a parameter,
//! adjusting the parameter value if necessary to make it reside within the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -