修改了Web后台的部分界面,增加了HAmqtt中的总电量传感器,后台新增mqtt上报频率设置

This commit is contained in:
OOP
2025-03-03 21:49:41 +08:00
parent e1e00b60ce
commit 9f9d4c7a56
4468 changed files with 1473046 additions and 10728 deletions

View File

@@ -0,0 +1,586 @@
/*
* @brief LPC540XX ADC driver
*
* @note
* Copyright(C) NXP Semiconductors, 2012
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#ifndef __ADC_540XX_H_
#define __ADC_540XX_H_
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup ADC_540XX CHIP: LPC540XX A/D conversion driver
* @ingroup CHIP_540XX_Drivers
* @{
*/
/** Sequence index enumerations, used in various parts of the code for
register indexing and sequencer selection */
typedef enum {
ADC_SEQA_IDX = 0,
ADC_SEQB_IDX
} ADC_SEQ_IDX_T;
/**
* @brief ADC register block structure
*/
typedef struct { /*!< ADCn Structure */
__IO uint32_t CTRL; // (0x00)
__IO uint32_t INSEL; // (0x04)
union {
__IO uint32_t SEQ_CTRL[2]; // (0x08~0x0C)
struct {
__IO uint32_t SEQA_CTRL;
__IO uint32_t SEQB_CTRL;
};
};
union {
__IO uint32_t SEQ_GDAT[2]; // (0x10~0x14)
struct {
__IO uint32_t SEQA_GDAT;
__IO uint32_t SEQB_GDAT;
};
};
__IO uint32_t RESERVED0[2]; // (0x18-0x1C)
__IO uint32_t DAT[12]; // (0x20-0x4C)
__IO uint32_t THR_LOW[2]; // (0x50~0x54)
__IO uint32_t THR_HIGH[2]; // (0x58~0x5C)
__IO uint32_t CHAN_THRSEL; // (0x60)
__IO uint32_t INTEN; // (0x64)
__IO uint32_t FLAGS; // (0x68)
__IO uint32_t STARTUP; // (0x6C)
__IO uint32_t CALIBR; // (0x70)
} LPC_ADC_T;
/** Maximum sample rate in Hz (12-bit conversions) */
#define ADC_MAX_SAMPLE_RATE 80000000
#define ADC_MAX_CHANNEL_NUM 12
/**
* @brief ADC register support bitfields and mask
*/
/** ADC Control register bit fields */
#define ADC_CR_CLKDIV_MASK (0xFF << 0) /*!< Mask for Clock divider value */
#define ADC_CR_CLKDIV_BITPOS (0) /*!< Bit position for Clock divider value */
#define ADC_CR_ASYNC_MODE (1 << 8) /*!< Asynchronous mode enable bit */
#define ADC_CR_RESOL(n) ((n) << 9) /*!< 2-bits, 6(0x0),8(0x1),10(0x2),12(0x3)-bit mode enable bit */
#define ADC_CR_LPWRMODEBIT (1 << 10) /*!< Low power mode enable bit */
#define ADC_CR_BYPASS (1 << 11) /*!< Bypass mode */
#define ADC_CR_TSAMP(n) ((n) << 12) /*!< 3-bits, 2.5(0x0),3.5(0x1),4.5(0x2),5.5(0x3),6.5(0x4),7.5(0x5),8.5(0x6),9.5(0x7) ADC clocks sampling time */
#define ADC_CR_CALMODEBIT (1 << 30) /*!< Self calibration cycle enable bit */
#define ADC_CR_BITACC(n) ((((n) & 0x1) << 9)) /*!< 12-bit or 10-bit ADC accuracy */
#define ADC_CR_CLKDIV(n) ((((n) & 0xFF) << 0)) /*!< The APB clock (PCLK) is divided by (this value plus one) to produce the clock for the A/D */
#define ADC_SAMPLE_RATE_CONFIG_MASK (ADC_CR_CLKDIV(0xFF) | ADC_CR_BITACC(0x01))
/**
* @brief ADC resolution bits 9 and 10
*/
typedef enum _ADC_RESOL_T {
ADC_RESOL_6BIT = 0,
ADC_RESOL_8BIT,
ADC_RESOL_10BIT,
ADC_RESOL_12BIT,
} ADC_RESOL_T;
/**
* @brief ADC sampling time bits 12, 13 and 14
*/
typedef enum _ADC_TSAMP_T {
ADC_TSAMP_2CLK5 = 0,
ADC_TSAMP_3CLK5,
ADC_TSAMP_4CLK5,
ADC_TSAMP_5CLK5,
ADC_TSAMP_6CLK5,
ADC_TSAMP_7CLK5,
ADC_TSAMP_8CLK5,
ADC_TSAMP_9CLK5,
} ADC_TSAMP_T;
/* ADC input Select register */
#define ADC_INPUTSEL_PIN (0x0<<0)
#define ADC_INPUTSEL_CORE_VOL (0x1<<0)
#define ADC_INPUTSEL_INTERNAL_VOL (0x2<<0)
#define ADC_INPUTSEL_TEMP_VOL (0x3<<0)
/** ADC Sequence Control register bit fields */
#define ADC_SEQ_CTRL_CHANSEL(n) (1 << (n)) /*!< Channel select macro */
#define ADC_SEQ_CTRL_CHANSEL_BITPOS(n) ((n)<<0) /*!< Channel select macro */
#define ADC_SEQ_CTRL_CHANSEL_MASK (0xFFF) /*!< Channel select mask */
/** SEQ_CTRL register bit fields */
#define ADC_SEQ_CTRL_TRIGGER(n) ((n)<<12)
#define ADC_SEQ_CTRL_HWTRIG_POLPOS (1 << 18) /*!< HW trigger polarity - positive edge */
#define ADC_SEQ_CTRL_HWTRIG_SYNCBYPASS (1 << 19) /*!< HW trigger bypass synchronisation */
#define ADC_SEQ_CTRL_START (1 << 26) /*!< Start conversion enable bit */
#define ADC_SEQ_CTRL_BURST (1 << 27) /*!< Repeated conversion enable bit */
#define ADC_SEQ_CTRL_SINGLESTEP (1 << 28) /*!< Single step enable bit */
#define ADC_SEQ_CTRL_LOWPRIO (1 << 29) /*!< High priority enable bit (regardless of name) */
#define ADC_SEQ_CTRL_MODE_EOS (1 << 30) /*!< Mode End of sequence enable bit */
#define ADC_SEQ_CTRL_SEQ_ENA (1UL << 31) /*!< Sequence enable bit */
/** ADC global data register bit fields */
#define ADC_SEQ_GDAT_RESULT_MASK (0xFFF << 4) /*!< Result value mask */
#define ADC_SEQ_GDAT_RESULT_BITPOS (4) /*!< Result start bit position */
#define ADC_SEQ_GDAT_THCMPRANGE_MASK (0x3 << 16) /*!< Comparion range mask */
#define ADC_SEQ_GDAT_THCMPRANGE_BITPOS (16) /*!< Comparison range bit position */
#define ADC_SEQ_GDAT_THCMPCROSS_MASK (0x3 << 18) /*!< Comparion cross mask */
#define ADC_SEQ_GDAT_THCMPCROSS_BITPOS (18) /*!< Comparison cross bit position */
#define ADC_SEQ_GDAT_CHAN_MASK (0xF << 26) /*!< Channel number mask */
#define ADC_SEQ_GDAT_CHAN_BITPOS (26) /*!< Channel number bit position */
#define ADC_SEQ_GDAT_OVERRUN (1 << 30) /*!< Overrun bit */
#define ADC_SEQ_GDAT_DATAVALID (1UL << 31) /*!< Data valid bit */
/** ADC Data register bit fields */
#define ADC_DR_RESULT_BITPOS (4) /*!< Result start bit position */
#define ADC_DR_RESULT(n) ((((n) >> 4) & 0xFFF)) /*!< Macro for getting the ADC data value */
#define ADC_DR_THCMPRANGE_MASK (0x3 << 16) /*!< Comparion range mask */
#define ADC_DR_THCMPRANGE_BITPOS (16) /*!< Comparison range bit position */
#define ADC_DR_THCMPRANGE(n) (((n) >> ADC_DR_THCMPRANGE_BITPOS) & 0x3)
#define ADC_DR_THCMPCROSS_MASK (0x3 << 18) /*!< Comparion cross mask */
#define ADC_DR_THCMPCROSS_BITPOS (18) /*!< Comparison cross bit position */
#define ADC_DR_THCMPCROSS(n) (((n) >> ADC_DR_THCMPCROSS_BITPOS) & 0x3)
#define ADC_DR_CHAN_MASK (0xF << 26) /*!< Channel number mask */
#define ADC_DR_CHAN_BITPOS (26) /*!< Channel number bit position */
#define ADC_DR_CHANNEL(n) (((n) >> ADC_DR_CHAN_BITPOS) & 0xF) /*!< Channel number bit position */
#define ADC_DR_OVERRUN (1 << 30) /*!< Overrun bit */
#define ADC_DR_DATAVALID (1UL << 31) /*!< Data valid bit */
#define ADC_DR_DONE(n) (((n) >> 31))
/** ADC low/high Threshold register bit fields */
#define ADC_THR_VAL_MASK (0xFFF << 4) /*!< Threshold value bit mask */
#define ADC_THR_VAL_POS (4) /*!< Threshold value bit position */
/** ADC Threshold select register bit fields */
#define ADC_THRSEL_CHAN_SEL_THR1(n) (1 << (n)) /*!< Select THR1 register for channel n */
/** ADC Interrupt Enable register bit fields */
#define ADC_INTEN_SEQA_ENABLE (1 << 0) /*!< Sequence A Interrupt enable bit */
#define ADC_INTEN_SEQB_ENABLE (1 << 1) /*!< Sequence B Interrupt enable bit */
#define ADC_INTEN_SEQN_ENABLE(seq) (1 << (seq)) /*!< Sequence A/B Interrupt enable bit */
#define ADC_INTEN_OVRRUN_ENABLE (1 << 2) /*!< Overrun Interrupt enable bit */
#define ADC_INTEN_CMP_DISBALE (0) /*!< Disable comparison interrupt value */
#define ADC_INTEN_CMP_OUTSIDETH (1) /*!< Outside threshold interrupt value */
#define ADC_INTEN_CMP_CROSSTH (2) /*!< Crossing threshold interrupt value */
#define ADC_INTEN_CMP_MASK (3) /*!< Comparison interrupt value mask */
#define ADC_INTEN_CMP_ENABLE(isel, ch) (((isel) & ADC_INTEN_CMP_MASK) << ((2 * (ch)) + 3)) /*!< Interrupt selection for channel */
/** ADC Flags register bit fields */
#define ADC_FLAGS_THCMP_MASK(ch) (1 << (ch)) /*!< Threshold comparison status for channel */
#define ADC_FLAGS_OVRRUN_MASK(ch) (1 << (12 + (ch))) /*!< Overrun status for channel */
#define ADC_FLAGS_SEQA_OVRRUN_MASK (1 << 24) /*!< Seq A Overrun status */
#define ADC_FLAGS_SEQB_OVRRUN_MASK (1 << 25) /*!< Seq B Overrun status */
#define ADC_FLAGS_SEQN_OVRRUN_MASK(seq) (1 << (24 + (seq))) /*!< Seq A/B Overrun status */
#define ADC_FLAGS_SEQA_INT_MASK (1 << 28) /*!< Seq A Interrupt status */
#define ADC_FLAGS_SEQB_INT_MASK (1 << 29) /*!< Seq B Interrupt status */
#define ADC_FLAGS_SEQN_INT_MASK(seq) (1 << (28 + (seq)))/*!< Seq A/B Interrupt status */
#define ADC_FLAGS_THCMP_INT_MASK (1 << 30) /*!< Threshold comparison Interrupt status */
#define ADC_FLAGS_OVRRUN_INT_MASK (1UL << 31) /*!< Overrun Interrupt status */
/** ADC Startup register bit fields */
#define ADC_STARTUP_ENABLE (0x1 << 0)
#define ADC_STARTUP_INIT (0x1 << 1)
/* ADC Calibration register definition */
#define ADC_CALIB (0x1<<0)
#define ADC_CALREQD (0x1<<1)
/**
* @brief Initialize the ADC peripheral
* @param pADC : The base of ADC peripheral on the chip
* @param flags : ADC flags for init (ADC_CR_MODE10BIT and/or ADC_CR_LPWRMODEBIT)
* @return Nothing
* @note To select low-power ADC mode, enable the ADC_CR_LPWRMODEBIT flag.
* To select 10-bit conversion mode, enable the ADC_CR_MODE10BIT flag.<br>
* Example: Chip_ADC_Init(LPC_ADC, (ADC_CR_MODE10BIT | ADC_CR_LPWRMODEBIT));
*/
void Chip_ADC_Init(LPC_ADC_T *pADC, uint32_t flags);
/**
* @brief Shutdown ADC
* @param pADC : The base of ADC peripheral on the chip
* @return Nothing
* @note Disables the ADC clocks and ADC power
*/
void Chip_ADC_DeInit(LPC_ADC_T *pADC);
/**
* @brief Set ADC divider
* @param pADC : The base of ADC peripheral on the chip
* @param div : ADC divider value to set minus 1
* @return Nothing
* @note The value is used as a divider to generate the ADC
* clock rate from the ADC input clock. The ADC input clock is based
* on the system clock. Valid values for this function are from 0 to 255
* with 0=divide by 1, 1=divide by 2, 2=divide by 3, etc.<br>
* Do not decrement this value by 1.<br>
* To set the ADC clock rate to 1MHz, use the following function:<br>
* Chip_ADC_SetDivider(LPC_ADC, (Chip_Clock_GetSystemClockRate() / 1000000) - 1);
*/
STATIC INLINE void Chip_ADC_SetDivider(LPC_ADC_T *pADC, uint8_t div)
{
uint32_t temp;
temp = pADC->CTRL & ~(ADC_CR_CLKDIV_MASK);
pADC->CTRL = temp | (uint32_t) div;
}
/**
* @brief Set ADC clock rate
* @param pADC : The base of ADC peripheral on the chip
* @param rate : rate in Hz to set ADC clock to (maximum ADC_MAX_SAMPLE_RATE)
* @return Nothing
*/
void Chip_ADC_SetClockRate(LPC_ADC_T *pADC, uint32_t rate);
/**
* @brief Get ADC divider
* @param pADC : The base of ADC peripheral on the chip
* @return the current ADC divider
* @note This function returns the divider that is used to generate the
* ADC frequency. The returned value must be incremented by 1. The
* frequency can be determined with the following function:<br>
* adc_freq = Chip_Clock_GetSystemClockRate() / (Chip_ADC_GetDivider(LPC_ADC) + 1);
*/
STATIC INLINE uint8_t Chip_ADC_GetDivider(LPC_ADC_T *pADC)
{
return pADC->CTRL & ADC_CR_CLKDIV_MASK;
}
/**
* @brief Start ADC calibration
* @param pADC : The base of ADC peripheral on the chip
* @return Nothing
* @note Calibration is not done as part of Chip_ADC_Init(), but
* is required after the call to Chip_ADC_Init() or after returning
* from a power-down state.
*/
void Chip_ADC_StartCalibration(LPC_ADC_T *pADC);
/**
* @brief Helper function for safely setting ADC sequencer register bits
* @param pADC : The base of ADC peripheral on the chip
* @param seqIndex : Sequencer to set bits for
* @param bits : Or'ed bits of a sequencer register to set
* @return Nothing
* @note This function will safely set the ADC sequencer register bits
* while maintaining bits 20..25 as 0, regardless of the read state of those bits.
*/
void Chip_ADC_SetSequencerBits(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex, uint32_t bits);
/**
* @brief Helper function for safely clearing ADC sequencer register bits
* @param pADC : The base of ADC peripheral on the chip
* @param seqIndex : Sequencer to clear bits for
* @param bits : Or'ed bits of a sequencer register to clear
* @return Nothing
* @note This function will safely clear the ADC sequencer register bits
* while maintaining bits 20..25 as 0, regardless of the read state of those bits.
*/
void Chip_ADC_ClearSequencerBits(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex, uint32_t bits);
/**
* @brief Sets up ADC conversion sequencer A or B
* @param pADC : The base of ADC peripheral on the chip
* @param seqIndex : Sequencer to setup
* @param options : OR'ed Sequencer options to setup (see notes)
* @return Nothing
* @note Sets up sequencer options for a conversion sequence. This function
* should be used to setup the selected channels for the sequence, the sequencer
* trigger, the trigger polarity, synchronization bypass, priority, and mode. All
* options are passed to the functions as a OR'ed list of values. This function will
* disable/clear the sequencer start/burst/single step/enable if they are enabled.<br>
* Select the channels by OR'ing in one or more ADC_SEQ_CTRL_CHANSEL(ch) values.<br>
* Select the hardware trigger by OR'ing in one ADC_SEQ_CTRL_HWTRIG_* value.<br>
* Select a positive edge hardware trigger by OR'ing in ADC_SEQ_CTRL_HWTRIG_POLPOS.<br>
* Select trigger bypass synchronisation by OR'ing in ADC_SEQ_CTRL_HWTRIG_SYNCBYPASS.<br>
* Select ADC single step on trigger/start by OR'ing in ADC_SEQ_CTRL_SINGLESTEP.<br>
* Select higher priority conversion on the other sequencer by OR'ing in ADC_SEQ_CTRL_LOWPRIO.<br>
* Select end of seqeuence instead of end of conversion interrupt by OR'ing in ADC_SEQ_CTRL_MODE_EOS.<br>
* Example for setting up sequencer A (channels 0-2, trigger on high edge of PIO0_2, interrupt on end of sequence):<br>
* Chip_ADC_SetupSequencer(LPC_ADC, ADC_SEQA_IDX, (
* ADC_SEQ_CTRL_CHANSEL(0) | ADC_SEQ_CTRL_CHANSEL(1) | ADC_SEQ_CTRL_CHANSEL(2) |
* ADC_SEQ_CTRL_HWTRIG_PIO0_2 | ADC_SEQ_CTRL_HWTRIG_POLPOS | ADC_SEQ_CTRL_MODE_EOS));
*/
STATIC INLINE void Chip_ADC_SetupSequencer(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex, uint32_t options)
{
pADC->SEQ_CTRL[seqIndex] = options;
}
/**
* @brief Get sequenceX control register value
* @param pADC : The base of ADC peripheral on the chip
* @return seq_ctrl : sequenceX_control register value
*/
STATIC INLINE uint32_t Chip_ADC_GetSequencerCtrl(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex)
{
return ( pADC->SEQ_CTRL[seqIndex] );
}
/**
* @brief Enables a sequencer
* @param pADC : The base of ADC peripheral on the chip
* @param seqIndex : Sequencer to enable
* @return Nothing
*/
STATIC INLINE void Chip_ADC_EnableSequencer(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex)
{
Chip_ADC_SetSequencerBits(pADC, seqIndex, ADC_SEQ_CTRL_SEQ_ENA);
}
/**
* @brief Disables a sequencer
* @param pADC : The base of ADC peripheral on the chip
* @param seqIndex : Sequencer to disable
* @return Nothing
*/
STATIC INLINE void Chip_ADC_DisableSequencer(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex)
{
Chip_ADC_ClearSequencerBits(pADC, seqIndex, ADC_SEQ_CTRL_SEQ_ENA);
}
/**
* @brief Forces a sequencer trigger event (software trigger of ADC)
* @param pADC : The base of ADC peripheral on the chip
* @param seqIndex : Sequencer to start
* @return Nothing
* @note This function sets the START bit for the sequencer to force a
* single conversion sequence or a single step conversion. START and BURST bits can not
* be set at the same time, thus, BURST bit will be cleared.
*/
STATIC INLINE void Chip_ADC_StartSequencer(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex)
{
Chip_ADC_ClearSequencerBits(pADC, seqIndex, ADC_SEQ_CTRL_BURST);
Chip_ADC_SetSequencerBits(pADC, seqIndex, ADC_SEQ_CTRL_START);
}
/**
* @brief Starts sequencer burst mode
* @param pADC : The base of ADC peripheral on the chip
* @param seqIndex : Sequencer to start burst on
* @return Nothing
* @note This function sets the BURST bit for the sequencer to force
* continuous conversion. Use Chip_ADC_StopBurstSequencer() to stop the
* ADC burst sequence. START and BURST bits can not be set at the same time, thus,
* START bit will be cleared.
*/
STATIC INLINE void Chip_ADC_StartBurstSequencer(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex)
{
/* START and BURST bits can not be set at the same time. */
Chip_ADC_ClearSequencerBits(pADC, seqIndex, ADC_SEQ_CTRL_START);
Chip_ADC_SetSequencerBits(pADC, seqIndex, ADC_SEQ_CTRL_BURST);
}
/**
* @brief Stops sequencer burst mode
* @param pADC : The base of ADC peripheral on the chip
* @param seqIndex : Sequencer to stop burst on
* @return Nothing
*/
STATIC INLINE void Chip_ADC_StopBurstSequencer(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex)
{
Chip_ADC_ClearSequencerBits(pADC, seqIndex, ADC_SEQ_CTRL_BURST);
}
/** ADC sequence global data register threshold comparison range enumerations */
typedef enum {
ADC_DR_THCMPRANGE_INRANGE,
ADC_DR_THCMPRANGE_RESERVED,
ADC_DR_THCMPRANGE_BELOW,
ADC_DR_THCMPRANGE_ABOVE
} ADC_DR_THCMPRANGE_T;
/** ADC sequence global data register threshold comparison cross enumerations */
typedef enum {
ADC_DR_THCMPCROSS_NOCROSS,
ADC_DR_THCMPCROSS_RESERVED,
ADC_DR_THCMPCROSS_DOWNWARD,
ADC_DR_THCMPCROSS_UPWARD
} ADC_DR_THCMPCROSS_T;
/**
* @brief Read a ADC sequence global data register
* @param pADC : The base of ADC peripheral on the chip
* @param seqIndex : Sequencer to read
* @return Current raw value of the ADC sequence A or B global data register
* @note This function returns the raw value of the data register and clears
* the overrun and datavalid status for the register. Once this register is read,
* the following functions can be used to parse the raw value:<br>
* uint32_t adcDataRawValue = Chip_ADC_GetGlobalDataReg(LPC_ADC, ADC_SEQA_IDX); // Get raw value
* uint32_t adcDataValue = ADC_DR_RESULT(adcDataRawValue); // Aligned and masked ADC data value
* ADC_DR_THCMPRANGE_T adcRange = (ADC_DR_THCMPRANGE_T) ADC_DR_THCMPRANGE(adcDataRawValue); // Sample range compared to threshold low/high
* ADC_DR_THCMPCROSS_T adcRange = (ADC_DR_THCMPCROSS_T) ADC_DR_THCMPCROSS(adcDataRawValue); // Sample cross compared to threshold low
* uint32_t channel = ADC_DR_CHANNEL(adcDataRawValue); // ADC channel for this sample/data
* bool adcDataOverrun = (bool) ((adcDataRawValue & ADC_DR_OVERRUN) != 0); // Data overrun flag
* bool adcDataValid = (bool) ((adcDataRawValue & ADC_SEQ_GDAT_DATAVALID) != 0); // Data valid flag
*/
STATIC INLINE uint32_t Chip_ADC_GetGlobalDataReg(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex)
{
return pADC->SEQ_GDAT[seqIndex];
}
/**
* @brief Read a ADC data register
* @param pADC : The base of ADC peripheral on the chip
* @param index : Data register to read, 0-11
* @return Current raw value of the ADC data register
* @note This function returns the raw value of the data register and clears
* the overrun and datavalid status for the register. Once this register is read,
* the following functions can be used to parse the raw value:<br>
* uint32_t adcDataRawValue = Chip_ADC_GetDataReg(LPC_ADC, ADC_MAX_CHANNEL_NUM); // Get raw value
* uint32_t adcDataValue = ADC_DR_RESULT(adcDataRawValue); // Aligned and masked ADC data value
* ADC_DR_THCMPRANGE_T adcRange = (ADC_DR_THCMPRANGE_T) ADC_DR_THCMPRANGE(adcDataRawValue); // Sample range compared to threshold low/high
* ADC_DR_THCMPCROSS_T adcRange = (ADC_DR_THCMPCROSS_T) ADC_DR_THCMPCROSS(adcDataRawValue); // Sample cross compared to threshold low
* uint32_t channel = ADC_DR_CHANNEL(adcDataRawValue); // ADC channel for this sample/data
* bool adcDataOverrun = (bool) ((adcDataRawValue & ADC_DR_OVERRUN) != 0); // Data overrun flag
* bool adcDataValid = (bool) ((adcDataRawValue & ADC_SEQ_GDAT_DATAVALID) != 0); // Data valid flag
*/
STATIC INLINE uint32_t Chip_ADC_GetDataReg(LPC_ADC_T *pADC, uint8_t index)
{
return pADC->DAT[index];
}
/**
* @brief Set Threshold low value in ADC
* @param pADC : The base of ADC peripheral on the chip
* @param thrnum : Threshold register value (1 for threshold register 1, 0 for threshold register 0)
* @param value : Threshold low data value (should be 12-bit value)
* @return None
*/
STATIC INLINE void Chip_ADC_SetThrLowValue(LPC_ADC_T *pADC, uint8_t thrnum, uint16_t value)
{
pADC->THR_LOW[thrnum] = (((uint32_t) value) << ADC_THR_VAL_POS);
}
/**
* @brief Set Threshold high value in ADC
* @param pADC : The base of ADC peripheral on the chip
* @param thrnum : Threshold register value (1 for threshold register 1, 0 for threshold register 0)
* @param value : Threshold high data value (should be 12-bit value)
* @return None
*/
STATIC INLINE void Chip_ADC_SetThrHighValue(LPC_ADC_T *pADC, uint8_t thrnum, uint16_t value)
{
pADC->THR_HIGH[thrnum] = (((uint32_t) value) << ADC_THR_VAL_POS);
}
/**
* @brief Select threshold 0 values for comparison for selected channels
* @param pADC : The base of ADC peripheral on the chip
* @param channels : An OR'ed value of one or more ADC_THRSEL_CHAN_SEL_THR1(ch) values
* @return None
* @note Select multiple channels to use the threshold 0 comparison.<br>
* Example:<br>
* Chip_ADC_SelectTH0Channels(LPC_ADC, (ADC_THRSEL_CHAN_SEL_THR1(1) | ADC_THRSEL_CHAN_SEL_THR1(2))); // Selects channels 1 and 2 for threshold 0
*/
void Chip_ADC_SelectTH0Channels(LPC_ADC_T *pADC, uint32_t channels);
/**
* @brief Select threshold 1 value for comparison for selected channels
* @param pADC : The base of ADC peripheral on the chip
* @param channels : An OR'ed value of one or more ADC_THRSEL_CHAN_SEL_THR1(ch) values
* @return None
* @note Select multiple channels to use the 1 threshold comparison.<br>
* Example:<br>
* Chip_ADC_SelectTH1Channels(LPC_ADC, (ADC_THRSEL_CHAN_SEL_THR1(4) | ADC_THRSEL_CHAN_SEL_THR1(5))); // Selects channels 4 and 5 for 1 threshold
*/
void Chip_ADC_SelectTH1Channels(LPC_ADC_T *pADC, uint32_t channels);
/**
* @brief Enable interrupts in ADC (sequencers A/B and overrun)
* @param pADC : The base of ADC peripheral on the chip
* @param intMask : Interrupt values to be enabled (see notes)
* @return None
* @note Select one or more OR'ed values of ADC_INTEN_SEQA_ENABLE,
* ADC_INTEN_SEQB_ENABLE, and ADC_INTEN_OVRRUN_ENABLE to enable the
* specific ADC interrupts.
*/
void Chip_ADC_EnableInt(LPC_ADC_T *pADC, uint32_t intMask);
/**
* @brief Disable interrupts in ADC (sequencers A/B and overrun)
* @param pADC : The base of ADC peripheral on the chip
* @param intMask : Interrupt values to be disabled (see notes)
* @return None
* @note Select one or more OR'ed values of ADC_INTEN_SEQA_ENABLE,
* ADC_INTEN_SEQB_ENABLE, and ADC_INTEN_OVRRUN_ENABLE to disable the
* specific ADC interrupts.
*/
void Chip_ADC_DisableInt(LPC_ADC_T *pADC, uint32_t intMask);
/** Threshold interrupt event options */
typedef enum {
ADC_INTEN_THCMP_DISABLE,
ADC_INTEN_THCMP_OUTSIDE,
ADC_INTEN_THCMP_CROSSING,
} ADC_INTEN_THCMP_T;
/**
* @brief Enable a threshold event interrupt in ADC
* @param pADC : The base of ADC peripheral on the chip
* @param ch : ADC channel to set threshold inetrrupt for, 1-8
* @param thInt : Selected threshold interrupt type
* @return None
*/
void Chip_ADC_SetThresholdInt(LPC_ADC_T *pADC, uint8_t ch, ADC_INTEN_THCMP_T thInt);
/**
* @brief Get flags register in ADC
* @param pADC : The base of ADC peripheral on the chip
* @return Flags register value (ORed ADC_FLAG* values)
* @note Mask the return value of this function with the ADC_FLAGS_*
* definitions to determine the overall ADC interrupt events.<br>
* Example:<br>
* if (Chip_ADC_GetFlags(LPC_ADC) & ADC_FLAGS_THCMP_MASK(3) // Check of threshold comp status for ADC channel 3
*/
STATIC INLINE uint32_t Chip_ADC_GetFlags(LPC_ADC_T *pADC)
{
return pADC->FLAGS;
}
/**
* @brief Clear flags register in ADC
* @param pADC : The base of ADC peripheral on the chip
* @param flags : An Or'ed values of ADC_FLAGS_* values to clear
* @return Flags register value (ORed ADC_FLAG* values)
*/
STATIC INLINE void Chip_ADC_ClearFlags(LPC_ADC_T *pADC, uint32_t flags)
{
pADC->FLAGS = flags;
}
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __ADC_540XX_H_ */

