lin_driver.c
来自「芯科原厂所有c8051fxx程序的例子。」· C语言 代码 · 共 492 行
C
492 行
// Copyright (c) 2006 SILICON LABORATORIES, INC.
//
// FILE NAME : LIN_Driver.c
// TARGET MCU : C8051F52xA-53xA
// DESCRIPTION : Low-level driver for Core LIN API
//
// This file processes interfaces directly to the LIN hardware of
// the F52xA-53xA.
//
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
//
#include <c8051F520.h>
#include "LIN.h"
//-----------------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------------
//
// These variables are used globally in LIN_Driver.c:
//
// 1. temp - Used as a temporary save location by _LIN_IREG_SET_BITS and
// _LIN_IREG_CLEAR_BITS.
//
// 2. pid_table - Contains the PID for each corresponding frame ID from 0x00
// to 0x3F.
//
// 3. EA_Save - This variable is used by l_disable_global_interrupts and
// l_restore_global_interrupts to save the state of EA.
//
l_u8 temp;
l_u8 code pid_table[0x40] =
{
0x80, 0xC1, 0x42, 0x03, 0xC4, 0x85, 0x06, 0x47,
0x08, 0x49, 0xCA, 0x8B, 0x4C, 0x0D, 0x8E, 0xCF,
0x50, 0x11, 0x92, 0xD3, 0x14, 0x55, 0xD6, 0x97,
0xD8, 0x99, 0x1A, 0x5B, 0x9C, 0xDD, 0x5E, 0x1F,
0x20, 0x61, 0xE2, 0xA3, 0x64, 0x25, 0xA6, 0xE7,
0xA8, 0xE9, 0x6A, 0x2B, 0xEC, 0xAD, 0x2E, 0x6F,
0xF0, 0xB1, 0x32, 0x73, 0xB4, 0xF5, 0x76, 0x37,
0x78, 0x39, 0xBA, 0xFB, 0x3C, 0x7D, 0xFE, 0xBF
};
l_bool EA_Save = 0;
//-----------------------------------------------------------------------------
// Functions
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// l_disable_global_interrupts ()
//-----------------------------------------------------------------------------
//
// Saves the current state of the global interrupt enable bit and disables
// all interrupts.
//
void l_disable_global_interrupts (void)
{
// Save the status of EA.
EA_Save = EA;
// Disable interrupts.
EA = 0;
EA = 0;
}
//-----------------------------------------------------------------------------
// l_restore_global_interrupts ()
//-----------------------------------------------------------------------------
//
// Restores the global interrupt enable bit to the value it held before the
// last call to l_disable_global_interrupts ().
//
void l_restore_global_interrupts (void)
{
// Restore EA.
EA = EA_Save;
}
//-----------------------------------------------------------------------------
// l_get_status ()
//-----------------------------------------------------------------------------
//
// Returns the result of the last transaction on the bus.
//
l_u8 l_get_status (void)
{
l_u8 retval, status, error;
// Initialize retval.
retval = 0;
// Read the LIN Status register
_LIN_IREG_READ (LINST, status);
// If transmission completed successfully, return TX_SUCCESS.
// If WAKEUP is set, a wake-up signal was transmitted or received. Do not
// set TX_SUCCESS.
if ((status & DONE) && (status & LININT) && (!(status & WAKEUP)))
retval |= TX_SUCCESS;
// If there was an error in transmission, return TX_ERROR.
if ((status & ERROR) && (status & LININT))
{
_LIN_IREG_READ (LINERR, error);
// Set ERROR_IN_RESPONSE for all frame errors.
if (error & (SYNCH | PRTY | CHK | BITERR))
retval |= TX_FRAME_ERROR;
else
retval |= TX_TIMEOUT;
}
return (retval);
}
//-----------------------------------------------------------------------------
// l_clear_status ()
//-----------------------------------------------------------------------------
//
// Clears the interrupt and error bits in LINCTRL.
//
void l_clear_status (void)
{
// Clear the interrupt and error bits.
_LIN_IREG_SET_BITS (LINCTRL, (RSTINT | RSTERR));
}
//-----------------------------------------------------------------------------
// l_get_frame_pid ()
//-----------------------------------------------------------------------------
//
// Returns the protected identifier for a frame with ID frame_id.
//
// Parameters:
//
// 1. frame_id - The ID for which the PID will be calculated.
//
l_u8 l_get_frame_pid (l_u8 frame_id)
{
return (pid_table[frame_id]);
}
//-----------------------------------------------------------------------------
// l_read_frame_id ()
//-----------------------------------------------------------------------------
//
// Returns the frame identifier.
//
l_u8 l_read_frame_id (void)
{
l_u8 frame_id;
_LIN_IREG_READ (LINID, frame_id);
return (frame_id);
}
//-----------------------------------------------------------------------------
// l_read_frame_data ()
//-----------------------------------------------------------------------------
//
// Reads the data of the received frame. Returns the number of bytes in the
// frame.
//
// Parameters:
//
// 1. rx_data - The data is loaded into rx_data with the
// following format:
//
// [ LINDT1, LINDT2, ..., LINDT8 ]
//
l_u8 l_read_frame_data (l_u8 * rx_data)
{
l_u8 len, i;
l_u8 * rx_ptr;
// Get the contents of LINSIZE.
_LIN_IREG_READ (LINSIZE, len);
// Remove ENCHK so len holds the value in [ LINSIZE3 : LINSIZE0 ].
len &= ~ENCHK;
// Set rx_ptr to point to the beginning of rx_data.
rx_ptr = rx_data;
// Read the data bytes into rx_data.
for (i = 0; i < len; i++)
{
_LIN_IREG_READ ((LINDT1 + i), *rx_ptr++);
}
return (len);
}
//-----------------------------------------------------------------------------
// l_get_bus_activity ()
//-----------------------------------------------------------------------------
//
// Returns 1 if the bus is active and 0 if it is inactive.
//
l_bool l_get_bus_activity (void)
{
l_u8 retval;
_LIN_IREG_READ (LINST, retval);
retval &= ACTIVE;
return ((l_bool) retval);
}
#if (LIN_MODE == LIN_MASTER)
//-----------------------------------------------------------------------------
// l_write_frame_id ()
//-----------------------------------------------------------------------------
//
// Loads the frame identifier of the frame.
//
// Parameters:
//
// 1. frame_id - The ID of the frame.
//
void l_write_frame_id (l_u8 frame_id)
{
// Write the frame_id to LINID.
_LIN_IREG_WRITE (LINID, frame_id);
}
//-----------------------------------------------------------------------------
// l_test_parity ()
//-----------------------------------------------------------------------------
//
// Checks the parity of a received PID.
//
// Parameters:
//
// 1. frame_pid - The PID for which the parity will be tested.
//
// Returns TRUE is the parity is correct and FALSE if it is incorrect.
//
l_bool l_test_parity (l_u8 frame_pid)
{
return (frame_pid == l_get_frame_pid (frame_pid & ~FRAME_PARITY));
}
#endif
//-----------------------------------------------------------------------------
// l_write_frame_length ()
//-----------------------------------------------------------------------------
//
// Writes the length of the frame to send.
//
// Parameters:
//
// 1. frame_len - The number of bytes to load.
//
//
void l_write_frame_length (l_u8 frame_len)
{
l_u8 tmp;
// Get the current value of LINSIZE.
_LIN_IREG_READ (LINSIZE, tmp);
// Write the new value without corrupting ENCHK.
tmp &= ~LINSIZE3_0;
tmp |= frame_len;
_LIN_IREG_WRITE (LINSIZE, tmp);
}
//-----------------------------------------------------------------------------
// l_write_frame_checksum_type ()
//-----------------------------------------------------------------------------
//
// Writes the type of checksum to send in the frame.
//
// Parameters:
//
// 1. frame_checksum - If 0, LIN hardware will use classic checksum.
// If 1, LIN hardware will use enhanced checksum.
//
void l_write_frame_checksum_type (l_u8 frame_checksum)
{
l_u8 tmp;
// Get the current value of LINSIZE.
_LIN_IREG_READ (LINSIZE, tmp);
// If enhanced checksum is selected, append ENCHK to the frame length.
if (frame_checksum == ENHANCED_CHECKSUM)
{
_LIN_IREG_WRITE (LINSIZE, (tmp | ENCHK));
}
// Otherwise, write the length.
else
{
_LIN_IREG_WRITE (LINSIZE, (tmp & ~ENCHK));
}
}
//-----------------------------------------------------------------------------
// l_write_frame_data ()
//-----------------------------------------------------------------------------
//
// Loads data into the LIN data registers.
//
// Parameters:
//
// 1. frame_len - The number of bytes to load.
//
// 2. frame_data - Pointer to an array of data to load.
//
void l_write_frame_data (l_u8 frame_len, l_u8 * frame_data)
{
l_u8 i;
l_u8 * frame_data_ptr;
// Initialize frame_data_ptr.
frame_data_ptr = frame_data;
// Load the data bytes.
for (i = 0; i < frame_len; i++)
{
_LIN_IREG_WRITE (LINDT1 + i, *frame_data_ptr++);
}
}
#if (LIN_MODE == LIN_MASTER)
//-----------------------------------------------------------------------------
// l_master_transmit_frame ()
//-----------------------------------------------------------------------------
//
// Transmits the frame with frame ID, frame length, checksum type, and
// frame direction as specified.
//
// Parameters:
//
// 1. frame_id - The ID of the frame.
//
// 2. frame_len - The length of the frame.
//
// 3. frame_data - Pointer to an array of data to be sent.
//
// 3. frame_checksum - If 0, LIN hardware will use classic checksum.
// If 1, LIN hardware will use enhanced checksum.
//
// 4. frame_direction - The direction of the frame. Possible values are:
//
// a. IN_FRAME - Frame data will be received by the device.
// b. OUT_FRAME - Frame data will be transmitted by the device.
//
void l_master_transmit_frame (l_u8 frame_id,
l_u8 frame_len,
l_u8 * frame_data,
l_u8 frame_checksum,
l_u8 frame_direction)
{
// Write frame_id to LINID.
l_write_frame_id (frame_id);
// Write the length of the frame.
l_write_frame_length (frame_len);
// Write the type of checksum to use in the frame.
l_write_frame_checksum_type (frame_checksum);
// Reset the hardware status information as it is no longer relevant.
l_clear_status ();
// Begin frame transmission. Set TXRX if frame is a FRAME_OUT.
if (frame_direction == OUT_FRAME)
{
// Load the data to transmit.
l_write_frame_data (frame_len, frame_data);
// Transmit the frame in TX mode.
_LIN_IREG_SET_BITS (LINCTRL, (STREQ | TXRX));
}
else
{
// Transmit the frame in RX mode.
_LIN_IREG_CLEAR_BITS (LINCTRL, TXRX);
_LIN_IREG_SET_BITS (LINCTRL, STREQ);
}
}
#elif (LIN_MODE == LIN_SLAVE)
//-----------------------------------------------------------------------------
// l_slave_transmit_frame ()
//-----------------------------------------------------------------------------
//
// Transmits the frame with frame length and checksum type as specified.
//
// Parameters:
//
// 1. frame_len - The length of the frame.
//
// 2. frame_checksum - If 0, LIN hardware will use classic checksum.
// If 1, LIN hardware will use enhanced checksum.
//
void l_slave_transmit_frame (l_u8 frame_len, l_u8 * frame_data, l_u8 frame_checksum)
{
// Set the TXRX bit to TX.
_LIN_IREG_SET_BITS (LINCTRL, TXRX);
// Write the length of the frame.
l_write_frame_length (frame_len);
// Write the type of checksum to use in the frame.
l_write_frame_checksum_type (frame_checksum);
// Load the data to transmit
l_write_frame_data (frame_len, frame_data);
// Set the DTACK bit in LINCTRL (leave the TXRX bit set as well).
_LIN_IREG_SET_BITS (LINCTRL, (TXRX | DTACK));
}
//-----------------------------------------------------------------------------
// l_slave_receive_frame ()
//-----------------------------------------------------------------------------
//
// Configures the device to receive the incoming frame data.
//
void l_slave_receive_frame (l_u8 frame_len, l_u8 frame_checksum)
{
// Clear TXRX for receive frame.
_LIN_IREG_CLEAR_BITS (LINCTRL, TXRX);
// Set the frame length.
l_write_frame_length (frame_len);
// Set the checksum type.
l_write_frame_checksum_type (frame_checksum);
// Write the DTACK bit.
_LIN_IREG_SET_BITS (LINCTRL, DTACK);
}
//-----------------------------------------------------------------------------
// l_slave_ignore_frame ()
//-----------------------------------------------------------------------------
//
// Configures the device to ignore the incoming frame data. Should be called
// when the slave receives a frame ID for which it is neither a publisher
// nor a subscriber.
//
void l_slave_ignore_frame (void)
{
// Set the STOP bit in LINCTRL.
_LIN_IREG_SET_BITS (LINCTRL, STOP);
}
//-----------------------------------------------------------------------------
// l_slave_go_to_sleep ()
//-----------------------------------------------------------------------------
//
// Performs hardware operations necessary to put the slave device in sleep
// mode.
//
void l_slave_go_to_sleep (void)
{
// Write to the SLEEP bit in LINCTRL.
_LIN_IREG_SET_BITS (LINCTRL, SLEEP);
}
#endif
//-----------------------------------------------------------------------------
// l_transmit_wake_up ()
//-----------------------------------------------------------------------------
//
// Sends a wakeup signal on the bus.
//
void l_transmit_wake_up (void)
{
// Write to WUPREQ in LINCTRL.
_LIN_IREG_SET_BITS (LINCTRL, WUPREQ);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?