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 + -
显示快捷键?