View File

@@ -0,0 +1,208 @@
/*
* @brief LPC540XX ADC driver (clock enable/disable only)
*
* @note
* Copyright(C) NXP Semiconductors, 2012
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licenser disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "chip.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
/* Set ADC interrupt bits (safe) */
void Chip_ADC_SetIntBits(LPC_ADC_T *pADC, uint32_t intMask)
{
uint32_t temp;
/* Read and write values may not be the same, write 0 to undefined bits */
temp = pADC->INTEN & 0x07FFFFFF;
pADC->INTEN = temp | intMask;
}
/* Clear ADC interrupt bits (safe) */
void Chip_ADC_ClearIntBits(LPC_ADC_T *pADC, uint32_t intMask)
{
uint32_t temp;
/* Read and write values may not be the same, write 0 to undefined bits */
temp = pADC->INTEN & 0x07FFFFFF;
pADC->INTEN = temp & ~intMask;
}
/* Set ADC threshold selection bits (safe) */
void Chip_ADC_SetTHRSELBits(LPC_ADC_T *pADC, uint32_t mask)
{
uint32_t temp;
/* Read and write values may not be the same, write 0 to undefined bits */
temp = pADC->CHAN_THRSEL & 0x00000FFF;
pADC->CHAN_THRSEL = temp | mask;
}
/* Clear ADC threshold selection bits (safe) */
void Chip_ADC_ClearTHRSELBits(LPC_ADC_T *pADC, uint32_t mask)
{
uint32_t temp;
/* Read and write values may not be the same, write 0 to undefined bits */
temp = pADC->CHAN_THRSEL & 0x00000FFF;
pADC->CHAN_THRSEL = temp & ~mask;
}
/*****************************************************************************
* Public functions
****************************************************************************/
/* Initialize the ADC peripheral */
void Chip_ADC_Init(LPC_ADC_T *pADC, uint32_t flags)
{
/* Power up ADC and enable ADC base clock */
Chip_SYSCON_PowerUp(SYSCON_PDRUNCFG_PD_ADC0 | SYSCON_PDRUNCFG_PD_VDDA_ENA | SYSCON_PDRUNCFG_PD_VREFP);
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_ADC0);
/* Disable ADC interrupts */
pADC->INTEN = 0;
/* Set ADC control options */
pADC->CTRL = flags;
}
/* Shutdown ADC */
void Chip_ADC_DeInit(LPC_ADC_T *pADC)
{
pADC->INTEN = 0;
pADC->CTRL = 0;
/* Stop ADC clock and then power down ADC */
Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_ADC0);
Chip_SYSCON_PowerDown(SYSCON_PDRUNCFG_PD_ADC0 | SYSCON_PDRUNCFG_PD_VDDA_ENA | SYSCON_PDRUNCFG_PD_VREFP);
}
/* Start ADC calibration */
void Chip_ADC_StartCalibration(LPC_ADC_T *pADC)
{
/* Set calibration mode */
pADC->CTRL |= ADC_CR_CALMODEBIT;
/* Clear ASYNC bit */
pADC->CTRL &= ~ADC_CR_ASYNC_MODE;
/* Setup ADC for about 500KHz (per UM) */
Chip_ADC_SetClockRate(pADC, 500000);
/* Clearn low power bit */
pADC->CTRL &= ~ADC_CR_LPWRMODEBIT;
/* Calibration is only complete when ADC_CR_CALMODEBIT bit has cleared */
}
/* Set ADC clock rate */
void Chip_ADC_SetClockRate(LPC_ADC_T *pADC, uint32_t rate)
{
uint32_t div;
/* Get ADC clock source to determine base ADC rate. IN sychronous mode,
the ADC base clock comes from the system clock. In ASYNC mode, it
comes from the ASYNC ADC clock and this function doesn't work. */
div = Chip_Clock_GetSystemClockRate() / rate;
if (div == 0) {
div = 1;
}
Chip_ADC_SetDivider(pADC, (uint8_t) div - 1);
}
/* Helper function for safely setting ADC sequencer register bits */
void Chip_ADC_SetSequencerBits(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex, uint32_t bits)
{
uint32_t temp;
/* Read sequencer register and mask off bits 20..25 */
temp = pADC->SEQ_CTRL[seqIndex] & ~(0x3F << 20);
/* OR in passed bits */
pADC->SEQ_CTRL[seqIndex] = temp | bits;
}
/* Helper function for safely clearing ADC sequencer register bits */
void Chip_ADC_ClearSequencerBits(LPC_ADC_T *pADC, ADC_SEQ_IDX_T seqIndex, uint32_t bits)
{
uint32_t temp;
/* Read sequencer register and mask off bits 20..25 */
temp = pADC->SEQ_CTRL[seqIndex] & ~(0x3F << 20);
/* OR in passed bits */
pADC->SEQ_CTRL[seqIndex] = temp & ~bits;
}
/* Enable interrupts in ADC (sequencers A/B and overrun) */
void Chip_ADC_EnableInt(LPC_ADC_T *pADC, uint32_t intMask)
{
Chip_ADC_SetIntBits(pADC, intMask);
}
/* Disable interrupts in ADC (sequencers A/B and overrun) */
void Chip_ADC_DisableInt(LPC_ADC_T *pADC, uint32_t intMask)
{
Chip_ADC_ClearIntBits(pADC, intMask);
}
/* Enable a threshold event interrupt in ADC */
void Chip_ADC_SetThresholdInt(LPC_ADC_T *pADC, uint8_t ch, ADC_INTEN_THCMP_T thInt)
{
int shiftIndex = 3 + (ch * 2);
/* Clear current bits first */
Chip_ADC_ClearIntBits(pADC, (ADC_INTEN_CMP_MASK << shiftIndex));
/* Set new threshold interrupt type */
Chip_ADC_SetIntBits(pADC, ((uint32_t) thInt << shiftIndex));
}
/* Select threshold 0 values for comparison for selected channels */
void Chip_ADC_SelectTH0Channels(LPC_ADC_T *pADC, uint32_t channels)
{
Chip_ADC_ClearTHRSELBits(pADC, channels);
}
/* Select threshold 1 value for comparison for selected channels */
void Chip_ADC_SelectTH1Channels(LPC_ADC_T *pADC, uint32_t channels)
{
Chip_ADC_SetTHRSELBits(pADC, channels);
}

View File

@@ -0,0 +1,171 @@
/*
* @brief LPC540XX DMA chip driver
*
* @note
* Copyright(C) NXP Semiconductors, 2013
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "chip.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
/* DMA SRAM table - this can be optionally used with the Chip_DMA_SetSRAMBase()
function if a DMA SRAM table is needed. This table is correctly aligned for
the DMA controller. */
#if defined(__CC_ARM)
/* Keil alignement to 512 bytes */
__align(512) DMA_CHDESC_T Chip_DMA_Table[MAX_DMA_CHANNEL];
#endif /* defined (__CC_ARM) */
/* IAR support */
#if defined(__ICCARM__)
/* IAR EWARM alignement to 512 bytes */
#pragma data_alignment=512
DMA_CHDESC_T Chip_DMA_Table[MAX_DMA_CHANNEL];
#endif /* defined (__ICCARM__) */
#if defined( __GNUC__ )
/* GNU alignement to 512 bytes */
DMA_CHDESC_T Chip_DMA_Table[MAX_DMA_CHANNEL] __attribute__ ((aligned(512)));
#endif /* defined (__GNUC__) */
/*****************************************************************************
* Private functions
****************************************************************************/
/*****************************************************************************
* Public functions
****************************************************************************/
/* Set DMA transfer register interrupt bits (safe) */
void Chip_DMA_SetTranBits(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t mask)
{
uint32_t temp;
/* Read and write values may not be the same, write 0 to
undefined bits */
temp = pDMA->DMACH[ch].XFERCFG & ~0xFC000CC0;
pDMA->DMACH[ch].XFERCFG = temp | mask;
}
/* Clear DMA transfer register interrupt bits (safe) */
void Chip_DMA_ClearTranBits(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t mask)
{
uint32_t temp;
/* Read and write values may not be the same, write 0 to
undefined bits */
temp = pDMA->DMACH[ch].XFERCFG & ~0xFC000CC0;
pDMA->DMACH[ch].XFERCFG = temp & ~mask;
}
/* Update the transfer size in an existing DMA channel transfer configuration */
void Chip_DMA_SetupChannelTransferSize(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t trans)
{
Chip_DMA_ClearTranBits(pDMA, ch, (0x3FF << 16));
Chip_DMA_SetTranBits(pDMA, ch, DMA_XFERCFG_XFERCOUNT(trans));
}
/* Sets up a DMA channel with the passed DMA transfer descriptor */
bool Chip_DMA_SetupTranChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch, DMA_CHDESC_T *desc)
{
bool good = false;
DMA_CHDESC_T *pDesc = (DMA_CHDESC_T *) pDMA->SRAMBASE;
if ((Chip_DMA_GetActiveChannels(pDMA) & (1 << ch)) == 0) {
/* Channel is not active, so update the descriptor */
pDesc[ch] = *desc;
good = true;
}
return good;
}
/**
* Initialize DMA parameters specific to a channel
*
* @param channel
* @param src_address
* @param dst_address
* @param xfr_width
* @param length_bytes
*/
void Chip_DMA_InitChannel( DMA_CHID_T channel, uint32_t src_address, uint32_t src_increment,
uint32_t dst_address, uint32_t dst_increment, uint32_t xfr_width, uint32_t length_bytes, uint32_t priority)
{
Chip_DMA_EnableChannel(LPC_DMA, channel);
Chip_DMA_EnableIntChannel(LPC_DMA, channel);
Chip_DMA_SetupChannelConfig(LPC_DMA, channel, DMA_CFG_PERIPHREQEN |
DMA_CFG_CHPRIORITY(priority));
if (src_increment != DMA_XFERCFG_SRCINC_0) {
Chip_DMA_Table[channel].source = DMA_ADDR((src_address + length_bytes)
- (1UL << xfr_width));
} else {
Chip_DMA_Table[channel].source = DMA_ADDR(src_address);
}
if (dst_increment != DMA_XFERCFG_DSTINC_0) {
Chip_DMA_Table[channel].dest = DMA_ADDR((dst_address + length_bytes)
- (1UL << xfr_width));
} else {
Chip_DMA_Table[channel].dest = DMA_ADDR(dst_address);
}
Chip_DMA_Table[channel].next = DMA_ADDR(0);
}
/**
* Start the DMA transfer
*
* @param channel
* @param src_increment
* @param dst_increment
* @param xfr_width
* @param length_bytes
*/
void Chip_DMA_StartTransfer(DMA_CHID_T channel, uint32_t src_increment, uint32_t dst_increment, uint32_t xfr_width, uint32_t length_bytes)
{
uint32_t xfer_count;
/* Calculate transfer_count ( length in terms of transfers) */
xfer_count = (xfr_width == DMA_XFERCFG_WIDTH_8) ? length_bytes :
(xfr_width == DMA_XFERCFG_WIDTH_16) ? (length_bytes >> 1) :
(length_bytes >> 2);
Chip_DMA_SetupChannelTransfer(LPC_DMA, channel,
(DMA_XFERCFG_CFGVALID | DMA_XFERCFG_SETINTA | DMA_XFERCFG_SWTRIG |
xfr_width | src_increment | dst_increment |
DMA_XFERCFG_XFERCOUNT(xfer_count)));
}

View File

@@ -0,0 +1,714 @@
/*
* @brief LPC540XX Cyclic Redundancy Check (CRC) Engine driver
*
* @note
* Copyright(C) NXP Semiconductors, 2012
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licenser disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#ifndef __DMA_540XX_H
#define __DMA_540XX_H
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup DMA_540XX CHIP: LPC540XX DMA Engine driver
* @ingroup CHIP_540XX_Drivers
* @{
*/
/** @defgroup DMA_11U6X CHIP: LPC11u6x DMA Controller driver
* @ingroup CHIP_11U6X_Drivers
* @{
*/
/**
* @brief DMA Controller shared registers structure
*/
typedef struct { /*!< DMA shared registers structure */
__IO uint32_t ENABLESET; /*!< DMA Channel Enable read and Set for all DMA channels */
__I uint32_t RESERVED0;
__O uint32_t ENABLECLR; /*!< DMA Channel Enable Clear for all DMA channels */
__I uint32_t RESERVED1;
__I uint32_t ACTIVE; /*!< DMA Channel Active status for all DMA channels */
__I uint32_t RESERVED2;
__I uint32_t BUSY; /*!< DMA Channel Busy status for all DMA channels */
__I uint32_t RESERVED3;
__IO uint32_t ERRINT; /*!< DMA Error Interrupt status for all DMA channels */
__I uint32_t RESERVED4;
__IO uint32_t INTENSET; /*!< DMA Interrupt Enable read and Set for all DMA channels */
__I uint32_t RESERVED5;
__O uint32_t INTENCLR; /*!< DMA Interrupt Enable Clear for all DMA channels */
__I uint32_t RESERVED6;
__IO uint32_t INTA; /*!< DMA Interrupt A status for all DMA channels */
__I uint32_t RESERVED7;
__IO uint32_t INTB; /*!< DMA Interrupt B status for all DMA channels */
__I uint32_t RESERVED8;
__O uint32_t SETVALID; /*!< DMA Set ValidPending control bits for all DMA channels */
__I uint32_t RESERVED9;
__O uint32_t SETTRIG; /*!< DMA Set Trigger control bits for all DMA channels */
__I uint32_t RESERVED10;
__O uint32_t ABORT; /*!< DMA Channel Abort control for all DMA channels */
} LPC_DMA_COMMON_T;
/**
* @brief DMA Controller shared registers structure
*/
typedef struct { /*!< DMA channel register structure */
__IO uint32_t CFG; /*!< DMA Configuration register */
__I uint32_t CTLSTAT; /*!< DMA Control and status register */
__IO uint32_t XFERCFG; /*!< DMA Transfer configuration register */
__I uint32_t RESERVED;
} LPC_DMA_CHANNEL_T;
/* DMA channel mapping - each channel is mapped to an individual peripheral
and direction or a DMA imput mux trigger */
typedef enum {
DMAREQ_UART0_RX = 0, /*!< UART00 receive DMA channel */
DMA_CH0 = DMAREQ_UART0_RX,
DMAREQ_UART0_TX, /*!< UART0 transmit DMA channel */
DMA_CH1 = DMAREQ_UART0_TX,
DMAREQ_UART1_RX, /*!< UART1 receive DMA channel */
DMA_CH2 = DMAREQ_UART1_RX,
DMAREQ_UART1_TX, /*!< UART1 transmit DMA channel */
DMA_CH3 = DMAREQ_UART1_TX,
DMAREQ_UART2_RX, /*!< UART2 receive DMA channel */
DMA_CH4 = DMAREQ_UART2_RX,
DMAREQ_UART2_TX, /*!< UART2 transmit DMA channel */
DMA_CH5 = DMAREQ_UART2_TX,
DMAREQ_UART3_RX, /*!< UART3 receive DMA channel */
DMA_CH6 = DMAREQ_UART3_RX,
DMAREQ_UART3_TX, /*!< UART3 transmit DMA channel */
DMA_CH7 = DMAREQ_UART3_TX,
DMAREQ_SPI0_RX, /*!< SPI0 receive DMA channel */
DMA_CH8 = DMAREQ_SPI0_RX,
DMAREQ_SPI0_TX, /*!< SPI0 transmit DMA channel */
DMA_CH9 = DMAREQ_SPI0_TX,
DMAREQ_SPI1_RX, /*!< SPI1 receive DMA channel */
DMA_CH10 = DMAREQ_SPI1_RX,
DMAREQ_SPI1_TX, /*!< SPI1 transmit DMA channel */
DMA_CH11 = DMAREQ_SPI1_TX,
DMAREQ_I2C0_SLAVE, /*!< I2C0 Slave DMA channel */
DMA_CH12 = DMAREQ_I2C0_SLAVE,
DMAREQ_I2C0_MASTER, /*!< I2C0 Master DMA channel */
DMA_CH13 = DMAREQ_I2C0_MASTER,
DMAREQ_I2C1_SLAVE, /*!< I2C1 Slave DMA channel */
DMA_CH14 = DMAREQ_I2C1_SLAVE,
DMAREQ_I2C1_MASTER, /*!< I2C1 Master DMA channel */
DMA_CH15 = DMAREQ_I2C1_MASTER,
DMAREQ_I2C2_SLAVE, /*!< I2C2 Slave DMA channel */
DMA_CH16 = DMAREQ_I2C2_SLAVE,
DMAREQ_I2C2_MASTER, /*!< I2C2 Master DMA channel */
DMA_CH17 = DMAREQ_I2C2_MASTER,
DMAREQ_I2C0_MONITOR, /*!< I2C0 Monitor DMA channel */
DMA_CH18 = DMAREQ_I2C0_MONITOR,
DMAREQ_I2C1_MONITOR, /*!< I2C1 Monitor DMA channel */
DMA_CH19 = DMAREQ_I2C1_MONITOR,
DMAREQ_I2C2_MONITOR, /*!< I2C2 Monitor DMA channel */
DMA_CH20 = DMAREQ_I2C2_MONITOR,
RESERVED_SPARE_DMA,
DMA_CH21 = RESERVED_SPARE_DMA
} DMA_CHID_T;
/* On LPC540XX, Max DMA channel is 22 */
#define MAX_DMA_CHANNEL (DMA_CH21+1)
/**
* @brief DMA Controller register block structure
*/
typedef struct { /*!< DMA Structure */
__IO uint32_t CTRL; /*!< DMA control register */
__I uint32_t INTSTAT; /*!< DMA Interrupt status register */
__IO uint32_t SRAMBASE; /*!< DMA SRAM address of the channel configuration table */
__I uint32_t RESERVED2[5];
LPC_DMA_COMMON_T DMACOMMON[1]; /*!< DMA shared channel (common) registers */
__I uint32_t RESERVED0[225];
LPC_DMA_CHANNEL_T DMACH[MAX_DMA_CHANNEL]; /*!< DMA channel registers */
} LPC_DMA_T;
/** @defgroup DMA_COMMON_540XX CHIP: LPC540XX DMA Controller driver common functions
* @{
*/
/**
* @brief Initialize DMA controller
* @param pDMA : The base of DMA controller on the chip
* @return Nothing
*/
STATIC INLINE void Chip_DMA_Init(LPC_DMA_T *pDMA)
{
(void) pDMA;
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_DMA);
// FIXME - PRESETCTRL reset needed? Currently not defined
}
/**
* @brief De-Initialize DMA controller
* @param pDMA : The base of DMA controller on the chip
* @return Nothing
*/
STATIC INLINE void Chip_DMA_DeInit(LPC_DMA_T *pDMA)
{
(void) pDMA;
Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_DMA);
}
/**
* @brief Enable DMA controller
* @param pDMA : The base of DMA controller on the chip
* @return Nothing
*/
STATIC INLINE void Chip_DMA_Enable(LPC_DMA_T *pDMA)
{
pDMA->CTRL = 1;
}
/**
* @brief Disable DMA controller
* @param pDMA : The base of DMA controller on the chip
* @return Nothing
*/
STATIC INLINE void Chip_DMA_Disable(LPC_DMA_T *pDMA)
{
pDMA->CTRL = 0;
}
/* DMA interrupt status bits (common) */
#define DMA_INTSTAT_ACTIVEINT 0x2 /*!< Summarizes whether any enabled interrupts are pending */
#define DMA_INTSTAT_ACTIVEERRINT 0x4 /*!< Summarizes whether any error interrupts are pending */
/**
* @brief Get pending interrupt or error interrupts
* @param pDMA : The base of DMA controller on the chip
* @return An Or'ed value of DMA_INTSTAT_* types
* @note If any DMA channels have an active interrupt or error interrupt
* pending, this functional will a common status that applies to all
* channels.
*/
STATIC INLINE uint32_t Chip_DMA_GetIntStatus(LPC_DMA_T *pDMA)
{
return pDMA->INTSTAT;
}
/**
* @brief Set DMA controller SRAM base address
* @param pDMA : The base of DMA controller on the chip
* @param base : The base address where the DMA descriptors will be stored
* @return Nothing
* @note A 256 byte block of memory aligned on a 256 byte boundary must be
* provided for this function. It sets the base address used for
* DMA descriptor table (16 descriptors total that use 16 bytes each).<br>
*
* A pre-defined table with correct alignment can be used for this
* function by calling Chip_DMA_SetSRAMBase(LPC_DMA, DMA_ADDR(Chip_DMA_Table));
*/
STATIC INLINE void Chip_DMA_SetSRAMBase(LPC_DMA_T *pDMA, uint32_t base)
{
pDMA->SRAMBASE = base;
}
/**
* @brief Returns DMA controller SRAM base address
* @param pDMA : The base of DMA controller on the chip
* @return The base address where the DMA descriptors are stored
*/
STATIC INLINE uint32_t Chip_DMA_GetSRAMBase(LPC_DMA_T *pDMA)
{
return pDMA->SRAMBASE;
}
/**
* @}
*/
/** @defgroup DMA_COMMON_540XX CHIP: LPC540XX DMA Controller driver common channel functions
* @{
*/
/**
* @brief Enables a single DMA channel
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
*/
STATIC INLINE void Chip_DMA_EnableChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
pDMA->DMACOMMON[0].ENABLESET = (1 << ch);
}
/**
* @brief Disables a single DMA channel
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
*/
STATIC INLINE void Chip_DMA_DisableChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
pDMA->DMACOMMON[0].ENABLECLR = (1 << ch);
}
/**
* @brief Returns all enabled DMA channels
* @param pDMA : The base of DMA controller on the chip
* @return An Or'ed value of all enabled DMA channels (0 - 15)
* @note A high values in bits 0 .. 15 in the return values indicates
* that the channel for that bit (bit 0 = channel 0, bit 1 -
* channel 1, etc.) is enabled. A low state is disabled.
*/
STATIC INLINE uint32_t Chip_DMA_GetEnabledChannels(LPC_DMA_T *pDMA)
{
return pDMA->DMACOMMON[0].ENABLESET;
}
/**
* @brief Returns all active DMA channels
* @param pDMA : The base of DMA controller on the chip
* @return An Or'ed value of all active DMA channels (0 - 15)
* @note A high values in bits 0 .. 15 in the return values indicates
* that the channel for that bit (bit 0 = channel 0, bit 1 -
* channel 1, etc.) is active. A low state is inactive. A active
* channel indicates that a DMA operation has been started but
* not yet fully completed.
*/
STATIC INLINE uint32_t Chip_DMA_GetActiveChannels(LPC_DMA_T *pDMA)
{
return pDMA->DMACOMMON[0].ACTIVE;
}
/**
* @brief Returns all busy DMA channels
* @param pDMA : The base of DMA controller on the chip
* @return An Or'ed value of all busy DMA channels (0 - 15)
* @note A high values in bits 0 .. 15 in the return values indicates
* that the channel for that bit (bit 0 = channel 0, bit 1 -
* channel 1, etc.) is busy. A low state is not busy. A DMA
* channel is considered busy when there is any operation
* related to that channel in the DMA controller<65>s internal
* pipeline.
*/
STATIC INLINE uint32_t Chip_DMA_GetBusyChannels(LPC_DMA_T *pDMA)
{
return pDMA->DMACOMMON[0].BUSY;
}
/**
* @brief Returns pending error interrupt status for all DMA channels
* @param pDMA : The base of DMA controller on the chip
* @return An Or'ed value of all channels (0 - 15) error interrupt status
* @note A high values in bits 0 .. 15 in the return values indicates
* that the channel for that bit (bit 0 = channel 0, bit 1 -
* channel 1, etc.) has a pending error interrupt. A low state
* indicates no error interrupt.
*/
STATIC INLINE uint32_t Chip_DMA_GetErrorIntChannels(LPC_DMA_T *pDMA)
{
return pDMA->DMACOMMON[0].ERRINT;
}
/**
* @brief Clears a pending error interrupt status for a single DMA channel
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
*/
STATIC INLINE void Chip_DMA_ClearErrorIntChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
pDMA->DMACOMMON[0].ERRINT = (1 << ch);
}
/**
* @brief Enables a single DMA channel's interrupt used in common DMA interrupt
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
*/
STATIC INLINE void Chip_DMA_EnableIntChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
pDMA->DMACOMMON[0].INTENSET = (1 << ch);
}
/**
* @brief Disables a single DMA channel's interrupt used in common DMA interrupt
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
*/
STATIC INLINE void Chip_DMA_DisableIntChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
pDMA->DMACOMMON[0].INTENCLR = (1 << ch);
}
/**
* @brief Returns all enabled interrupt channels
* @param pDMA : The base of DMA controller on the chip
* @return Nothing
* @note A high values in bits 0 .. 15 in the return values indicates
* that the channel for that bit (bit 0 = channel 0, bit 1 -
* channel 1, etc.) has an enabled interrupt for the channel.
* A low state indicates that the DMA channel will not contribute
* to the common DMA interrupt status.
*/
STATIC INLINE uint32_t Chip_DMA_GetEnableIntChannels(LPC_DMA_T *pDMA)
{
return pDMA->DMACOMMON[0].INTENSET;
}
/**
* @brief Returns active A interrupt status for all channels
* @param pDMA : The base of DMA controller on the chip
* @return Nothing
* @note A high values in bits 0 .. 15 in the return values indicates
* that the channel for that bit (bit 0 = channel 0, bit 1 -
* channel 1, etc.) has an active A interrupt for the channel.
* A low state indicates that the A interrupt is not active.
*/
STATIC INLINE uint32_t Chip_DMA_GetActiveIntAChannels(LPC_DMA_T *pDMA)
{
return pDMA->DMACOMMON[0].INTA;
}
/**
* @brief Clears active A interrupt status for a single channel
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
*/
STATIC INLINE void Chip_DMA_ClearActiveIntAChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
pDMA->DMACOMMON[0].INTA = (1 << ch);
}
/**
* @brief Returns active B interrupt status for all channels
* @param pDMA : The base of DMA controller on the chip
* @return Nothing
* @note A high values in bits 0 .. 15 in the return values indicates
* that the channel for that bit (bit 0 = channel 0, bit 1 -
* channel 1, etc.) has an active B interrupt for the channel.
* A low state indicates that the B interrupt is not active.
*/
STATIC INLINE uint32_t Chip_DMA_GetActiveIntBChannels(LPC_DMA_T *pDMA)
{
return pDMA->DMACOMMON[0].INTB;
}
/**
* @brief Clears active B interrupt status for a single channel
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
*/
STATIC INLINE void Chip_DMA_ClearActiveIntBChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
pDMA->DMACOMMON[0].INTB = (1 << ch);
}
/**
* @brief Sets the VALIDPENDING control bit for a single channel
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
* @note See the User Manual for more information for what this bit does.
*
*/
STATIC INLINE void Chip_DMA_SetValidChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
pDMA->DMACOMMON[0].SETVALID = (1 << ch);
}
/**
* @brief Sets the TRIG bit for a single channel
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
* @note See the User Manual for more information for what this bit does.
*/
STATIC INLINE void Chip_DMA_SetTrigChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
pDMA->DMACOMMON[0].SETTRIG = (1 << ch);
}
/**
* @brief Aborts a DMA operation for a single channel
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
* @note To abort a channel, the channel should first be disabled. Then wait
* until the channel is no longer busy by checking the corresponding
* bit in BUSY. Finally, abort the channel operation. This prevents the
* channel from restarting an incomplete operation when it is enabled
* again.
*/
STATIC INLINE void Chip_DMA_AbortChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
pDMA->DMACOMMON[0].ABORT = (1 << ch);
}
/**
* @}
*/
/** @defgroup DMA_CHANNEL_540XX CHIP: LPC540XX DMA Controller driver channel specific functions
* @{
*/
/* DMA channel source/address/next descriptor */
typedef struct {
uint32_t xfercfg; /*!< Transfer configuration (only used in linked lists and ping-pong configs) */
uint32_t source; /*!< DMA transfer source end address */
uint32_t dest; /*!< DMA transfer desintation end address */
uint32_t next; /*!< Link to next DMA descriptor, must be 16 byte aligned */
} DMA_CHDESC_T;
/* Support macro for DMA_CHDESC_T */
#define DMA_ADDR(addr) ((uint32_t) (addr))
/* DMA SRAM table - this can be optionally used with the Chip_DMA_SetSRAMBase()
function if a DMA SRAM table is needed. */
extern DMA_CHDESC_T Chip_DMA_Table[MAX_DMA_CHANNEL];
/* Support definitions for setting the configuration of a DMA channel. You
will need to get more information on these options from the User manual. */
#define DMA_CFG_PERIPHREQEN (1 << 0) /*!< Enables Peripheral DMA requests */
#define DMA_CFG_HWTRIGEN (1 << 1) /*!< Use hardware triggering via imput mux */
#define DMA_CFG_TRIGPOL_LOW (0 << 4) /*!< Hardware trigger is active low or falling edge */
#define DMA_CFG_TRIGPOL_HIGH (1 << 4) /*!< Hardware trigger is active high or rising edge */
#define DMA_CFG_TRIGTYPE_EDGE (0 << 5) /*!< Hardware trigger is edge triggered */
#define DMA_CFG_TRIGTYPE_LEVEL (1 << 5) /*!< Hardware trigger is level triggered */
#define DMA_CFG_TRIGBURST_SNGL (0 << 6) /*!< Single transfer. Hardware trigger causes a single transfer */
#define DMA_CFG_TRIGBURST_BURST (1 << 6) /*!< Burst transfer (see UM) */
#define DMA_CFG_BURSTPOWER_1 (0 << 8) /*!< Set DMA burst size to 1 transfer */
#define DMA_CFG_BURSTPOWER_2 (1 << 8) /*!< Set DMA burst size to 2 transfers */
#define DMA_CFG_BURSTPOWER_4 (2 << 8) /*!< Set DMA burst size to 4 transfers */
#define DMA_CFG_BURSTPOWER_8 (3 << 8) /*!< Set DMA burst size to 8 transfers */
#define DMA_CFG_BURSTPOWER_16 (4 << 8) /*!< Set DMA burst size to 16 transfers */
#define DMA_CFG_BURSTPOWER_32 (5 << 8) /*!< Set DMA burst size to 32 transfers */
#define DMA_CFG_BURSTPOWER_64 (6 << 8) /*!< Set DMA burst size to 64 transfers */
#define DMA_CFG_BURSTPOWER_128 (7 << 8) /*!< Set DMA burst size to 128 transfers */
#define DMA_CFG_BURSTPOWER_256 (8 << 8) /*!< Set DMA burst size to 256 transfers */
#define DMA_CFG_BURSTPOWER_512 (9 << 8) /*!< Set DMA burst size to 512 transfers */
#define DMA_CFG_BURSTPOWER_1024 (10 << 8) /*!< Set DMA burst size to 1024 transfers */
#define DMA_CFG_BURSTPOWER(n) ((n) << 8) /*!< Set DMA burst size to 2^n transfers, max n=10 */
#define DMA_CFG_SRCBURSTWRAP (1 << 14) /*!< Source burst wrapping is enabled for this DMA channel */
#define DMA_CFG_DSTBURSTWRAP (1 << 15) /*!< Destination burst wrapping is enabled for this DMA channel */
#define DMA_CFG_CHPRIORITY(p) ((p) << 16) /*!< Sets DMA channel priority, min 0 (highest), max 3 (lowest) */
/**
* @brief Setup a DMA channel configuration
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @param cfg : An Or'ed value of DMA_CFG_* values that define the channel's configuration
* @return Nothing
* @note This function sets up all configurable options for the DMA channel.
* These options are usually set once for a channel and then unchanged.<br>
*
* The following example show how to configure the channel for peripheral
* DMA requests, burst transfer size of 1 (in 'transfers', not bytes),
* continuous reading of the same source address, incrementing destination
* address, and highest channel priority.<br>
* Example: Chip_DMA_SetupChannelConfig(pDMA, SSP0_RX_DMA,
* (DMA_CFG_PERIPHREQEN | DMA_CFG_TRIGBURST_BURST | DMA_CFG_BURSTPOWER_1 |
* DMA_CFG_SRCBURSTWRAP | DMA_CFG_CHPRIORITY(0)));<br>
*
* The following example show how to configure the channel for an external
* trigger from the imput mux with low edge polarity, a burst transfer size of 8,
* incrementing source and destination addresses, and lowest channel
* priority.<br>
* Example: Chip_DMA_SetupChannelConfig(pDMA, DMA_CH14,
* (DMA_CFG_HWTRIGEN | DMA_CFG_TRIGPOL_LOW | DMA_CFG_TRIGTYPE_EDGE |
* DMA_CFG_TRIGBURST_BURST | DMA_CFG_BURSTPOWER_8 |
* DMA_CFG_CHPRIORITY(3)));<br>
*
* For non-peripheral DMA triggering (DMA_CFG_HWTRIGEN definition), use the
* DMA input mux functions to configure the DMA trigger source for a DMA channel.
*/
STATIC INLINE void Chip_DMA_SetupChannelConfig(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t cfg)
{
pDMA->DMACH[ch].CFG = cfg;
}
/* DMA channel control and status register definitions */
#define DMA_CTLSTAT_VALIDPENDING (1 << 0) /*!< Valid pending flag for this channel */
#define DMA_CTLSTAT_TRIG (1 << 2) /*!< Trigger flag. Indicates that the trigger for this channel is currently set */
/**
* @brief Returns channel specific status flags
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return AN Or'ed value of DMA_CTLSTAT_VALIDPENDING and DMA_CTLSTAT_TRIG
*/
STATIC INLINE uint32_t Chip_DMA_GetChannelStatus(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
return pDMA->DMACH[ch].XFERCFG;
}
/* DMA channel transfer configuration registers definitions */
#define DMA_XFERCFG_CFGVALID (1 << 0) /*!< Configuration Valid flag */
#define DMA_XFERCFG_RELOAD (1 << 1) /*!< Indicates whether the channels control structure will be reloaded when the current descriptor is exhausted */
#define DMA_XFERCFG_SWTRIG (1 << 2) /*!< Software Trigger */
#define DMA_XFERCFG_CLRTRIG (1 << 3) /*!< Clear Trigger */
#define DMA_XFERCFG_SETINTA (1 << 4) /*!< Set Interrupt flag A for this channel to fire when descriptor is complete */
#define DMA_XFERCFG_SETINTB (1 << 5) /*!< Set Interrupt flag B for this channel to fire when descriptor is complete */
#define DMA_XFERCFG_WIDTH_8 (0 << 8) /*!< 8-bit transfers are performed */
#define DMA_XFERCFG_WIDTH_16 (1 << 8) /*!< 16-bit transfers are performed */
#define DMA_XFERCFG_WIDTH_32 (2 << 8) /*!< 32-bit transfers are performed */
#define DMA_XFERCFG_SRCINC_0 (0 << 12) /*!< DMA source address is not incremented after a transfer */
#define DMA_XFERCFG_SRCINC_1 (1 << 12) /*!< DMA source address is incremented by 1 (width) after a transfer */
#define DMA_XFERCFG_SRCINC_2 (2 << 12) /*!< DMA source address is incremented by 2 (width) after a transfer */
#define DMA_XFERCFG_SRCINC_4 (3 << 12) /*!< DMA source address is incremented by 4 (width) after a transfer */
#define DMA_XFERCFG_DSTINC_0 (0 << 14) /*!< DMA destination address is not incremented after a transfer */
#define DMA_XFERCFG_DSTINC_1 (1 << 14) /*!< DMA destination address is incremented by 1 (width) after a transfer */
#define DMA_XFERCFG_DSTINC_2 (2 << 14) /*!< DMA destination address is incremented by 2 (width) after a transfer */
#define DMA_XFERCFG_DSTINC_4 (3 << 14) /*!< DMA destination address is incremented by 4 (width) after a transfer */
#define DMA_XFERCFG_XFERCOUNT(n) ((n - 1) << 16) /*!< DMA transfer count in 'transfers', between (0)1 and (1023)1024 */
typedef enum {
WIDTH_8_BITS = 0,
WIDTH_16_BITS = 1,
WIDTH_32_BITS = 2
} DataWidth;
/**
* @brief Setup a DMA channel transfer configuration
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @param cfg : An Or'ed value of DMA_XFERCFG_* values that define the channel's transfer configuration
* @return Nothing
* @note This function sets up the transfer configuration for the DMA channel.<br>
*
* The following example show how to configure the channel's transfer for
* multiple transfer descriptors (ie, ping-pong), interrupt 'A' trigger on
* transfer descriptor completion, 128 byte size transfers, and source and
* destination address increment.<br>
* Example: Chip_DMA_SetupChannelTransfer(pDMA, SSP0_RX_DMA,
* (DMA_XFERCFG_CFGVALID | DMA_XFERCFG_RELOAD | DMA_XFERCFG_SETINTA |
* DMA_XFERCFG_WIDTH_8 | DMA_XFERCFG_SRCINC_1 | DMA_XFERCFG_DSTINC_1 |
* DMA_XFERCFG_XFERCOUNT(128)));<br>
*/
STATIC INLINE void Chip_DMA_SetupChannelTransfer(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t cfg)
{
pDMA->DMACH[ch].XFERCFG = cfg;
}
/**
* @brief Set DMA transfer register interrupt bits (safe)
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @param mask : Bits to set
* @return Nothing
* @note This function safely sets bits in the DMA channel specific XFERCFG
* register.
*/
void Chip_DMA_SetTranBits(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t mask);
/**
* @brief Clear DMA transfer register interrupt bits (safe)
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @param mask : Bits to clear
* @return Nothing
* @note This function safely clears bits in the DMA channel specific XFERCFG
* register.
*/
void Chip_DMA_ClearTranBits(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t mask);
/**
* @brief Update the transfer size in an existing DMA channel transfer configuration
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @param trans : Number of transfers to update the transfer configuration to (1 - 1023)
* @return Nothing
*/
void Chip_DMA_SetupChannelTransferSize(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t trans);
/**
* @brief Sets a DMA channel configuration as valid
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
*/
STATIC INLINE void Chip_DMA_SetChannelValid(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
Chip_DMA_SetTranBits(pDMA, ch, DMA_XFERCFG_CFGVALID);
}
/**
* @brief Sets a DMA channel configuration as invalid
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
*/
STATIC INLINE void Chip_DMA_SetChannelInValid(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
Chip_DMA_ClearTranBits(pDMA, ch, DMA_XFERCFG_CFGVALID);
}
/**
* @brief Performs a software trigger of the DMA channel
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @return Nothing
*/
STATIC INLINE void Chip_DMA_SWTriggerChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
Chip_DMA_SetTranBits(pDMA, ch, DMA_XFERCFG_SWTRIG);
}
/**
* @brief Sets up a DMA channel with the passed DMA transfer descriptor
* @param pDMA : The base of DMA controller on the chip
* @param ch : DMA channel ID
* @param desc : Pointer to DMA transfer descriptor
* @return false if the DMA channel was active, otherwise true
* @note This function will set the DMA descriptor in the SRAM table to the
* the passed descriptor. This function is only meant to be used when
* the DMA channel is not active and can be used to setup the
* initial transfer for a linked list or ping-pong buffer or just a
* single transfer without a next descriptor.<br>
*
* If using this function to write the initial transfer descriptor in
* a linked list or ping-pong buffer configuration, it should contain a
* non-NULL 'next' field pointer.
*/
bool Chip_DMA_SetupTranChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch, DMA_CHDESC_T *desc);
void Chip_DMA_InitChannel( DMA_CHID_T channel, uint32_t src_address, uint32_t src_increment,
uint32_t dst_address, uint32_t dst_increment, uint32_t xfr_width, uint32_t length_bytes, uint32_t priority);
void Chip_DMA_StartTransfer(DMA_CHID_T channel, uint32_t src_increment, uint32_t dst_increment, uint32_t xfr_width, uint32_t length_bytes);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __DMA_540XX_H */

View File

@@ -0,0 +1,48 @@
/*
* @brief LPC540xx GPIO group driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "chip.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
/*****************************************************************************
* Public functions
****************************************************************************/

View File

@@ -0,0 +1,114 @@
/*
* @brief LPC540xx I2C slave driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "chip.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
#define NUMI2CDEVS 3
/* Clock and reset indexes */
static const uint8_t resetIdx[NUMI2CDEVS] = {
(uint8_t) RESET_I2C0, (uint8_t) RESET_I2C1,
(uint8_t) RESET_I2C2
};
static const uint8_t ClockIdx[NUMI2CDEVS] = {
(uint8_t) SYSCON_CLOCK_I2C0, (uint8_t) SYSCON_CLOCK_I2C1,
(uint8_t) SYSCON_CLOCK_I2C2
};
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
/* Returns the index needed for clock and reset lookup */
static int returnClkIdx(LPC_I2C_T *pI2C)
{
if (pI2C == LPC_I2C1) {
return 1;
}
else if (pI2C == LPC_I2C2) {
return 2;
}
return 0;
}
/*****************************************************************************
* Public functions
****************************************************************************/
/* Initializes the LPC_I2C peripheral */
void Chip_I2C_Init(LPC_I2C_T *pI2C)
{
int clkIndex = returnClkIdx(pI2C);
/* Enable clock to I2C peripheral and reset */
Chip_Clock_EnablePeriphClock((CHIP_SYSCON_CLOCK_T) ClockIdx[clkIndex]);
Chip_SYSCON_PeriphReset((CHIP_SYSCON_PERIPH_RESET_T) resetIdx[clkIndex]);
}
/* Shuts down the I2C controller block */
void Chip_I2C_DeInit(LPC_I2C_T *pI2C)
{
int clkIndex = returnClkIdx(pI2C);
/* Disable clock to I2C peripheral */
Chip_Clock_DisablePeriphClock((CHIP_SYSCON_CLOCK_T) ClockIdx[clkIndex]);
}
/* Sets register bit values with mask */
void Chip_I2C_SetRegMask(volatile uint32_t *pReg32, uint32_t mask, uint32_t bits)
{
*pReg32 = (*pReg32 & mask) | bits;
}
/* Clears register bit values with mask */
void Chip_I2C_ClearRegMask(volatile uint32_t *pReg32, uint32_t mask, uint32_t bits)
{
*pReg32 = (*pReg32 & mask) & ~bits;
}
/* Sets I2C Clock Divider registers */
void Chip_I2C_SetClockDiv(LPC_I2C_T *pI2C, uint32_t clkdiv)
{
if ((clkdiv >= 1) && (clkdiv <= 65536)) {
pI2C->CLKDIV = clkdiv - 1;
}
else {
pI2C->CLKDIV = 0;
}
}

View File

@@ -0,0 +1,332 @@
/*
* @brief LPC540xx I2C driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#ifndef __I2C_COMMON_540XX_H_
#define __I2C_COMMON_540XX_H_
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup I2C_540XX CHIP: LPC540xx I2C driver
* @ingroup CHIP_540XX_Drivers
* @{
*/
/**
* @brief I2C register block structure
*/
typedef struct { /* I2C0 Structure */
__IO uint32_t CFG; /*!< I2C Configuration Register common for Master, Slave and Monitor */
__IO uint32_t STAT; /*!< I2C Status Register common for Master, Slave and Monitor */
__IO uint32_t INTENSET; /*!< I2C Interrupt Enable Set Register common for Master, Slave and Monitor */
__O uint32_t INTENCLR; /*!< I2C Interrupt Enable Clear Register common for Master, Slave and Monitor */
__IO uint32_t TIMEOUT; /*!< I2C Timeout value Register */
__IO uint32_t CLKDIV; /*!< I2C Clock Divider Register */
__I uint32_t INTSTAT; /*!< I2C Interrupt Status Register */
__I uint32_t RESERVED0;
__IO uint32_t MSTCTL; /*!< I2C Master Control Register */
__IO uint32_t MSTTIME; /*!< I2C Master Time Register for SCL */
__IO uint32_t MSTDAT; /*!< I2C Master Data Register */
__I uint32_t RESERVED1[5];
__IO uint32_t SLVCTL; /*!< I2C Slave Control Register */
__IO uint32_t SLVDAT; /*!< I2C Slave Data Register */
__IO uint32_t SLVADR[4]; /*!< I2C Slave Address Registers */
__IO uint32_t SLVQUAL0; /*!< I2C Slave Address Qualifier 0 Register */
__I uint32_t RESERVED2[9];
__I uint32_t MONRXDAT; /*!< I2C Monitor Data Register */
} LPC_I2C_T;
/*
* @brief I2C Configuration register Bit definition
*/
#define I2C_CFG_MSTEN (1 << 0) /*!< Master Enable/Disable Bit */
#define I2C_CFG_SLVEN (1 << 1) /*!< Slave Enable/Disable Bit */
#define I2C_CFG_MONEN (1 << 2) /*!< Monitor Enable/Disable Bit */
#define I2C_CFG_TIMEOUTEN (1 << 3) /*!< Timeout Enable/Disable Bit */
#define I2C_CFG_MONCLKSTR (1 << 4) /*!< Monitor Clock Stretching Bit */
#define I2C_CFG_MASK ((uint32_t) 0x1F) /*!< Configuration Register Mask */
/*
* @brief I2C Status register Bit definition
*/
#define I2C_STAT_MSTPENDING (1 << 0) /*!< Master Pending Status Bit */
#define I2C_STAT_MSTSTATE (0x7 << 1) /*!< Master State Code */
#define I2C_STAT_MSTRARBLOSS (1 << 4) /*!< Master Arbitration Loss Bit */
#define I2C_STAT_MSTSTSTPERR (1 << 6) /*!< Master Start Stop Error Bit */
#define I2C_STAT_SLVPENDING (1 << 8) /*!< Slave Pending Status Bit */
#define I2C_STAT_SLVSTATE (0x3 << 9) /*!< Slave State Code */
#define I2C_STAT_SLVNOTSTR (1 << 11) /*!< Slave not stretching Clock Bit */
#define I2C_STAT_SLVIDX (0x3 << 12) /*!< Slave Address Index */
#define I2C_STAT_SLVSEL (1 << 14) /*!< Slave Selected Bit */
#define I2C_STAT_SLVDESEL (1 << 15) /*!< Slave Deselect Bit */
#define I2C_STAT_MONRDY (1 << 16) /*!< Monitor Ready Bit */
#define I2C_STAT_MONOV (1 << 17) /*!< Monitor Overflow Flag */
#define I2C_STAT_MONACTIVE (1 << 18) /*!< Monitor Active Flag */
#define I2C_STAT_MONIDLE (1 << 19) /*!< Monitor Idle Flag */
#define I2C_STAT_EVENTTIMEOUT (1 << 24) /*!< Event Timeout Interrupt Flag */
#define I2C_STAT_SCLTIMEOUT (1 << 25) /*!< SCL Timeout Interrupt Flag */
#define I2C_STAT_MSTCODE_IDLE (0) /*!< Master Idle State Code */
#define I2C_STAT_MSTCODE_RXREADY (1) /*!< Master Receive Ready State Code */
#define I2C_STAT_MSTCODE_TXREADY (2) /*!< Master Transmit Ready State Code */
#define I2C_STAT_MSTCODE_NACKADR (3) /*!< Master NACK by slave on address State Code */
#define I2C_STAT_MSTCODE_NACKDAT (4) /*!< Master NACK by slave on data State Code */
#define I2C_STAT_SLVCODE_ADDR (0) /*!< Master Idle State Code */
#define I2C_STAT_SLVCODE_RX (1) /*!< Received data is available Code */
#define I2C_STAT_SLVCODE_TX (2) /*!< Data can be transmitted Code */
/*
* @brief I2C Interrupt Enable Set register Bit definition
*/
#define I2C_INTENSET_MSTPENDING (1 << 0) /*!< Master Pending Interrupt Enable Bit */
#define I2C_INTENSET_MSTRARBLOSS (1 << 4) /*!< Master Arbitration Loss Interrupt Enable Bit */
#define I2C_INTENSET_MSTSTSTPERR (1 << 6) /*!< Master Start Stop Error Interrupt Enable Bit */
#define I2C_INTENSET_SLVPENDING (1 << 8) /*!< Slave Pending Interrupt Enable Bit */
#define I2C_INTENSET_SLVNOTSTR (1 << 11) /*!< Slave not stretching Clock Interrupt Enable Bit */
#define I2C_INTENSET_SLVDESEL (1 << 15) /*!< Slave Deselect Interrupt Enable Bit */
#define I2C_INTENSET_MONRDY (1 << 16) /*!< Monitor Ready Interrupt Enable Bit */
#define I2C_INTENSET_MONOV (1 << 17) /*!< Monitor Overflow Interrupt Enable Bit */
#define I2C_INTENSET_MONIDLE (1 << 19) /*!< Monitor Idle Interrupt Enable Bit */
#define I2C_INTENSET_EVENTTIMEOUT (1 << 24) /*!< Event Timeout Interrupt Enable Bit */
#define I2C_INTENSET_SCLTIMEOUT (1 << 25) /*!< SCL Timeout Interrupt Enable Bit */
/*
* @brief I2C Interrupt Enable Clear register Bit definition
*/
#define I2C_INTENCLR_MSTPENDING (1 << 0) /*!< Master Pending Interrupt Clear Bit */
#define I2C_INTENCLR_MSTRARBLOSS (1 << 4) /*!< Master Arbitration Loss Interrupt Clear Bit */
#define I2C_INTENCLR_MSTSTSTPERR (1 << 6) /*!< Master Start Stop Error Interrupt Clear Bit */
#define I2C_INTENCLR_SLVPENDING (1 << 8) /*!< Slave Pending Interrupt Clear Bit */
#define I2C_INTENCLR_SLVNOTSTR (1 << 11) /*!< Slave not stretching Clock Interrupt Clear Bit */
#define I2C_INTENCLR_SLVDESEL (1 << 15) /*!< Slave Deselect Interrupt Clear Bit */
#define I2C_INTENCLR_MONRDY (1 << 16) /*!< Monitor Ready Interrupt Clear Bit */
#define I2C_INTENCLR_MONOV (1 << 17) /*!< Monitor Overflow Interrupt Clear Bit */
#define I2C_INTENCLR_MONIDLE (1 << 19) /*!< Monitor Idle Interrupt Clear Bit */
#define I2C_INTENCLR_EVENTTIMEOUT (1 << 24) /*!< Event Timeout Interrupt Clear Bit */
#define I2C_INTENCLR_SCLTIMEOUT (1 << 25) /*!< SCL Timeout Interrupt Clear Bit */
/*
* @brief I2C TimeOut Value Macro
*/
#define I2C_TIMEOUT_VAL(n) (((uint32_t) ((n) - 1) & 0xFFF0) | 0x000F) /*!< Macro for Timeout value register */
/*
* @brief I2C Interrupt Status register Bit definition
*/
#define I2C_INTSTAT_MSTPENDING (1 << 0) /*!< Master Pending Interrupt Status Bit */
#define I2C_INTSTAT_MSTRARBLOSS (1 << 4) /*!< Master Arbitration Loss Interrupt Status Bit */
#define I2C_INTSTAT_MSTSTSTPERR (1 << 6) /*!< Master Start Stop Error Interrupt Status Bit */
#define I2C_INTSTAT_SLVPENDING (1 << 8) /*!< Slave Pending Interrupt Status Bit */
#define I2C_INTSTAT_SLVNOTSTR (1 << 11) /*!< Slave not stretching Clock Interrupt Status Bit */
#define I2C_INTSTAT_SLVDESEL (1 << 15) /*!< Slave Deselect Interrupt Status Bit */
#define I2C_INTSTAT_MONRDY (1 << 16) /*!< Monitor Ready Interrupt Status Bit */
#define I2C_INTSTAT_MONOV (1 << 17) /*!< Monitor Overflow Interrupt Status Bit */
#define I2C_INTSTAT_MONIDLE (1 << 19) /*!< Monitor Idle Interrupt Status Bit */
#define I2C_INTSTAT_EVENTTIMEOUT (1 << 24) /*!< Event Timeout Interrupt Status Bit */
#define I2C_INTSTAT_SCLTIMEOUT (1 << 25) /*!< SCL Timeout Interrupt Status Bit */
/*
* @brief I2C Master Control register Bit definition
*/
#define I2C_MSTCTL_MSTCONTINUE (1 << 0) /*!< Master Continue Bit */
#define I2C_MSTCTL_MSTSTART (1 << 1) /*!< Master Start Control Bit */
#define I2C_MSTCTL_MSTSTOP (1 << 2) /*!< Master Stop Control Bit */
#define I2C_MSTCTL_MSTDMA (1 << 3) /*!< Master DMA Enable Bit */
/*
* @brief I2C Master Time Register Field definition
*/
#define I2C_MSTTIME_MSTSCLLOW (0x07 << 0) /*!< Master SCL Low Time field */
#define I2C_MSTTIME_MSTSCLHIGH (0x07 << 4) /*!< Master SCL High Time field */
/*
* @brief I2C Master Data Mask
*/
#define I2C_MSTDAT_DATAMASK ((uint32_t) 0x00FF << 0) /*!< Master data mask */
/*
* @brief I2C Slave Control register Bit definition
*/
#define I2C_SLVCTL_SLVCONTINUE (1 << 0) /*!< Slave Continue Bit */
#define I2C_SLVCTL_SLVNACK (1 << 1) /*!< Slave NACK Bit */
#define I2C_SLVCTL_SLVDMA (1 << 3) /*!< Slave DMA Enable Bit */
/*
* @brief I2C Slave Data Mask
*/
#define I2C_SLVDAT_DATAMASK ((uint32_t) 0x00FF << 0) /*!< Slave data mask */
/*
* @brief I2C Slave Address register Bit definition
*/
#define I2C_SLVADR_SADISABLE (1 << 0) /*!< Slave Address n Disable Bit */
#define I2C_SLVADR_SLVADR (0x7F << 1) /*!< Slave Address field */
#define I2C_SLVADR_MASK ((uint32_t) 0x00FF) /*!< Slave Address Mask */
/*
* @brief I2C Slave Address Qualifier 0 Register Bit definition
*/
#define I2C_SLVQUAL_QUALMODE0 (1 << 0) /*!< Slave Qualifier Mode Enable Bit */
#define I2C_SLVQUAL_SLVQUAL0 (0x7F << 1) /*!< Slave Qualifier Address for Address 0 */
/*
* @brief I2C Monitor Data Register Bit definition
*/
#define I2C_MONRXDAT_DATA (0xFF << 0) /*!< Monitor Function Receive Data Field */
#define I2C_MONRXDAT_MONSTART (1 << 8) /*!< Monitor Received Start Bit */
#define I2C_MONRXDAT_MONRESTART (1 << 9) /*!< Monitor Received Repeated Start Bit */
#define I2C_MONRXDAT_MONNACK (1 << 10) /*!< Monitor Received Nack Bit */
/**
* @brief Initialize I2C Interface
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note This function enables the I2C clock for both the master and
* slave interfaces if the I2C channel.
*/
void Chip_I2C_Init(LPC_I2C_T *pI2C);
/**
* @brief Shutdown I2C Interface
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note This function disables the I2C clock for both the master and
* slave interfaces if the I2C channel.
*/
void Chip_I2C_DeInit(LPC_I2C_T *pI2C);
/**
* @brief Sets register bit values with mask
* @param pReg32 : Pointer to 32-bit register to set bits for
* @param mask : Zero write mask, will mask these bits are write back as 0
* @param bits : Bits to set
* @return Nothing
* @note This function is needed for read-modify-write operations where the register
* being changed has read bits that are undefined, but must be written back as 0.
*/
void Chip_I2C_SetRegMask(volatile uint32_t *pReg32, uint32_t mask, uint32_t bits);
/**
* @brief Clears register bit values with mask
* @param pReg32 : Pointer to 32-bit register to clear bits for
* @param mask : Zero write mask, will mask these bits are write back as 0
* @param bits : Bits to clear
* @return Nothing
* @note This function is needed for read-modify-write operations where the register
* being changed has read bits that are undefined, but must be written back as 0.
*/
void Chip_I2C_ClearRegMask(volatile uint32_t *pReg32, uint32_t mask, uint32_t bits);
/**
* @brief Sets I2C Clock Divider registers
* @param pI2C : Pointer to selected I2C peripheral
* @param clkdiv : Clock Divider value for I2C, value is between (1 - 65536)
* @return Nothing
* @note The clock to I2C block is determined by the following formula (I2C_PCLK
* is the frequency of the system clock): <br>
* I2C Clock Frequency = (I2C_PCLK)/clkdiv;<br>
* This divider must be setup for both the master and slave modes of the
* controller. When used in master mode, this divider is used with the MSTTIME
* register to generate the master I2C clock. Since the MSTTIME register has a
* limited range of divide values, this value should be selected to give an I2C
* clock rate that is about 2x to 18x greater than the desired master clock rate.
*/
void Chip_I2C_SetClockDiv(LPC_I2C_T *pI2C, uint32_t clkdiv);
/**
* @brief Get I2C Clock Divider registers
* @param pI2C : Pointer to selected I2C peripheral
* @return Clock Divider value
* @note Return the divider value for the I2C block
* It is the CLKDIV register value + 1
*/
static INLINE uint32_t Chip_I2C_GetClockDiv(LPC_I2C_T *pI2C)
{
return (pI2C->CLKDIV & 0xFFFF) + 1;
}
/**
* @brief Enable I2C Interrupts
* @param pI2C : Pointer to selected I2C peripheral
* @param intEn : ORed Value of I2C_INTENSET_* values to enable
* @return Nothing
*/
static INLINE void Chip_I2C_EnableInt(LPC_I2C_T *pI2C, uint32_t intEn)
{
pI2C->INTENSET = intEn;
}
/**
* @brief Disable I2C Interrupts
* @param pI2C : Pointer to selected I2C peripheral
* @param intClr : ORed Value of I2C_INTENSET_* values to disable
* @return Nothing
*/
static INLINE void Chip_I2C_DisableInt(LPC_I2C_T *pI2C, uint32_t intClr)
{
pI2C->INTENCLR = intClr;
}
/**
* @brief Disable I2C Interrupts
* @param pI2C : Pointer to selected I2C peripheral
* @param intClr : ORed Value of I2C_INTENSET_* values to disable
* @return Nothing
* @note It is recommended to use the Chip_I2C_DisableInt() function
* instead of this function.
*/
static INLINE void Chip_I2C_ClearInt(LPC_I2C_T *pI2C, uint32_t intClr)
{
Chip_I2C_DisableInt(pI2C, intClr);
}
/**
* @brief Returns pending I2C Interrupts
* @param pI2C : Pointer to selected I2C peripheral
* @return All pending interrupts, mask with I2C_INTENSET_* to determine specific interrupts
*/
static INLINE uint32_t Chip_I2C_GetPendingInt(LPC_I2C_T *pI2C)
{
return pI2C->INTSTAT;
}
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __I2C_COMMON_540XX_H_ */

View File

@@ -0,0 +1,249 @@
/*
* @brief LPC540xx I2C master driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "chip.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
/*****************************************************************************
* Public functions
****************************************************************************/
/* Sets HIGH and LOW duty cycle registers */
void Chip_I2CM_SetDutyCycle(LPC_I2C_T *pI2C, uint16_t sclH, uint16_t sclL)
{
/* Limit to usable range of timing values */
if (sclH < 2) {
sclH = 2;
}
else if (sclH > 9) {
sclH = 9;
}
if (sclL < 2) {
sclL = 2;
}
else if (sclL > 9) {
sclL = 9;
}
pI2C->MSTTIME = (((sclH - 2) & 0x07) << 4) | ((sclL - 2) & 0x07);
}
/* Set up bus speed for LPC_I2C interface */
uint32_t Chip_I2CM_SetBusSpeed(LPC_I2C_T *pI2C, uint32_t busSpeed)
{
#if 0
uint32_t scl;
scl = Chip_Clock_GetAsyncSyscon_ClockRate() / (Chip_I2C_GetClockDiv(pI2C) * busSpeed);
Chip_I2CM_SetDutyCycle(pI2C, (scl >> 1), (scl - (scl >> 1)));
#endif
// Wecan ToDo modify base on lpconen_2_14_1 ==> hw_i2cmd.c => i2cm_set_clock_rate 2015.06.04
uint32_t scl;
uint32_t inRate,div;
inRate = Chip_Clock_GetAsyncSyscon_ClockRate();
/* Determine the best I2C clock dividers to generate the target I2C master clock */
/* The maximum SCL and SCH dividers are 7, for a maximum divider set of 14 */
/* The I2C master divider is between 1 and 65536. */
/* Pick a main I2C divider that allows centered SCL/SCH dividers */
div = inRate / (busSpeed << 3);
if (div == 0) {
div = 1;
}
Chip_I2C_SetClockDiv(pI2C, div);
/* Determine SCL/SCH dividers */
scl = inRate / (div * busSpeed);
Chip_I2CM_SetDutyCycle(pI2C, (scl >> 1), (scl - (scl >> 1)));
return inRate / (div * scl);
/////////////////////////////////////////////////////////////////////////////////////////////////////
}
/* Master transfer state change handler handler */
uint32_t Chip_I2CM_XferHandler(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
{
uint32_t status = Chip_I2CM_GetStatus(pI2C);
if (status & I2C_STAT_MSTRARBLOSS) {
/* Master Lost Arbitration */
/* Set transfer status as Arbitration Lost */
xfer->status = I2CM_STATUS_ARBLOST;
/* Clear Status Flags */
Chip_I2CM_ClearStatus(pI2C, I2C_STAT_MSTRARBLOSS);
/* Master continue */
if (status & I2C_STAT_MSTPENDING) {
pI2C->MSTCTL = I2C_MSTCTL_MSTCONTINUE;
}
}
else if (status & I2C_STAT_MSTSTSTPERR) {
/* Master Start Stop Error */
/* Set transfer status as Bus Error */
xfer->status = I2CM_STATUS_BUS_ERROR;
/* Clear Status Flags */
Chip_I2CM_ClearStatus(pI2C, I2C_STAT_MSTSTSTPERR);
/* Master continue */
if (status & I2C_STAT_MSTPENDING) {
pI2C->MSTCTL = I2C_MSTCTL_MSTCONTINUE;
}
}
else if (status & I2C_STAT_MSTPENDING) {
/* Master is Pending */
/* Branch based on Master State Code */
switch (Chip_I2CM_GetMasterState(pI2C)) {
case I2C_STAT_MSTCODE_IDLE: /* Master idle */
/* Can transition to idle between transmit and receive states */
if (xfer->txSz) {
/* Start transmit state */
Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1));
pI2C->MSTCTL = I2C_MSTCTL_MSTSTART;
}
else if (xfer->rxSz) {
/* Start receive state with start ot repeat start */
Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1) | 0x1);
pI2C->MSTCTL = I2C_MSTCTL_MSTSTART;
}
else {
/* No data to send, done */
xfer->status = I2CM_STATUS_OK;
}
break;
case I2C_STAT_MSTCODE_RXREADY: /* Receive data is available */
/* Read Data up until the buffer size */
if (xfer->rxSz) {
*xfer->rxBuff = pI2C->MSTDAT;
xfer->rxBuff++;
xfer->rxSz--;
}
if (xfer->rxSz) {
pI2C->MSTCTL = I2C_MSTCTL_MSTCONTINUE;
}
else {
/* Last byte to receive, send stop after byte received */
pI2C->MSTCTL = I2C_MSTCTL_MSTCONTINUE | I2C_MSTCTL_MSTSTOP;
}
break;
case I2C_STAT_MSTCODE_TXREADY: /* Master Transmit available */
if (xfer->txSz) {
/* If Tx data available transmit data and continue */
pI2C->MSTDAT = (uint32_t) *xfer->txBuff;
pI2C->MSTCTL = I2C_MSTCTL_MSTCONTINUE;
xfer->txBuff++;
xfer->txSz--;
}
else if (xfer->rxSz == 0) {
pI2C->MSTCTL = I2C_MSTCTL_MSTSTOP;
}
else {
/* Start receive state with start ot repeat start */
Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1) | 0x1);
pI2C->MSTCTL = I2C_MSTCTL_MSTSTART;
}
break;
case I2C_STAT_MSTCODE_NACKADR: /* Slave address was NACK'ed */
/* Set transfer status as NACK on address */
xfer->status = I2CM_STATUS_NAK_ADR;
pI2C->MSTCTL = I2C_MSTCTL_MSTSTOP;
break;
case I2C_STAT_MSTCODE_NACKDAT: /* Slave data was NACK'ed */
/* Set transfer status as NACK on data */
xfer->status = I2CM_STATUS_NAK_DAT;
pI2C->MSTCTL = I2C_MSTCTL_MSTSTOP;
break;
default:
/* Illegal I2C master state machine case. This should never happen.
Try to advance state machine by continuing. */
xfer->status = I2CM_STATUS_ERROR;
pI2C->MSTCTL = I2C_MSTCTL_MSTCONTINUE;
break;
}
}
else {
/* Unsupported operation. This may be a call to the master handler
for a wrong interrupt type. This handler should only be called when a
master arbitration loss, master start/stop error, or master pending status
occurs. */
xfer->status = I2CM_STATUS_ERROR;
}
return xfer->status != I2CM_STATUS_BUSY;
}
/* Transmit and Receive data in master mode */
void Chip_I2CM_Xfer(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
{
/* set the transfer status as busy */
xfer->status = I2CM_STATUS_BUSY;
/* Reset master state machine */
Chip_I2CM_Disable(pI2C);
Chip_I2CM_Enable(pI2C);
/* Clear controller state. */
Chip_I2CM_ClearStatus(pI2C, I2C_STAT_MSTRARBLOSS | I2C_STAT_MSTSTSTPERR);
/* Handle transfer via initial call to handler */
Chip_I2CM_XferHandler(pI2C, xfer);
}
/* Transmit and Receive data in master mode */
uint32_t Chip_I2CM_XferBlocking(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
{
/* start transfer */
Chip_I2CM_Xfer(pI2C, xfer);
while (xfer->status == I2CM_STATUS_BUSY) {
/* wait for status change interrupt */
while (!Chip_I2CM_IsMasterPending(pI2C)) {}
/* call state change handler */
Chip_I2CM_XferHandler(pI2C, xfer);
}
return (xfer->status == I2CM_STATUS_OK);
}

View File

@@ -0,0 +1,318 @@
/*
* @brief LPC540xx I2C driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#ifndef __I2CM_540XX_H_
#define __I2CM_540XX_H_
#include "i2c_common_540xx.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup I2CM_540XX CHIP: LPC540xx I2C master-only driver
* @ingroup I2C_540XX
* This driver only works in master mode. To describe the I2C transactions
* following symbols are used in driver documentation.
*
* Key to symbols
* ==============
* S (1 bit) : Start bit
* P (1 bit) : Stop bit
* Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
* A, NA (1 bit) : Acknowledge and Not-Acknowledge bit.
* Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to
* get a 10 bit I2C address.
* Data (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh
* for 16 bit data.
* [..]: Data sent by I2C device, as opposed to data sent by the host adapter.
* @{
*/
/** I2CM_540XX_STATUS_TYPES I2C master transfer status types
*/
#define I2CM_STATUS_OK 0x00 /*!< Requested Request was executed successfully. */
#define I2CM_STATUS_ERROR 0x01 /*!< Unknown error condition. */
#define I2CM_STATUS_NAK_ADR 0x02 /*!< No acknowledgement received from slave during address phase. */
#define I2CM_STATUS_BUS_ERROR 0x03 /*!< I2C bus error */
#define I2CM_STATUS_NAK_DAT 0x04 /*!< No acknowledgement received from slave during address phase. */
#define I2CM_STATUS_ARBLOST 0x05 /*!< Arbitration lost. */
#define I2CM_STATUS_BUSY 0xFF /*!< I2C transmistter is busy. */
/**
* @brief Master transfer data structure definitions
*/
typedef struct {
const uint8_t *txBuff; /*!< Pointer to array of bytes to be transmitted */
uint8_t *rxBuff; /*!< Pointer memory where bytes received from I2C be stored */
volatile uint16_t txSz; /*!< Number of bytes in transmit array,
if 0 only receive transfer will be carried on */
volatile uint16_t rxSz; /*!< Number of bytes to received,
if 0 only transmission we be carried on */
volatile uint16_t status; /*!< Status of the current I2C transfer */
uint8_t slaveAddr; /*!< 7-bit I2C Slave address */
} I2CM_XFER_T;
/**
* @brief Sets HIGH and LOW duty cycle registers
* @param pI2C : Pointer to selected I2C peripheral
* @param sclH : Number of I2C_PCLK cycles for the SCL HIGH time value between (2 - 9).
* @param sclL : Number of I2C_PCLK cycles for the SCL LOW time value between (2 - 9).
* @return Nothing
* @note The I2C clock divider should be set to the appropriate value before calling this function
* The I2C baud is determined by the following formula: <br>
* I2C_bitFrequency = (I2C_PCLK)/(I2C_CLKDIV * (sclH + sclL)) <br>
* where I2C_PCLK is the frequency of the System clock and I2C_CLKDIV is I2C clock divider
*/
void Chip_I2CM_SetDutyCycle(LPC_I2C_T *pI2C, uint16_t sclH, uint16_t sclL);
/**
* @brief Set up bus speed for LPC_I2C controller
* @param pI2C : Pointer to selected I2C peripheral
* @param busSpeed : I2C bus clock rate
* @return Nothing
* @note Per I2C specification the busSpeed should be
* @li 100000 for Standard mode
* @li 400000 for Fast mode
* @li 1000000 for Fast mode plus
* IOCON registers corresponding to I2C pads should be updated
* according to the bus mode.
*/
uint32_t Chip_I2CM_SetBusSpeed(LPC_I2C_T *pI2C, uint32_t busSpeed);
/**
* @brief Enable I2C Master interface
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note
*/
static INLINE void Chip_I2CM_Enable(LPC_I2C_T *pI2C)
{
Chip_I2C_SetRegMask(&pI2C->CFG, I2C_CFG_MASK, I2C_CFG_MSTEN);
}
/**
* @brief Disable I2C Master interface
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note
*/
static INLINE void Chip_I2CM_Disable(LPC_I2C_T *pI2C)
{
Chip_I2C_ClearRegMask(&pI2C->CFG, I2C_CFG_MASK, I2C_CFG_MSTEN);
}
/**
* @brief Get I2C Status
* @param pI2C : Pointer to selected I2C peripheral
* @return I2C Status register value
* @note This function returns the value of the status register.
*/
static INLINE uint32_t Chip_I2CM_GetStatus(LPC_I2C_T *pI2C)
{
return pI2C->STAT;
}
/**
* @brief Clear I2C status bits (master)
* @param pI2C : Pointer to selected I2C peripheral
* @param clrStatus : Status bit to clear, ORed Value of I2C_STAT_MSTRARBLOSS and I2C_STAT_MSTSTSTPERR
* @return Nothing
* @note This function clears selected status flags.
*/
static INLINE void Chip_I2CM_ClearStatus(LPC_I2C_T *pI2C, uint32_t clrStatus)
{
/* Clear Master Arbitration Loss and Start, Stop Error */
pI2C->STAT = clrStatus & (I2C_STAT_MSTRARBLOSS | I2C_STAT_MSTSTSTPERR);
}
/**
* @brief Check if I2C Master is pending
* @param pI2C : Pointer to selected I2C peripheral
* @return Returns TRUE if the Master is pending else returns FALSE
* @note
*/
static INLINE bool Chip_I2CM_IsMasterPending(LPC_I2C_T *pI2C)
{
return (pI2C->STAT & I2C_STAT_MSTPENDING) != 0;
}
/**
* @brief Get current state of the I2C Master
* @param pI2C : Pointer to selected I2C peripheral
* @return Master State Code, a value in the range of 0 - 4
* @note After the Master is pending this state code tells the reason
* for Master pending.
*/
static INLINE uint32_t Chip_I2CM_GetMasterState(LPC_I2C_T *pI2C)
{
return (pI2C->STAT & I2C_STAT_MSTSTATE) >> 1;
}
/**
* @brief Transmit START or Repeat-START signal on I2C bus
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note This function sets the controller to transmit START condition when
* the bus becomes free. This should be called only when master is pending.
* The function writes a complete value to Master Control register, ORing is not advised.
*/
static INLINE void Chip_I2CM_SendStart(LPC_I2C_T *pI2C)
{
pI2C->MSTCTL = I2C_MSTCTL_MSTSTART;
}
/**
* @brief Transmit STOP signal on I2C bus
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note This function sets the controller to transmit STOP condition.
* This should be called only when master is pending. The function writes a
* complete value to Master Control register, ORing is not advised.
*/
static INLINE void Chip_I2CM_SendStop(LPC_I2C_T *pI2C)
{
pI2C->MSTCTL = I2C_MSTCTL_MSTSTOP;
}
/**
* @brief Master Continue transfer operation
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note This function sets the master controller to continue transmission.
* This should be called only when master is pending. The function writes a
* complete value to Master Control register, ORing is not advised.
*/
static INLINE void Chip_I2CM_MasterContinue(LPC_I2C_T *pI2C)
{
pI2C->MSTCTL = I2C_MSTCTL_MSTCONTINUE;
}
/**
* @brief Transmit a single data byte through the I2C peripheral (master)
* @param pI2C : Pointer to selected I2C peripheral
* @param data : Byte to transmit
* @return Nothing
* @note This function attempts to place a byte into the I2C Master
* Data Register
*
*/
static INLINE void Chip_I2CM_WriteByte(LPC_I2C_T *pI2C, uint8_t data)
{
pI2C->MSTDAT = (uint32_t) data;
}
/**
* @brief Read a single byte data from the I2C peripheral (master)
* @param pI2C : Pointer to selected I2C peripheral
* @return A single byte of data read
* @note This function reads a byte from the I2C receive hold register
* regardless of I2C state.
*/
static INLINE uint8_t Chip_I2CM_ReadByte(LPC_I2C_T *pI2C)
{
return (uint8_t) (pI2C->MSTDAT & I2C_MSTDAT_DATAMASK);
}
/**
* @brief Transfer state change handler
* @param pI2C : Pointer to selected I2C peripheral
* @param xfer : Pointer to a I2CM_XFER_T structure see notes below
* @return Returns non-zero value on completion of transfer. The @a status
* member of @a xfer structure contains the current status of the
* transfer at the end of the call.
* @note
* The parameter @a xfer should be same as the one passed to Chip_I2CM_Xfer()
* routine. This function should be called from the I2C interrupt handler
* only when a master interrupt occurs.
*/
uint32_t Chip_I2CM_XferHandler(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer);
/**
* @brief Transmit and Receive data in master mode
* @param pI2C : Pointer to selected I2C peripheral
* @param xfer : Pointer to a I2CM_XFER_T structure see notes below
* @return Nothing
* @note
* The parameter @a xfer should have its member @a slaveAddr initialized
* to the 7-Bit slave address to which the master will do the xfer, Bit0
* to bit6 should have the address and Bit8 is ignored. During the transfer
* no code (like event handler) must change the content of the memory
* pointed to by @a xfer. The member of @a xfer, @a txBuff and @a txSz be
* initialized to the memory from which the I2C must pick the data to be
* transfered to slave and the number of bytes to send respectively, similarly
* @a rxBuff and @a rxSz must have pointer to memroy where data received
* from slave be stored and the number of data to get from slave respectilvely.
* Following types of transfers are possible:
* - Write-only transfer: When @a rxSz member of @a xfer is set to 0.
*
* S Addr Wr [A] txBuff0 [A] txBuff1 [A] ... txBuffN [A] P
*
* - If I2CM_XFER_OPTION_IGNORE_NACK is set in @a options memeber
*
* S Addr Wr [A] txBuff0 [A or NA] ... txBuffN [A or NA] P
*
* - Read-only transfer: When @a txSz member of @a xfer is set to 0.
*
* S Addr Rd [A] [rxBuff0] A [rxBuff1] A ... [rxBuffN] NA P
*
* - If I2CM_XFER_OPTION_LAST_RX_ACK is set in @a options memeber
*
* S Addr Rd [A] [rxBuff0] A [rxBuff1] A ... [rxBuffN] A P
*
* - Read-Write transfer: When @a rxSz and @ txSz members of @a xfer are non-zero.
*
* S Addr Wr [A] txBuff0 [A] txBuff1 [A] ... txBuffN [A]
* S Addr Rd [A] [rxBuff0] A [rxBuff1] A ... [rxBuffN] NA P
*
*/
void Chip_I2CM_Xfer(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer);
/**
* @brief Transmit and Receive data in master mode
* @param pI2C : Pointer to selected I2C peripheral
* @param xfer : Pointer to a I2CM_XFER_T structure see notes below
* @return Returns non-zero value on successful completion of transfer.
* @note
* This function operates same as Chip_I2CM_Xfer(), but is a blocking call.
*/
uint32_t Chip_I2CM_XferBlocking(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __I2CM_540XX_H_ */

View File

@@ -0,0 +1,105 @@
/*
* @brief LPC540xx I2C slave driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "chip.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
/*****************************************************************************
* Public functions
****************************************************************************/
/* Slave transfer state change handler */
uint32_t Chip_I2CS_XferHandler(LPC_I2C_T *pI2C, const I2CS_XFER_T *xfers)
{
uint32_t done = 0, xferDone = 0;
uint8_t data;
uint32_t state;
/* Transfer complete? */
if ((Chip_I2C_GetPendingInt(pI2C) & I2C_INTENSET_SLVDESEL) != 0) {
Chip_I2CS_ClearStatus(pI2C, I2C_STAT_SLVDESEL);
xfers->slaveDone();
xferDone = 1;
}
else {
/* Determine the current I2C slave state */
state = Chip_I2CS_GetSlaveState(pI2C);
switch (state) {
case I2C_STAT_SLVCODE_ADDR: /* Slave address received */
/* Get slave address that needs servicing */
data = Chip_I2CS_GetSlaveAddr(pI2C, Chip_I2CS_GetSlaveMatchIndex(pI2C));
/* Call address callback */
xfers->slaveStart(data);
break;
case I2C_STAT_SLVCODE_RX: /* Data byte received, not used with DMA */
/* Get received data */
data = Chip_I2CS_ReadByte(pI2C);
done = xfers->slaveRecv(data);
break;
case I2C_STAT_SLVCODE_TX: /* Get byte that needs to be sent, or start DMA */
/* Get data to send */
done = xfers->slaveSend(&data);
if (!((done == I2C_SLVCTL_SLVNACK) || (done == I2C_SLVCTL_SLVDMA))) {
Chip_I2CS_WriteByte(pI2C, data);
}
break;
}
}
if (done == I2C_SLVCTL_SLVNACK) {
Chip_I2CS_SlaveNACK(pI2C);
done = 1;
}
else if (done == I2C_SLVCTL_SLVDMA) {
Chip_I2CS_SlaveEnableDMA(pI2C);
}
else {
Chip_I2CS_SlaveContinue(pI2C);
}
return xferDone;
}

View File

@@ -0,0 +1,369 @@
/*
* @brief LPC540xx I2C slave driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#ifndef __I2CS_540XX_H_
#define __I2CS_540XX_H_
#include "i2c_common_540xx.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup I2CS_540XX CHIP: LPC540xx I2C slave-only driver
* @ingroup I2C_540XX
* This driver only works in slave mode.
* @{
*/
/** @brief I2C slave service start callback
* This callback is called from the I2C slave handler when an I2C slave address is
* received and needs servicing. It's used to indicate the start of a slave transfer
* that will happen on the slave bus.
*/
typedef void (*I2CSlaveXferStart)(uint8_t addr);
/** @brief I2C slave send data callback
* This callback is called from the I2C slave handler when an I2C slave address needs
* data to send.<br>
* If you want to NAK the master, return I2C_SLVCTL_SLVNACK to the caller.
* Return I2C_SLVCTL_SLVCONTINUE or 0 to the caller for normal non-DMA data transfer.
* If you've setup a DMA descriptor for the transfer, return I2C_SLVCTL_SLVDMA to the caller.<br>
*/
typedef uint8_t (*I2CSlaveXferSend)(uint8_t *data);
/** @brief I2C slave receive data callback
* This callback is called from the I2C slave handler when an I2C slave address has
* receive data.<br>
* If you want to NAK the master, return I2C_SLVCTL_SLVNACK to the caller.
* Return I2C_SLVCTL_SLVCONTINUE or 0 to the caller for normal non-DMA data transfer.
* If you've setup a DMA descriptor for the transfer, return I2C_SLVCTL_SLVDMA to the caller.<br>
*/
typedef uint8_t (*I2CSlaveXferRecv)(uint8_t data);
/** @brief I2C slave service done callback
* This callback is called from the I2C slave handler when an I2C slave transfer is
* completed. It's used to indicate the end of a slave transfer.
*/
typedef void (*I2CSlaveXferDone)(void);
/**
* Slave transfer are performed using 4 callbacks. These 3 callbacks handle most I2C
* slave transfer cases. When the slave is setup and a slave interrupt is receive
* and processed with the Chip_I2CS_XferHandler() function in the I2C interrupt handler,
* one of these 4 callbacks is called. The callbacks can be used for unsized transfers
* from the master.
*
* When an address is received, the SlaveXferAddr() callback is called with the
* received address. Only addresses enabled in the slave controller will be handled.
* The slave controller can support up to 4 slave addresses.
*
* If the master is going to perform a read operation, the SlaveXferSend() callback
* is called. Place the data byte to send in *data and return a value of 0 or
* I2C_SLVCTL_SLVCONTINUE to the caller, or return a value o I2C_SLVCTL_SLVNACK to
* NACK the master. If you are using DMA and have setup a DMA descriptor in the
* callback, return I2C_SLVCTL_SLVDMA.<br>
*
* If the master performs a write operation, the SlaveXferRecv() callback is called
* with the received data. Return a value of 0 or I2C_SLVCTL_SLVCONTINUE to the caller
* to continue data transfer. Return I2C_SLVCTL_SLVNACK to NACk the master. If you
* are using DMA and have setup a DMA descriptor in the callback, return
* I2C_SLVCTL_SLVDMA.<br>
*
* Once the transfer completes, the SlaveXferDone() callback will be called.<br>
*/
typedef struct {
I2CSlaveXferStart slaveStart; /*!< Called when an matching I2C slave address is received */
I2CSlaveXferSend slaveSend; /*!< Called when a byte is needed to send to master */
I2CSlaveXferRecv slaveRecv; /*!< Called when a byte is received from master */
I2CSlaveXferDone slaveDone; /*!< Called when a slave transfer is complete */
} I2CS_XFER_T;
/**
* @brief Enable I2C slave interface
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note Do not call this function until the slave interface is fully configured.
*/
STATIC INLINE void Chip_I2CS_Enable(LPC_I2C_T *pI2C)
{
Chip_I2C_SetRegMask(&pI2C->CFG, I2C_CFG_MASK, I2C_CFG_SLVEN);
}
/**
* @brief Disable I2C slave interface
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
*/
STATIC INLINE void Chip_I2CS_Disable(LPC_I2C_T *pI2C)
{
Chip_I2C_ClearRegMask(&pI2C->CFG, I2C_CFG_MASK, I2C_CFG_SLVEN);
}
/**
* @brief Get I2C Status
* @param pI2C : Pointer to selected I2C peripheral
* @return I2C Status register value
* @note This function returns the value of the status register.
*/
STATIC INLINE uint32_t Chip_I2CS_GetStatus(LPC_I2C_T *pI2C)
{
return pI2C->STAT;
}
/**
* @brief Clear I2C status bits (slave)
* @param pI2C : Pointer to selected I2C peripheral
* @param clrStatus : Status bit to clear, must be I2C_STAT_SLVDESEL
* @return Nothing
* @note This function clears selected status flags.
*/
STATIC INLINE void Chip_I2CS_ClearStatus(LPC_I2C_T *pI2C, uint32_t clrStatus)
{
pI2C->STAT = clrStatus & I2C_STAT_SLVDESEL;
}
/**
* @brief Check if I2C slave is pending
* @param pI2C : Pointer to selected I2C peripheral
* @return Returns TRUE if the slave is pending else returns FALSE
* @note
*/
STATIC INLINE bool Chip_I2CS_IsSlavePending(LPC_I2C_T *pI2C)
{
return (pI2C->STAT & I2C_STAT_SLVPENDING) != 0;
}
/**
* @brief Check if I2C slave is selected
* @param pI2C : Pointer to selected I2C peripheral
* @return Returns TRUE if the slave is is selected, otherwise FALSE
* @note
*/
STATIC INLINE bool Chip_I2CS_IsSlaveSelected(LPC_I2C_T *pI2C)
{
return (pI2C->STAT & I2C_STAT_SLVSEL) != 0;
}
/**
* @brief Check if I2C slave is deselected
* @param pI2C : Pointer to selected I2C peripheral
* @return Returns TRUE if the slave is is deselected, otherwise FALSE
* @note
*/
STATIC INLINE bool Chip_I2CS_IsSlaveDeSelected(LPC_I2C_T *pI2C)
{
return (pI2C->STAT & I2C_STAT_SLVDESEL) != 0;
}
/**
* @brief Get current state of the I2C slave
* @param pI2C : Pointer to selected I2C peripheral
* @return slave State Code, a value of type I2C_STAT_SLVCODE_*
* @note After the slave is pending this state code tells the reason
* for slave pending.
*/
STATIC INLINE uint32_t Chip_I2CS_GetSlaveState(LPC_I2C_T *pI2C)
{
return (pI2C->STAT & I2C_STAT_SLVSTATE) >> 9;
}
/**
* @brief Returns the current slave address match index
* @param pI2C : Pointer to selected I2C peripheral
* @return slave match index, 0 - 3
*/
STATIC INLINE uint32_t Chip_I2CS_GetSlaveMatchIndex(LPC_I2C_T *pI2C)
{
return (pI2C->STAT & I2C_STAT_SLVIDX) >> 12;
}
/**
* @brief Slave Continue transfer operation (ACK)
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note This function sets the slave controller to continue transmission.
* This should be called only when slave is pending. The function writes a
* complete value to slave Control register, ORing is not advised.
*/
STATIC INLINE void Chip_I2CS_SlaveContinue(LPC_I2C_T *pI2C)
{
pI2C->SLVCTL = I2C_SLVCTL_SLVCONTINUE;
}
/**
* @brief Slave NACK operation
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note This function sets the slave controller to NAK the master.
*/
STATIC INLINE void Chip_I2CS_SlaveNACK(LPC_I2C_T *pI2C)
{
pI2C->SLVCTL = I2C_SLVCTL_SLVNACK;
}
/**
* @brief Enable slave DMA operation
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note This function enables DMA mode for the slave controller. In DMA
* mode, the 'continue' and 'NACK' operations aren't used and the I2C slave
* controller will automatically NACK any bytes beyond the available DMA
* buffer size.
*/
STATIC INLINE void Chip_I2CS_SlaveEnableDMA(LPC_I2C_T *pI2C)
{
pI2C->SLVCTL = I2C_SLVCTL_SLVDMA;
}
/**
* @brief Disable slave DMA operation
* @param pI2C : Pointer to selected I2C peripheral
* @return Nothing
* @note This function disables DMA mode for the slave controller.
*/
STATIC INLINE void Chip_I2CS_SlaveDisableDMA(LPC_I2C_T *pI2C)
{
pI2C->SLVCTL = 0;
}
/**
* @brief Transmit a single data byte through the I2C peripheral (slave)
* @param pI2C : Pointer to selected I2C peripheral
* @param data : Byte to transmit
* @return Nothing
* @note This function attempts to place a byte into the I2C slave
* Data Register
*
*/
STATIC INLINE void Chip_I2CS_WriteByte(LPC_I2C_T *pI2C, uint8_t data)
{
pI2C->SLVDAT = (uint32_t) data;
}
/**
* @brief Read a single byte data from the I2C peripheral (slave)
* @param pI2C : Pointer to selected I2C peripheral
* @return A single byte of data read
* @note This function reads a byte from the I2C receive hold register
* regardless of I2C state.
*/
STATIC INLINE uint8_t Chip_I2CS_ReadByte(LPC_I2C_T *pI2C)
{
return (uint8_t) (pI2C->SLVDAT & I2C_SLVDAT_DATAMASK);
}
/**
* @brief Set a I2C slave address for slave operation
* @param pI2C : Pointer to selected I2C peripheral
* @param slvNum : Possible slave address number, between 0 - 3
* @param slvAddr : Slave Address for the index (7-bits, bit 7 = 0)
* @return Nothing
* @note Setting a slave address also enables the slave address. Do
* not 'pre-shift' the slave address.
*/
STATIC INLINE void Chip_I2CS_SetSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum, uint8_t slvAddr)
{
pI2C->SLVADR[slvNum] = (uint32_t) (slvAddr << 1);
}
/**
* @brief Return a I2C programmed slave address
* @param pI2C : Pointer to selected I2C peripheral
* @param slvNum : Possible slave address number, between 0 - 3
* @return Nothing
*/
STATIC INLINE uint8_t Chip_I2CS_GetSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
{
return (pI2C->SLVADR[slvNum] >> 1) & 0x7F;
}
/**
* @brief Enable a I2C address
* @param pI2C : Pointer to selected I2C peripheral
* @param slvNum : Possible slave address number, between 0 - 3
* @return Nothing
*/
STATIC INLINE void Chip_I2CS_EnableSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
{
pI2C->SLVADR[slvNum] = (pI2C->SLVADR[slvNum] & I2C_SLVADR_MASK) & ~I2C_SLVADR_SADISABLE;
}
/**
* @brief Disable a I2C address
* @param pI2C : Pointer to selected I2C peripheral
* @param slvNum : Possible slave address number, between 0 - 3
* @return Nothing
*/
STATIC INLINE void Chip_I2CS_DisableSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
{
pI2C->SLVADR[slvNum] = (pI2C->SLVADR[slvNum] & I2C_SLVADR_MASK) | I2C_SLVADR_SADISABLE;
}
/**
* @brief Setup slave qialifier address
* @param pI2C : Pointer to selected I2C peripheral
* @param extend : true to extend I2C slave detect address 0 range, or false to match to corresponding bits
* @param slvAddr : Slave address qualifier, see SLVQUAL0 register in User Manual
* @return Nothing
* @note Do not 'pre-shift' the slave address.
*/
STATIC INLINE void Chip_I2CS_SetSlaveQual0(LPC_I2C_T *pI2C, bool extend, uint8_t slvNum)
{
slvNum = slvNum << 1;
if (extend) {
slvNum |= I2C_SLVQUAL_QUALMODE0;
}
pI2C->SLVQUAL0 = slvNum;
}
/**
* @brief Slave transfer state change handler
* @param pI2C : Pointer to selected I2C peripheral
* @param xfers : Pointer to a I2CS_MULTI_XFER_T structure see notes below
* @return Returns non-zero value on completion of transfer or NAK
* @note See @ref I2CS_XFER_T for more information on this function. When using
* this function, the I2C_INTENSET_SLVPENDING and I2C_INTENSET_SLVDESEL interrupts
* should be enabled and setup in the I2C interrupt handler to call this function
* when they fire.
*/
uint32_t Chip_I2CS_XferHandler(LPC_I2C_T *pI2C, const I2CS_XFER_T *xfers);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __I2CS_540XX_H_ */

View File

@@ -0,0 +1,264 @@
/*
* @brief LPC540XX SPI driver
*
* @note
* Copyright(C) NXP Semiconductors, 2012
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licenser disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "chip.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
STATIC void SPI_Send_Data_RxIgnore(LPC_SPI_T *pSPI,
SPI_DATA_SETUP_T *pXfSetup)
{
if (pXfSetup->TxCnt == (pXfSetup->Length - 1)) {
Chip_SPI_SendLastFrame_RxIgnore(pSPI, pXfSetup->pTx[pXfSetup->TxCnt], pXfSetup->DataSize);
}
else {
Chip_SPI_SendMidFrame(pSPI, pXfSetup->pTx[pXfSetup->TxCnt]);
}
pXfSetup->TxCnt++;
}
STATIC void SPI_Send_Data(LPC_SPI_T *pSPI,
SPI_DATA_SETUP_T *pXfSetup)
{
if (pXfSetup->TxCnt == (pXfSetup->Length - 1)) {
Chip_SPI_SendLastFrame(pSPI, pXfSetup->pTx[pXfSetup->TxCnt], pXfSetup->DataSize);
}
else {
Chip_SPI_SendMidFrame(pSPI, pXfSetup->pTx[pXfSetup->TxCnt]);
}
pXfSetup->TxCnt++;
}
STATIC void SPI_Send_Dummy(LPC_SPI_T *pSPI,
SPI_DATA_SETUP_T *pXfSetup)
{
if (pXfSetup->RxCnt == (pXfSetup->Length - 1)) {
Chip_SPI_SendLastFrame(pSPI, 0x55, pXfSetup->DataSize);
}
else {
Chip_SPI_SendMidFrame(pSPI, 0x55);
}
}
STATIC void SPI_Receive_Data(LPC_SPI_T *pSPI,
SPI_DATA_SETUP_T *pXfSetup)
{
pXfSetup->pRx[pXfSetup->RxCnt] = Chip_SPI_ReceiveFrame(pSPI);
pXfSetup->RxCnt++;
}
/*****************************************************************************
* Public functions
****************************************************************************/
/* Calculate the Clock Rate Divider for SPI Peripheral */
uint32_t Chip_SPI_CalClkRateDivider(LPC_SPI_T *pSPI, uint32_t bitRate)
{
uint32_t SPIClk;
uint32_t DivVal = 1;
/* Get SPI clock rate */
SPIClk = Chip_Clock_GetAsyncSysconClockRate(); /*The peripheral clock for both SPIs is the Async Syscon clock*/
DivVal = SPIClk / bitRate;
return DivVal;
}
/* Initialize the SPI */
void Chip_SPI_IF_Init(LPC_SPI_T *pSPI, SPI_MODECONFIG_T *pConfig)
{
uint32_t EnStat;
Chip_SPI_Init(pSPI);
EnStat = pSPI->CFG & SPI_CFG_SPI_EN;
/* Disable before update CFG register */
if (EnStat) {
Chip_SPI_Disable(pSPI);
}
/* SPI Configurate */
pSPI->CFG = ((uint32_t) pConfig->ClockMode) | ((uint32_t) pConfig->DataOrder) | ((uint32_t) pConfig->Mode) |
((uint32_t) pConfig->SSELPol);
if ( pConfig->Mode == SPI_CFG_MASTER_EN ) {
/* Rate Divider setting */
pSPI->DIV = SPI_DIV_VAL(pConfig->ClkDiv);
}
/* Clear status flag*/
Chip_SPI_ClearStatus(pSPI, SPI_STAT_RXOV | SPI_STAT_TXUR | SPI_STAT_SSA | SPI_STAT_SSD);
/* Return the previous state */
if (EnStat) {
Chip_SPI_Enable(pSPI);
}
}
/* Disable/Enable Interrupt */
void Chip_SPI_Int_Cmd(LPC_SPI_T *pSPI, uint32_t IntMask, FunctionalState NewState)
{
if (NewState == ENABLE) {
Chip_SPI_EnableInts(pSPI, IntMask);
}
else {
Chip_SPI_DisableInts(pSPI, IntMask);
}
}
/*Send and Receive SPI Data */
uint32_t Chip_SPI_RWFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
{
uint32_t Status;
/* Clear status */
Chip_SPI_ClearStatus(pSPI, SPI_STAT_RXOV | SPI_STAT_TXUR | SPI_STAT_SSA | SPI_STAT_SSD);
Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, SPI_TXCTL_ASSERT_SSEL | SPI_TXCTL_EOF);
pXfSetup->TxCnt = pXfSetup->RxCnt = 0;
while ((pXfSetup->TxCnt < pXfSetup->Length) ||
(pXfSetup->RxCnt < pXfSetup->Length)) {
Status = Chip_SPI_GetStatus(pSPI);
/* In case of TxReady */
if ((Status & SPI_STAT_TXRDY) && (pXfSetup->TxCnt < pXfSetup->Length)) {
SPI_Send_Data(pSPI, pXfSetup);
}
/*In case of Rx ready */
if ((Status & SPI_STAT_RXRDY) && (pXfSetup->RxCnt < pXfSetup->Length)) {
SPI_Receive_Data(pSPI, pXfSetup);
}
}
/* Check error */
if (Chip_SPI_GetStatus(pSPI) & (SPI_STAT_RXOV | SPI_STAT_TXUR)) {
return 0;
}
return pXfSetup->TxCnt;
}
uint32_t Chip_SPI_WriteFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
{
/* Clear status */
Chip_SPI_ClearStatus(pSPI, SPI_STAT_RXOV | SPI_STAT_TXUR | SPI_STAT_SSA | SPI_STAT_SSD);
Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, SPI_TXCTL_ASSERT_SSEL | SPI_TXCTL_EOF | SPI_TXCTL_RXIGNORE);
pXfSetup->TxCnt = pXfSetup->RxCnt = 0;
while (pXfSetup->TxCnt < pXfSetup->Length) {
/* Wait for TxReady */
while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_TXRDY)) {}
SPI_Send_Data_RxIgnore(pSPI, pXfSetup);
}
/* Make sure the last frame sent completely*/
while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_SSD)) {}
Chip_SPI_ClearStatus(pSPI, SPI_STAT_SSD);
/* Check overrun error */
if (Chip_SPI_GetStatus(pSPI) & SPI_STAT_TXUR) {
return 0;
}
return pXfSetup->TxCnt;
}
uint32_t Chip_SPI_ReadFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
{
/* Clear status */
Chip_SPI_ClearStatus(pSPI, SPI_STAT_RXOV | SPI_STAT_TXUR | SPI_STAT_SSA | SPI_STAT_SSD);
Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, SPI_TXCTL_ASSERT_SSEL | SPI_TXCTL_EOF);
pXfSetup->TxCnt = pXfSetup->RxCnt = 0;
while (pXfSetup->RxCnt < pXfSetup->Length) {
/* Wait for TxReady */
while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_TXRDY)) {}
SPI_Send_Dummy(pSPI, pXfSetup);
/* Wait for receive data */
while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_RXRDY)) {}
SPI_Receive_Data(pSPI, pXfSetup);
}
/* Check overrun error */
if (Chip_SPI_GetStatus(pSPI) & (SPI_STAT_RXOV | SPI_STAT_TXUR)) {
return 0;
}
return pXfSetup->RxCnt;
}
/* SPI Interrupt Read/Write with 8-bit frame width */
Status Chip_SPI_Int_RWFrames(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
{
uint32_t Status;
Status = Chip_SPI_GetStatus(pSPI);
/* Check error in INTSTAT register */
if (Status & (SPI_STAT_RXOV | SPI_STAT_TXUR)) {
return ERROR;
}
if (pXfSetup->TxCnt == 0) {
Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, SPI_TXCTL_ASSERT_SSEL | SPI_TXCTL_EOF);
}
if (pXfSetup->pRx == NULL) {
if ((Status & SPI_STAT_TXRDY) && (pXfSetup->TxCnt < pXfSetup->Length)) {
SPI_Send_Data_RxIgnore(pSPI, pXfSetup);
}
}
else {
/* check if Tx ready */
if ((Status & SPI_STAT_TXRDY) && (pXfSetup->TxCnt < pXfSetup->Length)) {
SPI_Send_Data(pSPI, pXfSetup);
}
/* check if RX FIFO contains data */
if ((Status & SPI_STAT_RXRDY) && (pXfSetup->RxCnt < pXfSetup->Length)) {
SPI_Receive_Data(pSPI, pXfSetup);
}
}
return SUCCESS;
}
// end file

View File

@@ -0,0 +1,262 @@
/*
* @brief LPC540XX SPI driver
*
* @note
* Copyright(C) NXP Semiconductors, 2012
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#ifndef __SPI_540XX_H_
#define __SPI_540XX_H_
#include "spi_common_540xx.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup SPI_LEGACY 540XX CHIP: LPC540XX SPI legacy driver
* @ingroup SPI_COMMON_540XX
* @{
*/
typedef enum {
SLAVE0 = ((~(1 << 0)) & 0xf),
SLAVE1 = ((~(1 << 1)) & 0xf),
SLAVE2 = ((~(1 << 2)) & 0xf),
SLAVE3 = ((~(1 << 3)) & 0xf)
} SLAVE_T;
#define SPI_TXDATCTL_SSELN(s) ((s) << 16)
/** @brief SPI Mode*/
typedef enum {
SPI_MODE_MASTER = SPI_CFG_MASTER_EN, /* Master Mode */
SPI_MODE_SLAVE = SPI_CFG_SLAVE_EN, /* Slave Mode */
} SPI_MODE_T;
/** @brief SPI Data Order Mode*/
typedef enum IP_SPI_DATA_ORDER {
SPI_DATA_MSB_FIRST = SPI_CFG_MSB_FIRST_EN, /* Standard Order */
SPI_DATA_LSB_FIRST = SPI_CFG_LSB_FIRST_EN, /* Reverse Order */
} SPI_DATA_ORDER_T;
/** @brief SPI SSEL Polarity definition*/
typedef enum IP_SPI_SSEL_POL {
SPI_SSEL_ACTIVE_LO = SPI_CFG_SPOL_LO, /* SSEL is active Low*/
SPI_SSEL_ACTIVE_HI = SPI_CFG_SPOL_HI, /* SSEL is active High */
} SPI_SSEL_POL_T;
/**
* @brief SPI Configure Struct
*/
typedef struct {
SPI_MODE_T Mode; /* Mode Select */
SPI_CLOCK_MODE_T ClockMode; /* CPHA CPOL Select */
SPI_DATA_ORDER_T DataOrder; /* MSB/LSB First */
SPI_SSEL_POL_T SSELPol; /* SSEL Polarity Select */
uint16_t ClkDiv; /* SPI Clock Divider Value */
} SPI_MODECONFIG_T;
/**
* @brief SPI data setup structure
*/
typedef struct {
uint16_t *pTx; /**< Pointer to data buffer*/
uint32_t TxCnt;/* Transmit Counter */
uint16_t *pRx; /**< Pointer to data buffer*/
uint32_t RxCnt;/* Transmit Counter */
uint32_t Length; /**< Data Length*/
uint16_t DataSize; /** < The size of a frame (1-16)*/
uint32_t completion_flag;
} SPI_DATA_SETUP_T;
/**
* @brief Initialize the SPI
* @param pSPI : The base SPI peripheral on the chip
* @param pConfig : SPI Configuration
* @return Nothing
*/
void Chip_SPI_IF_Init(LPC_SPI_T *pSPI, SPI_MODECONFIG_T *pConfig);
/**
* @brief Calculate the divider for SPI clock
* @param pSPI : The base of SPI peripheral on the chip
* @param bitRate : Expected clock rate
* @return Divider value
*/
uint32_t Chip_SPI_CalClkRateDivider(LPC_SPI_T *pSPI, uint32_t bitRate);
/**
* @brief Enable/Disable SPI interrupt
* @param pSPI : The base SPI peripheral on the chip
* @param IntMask : Interrupt mask
* @param NewState : ENABLE or DISABLE interrupt
* @return Nothing
*/
void Chip_SPI_Int_Cmd(LPC_SPI_T *pSPI, uint32_t IntMask, FunctionalState NewState);
/**
* @brief Set control information including SSEL, EOT, EOF RXIGNORE and FLEN
* @param pSPI : The base of SPI peripheral on the chip
* @param Flen : Data size (1-16)
* @param Flag : Flag control (Or-ed values of SPI_TXCTL_*)
* @note The control information has no effect unless data is later written to TXDAT
* @return Nothing
*/
STATIC INLINE void Chip_SPI_SetControlInfo(LPC_SPI_T *pSPI, uint8_t Flen, uint32_t Flag)
{
pSPI->TXCTRL = Flag | SPI_TXDATCTL_FLEN(Flen - 1);
}
/**
* @brief Send the first Frame of a transfer (Rx Ignore)
* @param pSPI : The base of SPI peripheral on the chip
* @param Data : Transmit data
* @param DataSize : Data Size (1-16)
* @return Nothing
*/
STATIC INLINE void Chip_SPI_SendFirstFrame_RxIgnore(LPC_SPI_T *pSPI, uint16_t Data, uint8_t DataSize)
{
pSPI->TXDATCTL = SPI_TXDATCTL_ASSERT_SSEL | SPI_TXDATCTL_EOF | SPI_TXDATCTL_RXIGNORE | SPI_TXDATCTL_FLEN(
DataSize - 1) | SPI_TXDATCTL_DATA(Data);
}
/**
* @brief Send the first Frame of a transfer
* @param pSPI : The base of SPI peripheral on the chip
* @param Data : Transmit data
* @param DataSize : Data Size (1-16)
* @return Nothing
*/
STATIC INLINE void Chip_SPI_SendFirstFrame(LPC_SPI_T *pSPI, uint16_t Data, uint8_t DataSize)
{
pSPI->TXDATCTL = SPI_TXDATCTL_ASSERT_SSEL | SPI_TXDATCTL_EOF | SPI_TXDATCTL_FLEN(DataSize - 1) | SPI_TXDATCTL_DATA(
Data);
}
/**
* @brief Send the middle Frame of a transfer
* @param pSPI : The base of SPI peripheral on the chip
* @param Data : Transmit data
* @return Nothing
*/
STATIC INLINE void Chip_SPI_SendMidFrame(LPC_SPI_T *pSPI, uint16_t Data)
{
pSPI->TXDAT = SPI_TXDAT_DATA(Data);
}
/**
* @brief Send the last Frame of a transfer (Rx Ignore)
* @param pSPI : The base of SPI peripheral on the chip
* @param Data : Transmit data
* @param DataSize : Data Size (1-16)
* @return Nothing
*/
STATIC INLINE void Chip_SPI_SendLastFrame_RxIgnore(LPC_SPI_T *pSPI, uint16_t Data, uint8_t DataSize)
{
pSPI->TXDATCTL = SPI_TXDATCTL_ASSERT_SSEL | SPI_TXDATCTL_EOF | SPI_TXDATCTL_EOT | SPI_TXDATCTL_RXIGNORE |
SPI_TXDATCTL_FLEN(DataSize - 1) | SPI_TXDATCTL_DATA(Data);
}
/**
* @brief Send the last Frame of a transfer
* @param pSPI : The base of SPI peripheral on the chip
* @param Data : Transmit data
* @param DataSize : Data Size (1-16)
* @return Nothing
*/
STATIC INLINE void Chip_SPI_SendLastFrame(LPC_SPI_T *pSPI, uint16_t Data, uint8_t DataSize)
{
pSPI->TXDATCTL = SPI_TXDATCTL_ASSERT_SSEL | SPI_TXDATCTL_EOF | SPI_TXDATCTL_EOT |
SPI_TXDATCTL_FLEN(DataSize - 1) | SPI_TXDATCTL_DATA(Data);
}
/**
* @brief Read data received
* @param pSPI : The base of SPI peripheral on the chip
* @return Receive data
*/
STATIC INLINE uint16_t Chip_SPI_ReceiveFrame(LPC_SPI_T *pSPI)
{
return SPI_RXDAT_DATA(pSPI->RXDAT);
}
/**
* @brief SPI Interrupt Read/Write
* @param pSPI : The base SPI peripheral on the chip
* @param xf_setup : Pointer to a SPI_DATA_SETUP_T structure that contains specified
* information about transmit/receive data configuration
* @return SUCCESS or ERROR
*/
Status Chip_SPI_Int_RWFrames(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *xf_setup);
/**
* @brief SPI Polling Read/Write in blocking mode
* @param pSPI : The base SPI peripheral on the chip
* @param pXfSetup : Pointer to a SPI_DATA_SETUP_T structure that contains specified
* information about transmit/receive data configuration
* @return Actual data length has been transferred
* @note
* This function can be used in both master and slave mode. It starts with writing phase and after that,
* a reading phase is generated to read any data available in RX_FIFO. All needed information is prepared
* through xf_setup param.
*/
uint32_t Chip_SPI_RWFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup);
/**
* @brief SPI Polling Write in blocking mode
* @param pSPI : The base SPI peripheral on the chip
* @param pXfSetup :Pointer to a SPI_DATA_SETUP_T structure that contains specified
* information about transmit/receive data configuration
* @return Actual data length has been transferred
* @note
* This function can be used in both master and slave mode. First, a writing operation will send
* the needed data. After that, a dummy reading operation is generated to clear data buffer
*/
uint32_t Chip_SPI_WriteFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup);
/**
* @brief SPI Polling Read in blocking mode
* @param pSPI : The base SPI peripheral on the chip
* @param pXfSetup :Pointer to a SPI_DATA_SETUP_T structure that contains specified
* information about transmit/receive data configuration
* @return Actual data length has been read
* @note
* This function can be used in both master and slave mode. First, a writing operation will send
* the needed data. After that, a dummy reading operation is generated to clear data buffer
*/
uint32_t Chip_SPI_ReadFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __SPI_540XX_H_ */

View File

@@ -0,0 +1,158 @@
/*
* @brief LPC540XX SPI driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licenser disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "chip.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
/* Return clock for the passed peripheral */
static CHIP_SYSCON_CLOCK_T getSPIClk(LPC_SPI_T *pSPI)
{
if (pSPI == LPC_SPI0) {
return SYSCON_CLOCK_SPI0;
}
return SYSCON_CLOCK_SPI1;
}
/*****************************************************************************
* Public functions
****************************************************************************/
/* Initialize the SPI */
void Chip_SPI_Init(LPC_SPI_T *pSPI)
{
/* Enable SPI clock and reset IP */
Chip_Clock_EnablePeriphClock(getSPIClk(pSPI));
if (pSPI == LPC_SPI1) {
Chip_SYSCON_PeriphReset(RESET_SPI1);
}
else {
Chip_SYSCON_PeriphReset(RESET_SPI0);
}
}
/* De-initializes the SPI peripheral */
void Chip_SPI_DeInit(LPC_SPI_T *pSPI)
{
Chip_SPI_Disable(pSPI);
Chip_Clock_DisablePeriphClock(getSPIClk(pSPI));
}
/* Set SPI CFG register values */
void Chip_SPI_SetCFGRegBits(LPC_SPI_T *pSPI, uint32_t bits)
{
uint32_t reg;
/* Mask off bits that are write as 0, read as undefined */
reg = pSPI->CFG & SPI_CFG_BITMASK;
/* Update CFG register with only selected bits enabled */
pSPI->CFG = reg | bits;
}
/* Clear SPI CFG register values */
void Chip_SPI_ClearCFGRegBits(LPC_SPI_T *pSPI, uint32_t bits)
{
uint32_t reg;
/* Mask off bits that are write as 0, read as undefined */
reg = pSPI->CFG & SPI_CFG_BITMASK;
/* Update CFG register with only selected bits disabled */
pSPI->CFG = reg & ~bits;
}
/* Enable SPI master mode */
void Chip_SPI_EnableMasterMode(LPC_SPI_T *pSPI)
{
Chip_SPI_SetCFGRegBits(pSPI, SPI_CFG_MASTER_EN);
/* Deassert all chip selects, only in master mode */
pSPI->TXCTRL = SPI_TXDATCTL_DEASSERT_ALL;
}
/* Setup SAPI configuration */
void Chip_SPI_ConfigureSPI(LPC_SPI_T *pSPI, SPI_CFGSETUP_T *pCFG)
{
uint32_t reg;
/* Get register and mask off config bits this function alters */
reg = pSPI->CFG & ~(SPI_CFG_MASTER_EN | SPI_CFG_LSB_FIRST_EN |
SPI_CFG_CPHA_SECOND | SPI_CFG_CPOL_HI);
if (pCFG->master) {
reg |= SPI_CFG_MASTER_EN;
}
if (pCFG->lsbFirst) {
reg |= SPI_CFG_LSB_FIRST_EN;
}
reg |= (uint32_t) pCFG->mode;
Chip_SPI_SetCFGRegBits(pSPI, reg);
/* Deassert all chip selects, only in master mode */
pSPI->TXCTRL = SPI_TXDATCTL_DEASSERT_ALL;
}
/* Flush FIFOs */
void Chip_SPI_FlushFifos(LPC_SPI_T *pSPI)
{
Chip_SPI_Disable(pSPI);
Chip_SPI_Enable(pSPI);
}
/* Set SPI TXCTRL register control options */
void Chip_SPI_SetTXCTRLRegBits(LPC_SPI_T *pSPI, uint32_t bits)
{
uint32_t reg;
reg = pSPI->TXCTRL & SPI_TXDATCTL_CTRLMASK;
pSPI->TXCTRL = reg | bits;
}
/* Clear SPI TXCTRL register control options */
void Chip_SPI_ClearTXCTRLRegBits(LPC_SPI_T *pSPI, uint32_t bits)
{
uint32_t reg;
reg = pSPI->TXCTRL & SPI_TXDATCTL_CTRLMASK;
pSPI->TXCTRL = reg & ~bits;
}

View File

@@ -0,0 +1,524 @@
/*
* @brief LPC540XX SPI common functions and definitions
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#ifndef __SPI_COMMON_540XX_H_
#define __SPI_COMMON_540XX_H_
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup SPI_COMMON_540XX CHIP: LPC540XX SPI common functions and definitions
* @ingroup CHIP_540XX_Drivers
* @{
*/
/**
* @brief SPI register block structure
*/
typedef struct { /*!< SPI Structure */
__IO uint32_t CFG; /*!< SPI Configuration register */
__IO uint32_t DLY; /*!< SPI Delay register */
__IO uint32_t STAT; /*!< SPI Status register */
__IO uint32_t INTENSET; /*!< SPI Interrupt Enable Set register */
__O uint32_t INTENCLR; /*!< SPI Interrupt Enable Clear register */
__I uint32_t RXDAT; /*!< SPI Receive Data register */
__IO uint32_t TXDATCTL; /*!< SPI Transmit Data with Control register */
__IO uint32_t TXDAT; /*!< SPI Transmit Data register */
__IO uint32_t TXCTRL; /*!< SPI Transmit Control register */
__IO uint32_t DIV; /*!< SPI clock Divider register */
__I uint32_t INTSTAT; /*!< SPI Interrupt Status register */
} LPC_SPI_T;
/**
* Macro defines for SPI Configuration register
*/
#define SPI_CFG_BITMASK (0xFBD) /** SPI register bit mask */
#define SPI_CFG_SPI_EN (1 << 0) /** SPI Slave Mode Select */
#define SPI_CFG_SLAVE_EN (0 << 0) /** SPI Master Mode Select */
#define SPI_CFG_MASTER_EN (1 << 2) /** SPI MSB First mode enable */
#define SPI_CFG_MSB_FIRST_EN (0 << 3) /** SPI LSB First mode enable */
#define SPI_CFG_LSB_FIRST_EN (1 << 3) /** SPI Clock Phase Select */
#define SPI_CFG_CPHA_FIRST (0 << 4) /** Capture data on the first edge, Change data on the following edge */
#define SPI_CFG_CPHA_SECOND (1 << 4) /** SPI Clock Polarity Select */
#define SPI_CFG_CPOL_LO (0 << 5) /** The rest state of the clock (between frames) is low. */
#define SPI_CFG_CPOL_HI (1 << 5) /** The rest state of the clock (between frames) is high. */
#define SPI_CFG_LBM_EN (1 << 7) /** SPI control 1 loopback mode enable */
#define SPI_CFG_SPOL_LO (0 << 8) /** SPI SSEL0 Polarity Select */
#define SPI_CFG_SPOL_HI (1 << 8) /** SSEL0 is active High */
#define SPI_CFG_SPOLNUM_HI(n) (1 << ((n) + 8)) /** SSELN is active High, selects 0 - 3 */
/**
* Macro defines for SPI Delay register
*/
#define SPI_DLY_BITMASK (0xFFFF) /** SPI DLY Register Mask */
#define SPI_DLY_PRE_DELAY(n) (((n) & 0x0F) << 0) /** Time in SPI clocks between SSEL assertion and the beginning of a data frame */
#define SPI_DLY_POST_DELAY(n) (((n) & 0x0F) << 4) /** Time in SPI clocks between the end of a data frame and SSEL deassertion. */
#define SPI_DLY_FRAME_DELAY(n) (((n) & 0x0F) << 8) /** Minimum time in SPI clocks between adjacent data frames. */
#define SPI_DLY_TRANSFER_DELAY(n) (((n) & 0x0F) << 12) /** Minimum time in SPI clocks that the SSEL is deasserted between transfers. */
/**
* Macro defines for SPI Status register
*/
#define SPI_STAT_BITMASK (0x1FF) /** SPI STAT Register BitMask */
#define SPI_STAT_RXRDY (1 << 0) /** Receiver Ready Flag */
#define SPI_STAT_TXRDY (1 << 1) /** Transmitter Ready Flag */
#define SPI_STAT_RXOV (1 << 2) /** Receiver Overrun interrupt flag */
#define SPI_STAT_TXUR (1 << 3) /** Transmitter Underrun interrupt flag (In Slave Mode only) */
#define SPI_STAT_SSA (1 << 4) /** Slave Select Assert */
#define SPI_STAT_SSD (1 << 5) /** Slave Select Deassert */
#define SPI_STAT_STALLED (1 << 6) /** Stalled status flag */
#define SPI_STAT_EOT (1 << 7) /** End Transfer flag */
#define SPI_STAT_MSTIDLE (1 << 8) /** Idle status flag */
/**
* Macro defines for SPI Interrupt Enable read and Set register
*/
#define SPI_INTENSET_BITMASK (0x3F) /** SPI INTENSET Register BitMask */
#define SPI_INTENSET_RXDYEN (1 << 0) /** Enable Interrupt when receiver data is available */
#define SPI_INTENSET_TXDYEN (1 << 1) /** Enable Interrupt when the transmitter holding register is available. */
#define SPI_INTENSET_RXOVEN (1 << 2) /** Enable Interrupt when a receiver overrun occurs */
#define SPI_INTENSET_TXUREN (1 << 3) /** Enable Interrupt when a transmitter underrun occurs (In Slave Mode Only)*/
#define SPI_INTENSET_SSAEN (1 << 4) /** Enable Interrupt when the Slave Select is asserted.*/
#define SPI_INTENSET_SSDEN (1 << 5) /** Enable Interrupt when the Slave Select is deasserted..*/
/**
* Macro defines for SPI Interrupt Enable Clear register
*/
#define SPI_INTENCLR_BITMASK (0x3F) /** SPI INTENCLR Register BitMask */
#define SPI_INTENCLR_RXDYEN (1 << 0) /** Disable Interrupt when receiver data is available */
#define SPI_INTENCLR_TXDYEN (1 << 1) /** Disable Interrupt when the transmitter holding register is available. */
#define SPI_INTENCLR_RXOVEN (1 << 2) /** Disable Interrupt when a receiver overrun occurs */
#define SPI_INTENCLR_TXUREN (1 << 3) /** Disable Interrupt when a transmitter underrun occurs (In Slave Mode Only) */
#define SPI_INTENCLR_SSAEN (1 << 4) /** Disable Interrupt when the Slave Select is asserted. */
#define SPI_INTENCLR_SSDEN (1 << 5) /** Disable Interrupt when the Slave Select is deasserted.. */
/**
* Macro defines for SPI Receiver Data register
*/
#define SPI_RXDAT_BITMASK (0x1FFFFF) /** SPI RXDAT Register BitMask */
#define SPI_RXDAT_DATA(n) ((n) & 0xFFFF) /** Receiver Data */
#define SPI_RXDAT_RXSSELN_ACTIVE (0 << 16) /** The state of SSEL pin is active */
#define SPI_RXDAT_RXSSELN_INACTIVE ((1 << 16) /** The state of SSEL pin is inactive */
#define SPI_RXDAT_RXSSELNUM_INACTIVE(n) (1 << ((n) + 16)) /** The state of SSELN pin is inactive */
#define SPI_RXDAT_SOT (1 << 20) /** Start of Transfer flag */
/**
* Macro defines for SPI Transmitter Data and Control register
*/
#define SPI_TXDATCTL_BITMASK (0xF7FFFFF) /** SPI TXDATCTL Register BitMask */
#define SPI_TXDATCTL_DATA(n) ((n) & 0xFFFF) /** SPI Transmit Data */
#define SPI_TXDATCTL_CTRLMASK (0xF7F0000) /** SPI TXDATCTL Register BitMask for control bits only */
#define SPI_TXDATCTL_ASSERT_SSEL (0 << 16) /** Assert SSEL0 pin */
#define SPI_TXDATCTL_DEASSERT_SSEL (1 << 16) /** Deassert SSEL0 pin */
#define SPI_TXDATCTL_DEASSERTNUM_SSEL(n) (1 << ((n) + 16)) /** Deassert SSELN pin */
#define SPI_TXDATCTL_DEASSERT_ALL (0xF << 16) /** Deassert all SSEL pins */
#define SPI_TXDATCTL_EOT (1 << 20) /** End of Transfer flag (TRANSFER_DELAY is applied after sending the current frame) */
#define SPI_TXDATCTL_EOF (1 << 21) /** End of Frame flag (FRAME_DELAY is applied after sending the current part) */
#define SPI_TXDATCTL_RXIGNORE (1 << 22) /** Receive Ignore Flag */
#define SPI_TXDATCTL_FLEN(n) (((n) & 0x0F) << 24) /** Frame length - 1 */
/**
* Macro defines for SPI Transmitter Data Register
*/
#define SPI_TXDAT_DATA(n) ((n) & 0xFFFF) /** SPI Transmit Data */
/**
* Macro defines for SPI Transmitter Control register
*/
#define SPI_TXCTL_BITMASK (0xF7F0000) /** SPI TXDATCTL Register BitMask */
#define SPI_TXCTL_ASSERT_SSEL (0 << 16) /** Assert SSEL0 pin */
#define SPI_TXCTL_DEASSERT_SSEL (1 << 16) /** Deassert SSEL0 pin */
#define SPI_TXCTL_DEASSERTNUM_SSEL(n) (1 << ((n) + 16)) /** Deassert SSELN pin */
#define SPI_TXDATCTL_DEASSERT_ALL (0xF << 16) /** Deassert all SSEL pins */
#define SPI_TXCTL_EOT (1 << 20) /** End of Transfer flag (TRANSFER_DELAY is applied after sending the current frame) */
#define SPI_TXCTL_EOF (1 << 21) /** End of Frame flag (FRAME_DELAY is applied after sending the current part) */
#define SPI_TXCTL_RXIGNORE (1 << 22) /** Receive Ignore Flag */
#define SPI_TXCTL_FLEN(n) ((((n) - 1) & 0x0F) << 24) /** Frame length, 0 - 16 */
#define SPI_TXCTL_FLENMASK (0xF << 24) /** Frame length mask */
/**
* Macro defines for SPI Divider register
*/
#define SPI_DIV_VAL(n) ((n) & 0xFFFF) /** Rate divider value mask (In Master Mode only)*/
/**
* Macro defines for SPI Interrupt Status register
*/
#define SPI_INTSTAT_BITMASK (0x3F) /** SPI INTSTAT Register Bitmask */
#define SPI_INTSTAT_RXRDY (1 << 0) /** Receiver Ready Flag */
#define SPI_INTSTAT_TXRDY (1 << 1) /** Transmitter Ready Flag */
#define SPI_INTSTAT_RXOV (1 << 2) /** Receiver Overrun interrupt flag */
#define SPI_INTSTAT_TXUR (1 << 3) /** Transmitter Underrun interrupt flag (In Slave Mode only) */
#define SPI_INTSTAT_SSA (1 << 4) /** Slave Select Assert */
#define SPI_INTSTAT_SSD (1 << 5) /** Slave Select Deassert */
/**
* @brief Initialize the SPI
* @param pSPI : The base SPI peripheral on the chip
* @return Nothing
*/
void Chip_SPI_Init(LPC_SPI_T *pSPI);
/**
* @brief Disable SPI operation
* @param pSPI : The base of SPI peripheral on the chip
* @return Nothing
* @note The SPI controller is disabled.
*/
void Chip_SPI_DeInit(LPC_SPI_T *pSPI);
/**
* @brief Set SPI CFG register values
* @param pSPI : The base of SPI peripheral on the chip
* @param bits : CFG register bits to set, amd OR'ed value of SPI_CFG_* definitions
* @return Nothing
* @note This function safely sets only the selected bits in the SPI CFG register.
* It can be used to enable multiple bits at once.
*/
void Chip_SPI_SetCFGRegBits(LPC_SPI_T *pSPI, uint32_t bits);
/**
* @brief Clear SPI CFG register values
* @param pSPI : The base of SPI peripheral on the chip
* @param bits : CFG register bits to clear, amd OR'ed value of SPI_CFG_* definitions
* @return Nothing
* @note This function safely clears only the selected bits in the SPI CFG register.
* It can be used to disable multiple bits at once.
*/
void Chip_SPI_ClearCFGRegBits(LPC_SPI_T *pSPI, uint32_t bits);
/**
* @brief Enable SPI peripheral
* @param pSPI : The base of SPI peripheral on the chip
* @return Nothing
*/
STATIC INLINE void Chip_SPI_Enable(LPC_SPI_T *pSPI)
{
Chip_SPI_SetCFGRegBits(pSPI, SPI_CFG_SPI_EN);
}
/**
* @brief Disable SPI peripheral
* @param pSPI : The base of SPI peripheral on the chip
* @return Nothing
*/
STATIC INLINE void Chip_SPI_Disable(LPC_SPI_T *pSPI)
{
Chip_SPI_ClearCFGRegBits(pSPI, SPI_CFG_SPI_EN);
}
/**
* @brief Enable SPI master mode
* @param pSPI : The base of SPI peripheral on the chip
* @return Nothing
* @note SPI slave mode will be disabled with this call. All SPI SSEL
* lines will also be deasserted.
*/
void Chip_SPI_EnableMasterMode(LPC_SPI_T *pSPI);
/**
* @brief Enable SPI slave mode
* @param pSPI : The base of SPI peripheral on the chip
* @return Nothing
* @note SPI master mode will be disabled with this call.
*/
STATIC INLINE void Chip_SPI_EnableSlaveMode(LPC_SPI_T *pSPI)
{
Chip_SPI_ClearCFGRegBits(pSPI, SPI_CFG_MASTER_EN);
}
/**
* @brief Enable LSB First transfers
* @param pSPI : The base of SPI peripheral on the chip
* @return Nothing
*/
STATIC INLINE void Chip_SPI_EnableLSBFirst(LPC_SPI_T *pSPI)
{
Chip_SPI_SetCFGRegBits(pSPI, SPI_CFG_LSB_FIRST_EN);
}
/**
* @brief Enable MSB First transfers
* @param pSPI : The base of SPI peripheral on the chip
* @return Nothing
*/
STATIC INLINE void Chip_SPI_EnableMSBFirst(LPC_SPI_T *pSPI)
{
Chip_SPI_ClearCFGRegBits(pSPI, SPI_CFG_LSB_FIRST_EN);
}
/** @brief SPI Clock Mode*/
typedef enum IP_SPI_CLOCK_MODE {
SPI_CLOCK_CPHA0_CPOL0 = SPI_CFG_CPOL_LO | SPI_CFG_CPHA_FIRST, /**< CPHA = 0, CPOL = 0 */
SPI_CLOCK_MODE0 = SPI_CLOCK_CPHA0_CPOL0, /**< Alias for CPHA = 0, CPOL = 0 */
SPI_CLOCK_CPHA1_CPOL0 = SPI_CFG_CPOL_LO | SPI_CFG_CPHA_SECOND, /**< CPHA = 0, CPOL = 1 */
SPI_CLOCK_MODE1 = SPI_CLOCK_CPHA1_CPOL0, /**< Alias for CPHA = 0, CPOL = 1 */
SPI_CLOCK_CPHA0_CPOL1 = SPI_CFG_CPOL_HI | SPI_CFG_CPHA_FIRST, /**< CPHA = 1, CPOL = 0 */
SPI_CLOCK_MODE2 = SPI_CLOCK_CPHA0_CPOL1, /**< Alias for CPHA = 1, CPOL = 0 */
SPI_CLOCK_CPHA1_CPOL1 = SPI_CFG_CPOL_HI | SPI_CFG_CPHA_SECOND, /**< CPHA = 1, CPOL = 1 */
SPI_CLOCK_MODE3 = SPI_CLOCK_CPHA1_CPOL1, /**< Alias for CPHA = 1, CPOL = 1 */
} SPI_CLOCK_MODE_T;
/**
* @brief Set SPI mode
* @param pSPI : The base of SPI peripheral on the chip
* @param mode : SPI mode to set the SPI interface to
* @return Nothing
*/
STATIC INLINE void Chip_SPI_SetSPIMode(LPC_SPI_T *pSPI, SPI_CLOCK_MODE_T mode)
{
Chip_SPI_ClearCFGRegBits(pSPI, (SPI_CFG_CPOL_HI | SPI_CFG_CPHA_SECOND));
Chip_SPI_SetCFGRegBits(pSPI, (uint32_t) mode);
}
/**
* @brief Set polarity on the SPI chip select high
* @param pSPI : The base of SPI peripheral on the chip
* @param csNum : Chip select number, 0 - 3
* @return Nothing
* @note SPI chip select polarity is active high.
*/
STATIC INLINE void Chip_SPI_SetCSPolHigh(LPC_SPI_T *pSPI, uint8_t csNum)
{
Chip_SPI_SetCFGRegBits(pSPI, SPI_CFG_SPOLNUM_HI(csNum));
}
/**
* @brief Set polarity on the SPI chip select low
* @param pSPI : The base of SPI peripheral on the chip
* @param csNum : Chip select number, 0 - 3
* @return Nothing
* @note SPI chip select polarity is active low.
*/
STATIC INLINE void Chip_SPI_SetCSPolLow(LPC_SPI_T *pSPI, uint8_t csNum)
{
Chip_SPI_ClearCFGRegBits(pSPI, SPI_CFG_SPOLNUM_HI(csNum));
}
/** SPI configuration structure used for setting up master/slave mode, LSB or
* MSB first, and SPI mode in a single function call. */
typedef struct {
uint32_t master : 8; /* Set to non-0 value to use master mode, 0 for slave */
uint32_t lsbFirst : 8; /* Set to non-0 value to send LSB first, 0 for MSB first */
SPI_CLOCK_MODE_T mode : 8; /* Mode selection */
uint32_t reserved : 8; /* Reserved, for alignment only */
} SPI_CFGSETUP_T;
/**
* @brief Setup SPI configuration
* @param pSPI : The base of SPI peripheral on the chip
* @param pCFG : Pointer to SPI configuration structure
* @return Nothing
*/
void Chip_SPI_ConfigureSPI(LPC_SPI_T *pSPI, SPI_CFGSETUP_T *pCFG);
/**
* @brief Get the current status of SPI controller
* @param pSPI : The base of SPI peripheral on the chip
* @return SPI Status (Or-ed bit value of SPI_STAT_*)
* @note Mask the return value with a value of type SPI_STAT_* to determine
* if that status is active.
*/
STATIC INLINE uint32_t Chip_SPI_GetStatus(LPC_SPI_T *pSPI)
{
return pSPI->STAT;
}
/**
* @brief Clear SPI status
* @param pSPI : The base of SPI peripheral on the chip
* @param Flag : Clear Flag (Or-ed bit value of SPI_STAT_*)
* @return Nothing
* @note Only SPI_STAT_RXOV, SPI_STAT_TXUR, SPI_STAT_SSA, and
* SPI_STAT_SSD statuses can be cleared.
*/
STATIC INLINE void Chip_SPI_ClearStatus(LPC_SPI_T *pSPI, uint32_t Flag)
{
pSPI->STAT = Flag;
}
/**
* @brief Enable a SPI interrupt
* @param pSPI : The base of SPI peripheral on the chip
* @param intMask : Or'ed value of SPI_INTENSET_* values to enable
* @return Nothing
*/
STATIC INLINE void Chip_SPI_EnableInts(LPC_SPI_T *pSPI, uint32_t Flag)
{
pSPI->INTENSET = Flag;
}
/**
* @brief Disable a SPI interrupt
* @param pSPI : The base of SPI peripheral on the chip
* @param intMask : Or'ed value of SPI_INTENCLR_* values to disable
* @return Nothing
*/
STATIC INLINE void Chip_SPI_DisableInts(LPC_SPI_T *pSPI, uint32_t Flag)
{
pSPI->INTENCLR = Flag;
}
/**
* @brief Return enabled SPI interrupts
* @param pSPI : The base of SPI peripheral on the chip
* @return An Or'ed value of SPI_INTENSET_* values
* @note Mask the return value with a SPI_INTENSET_* value to determine
* if the interrupt is enabled.
*/
STATIC INLINE uint32_t Chip_SPI_GetEnabledInts(LPC_SPI_T *pSPI)
{
return pSPI->INTENSET;
}
/**
* @brief Return pending SPI interrupts
* @param pSPI : The base of SPI peripheral on the chip
* @return An Or'ed value of SPI_INTSTAT_* values
* @note Mask the return value with a SPI_INTSTAT_* value to determine
* if the interrupt is pending.
*/
STATIC INLINE uint32_t Chip_SPI_GetPendingInts(LPC_SPI_T *pSPI)
{
return pSPI->INTSTAT;
}
/**
* @brief Flush FIFOs
* @param pSPI : The base of SPI peripheral on the chip
* @return Nothing
*/
void Chip_SPI_FlushFifos(LPC_SPI_T *pSPI);
/**
* @brief Read raw data from receive FIFO with status bits
* @param pSPI : The base of SPI peripheral on the chip
* @return Current value in receive data FIFO plus status bits
*/
STATIC INLINE uint32_t Chip_SPI_ReadRawRXFifo(LPC_SPI_T *pSPI)
{
return pSPI->RXDAT;
}
/**
* @brief Read data from receive FIFO masking off status bits
* @param pSPI : The base of SPI peripheral on the chip
* @return Current value in receive data FIFO
* @note The return value is masked with 0xFFFF to not exceed 16-bits. All
* other status bits are thrown away. This register should only be read if it
* has data in it. This function is useful for systems that don't need SPI
* select (SSEL) monitoring.
*/
STATIC INLINE uint32_t Chip_SPI_ReadRXData(LPC_SPI_T *pSPI)
{
return (pSPI->RXDAT & 0xFFFF);
}
/**
* @brief Write data to transmit FIFO
* @param pSPI : The base of SPI peripheral on the chip
* @param data : Data to write
* @return Nothing
*/
STATIC INLINE void Chip_SPI_WriteTXData(LPC_SPI_T *pSPI, uint16_t data)
{
pSPI->TXDAT = (uint32_t) data;
}
/**
* @brief Set SPI TXCTRL register control options
* @param pSPI : The base of SPI peripheral on the chip
* @param bits : TXCTRL register bits to set, amd OR'ed value of SPI_TXDATCTL_* definitions
* @return Nothing
* @note This function safely sets only the selected bits in the SPI TXCTRL register.
* It can be used to enable multiple bits at once.
*/
void Chip_SPI_SetTXCTRLRegBits(LPC_SPI_T *pSPI, uint32_t bits);
/**
* @brief Clear SPI TXCTRL register control options
* @param pSPI : The base of SPI peripheral on the chip
* @param bits : TXCTRL register bits to clear, amd OR'ed value of SPI_TXDATCTL_* definitions
* @return Nothing
* @note This function safely clears only the selected bits in the SPI TXCTRL register.
* It can be used to disable multiple bits at once.
*/
void Chip_SPI_ClearTXCTRLRegBits(LPC_SPI_T *pSPI, uint32_t bits);
/**
* @brief Set TX control options (safe)
* @param pSPI : The base of SPI peripheral on the chip
* @param ctrlBits : Or'ed control bits to set
* @return Nothing
* @note Selectable control states include SPI_TXCTL_DEASSERTNUM_SSEL(0/1/2/3),
* SPI_TXCTL_EOT, SPI_TXCTL_EOF, SPI_TXCTL_RXIGNORE, and SPI_TXCTL_FLEN(bits).
*/
STATIC INLINE void Chip_SPI_SetTXCtl(LPC_SPI_T *pSPI, uint32_t ctrlBits)
{
Chip_SPI_SetTXCTRLRegBits(pSPI, ctrlBits);
}
/**
* @brief Clear TX control options (safe)
* @param pSPI : The base of SPI peripheral on the chip
* @param ctrlBits : Or'ed control bits to clear
* @return Nothing
* @note Selectable control states include SPI_TXCTL_DEASSERTNUM_SSEL(0/1/2/3),
* SPI_TXCTL_EOT, SPI_TXCTL_EOF, SPI_TXCTL_RXIGNORE, and SPI_TXCTL_FLEN(bits).
*/
STATIC INLINE void Chip_SPI_ClearTXCtl(LPC_SPI_T *pSPI, uint32_t ctrlBits)
{
Chip_SPI_ClearTXCTRLRegBits(pSPI, ctrlBits);
}
/**
* @brief Set TX data transfer size in bits
* @param pSPI : The base of SPI peripheral on the chip
* @param numBits : Number of bits to transmit and receive, must be 1 to 16
* @return Nothing
*/
STATIC INLINE void Chip_SPI_SetXferSize(LPC_SPI_T *pSPI, uint32_t ctrlBits)
{
Chip_SPI_ClearTXCTRLRegBits(pSPI, SPI_TXCTL_FLENMASK);
Chip_SPI_SetTXCTRLRegBits(pSPI, SPI_TXCTL_FLEN(ctrlBits));
}
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __SPI_COMMON_540XX_H_ */

View File

@@ -0,0 +1,232 @@
/*
* @brief LPC540XX SPI master driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licenser disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "chip.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
static volatile bool xmitOn;
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
/*****************************************************************************
* Public functions
****************************************************************************/
/* Get SPI master bit rate */
uint32_t Chip_SPIM_GetClockRate(LPC_SPI_T *pSPI)
{
// Magicoe return Chip_Clock_GetAsyncSysconClockRate() / (pSPI->DIV + 1);
return Chip_Clock_GetAsyncSyscon_ClockRate() / (pSPI->DIV + 1);
}
/* Set SPI master bit rate */
uint32_t Chip_SPIM_SetClockRate(LPC_SPI_T *pSPI, uint32_t rate)
{
uint32_t baseClock, div;
/* Get peripheral base clock rate */
// Magicoe baseClock = Chip_Clock_GetAsyncSysconClockRate();
baseClock = Chip_Clock_GetAsyncSyscon_ClockRate();
/* Compute divider */
div = baseClock / rate;
/* Limit values */
if (div == 0) {
div = 1;
}
else if (div > 0x10000) {
div = 0x10000;
}
pSPI->DIV = div - 1;
return Chip_SPIM_GetClockRate(pSPI);
}
/* Configure SPI Delay parameters */
void Chip_SPIM_DelayConfig(LPC_SPI_T *pSPI, SPIM_DELAY_CONFIG_T *pConfig)
{
pSPI->DLY = (SPI_DLY_PRE_DELAY(pConfig->PreDelay) |
SPI_DLY_POST_DELAY(pConfig->PostDelay) |
SPI_DLY_FRAME_DELAY(pConfig->FrameDelay) |
SPI_DLY_TRANSFER_DELAY(pConfig->TransferDelay - 1));
}
/* Assert a SPI select */
void Chip_SPIM_AssertSSEL(LPC_SPI_T *pSPI, uint8_t sselNum)
{
uint32_t reg;
reg = pSPI->TXCTRL & SPI_TXDATCTL_CTRLMASK;
/* Assert a SSEL line by driving it low */
reg &= ~SPI_TXDATCTL_DEASSERTNUM_SSEL(sselNum);
pSPI->TXCTRL = reg;
}
/* Deassert a SPI select */
void Chip_SPIM_DeAssertSSEL(LPC_SPI_T *pSPI, uint8_t sselNum)
{
uint32_t reg;
reg = pSPI->TXCTRL & SPI_TXDATCTL_CTRLMASK;
pSPI->TXCTRL = reg | SPI_TXDATCTL_DEASSERTNUM_SSEL(sselNum);
}
/* SPI master transfer state change handler */
void Chip_SPIM_XferHandler(LPC_SPI_T *pSPI, SPIM_XFER_T *xfer)
{
uint32_t data;
uint8_t flen;
/* Get length of a receive value */
flen = (pSPI->TXCTRL >> 24) & 0xF;
/* Master asserts slave */
if ((Chip_SPI_GetStatus(pSPI) & SPI_STAT_SSA) != 0) {
Chip_SPI_ClearStatus(pSPI, SPI_STAT_SSA);
/* SSEL assertion callback */
xfer->pCB->masterXferCSAssert(xfer);
}
/* Slave de-assertion */
if ((Chip_SPI_GetStatus(pSPI) & SPI_STAT_SSD) != 0) {
Chip_SPI_ClearStatus(pSPI, SPI_STAT_SSD);
/* If transmitter disabled and deassert happens, the transfer is done */
if (xmitOn == false) {
xfer->pCB->mMasterXferDone(xfer);
}
}
/* Transmit data? */
while (((Chip_SPI_GetStatus(pSPI) & SPI_STAT_TXRDY) != 0) && (xmitOn == true)) {
if ((xfer->txCount == 1) && (xfer->terminate)) {
/* Transfer is done, this will be last data */
Chip_SPIM_ForceEndOfTransfer(pSPI);
xmitOn = false;
}
else if (xfer->txCount == 0) {
/* Request a new buffer first */
xfer->pCB->masterXferSend(xfer);
}
if (xfer->txCount > 0) {
/* Send 0 if ignoring transmit */
if (xfer->pTXData8 == NULL) {
data = 0;
}
else {
/* Copy buffer to data */
if (flen > 8) {
data = (uint32_t) *xfer->pTXData16;
xfer->pTXData16++;
}
else {
data = (uint32_t) *xfer->pTXData8;
xfer->pTXData8++;
}
xfer->dataTXferred++;
}
Chip_SPI_WriteTXData(pSPI, data);
xfer->txCount--;
}
}
/* Data received? */
while ((Chip_SPI_GetStatus(pSPI) & SPI_STAT_RXRDY) != 0) {
/* Get raw data and status */
data = Chip_SPI_ReadRawRXFifo(pSPI);
/* Only copy data when not ignoring receive */
if (xfer->pRXData8 != NULL) {
/* Enough size in current buffers? */
if (xfer->rxCount == 0) {
/* Request a new buffer first */
xfer->pCB->masterXferRecv(xfer);
}
/* Copy data to buffer */
if (xfer->rxCount > 0) {
if (flen > 8) {
*xfer->pRXData16 = (uint16_t) (data & 0xFFFF);
xfer->pRXData16++;
}
else {
*xfer->pRXData8 = (uint8_t) (data & 0xFF);
xfer->pRXData8++;
}
xfer->dataRXferred++;
xfer->rxCount--;
}
}
}
}
/* Start non-blocking SPI master transfer */
void Chip_SPIM_Xfer(LPC_SPI_T *pSPI, SPIM_XFER_T *xfer)
{
/* Setup SPI master select, data length, EOT/EOF timing, and RX data ignore */
pSPI->TXCTRL = xfer->options | SPI_TXDATCTL_DEASSERT_ALL;
Chip_SPIM_AssertSSEL(pSPI, xfer->sselNum);
/* Clear initial transfer states */
xfer->dataRXferred = xfer->dataTXferred = 0;
/* Call main handler to start transfer */
xmitOn = true;
Chip_SPIM_XferHandler(pSPI, xfer);
}
/* Perform blocking SPI master transfer */
void Chip_SPIM_XferBlocking(LPC_SPI_T *pSPI, SPIM_XFER_T *xfer)
{
/* Start trasnfer */
Chip_SPIM_Xfer(pSPI, xfer);
/* Wait for termination */
while (xmitOn == true) {
Chip_SPIM_XferHandler(pSPI, xfer);
}
}

View File

@@ -0,0 +1,263 @@
/*
* @brief LPC540XX SPI master driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#ifndef __SPIM_540XX_H_
#define __SPIM_540XX_H_
#include "spi_common_540xx.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup SPI_MASTER_540XX CHIP: LPC540XX SPI master driver
* @ingroup SPI_COMMON_540XX
* @{
*/
/**
* @brief Get SPI master bit rate
* @param pSPI : The base of SPI peripheral on the chip
* @return The actual SPI clock bit rate
*/
uint32_t Chip_SPIM_GetClockRate(LPC_SPI_T *pSPI);
/**
* @brief Set SPI master bit rate
* @param pSPI : The base of SPI peripheral on the chip
* @param rate : Desired clock bit rate for the SPI interface
* @return The actual SPI clock bit rate
* @note This function will set the SPI clock divider to get closest
* to the desired rate as possible.
*/
uint32_t Chip_SPIM_SetClockRate(LPC_SPI_T *pSPI, uint32_t rate);
/**
* @brief SPI Delay Configure Struct
*/
typedef struct {
uint8_t PreDelay; /** Pre-delay value in SPI clocks, 0 - 15 */
uint8_t PostDelay; /** Post-delay value in SPI clocks, 0 - 15 */
uint8_t FrameDelay; /** Delay value between frames of a transfer in SPI clocks, 0 - 15 */
uint8_t TransferDelay; /** Delay value between transfers in SPI clocks, 1 - 16 */
} SPIM_DELAY_CONFIG_T;
/**
* @brief Config SPI Delay parameters
* @param pSPI : The base of SPI peripheral on the chip
* @param pConfig : SPI Delay Configure Struct
* @return Nothing
*/
void Chip_SPIM_DelayConfig(LPC_SPI_T *pSPI, SPIM_DELAY_CONFIG_T *pConfig);
/**
* @brief Forces an end of transfer for the current master transfer
* @param pSPI : The base of SPI peripheral on the chip
* @return Nothing
* @note Use this function to perform an immediate end of trasnfer for the
* current master operation. If the master is currently transferring data started
* with the Chip_SPIM_Xfer function, this terminates the transfer after the
* current byte completes and completes the transfer.
*/
STATIC INLINE void Chip_SPIM_ForceEndOfTransfer(LPC_SPI_T *pSPI)
{
pSPI->STAT = SPI_STAT_EOT;
}
/**
* @brief Assert a SPI select
* @param pSPI : The base of SPI peripheral on the chip
* @param sselNum : SPI select to assert, 0 - 3
* @return Nothing
*/
void Chip_SPIM_AssertSSEL(LPC_SPI_T *pSPI, uint8_t sselNum);
/**
* @brief Deassert a SPI select
* @param pSPI : The base of SPI peripheral on the chip
* @param sselNum : SPI select to deassert, 0 - 3
* @return Nothing
*/
void Chip_SPIM_DeAssertSSEL(LPC_SPI_T *pSPI, uint8_t sselNum);
/**
* @brief Enable loopback mode
* @param pSPI : The base of SPI peripheral on the chip
* @return Nothing
* @note Serial input is taken from the serial output (MOSI or MISO) rather
* than the serial input pin.
*/
STATIC INLINE void Chip_SPIM_EnableLoopBack(LPC_SPI_T *pSPI)
{
Chip_SPI_SetCFGRegBits(pSPI, SPI_CFG_LBM_EN);
}
/**
* @brief Disable loopback mode
* @param pSPI : The base of SPI peripheral on the chip
* @return Nothing
*/
STATIC INLINE void Chip_SPIM_DisableLoopBack(LPC_SPI_T *pSPI)
{
Chip_SPI_ClearCFGRegBits(pSPI, SPI_CFG_LBM_EN);
}
struct SPIM_XFER;
/** @brief SPI master select assert callback
* This callback is called from the SPI master handler when the SPI master
* selects the slave (asserts SSEL).
*/
typedef void (*SPIMasterXferCSAssert)(struct SPIM_XFER *pMasterXfer);
/** @brief SPI master send data callback
* This callback is called from the SPI master handler when the SPI master
* needs a data buffer to send.
*/
typedef void (*SPIMasterXferSend)(struct SPIM_XFER *pMasterXfer);
/** @brief SPI master receive data callback
* This callback is called from the SPI master handler when the SPI master
* needs a buffer to place data into.
*/
typedef void (*SPIMasterXferRecv)(struct SPIM_XFER *pMasterXfer);
/** @brief SPI master transfer select deassert data callback
* This callback is called from the SPI master handler when the SPI master
* deasserts the slave select.
*/
typedef void (*SPIMMasterXferCSDeAssert)(struct SPIM_XFER *pMasterXfer);
/** @brief SPI master transfer done data callback
* This callback is called from the SPI master handler when the SPI master
* has completed the transfer and becomes idle.
*/
typedef void (*SPIMMasterXferDone)(struct SPIM_XFER *pMasterXfer);
/** SPI slave callback functions */
typedef struct {
SPIMasterXferCSAssert masterXferCSAssert; /** SPI transfer CS assert, called when a slave select is asserted */
SPIMasterXferSend masterXferSend; /** SPI transfer data receive buffer callback, called when a send buffer is needed */
SPIMasterXferRecv masterXferRecv; /** SPI transfer send buffer callback, called when send buffer is needed (and SPI_TXCTL_RXIGNORE option is not set) */
SPIMMasterXferCSDeAssert mMasterXferCSDeAssert; /** SPI transfer CS deassert, called when a slave select is deasserted */
SPIMMasterXferDone mMasterXferDone; /** SPI transfer done callback, called when transfer is complete */
} SPIM_CALLBACKS_T;
/** Slave transfer data context */
typedef struct SPIM_XFER {
const SPIM_CALLBACKS_T *pCB; /** Pointer to SPI master data callback functions */
union { /** Pointer to receive buffer, set to NULL to toss receeive data */
uint8_t *pRXData8; /** Receive buffer used with data transfer size <= 8-bits, modified by driver */
uint16_t *pRXData16; /** Receive buffer used with data transfer size > 8-bits, modified by driver */
};
union { /** Pointer to transmit buffer, set to NULL to transmit 0x0 */
uint8_t *pTXData8; /** Send buffer used with data transfer size <= 8-bits, modified by driver */
uint16_t *pTXData16; /** Send buffer used with data transfer size > 8-bits, modified by driver */
};
uint32_t options; /** Master transfer options, an OR'ed value of SPI_TXCTL_EOT, SPI_TXCTL_EOF, SPI_TXCTL_RXIGNORE, and SPI_TXCTL_FLEN(bits) */
uint16_t rxCount; /** Size of the pRXData buffer in items (not bytes), modified by driver */
uint16_t txCount; /** Number of items (not bytes) to send in pTXData buffer, modified by driver */
uint16_t dataRXferred; /** Total items (not bytes) received, modified by driver */
uint16_t dataTXferred; /** Total items (not bytes) transmitted, modified by driver */
uint8_t sselNum; /** Slave number assigned to this transfer, 0 - 3, used by driver to select slave */
bool terminate; /** Transfer will terminate when txCount goes to 0 and master goes idle, must be set before last byte is sent */
} SPIM_XFER_T;
/**
* @brief SPI master transfer state change handler
* @param pSPI : The base of SPI peripheral on the chip
* @param xfers : Pointer to a SPIM_XFER_T structure see notes below
* @return Nothing
* @note See @ref SPIM_XFER_T for more information on this function. When using
* this function, the SPI master interrupts should be enabled and setup in the SPI
* interrupt handler to call this function when they fire. This function is meant
* to be called from the interrupt handler.
*/
void Chip_SPIM_XferHandler(LPC_SPI_T *pSPI, SPIM_XFER_T *xfer);
/**
* @brief Start non-blocking SPI master transfer
* @param pSPI : The base of SPI peripheral on the chip
* @param xfers : Pointer to a SPIM_XFER_T structure see notes below
* @return Nothing
* @note This function starts a non-blocking SPI master transfer with the
* parameters setup in the passed @ref SPIM_XFER_T structure. Once the transfer is
* started, the interrupt handler must call Chip_SPIM_XferHandler to keep the
* transfer going and fed with data. This function should only be called when
* the master is idle.<br>
*
* This function must be called with the options and sselNum fields correctly
* setup. Initial data buffers and the callback pointer must also be setup. No
* sanity checks are performed on the passed data.<br>
*
* Example call:<br>
* SPIM_XFER_T mxfer;
* mxfer.pCB = &masterCallbacks;
* mxfer.sselNum = 2; // Use chip select 2
* mxfer.options = SPI_TXCTL_FLEN(8); // 8 data bits, supports 1 - 16 bits
* mxfer.options |= SPI_TXCTL_EOT | SPI_TXCTL_EOF; // Apply frame and transfer delays to master transfer
* mxfer.options |= SPI_TXCTL_RXIGNORE; // Ignore RX data, will toss receive data regardless of pRXData8 or pRXData16 buffer
* mxfer.pTXData8 = SendBuffer;
* mxfer.txCount = 16; // Number of bytes to send before SPIMasterXferSend callback is called
* mxfer.pRXData8 = RecvBuffer; // Will not receive data if pRXData8/pRXData16 is NULL or SPI_TXCTL_RXIGNORE option is set
* mxfer.rxCount = 16; // Number of bytes to receive before SPIMasterXferRecv callback is called
* Chip_SPIM_Xfer(LPC_SPI0, &mxfer); // Start transfer
*
* Note that the transfer, once started, needs to be constantly fed by the callbacks.
* The txCount and rxCount field only indicate the buffer size before the callbacks are called.
* To terminate the transfer, the SPIMasterXferSend callback must set the terminate field.
*/
void Chip_SPIM_Xfer(LPC_SPI_T *pSPI, SPIM_XFER_T *xfer);
/**
* @brief Perform blocking SPI master transfer
* @param pSPI : The base of SPI peripheral on the chip
* @param xfers : Pointer to a SPIM_XFER_T structure see notes below
* @return Nothing
* @note This function starts a blocking SPI master transfer with the
* parameters setup in the passed @ref SPIM_XFER_T structure. Once the transfer is
* started, the callbacks in Chip_SPIM_XferHandler may be called to keep the
* transfer going and fed with data. SPI interrupts must be disabled prior to
* calling this function. It is not recommended to use this function.<br>
*/
void Chip_SPIM_XferBlocking(LPC_SPI_T *pSPI, SPIM_XFER_T *xfer);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __SPIM_540XX_H_ */

View File

@@ -0,0 +1,177 @@
/*
* @brief LPC540XX SPI master driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licenser disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "chip.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
/* Flag used to tell polling function (if used) that a deassert event
happened */
static volatile bool deasserted;
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
/* Determine SSEL associated with the current data value */
static uint8_t Chip_SPIS_FindSSEL(LPC_SPI_T *pSPI, uint32_t data)
{
int i;
uint8_t ssel = 0;
for (i = 0; i <= 3; i++) {
if ((data & SPI_RXDAT_RXSSELNUM_INACTIVE(i)) == 0) {
/* Signal is active on low */
ssel = (uint8_t) i;
}
}
return ssel;
}
/*****************************************************************************
* Public functions
****************************************************************************/
/* SPI slave transfer state change handler */
uint32_t Chip_SPIS_XferHandler(LPC_SPI_T *pSPI, SPIS_XFER_T *xfer)
{
uint32_t staterr, data;
uint8_t flen;
/* Get length of a receive value */
flen = (pSPI->TXCTRL >> 24) & 0xF;
/* Get errors for later, we'll continue even if errors occur, but we notify
caller on return */
staterr = Chip_SPI_GetStatus(pSPI) & (SPI_STAT_RXOV | SPI_STAT_TXUR);
if (staterr != 0) {
Chip_SPI_ClearStatus(pSPI, staterr);
}
/* Slave assertion */
if ((Chip_SPI_GetStatus(pSPI) & SPI_STAT_SSA) != 0) {
Chip_SPI_ClearStatus(pSPI, SPI_STAT_SSA);
/* Determine SPI select. Read the data FIFO to get the slave number. Data
should not be in the receive FIFO yet, only the statuses */
xfer->sselNum = Chip_SPIS_FindSSEL(pSPI, Chip_SPI_ReadRawRXFifo(pSPI));
/* SSEL assertion callback */
xfer->pCB->slaveXferCSAssert(xfer);
}
/* Transmit data? */
while ((Chip_SPI_GetStatus(pSPI) & SPI_STAT_TXRDY) != 0) {
if (xfer->txCount == 0) {
/* Request a new buffer first */
xfer->pCB->slaveXferSend(xfer);
}
/* Send 0 on empty buffer or count */
if ((xfer->txCount == 0) || (xfer->pTXData8 == NULL)) {
data = 0;
}
else {
/* Copy buffer to data */
if (flen > 8) {
data = (uint32_t) *xfer->pTXData16;
xfer->pTXData16++;
}
else {
data = (uint32_t) *xfer->pTXData8;
xfer->pTXData8++;
}
xfer->dataTXferred++;
xfer->txCount--;
}
Chip_SPI_WriteTXData(pSPI, data);
}
/* Data received? */
while ((Chip_SPI_GetStatus(pSPI) & SPI_STAT_RXRDY) != 0) {
/* Get raw data and status */
data = Chip_SPI_ReadRawRXFifo(pSPI);
/* Only copy data when not ignoring receive */
if (xfer->pRXData8 != NULL) {
/* Enough size in current buffers? */
if (xfer->rxCount == 0) {
/* Request a new buffer first */
xfer->pCB->slaveXferRecv(xfer);
}
/* Copy data to buffer */
if (flen > 8) {
*xfer->pRXData16 = (uint16_t) (data & 0xFFFF);
xfer->pRXData16++;
}
else {
*xfer->pRXData8 = (uint8_t) (data & 0xFF);
xfer->pRXData8++;
}
xfer->dataRXferred++;
xfer->rxCount--;
}
}
/* Slave de-assertion */
if (((Chip_SPI_GetStatus(pSPI) & SPI_STAT_SSD) != 0) && ((Chip_SPI_GetStatus(pSPI) & SPI_STAT_RXRDY) == 0)) {
Chip_SPI_ClearStatus(pSPI, SPI_STAT_SSD);
xfer->pCB->slaveXferCSDeAssert(xfer);
deasserted = true;
}
return staterr;
}
/* SPI slave transfer blocking function */
uint32_t Chip_SPIS_XferBlocking(LPC_SPI_T *pSPI, SPIS_XFER_T *xfer)
{
uint32_t status = 0;
/* Wait forever until deassertion event */
deasserted = false;
while ((!deasserted) && (status == 0)) {
status = Chip_SPIS_XferHandler(pSPI, xfer);
}
return status;
}

View File

@@ -0,0 +1,155 @@
/*
* @brief LPC540XX SPI slave driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#ifndef __SPIS_540XX_H_
#define __SPIS_540XX_H_
#include "spi_common_540xx.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup SPI_SLAVE_540XX CHIP: LPC540XX SPI slave driver
* @ingroup SPI_COMMON_540XX
* @{
*/
struct SPIS_XFER;
/** @brief SPI slave select assertion callback
* This callback is called from the SPI slave handler when an SPI slave select (SSEL)
* is initially asserted. It is used to indicate the start of a slave transfer that
* will happen on the bus.
*/
typedef void (*SPISlaveXferCSAssert)(struct SPIS_XFER *pSlaveXfer);
/** @brief SPI slave send data callback
* This callback is called from the SPI slave handler when an SPI slave select (SSEL)
* needs a data buffer to send.
*/
typedef void (*SPISlaveXferSend)(struct SPIS_XFER *pSlaveXfer);
/** @brief SPI slave receive data callback
* This callback is called from the SPI slave handler when an SPI slave select (SSEL)
* needs a buffer to place data.
*/
typedef void (*SPISlaveXferRecv)(struct SPIS_XFER *pSlaveXfer);
/** @brief SPI slave select de-assertion callback
* This callback is called from the SPI slave handler when an SPI slave select (SSEL)
* is de-asserted. It can be used to indicate the end of a transfer.
*/
typedef void (*SPISlaveXferCSDeAssert)(struct SPIS_XFER *pSlaveXfer);
/** SPI slave callback functions */
typedef struct {
SPISlaveXferCSAssert slaveXferCSAssert; /** SPI transfer start callback, called on SPI CS assertion */
SPISlaveXferSend slaveXferSend; /** SPI transfer data receive buffer callback, called when a receive buffer is needed */
SPISlaveXferRecv slaveXferRecv; /** SPI transfer send buffer callback, called when data is needed */
SPISlaveXferCSDeAssert slaveXferCSDeAssert; /** SPI transfer completion callback, called on SPI CS deassertion */
} SPIS_CALLBACKS_T;
/** Slave transfer data context */
typedef struct SPIS_XFER {
const SPIS_CALLBACKS_T *pCB; /** Pointer to SPI slave callback functions */
union { /** Pointer to receive buffer, set to NULL to toss receeive data */
uint8_t *pRXData8; /** Receive buffer used with data transfer size <= 8-bits, modified by driver */
uint16_t *pRXData16; /** Receive buffer used with data transfer size > 8-bits, modified by driver */
};
union { /** Pointer to transmit buffer, set to NULL to transmit 0x0 */
uint8_t *pTXData8; /** Send buffer used with data transfer size <= 8-bits, modified by driver */
uint16_t *pTXData16; /** Send buffer used with data transfer size > 8-bits, modified by driver */
};
uint16_t rxCount; /** Size of the pRXData buffer in items (not bytes), modified by driver */
uint16_t txCount; /** Number of items (not bytes) to send in pTXData buffer, modified by driver */
uint16_t dataRXferred; /** Total items (not bytes) received, modified by driver */
uint16_t dataTXferred; /** Total items (not bytes) transmitted, modified by driver */
uint8_t sselNum; /** Slave number assigned to this transfer, 0 - 3, modified by driver */
} SPIS_XFER_T;
/**
* @brief SPI slave transfer state change handler
* @param pSPI : The base of SPI peripheral on the chip
* @param xfers : Pointer to a SPIS_XFER_T structure see notes below
* @return returns 0 on success, or SPI_STAT_RXOV and/or SPI_STAT_TXUR on an error
* @note See @ref SPIS_XFER_T for more information on this function. When using
* this function, the SPI slave interrupts should be enabled and setup in the SPI
* interrupt handler to call this function when they fire. This function is meant
* to be called from the interrupt handler. The @ref SPIS_XFER_T data does not need
* to be setup prior to the call and should be setup by the callbacks instead.<br>
*
* The callbacks are handled in the interrupt handler. If you are getting overflow
* or underflow errors, you might need to lower the speed of the master clock or
* extend the master's select assetion time.<br>
*/
uint32_t Chip_SPIS_XferHandler(LPC_SPI_T *pSPI, SPIS_XFER_T *xfer);
/**
* @brief Pre-buffers slave transmit data
* @param pSPI : The base of SPI peripheral on the chip
* @param xfers : Pointer to a SPIS_XFER_T structure see notes below
* @return Nothing
* @note Pre-buffering allows the slave to prime the transmit FIFO with data prior to
* the master starting a transfer. If data is not pre-buffered, the initial slave
* transmit data will always be 0x0 with a slave transmit underflow status.
* Pre-buffering is best used when only a single slave select is used by an
* application.
*/
STATIC INLINE void Chip_SPIS_PreBuffSlave(LPC_SPI_T *pSPI, SPIS_XFER_T *xfer)
{
Chip_SPIS_XferHandler(pSPI, xfer);
}
/**
* @brief SPI slave transfer blocking function
* @param pSPI : The base of SPI peripheral on the chip
* @param xfers : Pointer to a SPIS_XFER_T structure
* @return returns 0 on success, or SPI_STAT_RXOV and/or SPI_STAT_TXUR on an error
* @note This function performs a blocking transfer on the SPI slave interface.
* It is not recommended to use this function. Once this function is called, it
* will block forever until a slave transfer consisting of a slave SSEL assertion,
* and de-assertion occur. The callbacks are still used for slave data buffer
* management. SPI interrupts must be disabled prior to calling this function.
*/
uint32_t Chip_SPIS_XferBlocking(LPC_SPI_T *pSPI, SPIS_XFER_T *xfer);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __SPIS_540XX_H_ */

View File

@@ -0,0 +1,245 @@
/*
* @brief LPC540XX UART driver
*
* @note
* Copyright(C) NXP Semiconductors, 2012
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licenser disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include "chip.h"
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
/* Return UART clock ID from the UART register address */
static CHIP_SYSCON_CLOCK_T getUARTClockID(LPC_USART_T *pUART)
{
if (pUART == LPC_USART0) {
return SYSCON_CLOCK_USART0;
}
else if (pUART == LPC_USART1) {
return SYSCON_CLOCK_USART1;
}
else if (pUART == LPC_USART2) {
return SYSCON_CLOCK_USART2;
}
return SYSCON_CLOCK_USART3;
}
/*****************************************************************************
* Public functions
****************************************************************************/
/* Initialize the UART peripheral */
void Chip_UART_Init(LPC_USART_T *pUART)
{
/* Enable USART clock */
Chip_Clock_EnablePeriphClock(getUARTClockID(pUART));
/* UART reset */
if (pUART == LPC_USART0) {
/* Peripheral reset control to USART0 */
Chip_SYSCON_PeriphReset(RESET_USART0);
}
else if (pUART == LPC_USART1) {
/* Peripheral reset control to USART1 */
Chip_SYSCON_PeriphReset(RESET_USART1);
}
else if (pUART == LPC_USART2) {
/* Peripheral reset control to USART2 */
Chip_SYSCON_PeriphReset(RESET_USART2);
}
else if (pUART == LPC_USART3) {
/* Peripheral reset control to USART3 */
Chip_SYSCON_PeriphReset(RESET_USART3);
}
}
/* Initialize the UART peripheral */
void Chip_UART_DeInit(LPC_USART_T *pUART)
{
/* Enable USART clock */
Chip_Clock_DisablePeriphClock(getUARTClockID(pUART));
}
/* Transmit a byte array through the UART peripheral (non-blocking) */
int Chip_UART_Send(LPC_USART_T *pUART, const void *data, int numBytes)
{
int sent = 0;
uint8_t *p8 = (uint8_t *) data;
/* Send until the transmit FIFO is full or out of bytes */
while ((sent < numBytes) &&
((Chip_UART_GetStatus(pUART) & UART_STAT_TXRDY) != 0)) {
Chip_UART_SendByte(pUART, *p8);
p8++;
sent++;
}
return sent;
}
/* Transmit a byte array through the UART peripheral (blocking) */
int Chip_UART_SendBlocking(LPC_USART_T *pUART, const void *data, int numBytes)
{
int pass, sent = 0;
uint8_t *p8 = (uint8_t *) data;
while (numBytes > 0) {
pass = Chip_UART_Send(pUART, p8, numBytes);
numBytes -= pass;
sent += pass;
p8 += pass;
}
return sent;
}
/* Read data through the UART peripheral (non-blocking) */
int Chip_UART_Read(LPC_USART_T *pUART, void *data, int numBytes)
{
int readBytes = 0;
uint8_t *p8 = (uint8_t *) data;
/* Send until the transmit FIFO is full or out of bytes */
while ((readBytes < numBytes) &&
((Chip_UART_GetStatus(pUART) & UART_STAT_RXRDY) != 0)) {
*p8 = Chip_UART_ReadByte(pUART);
p8++;
readBytes++;
}
return readBytes;
}
/* Read data through the UART peripheral (blocking) */
int Chip_UART_ReadBlocking(LPC_USART_T *pUART, void *data, int numBytes)
{
int pass, readBytes = 0;
uint8_t *p8 = (uint8_t *) data;
while (readBytes < numBytes) {
pass = Chip_UART_Read(pUART, p8, numBytes);
numBytes -= pass;
readBytes += pass;
p8 += pass;
}
return readBytes;
}
/* Set baud rate for UART */
void Chip_UART_SetBaud(LPC_USART_T *pUART, uint32_t baudrate)
{
uint32_t err, uart_fra_multiplier, baudRateGenerator;
uint32_t AsyncSysconSystemClock = Chip_Clock_GetAsyncSyscon_ClockRate(); // Magicoe fixed Chip_Clock_GetAsyncSysconClockRate();
/* Calculate baudrate generator value */
baudRateGenerator = AsyncSysconSystemClock / (16 * baudrate);
err = AsyncSysconSystemClock - baudRateGenerator * 16 * baudrate;
uart_fra_multiplier = (err * 0xFF) / (baudRateGenerator * 16 * baudrate);
pUART->BRG = baudRateGenerator - 1; /* baud rate */
Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_FRG);
Chip_SYSCON_SetUSARTFRGCtrl(uart_fra_multiplier, 0xFF);
}
/* UART receive-only interrupt handler for ring buffers */
void Chip_UART_RXIntHandlerRB(LPC_USART_T *pUART, RINGBUFF_T *pRB)
{
/* New data will be ignored if data not popped in time */
while ((Chip_UART_GetStatus(pUART) & UART_STAT_RXRDY) != 0) {
uint8_t ch = Chip_UART_ReadByte(pUART);
RingBuffer_Insert(pRB, &ch);
}
}
/* UART transmit-only interrupt handler for ring buffers */
void Chip_UART_TXIntHandlerRB(LPC_USART_T *pUART, RINGBUFF_T *pRB)
{
uint8_t ch;
/* Fill FIFO until full or until TX ring buffer is empty */
while (((Chip_UART_GetStatus(pUART) & UART_STAT_TXRDY) != 0) &&
RingBuffer_Pop(pRB, &ch)) {
Chip_UART_SendByte(pUART, ch);
}
}
/* Populate a transmit ring buffer and start UART transmit */
uint32_t Chip_UART_SendRB(LPC_USART_T *pUART, RINGBUFF_T *pRB, const void *data, int count)
{
uint32_t ret;
uint8_t *p8 = (uint8_t *) data;
/* Don't let UART transmit ring buffer change in the UART IRQ handler */
Chip_UART_IntDisable(pUART, UART_INTEN_TXRDY);
/* Move as much data as possible into transmit ring buffer */
ret = RingBuffer_InsertMult(pRB, p8, count);
Chip_UART_TXIntHandlerRB(pUART, pRB);
/* Add additional data to transmit ring buffer if possible */
ret += RingBuffer_InsertMult(pRB, (p8 + ret), (count - ret));
/* Enable UART transmit interrupt */
Chip_UART_IntEnable(pUART, UART_INTEN_TXRDY);
return ret;
}
/* Copy data from a receive ring buffer */
int Chip_UART_ReadRB(LPC_USART_T *pUART, RINGBUFF_T *pRB, void *data, int bytes)
{
(void) pUART;
return RingBuffer_PopMult(pRB, (uint8_t *) data, bytes);
}
/* UART receive/transmit interrupt handler for ring buffers */
void Chip_UART_IRQRBHandler(LPC_USART_T *pUART, RINGBUFF_T *pRXRB, RINGBUFF_T *pTXRB)
{
/* Handle transmit interrupt if enabled */
if ((Chip_UART_GetStatus(pUART) & UART_STAT_TXRDY) != 0) {
Chip_UART_TXIntHandlerRB(pUART, pTXRB);
/* Disable transmit interrupt if the ring buffer is empty */
if (RingBuffer_IsEmpty(pTXRB)) {
Chip_UART_IntDisable(pUART, UART_INTEN_TXRDY);
}
}
/* Handle receive interrupt */
Chip_UART_RXIntHandlerRB(pUART, pRXRB);
}

View File

@@ -0,0 +1,445 @@
/*
* @brief LPC540XX UART driver
*
* @note
* Copyright(C) NXP Semiconductors, 2012
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#ifndef __UART_540XX_H_
#define __UART_540XX_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "ring_buffer.h"
/** @defgroup UART_540XX CHIP: LPC540XX UART Driver
* @ingroup CHIP_LPC540XX_Drivers
* @{
*/
/**
* @brief UART register block structure
*/
typedef struct {
__IO uint32_t CFG; /*!< Configuration register */
__IO uint32_t CTRL; /*!< Control register */
__IO uint32_t STAT; /*!< Status register */
__IO uint32_t INTENSET; /*!< Interrupt Enable read and set register */
__O uint32_t INTENCLR; /*!< Interrupt Enable clear register */
__I uint32_t RXDATA; /*!< Receive Data register */
__I uint32_t RXDATA_STAT; /*!< Receive Data with status register */
__IO uint32_t TXDATA; /*!< Transmit data register */
__IO uint32_t BRG; /*!< Baud Rate Generator register */
__IO uint32_t INTSTAT; /*!< Interrupt status register */
__IO uint32_t OSR; /*!< Oversample selection register */
__IO uint32_t ADDR; /*!< Address register */
} LPC_USART_T;
/**
* @brief UART CFG register definitions
*/
#define UART_CFG_ENABLE (0x01 << 0)
#define UART_CFG_DATALEN_7 (0x00 << 2) /*!< UART 7 bit length mode */
#define UART_CFG_DATALEN_8 (0x01 << 2) /*!< UART 8 bit length mode */
#define UART_CFG_DATALEN_9 (0x02 << 2) /*!< UART 9 bit length mode */
#define UART_CFG_PARITY_NONE (0x00 << 4) /*!< No parity */
#define UART_CFG_PARITY_EVEN (0x02 << 4) /*!< Even parity */
#define UART_CFG_PARITY_ODD (0x03 << 4) /*!< Odd parity */
#define UART_CFG_STOPLEN_1 (0x00 << 6) /*!< UART One Stop Bit Select */
#define UART_CFG_STOPLEN_2 (0x01 << 6) /*!< UART Two Stop Bits Select */
#define UART_CFG_MODE32K (0x01 << 7) /*!< UART 32K MODE */
#define UART_CFG_LINMODE (0x01 << 8) /*!< UART LIN MODE */
#define UART_CFG_CTSEN (0x01 << 9) /*!< CTS enable bit */
#define UART_CFG_SYNCEN (0x01 << 11) /*!< Synchronous mode enable bit */
#define UART_CFG_CLKPOL (0x01 << 12) /*!< Un_RXD rising edge sample enable bit */
#define UART_CFG_SYNCMST (0x01 << 14) /*!< Select master mode (synchronous mode) enable bit */
#define UART_CFG_LOOP (0x01 << 15) /*!< Loopback mode enable bit */
/**
* @brief UART CTRL register definitions
*/
#define UART_CTRL_TXBRKEN (0x01 << 1) /*!< Continuous break enable bit */
#define UART_CTRL_ADDRDET (0x01 << 2) /*!< Address detect mode enable bit */
#define UART_CTRL_TXDIS (0x01 << 6) /*!< Transmit disable bit */
#define UART_CTRL_CC (0x01 << 8) /*!< Continuous Clock mode enable bit */
#define UART_CTRL_CLRCC (0x01 << 9) /*!< Clear Continuous Clock bit */
#define UART_CTRL_AUTOBAUD (0x01 << 16) /*!< Auto baud bit */
/**
* @brief UART STAT register definitions
*/
#define UART_STAT_RXRDY (0x01 << 0) /*!< Receiver ready */
#define UART_STAT_RXIDLE (0x01 << 1) /*!< Receiver idle */
#define UART_STAT_TXRDY (0x01 << 2) /*!< Transmitter ready for data */
#define UART_STAT_TXIDLE (0x01 << 3) /*!< Transmitter idle */
#define UART_STAT_CTS (0x01 << 4) /*!< Status of CTS signal */
#define UART_STAT_DELTACTS (0x01 << 5) /*!< Change in CTS state */
#define UART_STAT_TXDISINT (0x01 << 6) /*!< Transmitter disabled */
#define UART_STAT_OVERRUNINT (0x01 << 8) /*!< Overrun Error interrupt flag. */
#define UART_STAT_RXBRK (0x01 << 10) /*!< Received break */
#define UART_STAT_DELTARXBRK (0x01 << 11) /*!< Change in receive break detection */
#define UART_STAT_START (0x01 << 12) /*!< Start detected */
#define UART_STAT_FRM_ERRINT (0x01 << 13) /*!< Framing Error interrupt flag */
#define UART_STAT_PAR_ERRINT (0x01 << 14) /*!< Parity Error interrupt flag */
#define UART_STAT_RXNOISEINT (0x01 << 15) /*!< Received Noise interrupt flag */
#define UART_STAT_ABERR (0x01 << 16) /*!< Auto baud error flag */
/**
* @brief UART INTENSET/INTENCLR register definitions
*/
#define UART_INTEN_RXRDY (0x01 << 0) /*!< Receive Ready interrupt */
#define UART_INTEN_TXRDY (0x01 << 2) /*!< Transmit Ready interrupt */
#define UART_INTEN_DELTACTS (0x01 << 5) /*!< Change in CTS state interrupt */
#define UART_INTEN_TXDIS (0x01 << 6) /*!< Transmitter disable interrupt */
#define UART_INTEN_OVERRUN (0x01 << 8) /*!< Overrun error interrupt */
#define UART_INTEN_DELTARXBRK (0x01 << 11) /*!< Change in receiver break detection interrupt */
#define UART_INTEN_START (0x01 << 12) /*!< Start detect interrupt */
#define UART_INTEN_FRAMERR (0x01 << 13) /*!< Frame error interrupt */
#define UART_INTEN_PARITYERR (0x01 << 14) /*!< Parity error interrupt */
#define UART_INTEN_RXNOISE (0x01 << 15) /*!< Received noise interrupt */
/**
* @brief Enable the UART
* @param pUART : Pointer to selected UARTx peripheral
* @return Nothing
*/
STATIC INLINE void Chip_UART_Enable(LPC_USART_T *pUART)
{
pUART->CFG |= UART_CFG_ENABLE;
}
/**
* @brief Disable the UART
* @param pUART : Pointer to selected UARTx peripheral
* @return Nothing
*/
STATIC INLINE void Chip_UART_Disable(LPC_USART_T *pUART)
{
pUART->CFG &= ~UART_CFG_ENABLE;
}
/**
* @brief Enable transmission on UART TxD pin
* @param pUART : Pointer to selected pUART peripheral
* @return Nothing
*/
STATIC INLINE void Chip_UART_TXEnable(LPC_USART_T *pUART)
{
pUART->CTRL &= ~UART_CTRL_TXDIS;
}
/**
* @brief Disable transmission on UART TxD pin
* @param pUART : Pointer to selected pUART peripheral
* @return Nothing
*/
STATIC INLINE void Chip_UART_TXDisable(LPC_USART_T *pUART)
{
pUART->CTRL |= UART_CTRL_TXDIS;
}
/**
* @brief Set auto baud
* @param pUART : Pointer to selected pUART peripheral
* @return true if auto baud succeeds, false if fails
*/
STATIC INLINE uint32_t Chip_UART_AutoBaud(LPC_USART_T *pUART)
{
while ( (pUART->STAT & UART_STAT_RXIDLE) != UART_STAT_RXIDLE );
pUART->CTRL |= UART_CTRL_AUTOBAUD;
while ( pUART->CTRL & UART_CTRL_AUTOBAUD ) {
if ( pUART->STAT & UART_STAT_ABERR ) {
pUART->STAT = UART_STAT_ABERR;
return ( false );
}
}
return ( true );
}
/**
* @brief Transmit a single data byte through the UART peripheral
* @param pUART : Pointer to selected UART peripheral
* @param data : Byte to transmit
* @return Nothing
* @note This function attempts to place a byte into the UART transmit
* holding register regard regardless of UART state.
*/
STATIC INLINE void Chip_UART_SendByte(LPC_USART_T *pUART, uint8_t data)
{
pUART->TXDATA = (uint32_t) data;
}
/**
* @brief Read a single byte data from the UART peripheral
* @param pUART : Pointer to selected UART peripheral
* @return A single byte of data read
* @note This function reads a byte from the UART receive FIFO or
* receive hold register regard regardless of UART state. The
* FIFO status should be read first prior to using this function
*/
STATIC INLINE uint32_t Chip_UART_ReadByte(LPC_USART_T *pUART)
{
/* Strip off undefined reserved bits, keep 9 lower bits */
return (uint32_t) (pUART->RXDATA & 0x000001FF);
}
/**
* @brief Enable UART interrupts
* @param pUART : Pointer to selected UART peripheral
* @param intMask : OR'ed Interrupts to enable
* @return Nothing
* @note Use an OR'ed value of UART_INTEN_* definitions with this function
* to enable specific UART interrupts.
*/
STATIC INLINE void Chip_UART_IntEnable(LPC_USART_T *pUART, uint32_t intMask)
{
pUART->INTENSET = intMask;
}
/**
* @brief Disable UART interrupts
* @param pUART : Pointer to selected UART peripheral
* @param intMask : OR'ed Interrupts to disable
* @return Nothing
* @note Use an OR'ed value of UART_INTEN_* definitions with this function
* to disable specific UART interrupts.
*/
STATIC INLINE void Chip_UART_IntDisable(LPC_USART_T *pUART, uint32_t intMask)
{
pUART->INTENCLR = intMask;
}
/**
* @brief Returns UART interrupts that are enabled
* @param pUART : Pointer to selected UART peripheral
* @return Returns the enabled UART interrupts
* @note Use an OR'ed value of UART_INTEN_* definitions with this function
* to determine which interrupts are enabled. You can check
* for multiple enabled bits if needed.
*/
STATIC INLINE uint32_t Chip_UART_GetIntsEnabled(LPC_USART_T *pUART)
{
return pUART->INTENSET;
}
/**
* @brief Get UART interrupt status
* @param pUART : The base of UART peripheral on the chip
* @return The Interrupt status register of UART
* @note Multiple interrupts may be pending. Mask the return value
* with one or more UART_INTEN_* definitions to determine
* pending interrupts.
*/
STATIC INLINE uint32_t Chip_UART_GetIntStatus(LPC_USART_T *pUART)
{
return pUART->INTSTAT;
}
/**
* @brief Configure data width, parity and stop bits
* @param pUART : Pointer to selected pUART peripheral
* @param config : UART configuration, OR'ed values of select UART_CFG_* defines
* @return Nothing
* @note Select OR'ed config options for the UART from the UART_CFG_PARITY_*,
* UART_CFG_STOPLEN_*, and UART_CFG_DATALEN_* definitions. For example,
* a configuration of 8 data bits, 1 stop bit, and even (enabled) parity would be
* (UART_CFG_DATALEN_8 | UART_CFG_STOPLEN_1 | UART_CFG_PARITY_EVEN). Will not
* alter other bits in the CFG register.
*/
STATIC INLINE void Chip_UART_ConfigData(LPC_USART_T *pUART, uint32_t config)
{
pUART->CFG = config;
}
/**
* @brief Get the UART status register
* @param pUART : Pointer to selected UARTx peripheral
* @return UART status register
* @note Multiple statuses may be pending. Mask the return value
* with one or more UART_STAT_* definitions to determine
* statuses.
*/
STATIC INLINE uint32_t Chip_UART_GetStatus(LPC_USART_T *pUART)
{
return pUART->STAT;
}
/**
* @brief Clear the UART status register
* @param pUART : Pointer to selected UARTx peripheral
* @param stsMask : OR'ed statuses to disable
* @return Nothing
* @note Multiple interrupts may be pending. Mask the return value
* with one or more UART_INTEN_* definitions to determine
* pending interrupts.
*/
STATIC INLINE void Chip_UART_ClearStatus(LPC_USART_T *pUART, uint32_t stsMask)
{
pUART->STAT = stsMask;
}
/**
* @brief Initialize the UART peripheral
* @param pUART : The base of UART peripheral on the chip
* @return Nothing
*/
void Chip_UART_Init(LPC_USART_T *pUART);
/**
* @brief Deinitialize the UART peripheral
* @param pUART : The base of UART peripheral on the chip
* @return Nothing
*/
void Chip_UART_DeInit(LPC_USART_T *pUART);
/**
* @brief Transmit a byte array through the UART peripheral (non-blocking)
* @param pUART : Pointer to selected UART peripheral
* @param data : Pointer to bytes to transmit
* @param numBytes : Number of bytes to transmit
* @return The actual number of bytes placed into the FIFO
* @note This function places data into the transmit FIFO until either
* all the data is in the FIFO or the FIFO is full. This function
* will not block in the FIFO is full. The actual number of bytes
* placed into the FIFO is returned. This function ignores errors.
*/
int Chip_UART_Send(LPC_USART_T *pUART, const void *data, int numBytes);
/**
* @brief Read data through the UART peripheral (non-blocking)
* @param pUART : Pointer to selected UART peripheral
* @param data : Pointer to bytes array to fill
* @param numBytes : Size of the passed data array
* @return The actual number of bytes read
* @note This function reads data from the receive FIFO until either
* all the data has been read or the passed buffer is completely full.
* This function will not block. This function ignores errors.
*/
int Chip_UART_Read(LPC_USART_T *pUART, void *data, int numBytes);
/**
* @brief Set baud rate for UART
* @param pUART : The base of UART peripheral on the chip
* @param baudrate: Baud rate to be set
* @return Nothing
*/
void Chip_UART_SetBaud(LPC_USART_T *pUART, uint32_t baudrate);
/**
* @brief Transmit a byte array through the UART peripheral (blocking)
* @param pUART : Pointer to selected UART peripheral
* @param data : Pointer to data to transmit
* @param numBytes : Number of bytes to transmit
* @return The number of bytes transmitted
* @note This function will send or place all bytes into the transmit
* FIFO. This function will block until the last bytes are in the FIFO.
*/
int Chip_UART_SendBlocking(LPC_USART_T *pUART, const void *data, int numBytes);
/**
* @brief Read data through the UART peripheral (blocking)
* @param pUART : Pointer to selected UART peripheral
* @param data : Pointer to data array to fill
* @param numBytes : Size of the passed data array
* @return The size of the dat array
* @note This function reads data from the receive FIFO until the passed
* buffer is completely full. The function will block until full.
* This function ignores errors.
*/
int Chip_UART_ReadBlocking(LPC_USART_T *pUART, void *data, int numBytes);
/**
* @brief UART receive-only interrupt handler for ring buffers
* @param pUART : Pointer to selected UART peripheral
* @param pRB : Pointer to ring buffer structure to use
* @return Nothing
* @note If ring buffer support is desired for the receive side
* of data transfer, the UART interrupt should call this
* function for a receive based interrupt status.
*/
void Chip_UART_RXIntHandlerRB(LPC_USART_T *pUART, RINGBUFF_T *pRB);
/**
* @brief UART transmit-only interrupt handler for ring buffers
* @param pUART : Pointer to selected UART peripheral
* @param pRB : Pointer to ring buffer structure to use
* @return Nothing
* @note If ring buffer support is desired for the transmit side
* of data transfer, the UART interrupt should call this
* function for a transmit based interrupt status.
*/
void Chip_UART_TXIntHandlerRB(LPC_USART_T *pUART, RINGBUFF_T *pRB);
/**
* @brief Populate a transmit ring buffer and start UART transmit
* @param pUART : Pointer to selected UART peripheral
* @param pRB : Pointer to ring buffer structure to use
* @param data : Pointer to buffer to move to ring buffer
* @param count : Number of bytes to move
* @return The number of bytes placed into the ring buffer
* @note Will move the data into the TX ring buffer and start the
* transfer. If the number of bytes returned is less than the
* number of bytes to send, the ring buffer is considered full.
*/
uint32_t Chip_UART_SendRB(LPC_USART_T *pUART, RINGBUFF_T *pRB, const void *data, int count);
/**
* @brief Copy data from a receive ring buffer
* @param pUART : Pointer to selected UART peripheral
* @param pRB : Pointer to ring buffer structure to use
* @param data : Pointer to buffer to fill from ring buffer
* @param bytes : Size of the passed buffer in bytes
* @return The number of bytes placed into the ring buffer
* @note Will move the data from the RX ring buffer up to the
* the maximum passed buffer size. Returns 0 if there is
* no data in the ring buffer.
*/
int Chip_UART_ReadRB(LPC_USART_T *pUART, RINGBUFF_T *pRB, void *data, int bytes);
/**
* @brief UART receive/transmit interrupt handler for ring buffers
* @param pUART : Pointer to selected UART peripheral
* @param pRXRB : Pointer to transmit ring buffer
* @param pTXRB : Pointer to receive ring buffer
* @return Nothing
* @note This provides a basic implementation of the UART IRQ
* handler for support of a ring buffer implementation for
* transmit and receive.
*/
void Chip_UART_IRQRBHandler(LPC_USART_T *pUART, RINGBUFF_T *pRXRB, RINGBUFF_T *pTXRB);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __UART_540XX_H_ */