Fix line-endings on LPC17xx and LPC43xx files

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@6745 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
theshed 2014-03-02 18:08:25 +00:00
parent 4353bdce7e
commit 24389bfe09
46 changed files with 51695 additions and 51695 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,294 +1,294 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx ADC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/adc_lld.c
* @brief LPC17xx ADC subsystem low level driver source.
* @note Values in samples buffer are from DR register.
* To get ADC values make conversion (DR >> 6) & 0x03FF.
* DMA only support one ADC channel.
* @addtogroup ADC
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_ADC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief ADC1 driver identifier.*/
ADCDriver ADCD1;
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
static lpc17xx_dma_lli_config_t lpc_adc_lli[2] __attribute__((aligned(0x10)));
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
#if LPC17xx_ADC_USE_DMA
/**
* @brief Common IRQ handler.
*
* @param[in] adcp pointer to the @p ADCDriver object
*/
static void adc_serve_dma_interrupt(ADCDriver *adcp, uint32_t flags) {
(void) flags;
if ((flags & (1 << LPC17xx_ADC_DMA_CHANNEL)) != 0) {
_adc_isr_error_code(adcp, flags); /* DMA errors handling.*/
}
else if (adcp->half_buffer == false) {
_adc_isr_half_code(adcp);
adcp->half_buffer = true;
}
else {
_adc_isr_full_code(adcp);
adcp->half_buffer = false;
}
}
#endif
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief ADC interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector98) {
uint32_t status;
uint32_t n;
uint8_t i;
CH_IRQ_PROLOGUE();
status = LPC_ADC->STAT;
n = ADCD1.num;
/* Note, an overrun may occur only in burst mode, if one or more
conversions was (were) lost. */
if ((status & ADC0STAT_OVERRUN_MASK)) {
if (ADCD1.grpp != NULL)
_adc_isr_error_code(&ADCD1, ADC_ERR_OVERRUN);
}
else {
status = status & ADC0STAT_DONE_MASK;
for (i = 0; i < ADC_MAX_CHANNELS; i++) {
if (status & (0x01 << i)) {
ADCD1.samples[n] = LPC_ADC->DR[i];
n++;
}
}
if (n == (ADCD1.nsamples / 2)) {
_adc_isr_half_code(&ADCD1);
}
if (n == ADCD1.nsamples) {
n = 0;
_adc_isr_full_code(&ADCD1);
}
}
ADCD1.num = n;
CH_IRQ_EPILOGUE();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level ADC driver initialization.
*
* @notapi
*/
void adc_lld_init(void) {
/* Driver initialization.*/
adcObjectInit(&ADCD1);
ADCD1.adc = LPC_ADC;
#if LPC17xx_ADC_USE_DMA
nvicDisableVector(ADC_IRQn);
#else
nvicEnableVector(ADC_IRQn, CORTEX_PRIORITY_MASK(LPC17xx_ADC_IRQ_PRIORITY));
#endif
}
/**
* @brief Configures and activates the ADC peripheral.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_start(ADCDriver *adcp) {
/* If in stopped state then enables the ADC. */
if (adcp->state == ADC_STOP) {
LPC_SC->PCONP |= (1UL << 12); /* Enable ADC power */
#if LPC17xx_ADC_USE_DMA
dmaChannelAllocate(LPC17xx_ADC_DMA_CHANNEL, \
(lpc17xx_dmaisr_t)adc_serve_dma_interrupt, \
(void *)adcp);
#endif
}
}
/**
* @brief Deactivates the ADC peripheral.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_stop(ADCDriver *adcp) {
/* If in ready state then disables the ADC clock.*/
if (adcp->state == ADC_READY) {
adcp->adc->CR = 0; /* Clear PDN bit */
LPC_SC->PCONP &= ~(1UL << 12); /* Disable ADC power */
#if LPC17xx_ADC_USE_DMA
dmaChannelRelease(LPC17xx_ADC_DMA_CHANNEL);
#endif
}
}
/**
* @brief Starts an ADC conversion.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_start_conversion(ADCDriver *adcp) {
uint32_t dummy;
uint32_t cr;
uint8_t i;
#if LPC17xx_ADC_USE_DMA
uint32_t dma_ch_config;
uint8_t ch;
#endif
cr = adcp->grpp->cr0;
adcp->num = 0;
adcp->nsamples = adcp->depth * adcp->grpp->num_channels;
for (i = 0; i < ADC_MAX_CHANNELS; i++) {
dummy = adcp->adc->DR[i]; /* Clear all DONE and OVERRUN flags. */
}
#if LPC17xx_ADC_USE_DMA
adcp->half_buffer = false;
ch = 0;
for (i = 0; i < 8; i++) {
if (cr & (1UL << i)) {
ch = i; /* Get number of first enabled channel. */
break;
}
}
/* DMA configuration */
lpc_adc_lli[0].srcaddr = (uint32_t)&adcp->adc->DR[ch];
lpc_adc_lli[0].dstaddr = (uint32_t)&adcp->samples[0];
lpc_adc_lli[0].lli = (uint32_t) &lpc_adc_lli[1];
lpc_adc_lli[0].control =
DMA_CTRL_TRANSFER_SIZE(adcp->nsamples/2) |
DMA_CTRL_SRC_BSIZE_1 |
DMA_CTRL_DST_BSIZE_1 |
DMA_CTRL_SRC_WIDTH_WORD |
DMA_CTRL_DST_WIDTH_WORD |
DMA_CTRL_SRC_NOINC |
DMA_CTRL_DST_INC |
DMA_CTRL_PROT1_USER |
DMA_CTRL_PROT2_NONBUFF |
DMA_CTRL_PROT3_NONCACHE |
DMA_CTRL_INT;
lpc_adc_lli[1].srcaddr = lpc_adc_lli[0].srcaddr;
lpc_adc_lli[1].dstaddr = (uint32_t)&adcp->samples[adcp->nsamples/2];
lpc_adc_lli[1].control = lpc_adc_lli[0].control;
if (adcp->grpp->circular == true) {
lpc_adc_lli[1].lli = (uint32_t) &lpc_adc_lli[0];
}
else {
lpc_adc_lli[1].lli = 0;
}
dma_ch_config =
DMA_CFG_CH_ENABLE |
DMA_CFG_SRC_PERIPH(DMA_ADC) |
DMA_CFG_TTYPE_P2M |
DMA_CFG_IE |
DMA_CFG_ITC;
dmaChannelSrcAddr(LPC17xx_ADC_DMA_CHANNEL, lpc_adc_lli[0].srcaddr);
dmaChannelDstAddr(LPC17xx_ADC_DMA_CHANNEL, lpc_adc_lli[0].dstaddr);
dmaChannelLinkedList(LPC17xx_ADC_DMA_CHANNEL, lpc_adc_lli[0].lli);
dmaChannelControl(LPC17xx_ADC_DMA_CHANNEL, lpc_adc_lli[0].control);
dmaChannelConfig(LPC17xx_ADC_DMA_CHANNEL, dma_ch_config);
#endif
/* ADC configuration and conversion start. */
adcp->adc->INTEN = adcp->grpp->inten; /* Set ADC interrupt on selected channels */
adcp->adc->CR = (cr & 0x0000FFFF) | ((LPC17xx_ADC_CLKDIV - 1) << 8) | AD0CR_PDN;
adcp->adc->CR |= cr & 0xFFFF0000;
}
/**
* @brief Stops an ongoing conversion.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_stop_conversion(ADCDriver *adcp) {
#if LPC17xx_ADC_USE_DMA
dmaChannelDisable(LPC17xx_ADC_DMA_CHANNEL);
#endif
adcp->adc->CR &= ~(AD0CR_MODE_BURST | AD0CR_START_MASK); /* Disable ADC conversion. */
adcp->adc->INTEN = 0; /* Mask ADC interrupts. */
}
#endif /* HAL_USE_ADC */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx ADC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/adc_lld.c
* @brief LPC17xx ADC subsystem low level driver source.
* @note Values in samples buffer are from DR register.
* To get ADC values make conversion (DR >> 6) & 0x03FF.
* DMA only support one ADC channel.
* @addtogroup ADC
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_ADC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief ADC1 driver identifier.*/
ADCDriver ADCD1;
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
static lpc17xx_dma_lli_config_t lpc_adc_lli[2] __attribute__((aligned(0x10)));
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
#if LPC17xx_ADC_USE_DMA
/**
* @brief Common IRQ handler.
*
* @param[in] adcp pointer to the @p ADCDriver object
*/
static void adc_serve_dma_interrupt(ADCDriver *adcp, uint32_t flags) {
(void) flags;
if ((flags & (1 << LPC17xx_ADC_DMA_CHANNEL)) != 0) {
_adc_isr_error_code(adcp, flags); /* DMA errors handling.*/
}
else if (adcp->half_buffer == false) {
_adc_isr_half_code(adcp);
adcp->half_buffer = true;
}
else {
_adc_isr_full_code(adcp);
adcp->half_buffer = false;
}
}
#endif
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief ADC interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector98) {
uint32_t status;
uint32_t n;
uint8_t i;
CH_IRQ_PROLOGUE();
status = LPC_ADC->STAT;
n = ADCD1.num;
/* Note, an overrun may occur only in burst mode, if one or more
conversions was (were) lost. */
if ((status & ADC0STAT_OVERRUN_MASK)) {
if (ADCD1.grpp != NULL)
_adc_isr_error_code(&ADCD1, ADC_ERR_OVERRUN);
}
else {
status = status & ADC0STAT_DONE_MASK;
for (i = 0; i < ADC_MAX_CHANNELS; i++) {
if (status & (0x01 << i)) {
ADCD1.samples[n] = LPC_ADC->DR[i];
n++;
}
}
if (n == (ADCD1.nsamples / 2)) {
_adc_isr_half_code(&ADCD1);
}
if (n == ADCD1.nsamples) {
n = 0;
_adc_isr_full_code(&ADCD1);
}
}
ADCD1.num = n;
CH_IRQ_EPILOGUE();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level ADC driver initialization.
*
* @notapi
*/
void adc_lld_init(void) {
/* Driver initialization.*/
adcObjectInit(&ADCD1);
ADCD1.adc = LPC_ADC;
#if LPC17xx_ADC_USE_DMA
nvicDisableVector(ADC_IRQn);
#else
nvicEnableVector(ADC_IRQn, CORTEX_PRIORITY_MASK(LPC17xx_ADC_IRQ_PRIORITY));
#endif
}
/**
* @brief Configures and activates the ADC peripheral.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_start(ADCDriver *adcp) {
/* If in stopped state then enables the ADC. */
if (adcp->state == ADC_STOP) {
LPC_SC->PCONP |= (1UL << 12); /* Enable ADC power */
#if LPC17xx_ADC_USE_DMA
dmaChannelAllocate(LPC17xx_ADC_DMA_CHANNEL, \
(lpc17xx_dmaisr_t)adc_serve_dma_interrupt, \
(void *)adcp);
#endif
}
}
/**
* @brief Deactivates the ADC peripheral.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_stop(ADCDriver *adcp) {
/* If in ready state then disables the ADC clock.*/
if (adcp->state == ADC_READY) {
adcp->adc->CR = 0; /* Clear PDN bit */
LPC_SC->PCONP &= ~(1UL << 12); /* Disable ADC power */
#if LPC17xx_ADC_USE_DMA
dmaChannelRelease(LPC17xx_ADC_DMA_CHANNEL);
#endif
}
}
/**
* @brief Starts an ADC conversion.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_start_conversion(ADCDriver *adcp) {
uint32_t dummy;
uint32_t cr;
uint8_t i;
#if LPC17xx_ADC_USE_DMA
uint32_t dma_ch_config;
uint8_t ch;
#endif
cr = adcp->grpp->cr0;
adcp->num = 0;
adcp->nsamples = adcp->depth * adcp->grpp->num_channels;
for (i = 0; i < ADC_MAX_CHANNELS; i++) {
dummy = adcp->adc->DR[i]; /* Clear all DONE and OVERRUN flags. */
}
#if LPC17xx_ADC_USE_DMA
adcp->half_buffer = false;
ch = 0;
for (i = 0; i < 8; i++) {
if (cr & (1UL << i)) {
ch = i; /* Get number of first enabled channel. */
break;
}
}
/* DMA configuration */
lpc_adc_lli[0].srcaddr = (uint32_t)&adcp->adc->DR[ch];
lpc_adc_lli[0].dstaddr = (uint32_t)&adcp->samples[0];
lpc_adc_lli[0].lli = (uint32_t) &lpc_adc_lli[1];
lpc_adc_lli[0].control =
DMA_CTRL_TRANSFER_SIZE(adcp->nsamples/2) |
DMA_CTRL_SRC_BSIZE_1 |
DMA_CTRL_DST_BSIZE_1 |
DMA_CTRL_SRC_WIDTH_WORD |
DMA_CTRL_DST_WIDTH_WORD |
DMA_CTRL_SRC_NOINC |
DMA_CTRL_DST_INC |
DMA_CTRL_PROT1_USER |
DMA_CTRL_PROT2_NONBUFF |
DMA_CTRL_PROT3_NONCACHE |
DMA_CTRL_INT;
lpc_adc_lli[1].srcaddr = lpc_adc_lli[0].srcaddr;
lpc_adc_lli[1].dstaddr = (uint32_t)&adcp->samples[adcp->nsamples/2];
lpc_adc_lli[1].control = lpc_adc_lli[0].control;
if (adcp->grpp->circular == true) {
lpc_adc_lli[1].lli = (uint32_t) &lpc_adc_lli[0];
}
else {
lpc_adc_lli[1].lli = 0;
}
dma_ch_config =
DMA_CFG_CH_ENABLE |
DMA_CFG_SRC_PERIPH(DMA_ADC) |
DMA_CFG_TTYPE_P2M |
DMA_CFG_IE |
DMA_CFG_ITC;
dmaChannelSrcAddr(LPC17xx_ADC_DMA_CHANNEL, lpc_adc_lli[0].srcaddr);
dmaChannelDstAddr(LPC17xx_ADC_DMA_CHANNEL, lpc_adc_lli[0].dstaddr);
dmaChannelLinkedList(LPC17xx_ADC_DMA_CHANNEL, lpc_adc_lli[0].lli);
dmaChannelControl(LPC17xx_ADC_DMA_CHANNEL, lpc_adc_lli[0].control);
dmaChannelConfig(LPC17xx_ADC_DMA_CHANNEL, dma_ch_config);
#endif
/* ADC configuration and conversion start. */
adcp->adc->INTEN = adcp->grpp->inten; /* Set ADC interrupt on selected channels */
adcp->adc->CR = (cr & 0x0000FFFF) | ((LPC17xx_ADC_CLKDIV - 1) << 8) | AD0CR_PDN;
adcp->adc->CR |= cr & 0xFFFF0000;
}
/**
* @brief Stops an ongoing conversion.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_stop_conversion(ADCDriver *adcp) {
#if LPC17xx_ADC_USE_DMA
dmaChannelDisable(LPC17xx_ADC_DMA_CHANNEL);
#endif
adcp->adc->CR &= ~(AD0CR_MODE_BURST | AD0CR_START_MASK); /* Disable ADC conversion. */
adcp->adc->INTEN = 0; /* Mask ADC interrupts. */
}
#endif /* HAL_USE_ADC */
/** @} */

View File

@ -1,347 +1,347 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx ADC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/adc_lld.h
* @brief LPC17xx ADC subsystem low level driver header.
* @note Values in samples buffer are from DR register.
* To get ADC values make conversion (DR >> 6) & 0x03FF.
* DMA only support one ADC channel.
* @addtogroup ADC
* @{
*/
#ifndef _ADC_LLD_H_
#define _ADC_LLD_H_
#if HAL_USE_ADC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define ADC0STAT_DONE_MASK 0x000000FF
#define ADC0STAT_OVERRUN_MASK 0x0000FF00
#define AD0CR_PDN (1UL << 21)
/**
* @name Absolute Maximum Ratings
* @{
*/
/**
* @brief Maximum ADC clock frequency.
*/
#define LPC17xx_ADCCLK_MAX 13000000
/**
* @brief Available number of ADC channels.
*/
#define ADC_MAX_CHANNELS 8
/** @} */
/**
* @name ADC settings
* @{
*/
/**
* @name Available analog channels
* @note In software-controlled mode only
* one channel can be selected.
* @{
*/
#define AD0CR_CHANNEL0 (1UL << 0)
#define AD0CR_CHANNEL1 (1UL << 1)
#define AD0CR_CHANNEL2 (1UL << 2)
#define AD0CR_CHANNEL3 (1UL << 3)
#define AD0CR_CHANNEL4 (1UL << 4)
#define AD0CR_CHANNEL5 (1UL << 5)
#define AD0CR_CHANNEL6 (1UL << 6)
#define AD0CR_CHANNEL7 (1UL << 7)
/** @} */
/**
* @name ADC mode types
* @note In software-controlled mode only one conversion
* is make
* @{
*/
#define AD0CR_MODE_SOFT (0UL << 16)
#define AD0CR_MODE_BURST (1UL << 16)
/** @} */
/**
* @name Triggers selection
* @note Only use in software-controlled mode
* @{
*/
#define AD0CR_START_NO (0UL << 24)
#define AD0CR_START_NOW (1UL << 24)
#define AD0CR_START_CT16B0_CAP0 (2UL << 24)
#define AD0CR_START_CT32B0_CAP0 (3UL << 24)
#define AD0CR_START_CT32B0_MAT0 (4UL << 24)
#define AD0CR_START_CT32B0_MAT1 (5UL << 24)
#define AD0CR_START_CT16B0_MAT0 (6UL << 24)
#define AD0CR_START_CT16B0_MAT1 (7UL << 24)
#define AD0CR_START_MASK (7UL << 24)
/** @} */
/**
* @name Trigger edge type selection
* @note Only use in software-controlled mode.
* @{
*/
#define AD0CR_EDGE_RISSING (0UL << 27)
#define AD0CR_EDGE_FALLING (1UL << 27)
/** @} */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief ADC common clock divider.
*/
#if !defined(LPC17xx_ADC_CLKDIV) || defined(__DOXYGEN__)
#define LPC17xx_ADC_CLKDIV 12
#endif
#if LPC17xx_PCLK/LPC17xx_ADC_CLKDIV > LPC17xx_ADCCLK_MAX
#error "ADC clock frequency out of the acceptable range (13MHz max)"
#endif
/**
* @brief ADC interrupt priority level setting.
*/
#if !defined(LPC17xx_ADC_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_ADC_IRQ_PRIORITY 3
#endif
/**
* @brief ADC DMA enable switch.
* @details If set to @p TRUE the support for ADC DMA is included.
* @note ADC DMA only support one selected channel. The default is @p FALSE.
*/
#if !defined(LPC17xx_ADC_USE_DMA) || defined(__DOXYGEN__)
#define LPC17xx_ADC_USE_DMA FALSE
#endif
#if LPC17xx_ADC_USE_DMA || defined(__DOXYGEN__)
#if !defined(LPC17xx_DMA_REQUIRED)
#define LPC17xx_DMA_REQUIRED
#endif
#endif
/**
* @brief ADC DMA channel.
*/
#if !defined(LPC17xx_ADC_DMA_CHANNEL) || defined(__DOXYGEN__)
#define LPC17xx_ADC_DMA_CHANNEL DMA_CHANNEL6
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief ADC sample data type.
*/
typedef uint32_t adcsample_t;
/**
* @brief Channels number in a conversion group.
*/
typedef uint16_t adc_channels_num_t;
/**
* @brief Possible ADC failure causes.
* @note Error codes are architecture dependent and should not relied
* upon.
*/
typedef enum {
ADC_ERR_OVERRUN = 1 /**< ADC overrun condition. */
} adcerror_t;
/**
* @brief Type of a structure representing an ADC driver.
*/
typedef struct ADCDriver ADCDriver;
/**
* @brief ADC notification callback type.
*
* @param[in] adcp pointer to the @p ADCDriver object triggering the
* callback
* @param[in] buffer pointer to the most recent samples data
* @param[in] n number of buffer rows available starting from @p buffer
*/
typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n);
/**
* @brief ADC error callback type.
*
* @param[in] adcp pointer to the @p ADCDriver object triggering the
* callback
* @param[in] err ADC error code
*/
typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err);
/**
* @brief Conversion group configuration structure.
* @details This implementation-dependent structure describes a conversion
* operation.
* @note The use of this configuration structure requires knowledge of
* LPC17xx ADC cell registers interface, please refer to the LPC17xx
* reference manual for details.
*/
typedef struct {
/**
* @brief Enables the circular buffer mode for the group.
*/
bool_t circular;
/**
* @brief Number of the analog channels belonging to the conversion group.
*/
adc_channels_num_t num_channels;
/**
* @brief Callback function associated to the group or @p NULL.
*/
adccallback_t end_cb;
/**
* @brief Error callback or @p NULL.
*/
adcerrorcallback_t error_cb;
/* End of the mandatory fields.*/
/**
* @brief ADC CR0 register initialization data.
* @note All the required bits must be defined into this field.
*/
uint32_t cr0;
/**
* @brief ADC INTENT register initialization data.
* @note In interrupt burst mode only define interrupt for
* last enabled channel.
*/
uint32_t inten;
} ADCConversionGroup;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
uint32_t dummy;
} ADCConfig;
/**
* @brief Structure representing an ADC driver.
*/
struct ADCDriver {
/**
* @brief Driver state.
*/
adcstate_t state;
/**
* @brief Current configuration data.
*/
const ADCConfig *config;
/**
* @brief Current samples buffer pointer or @p NULL.
*/
adcsample_t *samples;
/**
* @brief Current samples buffer depth or @p 0.
*/
size_t depth;
/**
* @brief Current conversion group pointer or @p NULL.
*/
const ADCConversionGroup *grpp;
#if ADC_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif
#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the peripheral.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* ADC_USE_MUTUAL_EXCLUSION */
#if defined(ADC_DRIVER_EXT_FIELDS)
ADC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the ADCx registers block.
*/
LPC_ADC_TypeDef *adc;
/**
* @brief Number of all samples in buffer.
*/
uint32_t nsamples;
/**
* @brief Samples buffer counter.
*/
uint32_t num;
#if LPC17xx_ADC_USE_DMA
/**
* @brief Half buffer indicator.
*/
bool_t half_buffer;
#endif
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
extern ADCDriver ADCD1;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void adc_lld_init(void);
void adc_lld_start(ADCDriver *adcp);
void adc_lld_stop(ADCDriver *adcp);
void adc_lld_start_conversion(ADCDriver *adcp);
void adc_lld_stop_conversion(ADCDriver *adcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_ADC */
#endif /* _ADC_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx ADC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/adc_lld.h
* @brief LPC17xx ADC subsystem low level driver header.
* @note Values in samples buffer are from DR register.
* To get ADC values make conversion (DR >> 6) & 0x03FF.
* DMA only support one ADC channel.
* @addtogroup ADC
* @{
*/
#ifndef _ADC_LLD_H_
#define _ADC_LLD_H_
#if HAL_USE_ADC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define ADC0STAT_DONE_MASK 0x000000FF
#define ADC0STAT_OVERRUN_MASK 0x0000FF00
#define AD0CR_PDN (1UL << 21)
/**
* @name Absolute Maximum Ratings
* @{
*/
/**
* @brief Maximum ADC clock frequency.
*/
#define LPC17xx_ADCCLK_MAX 13000000
/**
* @brief Available number of ADC channels.
*/
#define ADC_MAX_CHANNELS 8
/** @} */
/**
* @name ADC settings
* @{
*/
/**
* @name Available analog channels
* @note In software-controlled mode only
* one channel can be selected.
* @{
*/
#define AD0CR_CHANNEL0 (1UL << 0)
#define AD0CR_CHANNEL1 (1UL << 1)
#define AD0CR_CHANNEL2 (1UL << 2)
#define AD0CR_CHANNEL3 (1UL << 3)
#define AD0CR_CHANNEL4 (1UL << 4)
#define AD0CR_CHANNEL5 (1UL << 5)
#define AD0CR_CHANNEL6 (1UL << 6)
#define AD0CR_CHANNEL7 (1UL << 7)
/** @} */
/**
* @name ADC mode types
* @note In software-controlled mode only one conversion
* is make
* @{
*/
#define AD0CR_MODE_SOFT (0UL << 16)
#define AD0CR_MODE_BURST (1UL << 16)
/** @} */
/**
* @name Triggers selection
* @note Only use in software-controlled mode
* @{
*/
#define AD0CR_START_NO (0UL << 24)
#define AD0CR_START_NOW (1UL << 24)
#define AD0CR_START_CT16B0_CAP0 (2UL << 24)
#define AD0CR_START_CT32B0_CAP0 (3UL << 24)
#define AD0CR_START_CT32B0_MAT0 (4UL << 24)
#define AD0CR_START_CT32B0_MAT1 (5UL << 24)
#define AD0CR_START_CT16B0_MAT0 (6UL << 24)
#define AD0CR_START_CT16B0_MAT1 (7UL << 24)
#define AD0CR_START_MASK (7UL << 24)
/** @} */
/**
* @name Trigger edge type selection
* @note Only use in software-controlled mode.
* @{
*/
#define AD0CR_EDGE_RISSING (0UL << 27)
#define AD0CR_EDGE_FALLING (1UL << 27)
/** @} */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief ADC common clock divider.
*/
#if !defined(LPC17xx_ADC_CLKDIV) || defined(__DOXYGEN__)
#define LPC17xx_ADC_CLKDIV 12
#endif
#if LPC17xx_PCLK/LPC17xx_ADC_CLKDIV > LPC17xx_ADCCLK_MAX
#error "ADC clock frequency out of the acceptable range (13MHz max)"
#endif
/**
* @brief ADC interrupt priority level setting.
*/
#if !defined(LPC17xx_ADC_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_ADC_IRQ_PRIORITY 3
#endif
/**
* @brief ADC DMA enable switch.
* @details If set to @p TRUE the support for ADC DMA is included.
* @note ADC DMA only support one selected channel. The default is @p FALSE.
*/
#if !defined(LPC17xx_ADC_USE_DMA) || defined(__DOXYGEN__)
#define LPC17xx_ADC_USE_DMA FALSE
#endif
#if LPC17xx_ADC_USE_DMA || defined(__DOXYGEN__)
#if !defined(LPC17xx_DMA_REQUIRED)
#define LPC17xx_DMA_REQUIRED
#endif
#endif
/**
* @brief ADC DMA channel.
*/
#if !defined(LPC17xx_ADC_DMA_CHANNEL) || defined(__DOXYGEN__)
#define LPC17xx_ADC_DMA_CHANNEL DMA_CHANNEL6
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief ADC sample data type.
*/
typedef uint32_t adcsample_t;
/**
* @brief Channels number in a conversion group.
*/
typedef uint16_t adc_channels_num_t;
/**
* @brief Possible ADC failure causes.
* @note Error codes are architecture dependent and should not relied
* upon.
*/
typedef enum {
ADC_ERR_OVERRUN = 1 /**< ADC overrun condition. */
} adcerror_t;
/**
* @brief Type of a structure representing an ADC driver.
*/
typedef struct ADCDriver ADCDriver;
/**
* @brief ADC notification callback type.
*
* @param[in] adcp pointer to the @p ADCDriver object triggering the
* callback
* @param[in] buffer pointer to the most recent samples data
* @param[in] n number of buffer rows available starting from @p buffer
*/
typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n);
/**
* @brief ADC error callback type.
*
* @param[in] adcp pointer to the @p ADCDriver object triggering the
* callback
* @param[in] err ADC error code
*/
typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err);
/**
* @brief Conversion group configuration structure.
* @details This implementation-dependent structure describes a conversion
* operation.
* @note The use of this configuration structure requires knowledge of
* LPC17xx ADC cell registers interface, please refer to the LPC17xx
* reference manual for details.
*/
typedef struct {
/**
* @brief Enables the circular buffer mode for the group.
*/
bool_t circular;
/**
* @brief Number of the analog channels belonging to the conversion group.
*/
adc_channels_num_t num_channels;
/**
* @brief Callback function associated to the group or @p NULL.
*/
adccallback_t end_cb;
/**
* @brief Error callback or @p NULL.
*/
adcerrorcallback_t error_cb;
/* End of the mandatory fields.*/
/**
* @brief ADC CR0 register initialization data.
* @note All the required bits must be defined into this field.
*/
uint32_t cr0;
/**
* @brief ADC INTENT register initialization data.
* @note In interrupt burst mode only define interrupt for
* last enabled channel.
*/
uint32_t inten;
} ADCConversionGroup;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
uint32_t dummy;
} ADCConfig;
/**
* @brief Structure representing an ADC driver.
*/
struct ADCDriver {
/**
* @brief Driver state.
*/
adcstate_t state;
/**
* @brief Current configuration data.
*/
const ADCConfig *config;
/**
* @brief Current samples buffer pointer or @p NULL.
*/
adcsample_t *samples;
/**
* @brief Current samples buffer depth or @p 0.
*/
size_t depth;
/**
* @brief Current conversion group pointer or @p NULL.
*/
const ADCConversionGroup *grpp;
#if ADC_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif
#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the peripheral.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* ADC_USE_MUTUAL_EXCLUSION */
#if defined(ADC_DRIVER_EXT_FIELDS)
ADC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the ADCx registers block.
*/
LPC_ADC_TypeDef *adc;
/**
* @brief Number of all samples in buffer.
*/
uint32_t nsamples;
/**
* @brief Samples buffer counter.
*/
uint32_t num;
#if LPC17xx_ADC_USE_DMA
/**
* @brief Half buffer indicator.
*/
bool_t half_buffer;
#endif
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
extern ADCDriver ADCD1;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void adc_lld_init(void);
void adc_lld_start(ADCDriver *adcp);
void adc_lld_stop(ADCDriver *adcp);
void adc_lld_start_conversion(ADCDriver *adcp);
void adc_lld_stop_conversion(ADCDriver *adcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_ADC */
#endif /* _ADC_LLD_H_ */
/** @} */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,210 +1,210 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx DAC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/dac_lld.c
* @brief LPC17xx DAC subsystem low level driver source.
*
* @addtogroup DAC
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_DAC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief CHN1 driver identifier.*/
DACDriver DACD1;
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
static lpc17xx_dma_lli_config_t lpc_dac_lli[2] __attribute__((aligned(0x10)));
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief DAC DMA interrupt function.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] flags dma error flags
*/
static void dac_serve_dma_interrupt(DACDriver *dacp, uint32_t flags) {
if ((flags & (1 << LPC17xx_DAC_DMA_CHANNEL)) != 0) {
_dac_isr_error_code(dacp, flags); /* DMA errors handling.*/
}
else {
if (dacp->half_buffer == false) {
_dac_isr_half_code(dacp);
dacp->half_buffer = true;
}
else {
_dac_isr_full_code(dacp);
dacp->half_buffer = false;
}
}
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level DAC driver initialization.
*
* @notapi
*/
void dac_lld_init(void) {
dacObjectInit(&DACD1);
}
/**
* @brief Configures and activates the DAC peripheral.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
void dac_lld_start(DACDriver *dacp) {
if (dacp->state == DAC_STOP) {
/* Enable DAC */
LPC_PINCON->PINSEL1 |= (2UL << 20); /* Set AOUT P0.26 pin.*/
LPC_DAC->CR = 0;
LPC_DAC->CTRL = 0;
LPC_DAC->CNTVAL = LPC17xx_PCLK/dacp->config->frequency;
dmaChannelAllocate(LPC17xx_DAC_DMA_CHANNEL, \
(lpc17xx_dmaisr_t)dac_serve_dma_interrupt, \
(void *)dacp);
}
}
/**
* @brief Deactivates the DAC peripheral.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
void dac_lld_stop(DACDriver *dacp) {
/* If in ready state then disables the DAC clock.*/
if (dacp->state == DAC_READY) {
/* DMA disable.*/
dmaChannelDisable(LPC17xx_DAC_DMA_CHANNEL);
dmaChannelRelease(LPC17xx_DAC_DMA_CHANNEL);
/* Disable DAC */
LPC_PINCON->PINSEL1 &= ~(2UL << 20); /* Disable AOUT P0.26 pin.*/
}
}
/**
* @brief Sends data over the DAC bus.
* @details This asynchronous function starts a transmit operation.
* @post At the end of the operation the configured callback is invoked.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @notapi
*/
void dac_lld_start_conversion(DACDriver *dacp) {
dacp->half_buffer = false;
uint32_t dma_ch_config;
/* DMA configuration */
lpc_dac_lli[0].srcaddr = (uint32_t) &dacp->samples[0];
lpc_dac_lli[0].dstaddr = (uint32_t)&LPC_DAC->CR;
lpc_dac_lli[0].lli = (uint32_t) &lpc_dac_lli[1];
lpc_dac_lli[0].control =
DMA_CTRL_TRANSFER_SIZE(dacp->depth/2) |
DMA_CTRL_SRC_BSIZE_1 |
DMA_CTRL_DST_BSIZE_1 |
DMA_CTRL_SRC_WIDTH_WORD |
DMA_CTRL_DST_WIDTH_WORD |
DMA_CTRL_SRC_INC |
DMA_CTRL_DST_NOINC |
DMA_CTRL_PROT1_USER |
DMA_CTRL_PROT2_NONBUFF |
DMA_CTRL_PROT3_NONCACHE |
DMA_CTRL_INT;
lpc_dac_lli[1].srcaddr = (uint32_t) &dacp->samples[dacp->depth/2];
lpc_dac_lli[1].dstaddr = lpc_dac_lli[0].dstaddr;
lpc_dac_lli[1].control = lpc_dac_lli[0].control;
if (dacp->grpp->circular == true) {
lpc_dac_lli[1].lli = (uint32_t) &lpc_dac_lli[0];
}
else {
lpc_dac_lli[1].lli = 0;
}
dma_ch_config =
DMA_CFG_CH_ENABLE |
DMA_CFG_DST_PERIPH(DMA_DAC) |
DMA_CFG_TTYPE_M2P |
DMA_CFG_IE |
DMA_CFG_ITC;
dmaChannelSrcAddr(LPC17xx_DAC_DMA_CHANNEL, lpc_dac_lli[0].srcaddr);
dmaChannelDstAddr(LPC17xx_DAC_DMA_CHANNEL, lpc_dac_lli[0].dstaddr);
dmaChannelLinkedList(LPC17xx_DAC_DMA_CHANNEL, lpc_dac_lli[0].lli);
dmaChannelControl(LPC17xx_DAC_DMA_CHANNEL, lpc_dac_lli[0].control);
dmaChannelConfig(LPC17xx_DAC_DMA_CHANNEL, dma_ch_config);
LPC_DAC->CTRL = DACCTRL_DMA_ENA | DACCTRL_CNT_ENA | DACCTRL_DBLBUF_ENA;
}
void dac_lld_stop_conversion(DACDriver *dacp) {
/* If in active state then disables the DAC.*/
if (dacp->state == DAC_ACTIVE) {
/* DMA disable.*/
dmaChannelDisable(LPC17xx_DAC_DMA_CHANNEL);
}
};
#endif /* HAL_USE_DAC */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx DAC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/dac_lld.c
* @brief LPC17xx DAC subsystem low level driver source.
*
* @addtogroup DAC
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_DAC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief CHN1 driver identifier.*/
DACDriver DACD1;
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
static lpc17xx_dma_lli_config_t lpc_dac_lli[2] __attribute__((aligned(0x10)));
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief DAC DMA interrupt function.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] flags dma error flags
*/
static void dac_serve_dma_interrupt(DACDriver *dacp, uint32_t flags) {
if ((flags & (1 << LPC17xx_DAC_DMA_CHANNEL)) != 0) {
_dac_isr_error_code(dacp, flags); /* DMA errors handling.*/
}
else {
if (dacp->half_buffer == false) {
_dac_isr_half_code(dacp);
dacp->half_buffer = true;
}
else {
_dac_isr_full_code(dacp);
dacp->half_buffer = false;
}
}
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level DAC driver initialization.
*
* @notapi
*/
void dac_lld_init(void) {
dacObjectInit(&DACD1);
}
/**
* @brief Configures and activates the DAC peripheral.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
void dac_lld_start(DACDriver *dacp) {
if (dacp->state == DAC_STOP) {
/* Enable DAC */
LPC_PINCON->PINSEL1 |= (2UL << 20); /* Set AOUT P0.26 pin.*/
LPC_DAC->CR = 0;
LPC_DAC->CTRL = 0;
LPC_DAC->CNTVAL = LPC17xx_PCLK/dacp->config->frequency;
dmaChannelAllocate(LPC17xx_DAC_DMA_CHANNEL, \
(lpc17xx_dmaisr_t)dac_serve_dma_interrupt, \
(void *)dacp);
}
}
/**
* @brief Deactivates the DAC peripheral.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
void dac_lld_stop(DACDriver *dacp) {
/* If in ready state then disables the DAC clock.*/
if (dacp->state == DAC_READY) {
/* DMA disable.*/
dmaChannelDisable(LPC17xx_DAC_DMA_CHANNEL);
dmaChannelRelease(LPC17xx_DAC_DMA_CHANNEL);
/* Disable DAC */
LPC_PINCON->PINSEL1 &= ~(2UL << 20); /* Disable AOUT P0.26 pin.*/
}
}
/**
* @brief Sends data over the DAC bus.
* @details This asynchronous function starts a transmit operation.
* @post At the end of the operation the configured callback is invoked.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @notapi
*/
void dac_lld_start_conversion(DACDriver *dacp) {
dacp->half_buffer = false;
uint32_t dma_ch_config;
/* DMA configuration */
lpc_dac_lli[0].srcaddr = (uint32_t) &dacp->samples[0];
lpc_dac_lli[0].dstaddr = (uint32_t)&LPC_DAC->CR;
lpc_dac_lli[0].lli = (uint32_t) &lpc_dac_lli[1];
lpc_dac_lli[0].control =
DMA_CTRL_TRANSFER_SIZE(dacp->depth/2) |
DMA_CTRL_SRC_BSIZE_1 |
DMA_CTRL_DST_BSIZE_1 |
DMA_CTRL_SRC_WIDTH_WORD |
DMA_CTRL_DST_WIDTH_WORD |
DMA_CTRL_SRC_INC |
DMA_CTRL_DST_NOINC |
DMA_CTRL_PROT1_USER |
DMA_CTRL_PROT2_NONBUFF |
DMA_CTRL_PROT3_NONCACHE |
DMA_CTRL_INT;
lpc_dac_lli[1].srcaddr = (uint32_t) &dacp->samples[dacp->depth/2];
lpc_dac_lli[1].dstaddr = lpc_dac_lli[0].dstaddr;
lpc_dac_lli[1].control = lpc_dac_lli[0].control;
if (dacp->grpp->circular == true) {
lpc_dac_lli[1].lli = (uint32_t) &lpc_dac_lli[0];
}
else {
lpc_dac_lli[1].lli = 0;
}
dma_ch_config =
DMA_CFG_CH_ENABLE |
DMA_CFG_DST_PERIPH(DMA_DAC) |
DMA_CFG_TTYPE_M2P |
DMA_CFG_IE |
DMA_CFG_ITC;
dmaChannelSrcAddr(LPC17xx_DAC_DMA_CHANNEL, lpc_dac_lli[0].srcaddr);
dmaChannelDstAddr(LPC17xx_DAC_DMA_CHANNEL, lpc_dac_lli[0].dstaddr);
dmaChannelLinkedList(LPC17xx_DAC_DMA_CHANNEL, lpc_dac_lli[0].lli);
dmaChannelControl(LPC17xx_DAC_DMA_CHANNEL, lpc_dac_lli[0].control);
dmaChannelConfig(LPC17xx_DAC_DMA_CHANNEL, dma_ch_config);
LPC_DAC->CTRL = DACCTRL_DMA_ENA | DACCTRL_CNT_ENA | DACCTRL_DBLBUF_ENA;
}
void dac_lld_stop_conversion(DACDriver *dacp) {
/* If in active state then disables the DAC.*/
if (dacp->state == DAC_ACTIVE) {
/* DMA disable.*/
dmaChannelDisable(LPC17xx_DAC_DMA_CHANNEL);
}
};
#endif /* HAL_USE_DAC */
/** @} */

View File

@ -1,207 +1,207 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx DAC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/dac_lld.h
* @brief LPC17xx DAC subsystem low level driver header.
*
* @addtogroup DAC
* @{
*/
#ifndef _DAC_LLD_H_
#define _DAC_LLD_H_
#if HAL_USE_DAC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define DACR_BIAS (1UL << 16)
#define DACCTRL_INT_DMA_REQ (1UL << 0)
#define DACCTRL_DBLBUF_ENA (1UL << 1)
#define DACCTRL_CNT_ENA (1UL << 2)
#define DACCTRL_DMA_ENA (1UL << 3)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief DMA stream used for DAC CHN1 TX operations.
* @note This option is only available on platforms with enhanced DMA.
*/
#if !defined(LPC17xx_DAC_DMA_CHANNEL) || defined(__DOXYGEN__)
#define LPC17xx_DAC_DMA_CHANNEL DMA_CHANNEL5
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !defined(LPC17xx_DMA_REQUIRED)
#define LPC17xx_DMA_REQUIRED
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an DAC driver.
*/
typedef struct DACDriver DACDriver;
/**
* @brief Type representing a DAC sample.
*/
typedef uint32_t dacsample_t;
/**
* @brief DAC notification callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
* callback
*/
typedef void (*dacendcallback_t)(DACDriver *dacp, const dacsample_t * samples, size_t pos);
/**
* @brief DAC notification callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
* callback
*/
typedef void (*dacerrcallback_t)(DACDriver *dacp, uint32_t flags);
/**
* @brief DAC Conversion group structure.
*/
typedef struct {
/**
* @brief Number of DAC channels.
*/
uint16_t num_channels;
/**
* @brief Operation complete callback or @p NULL.
*/
dacendcallback_t end_cb;
/**
* @brief Error handling callback or @p NULL.
*/
dacerrcallback_t error_cb;
/**
* @brief Error handling callback or @p NULL.
*/
bool circular;
} DACConversionGroup;
/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
* @brief Timer frequency in Hz.
*/
uint32_t frequency;
/* End of the mandatory fields.*/
} DACConfig;
/**
* @brief Structure representing a DAC driver.
*/
struct DACDriver {
/**
* @brief Driver state.
*/
dacstate_t state;
/**
* @brief Conversion group.
*/
const DACConversionGroup *grpp;
/**
* @brief Samples buffer pointer.
*/
const dacsample_t *samples;
/**
* @brief Samples buffer size.
*/
uint16_t depth;
/**
* @brief Current configuration data.
*/
const DACConfig *config;
#if DAC_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif /* DAC_USE_WAIT */
#if DAC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* DAC_USE_MUTUAL_EXCLUSION */
#if defined(DAC_DRIVER_EXT_FIELDS)
DAC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Half buffer indicator.
*/
bool_t half_buffer;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
extern DACDriver DACD1;
#ifdef __cplusplus
extern "C" {
#endif
void dac_lld_init(void);
void dac_lld_start(DACDriver *dacp);
void dac_lld_stop(DACDriver *dacp);
void dac_lld_start_conversion(DACDriver *dacp);
void dac_lld_stop_conversion(DACDriver *dacp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_DAC */
#endif /* _DAC_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx DAC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/dac_lld.h
* @brief LPC17xx DAC subsystem low level driver header.
*
* @addtogroup DAC
* @{
*/
#ifndef _DAC_LLD_H_
#define _DAC_LLD_H_
#if HAL_USE_DAC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define DACR_BIAS (1UL << 16)
#define DACCTRL_INT_DMA_REQ (1UL << 0)
#define DACCTRL_DBLBUF_ENA (1UL << 1)
#define DACCTRL_CNT_ENA (1UL << 2)
#define DACCTRL_DMA_ENA (1UL << 3)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief DMA stream used for DAC CHN1 TX operations.
* @note This option is only available on platforms with enhanced DMA.
*/
#if !defined(LPC17xx_DAC_DMA_CHANNEL) || defined(__DOXYGEN__)
#define LPC17xx_DAC_DMA_CHANNEL DMA_CHANNEL5
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !defined(LPC17xx_DMA_REQUIRED)
#define LPC17xx_DMA_REQUIRED
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an DAC driver.
*/
typedef struct DACDriver DACDriver;
/**
* @brief Type representing a DAC sample.
*/
typedef uint32_t dacsample_t;
/**
* @brief DAC notification callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
* callback
*/
typedef void (*dacendcallback_t)(DACDriver *dacp, const dacsample_t * samples, size_t pos);
/**
* @brief DAC notification callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
* callback
*/
typedef void (*dacerrcallback_t)(DACDriver *dacp, uint32_t flags);
/**
* @brief DAC Conversion group structure.
*/
typedef struct {
/**
* @brief Number of DAC channels.
*/
uint16_t num_channels;
/**
* @brief Operation complete callback or @p NULL.
*/
dacendcallback_t end_cb;
/**
* @brief Error handling callback or @p NULL.
*/
dacerrcallback_t error_cb;
/**
* @brief Error handling callback or @p NULL.
*/
bool circular;
} DACConversionGroup;
/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
* @brief Timer frequency in Hz.
*/
uint32_t frequency;
/* End of the mandatory fields.*/
} DACConfig;
/**
* @brief Structure representing a DAC driver.
*/
struct DACDriver {
/**
* @brief Driver state.
*/
dacstate_t state;
/**
* @brief Conversion group.
*/
const DACConversionGroup *grpp;
/**
* @brief Samples buffer pointer.
*/
const dacsample_t *samples;
/**
* @brief Samples buffer size.
*/
uint16_t depth;
/**
* @brief Current configuration data.
*/
const DACConfig *config;
#if DAC_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif /* DAC_USE_WAIT */
#if DAC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* DAC_USE_MUTUAL_EXCLUSION */
#if defined(DAC_DRIVER_EXT_FIELDS)
DAC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Half buffer indicator.
*/
bool_t half_buffer;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
extern DACDriver DACD1;
#ifdef __cplusplus
extern "C" {
#endif
void dac_lld_init(void);
void dac_lld_start(DACDriver *dacp);
void dac_lld_stop(DACDriver *dacp);
void dac_lld_start_conversion(DACDriver *dacp);
void dac_lld_stop_conversion(DACDriver *dacp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_DAC */
#endif /* _DAC_LLD_H_ */
/** @} */

View File

@ -1,338 +1,338 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/gpt_lld.c
* @brief LPC17xx GPT subsystem low level driver source.
*
* @addtogroup GPT
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief GPT1 driver identifier.
* @note The driver GPT1 allocates the complex timer TIM0 when enabled.
*/
#if LPC17xx_GPT_USE_TIM0 || defined(__DOXYGEN__)
GPTDriver GPTD1;
#endif
/**
* @brief GPT2 driver identifier.
* @note The driver GPT2 allocates the timer TIM1 when enabled.
*/
#if LPC17xx_GPT_USE_TIM1 || defined(__DOXYGEN__)
GPTDriver GPTD2;
#endif
/**
* @brief GPT3 driver identifier.
* @note The driver GPT3 allocates the timer TIM2 when enabled.
*/
#if LPC17xx_GPT_USE_TIM2 || defined(__DOXYGEN__)
GPTDriver GPTD3;
#endif
/**
* @brief GPT4 driver identifier.
* @note The driver GPT4 allocates the timer TIM3 when enabled.
*/
#if LPC17xx_GPT_USE_TIM3 || defined(__DOXYGEN__)
GPTDriver GPTD4;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Shared IRQ handler.
*
* @param[in] gptp pointer to a @p GPTDriver object
*/
static void gpt_lld_serve_interrupt(GPTDriver *gptp) {
gptp->tmr->IR = 1; /* Clear interrupt on match MR0.*/
if (gptp->state == GPT_ONESHOT) {
gptp->state = GPT_READY; /* Back in GPT_READY state. */
gpt_lld_stop_timer(gptp); /* Timer automatically stopped. */
}
gptp->config->callback(gptp);
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if LPC17xx_GPT_USE_TIM0
/**
* @brief TIM0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector44) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD1);
CH_IRQ_EPILOGUE();
}
#endif /* LPC17xx_GPT_USE_TIM0 */
#if LPC17xx_GPT_USE_TIM1
/**
* @brief TIM1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector48) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD2);
CH_IRQ_EPILOGUE();
}
#endif /* LPC17xx_GPT_USE_TIM0 */
#if LPC17xx_GPT_USE_TIM2
/**
* @brief TIM2 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector4C) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD3);
CH_IRQ_EPILOGUE();
}
#endif /* LPC17xx_GPT_USE_TIM2 */
#if LPC17xx_GPT_USE_TIM3
/**
* @brief TIM3 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector50) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD4);
CH_IRQ_EPILOGUE();
}
#endif /* LPC17xx_GPT_USE_TIM3 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level GPT driver initialization.
*
* @notapi
*/
void gpt_lld_init(void) {
#if LPC17xx_GPT_USE_TIM0
/* Driver initialization.*/
GPTD1.tmr = LPC_TIM0;
gptObjectInit(&GPTD1);
#endif
#if LPC17xx_GPT_USE_TIM1
/* Driver initialization.*/
GPTD2.tmr = LPC_TIM1;
gptObjectInit(&GPTD2);
#endif
#if LPC17xx_GPT_USE_TIM2
/* Driver initialization.*/
GPTD3.tmr = LPC_TIM2;
gptObjectInit(&GPTD3);
#endif
#if LPC17xx_GPT_USE_TIM3
/* Driver initialization.*/
GPTD4.tmr = LPC_TIM3;
gptObjectInit(&GPTD4);
#endif
}
/**
* @brief Configures and activates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_start(GPTDriver *gptp) {
uint32_t pr;
if (gptp->state == GPT_STOP) {
/* Clock activation.*/
#if LPC17xx_GPT_USE_TIM0
if (&GPTD1 == gptp) {
LPC_SC->PCONP |= (1UL << 1);
nvicEnableVector(TIMER0_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
#if LPC17xx_GPT_USE_TIM1
if (&GPTD2 == gptp) {
LPC_SC->PCONP |= (1UL << 2);
nvicEnableVector(TIMER1_IRQn, CORTEX_PRIORITY_MASK(3));
}
#endif
#if LPC17xx_GPT_USE_TIM2
if (&GPTD3 == gptp) {
LPC_SC->PCONP |= (1UL << 22);
nvicEnableVector(TIMER2_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
#if LPC17xx_GPT_USE_TIM3
if (&GPTD4 == gptp) {
LPC_SC->PCONP |= (1UL << 23);
nvicEnableVector(TIMER3_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
}
/* Prescaler value calculation.*/
pr = (uint16_t)((LPC17xx_PCLK/ gptp->config->frequency) - 1);
chDbgAssert(((uint32_t)(pr + 1) * gptp->config->frequency) == LPC17xx_PCLK,
"gpt_lld_start(), #1", "invalid frequency");
/* Timer configuration.*/
gptp->tmr->PR = pr;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
}
/**
* @brief Deactivates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop(GPTDriver *gptp) {
if (gptp->state == GPT_READY) {
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
#if LPC17xx_GPT_USE_TIM0
if (&GPTD1 == gptp) {
nvicDisableVector(TIMER0_IRQn);
LPC_SC->PCONP &= ~(1UL << 1);
}
#endif
#if LPC17xx_GPT_USE_TIM1
if (&GPTD2 == gptp) {
nvicDisableVector(TIMER1_IRQn);
LPC_SC->PCONP &= ~(1UL << 2);
}
#endif
#if LPC17xx_GPT_USE_TIM2
if (&GPTD3 == gptp) {
nvicDisableVector(TIMER2_IRQn);
LPC_SC->PCONP &= ~(1UL << 22);
}
#endif
#if LPC17xx_GPT_USE_TIM3
if (&GPTD4 == gptp) {
nvicDisableVector(TIMER3_IRQn);
LPC_SC->PCONP &= ~(1UL << 23);
}
#endif
}
}
/**
* @brief Starts the timer in continuous mode.
*
* @param[in] gptp pointer to the @p GPTDriver object
* @param[in] interval period in ticks
*
* @notapi
*/
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) {
gptp->tmr->MR0 = interval - 1;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 3; /* IRQ and clr TC on match MR0. */
gptp->tmr->TCR = 2; /* Reset counter and prescaler. */
gptp->tmr->TCR = 1; /* Timer enabled. */
}
/**
* @brief Stops the timer.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop_timer(GPTDriver *gptp) {
gptp->tmr->IR = 1;
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
}
/**
* @brief Starts the timer in one shot mode and waits for completion.
* @details This function specifically polls the timer waiting for completion
* in order to not have extra delays caused by interrupt servicing,
* this function is only recommended for short delays.
*
* @param[in] gptp pointer to the @p GPTDriver object
* @param[in] interval time interval in ticks
*
* @notapi
*/
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) {
gptp->tmr->MR0 = interval - 1;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 4; /* Stop TC on match MR0. */
gptp->tmr->TCR = 2; /* Reset counter and prescaler. */
gptp->tmr->TCR = 1; /* Timer enabled. */
while (gptp->tmr->TCR & 1)
;
}
#endif /* HAL_USE_GPT */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/gpt_lld.c
* @brief LPC17xx GPT subsystem low level driver source.
*
* @addtogroup GPT
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief GPT1 driver identifier.
* @note The driver GPT1 allocates the complex timer TIM0 when enabled.
*/
#if LPC17xx_GPT_USE_TIM0 || defined(__DOXYGEN__)
GPTDriver GPTD1;
#endif
/**
* @brief GPT2 driver identifier.
* @note The driver GPT2 allocates the timer TIM1 when enabled.
*/
#if LPC17xx_GPT_USE_TIM1 || defined(__DOXYGEN__)
GPTDriver GPTD2;
#endif
/**
* @brief GPT3 driver identifier.
* @note The driver GPT3 allocates the timer TIM2 when enabled.
*/
#if LPC17xx_GPT_USE_TIM2 || defined(__DOXYGEN__)
GPTDriver GPTD3;
#endif
/**
* @brief GPT4 driver identifier.
* @note The driver GPT4 allocates the timer TIM3 when enabled.
*/
#if LPC17xx_GPT_USE_TIM3 || defined(__DOXYGEN__)
GPTDriver GPTD4;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Shared IRQ handler.
*
* @param[in] gptp pointer to a @p GPTDriver object
*/
static void gpt_lld_serve_interrupt(GPTDriver *gptp) {
gptp->tmr->IR = 1; /* Clear interrupt on match MR0.*/
if (gptp->state == GPT_ONESHOT) {
gptp->state = GPT_READY; /* Back in GPT_READY state. */
gpt_lld_stop_timer(gptp); /* Timer automatically stopped. */
}
gptp->config->callback(gptp);
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if LPC17xx_GPT_USE_TIM0
/**
* @brief TIM0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector44) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD1);
CH_IRQ_EPILOGUE();
}
#endif /* LPC17xx_GPT_USE_TIM0 */
#if LPC17xx_GPT_USE_TIM1
/**
* @brief TIM1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector48) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD2);
CH_IRQ_EPILOGUE();
}
#endif /* LPC17xx_GPT_USE_TIM0 */
#if LPC17xx_GPT_USE_TIM2
/**
* @brief TIM2 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector4C) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD3);
CH_IRQ_EPILOGUE();
}
#endif /* LPC17xx_GPT_USE_TIM2 */
#if LPC17xx_GPT_USE_TIM3
/**
* @brief TIM3 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector50) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD4);
CH_IRQ_EPILOGUE();
}
#endif /* LPC17xx_GPT_USE_TIM3 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level GPT driver initialization.
*
* @notapi
*/
void gpt_lld_init(void) {
#if LPC17xx_GPT_USE_TIM0
/* Driver initialization.*/
GPTD1.tmr = LPC_TIM0;
gptObjectInit(&GPTD1);
#endif
#if LPC17xx_GPT_USE_TIM1
/* Driver initialization.*/
GPTD2.tmr = LPC_TIM1;
gptObjectInit(&GPTD2);
#endif
#if LPC17xx_GPT_USE_TIM2
/* Driver initialization.*/
GPTD3.tmr = LPC_TIM2;
gptObjectInit(&GPTD3);
#endif
#if LPC17xx_GPT_USE_TIM3
/* Driver initialization.*/
GPTD4.tmr = LPC_TIM3;
gptObjectInit(&GPTD4);
#endif
}
/**
* @brief Configures and activates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_start(GPTDriver *gptp) {
uint32_t pr;
if (gptp->state == GPT_STOP) {
/* Clock activation.*/
#if LPC17xx_GPT_USE_TIM0
if (&GPTD1 == gptp) {
LPC_SC->PCONP |= (1UL << 1);
nvicEnableVector(TIMER0_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
#if LPC17xx_GPT_USE_TIM1
if (&GPTD2 == gptp) {
LPC_SC->PCONP |= (1UL << 2);
nvicEnableVector(TIMER1_IRQn, CORTEX_PRIORITY_MASK(3));
}
#endif
#if LPC17xx_GPT_USE_TIM2
if (&GPTD3 == gptp) {
LPC_SC->PCONP |= (1UL << 22);
nvicEnableVector(TIMER2_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
#if LPC17xx_GPT_USE_TIM3
if (&GPTD4 == gptp) {
LPC_SC->PCONP |= (1UL << 23);
nvicEnableVector(TIMER3_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
}
/* Prescaler value calculation.*/
pr = (uint16_t)((LPC17xx_PCLK/ gptp->config->frequency) - 1);
chDbgAssert(((uint32_t)(pr + 1) * gptp->config->frequency) == LPC17xx_PCLK,
"gpt_lld_start(), #1", "invalid frequency");
/* Timer configuration.*/
gptp->tmr->PR = pr;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
}
/**
* @brief Deactivates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop(GPTDriver *gptp) {
if (gptp->state == GPT_READY) {
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
#if LPC17xx_GPT_USE_TIM0
if (&GPTD1 == gptp) {
nvicDisableVector(TIMER0_IRQn);
LPC_SC->PCONP &= ~(1UL << 1);
}
#endif
#if LPC17xx_GPT_USE_TIM1
if (&GPTD2 == gptp) {
nvicDisableVector(TIMER1_IRQn);
LPC_SC->PCONP &= ~(1UL << 2);
}
#endif
#if LPC17xx_GPT_USE_TIM2
if (&GPTD3 == gptp) {
nvicDisableVector(TIMER2_IRQn);
LPC_SC->PCONP &= ~(1UL << 22);
}
#endif
#if LPC17xx_GPT_USE_TIM3
if (&GPTD4 == gptp) {
nvicDisableVector(TIMER3_IRQn);
LPC_SC->PCONP &= ~(1UL << 23);
}
#endif
}
}
/**
* @brief Starts the timer in continuous mode.
*
* @param[in] gptp pointer to the @p GPTDriver object
* @param[in] interval period in ticks
*
* @notapi
*/
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) {
gptp->tmr->MR0 = interval - 1;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 3; /* IRQ and clr TC on match MR0. */
gptp->tmr->TCR = 2; /* Reset counter and prescaler. */
gptp->tmr->TCR = 1; /* Timer enabled. */
}
/**
* @brief Stops the timer.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop_timer(GPTDriver *gptp) {
gptp->tmr->IR = 1;
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
}
/**
* @brief Starts the timer in one shot mode and waits for completion.
* @details This function specifically polls the timer waiting for completion
* in order to not have extra delays caused by interrupt servicing,
* this function is only recommended for short delays.
*
* @param[in] gptp pointer to the @p GPTDriver object
* @param[in] interval time interval in ticks
*
* @notapi
*/
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) {
gptp->tmr->MR0 = interval - 1;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 4; /* Stop TC on match MR0. */
gptp->tmr->TCR = 2; /* Reset counter and prescaler. */
gptp->tmr->TCR = 1; /* Timer enabled. */
while (gptp->tmr->TCR & 1)
;
}
#endif /* HAL_USE_GPT */
/** @} */

View File

@ -1,208 +1,208 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/gpt_lld.h
* @brief LPC17xx GPT subsystem low level driver header.
*
* @addtogroup GPT
* @{
*/
#ifndef _GPT_LLD_H_
#define _GPT_LLD_H_
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief GPT1 driver enable switch.
* @details If set to @p TRUE the support for GPT1 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_GPT_USE_TIM0) || defined(__DOXYGEN__)
#define LPC17xx_GPT_USE_TIM0 TRUE
#endif
/**
* @brief GPT2 driver enable switch.
* @details If set to @p TRUE the support for GPT2 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_GPT_USE_TIM1) || defined(__DOXYGEN__)
#define LPC17xx_GPT_USE_TIM1 TRUE
#endif
/**
* @brief GPT3 driver enable switch.
* @details If set to @p TRUE the support for GPT3 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_GPT_USE_TIM2) || defined(__DOXYGEN__)
#define LPC17xx_GPT_USE_TIM2 TRUE
#endif
/**
* @brief GPT4 driver enable switch.
* @details If set to @p TRUE the support for GPT4 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_GPT_USE_TIM3) || defined(__DOXYGEN__)
#define LPC17xx_GPT_USE_TIM3 TRUE
#endif
/**
* @brief GPT1 interrupt priority level setting.
*/
#if !defined(LPC17xx_GPT_TIM0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_GPT_TIM0_IRQ_PRIORITY 2
#endif
/**
* @brief GPT2 interrupt priority level setting.
*/
#if !defined(LPC17xx_GPT_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_GPT_TIM1_IRQ_PRIORITY 2
#endif
/**
* @brief GPT3 interrupt priority level setting.
*/
#if !defined(LPC17xx_GPT_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_GPT_TIM2_IRQ_PRIORITY 2
#endif
/**
* @brief GPT4 interrupt priority level setting.
*/
#if !defined(LPC17xx_GPT_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_GPT_TIM3_IRQ_PRIORITY 2
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !LPC17xx_GPT_USE_TIM0 && !LPC17xx_GPT_USE_TIM1 && \
!LPC17xx_GPT_USE_TIM2 && !LPC17xx_GPT_USE_TIM3
#error "GPT driver activated but no CT peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief GPT frequency type.
*/
typedef uint32_t gptfreq_t;
/**
* @brief GPT counter type.
*/
typedef uint32_t gptcnt_t;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
gptfreq_t frequency;
/**
* @brief Timer callback pointer.
* @note This callback is invoked on GPT counter events.
*/
gptcallback_t callback;
/* End of the mandatory fields.*/
} GPTConfig;
/**
* @brief Structure representing a GPT driver.
*/
struct GPTDriver {
/**
* @brief Driver state.
*/
gptstate_t state;
/**
* @brief Current configuration data.
*/
const GPTConfig *config;
/* End of the mandatory fields.*/
/**
* @brief Timer base clock.
*/
uint32_t clock;
/**
* @brief Pointer to the CTxxBy registers block.
*/
LPC_TIM_TypeDef *tmr;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC17xx_GPT_USE_TIM0 && !defined(__DOXYGEN__)
extern GPTDriver GPTD1;
#endif
#if LPC17xx_GPT_USE_TIM1 && !defined(__DOXYGEN__)
extern GPTDriver GPTD2;
#endif
#if LPC17xx_GPT_USE_TIM2 && !defined(__DOXYGEN__)
extern GPTDriver GPTD3;
#endif
#if LPC17xx_GPT_USE_TIM3 && !defined(__DOXYGEN__)
extern GPTDriver GPTD4;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void gpt_lld_init(void);
void gpt_lld_start(GPTDriver *gptp);
void gpt_lld_stop(GPTDriver *gptp);
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period);
void gpt_lld_stop_timer(GPTDriver *gptp);
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_GPT */
#endif /* _GPT_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/gpt_lld.h
* @brief LPC17xx GPT subsystem low level driver header.
*
* @addtogroup GPT
* @{
*/
#ifndef _GPT_LLD_H_
#define _GPT_LLD_H_
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief GPT1 driver enable switch.
* @details If set to @p TRUE the support for GPT1 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_GPT_USE_TIM0) || defined(__DOXYGEN__)
#define LPC17xx_GPT_USE_TIM0 TRUE
#endif
/**
* @brief GPT2 driver enable switch.
* @details If set to @p TRUE the support for GPT2 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_GPT_USE_TIM1) || defined(__DOXYGEN__)
#define LPC17xx_GPT_USE_TIM1 TRUE
#endif
/**
* @brief GPT3 driver enable switch.
* @details If set to @p TRUE the support for GPT3 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_GPT_USE_TIM2) || defined(__DOXYGEN__)
#define LPC17xx_GPT_USE_TIM2 TRUE
#endif
/**
* @brief GPT4 driver enable switch.
* @details If set to @p TRUE the support for GPT4 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_GPT_USE_TIM3) || defined(__DOXYGEN__)
#define LPC17xx_GPT_USE_TIM3 TRUE
#endif
/**
* @brief GPT1 interrupt priority level setting.
*/
#if !defined(LPC17xx_GPT_TIM0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_GPT_TIM0_IRQ_PRIORITY 2
#endif
/**
* @brief GPT2 interrupt priority level setting.
*/
#if !defined(LPC17xx_GPT_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_GPT_TIM1_IRQ_PRIORITY 2
#endif
/**
* @brief GPT3 interrupt priority level setting.
*/
#if !defined(LPC17xx_GPT_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_GPT_TIM2_IRQ_PRIORITY 2
#endif
/**
* @brief GPT4 interrupt priority level setting.
*/
#if !defined(LPC17xx_GPT_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_GPT_TIM3_IRQ_PRIORITY 2
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !LPC17xx_GPT_USE_TIM0 && !LPC17xx_GPT_USE_TIM1 && \
!LPC17xx_GPT_USE_TIM2 && !LPC17xx_GPT_USE_TIM3
#error "GPT driver activated but no CT peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief GPT frequency type.
*/
typedef uint32_t gptfreq_t;
/**
* @brief GPT counter type.
*/
typedef uint32_t gptcnt_t;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
gptfreq_t frequency;
/**
* @brief Timer callback pointer.
* @note This callback is invoked on GPT counter events.
*/
gptcallback_t callback;
/* End of the mandatory fields.*/
} GPTConfig;
/**
* @brief Structure representing a GPT driver.
*/
struct GPTDriver {
/**
* @brief Driver state.
*/
gptstate_t state;
/**
* @brief Current configuration data.
*/
const GPTConfig *config;
/* End of the mandatory fields.*/
/**
* @brief Timer base clock.
*/
uint32_t clock;
/**
* @brief Pointer to the CTxxBy registers block.
*/
LPC_TIM_TypeDef *tmr;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC17xx_GPT_USE_TIM0 && !defined(__DOXYGEN__)
extern GPTDriver GPTD1;
#endif
#if LPC17xx_GPT_USE_TIM1 && !defined(__DOXYGEN__)
extern GPTDriver GPTD2;
#endif
#if LPC17xx_GPT_USE_TIM2 && !defined(__DOXYGEN__)
extern GPTDriver GPTD3;
#endif
#if LPC17xx_GPT_USE_TIM3 && !defined(__DOXYGEN__)
extern GPTDriver GPTD4;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void gpt_lld_init(void);
void gpt_lld_start(GPTDriver *gptp);
void gpt_lld_stop(GPTDriver *gptp);
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period);
void gpt_lld_stop_timer(GPTDriver *gptp);
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_GPT */
#endif /* _GPT_LLD_H_ */
/** @} */

View File

@ -1,158 +1,158 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx HAL driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/hal_lld.c
* @brief LPC17xx HAL subsystem low level driver source.
*
* @addtogroup HAL
* @{
*/
#include "ch.h"
#include "hal.h"
/**
* @brief Register missing in NXP header file.
*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level HAL driver initialization.
*
* @notapi
*/
void hal_lld_init(void) {
/* SysTick initialization using the system clock.*/
nvicSetSystemHandlerPriority(HANDLER_SYSTICK, CORTEX_PRIORITY_SYSTICK);
SysTick->LOAD = LPC17xx_CCLK / CH_FREQUENCY - 1;
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_ENABLE_Msk |
SysTick_CTRL_TICKINT_Msk;
/* DWT cycle counter enable.*/
SCS_DEMCR |= SCS_DEMCR_TRCENA;
DWT_CTRL |= DWT_CTRL_CYCCNTENA;
#if defined(LPC17xx_DMA_REQUIRED)
dmaInit();
#endif
}
/**
* @brief LPC17xx clocks and PLL initialization.
* @note All the involved constants come from the file @p board.h.
* @note This function must be invoked only after the system reset.
*
* @special
*/
void LPC17xx_clock_init(void) {
/* Flash wait states setting, the code takes care to not touch TBD bits.*/
LPC_SC->FLASHCFG = (LPC_SC->FLASHCFG & ~(0x0000000F << 12)) | (LPC17xx_FLASHCFG_FLASHTIM << 12);
/* System oscillator initialization if required.*/
#if LPC17xx_MAINOSC_ENABLE
LPC_SC->SCS = (1 << 5) | (LPC17xx_OSCRANGE << 4); /* Enable Main oscillator */
while (!(LPC_SC->SCS & (1 << 6)))
; /* Wait for main oscillator to be ready */
#endif
/* Peripheral clock divider initialization, must be set before enabling Main PLL (PLL0).
Read errata sheet ES_LPC176x. */
LPC_SC->PCLKSEL0 = LPC17xx_PCLKSEL0;
LPC_SC->PCLKSEL1 = LPC17xx_PCLKSEL1;
LPC_SC->CCLKCFG = LPC17xx_CCLK_DIV - 1; /* Set CPU clock divider */
LPC_SC->CLKSRCSEL = LPC17xx_SYSCLK_SELECT; /* Select clock source for PLL0 if enabled or CPU */
#if LPC17xx_MAINPLL_ENABLE
/* PLL0 configuration and start */
LPC_SC->PLL0CFG = (LPC17xx_PLL0CFG_NSEL0 << 16) | LPC17xx_PLL0CFG_MSEL0;
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
LPC_SC->PLL0CON = 0x01; /* Enable PLL0. */
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
while (!(LPC_SC->PLL0STAT & (1UL << 26)))
; /* Wait for PLL0 locked */
LPC_SC->PLL0CON = 0x03; /* Enable and Connect PLL0. */
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
while (!(LPC_SC->PLL0STAT & ((1UL << 25) | (1UL << 24))))
; /* Wait for PLL0 connected */
#endif /* LPC17xx_MAINPLL_ENABLE == TRUE */
#if LPC17xx_USBPLL_ENABLE
/* PLL1 configuration and start */
LPC_SC->PLL1CFG = (LPC17xx_PLL1CFG_PSEL1 << 5) | LPC17xx_PLL1CFG_MSEL1;
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
LPC_SC->PLL1CON = 0x01; /* Enable PLL1. */
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
while (!(LPC_SC->PLL1STAT & (1UL << 10)))
; /* Wait for PLL1 locked */
LPC_SC->PLL1CON = 0x03; /* Enable and Connect PLL1. */
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
while (!(LPC_SC->PLL1STAT & ((1UL << 9) | (1UL << 8))))
; /* Wait for PLL1 connected */
#endif /* LPC17xx_USBPLL_ENABLE == TRUE */
#if !LPC17xx_USBPLL_ENABLE && HAL_USE_USB
LPC_SC->USBCLKCFG = LPC17xx_USBCLKPLL0_SELECT;
#endif
/* Power control configuration */
LPC_SC->PCONP = (1 << 15) | (1 << 9); /* Enable power for GPIO and RTC */
#if LPC17xx_CLKOUT_ENABLE
LPC_SC->CLKOUTCFG = (1UL << 8) | ((LPC17xx_CLKOUT_DIV - 1) << 4) | LPC17xx_CLKOUT_SELECT;
#endif
}
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx HAL driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/hal_lld.c
* @brief LPC17xx HAL subsystem low level driver source.
*
* @addtogroup HAL
* @{
*/
#include "ch.h"
#include "hal.h"
/**
* @brief Register missing in NXP header file.
*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level HAL driver initialization.
*
* @notapi
*/
void hal_lld_init(void) {
/* SysTick initialization using the system clock.*/
nvicSetSystemHandlerPriority(HANDLER_SYSTICK, CORTEX_PRIORITY_SYSTICK);
SysTick->LOAD = LPC17xx_CCLK / CH_FREQUENCY - 1;
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_ENABLE_Msk |
SysTick_CTRL_TICKINT_Msk;
/* DWT cycle counter enable.*/
SCS_DEMCR |= SCS_DEMCR_TRCENA;
DWT_CTRL |= DWT_CTRL_CYCCNTENA;
#if defined(LPC17xx_DMA_REQUIRED)
dmaInit();
#endif
}
/**
* @brief LPC17xx clocks and PLL initialization.
* @note All the involved constants come from the file @p board.h.
* @note This function must be invoked only after the system reset.
*
* @special
*/
void LPC17xx_clock_init(void) {
/* Flash wait states setting, the code takes care to not touch TBD bits.*/
LPC_SC->FLASHCFG = (LPC_SC->FLASHCFG & ~(0x0000000F << 12)) | (LPC17xx_FLASHCFG_FLASHTIM << 12);
/* System oscillator initialization if required.*/
#if LPC17xx_MAINOSC_ENABLE
LPC_SC->SCS = (1 << 5) | (LPC17xx_OSCRANGE << 4); /* Enable Main oscillator */
while (!(LPC_SC->SCS & (1 << 6)))
; /* Wait for main oscillator to be ready */
#endif
/* Peripheral clock divider initialization, must be set before enabling Main PLL (PLL0).
Read errata sheet ES_LPC176x. */
LPC_SC->PCLKSEL0 = LPC17xx_PCLKSEL0;
LPC_SC->PCLKSEL1 = LPC17xx_PCLKSEL1;
LPC_SC->CCLKCFG = LPC17xx_CCLK_DIV - 1; /* Set CPU clock divider */
LPC_SC->CLKSRCSEL = LPC17xx_SYSCLK_SELECT; /* Select clock source for PLL0 if enabled or CPU */
#if LPC17xx_MAINPLL_ENABLE
/* PLL0 configuration and start */
LPC_SC->PLL0CFG = (LPC17xx_PLL0CFG_NSEL0 << 16) | LPC17xx_PLL0CFG_MSEL0;
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
LPC_SC->PLL0CON = 0x01; /* Enable PLL0. */
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
while (!(LPC_SC->PLL0STAT & (1UL << 26)))
; /* Wait for PLL0 locked */
LPC_SC->PLL0CON = 0x03; /* Enable and Connect PLL0. */
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
while (!(LPC_SC->PLL0STAT & ((1UL << 25) | (1UL << 24))))
; /* Wait for PLL0 connected */
#endif /* LPC17xx_MAINPLL_ENABLE == TRUE */
#if LPC17xx_USBPLL_ENABLE
/* PLL1 configuration and start */
LPC_SC->PLL1CFG = (LPC17xx_PLL1CFG_PSEL1 << 5) | LPC17xx_PLL1CFG_MSEL1;
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
LPC_SC->PLL1CON = 0x01; /* Enable PLL1. */
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
while (!(LPC_SC->PLL1STAT & (1UL << 10)))
; /* Wait for PLL1 locked */
LPC_SC->PLL1CON = 0x03; /* Enable and Connect PLL1. */
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
while (!(LPC_SC->PLL1STAT & ((1UL << 9) | (1UL << 8))))
; /* Wait for PLL1 connected */
#endif /* LPC17xx_USBPLL_ENABLE == TRUE */
#if !LPC17xx_USBPLL_ENABLE && HAL_USE_USB
LPC_SC->USBCLKCFG = LPC17xx_USBCLKPLL0_SELECT;
#endif
/* Power control configuration */
LPC_SC->PCONP = (1 << 15) | (1 << 9); /* Enable power for GPIO and RTC */
#if LPC17xx_CLKOUT_ENABLE
LPC_SC->CLKOUTCFG = (1UL << 8) | ((LPC17xx_CLKOUT_DIV - 1) << 4) | LPC17xx_CLKOUT_SELECT;
#endif
}
/** @} */

View File

@ -1,433 +1,433 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx HAL driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/hal_lld.h
* @brief HAL subsystem low level driver header template.
*
* @addtogroup HAL
* @{
*/
#ifndef _HAL_LLD_H_
#define _HAL_LLD_H_
#include "LPC17xx.h"
#include "nvic.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Defines the support for realtime counters in the HAL.
*/
#define HAL_IMPLEMENTS_COUNTERS TRUE
/**
* @brief Platform name.
*/
#define PLATFORM_NAME "LPC17xx"
#define IRCOSCCLK 4000000UL /**< High speed internal clock. */
#define CLKSRCSEL_IRCOSC 0UL /**< Clock source is IRC. */
#define CLKSRCSEL_MAINOSC 1UL /**< Clock source is Main oscillator. */
#define CLKSRCSEL_RTCOSC 2UL /**< Clock source is RTC oscillator. */
#define PCLKSEL_CCLK_DIV_4 0UL /**< Peripheral clock source is CCLK/4 */
#define PCLKSEL_CCLK 1UL /**< Peripheral clock source is CCLK */
#define PCLKSEL_CCLK_DIV_2 2UL /**< Peripheral clock source is CCLK/2 */
#define PCLKSEL_CCLK_DIV_8 3UL /**< Peripheral clock source is CCLK/8 */
#define PCLKSEL_MASK 3UL
#define CLKOUTSEL_CCLK 0UL /**< Clock output is CPU clock. */
#define CLKOUTSEL_MAINOSC 1UL /**< Clock output is Main oscillator. */
#define CLKOUTSEL_IRCOSC 2UL /**< Clock output is IRC oscillator. */
#define CLKOUTSEL_USBCLK 3UL /**< Clock output is USB clock. */
#define CLKOUTSEL_RTCOSC 4UL /**< Clock output is RTC oscillator. */
#define PCLKSEL_CCLK_DIV_4 0UL /**< Peripheral clock output is CCLK/4 */
#define PCLKSEL_CCLK 1UL /**< Peripheral clock output is CCLK */
#define PCLKSEL_CCLK_DIV_2 2UL /**< Peripheral clock output is CCLK/2 */
#define PCLKSEL_CCLK_DIV_8 3UL /**< Peripheral clock output is CCLK/8 */
#define USBSEL_PLL0_DIV_6 5UL /**< USB clock source is PLL0/6. */
#define USBSEL_PLL0_DIV_7 7UL /**< USB clock source is PLL0/7. */
#define USBSEL_PLL0_DIV_9 9UL /**< USB clock source is PLL0/9. */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Main oscillator enable.
*/
#if !defined(LPC17xx_MAINOSC_ENABLE) || defined(__DOXYGEN__)
#define LPC17xx_MAINOSC_ENABLE TRUE
#endif
/**
* @brief System PLL clock source select.
*/
#if !defined(LPC17xx_SYSCLK_SELECT) || defined(__DOXYGEN__)
#define LPC17xx_SYSCLK_SELECT CLKSRCSEL_MAINOSC
#endif
/**
* @brief Main PLL enable.
*/
#if !defined(LPC17xx_MAINPLL_ENABLE) || defined(__DOXYGEN__)
#define LPC17xx_MAINPLL_ENABLE TRUE
#endif
/**
* @brief Main PLL multiplier.
* @note Final frequency must not exceed the CCO ratings.
*/
#if !defined(LPC17xx_MAINPLL_MUL) || defined(__DOXYGEN__)
#define LPC17xx_MAINPLL_MUL 200
#endif
/**
* @brief Main PLL pre-divider.
* @note The value must be in the 1..32 range and the final frequency
* must not exceed the CCO ratings.
*/
#if !defined(LPC17xx_MAINPLL_PREDIV) || defined(__DOXYGEN__)
#define LPC17xx_MAINPLL_PREDIV 6
#endif
/**
* @brief USB PLL enable.
*/
#if !defined(LPC17xx_USBPLL_ENABLE) || defined(__DOXYGEN__)
#define LPC17xx_USBPLL_ENABLE FALSE
#endif
/**
* @brief USB PLL multiplier.
* @note The value must be in the 1..32 range and the final frequency
* must not exceed the CCO ratings and USB clock must be equal 48MHz.
*/
#if !defined(LPC17xx_USBPLL_MUL) || defined(__DOXYGEN__)
#define LPC17xx_USBPLL_MUL 4
#endif
/**
* @brief USB PLL divider.
* @note The value must be 2, 4, 8 or 16 and the final frequency
* must not exceed the CCO ratings and USB clock must be equal 48MHz.
*/
#if !defined(LPC17xx_USBPLL_DIV) || defined(__DOXYGEN__)
#define LPC17xx_USBPLL_DIV 4
#endif
/**
* @brief CPU clock divider.
* @note The value must be chosen between (1...255).
*/
#if !defined(LPC17xx_CCLK_DIV) || defined(__DOXYGEN__)
#define LPC17xx_CCLK_DIV 4
#endif
/**
* @brief PCLK clock select.
*/
#if !defined(LPC17xx_PCLK_SELECT) || defined(__DOXYGEN__)
#define LPC17xx_PCLK_SELECT PCLKSEL_CCLK
#endif
/**
* @brief Clock output enable.
* @note
*/
#if !defined(LPC17xx_CLKOUT_ENABLE) || defined(__DOXYGEN__)
#define LPC17xx_CLKOUT_ENABLE FALSE
#endif
/**
* @brief Clock output divider.
* @note The value must be chosen between (1...16).
*/
#if !defined(LPC17xx_CLKOUT_DIV) || defined(__DOXYGEN__)
#define LPC17xx_CLKOUT_DIV 4
#endif
/**
* @brief Clock output clock source select.
*/
#if !defined(LPC17xx_CLKOUT_SELECT) || defined(__DOXYGEN__)
#define LPC17xx_CLKOUT_SELECT CLKOUTSEL_MAINOSC
#endif
/**
* @brief USB clock PPL0 clock source select.
* @note PLL0 output must be 288MHz (USBSEL_PLL0_DIV_6), 384MHz (USBSEL_PLL0_DIV_8) or
* 480MHz(USBSEL_PLL0_DIV_10). Only is used when USB PLL (PLL1) disable.
*/
#if !defined(LPC17xx_USBCLKPLL0_SELECT) || defined(__DOXYGEN__)
#define LPC17xx_USBCLKPLL0_SELECT USBSEL_PLL0_DIV_6
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/**
* @brief Calculated OSCRANGE setting.
*/
#if (MAINOSCCLK < 18000000) || defined(__DOXYGEN__)
#define LPC17xx_OSCRANGE 0
#else
#define LPC17xx_OSCRANGE 1
#endif
/**
* @brief PLL input clock frequency.
*/
#if (LPC17xx_SYSCLK_SELECT == CLKSRCSEL_IRCOSC) || defined(__DOXYGEN__)
#define LPC17xx_SYSCLK IRCOSCCLK
#elif LPC17xx_SYSCLK_SELECT == CLKSRCSEL_MAINOSC
#define LPC17xx_SYSCLK MAINOSCCLK
#elif LPC17xx_SYSCLK_SELECT == CLKSRCSEL_RTCOSC
#define LPC17xx_SYSCLK RTCOSCCLK
#else
#error "Invalid LPC17xx_SYSCLK_SELECT clock source specified."
#endif
/**
* @brief MSEL mask in SYSPLLCTRL register.
*/
#if ((LPC17xx_MAINPLL_MUL % 2) == 0) || defined(__DOXYGEN__)
#define LPC17xx_PLL0CFG_MSEL0 ((LPC17xx_MAINPLL_MUL/2) - 1)
#else
#error "Invalid LPC17xx_PLL0CFG_MUL value."
#endif
/**
* @brief PSEL mask in SYSPLLCTRL register.
*/
#if ((LPC17xx_MAINPLL_PREDIV >= 1) && (LPC17xx_MAINPLL_PREDIV <= 32)) || defined(__DOXYGEN__)
#define LPC17xx_PLL0CFG_NSEL0 (LPC17xx_MAINPLL_PREDIV - 1)
#else
#error "Invalid LPC17xx_MAINPLL_PREDIV value (1 to 32 accepted)."
#endif
/**
* @brief CCO frequency.
*/
#define LPC17xx_MAINPLLCCO ((LPC17xx_MAINPLL_MUL * \
LPC17xx_SYSCLK)/LPC17xx_MAINPLL_PREDIV)
#if (LPC17xx_MAINPLLCCO < 275000000) || (LPC17xx_SYSPLLCCO > 550000000)
#error "CCO frequency out of the acceptable range (275...550)."
#endif
/**
* @brief PLL output clock frequency.
*/
#if LPC17xx_MAINPLL_ENABLE
#define LPC17xx_MAINPLLCLK LPC17xx_MAINPLLCCO
#else
#define LPC17xx_MAINPLLCLK LPC17xx_SYSCLK
#endif
/**
* @brief CPU clock frequency.
* @note Most of LPC17xx have max 120 MHz clock.
*/
#define LPC17xx_CCLK (LPC17xx_MAINPLLCLK/LPC17xx_CCLK_DIV)
#if (LPC17xx_CCLK > 120000000) || defined(__DOXYGEN__)
#error "CPU Clock out of range."
#endif
#if LPC17xx_USBPLL_ENABLE
/**
* @brief Main oscillator out of range.
*/
#if ((MAINOSCCLK < 10000000) && (MAINOSCCLK > 25000000)) || defined(__DOXYGEN__)
#error "Main oscillator clock out of range."
#endif
/**
* @brief MSEL1 mask in PLL1CFG register.
*/
#if (LPC17xx_USBPLL_MUL >= 1) && (LPC17xx_USBPLL_MUL <= 32) || defined(__DOXYGEN__)
#define LPC17xx_PLL1CFG_MSEL1 (LPC17xx_USBPLL_MUL - 1)
#else
#error "Invalid LPC17xx_USBPLL_MUL value (1 to 32 accepted)."
#endif
/**
* @brief PSEL1 mask in PLL1CFG register.
*/
#if (LPC17xx_USBPLL_DIV == 2) || defined(__DOXYGEN__)
#define LPC17xx_PLL1CFG_PSEL1 0UL
#elif (LPC17xx_USBPLL_DIV == 4)
#define LPC17xx_PLL1CFG_PSEL1 1UL
#elif (LPC17xx_USBPLL_DIV == 8)
#define LPC17xx_PLL1CFG_PSEL1 2UL
#elif (LPC17xx_USBPLL_DIV == 16)
#define LPC17xx_PLL1CFG_PSEL1 3UL
#else
#error "Invalid LPC17xx_USBPLL_DIV value (2, 4, 8, 16 accepted)."
#endif
/**
* @brief USB PLL CCO frequency.
*/
#define LPC17xx_USBPLLCCO (MAINOSCCLK * LPC17xx_USBPLL_MUL * \
LPC17xx_USBPLL_DIV)
#if (LPC17xx_USBPLLCCO < 156000000) || (LPC17xx_SYSPLLCCO > 320000000)
#error "CCO frequency out of the acceptable range (156...320)"
#endif
/**
* @brief USB clock frequency.
* @note Must be 48 MHz.
*/
#define LPC17xx_USBCLK (LPC17xx_USBPLLCCO/LPC17xx_USBPLL_DIV)
#if (LPC17xx_USBCLK != 48000000) || defined(__DOXYGEN__)
#error "USB clock out of range."
#endif
#endif
/**
* @brief Peripheral clock frequency.
*/
#if (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK_DIV_4) || defined(__DOXYGEN__)
#define LPC17xx_PCLK (LPC17xx_CCLK/4)
#define LPC17xx_PCLKSEL0 0x00
#define LPC17xx_PCLKSEL1 0x00
#elif (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK)
#define LPC17xx_PCLK (LPC17xx_CCLK)
#define LPC17xx_PCLKSEL0 0x55515155
#define LPC17xx_PCLKSEL1 0x54555455
#elif (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK_DIV_2)
#define LPC17xx_PCLK (LPC17xx_CCLK/2)
#define LPC17xx_PCLKSEL0 0xAAA2A2AA
#define LPC17xx_PCLKSEL1 0xA8AAA8AA
#elif (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK_DIV_8)
#define LPC17xx_PCLK (LPC17xx_CCLK/8)
#define LPC17xx_PCLKSEL0 0xFFF3F3FF
#define LPC17xx_PCLKSEL1 0xFCFFFCFF
#else
#error "Invalid LPC17xx_PCLK_SELECT value"
#endif
/**
* @brief LPC17xx_CLKOUT_DIV out of range.
*/
#if ((LPC17xx_CLKOUT_DIV < 1) && (LPC17xx_CLKOUT_DIV > 16)) || defined(__DOXYGEN__)
#error "Invalid LPC17xx_CLKOUT_DIV value (1 to 16 accepted)."
#endif
/**
* @brief CLKOUT frequency.
*/
#if (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_CCLK) || defined(__DOXYGEN__)
#define LPC17xx_CLKOUTCLK (LPC17xx_CCLK/LPC17xx_CLKOUT_DIV)
#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_MAINOSC)
#define LPC17xx_CLKOUTCLK (MAINOSCCLK/LPC17xx_CLKOUT_DIV)
#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_IRCOSC)
#define LPC17xx_CLKOUTCLK (IRCOSCCLK/LPC17xx_CLKOUT_DIV)
#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_USBCLK)
#define LPC17xx_CLKOUTCLK (LPC17xx_USBCLK/LPC17xx_CLKOUT_DIV)
#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_RTCOSC)
#define LPC17xx_CLKOUTCLK (RTCOSCCLK/LPC17xx_CLKOUT_DIV)
#else
#error "Invalid LPC17xx_CLKOUT_SELECT value."
#endif
/**
* @brief CLKOUT frequency out of range.
*/
#if (LPC17xx_CLKOUTCLK > 50000000) || defined(__DOXYGEN__)
#error "CLKOUT frequency out of the acceptable range (less than 50 MHz)"
#endif
/**
* @brief Flash wait states.
*/
#if (LPC17xx_CCLK <= 20000000) || defined(__DOXYGEN__)
#define LPC17xx_FLASHCFG_FLASHTIM 0UL
#elif LPC17xx_CCLK <= 40000000
#define LPC17xx_FLASHCFG_FLASHTIM 1UL
#elif LPC17xx_CCLK <= 60000000
#define LPC17xx_FLASHCFG_FLASHTIM 2UL
#elif LPC17xx_CCLK <= 80000000
#define LPC17xx_FLASHCFG_FLASHTIM 3UL
#elif LPC17xx_CCLK <= 120000000
#define LPC17xx_FLASHCFG_FLASHTIM 4UL
#else
#define LPC17xx_FLASHCFG_FLASHTIM 5UL
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of the realtime free counter value.
*/
typedef uint32_t halrtcnt_t;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Returns the current value of the system free running counter.
* @note This service is implemented by returning the content of the
* DWT_CYCCNT register.
*
* @return The value of the system free running counter of
* type halrtcnt_t.
*
* @notapi
*/
#define hal_lld_get_counter_value() DWT_CYCCNT
/**
* @brief Realtime counter frequency.
* @note The DWT_CYCCNT register is incremented directly by the cpu
* clock so this function returns LPC17xx_CCLK.
*
* @return The realtime counter frequency of type halclock_t.
*
* @notapi
*/
#define hal_lld_get_counter_frequency() LPC17xx_CCLK
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#include "lpc17xx_dma.h"
#ifdef __cplusplus
extern "C" {
#endif
void hal_lld_init(void);
void LPC17xx_clock_init(void);
#ifdef __cplusplus
}
#endif
#endif /* _HAL_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx HAL driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/hal_lld.h
* @brief HAL subsystem low level driver header template.
*
* @addtogroup HAL
* @{
*/
#ifndef _HAL_LLD_H_
#define _HAL_LLD_H_
#include "LPC17xx.h"
#include "nvic.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Defines the support for realtime counters in the HAL.
*/
#define HAL_IMPLEMENTS_COUNTERS TRUE
/**
* @brief Platform name.
*/
#define PLATFORM_NAME "LPC17xx"
#define IRCOSCCLK 4000000UL /**< High speed internal clock. */
#define CLKSRCSEL_IRCOSC 0UL /**< Clock source is IRC. */
#define CLKSRCSEL_MAINOSC 1UL /**< Clock source is Main oscillator. */
#define CLKSRCSEL_RTCOSC 2UL /**< Clock source is RTC oscillator. */
#define PCLKSEL_CCLK_DIV_4 0UL /**< Peripheral clock source is CCLK/4 */
#define PCLKSEL_CCLK 1UL /**< Peripheral clock source is CCLK */
#define PCLKSEL_CCLK_DIV_2 2UL /**< Peripheral clock source is CCLK/2 */
#define PCLKSEL_CCLK_DIV_8 3UL /**< Peripheral clock source is CCLK/8 */
#define PCLKSEL_MASK 3UL
#define CLKOUTSEL_CCLK 0UL /**< Clock output is CPU clock. */
#define CLKOUTSEL_MAINOSC 1UL /**< Clock output is Main oscillator. */
#define CLKOUTSEL_IRCOSC 2UL /**< Clock output is IRC oscillator. */
#define CLKOUTSEL_USBCLK 3UL /**< Clock output is USB clock. */
#define CLKOUTSEL_RTCOSC 4UL /**< Clock output is RTC oscillator. */
#define PCLKSEL_CCLK_DIV_4 0UL /**< Peripheral clock output is CCLK/4 */
#define PCLKSEL_CCLK 1UL /**< Peripheral clock output is CCLK */
#define PCLKSEL_CCLK_DIV_2 2UL /**< Peripheral clock output is CCLK/2 */
#define PCLKSEL_CCLK_DIV_8 3UL /**< Peripheral clock output is CCLK/8 */
#define USBSEL_PLL0_DIV_6 5UL /**< USB clock source is PLL0/6. */
#define USBSEL_PLL0_DIV_7 7UL /**< USB clock source is PLL0/7. */
#define USBSEL_PLL0_DIV_9 9UL /**< USB clock source is PLL0/9. */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Main oscillator enable.
*/
#if !defined(LPC17xx_MAINOSC_ENABLE) || defined(__DOXYGEN__)
#define LPC17xx_MAINOSC_ENABLE TRUE
#endif
/**
* @brief System PLL clock source select.
*/
#if !defined(LPC17xx_SYSCLK_SELECT) || defined(__DOXYGEN__)
#define LPC17xx_SYSCLK_SELECT CLKSRCSEL_MAINOSC
#endif
/**
* @brief Main PLL enable.
*/
#if !defined(LPC17xx_MAINPLL_ENABLE) || defined(__DOXYGEN__)
#define LPC17xx_MAINPLL_ENABLE TRUE
#endif
/**
* @brief Main PLL multiplier.
* @note Final frequency must not exceed the CCO ratings.
*/
#if !defined(LPC17xx_MAINPLL_MUL) || defined(__DOXYGEN__)
#define LPC17xx_MAINPLL_MUL 200
#endif
/**
* @brief Main PLL pre-divider.
* @note The value must be in the 1..32 range and the final frequency
* must not exceed the CCO ratings.
*/
#if !defined(LPC17xx_MAINPLL_PREDIV) || defined(__DOXYGEN__)
#define LPC17xx_MAINPLL_PREDIV 6
#endif
/**
* @brief USB PLL enable.
*/
#if !defined(LPC17xx_USBPLL_ENABLE) || defined(__DOXYGEN__)
#define LPC17xx_USBPLL_ENABLE FALSE
#endif
/**
* @brief USB PLL multiplier.
* @note The value must be in the 1..32 range and the final frequency
* must not exceed the CCO ratings and USB clock must be equal 48MHz.
*/
#if !defined(LPC17xx_USBPLL_MUL) || defined(__DOXYGEN__)
#define LPC17xx_USBPLL_MUL 4
#endif
/**
* @brief USB PLL divider.
* @note The value must be 2, 4, 8 or 16 and the final frequency
* must not exceed the CCO ratings and USB clock must be equal 48MHz.
*/
#if !defined(LPC17xx_USBPLL_DIV) || defined(__DOXYGEN__)
#define LPC17xx_USBPLL_DIV 4
#endif
/**
* @brief CPU clock divider.
* @note The value must be chosen between (1...255).
*/
#if !defined(LPC17xx_CCLK_DIV) || defined(__DOXYGEN__)
#define LPC17xx_CCLK_DIV 4
#endif
/**
* @brief PCLK clock select.
*/
#if !defined(LPC17xx_PCLK_SELECT) || defined(__DOXYGEN__)
#define LPC17xx_PCLK_SELECT PCLKSEL_CCLK
#endif
/**
* @brief Clock output enable.
* @note
*/
#if !defined(LPC17xx_CLKOUT_ENABLE) || defined(__DOXYGEN__)
#define LPC17xx_CLKOUT_ENABLE FALSE
#endif
/**
* @brief Clock output divider.
* @note The value must be chosen between (1...16).
*/
#if !defined(LPC17xx_CLKOUT_DIV) || defined(__DOXYGEN__)
#define LPC17xx_CLKOUT_DIV 4
#endif
/**
* @brief Clock output clock source select.
*/
#if !defined(LPC17xx_CLKOUT_SELECT) || defined(__DOXYGEN__)
#define LPC17xx_CLKOUT_SELECT CLKOUTSEL_MAINOSC
#endif
/**
* @brief USB clock PPL0 clock source select.
* @note PLL0 output must be 288MHz (USBSEL_PLL0_DIV_6), 384MHz (USBSEL_PLL0_DIV_8) or
* 480MHz(USBSEL_PLL0_DIV_10). Only is used when USB PLL (PLL1) disable.
*/
#if !defined(LPC17xx_USBCLKPLL0_SELECT) || defined(__DOXYGEN__)
#define LPC17xx_USBCLKPLL0_SELECT USBSEL_PLL0_DIV_6
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/**
* @brief Calculated OSCRANGE setting.
*/
#if (MAINOSCCLK < 18000000) || defined(__DOXYGEN__)
#define LPC17xx_OSCRANGE 0
#else
#define LPC17xx_OSCRANGE 1
#endif
/**
* @brief PLL input clock frequency.
*/
#if (LPC17xx_SYSCLK_SELECT == CLKSRCSEL_IRCOSC) || defined(__DOXYGEN__)
#define LPC17xx_SYSCLK IRCOSCCLK
#elif LPC17xx_SYSCLK_SELECT == CLKSRCSEL_MAINOSC
#define LPC17xx_SYSCLK MAINOSCCLK
#elif LPC17xx_SYSCLK_SELECT == CLKSRCSEL_RTCOSC
#define LPC17xx_SYSCLK RTCOSCCLK
#else
#error "Invalid LPC17xx_SYSCLK_SELECT clock source specified."
#endif
/**
* @brief MSEL mask in SYSPLLCTRL register.
*/
#if ((LPC17xx_MAINPLL_MUL % 2) == 0) || defined(__DOXYGEN__)
#define LPC17xx_PLL0CFG_MSEL0 ((LPC17xx_MAINPLL_MUL/2) - 1)
#else
#error "Invalid LPC17xx_PLL0CFG_MUL value."
#endif
/**
* @brief PSEL mask in SYSPLLCTRL register.
*/
#if ((LPC17xx_MAINPLL_PREDIV >= 1) && (LPC17xx_MAINPLL_PREDIV <= 32)) || defined(__DOXYGEN__)
#define LPC17xx_PLL0CFG_NSEL0 (LPC17xx_MAINPLL_PREDIV - 1)
#else
#error "Invalid LPC17xx_MAINPLL_PREDIV value (1 to 32 accepted)."
#endif
/**
* @brief CCO frequency.
*/
#define LPC17xx_MAINPLLCCO ((LPC17xx_MAINPLL_MUL * \
LPC17xx_SYSCLK)/LPC17xx_MAINPLL_PREDIV)
#if (LPC17xx_MAINPLLCCO < 275000000) || (LPC17xx_SYSPLLCCO > 550000000)
#error "CCO frequency out of the acceptable range (275...550)."
#endif
/**
* @brief PLL output clock frequency.
*/
#if LPC17xx_MAINPLL_ENABLE
#define LPC17xx_MAINPLLCLK LPC17xx_MAINPLLCCO
#else
#define LPC17xx_MAINPLLCLK LPC17xx_SYSCLK
#endif
/**
* @brief CPU clock frequency.
* @note Most of LPC17xx have max 120 MHz clock.
*/
#define LPC17xx_CCLK (LPC17xx_MAINPLLCLK/LPC17xx_CCLK_DIV)
#if (LPC17xx_CCLK > 120000000) || defined(__DOXYGEN__)
#error "CPU Clock out of range."
#endif
#if LPC17xx_USBPLL_ENABLE
/**
* @brief Main oscillator out of range.
*/
#if ((MAINOSCCLK < 10000000) && (MAINOSCCLK > 25000000)) || defined(__DOXYGEN__)
#error "Main oscillator clock out of range."
#endif
/**
* @brief MSEL1 mask in PLL1CFG register.
*/
#if (LPC17xx_USBPLL_MUL >= 1) && (LPC17xx_USBPLL_MUL <= 32) || defined(__DOXYGEN__)
#define LPC17xx_PLL1CFG_MSEL1 (LPC17xx_USBPLL_MUL - 1)
#else
#error "Invalid LPC17xx_USBPLL_MUL value (1 to 32 accepted)."
#endif
/**
* @brief PSEL1 mask in PLL1CFG register.
*/
#if (LPC17xx_USBPLL_DIV == 2) || defined(__DOXYGEN__)
#define LPC17xx_PLL1CFG_PSEL1 0UL
#elif (LPC17xx_USBPLL_DIV == 4)
#define LPC17xx_PLL1CFG_PSEL1 1UL
#elif (LPC17xx_USBPLL_DIV == 8)
#define LPC17xx_PLL1CFG_PSEL1 2UL
#elif (LPC17xx_USBPLL_DIV == 16)
#define LPC17xx_PLL1CFG_PSEL1 3UL
#else
#error "Invalid LPC17xx_USBPLL_DIV value (2, 4, 8, 16 accepted)."
#endif
/**
* @brief USB PLL CCO frequency.
*/
#define LPC17xx_USBPLLCCO (MAINOSCCLK * LPC17xx_USBPLL_MUL * \
LPC17xx_USBPLL_DIV)
#if (LPC17xx_USBPLLCCO < 156000000) || (LPC17xx_SYSPLLCCO > 320000000)
#error "CCO frequency out of the acceptable range (156...320)"
#endif
/**
* @brief USB clock frequency.
* @note Must be 48 MHz.
*/
#define LPC17xx_USBCLK (LPC17xx_USBPLLCCO/LPC17xx_USBPLL_DIV)
#if (LPC17xx_USBCLK != 48000000) || defined(__DOXYGEN__)
#error "USB clock out of range."
#endif
#endif
/**
* @brief Peripheral clock frequency.
*/
#if (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK_DIV_4) || defined(__DOXYGEN__)
#define LPC17xx_PCLK (LPC17xx_CCLK/4)
#define LPC17xx_PCLKSEL0 0x00
#define LPC17xx_PCLKSEL1 0x00
#elif (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK)
#define LPC17xx_PCLK (LPC17xx_CCLK)
#define LPC17xx_PCLKSEL0 0x55515155
#define LPC17xx_PCLKSEL1 0x54555455
#elif (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK_DIV_2)
#define LPC17xx_PCLK (LPC17xx_CCLK/2)
#define LPC17xx_PCLKSEL0 0xAAA2A2AA
#define LPC17xx_PCLKSEL1 0xA8AAA8AA
#elif (LPC17xx_PCLK_SELECT == PCLKSEL_CCLK_DIV_8)
#define LPC17xx_PCLK (LPC17xx_CCLK/8)
#define LPC17xx_PCLKSEL0 0xFFF3F3FF
#define LPC17xx_PCLKSEL1 0xFCFFFCFF
#else
#error "Invalid LPC17xx_PCLK_SELECT value"
#endif
/**
* @brief LPC17xx_CLKOUT_DIV out of range.
*/
#if ((LPC17xx_CLKOUT_DIV < 1) && (LPC17xx_CLKOUT_DIV > 16)) || defined(__DOXYGEN__)
#error "Invalid LPC17xx_CLKOUT_DIV value (1 to 16 accepted)."
#endif
/**
* @brief CLKOUT frequency.
*/
#if (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_CCLK) || defined(__DOXYGEN__)
#define LPC17xx_CLKOUTCLK (LPC17xx_CCLK/LPC17xx_CLKOUT_DIV)
#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_MAINOSC)
#define LPC17xx_CLKOUTCLK (MAINOSCCLK/LPC17xx_CLKOUT_DIV)
#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_IRCOSC)
#define LPC17xx_CLKOUTCLK (IRCOSCCLK/LPC17xx_CLKOUT_DIV)
#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_USBCLK)
#define LPC17xx_CLKOUTCLK (LPC17xx_USBCLK/LPC17xx_CLKOUT_DIV)
#elif (LPC17xx_CLKOUT_SELECT == CLKOUTSEL_RTCOSC)
#define LPC17xx_CLKOUTCLK (RTCOSCCLK/LPC17xx_CLKOUT_DIV)
#else
#error "Invalid LPC17xx_CLKOUT_SELECT value."
#endif
/**
* @brief CLKOUT frequency out of range.
*/
#if (LPC17xx_CLKOUTCLK > 50000000) || defined(__DOXYGEN__)
#error "CLKOUT frequency out of the acceptable range (less than 50 MHz)"
#endif
/**
* @brief Flash wait states.
*/
#if (LPC17xx_CCLK <= 20000000) || defined(__DOXYGEN__)
#define LPC17xx_FLASHCFG_FLASHTIM 0UL
#elif LPC17xx_CCLK <= 40000000
#define LPC17xx_FLASHCFG_FLASHTIM 1UL
#elif LPC17xx_CCLK <= 60000000
#define LPC17xx_FLASHCFG_FLASHTIM 2UL
#elif LPC17xx_CCLK <= 80000000
#define LPC17xx_FLASHCFG_FLASHTIM 3UL
#elif LPC17xx_CCLK <= 120000000
#define LPC17xx_FLASHCFG_FLASHTIM 4UL
#else
#define LPC17xx_FLASHCFG_FLASHTIM 5UL
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of the realtime free counter value.
*/
typedef uint32_t halrtcnt_t;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Returns the current value of the system free running counter.
* @note This service is implemented by returning the content of the
* DWT_CYCCNT register.
*
* @return The value of the system free running counter of
* type halrtcnt_t.
*
* @notapi
*/
#define hal_lld_get_counter_value() DWT_CYCCNT
/**
* @brief Realtime counter frequency.
* @note The DWT_CYCCNT register is incremented directly by the cpu
* clock so this function returns LPC17xx_CCLK.
*
* @return The realtime counter frequency of type halclock_t.
*
* @notapi
*/
#define hal_lld_get_counter_frequency() LPC17xx_CCLK
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#include "lpc17xx_dma.h"
#ifdef __cplusplus
extern "C" {
#endif
void hal_lld_init(void);
void LPC17xx_clock_init(void);
#ifdef __cplusplus
}
#endif
#endif /* _HAL_LLD_H_ */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -1,271 +1,271 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx I2C driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file LPC17xx/i2c_lld.h
* @brief LPC17xx I2C subsystem low level driver header.
*
* @addtogroup I2C
* @{
*/
#ifndef _I2C_LLD_H_
#define _I2C_LLD_H_
#if HAL_USE_I2C || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define I2C_CONSET_AA 0x04 /* Assert acknowledge flag. */
#define I2C_CONSET_SI 0x08 /* I2C interrupt flag. */
#define I2C_CONSET_STO 0x10 /* STOP flag. */
#define I2C_CONSET_STA 0x20 /* START flag. */
#define I2C_CONSET_EN 0x40 /* I2C interface enable. */
#define I2C_CONCLR_AAC 0x04 /* Assert acknowledge Clear bit. */
#define I2C_CONCLR_SIC 0x08 /* I2C interrupt Clear bit. */
#define I2C_CONCLR_STAC 0x20 /* START flag Clear bit. */
#define I2C_CONCLR_ENC 0x40 /* I2C interface Disable bit. */
#define I2C_WR_BIT 0x00
#define I2C_RD_BIT 0x01
#define I2C_STATE_MS_START 0x08
#define I2C_STATE_MS_RSTART 0x10
#define I2C_STATE_MS_SLAW_ACK 0x18
#define I2C_STATE_MS_SLAW_NACK 0x20
#define I2C_STATE_MS_TDAT_ACK 0x28
#define I2C_STATE_MS_TDAT_NACK 0x30
#define I2C_STATE_ARB_LOST 0x38
#define I2C_STATE_MS_SLAR_ACK 0x40
#define I2C_STATE_MS_SLAR_NACK 0x48
#define I2C_STATE_MS_RDAT_ACK 0x50
#define I2C_STATE_MS_RDAT_NACK 0x58
#define I2C_STATE_BUS_ERROR 0x00
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief I2C0 driver enable switch.
* @details If set to @p TRUE the support for device I2C0 is included.
* @note The default is @p FALSE.
*/
#if !defined(LPC17xx_I2C_USE_I2C0) || defined(__DOXYGEN__)
#define LPC17xx_I2C_USE_I2C0 FALSE
#endif
/**
* @brief I2C0 interrupt priority level setting.
*/
#if !defined(LPC17xx_I2C_I2C0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_I2C_I2C0_IRQ_PRIORITY 3
#endif
/**
* @brief I2C1 driver enable switch.
* @details If set to @p TRUE the support for device I2C0 is included.
* @note The default is @p FALSE.
*/
#if !defined(LPC17xx_I2C_USE_I2C1) || defined(__DOXYGEN__)
#define LPC17xx_I2C_USE_I2C1 FALSE
#endif
/**
* @brief I2C1 interrupt priority level setting.
*/
#if !defined(LPC17xx_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_I2C_I2C1_IRQ_PRIORITY 3
#endif
/**
* @brief I2C2 driver enable switch.
* @details If set to @p TRUE the support for device I2C0 is included.
* @note The default is @p FALSE.
*/
#if !defined(LPC17xx_I2C_USE_I2C2) || defined(__DOXYGEN__)
#define LPC17xx_I2C_USE_I2C2 FALSE
#endif
/**
* @brief I2C0 interrupt priority level setting.
*/
#if !defined(LPC17xx_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_I2C_I2C2_IRQ_PRIORITY 3
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type representing I2C address.
*/
typedef uint16_t i2caddr_t;
/**
* @brief I2C Driver condition flags type.
*/
typedef uint32_t i2cflags_t;
/**
* @brief Supported modes for the I2C bus.
*/
typedef enum {
I2C_STANDARD_MODE = 1,
I2C_FAST_MODE = 2,
I2C_FAST_MODE_PLUS = 3,
} i2cmode_t;
/**
* @brief Driver configuration structure.
*/
typedef struct {
i2cmode_t mode; /**< @brief Specifies the I2C mode. */
uint32_t clock_timing; /**< @brief Specifies the clock timing */
} I2CConfig;
/**
* @brief Type of a structure representing an I2C driver.
*/
typedef struct I2CDriver I2CDriver;
/**
* @brief Structure representing an I2C driver.
*/
struct I2CDriver {
/**
* @brief Driver state.
*/
i2cstate_t state;
/**
* @brief Current configuration data.
*/
const I2CConfig *config;
/**
* @brief Error flags.
*/
i2cflags_t errors;
#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* I2C_USE_MUTUAL_EXCLUSION */
#if defined(I2C_DRIVER_EXT_FIELDS)
I2C_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Thread waiting for I/O completion.
*/
Thread *thread;
/**
* @brief Current slave address without R/W bit.
*/
i2caddr_t addr;
/**
* @brief Pointer to the transmit buffer.
*/
const uint8_t *txbuf;
/**
* @brief Number of bytes to transmit.
*/
size_t txbytes;
/**
* @brief Pointer to the receive buffer.
*/
uint8_t *rxbuf;
/**
* @brief Number of bytes to receive.
*/
size_t rxbytes;
/**
* @brief Pointer to the I2C registers block.
*/
LPC_I2C_TypeDef *i2c;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get errors from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC17xx_I2C_USE_I2C0 && !defined(__DOXYGEN__)
extern I2CDriver I2CD1;
#endif
#if LPC17xx_I2C_USE_I2C1 && !defined(__DOXYGEN__)
extern I2CDriver I2CD2;
#endif
#if LPC17xx_I2C_USE_I2C2 && !defined(__DOXYGEN__)
extern I2CDriver I2CD3;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void i2c_lld_init(void);
void i2c_lld_start(I2CDriver *i2cp);
void i2c_lld_stop(I2CDriver *i2cp);
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
#ifdef __cplusplus
}
#endif
#endif
#endif /* _I2C_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx I2C driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file LPC17xx/i2c_lld.h
* @brief LPC17xx I2C subsystem low level driver header.
*
* @addtogroup I2C
* @{
*/
#ifndef _I2C_LLD_H_
#define _I2C_LLD_H_
#if HAL_USE_I2C || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define I2C_CONSET_AA 0x04 /* Assert acknowledge flag. */
#define I2C_CONSET_SI 0x08 /* I2C interrupt flag. */
#define I2C_CONSET_STO 0x10 /* STOP flag. */
#define I2C_CONSET_STA 0x20 /* START flag. */
#define I2C_CONSET_EN 0x40 /* I2C interface enable. */
#define I2C_CONCLR_AAC 0x04 /* Assert acknowledge Clear bit. */
#define I2C_CONCLR_SIC 0x08 /* I2C interrupt Clear bit. */
#define I2C_CONCLR_STAC 0x20 /* START flag Clear bit. */
#define I2C_CONCLR_ENC 0x40 /* I2C interface Disable bit. */
#define I2C_WR_BIT 0x00
#define I2C_RD_BIT 0x01
#define I2C_STATE_MS_START 0x08
#define I2C_STATE_MS_RSTART 0x10
#define I2C_STATE_MS_SLAW_ACK 0x18
#define I2C_STATE_MS_SLAW_NACK 0x20
#define I2C_STATE_MS_TDAT_ACK 0x28
#define I2C_STATE_MS_TDAT_NACK 0x30
#define I2C_STATE_ARB_LOST 0x38
#define I2C_STATE_MS_SLAR_ACK 0x40
#define I2C_STATE_MS_SLAR_NACK 0x48
#define I2C_STATE_MS_RDAT_ACK 0x50
#define I2C_STATE_MS_RDAT_NACK 0x58
#define I2C_STATE_BUS_ERROR 0x00
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief I2C0 driver enable switch.
* @details If set to @p TRUE the support for device I2C0 is included.
* @note The default is @p FALSE.
*/
#if !defined(LPC17xx_I2C_USE_I2C0) || defined(__DOXYGEN__)
#define LPC17xx_I2C_USE_I2C0 FALSE
#endif
/**
* @brief I2C0 interrupt priority level setting.
*/
#if !defined(LPC17xx_I2C_I2C0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_I2C_I2C0_IRQ_PRIORITY 3
#endif
/**
* @brief I2C1 driver enable switch.
* @details If set to @p TRUE the support for device I2C0 is included.
* @note The default is @p FALSE.
*/
#if !defined(LPC17xx_I2C_USE_I2C1) || defined(__DOXYGEN__)
#define LPC17xx_I2C_USE_I2C1 FALSE
#endif
/**
* @brief I2C1 interrupt priority level setting.
*/
#if !defined(LPC17xx_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_I2C_I2C1_IRQ_PRIORITY 3
#endif
/**
* @brief I2C2 driver enable switch.
* @details If set to @p TRUE the support for device I2C0 is included.
* @note The default is @p FALSE.
*/
#if !defined(LPC17xx_I2C_USE_I2C2) || defined(__DOXYGEN__)
#define LPC17xx_I2C_USE_I2C2 FALSE
#endif
/**
* @brief I2C0 interrupt priority level setting.
*/
#if !defined(LPC17xx_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_I2C_I2C2_IRQ_PRIORITY 3
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type representing I2C address.
*/
typedef uint16_t i2caddr_t;
/**
* @brief I2C Driver condition flags type.
*/
typedef uint32_t i2cflags_t;
/**
* @brief Supported modes for the I2C bus.
*/
typedef enum {
I2C_STANDARD_MODE = 1,
I2C_FAST_MODE = 2,
I2C_FAST_MODE_PLUS = 3,
} i2cmode_t;
/**
* @brief Driver configuration structure.
*/
typedef struct {
i2cmode_t mode; /**< @brief Specifies the I2C mode. */
uint32_t clock_timing; /**< @brief Specifies the clock timing */
} I2CConfig;
/**
* @brief Type of a structure representing an I2C driver.
*/
typedef struct I2CDriver I2CDriver;
/**
* @brief Structure representing an I2C driver.
*/
struct I2CDriver {
/**
* @brief Driver state.
*/
i2cstate_t state;
/**
* @brief Current configuration data.
*/
const I2CConfig *config;
/**
* @brief Error flags.
*/
i2cflags_t errors;
#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* I2C_USE_MUTUAL_EXCLUSION */
#if defined(I2C_DRIVER_EXT_FIELDS)
I2C_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Thread waiting for I/O completion.
*/
Thread *thread;
/**
* @brief Current slave address without R/W bit.
*/
i2caddr_t addr;
/**
* @brief Pointer to the transmit buffer.
*/
const uint8_t *txbuf;
/**
* @brief Number of bytes to transmit.
*/
size_t txbytes;
/**
* @brief Pointer to the receive buffer.
*/
uint8_t *rxbuf;
/**
* @brief Number of bytes to receive.
*/
size_t rxbytes;
/**
* @brief Pointer to the I2C registers block.
*/
LPC_I2C_TypeDef *i2c;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get errors from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC17xx_I2C_USE_I2C0 && !defined(__DOXYGEN__)
extern I2CDriver I2CD1;
#endif
#if LPC17xx_I2C_USE_I2C1 && !defined(__DOXYGEN__)
extern I2CDriver I2CD2;
#endif
#if LPC17xx_I2C_USE_I2C2 && !defined(__DOXYGEN__)
extern I2CDriver I2CD3;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void i2c_lld_init(void);
void i2c_lld_start(I2CDriver *i2cp);
void i2c_lld_stop(I2CDriver *i2cp);
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
#ifdef __cplusplus
}
#endif
#endif
#endif /* _I2C_LLD_H_ */
/** @} */

View File

@ -1,205 +1,205 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx DMA driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/LPC17xx_dma.c
* @brief DMA driver code.
*
* @addtogroup LPC17xx_DMA
* @details DMA sharing helper driver. In the LPC17xx the DMA streams are a
* shared resource, this driver allows to allocate and free DMA
* streams at runtime in order to allow all the other device
* drivers to coordinate the access to the resource.
* @note The DMA ISR handlers are all declared into this module because
* sharing, the various device drivers can associate a callback to
* ISRs when allocating streams.
* @{
*/
#include "ch.h"
#include "hal.h"
/* The following macro is only defined if some driver requiring DMA services
has been enabled.*/
#if defined(LPC17xx_DMA_REQUIRED) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
LPC_GPDMACH_TypeDef * \
_lpc17xx_dma_channel_config_t[LPC17xx_DMA_CHANNELS] = {
LPC_GPDMACH0, LPC_GPDMACH1, LPC_GPDMACH2, LPC_GPDMACH3, LPC_GPDMACH4,
LPC_GPDMACH5, LPC_GPDMACH6, LPC_GPDMACH7 };
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief DMA ISR redirector type.
*/
typedef struct {
lpc17xx_dmaisr_t dma_func; /**< @brief DMA callback function. */
void *dma_param; /**< @brief DMA callback parameter. */
} dma_isr_redir_t;
/**
* @brief Mask of the allocated streams.
*/
static uint32_t dma_streams_mask;
/**
* @brief DMA IRQ redirectors.
*/
static dma_isr_redir_t dma_isr_redir[LPC17xx_DMA_CHANNELS];
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief DMA interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(VectorA8) {
uint32_t irq_status;
uint32_t err_status;
uint8_t i;
CH_IRQ_PROLOGUE();
irq_status = LPC_GPDMA->IntTCStat;
LPC_GPDMA->IntTCClear = irq_status; /* Clear DMA interrupt flag */
err_status = LPC_GPDMA->IntErrStat;
LPC_GPDMA->IntErrClr = err_status; /* Clear DMA error flag if any*/
for (i = 0; i < LPC17xx_DMA_CHANNELS; i++) {
if (irq_status & (1UL << i)) {
if (dma_isr_redir[i].dma_func)
dma_isr_redir[i].dma_func(dma_isr_redir[i].dma_param, err_status);
}
}
CH_IRQ_EPILOGUE();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief LPC17xx DMA initialization.
*
* @init
*/
void dmaInit(void) {
uint8_t i;
LPC_SC->PCONP |= (1UL << 29); /* Enable DMA power */
/* Disable all channels */
for (i = 0; i < LPC17xx_DMA_CHANNELS; i++)
_lpc17xx_dma_channel_config_t[i]->CConfig = 0;
LPC_GPDMA->IntTCClear = 0xFF;
LPC_GPDMA->IntErrClr = 0xFF;
LPC_GPDMA->Config = DMACCONFIG_E; /* Enable DMA Controller */
while((LPC_GPDMA->Config & DMACCONFIG_E) != 0x01)
;
nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC17xx_DMA_IRQ_PRIORITY));
}
/**
* @brief Allocates a DMA channel.
* @details The channel is allocated.
* @pre The channel must not be already in use or an error is returned.
* @post The channel is allocated and the default ISR handler redirected
* to the specified function.
* @post The channel must be freed using @p dmaChannelRelease() before it can
* be reused with another peripheral.
* @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmach DMA channel number
* @param[in] func handling function pointer, can be @p NULL
* @param[in] param a parameter to be passed to the handling function
* @return The operation status.
* @retval FALSE no error, stream taken.
* @retval TRUE error, stream already taken.
*
* @special
*/
bool_t dmaChannelAllocate(lpc17xx_dma_channel_t dmach,
lpc17xx_dmaisr_t func,
void *param) {
uint32_t channel;
channel = (1UL << dmach);
/* Checks if the channel is already taken.*/
if ((dma_streams_mask & channel) != 0)
return TRUE;
/* Marks the stream as allocated.*/
dma_isr_redir[dmach].dma_func = func;
dma_isr_redir[dmach].dma_param = param;
dma_streams_mask |= channel;
return FALSE;
}
/**
* @brief Releases a DMA channel.
* @details The channel is freed.
* Trying to release a unallocated channel is an illegal operation
* and is trapped if assertions are enabled.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post The channel is again available.
* @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmach DMA channel number
*
* @special
*/
void dmaChannelRelease(lpc17xx_dma_channel_t dmach) {
uint32_t channel;
channel = (1UL << dmach);
/* Check if the streams is not taken.*/
chDbgAssert((dma_streams_mask & channel) != 0,
"dmaStreamRelease(), #1", "not allocated");
dma_streams_mask &= ~channel; /* Marks the stream as not allocated.*/
}
#endif /* LPC17xx_DMA_REQUIRED */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx DMA driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/LPC17xx_dma.c
* @brief DMA driver code.
*
* @addtogroup LPC17xx_DMA
* @details DMA sharing helper driver. In the LPC17xx the DMA streams are a
* shared resource, this driver allows to allocate and free DMA
* streams at runtime in order to allow all the other device
* drivers to coordinate the access to the resource.
* @note The DMA ISR handlers are all declared into this module because
* sharing, the various device drivers can associate a callback to
* ISRs when allocating streams.
* @{
*/
#include "ch.h"
#include "hal.h"
/* The following macro is only defined if some driver requiring DMA services
has been enabled.*/
#if defined(LPC17xx_DMA_REQUIRED) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
LPC_GPDMACH_TypeDef * \
_lpc17xx_dma_channel_config_t[LPC17xx_DMA_CHANNELS] = {
LPC_GPDMACH0, LPC_GPDMACH1, LPC_GPDMACH2, LPC_GPDMACH3, LPC_GPDMACH4,
LPC_GPDMACH5, LPC_GPDMACH6, LPC_GPDMACH7 };
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief DMA ISR redirector type.
*/
typedef struct {
lpc17xx_dmaisr_t dma_func; /**< @brief DMA callback function. */
void *dma_param; /**< @brief DMA callback parameter. */
} dma_isr_redir_t;
/**
* @brief Mask of the allocated streams.
*/
static uint32_t dma_streams_mask;
/**
* @brief DMA IRQ redirectors.
*/
static dma_isr_redir_t dma_isr_redir[LPC17xx_DMA_CHANNELS];
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief DMA interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(VectorA8) {
uint32_t irq_status;
uint32_t err_status;
uint8_t i;
CH_IRQ_PROLOGUE();
irq_status = LPC_GPDMA->IntTCStat;
LPC_GPDMA->IntTCClear = irq_status; /* Clear DMA interrupt flag */
err_status = LPC_GPDMA->IntErrStat;
LPC_GPDMA->IntErrClr = err_status; /* Clear DMA error flag if any*/
for (i = 0; i < LPC17xx_DMA_CHANNELS; i++) {
if (irq_status & (1UL << i)) {
if (dma_isr_redir[i].dma_func)
dma_isr_redir[i].dma_func(dma_isr_redir[i].dma_param, err_status);
}
}
CH_IRQ_EPILOGUE();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief LPC17xx DMA initialization.
*
* @init
*/
void dmaInit(void) {
uint8_t i;
LPC_SC->PCONP |= (1UL << 29); /* Enable DMA power */
/* Disable all channels */
for (i = 0; i < LPC17xx_DMA_CHANNELS; i++)
_lpc17xx_dma_channel_config_t[i]->CConfig = 0;
LPC_GPDMA->IntTCClear = 0xFF;
LPC_GPDMA->IntErrClr = 0xFF;
LPC_GPDMA->Config = DMACCONFIG_E; /* Enable DMA Controller */
while((LPC_GPDMA->Config & DMACCONFIG_E) != 0x01)
;
nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC17xx_DMA_IRQ_PRIORITY));
}
/**
* @brief Allocates a DMA channel.
* @details The channel is allocated.
* @pre The channel must not be already in use or an error is returned.
* @post The channel is allocated and the default ISR handler redirected
* to the specified function.
* @post The channel must be freed using @p dmaChannelRelease() before it can
* be reused with another peripheral.
* @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmach DMA channel number
* @param[in] func handling function pointer, can be @p NULL
* @param[in] param a parameter to be passed to the handling function
* @return The operation status.
* @retval FALSE no error, stream taken.
* @retval TRUE error, stream already taken.
*
* @special
*/
bool_t dmaChannelAllocate(lpc17xx_dma_channel_t dmach,
lpc17xx_dmaisr_t func,
void *param) {
uint32_t channel;
channel = (1UL << dmach);
/* Checks if the channel is already taken.*/
if ((dma_streams_mask & channel) != 0)
return TRUE;
/* Marks the stream as allocated.*/
dma_isr_redir[dmach].dma_func = func;
dma_isr_redir[dmach].dma_param = param;
dma_streams_mask |= channel;
return FALSE;
}
/**
* @brief Releases a DMA channel.
* @details The channel is freed.
* Trying to release a unallocated channel is an illegal operation
* and is trapped if assertions are enabled.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post The channel is again available.
* @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmach DMA channel number
*
* @special
*/
void dmaChannelRelease(lpc17xx_dma_channel_t dmach) {
uint32_t channel;
channel = (1UL << dmach);
/* Check if the streams is not taken.*/
chDbgAssert((dma_streams_mask & channel) != 0,
"dmaStreamRelease(), #1", "not allocated");
dma_streams_mask &= ~channel; /* Marks the stream as not allocated.*/
}
#endif /* LPC17xx_DMA_REQUIRED */
/** @} */

View File

@ -1,422 +1,422 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx DMA driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/LPC17xx_dma.h
* @brief DMA driver header.
*
* @addtogroup LPC17xx_DMA
* @{
*/
#ifndef _LPC17xx_DMA_H_
#define _LPC17xx_DMA_H_
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define DMACCONFIG_E (1UL << 0)
#define DMACCONFIG_M (1UL << 1)
/**
* @brief Total number of DMA streams.
* @note This is the total number of streams among all the DMA units.
*/
#define LPC17xx_DMA_CHANNELS 8
/**
* @name DMA control data configuration
* @{
*/
/**
* @brief DMA transfer size.
*
* @param[in] n DMA transfer size
*/
#define DMA_CTRL_TRANSFER_SIZE(n) (n)
/**
* @brief DMA source burst size.
*/
#define DMA_CTRL_SRC_BSIZE_1 (0 << 12)
#define DMA_CTRL_SRC_BSIZE_4 (1UL << 12)
#define DMA_CTRL_SRC_BSIZE_8 (2UL << 12)
#define DMA_CTRL_SRC_BSIZE_16 (3UL << 12)
#define DMA_CTRL_SRC_BSIZE_32 (4UL << 12)
#define DMA_CTRL_SRC_BSIZE_64 (5UL << 12)
#define DMA_CTRL_SRC_BSIZE_128 (6UL << 12)
#define DMA_CTRL_SRC_BSIZE_256 (7UL << 12)
/**
* @brief DMA destination burst size.
* @{
*/
#define DMA_CTRL_DST_BSIZE_1 (0 << 15)
#define DMA_CTRL_DST_BSIZE_4 (1UL << 15)
#define DMA_CTRL_DST_BSIZE_8 (2UL << 15)
#define DMA_CTRL_DST_BSIZE_16 (3UL << 15)
#define DMA_CTRL_DST_BSIZE_32 (4UL << 15)
#define DMA_CTRL_DST_BSIZE_64 (5UL << 15)
#define DMA_CTRL_DST_BSIZE_128 (6UL << 15)
#define DMA_CTRL_DST_BSIZE_256 (7UL << 15)
/** @} */
/**
* @name DMA source transfer width.
* @{
*/
#define DMA_CTRL_SRC_WIDTH_BYTE (0 << 18)
#define DMA_CTRL_SRC_WIDTH_HWORD (1UL << 18)
#define DMA_CTRL_SRC_WIDTH_WORD (2UL << 18)
/** @} */
/**
* @name DMA destination transfer width.
* @{
*/
#define DMA_CTRL_DST_WIDTH_BYTE (0 << 21)
#define DMA_CTRL_DST_WIDTH_HWORD (1UL << 21)
#define DMA_CTRL_DST_WIDTH_WORD (2UL << 21)
/**
* @name DMA source increment after each transfer.
* @{
*/
#define DMA_CTRL_SRC_NOINC (0UL << 26)
#define DMA_CTRL_SRC_INC (1UL << 26)
/**
* @name DMA destination increment after each transfer.
* @{
*/
#define DMA_CTRL_DST_NOINC (0UL << 27)
#define DMA_CTRL_DST_INC (1UL << 27)
/**
* @name DMA bus access bits.
* @{
*/
#define DMA_CTRL_PROT1_USER (0 << 28)
#define DMA_CTRL_PROT1_PRIV (1UL << 28)
#define DMA_CTRL_PROT2_NONBUFF (0 << 29)
#define DMA_CTRL_PROT2_BUFF (1UL << 29)
#define DMA_CTRL_PROT3_NONCACHE (0 << 30)
#define DMA_CTRL_PROT3_CACHE (1UL << 30)
/** @} */
/**
* @name DMA terminal count interrupt enable.
* @{
*/
#define DMA_CTRL_INT (1UL << 31)
/** @} */
/**
* @name DMA channel enable.
* @{
*/
#define DMA_CFG_CH_ENABLE (1UL << 0)
/**
* @brief Source peripheral.
*
* @param[in] source source peripheral
*/
#define DMA_CFG_SRC_PERIPH(src) ((src) << 1)
/**
* @brief Destination peripheral.
*
* @param[in] destination destination peripheral
*/
#define DMA_CFG_DST_PERIPH(dst) ((dst) << 6)
/**
* @name Transfer type.
* @{
*/
#define DMA_CFG_TTYPE_M2M (0 << 11)
#define DMA_CFG_TTYPE_M2P (1UL << 11)
#define DMA_CFG_TTYPE_P2M (2UL << 11)
#define DMA_CFG_TTYPE_P2P (3UL << 11)
/** @} */
/**
* @name Interrupt error mask.
* @{
*/
#define DMA_CFG_IE (1UL << 14)
/** @} */
/**
* @name Terminal count interrupt mask.
* @{
*/
#define DMA_CFG_ITC (1UL << 15)
/** @} */
/**
* @name Active.
* @note Read only
* @{
*/
#define DMA_CFG_ACTIVE (1UL << 17)
/** @} */
/**
* @name Halt.
* @{
*/
#define DMA_CFG_HALT (1UL << 18)
/** @} */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief DMA interrupt priority level setting.
*/
#if !defined(LPC17xx_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_DMA_IRQ_PRIORITY 3
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
typedef struct {
volatile uint32_t srcaddr; /**< @brief Source address. */
volatile uint32_t dstaddr; /**< @brief Destination address. */
volatile uint32_t lli; /**< @brief Linked List Item. */
volatile uint32_t control; /**< @brief Control. */
volatile uint32_t config; /**< @brief Configuration. */
} lpc17xx_dma_channel_config_t;
typedef struct {
volatile uint32_t srcaddr; /**< @brief Source address. */
volatile uint32_t dstaddr; /**< @brief Destination address. */
volatile uint32_t lli; /**< @brief Linked List Item. */
volatile uint32_t control; /**< @brief Control. */
} lpc17xx_dma_lli_config_t;
/**
* @brief DMA channel number.
*/
typedef enum {
DMA_CHANNEL0 = 0,
DMA_CHANNEL1 = 1,
DMA_CHANNEL2 = 2,
DMA_CHANNEL3 = 3,
DMA_CHANNEL4 = 4,
DMA_CHANNEL5 = 5,
DMA_CHANNEL6 = 6,
DMA_CHANNEL7 = 7
} lpc17xx_dma_channel_t;
/**
* @brief DMA source or destination type.
*/
typedef enum {
DMA_SSP0_TX = 0,
DMA_SSP0_RX = 1,
DMA_SSP1_TX = 2,
DMA_SSP1_RX = 3,
DMA_ADC = 4,
DMA_I2S_CH0 = 5,
DMA_I2S_CH1 = 6,
DMA_DAC = 7,
DMA_UART0_TX_MAT0_0 = 8,
DMA_UART0_RX_MAT0_1 = 9,
DMA_UART1_TX_MAT1_0 = 10,
DMA_UART1_RX_MAT1_1 = 11,
DMA_UART2_TX_MAT2_0 = 12,
DMA_UART2_RX_MAT2_1 = 13,
DMA_UART3_TX_MAT3_0 = 14,
DMA_UART3_RX_MAT3_1 = 15
} lpc17xx_dma_src_dst_t;
/**
* @brief LPC17xx DMA ISR function type.
*
* @param[in] p parameter for the registered function
* @param[in] flags pre-shifted content of the xISR register, the bits
* are aligned to bit zero
*/
typedef void (*lpc17xx_dmaisr_t)(void *p, uint32_t flags);
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Associates a memory source to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a source address
*
* @special
*/
#define dmaChannelSrcAddr(dmach, addr) \
_lpc17xx_dma_channel_config_t[dmach]->CSrcAddr = (uint32_t)(addr)
/**
* @brief Associates a memory destination to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a destination address
*
* @special
*/
#define dmaChannelDstAddr(dmach, addr) \
_lpc17xx_dma_channel_config_t[dmach]->CDestAddr = (uint32_t)(addr)
/**
* @brief Associates a linked list item address to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a linked list item
*
* @special
*/
#define dmaChannelLinkedList(dmach, addr) \
_lpc17xx_dma_channel_config_t[dmach]->CLLI = ((uint32_t)(addr))
/**
* @brief Set control configuration to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] ctrl control configuration value
*
* @special
*/
#define dmaChannelControl(dmach, ctrl) \
_lpc17xx_dma_channel_config_t[dmach]->CControl = (ctrl)
/**
* @brief Set configuration to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaStreamAllocate().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmach DMA channel number
* @param[in] config dma channel configuration value
*
* @special
*/
#define dmaChannelConfig(dmach, config) \
_lpc17xx_dma_channel_config_t[dmach]->CConfig = (config)
/**
* @brief Trigger DMA software burst transfer request.
*
* @param[in] src peripheral source request
*
* @special
*/
#define dmaSoftBurstRequest(src) \
LPC_GPDMA->SoftBReq = (src)
/**
* @brief Trigger DMA software single transfer request.
*
* @param[in] src peripheral source request
*
* @special
*/
#define dmaSoftSingleRequest(src) \
LPC_GPDMA->SoftSReq = (src)
/**
* @brief DMA channel enable.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
*
* @special
*/
#define dmaChannelEnable(dmach) \
_lpc17xx_dma_channel_config_t[dmach]->CConfig |= (DMA_CFG_CH_ENABLE)
/**
* @brief DMA channel disable.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
*
* @special
*/
#define dmaChannelDisable(dmach) \
_lpc17xx_dma_channel_config_t[dmach]->CConfig &= ~(DMA_CFG_CH_ENABLE)
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
extern LPC_GPDMACH_TypeDef * _lpc17xx_dma_channel_config_t[];
#endif
#ifdef __cplusplus
extern "C" {
#endif
void dmaInit(void);
bool_t dmaChannelAllocate(lpc17xx_dma_channel_t dmach,
lpc17xx_dmaisr_t func,
void *param);
void dmaChannelRelease(lpc17xx_dma_channel_t dmach);
#ifdef __cplusplus
}
#endif
#endif /* _LPC17xx_DMA_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx DMA driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/LPC17xx_dma.h
* @brief DMA driver header.
*
* @addtogroup LPC17xx_DMA
* @{
*/
#ifndef _LPC17xx_DMA_H_
#define _LPC17xx_DMA_H_
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define DMACCONFIG_E (1UL << 0)
#define DMACCONFIG_M (1UL << 1)
/**
* @brief Total number of DMA streams.
* @note This is the total number of streams among all the DMA units.
*/
#define LPC17xx_DMA_CHANNELS 8
/**
* @name DMA control data configuration
* @{
*/
/**
* @brief DMA transfer size.
*
* @param[in] n DMA transfer size
*/
#define DMA_CTRL_TRANSFER_SIZE(n) (n)
/**
* @brief DMA source burst size.
*/
#define DMA_CTRL_SRC_BSIZE_1 (0 << 12)
#define DMA_CTRL_SRC_BSIZE_4 (1UL << 12)
#define DMA_CTRL_SRC_BSIZE_8 (2UL << 12)
#define DMA_CTRL_SRC_BSIZE_16 (3UL << 12)
#define DMA_CTRL_SRC_BSIZE_32 (4UL << 12)
#define DMA_CTRL_SRC_BSIZE_64 (5UL << 12)
#define DMA_CTRL_SRC_BSIZE_128 (6UL << 12)
#define DMA_CTRL_SRC_BSIZE_256 (7UL << 12)
/**
* @brief DMA destination burst size.
* @{
*/
#define DMA_CTRL_DST_BSIZE_1 (0 << 15)
#define DMA_CTRL_DST_BSIZE_4 (1UL << 15)
#define DMA_CTRL_DST_BSIZE_8 (2UL << 15)
#define DMA_CTRL_DST_BSIZE_16 (3UL << 15)
#define DMA_CTRL_DST_BSIZE_32 (4UL << 15)
#define DMA_CTRL_DST_BSIZE_64 (5UL << 15)
#define DMA_CTRL_DST_BSIZE_128 (6UL << 15)
#define DMA_CTRL_DST_BSIZE_256 (7UL << 15)
/** @} */
/**
* @name DMA source transfer width.
* @{
*/
#define DMA_CTRL_SRC_WIDTH_BYTE (0 << 18)
#define DMA_CTRL_SRC_WIDTH_HWORD (1UL << 18)
#define DMA_CTRL_SRC_WIDTH_WORD (2UL << 18)
/** @} */
/**
* @name DMA destination transfer width.
* @{
*/
#define DMA_CTRL_DST_WIDTH_BYTE (0 << 21)
#define DMA_CTRL_DST_WIDTH_HWORD (1UL << 21)
#define DMA_CTRL_DST_WIDTH_WORD (2UL << 21)
/**
* @name DMA source increment after each transfer.
* @{
*/
#define DMA_CTRL_SRC_NOINC (0UL << 26)
#define DMA_CTRL_SRC_INC (1UL << 26)
/**
* @name DMA destination increment after each transfer.
* @{
*/
#define DMA_CTRL_DST_NOINC (0UL << 27)
#define DMA_CTRL_DST_INC (1UL << 27)
/**
* @name DMA bus access bits.
* @{
*/
#define DMA_CTRL_PROT1_USER (0 << 28)
#define DMA_CTRL_PROT1_PRIV (1UL << 28)
#define DMA_CTRL_PROT2_NONBUFF (0 << 29)
#define DMA_CTRL_PROT2_BUFF (1UL << 29)
#define DMA_CTRL_PROT3_NONCACHE (0 << 30)
#define DMA_CTRL_PROT3_CACHE (1UL << 30)
/** @} */
/**
* @name DMA terminal count interrupt enable.
* @{
*/
#define DMA_CTRL_INT (1UL << 31)
/** @} */
/**
* @name DMA channel enable.
* @{
*/
#define DMA_CFG_CH_ENABLE (1UL << 0)
/**
* @brief Source peripheral.
*
* @param[in] source source peripheral
*/
#define DMA_CFG_SRC_PERIPH(src) ((src) << 1)
/**
* @brief Destination peripheral.
*
* @param[in] destination destination peripheral
*/
#define DMA_CFG_DST_PERIPH(dst) ((dst) << 6)
/**
* @name Transfer type.
* @{
*/
#define DMA_CFG_TTYPE_M2M (0 << 11)
#define DMA_CFG_TTYPE_M2P (1UL << 11)
#define DMA_CFG_TTYPE_P2M (2UL << 11)
#define DMA_CFG_TTYPE_P2P (3UL << 11)
/** @} */
/**
* @name Interrupt error mask.
* @{
*/
#define DMA_CFG_IE (1UL << 14)
/** @} */
/**
* @name Terminal count interrupt mask.
* @{
*/
#define DMA_CFG_ITC (1UL << 15)
/** @} */
/**
* @name Active.
* @note Read only
* @{
*/
#define DMA_CFG_ACTIVE (1UL << 17)
/** @} */
/**
* @name Halt.
* @{
*/
#define DMA_CFG_HALT (1UL << 18)
/** @} */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief DMA interrupt priority level setting.
*/
#if !defined(LPC17xx_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_DMA_IRQ_PRIORITY 3
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
typedef struct {
volatile uint32_t srcaddr; /**< @brief Source address. */
volatile uint32_t dstaddr; /**< @brief Destination address. */
volatile uint32_t lli; /**< @brief Linked List Item. */
volatile uint32_t control; /**< @brief Control. */
volatile uint32_t config; /**< @brief Configuration. */
} lpc17xx_dma_channel_config_t;
typedef struct {
volatile uint32_t srcaddr; /**< @brief Source address. */
volatile uint32_t dstaddr; /**< @brief Destination address. */
volatile uint32_t lli; /**< @brief Linked List Item. */
volatile uint32_t control; /**< @brief Control. */
} lpc17xx_dma_lli_config_t;
/**
* @brief DMA channel number.
*/
typedef enum {
DMA_CHANNEL0 = 0,
DMA_CHANNEL1 = 1,
DMA_CHANNEL2 = 2,
DMA_CHANNEL3 = 3,
DMA_CHANNEL4 = 4,
DMA_CHANNEL5 = 5,
DMA_CHANNEL6 = 6,
DMA_CHANNEL7 = 7
} lpc17xx_dma_channel_t;
/**
* @brief DMA source or destination type.
*/
typedef enum {
DMA_SSP0_TX = 0,
DMA_SSP0_RX = 1,
DMA_SSP1_TX = 2,
DMA_SSP1_RX = 3,
DMA_ADC = 4,
DMA_I2S_CH0 = 5,
DMA_I2S_CH1 = 6,
DMA_DAC = 7,
DMA_UART0_TX_MAT0_0 = 8,
DMA_UART0_RX_MAT0_1 = 9,
DMA_UART1_TX_MAT1_0 = 10,
DMA_UART1_RX_MAT1_1 = 11,
DMA_UART2_TX_MAT2_0 = 12,
DMA_UART2_RX_MAT2_1 = 13,
DMA_UART3_TX_MAT3_0 = 14,
DMA_UART3_RX_MAT3_1 = 15
} lpc17xx_dma_src_dst_t;
/**
* @brief LPC17xx DMA ISR function type.
*
* @param[in] p parameter for the registered function
* @param[in] flags pre-shifted content of the xISR register, the bits
* are aligned to bit zero
*/
typedef void (*lpc17xx_dmaisr_t)(void *p, uint32_t flags);
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Associates a memory source to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a source address
*
* @special
*/
#define dmaChannelSrcAddr(dmach, addr) \
_lpc17xx_dma_channel_config_t[dmach]->CSrcAddr = (uint32_t)(addr)
/**
* @brief Associates a memory destination to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a destination address
*
* @special
*/
#define dmaChannelDstAddr(dmach, addr) \
_lpc17xx_dma_channel_config_t[dmach]->CDestAddr = (uint32_t)(addr)
/**
* @brief Associates a linked list item address to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a linked list item
*
* @special
*/
#define dmaChannelLinkedList(dmach, addr) \
_lpc17xx_dma_channel_config_t[dmach]->CLLI = ((uint32_t)(addr))
/**
* @brief Set control configuration to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] ctrl control configuration value
*
* @special
*/
#define dmaChannelControl(dmach, ctrl) \
_lpc17xx_dma_channel_config_t[dmach]->CControl = (ctrl)
/**
* @brief Set configuration to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaStreamAllocate().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmach DMA channel number
* @param[in] config dma channel configuration value
*
* @special
*/
#define dmaChannelConfig(dmach, config) \
_lpc17xx_dma_channel_config_t[dmach]->CConfig = (config)
/**
* @brief Trigger DMA software burst transfer request.
*
* @param[in] src peripheral source request
*
* @special
*/
#define dmaSoftBurstRequest(src) \
LPC_GPDMA->SoftBReq = (src)
/**
* @brief Trigger DMA software single transfer request.
*
* @param[in] src peripheral source request
*
* @special
*/
#define dmaSoftSingleRequest(src) \
LPC_GPDMA->SoftSReq = (src)
/**
* @brief DMA channel enable.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
*
* @special
*/
#define dmaChannelEnable(dmach) \
_lpc17xx_dma_channel_config_t[dmach]->CConfig |= (DMA_CFG_CH_ENABLE)
/**
* @brief DMA channel disable.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
*
* @special
*/
#define dmaChannelDisable(dmach) \
_lpc17xx_dma_channel_config_t[dmach]->CConfig &= ~(DMA_CFG_CH_ENABLE)
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
extern LPC_GPDMACH_TypeDef * _lpc17xx_dma_channel_config_t[];
#endif
#ifdef __cplusplus
extern "C" {
#endif
void dmaInit(void);
bool_t dmaChannelAllocate(lpc17xx_dma_channel_t dmach,
lpc17xx_dmaisr_t func,
void *param);
void dmaChannelRelease(lpc17xx_dma_channel_t dmach);
#ifdef __cplusplus
}
#endif
#endif /* _LPC17xx_DMA_H_ */
/** @} */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,158 +1,158 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/pal_lld.c
* @brief LPC17xx GPIO low level driver code.
*
* @addtogroup PAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief LPC17xx I/O ports configuration.
* @details GPIO unit registers initialization.
*
* @param[in] config the LPC17xx ports configuration
*
* @notapi
*/
void _pal_lld_init(const PALConfig *config) {
LPC_GPIO0->FIODIR = config->P0.dir;
LPC_GPIO1->FIODIR = config->P1.dir;
LPC_GPIO2->FIODIR = config->P2.dir;
LPC_GPIO3->FIODIR = config->P3.dir;
LPC_GPIO4->FIODIR = config->P4.dir;
LPC_GPIO0->FIOMASK = 0;
LPC_GPIO1->FIOMASK = 0;
LPC_GPIO2->FIOMASK = 0;
LPC_GPIO3->FIOMASK = 0;
LPC_GPIO4->FIOMASK = 0;
LPC_GPIO0->FIOPIN = config->P0.data;
LPC_GPIO1->FIOPIN = config->P1.data;
LPC_GPIO2->FIOPIN = config->P2.data;
LPC_GPIO3->FIOPIN = config->P3.data;
LPC_GPIO4->FIOPIN = config->P4.data;
}
/**
* @brief Reads a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @return The group logical states.
*
* @notapi
*/
uint32_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset) {
uint32_t p;
port->FIOMASK = ~((mask) << offset);
p = port->FIOPIN;
port->FIOMASK = 0;
return p;
}
/**
* @brief Writes a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] bits bits to be written. Values exceeding the group width
* are masked.
*
* @notapi
*/
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset,
uint32_t bits) {
port->FIOMASK = ~((mask) << offset);
port->FIOPIN = bits;
port->FIOMASK = 0;
}
/**
* @brief Pads mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with
* high state.
* @note This function does not alter the @p PINSELx registers. Alternate
* functions setup must be handled by device-specific code.
*
* @param[in] port the port identifier
* @param[in] mask the group mask
* @param[in] mode the mode
*
* @notapi
*/
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode) {
switch (mode) {
case PAL_MODE_RESET:
case PAL_MODE_INPUT:
port->FIODIR &= ~mask;
break;
case PAL_MODE_UNCONNECTED:
palSetPort(port, PAL_WHOLE_PORT);
case PAL_MODE_OUTPUT_PUSHPULL:
port->FIODIR |= mask;
break;
}
}
#endif /* HAL_USE_PAL */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/pal_lld.c
* @brief LPC17xx GPIO low level driver code.
*
* @addtogroup PAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief LPC17xx I/O ports configuration.
* @details GPIO unit registers initialization.
*
* @param[in] config the LPC17xx ports configuration
*
* @notapi
*/
void _pal_lld_init(const PALConfig *config) {
LPC_GPIO0->FIODIR = config->P0.dir;
LPC_GPIO1->FIODIR = config->P1.dir;
LPC_GPIO2->FIODIR = config->P2.dir;
LPC_GPIO3->FIODIR = config->P3.dir;
LPC_GPIO4->FIODIR = config->P4.dir;
LPC_GPIO0->FIOMASK = 0;
LPC_GPIO1->FIOMASK = 0;
LPC_GPIO2->FIOMASK = 0;
LPC_GPIO3->FIOMASK = 0;
LPC_GPIO4->FIOMASK = 0;
LPC_GPIO0->FIOPIN = config->P0.data;
LPC_GPIO1->FIOPIN = config->P1.data;
LPC_GPIO2->FIOPIN = config->P2.data;
LPC_GPIO3->FIOPIN = config->P3.data;
LPC_GPIO4->FIOPIN = config->P4.data;
}
/**
* @brief Reads a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @return The group logical states.
*
* @notapi
*/
uint32_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset) {
uint32_t p;
port->FIOMASK = ~((mask) << offset);
p = port->FIOPIN;
port->FIOMASK = 0;
return p;
}
/**
* @brief Writes a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] bits bits to be written. Values exceeding the group width
* are masked.
*
* @notapi
*/
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset,
uint32_t bits) {
port->FIOMASK = ~((mask) << offset);
port->FIOPIN = bits;
port->FIOMASK = 0;
}
/**
* @brief Pads mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with
* high state.
* @note This function does not alter the @p PINSELx registers. Alternate
* functions setup must be handled by device-specific code.
*
* @param[in] port the port identifier
* @param[in] mask the group mask
* @param[in] mode the mode
*
* @notapi
*/
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode) {
switch (mode) {
case PAL_MODE_RESET:
case PAL_MODE_INPUT:
port->FIODIR &= ~mask;
break;
case PAL_MODE_UNCONNECTED:
palSetPort(port, PAL_WHOLE_PORT);
case PAL_MODE_OUTPUT_PUSHPULL:
port->FIODIR |= mask;
break;
}
}
#endif /* HAL_USE_PAL */
/** @} */

View File

@ -1,332 +1,332 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/pal_lld.h
* @brief LPC17xx GPIO low level driver header.
*
* @addtogroup PAL
* @{
*/
#ifndef _PAL_LLD_H_
#define _PAL_LLD_H_
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Unsupported modes and specific modes */
/*===========================================================================*/
#undef PAL_MODE_INPUT_PULLUP
#undef PAL_MODE_INPUT_PULLDOWN
#undef PAL_MODE_INPUT_ANALOG
#undef PAL_MODE_OUTPUT_OPENDRAIN
/*===========================================================================*/
/* I/O Ports Types and constants. */
/*===========================================================================*/
/**
* @brief GPIO port setup info.
*/
typedef struct {
/** Initial value for FIO_PIN register.*/
uint32_t data;
/** Initial value for FIO_DIR register.*/
uint32_t dir;
} lpc17xx_gpio_setup_t;
/**
* @brief GPIO static initializer.
* @details An instance of this structure must be passed to @p palInit() at
* system startup time in order to initialized the digital I/O
* subsystem. This represents only the initial setup, specific pads
* or whole ports can be reprogrammed at later time.
* @note The @p IOCON block is not configured, initially all pins have
* enabled pullups and are programmed as GPIO. It is responsibility
* of the various drivers to reprogram the pins in the proper mode.
* Pins that are not handled by any driver may be programmed in
* @p board.c.
*/
typedef struct {
/** @brief GPIO 0 setup data.*/
lpc17xx_gpio_setup_t P0;
/** @brief GPIO 1 setup data.*/
lpc17xx_gpio_setup_t P1;
/** @brief GPIO 2 setup data.*/
lpc17xx_gpio_setup_t P2;
/** @brief GPIO 3 setup data.*/
lpc17xx_gpio_setup_t P3;
/** @brief GPIO 4 setup data.*/
lpc17xx_gpio_setup_t P4;
} PALConfig;
/**
* @brief Width, in bits, of an I/O port.
*/
#define PAL_IOPORTS_WIDTH 32
/**
* @brief Whole port mask.
* @brief This macro specifies all the valid bits into a port.
*/
#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFFFFF)
/**
* @brief Digital I/O port sized unsigned type.
*/
typedef uint32_t ioportmask_t;
/**
* @brief Digital I/O modes.
*/
typedef uint32_t iomode_t;
/**
* @brief Port Identifier.
*/
typedef LPC_GPIO_TypeDef *ioportid_t;
/*===========================================================================*/
/* I/O Ports Identifiers. */
/*===========================================================================*/
/**
* @brief GPIO0 port identifier.
*/
#define IOPORT1 LPC_GPIO0
#define GPIO0 LPC_GPIO0
/**
* @brief GPIO1 port identifier.
*/
#define IOPORT2 LPC_GPIO1
#define GPIO1 LPC_GPIO1
/**
* @brief GPIO2 port identifier.
*/
#define IOPORT3 LPC_GPIO2
#define GPIO2 LPC_GPIO2
/**
* @brief GPIO3 port identifier.
*/
#define IOPORT4 LPC_GPIO3
#define GPIO3 LPC_GPIO3
/**
* @brief GPIO3 port identifier.
*/
#define IOPORT5 LPC_GPIO4
#define GPIO4 LPC_GPIO4
/*===========================================================================*/
/* Implementation, some of the following macros could be implemented as */
/* functions, if so please put them in pal_lld.c. */
/*===========================================================================*/
/**
* @brief Low level PAL subsystem initialization.
*
* @param[in] config architecture-dependent ports configuration
*
* @notapi
*/
#define pal_lld_init(config) _pal_lld_init(config)
/**
* @brief Reads the physical I/O port states.
*
* @param[in] port port identifier
* @return The port bits.
*
* @notapi
*/
#define pal_lld_readport(port) ((port)->FIOPIN)
/**
* @brief Reads the output latch.
* @details The purpose of this function is to read back the latched output
* value.
*
* @param[in] port port identifier
* @return The latched logical states.
*
* @notapi
*/
#define pal_lld_readlatch(port) ((port)->FIOPIN)
/**
* @brief Writes a bits mask on a I/O port.
*
* @param[in] port port identifier
* @param[in] bits bits to be written on the specified port
*
* @notapi
*/
#define pal_lld_writeport(port, bits) ((port)->FIOPIN = (bits))
/**
* @brief Sets a bits mask on a I/O port.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] bits bits to be ORed on the specified port
*
* @notapi
*/
#define pal_lld_setport(port, bits) ((port)->FIOSET = bits)
/**
* @brief Clears a bits mask on a I/O port.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] bits bits to be cleared on the specified port
*
* @notapi
*/
#define pal_lld_clearport(port, bits) ((port)->FIOCLR = bits)
/**
* @brief Reads a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @return The group logical states.
*
* @notapi
*/
#define pal_lld_readgroup(port, mask, offset) \
_pal_lld_readgroup(port, mask, offset)
/**
* @brief Writes a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] bits bits to be written. Values exceeding the group width
* are masked.
*
* @notapi
*/
#define pal_lld_writegroup(port, mask, offset, bits) \
_pal_lld_writegroup(port, mask, offset, bits)
/**
* @brief Pads group mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
* @note Programming an unknown or unsupported mode is silently ignored.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] mode group mode
*
* @notapi
*/
#define pal_lld_setgroupmode(port, mask, offset, mode) \
_pal_lld_setgroupmode(port, mask << offset, mode)
/**
* @brief Writes a logical state on an output pad.
* @note This function is not meant to be invoked directly by the
* application code.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @param[in] bit logical value, the value must be @p PAL_LOW or
* @p PAL_HIGH
*
* @notapi
*/
#define pal_lld_writepad(port, pad, bit) \
((bit) == PAL_LOW) ? pal_lld_clearpad(port, pad) : \
pal_lld_setpad(port, pad)
/**
* @brief Sets a pad logical state to @p PAL_HIGH.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_setpad(port, pad) \
((port)->FIOSET = 1UL << (pad))
/**
* @brief Clears a pad logical state to @p PAL_LOW.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_clearpad(port, pad) \
((port)->FIOCLR = 1UL << (pad))
#if !defined(__DOXYGEN__)
extern const PALConfig pal_default_config;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void _pal_lld_init(const PALConfig *config);
uint32_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset);
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset,
uint32_t bits);
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PAL */
#endif /* _PAL_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/pal_lld.h
* @brief LPC17xx GPIO low level driver header.
*
* @addtogroup PAL
* @{
*/
#ifndef _PAL_LLD_H_
#define _PAL_LLD_H_
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Unsupported modes and specific modes */
/*===========================================================================*/
#undef PAL_MODE_INPUT_PULLUP
#undef PAL_MODE_INPUT_PULLDOWN
#undef PAL_MODE_INPUT_ANALOG
#undef PAL_MODE_OUTPUT_OPENDRAIN
/*===========================================================================*/
/* I/O Ports Types and constants. */
/*===========================================================================*/
/**
* @brief GPIO port setup info.
*/
typedef struct {
/** Initial value for FIO_PIN register.*/
uint32_t data;
/** Initial value for FIO_DIR register.*/
uint32_t dir;
} lpc17xx_gpio_setup_t;
/**
* @brief GPIO static initializer.
* @details An instance of this structure must be passed to @p palInit() at
* system startup time in order to initialized the digital I/O
* subsystem. This represents only the initial setup, specific pads
* or whole ports can be reprogrammed at later time.
* @note The @p IOCON block is not configured, initially all pins have
* enabled pullups and are programmed as GPIO. It is responsibility
* of the various drivers to reprogram the pins in the proper mode.
* Pins that are not handled by any driver may be programmed in
* @p board.c.
*/
typedef struct {
/** @brief GPIO 0 setup data.*/
lpc17xx_gpio_setup_t P0;
/** @brief GPIO 1 setup data.*/
lpc17xx_gpio_setup_t P1;
/** @brief GPIO 2 setup data.*/
lpc17xx_gpio_setup_t P2;
/** @brief GPIO 3 setup data.*/
lpc17xx_gpio_setup_t P3;
/** @brief GPIO 4 setup data.*/
lpc17xx_gpio_setup_t P4;
} PALConfig;
/**
* @brief Width, in bits, of an I/O port.
*/
#define PAL_IOPORTS_WIDTH 32
/**
* @brief Whole port mask.
* @brief This macro specifies all the valid bits into a port.
*/
#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFFFFF)
/**
* @brief Digital I/O port sized unsigned type.
*/
typedef uint32_t ioportmask_t;
/**
* @brief Digital I/O modes.
*/
typedef uint32_t iomode_t;
/**
* @brief Port Identifier.
*/
typedef LPC_GPIO_TypeDef *ioportid_t;
/*===========================================================================*/
/* I/O Ports Identifiers. */
/*===========================================================================*/
/**
* @brief GPIO0 port identifier.
*/
#define IOPORT1 LPC_GPIO0
#define GPIO0 LPC_GPIO0
/**
* @brief GPIO1 port identifier.
*/
#define IOPORT2 LPC_GPIO1
#define GPIO1 LPC_GPIO1
/**
* @brief GPIO2 port identifier.
*/
#define IOPORT3 LPC_GPIO2
#define GPIO2 LPC_GPIO2
/**
* @brief GPIO3 port identifier.
*/
#define IOPORT4 LPC_GPIO3
#define GPIO3 LPC_GPIO3
/**
* @brief GPIO3 port identifier.
*/
#define IOPORT5 LPC_GPIO4
#define GPIO4 LPC_GPIO4
/*===========================================================================*/
/* Implementation, some of the following macros could be implemented as */
/* functions, if so please put them in pal_lld.c. */
/*===========================================================================*/
/**
* @brief Low level PAL subsystem initialization.
*
* @param[in] config architecture-dependent ports configuration
*
* @notapi
*/
#define pal_lld_init(config) _pal_lld_init(config)
/**
* @brief Reads the physical I/O port states.
*
* @param[in] port port identifier
* @return The port bits.
*
* @notapi
*/
#define pal_lld_readport(port) ((port)->FIOPIN)
/**
* @brief Reads the output latch.
* @details The purpose of this function is to read back the latched output
* value.
*
* @param[in] port port identifier
* @return The latched logical states.
*
* @notapi
*/
#define pal_lld_readlatch(port) ((port)->FIOPIN)
/**
* @brief Writes a bits mask on a I/O port.
*
* @param[in] port port identifier
* @param[in] bits bits to be written on the specified port
*
* @notapi
*/
#define pal_lld_writeport(port, bits) ((port)->FIOPIN = (bits))
/**
* @brief Sets a bits mask on a I/O port.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] bits bits to be ORed on the specified port
*
* @notapi
*/
#define pal_lld_setport(port, bits) ((port)->FIOSET = bits)
/**
* @brief Clears a bits mask on a I/O port.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] bits bits to be cleared on the specified port
*
* @notapi
*/
#define pal_lld_clearport(port, bits) ((port)->FIOCLR = bits)
/**
* @brief Reads a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @return The group logical states.
*
* @notapi
*/
#define pal_lld_readgroup(port, mask, offset) \
_pal_lld_readgroup(port, mask, offset)
/**
* @brief Writes a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] bits bits to be written. Values exceeding the group width
* are masked.
*
* @notapi
*/
#define pal_lld_writegroup(port, mask, offset, bits) \
_pal_lld_writegroup(port, mask, offset, bits)
/**
* @brief Pads group mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
* @note Programming an unknown or unsupported mode is silently ignored.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] mode group mode
*
* @notapi
*/
#define pal_lld_setgroupmode(port, mask, offset, mode) \
_pal_lld_setgroupmode(port, mask << offset, mode)
/**
* @brief Writes a logical state on an output pad.
* @note This function is not meant to be invoked directly by the
* application code.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @param[in] bit logical value, the value must be @p PAL_LOW or
* @p PAL_HIGH
*
* @notapi
*/
#define pal_lld_writepad(port, pad, bit) \
((bit) == PAL_LOW) ? pal_lld_clearpad(port, pad) : \
pal_lld_setpad(port, pad)
/**
* @brief Sets a pad logical state to @p PAL_HIGH.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_setpad(port, pad) \
((port)->FIOSET = 1UL << (pad))
/**
* @brief Clears a pad logical state to @p PAL_LOW.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_clearpad(port, pad) \
((port)->FIOCLR = 1UL << (pad))
#if !defined(__DOXYGEN__)
extern const PALConfig pal_default_config;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void _pal_lld_init(const PALConfig *config);
uint32_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset);
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset,
uint32_t bits);
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PAL */
#endif /* _PAL_LLD_H_ */
/** @} */

View File

@ -1,17 +1,17 @@
# List of all the LPC17xx platform files.
PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/LPC17xx/hal_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/lpc17xx_dma.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/adc_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/gpt_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/pal_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/serial_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/rtc_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/i2c_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/spi_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/dac_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/mac_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/can_lld.c
# Required include directories
PLATFORMINC = ${CHIBIOS}/os/hal/platforms/LPC17xx
# List of all the LPC17xx platform files.
PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/LPC17xx/hal_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/lpc17xx_dma.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/adc_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/gpt_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/pal_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/serial_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/rtc_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/i2c_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/spi_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/dac_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/mac_lld.c \
${CHIBIOS}/os/hal/platforms/LPC17xx/can_lld.c
# Required include directories
PLATFORMINC = ${CHIBIOS}/os/hal/platforms/LPC17xx

View File

@ -1,290 +1,290 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx RTC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file LPC17xx/rtc_lld.c
* @brief LPC17xx RTC low level driver.
*
* @addtogroup RTC
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_RTC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief RTC driver identifier.
*/
RTCDriver RTCD1;
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Enable RTC clock.
*/
#define _rtc_clk_enable() \
LPC_RTC->CCR |= CCR_CLKEN
/**
* @brief Disable RTC clock.
*/
#define _rtc_clk_disable() \
LPC_RTC->CCR &= ~CCR_CLKEN
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief RTC interrupt handler.
*
* @isr
*/
#if LPC17xx_RTC_USE_ALARM || defined(__DOXYGEN__)
CH_IRQ_HANDLER(Vector84) {
uint32_t status;
CH_IRQ_PROLOGUE();
status = LPC_RTC->ILR;
LPC_RTC->ILR = status; /* Clear interrupt flag */
if ((status & ILR_RTCALF) && (RTCD1.callback != NULL))
RTCD1.callback(&RTCD1, RTC_EVENT_ALARM);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Enable access to registers.
*
* @api
*/
void rtc_lld_init(void) {
if(LPC_RTC->RTC_AUX & RTC_AUX_RTC_OSCF) { /* Set after RTC power was first turn. */
LPC_RTC->CCR = CCR_CCALEN; /* Disable calibration and RTC clock. */
LPC_RTC->CALIBRATION = 0;
LPC_RTC->RTC_AUX = RTC_AUX_RTC_OSCF; /* Clear RTC Oscillator Fail detect flag. */
LPC_RTC->CIIR = 0; /* Disable Counter Increment Interrupt. */
LPC_RTC->AMR = AMR_MASK_ALL; /* Mask alarm interrupt. */
LPC_RTC->ILR = ILR_RTCALF | ILR_RTCCIF; /* Clear interrupt flags. */
/* Set date to Saturday 01.01.2000 00:00:00 */
LPC_RTC->SEC = 0;
LPC_RTC->MIN = 0;
LPC_RTC->HOUR = 0;
LPC_RTC->DOM = 1;
LPC_RTC->MONTH = 1;
LPC_RTC->YEAR = 2000;
LPC_RTC->DOW = 6;
LPC_RTC->DOY = 1;
_rtc_clk_enable(); /* Enable RTC clock. */
}
#if LPC17xx_RTC_USE_ALARM
nvicEnableVector(RTC_IRQn, CORTEX_PRIORITY_MASK(LPC17xx_RTC_IRQ_PRIORITY));
#endif
return;
}
/**
* @brief Set current time.
* @note Fractional part will be silently ignored. There is no possibility
* to set it on STM32 platform.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[in] timespec pointer to a @p RTCTime structure
*
* @api
*/
void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec) {
(void)rtcp;
_rtc_clk_disable(); /* Disable RTC clock. */
LPC_RTC->SEC = timespec->sec;
LPC_RTC->MIN = timespec->min;
LPC_RTC->HOUR = timespec->hour;
LPC_RTC->DOM = timespec->dom;
LPC_RTC->MONTH = timespec->month;
LPC_RTC->YEAR = timespec->year;
LPC_RTC->DOW = timespec->dow;
LPC_RTC->DOY = timespec->doy;
_rtc_clk_enable(); /* Enable RTC clock. */
}
/**
* @brief Get current time.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[out] timespec pointer to a @p RTCTime structure
*
* @api
*/
void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec) {
(void)rtcp;
timespec->sec = LPC_RTC->SEC;
timespec->min = LPC_RTC->MIN;
timespec->hour = LPC_RTC->HOUR;
timespec->dom = LPC_RTC->DOM;
timespec->month = LPC_RTC->MONTH;
timespec->year = LPC_RTC->YEAR;
timespec->dow = LPC_RTC->DOW;
timespec->doy = LPC_RTC->DOY;
}
/**
* @brief Set alarm time.
*
* @note Default value after BKP domain reset for both comparators is 0.
* @note Function does not performs any checks of alarm time validity.
*
* @param[in] rtcp Pointer to RTC driver structure.
* @param[in] alarm Alarm identifier. Can be 1 or 2.
* @param[in] alarmspec Pointer to a @p RTCAlarm structure.
*
* @api
*/
void rtc_lld_set_alarm(RTCDriver *rtcp,
rtcalarm_t alarm,
const RTCAlarm *alarmspec) {
(void)rtcp;
(void)alarm;
LPC_RTC->ALSEC = alarmspec->alsec;
LPC_RTC->ALMIN = alarmspec->almin;
LPC_RTC->ALHOUR = alarmspec->alhour;
LPC_RTC->ALDOM = alarmspec->aldom;
LPC_RTC->ALMON = alarmspec->almonth;
LPC_RTC->ALYEAR = alarmspec->alyear;
LPC_RTC->ALDOW = alarmspec->aldow;
LPC_RTC->ALDOY = alarmspec->aldoy;
}
/**
* @brief Get alarm time.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[in] alarm alarm identifier
* @param[out] alarmspec pointer to a @p RTCAlarm structure
*
* @api
*/
void rtc_lld_get_alarm(RTCDriver *rtcp,
rtcalarm_t alarm,
RTCAlarm *alarmspec) {
(void)rtcp;
(void)alarm;
alarmspec->alsec = LPC_RTC->ALSEC;
alarmspec->almin = LPC_RTC->ALMIN;
alarmspec->alhour = LPC_RTC->ALHOUR;
alarmspec->aldom = LPC_RTC->ALDOM;
alarmspec->almonth = LPC_RTC->ALMON;
alarmspec->alyear = LPC_RTC->ALYEAR;
alarmspec->aldow = LPC_RTC->ALDOW;
alarmspec->aldoy = LPC_RTC->ALDOY;
}
/**
* @brief Enables or disables RTC callbacks.
* @details This function enables or disables callbacks, use a @p NULL pointer
* in order to disable a callback.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[in] callback callback function pointer or @p NULL
*
* @notapi
*/
void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) {
LPC_RTC->AMR = AMR_MASK_ALL; /* Mask alarm interrupt. */
LPC_RTC->ILR = ILR_RTCALF; /* Clear interrupt flag. */
if (callback != NULL) {
/* IRQ sources enabled only after setting up the callback.*/
rtcp->callback = callback;
LPC_RTC->AMR = 0; /* Enable alarm interrupt. */
}
else {
/* Callback set to NULL only after disabling the IRQ sources.*/
rtcp->callback = NULL;
}
}
#include "chrtclib.h"
/**
* @brief Get current time in format suitable for usage in FatFS.
*
* @param[in] rtcp pointer to RTC driver structure
* @return FAT time value.
*
* @api
*/
uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp) {
uint32_t fattime;
struct tm timp;
rtcGetTimeTm(rtcp, &timp);
fattime = (timp.tm_sec) >> 1;
fattime |= (timp.tm_min) << 5;
fattime |= (timp.tm_hour) << 11;
fattime |= (timp.tm_mday) << 16;
fattime |= (timp.tm_mon + 1) << 21;
fattime |= (timp.tm_year - 80) << 25;
return fattime;
}
#endif /* HAL_USE_RTC */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx RTC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file LPC17xx/rtc_lld.c
* @brief LPC17xx RTC low level driver.
*
* @addtogroup RTC
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_RTC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief RTC driver identifier.
*/
RTCDriver RTCD1;
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Enable RTC clock.
*/
#define _rtc_clk_enable() \
LPC_RTC->CCR |= CCR_CLKEN
/**
* @brief Disable RTC clock.
*/
#define _rtc_clk_disable() \
LPC_RTC->CCR &= ~CCR_CLKEN
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief RTC interrupt handler.
*
* @isr
*/
#if LPC17xx_RTC_USE_ALARM || defined(__DOXYGEN__)
CH_IRQ_HANDLER(Vector84) {
uint32_t status;
CH_IRQ_PROLOGUE();
status = LPC_RTC->ILR;
LPC_RTC->ILR = status; /* Clear interrupt flag */
if ((status & ILR_RTCALF) && (RTCD1.callback != NULL))
RTCD1.callback(&RTCD1, RTC_EVENT_ALARM);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Enable access to registers.
*
* @api
*/
void rtc_lld_init(void) {
if(LPC_RTC->RTC_AUX & RTC_AUX_RTC_OSCF) { /* Set after RTC power was first turn. */
LPC_RTC->CCR = CCR_CCALEN; /* Disable calibration and RTC clock. */
LPC_RTC->CALIBRATION = 0;
LPC_RTC->RTC_AUX = RTC_AUX_RTC_OSCF; /* Clear RTC Oscillator Fail detect flag. */
LPC_RTC->CIIR = 0; /* Disable Counter Increment Interrupt. */
LPC_RTC->AMR = AMR_MASK_ALL; /* Mask alarm interrupt. */
LPC_RTC->ILR = ILR_RTCALF | ILR_RTCCIF; /* Clear interrupt flags. */
/* Set date to Saturday 01.01.2000 00:00:00 */
LPC_RTC->SEC = 0;
LPC_RTC->MIN = 0;
LPC_RTC->HOUR = 0;
LPC_RTC->DOM = 1;
LPC_RTC->MONTH = 1;
LPC_RTC->YEAR = 2000;
LPC_RTC->DOW = 6;
LPC_RTC->DOY = 1;
_rtc_clk_enable(); /* Enable RTC clock. */
}
#if LPC17xx_RTC_USE_ALARM
nvicEnableVector(RTC_IRQn, CORTEX_PRIORITY_MASK(LPC17xx_RTC_IRQ_PRIORITY));
#endif
return;
}
/**
* @brief Set current time.
* @note Fractional part will be silently ignored. There is no possibility
* to set it on STM32 platform.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[in] timespec pointer to a @p RTCTime structure
*
* @api
*/
void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec) {
(void)rtcp;
_rtc_clk_disable(); /* Disable RTC clock. */
LPC_RTC->SEC = timespec->sec;
LPC_RTC->MIN = timespec->min;
LPC_RTC->HOUR = timespec->hour;
LPC_RTC->DOM = timespec->dom;
LPC_RTC->MONTH = timespec->month;
LPC_RTC->YEAR = timespec->year;
LPC_RTC->DOW = timespec->dow;
LPC_RTC->DOY = timespec->doy;
_rtc_clk_enable(); /* Enable RTC clock. */
}
/**
* @brief Get current time.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[out] timespec pointer to a @p RTCTime structure
*
* @api
*/
void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec) {
(void)rtcp;
timespec->sec = LPC_RTC->SEC;
timespec->min = LPC_RTC->MIN;
timespec->hour = LPC_RTC->HOUR;
timespec->dom = LPC_RTC->DOM;
timespec->month = LPC_RTC->MONTH;
timespec->year = LPC_RTC->YEAR;
timespec->dow = LPC_RTC->DOW;
timespec->doy = LPC_RTC->DOY;
}
/**
* @brief Set alarm time.
*
* @note Default value after BKP domain reset for both comparators is 0.
* @note Function does not performs any checks of alarm time validity.
*
* @param[in] rtcp Pointer to RTC driver structure.
* @param[in] alarm Alarm identifier. Can be 1 or 2.
* @param[in] alarmspec Pointer to a @p RTCAlarm structure.
*
* @api
*/
void rtc_lld_set_alarm(RTCDriver *rtcp,
rtcalarm_t alarm,
const RTCAlarm *alarmspec) {
(void)rtcp;
(void)alarm;
LPC_RTC->ALSEC = alarmspec->alsec;
LPC_RTC->ALMIN = alarmspec->almin;
LPC_RTC->ALHOUR = alarmspec->alhour;
LPC_RTC->ALDOM = alarmspec->aldom;
LPC_RTC->ALMON = alarmspec->almonth;
LPC_RTC->ALYEAR = alarmspec->alyear;
LPC_RTC->ALDOW = alarmspec->aldow;
LPC_RTC->ALDOY = alarmspec->aldoy;
}
/**
* @brief Get alarm time.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[in] alarm alarm identifier
* @param[out] alarmspec pointer to a @p RTCAlarm structure
*
* @api
*/
void rtc_lld_get_alarm(RTCDriver *rtcp,
rtcalarm_t alarm,
RTCAlarm *alarmspec) {
(void)rtcp;
(void)alarm;
alarmspec->alsec = LPC_RTC->ALSEC;
alarmspec->almin = LPC_RTC->ALMIN;
alarmspec->alhour = LPC_RTC->ALHOUR;
alarmspec->aldom = LPC_RTC->ALDOM;
alarmspec->almonth = LPC_RTC->ALMON;
alarmspec->alyear = LPC_RTC->ALYEAR;
alarmspec->aldow = LPC_RTC->ALDOW;
alarmspec->aldoy = LPC_RTC->ALDOY;
}
/**
* @brief Enables or disables RTC callbacks.
* @details This function enables or disables callbacks, use a @p NULL pointer
* in order to disable a callback.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[in] callback callback function pointer or @p NULL
*
* @notapi
*/
void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) {
LPC_RTC->AMR = AMR_MASK_ALL; /* Mask alarm interrupt. */
LPC_RTC->ILR = ILR_RTCALF; /* Clear interrupt flag. */
if (callback != NULL) {
/* IRQ sources enabled only after setting up the callback.*/
rtcp->callback = callback;
LPC_RTC->AMR = 0; /* Enable alarm interrupt. */
}
else {
/* Callback set to NULL only after disabling the IRQ sources.*/
rtcp->callback = NULL;
}
}
#include "chrtclib.h"
/**
* @brief Get current time in format suitable for usage in FatFS.
*
* @param[in] rtcp pointer to RTC driver structure
* @return FAT time value.
*
* @api
*/
uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp) {
uint32_t fattime;
struct tm timp;
rtcGetTimeTm(rtcp, &timp);
fattime = (timp.tm_sec) >> 1;
fattime |= (timp.tm_min) << 5;
fattime |= (timp.tm_hour) << 11;
fattime |= (timp.tm_mday) << 16;
fattime |= (timp.tm_mon + 1) << 21;
fattime |= (timp.tm_year - 80) << 25;
return fattime;
}
#endif /* HAL_USE_RTC */
/** @} */

View File

@ -1,279 +1,279 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx RTC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file LPC17xx/rtc_lld.h
* @brief LPC17xx RTC low level driver header.
*
* @addtogroup RTC
* @{
*/
#ifndef _RTC_LLD_H_
#define _RTC_LLD_H_
#if HAL_USE_RTC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define ILR_RTCCIF 0x01
#define ILR_RTCALF 0x02
#define CCR_CLKEN 0x01
#define CCR_CTCRST 0x02
#define CCR_CCALEN 0x10
#define CIIR_IMSEC 0x01
#define CIIR_IMMIN 0x02
#define CIIR_IMHOUR 0x04
#define CIIR_IMDOM 0x08
#define CIIR_IMDOW 0x10
#define CIIR_IMDOY 0x20
#define CIIR_IMMON 0x40
#define CIIR_IMYEAR 0x80
#define AMR_AMRSEC 0x01
#define AMR_AMRMIN 0x02
#define AMR_AMRHOUR 0x04
#define AMR_AMRDOM 0x08
#define AMR_AMRDOW 0x10
#define AMR_AMRDOY 0x20
#define AMR_AMRMON 0x40
#define AMR_AMRYEAR 0x80
#define AMR_MASK_ALL 0xFF
#define RTC_AUX_RTC_OSCF 0x10
#define RTC_AUXEN_RTC_OSCFEN 0x10
/**
* @brief This RTC implementation supports callbacks.
*/
#define RTC_SUPPORTS_CALLBACKS TRUE
/**
* @brief One alarm comparator available.
*/
#define RTC_ALARMS 1
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/*
* RTC driver system settings.
*/
/**
* @brief RTC Alarm enable.
*/
#if !defined(LPC17xx_RTC_USE_ALARM) || defined(__DOXYGEN__)
#define LPC17xx_RTC_USE_ALARM FALSE
#endif
/**
* @brief RTC IRQ Priority.
*/
#if !defined(LPC17xx_RTC_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_RTC_IRQ_PRIORITY 3
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an RTC alarm time stamp.
*/
typedef struct RTCAlarm RTCAlarm;
/**
* @brief Type of a structure representing an RTC wakeup period.
*/
typedef struct RTCWakeup RTCWakeup;
/**
* @brief Type of a structure representing an RTC callbacks config.
*/
typedef struct RTCCallbackConfig RTCCallbackConfig;
/**
* @brief Type of an RTC alarm.
* @details Meaningful on platforms with more than 1 alarm comparator.
*/
typedef uint32_t rtcalarm_t;
/**
* @brief Type of an RTC event.
*/
typedef enum {
RTC_EVENT_ALARM = 0 /** Triggered on alarm. */
} rtcevent_t;
/**
* @brief Type of a generic RTC callback.
*/
typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event);
/**
* @brief Structure representing an RTC callbacks config.
*/
struct RTCCallbackConfig{
/**
* @brief Generic RTC callback pointer.
*/
rtccb_t callback;
};
/**
* @brief Structure representing an RTC time stamp.
*/
struct RTCTime {
/**
* @brief RTC seconds register.
*/
uint8_t sec;
/**
* @brief RTC minutes register.
*/
uint8_t min;
/**
* @brief RTC hours register.
*/
uint8_t hour;
/**
* @brief RTC day of month register.
*/
uint8_t dom;
/**
* @brief RTC month register.
*/
uint8_t month;
/**
* @brief RTC day of week register.
*/
uint8_t dow;
/**
* @brief RTC year register.
*/
uint16_t year;
/**
* @brief RTC day of year register.
*/
uint16_t doy;
};
/**
* @brief Structure representing an RTC alarm time stamp.
*/
struct RTCAlarm {
/**
* @brief RTC alarm seconds register.
*/
uint8_t alsec;
/**
* @brief RTC alarm minutes register.
*/
uint8_t almin;
/**
* @brief RTC alarm hours register.
*/
uint8_t alhour;
/**
* @brief RTC alarm day of month register.
*/
uint8_t aldom;
/**
* @brief RTC alarm month register.
*/
uint8_t almonth;
/**
* @brief RTC alarm day of week register.
*/
uint8_t aldow;
/**
* @brief RTC alarm year register.
*/
uint16_t alyear;
/**
* @brief RTC alarm day of year register.
*/
uint16_t aldoy;
};
/**
* @brief Structure representing an RTC driver.
*/
struct RTCDriver{
/**
* @brief Callback pointer.
*/
rtccb_t callback;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
extern RTCDriver RTCD1;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void rtc_lld_init(void);
void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec);
void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec);
void rtc_lld_set_alarm(RTCDriver *rtcp,
rtcalarm_t alarm,
const RTCAlarm *alarmspec);
void rtc_lld_get_alarm(RTCDriver *rtcp,
rtcalarm_t alarm,
RTCAlarm *alarmspec);
void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback);
uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_RTC */
#endif /* _RTC_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC17xx RTC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file LPC17xx/rtc_lld.h
* @brief LPC17xx RTC low level driver header.
*
* @addtogroup RTC
* @{
*/
#ifndef _RTC_LLD_H_
#define _RTC_LLD_H_
#if HAL_USE_RTC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define ILR_RTCCIF 0x01
#define ILR_RTCALF 0x02
#define CCR_CLKEN 0x01
#define CCR_CTCRST 0x02
#define CCR_CCALEN 0x10
#define CIIR_IMSEC 0x01
#define CIIR_IMMIN 0x02
#define CIIR_IMHOUR 0x04
#define CIIR_IMDOM 0x08
#define CIIR_IMDOW 0x10
#define CIIR_IMDOY 0x20
#define CIIR_IMMON 0x40
#define CIIR_IMYEAR 0x80
#define AMR_AMRSEC 0x01
#define AMR_AMRMIN 0x02
#define AMR_AMRHOUR 0x04
#define AMR_AMRDOM 0x08
#define AMR_AMRDOW 0x10
#define AMR_AMRDOY 0x20
#define AMR_AMRMON 0x40
#define AMR_AMRYEAR 0x80
#define AMR_MASK_ALL 0xFF
#define RTC_AUX_RTC_OSCF 0x10
#define RTC_AUXEN_RTC_OSCFEN 0x10
/**
* @brief This RTC implementation supports callbacks.
*/
#define RTC_SUPPORTS_CALLBACKS TRUE
/**
* @brief One alarm comparator available.
*/
#define RTC_ALARMS 1
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/*
* RTC driver system settings.
*/
/**
* @brief RTC Alarm enable.
*/
#if !defined(LPC17xx_RTC_USE_ALARM) || defined(__DOXYGEN__)
#define LPC17xx_RTC_USE_ALARM FALSE
#endif
/**
* @brief RTC IRQ Priority.
*/
#if !defined(LPC17xx_RTC_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_RTC_IRQ_PRIORITY 3
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an RTC alarm time stamp.
*/
typedef struct RTCAlarm RTCAlarm;
/**
* @brief Type of a structure representing an RTC wakeup period.
*/
typedef struct RTCWakeup RTCWakeup;
/**
* @brief Type of a structure representing an RTC callbacks config.
*/
typedef struct RTCCallbackConfig RTCCallbackConfig;
/**
* @brief Type of an RTC alarm.
* @details Meaningful on platforms with more than 1 alarm comparator.
*/
typedef uint32_t rtcalarm_t;
/**
* @brief Type of an RTC event.
*/
typedef enum {
RTC_EVENT_ALARM = 0 /** Triggered on alarm. */
} rtcevent_t;
/**
* @brief Type of a generic RTC callback.
*/
typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event);
/**
* @brief Structure representing an RTC callbacks config.
*/
struct RTCCallbackConfig{
/**
* @brief Generic RTC callback pointer.
*/
rtccb_t callback;
};
/**
* @brief Structure representing an RTC time stamp.
*/
struct RTCTime {
/**
* @brief RTC seconds register.
*/
uint8_t sec;
/**
* @brief RTC minutes register.
*/
uint8_t min;
/**
* @brief RTC hours register.
*/
uint8_t hour;
/**
* @brief RTC day of month register.
*/
uint8_t dom;
/**
* @brief RTC month register.
*/
uint8_t month;
/**
* @brief RTC day of week register.
*/
uint8_t dow;
/**
* @brief RTC year register.
*/
uint16_t year;
/**
* @brief RTC day of year register.
*/
uint16_t doy;
};
/**
* @brief Structure representing an RTC alarm time stamp.
*/
struct RTCAlarm {
/**
* @brief RTC alarm seconds register.
*/
uint8_t alsec;
/**
* @brief RTC alarm minutes register.
*/
uint8_t almin;
/**
* @brief RTC alarm hours register.
*/
uint8_t alhour;
/**
* @brief RTC alarm day of month register.
*/
uint8_t aldom;
/**
* @brief RTC alarm month register.
*/
uint8_t almonth;
/**
* @brief RTC alarm day of week register.
*/
uint8_t aldow;
/**
* @brief RTC alarm year register.
*/
uint16_t alyear;
/**
* @brief RTC alarm day of year register.
*/
uint16_t aldoy;
};
/**
* @brief Structure representing an RTC driver.
*/
struct RTCDriver{
/**
* @brief Callback pointer.
*/
rtccb_t callback;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
extern RTCDriver RTCD1;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void rtc_lld_init(void);
void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec);
void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec);
void rtc_lld_set_alarm(RTCDriver *rtcp,
rtcalarm_t alarm,
const RTCAlarm *alarmspec);
void rtc_lld_get_alarm(RTCDriver *rtcp,
rtcalarm_t alarm,
RTCAlarm *alarmspec);
void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback);
uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_RTC */
#endif /* _RTC_LLD_H_ */
/** @} */

View File

@ -1,476 +1,476 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/serial_lld.c
* @brief LPC17xx low level serial driver code.
*
* @addtogroup SERIAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
#if LPC17xx_SERIAL_USE_UART0 || defined(__DOXYGEN__)
/** @brief UART0 serial driver identifier.*/
SerialDriver SD1;
#endif
#if LPC17xx_SERIAL_USE_UART1 || defined(__DOXYGEN__)
/** @brief UART1 serial driver identifier.*/
SerialDriver SD2;
#endif
#if LPC17xx_SERIAL_USE_UART2 || defined(__DOXYGEN__)
/** @brief UART2 serial driver identifier.*/
SerialDriver SD3;
#endif
#if LPC17xx_SERIAL_USE_UART3 || defined(__DOXYGEN__)
/** @brief UART3 serial driver identifier.*/
SerialDriver SD4;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/** @brief Driver default configuration.*/
static const SerialConfig default_config = {
SERIAL_DEFAULT_BITRATE,
LCR_WL8 | LCR_STOP1 | LCR_NOPARITY,
FCR_TRIGGER0
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief UART initialization.
*
* @param[in] sdp communication channel associated to the UART
* @param[in] config the architecture-dependent serial driver configuration
*/
static void uart_init(SerialDriver *sdp, const SerialConfig *config) {
LPC_UART_TypeDef *u = sdp->uart;
uint32_t div = 0;
#if LPC17xx_SERIAL_USE_UART0
if (&SD1 == sdp) {
div = LPC17xx_SERIAL_UART0_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC17xx_SERIAL_USE_UART1
if (&SD2 == sdp) {
div = LPC17xx_SERIAL_UART1_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC17xx_SERIAL_USE_UART2
if (&SD3 == sdp) {
div = LPC17xx_SERIAL_UART2_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC17xx_SERIAL_USE_UART3
if (&SD4 == sdp) {
div = LPC17xx_SERIAL_UART3_PCLK / (config->sc_speed << 4);
}
#endif
u->LCR = config->sc_lcr | LCR_DLAB;
u->DLL = div;
u->DLM = div >> 8;
u->LCR = config->sc_lcr;
u->FCR = FCR_ENABLE | FCR_RXRESET | FCR_TXRESET | config->sc_fcr;
u->ACR = 0;
u->FDR = 0x10;
u->TER = TER_ENABLE;
u->IER = IER_RBR | IER_STATUS;
}
/**
* @brief UART de-initialization.
*
* @param[in] u pointer to an UART I/O block
*/
static void uart_deinit(LPC_UART_TypeDef *u) {
u->LCR = LCR_DLAB;
u->DLL = 1;
u->DLM = 0;
u->LCR = 0;
u->FDR = 0x10;
u->IER = 0;
u->FCR = FCR_RXRESET | FCR_TXRESET;
u->ACR = 0;
u->TER = TER_ENABLE;
}
/**
* @brief Error handling routine.
*
* @param[in] sdp communication channel associated to the UART
* @param[in] err UART LSR register value
*/
static void set_error(SerialDriver *sdp, IOREG32 err) {
flagsmask_t sts = 0;
if (err & LSR_OVERRUN)
sts |= SD_OVERRUN_ERROR;
if (err & LSR_PARITY)
sts |= SD_PARITY_ERROR;
if (err & LSR_FRAMING)
sts |= SD_FRAMING_ERROR;
if (err & LSR_BREAK)
sts |= SD_BREAK_DETECTED;
chSysLockFromIsr();
chnAddFlagsI(sdp, sts);
chSysUnlockFromIsr();
}
/**
* @brief Common IRQ handler.
* @note Tries hard to clear all the pending interrupt sources, we don't
* want to go through the whole ISR and have another interrupt soon
* after.
*
* @param[in] u pointer to an UART I/O block
* @param[in] sdp communication channel associated to the UART
*/
static void serve_interrupt(SerialDriver *sdp) {
LPC_UART_TypeDef *u = sdp->uart;
while (TRUE) {
switch (u->IIR & IIR_SRC_MASK) {
case IIR_SRC_NONE:
return;
case IIR_SRC_ERROR:
set_error(sdp, u->LSR);
break;
case IIR_SRC_TIMEOUT:
case IIR_SRC_RX:
chSysLockFromIsr();
if (chIQIsEmptyI(&sdp->iqueue))
chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE);
chSysUnlockFromIsr();
while (u->LSR & LSR_RBR_FULL) {
chSysLockFromIsr();
if (chIQPutI(&sdp->iqueue, u->RBR) < Q_OK)
chnAddFlagsI(sdp, SD_OVERRUN_ERROR);
chSysUnlockFromIsr();
}
break;
case IIR_SRC_TX:
{
int i = LPC17xx_SERIAL_FIFO_PRELOAD;
do {
msg_t b;
chSysLockFromIsr();
b = chOQGetI(&sdp->oqueue);
chSysUnlockFromIsr();
if (b < Q_OK) {
u->IER &= ~IER_THRE;
chSysLockFromIsr();
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
chSysUnlockFromIsr();
break;
}
u->THR = b;
} while (--i);
}
break;
default:
(void) u->THR;
(void) u->RBR;
}
}
}
/**
* @brief Attempts a TX FIFO preload.
*/
static void preload(SerialDriver *sdp) {
LPC_UART_TypeDef *u = sdp->uart;
if (u->LSR & LSR_THRE) {
int i = LPC17xx_SERIAL_FIFO_PRELOAD;
do {
msg_t b = chOQGetI(&sdp->oqueue);
if (b < Q_OK) {
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
return;
}
u->THR = b;
} while (--i);
}
u->IER |= IER_THRE;
}
/**
* @brief Driver SD1 output notification.
*/
#if LPC17xx_SERIAL_USE_UART0 || defined(__DOXYGEN__)
static void notify1(GenericQueue *qp) {
(void)qp;
preload(&SD1);
}
#endif
/**
* @brief Driver SD2 output notification.
*/
#if LPC17xx_SERIAL_USE_UART1 || defined(__DOXYGEN__)
static void notify2(GenericQueue *qp) {
(void)qp;
preload(&SD2);
}
#endif
/**
* @brief Driver SD3 output notification.
*/
#if LPC17xx_SERIAL_USE_UART2 || defined(__DOXYGEN__)
static void notify3(GenericQueue *qp) {
(void)qp;
preload(&SD3);
}
#endif
/**
* @brief Driver SD4 output notification.
*/
#if LPC17xx_SERIAL_USE_UART3 || defined(__DOXYGEN__)
static void notify4(GenericQueue *qp) {
(void)qp;
preload(&SD4);
}
#endif
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief UART0 IRQ handler.
*
* @isr
*/
#if LPC17xx_SERIAL_USE_UART0 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(Vector54) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD1);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART1 IRQ handler.
*
* @isr
*/
#if LPC17xx_SERIAL_USE_UART1 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(Vector58) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD2);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART2 IRQ handler.
*
* @isr
*/
#if LPC17xx_SERIAL_USE_UART2 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(Vector5C) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD3);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART3 IRQ handler.
*
* @isr
*/
#if LPC17xx_SERIAL_USE_UART3 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(Vector60) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD4);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level serial driver initialization.
*
* @notapi
*/
void sd_lld_init(void) {
#if LPC17xx_SERIAL_USE_UART0
sdObjectInit(&SD1, NULL, notify1);
SD1.uart = (LPC_UART_TypeDef*) LPC_UART0;
#endif
#if LPC17xx_SERIAL_USE_UART1
sdObjectInit(&SD2, NULL, notify2);
SD2.uart = (LPC_UART_TypeDef*) LPC_UART1;
#endif
#if LPC17xx_SERIAL_USE_UART2
sdObjectInit(&SD3, NULL, notify3);
SD3.uart = (LPC_UART_TypeDef*) LPC_UART2;
#endif
#if LPC17xx_SERIAL_USE_UART3
sdObjectInit(&SD4, NULL, notify4);
SD4.uart = (LPC_UART_TypeDef*) LPC_UART3;
#endif
}
/**
* @brief Low level serial driver configuration and (re)start.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] config the architecture-dependent serial driver configuration.
* If this parameter is set to @p NULL then a default
* configuration is used.
*
* @notapi
*/
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
if (config == NULL)
config = &default_config;
if (sdp->state == SD_STOP) {
#if LPC17xx_SERIAL_USE_UART0
if (&SD1 == sdp) {
LPC_SC->PCONP |= (1 << 3);
nvicEnableVector(UART0_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART0_IRQ_PRIORITY));
}
#endif
#if LPC17xx_SERIAL_USE_UART1
if (&SD2 == sdp) {
LPC_SC->PCONP |= (1 << 4);
nvicEnableVector(UART1_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART1_IRQ_PRIORITY));
}
#endif
#if LPC17xx_SERIAL_USE_UART2
if (&SD3 == sdp) {
LPC_SC->PCONP |= (1 << 24);
nvicEnableVector(UART2_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART2_IRQ_PRIORITY));
}
#endif
#if LPC17xx_SERIAL_USE_UART3
if (&SD4 == sdp) {
LPC_SC->PCONP |= (1 << 25);
nvicEnableVector(UART3_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART3_IRQ_PRIORITY));
}
#endif
}
uart_init(sdp, config);
}
/**
* @brief Low level serial driver stop.
* @details De-initializes the UART, stops the associated clock, resets the
* interrupt vector.
*
* @param[in] sdp pointer to a @p SerialDriver object
*
* @notapi
*/
void sd_lld_stop(SerialDriver *sdp) {
if (sdp->state == SD_READY) {
uart_deinit(sdp->uart);
#if LPC17xx_SERIAL_USE_UART0
if (&SD1 == sdp) {
LPC_SC->PCONP &= ~(1 << 3);
nvicDisableVector(UART0_IRQn);
return;
}
#endif
#if LPC17xx_SERIAL_USE_UART1
if (&SD2 == sdp) {
LPC_SC->PCONP &= ~(1 << 4);
nvicDisableVector(UART1_IRQn);
return;
}
#endif
#if LPC17xx_SERIAL_USE_UART2
if (&SD3 == sdp) {
LPC_SC->PCONP &= ~(1 << 24);
nvicDisableVector(UART2_IRQn);
return;
}
#endif
#if LPC17xx_SERIAL_USE_UART3
if (&SD4 == sdp) {
LPC_SC->PCONP &= ~(1 << 25);
nvicDisableVector(UART3_IRQn);
return;
}
#endif
}
}
#endif /* HAL_USE_SERIAL */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/serial_lld.c
* @brief LPC17xx low level serial driver code.
*
* @addtogroup SERIAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
#if LPC17xx_SERIAL_USE_UART0 || defined(__DOXYGEN__)
/** @brief UART0 serial driver identifier.*/
SerialDriver SD1;
#endif
#if LPC17xx_SERIAL_USE_UART1 || defined(__DOXYGEN__)
/** @brief UART1 serial driver identifier.*/
SerialDriver SD2;
#endif
#if LPC17xx_SERIAL_USE_UART2 || defined(__DOXYGEN__)
/** @brief UART2 serial driver identifier.*/
SerialDriver SD3;
#endif
#if LPC17xx_SERIAL_USE_UART3 || defined(__DOXYGEN__)
/** @brief UART3 serial driver identifier.*/
SerialDriver SD4;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/** @brief Driver default configuration.*/
static const SerialConfig default_config = {
SERIAL_DEFAULT_BITRATE,
LCR_WL8 | LCR_STOP1 | LCR_NOPARITY,
FCR_TRIGGER0
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief UART initialization.
*
* @param[in] sdp communication channel associated to the UART
* @param[in] config the architecture-dependent serial driver configuration
*/
static void uart_init(SerialDriver *sdp, const SerialConfig *config) {
LPC_UART_TypeDef *u = sdp->uart;
uint32_t div = 0;
#if LPC17xx_SERIAL_USE_UART0
if (&SD1 == sdp) {
div = LPC17xx_SERIAL_UART0_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC17xx_SERIAL_USE_UART1
if (&SD2 == sdp) {
div = LPC17xx_SERIAL_UART1_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC17xx_SERIAL_USE_UART2
if (&SD3 == sdp) {
div = LPC17xx_SERIAL_UART2_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC17xx_SERIAL_USE_UART3
if (&SD4 == sdp) {
div = LPC17xx_SERIAL_UART3_PCLK / (config->sc_speed << 4);
}
#endif
u->LCR = config->sc_lcr | LCR_DLAB;
u->DLL = div;
u->DLM = div >> 8;
u->LCR = config->sc_lcr;
u->FCR = FCR_ENABLE | FCR_RXRESET | FCR_TXRESET | config->sc_fcr;
u->ACR = 0;
u->FDR = 0x10;
u->TER = TER_ENABLE;
u->IER = IER_RBR | IER_STATUS;
}
/**
* @brief UART de-initialization.
*
* @param[in] u pointer to an UART I/O block
*/
static void uart_deinit(LPC_UART_TypeDef *u) {
u->LCR = LCR_DLAB;
u->DLL = 1;
u->DLM = 0;
u->LCR = 0;
u->FDR = 0x10;
u->IER = 0;
u->FCR = FCR_RXRESET | FCR_TXRESET;
u->ACR = 0;
u->TER = TER_ENABLE;
}
/**
* @brief Error handling routine.
*
* @param[in] sdp communication channel associated to the UART
* @param[in] err UART LSR register value
*/
static void set_error(SerialDriver *sdp, IOREG32 err) {
flagsmask_t sts = 0;
if (err & LSR_OVERRUN)
sts |= SD_OVERRUN_ERROR;
if (err & LSR_PARITY)
sts |= SD_PARITY_ERROR;
if (err & LSR_FRAMING)
sts |= SD_FRAMING_ERROR;
if (err & LSR_BREAK)
sts |= SD_BREAK_DETECTED;
chSysLockFromIsr();
chnAddFlagsI(sdp, sts);
chSysUnlockFromIsr();
}
/**
* @brief Common IRQ handler.
* @note Tries hard to clear all the pending interrupt sources, we don't
* want to go through the whole ISR and have another interrupt soon
* after.
*
* @param[in] u pointer to an UART I/O block
* @param[in] sdp communication channel associated to the UART
*/
static void serve_interrupt(SerialDriver *sdp) {
LPC_UART_TypeDef *u = sdp->uart;
while (TRUE) {
switch (u->IIR & IIR_SRC_MASK) {
case IIR_SRC_NONE:
return;
case IIR_SRC_ERROR:
set_error(sdp, u->LSR);
break;
case IIR_SRC_TIMEOUT:
case IIR_SRC_RX:
chSysLockFromIsr();
if (chIQIsEmptyI(&sdp->iqueue))
chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE);
chSysUnlockFromIsr();
while (u->LSR & LSR_RBR_FULL) {
chSysLockFromIsr();
if (chIQPutI(&sdp->iqueue, u->RBR) < Q_OK)
chnAddFlagsI(sdp, SD_OVERRUN_ERROR);
chSysUnlockFromIsr();
}
break;
case IIR_SRC_TX:
{
int i = LPC17xx_SERIAL_FIFO_PRELOAD;
do {
msg_t b;
chSysLockFromIsr();
b = chOQGetI(&sdp->oqueue);
chSysUnlockFromIsr();
if (b < Q_OK) {
u->IER &= ~IER_THRE;
chSysLockFromIsr();
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
chSysUnlockFromIsr();
break;
}
u->THR = b;
} while (--i);
}
break;
default:
(void) u->THR;
(void) u->RBR;
}
}
}
/**
* @brief Attempts a TX FIFO preload.
*/
static void preload(SerialDriver *sdp) {
LPC_UART_TypeDef *u = sdp->uart;
if (u->LSR & LSR_THRE) {
int i = LPC17xx_SERIAL_FIFO_PRELOAD;
do {
msg_t b = chOQGetI(&sdp->oqueue);
if (b < Q_OK) {
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
return;
}
u->THR = b;
} while (--i);
}
u->IER |= IER_THRE;
}
/**
* @brief Driver SD1 output notification.
*/
#if LPC17xx_SERIAL_USE_UART0 || defined(__DOXYGEN__)
static void notify1(GenericQueue *qp) {
(void)qp;
preload(&SD1);
}
#endif
/**
* @brief Driver SD2 output notification.
*/
#if LPC17xx_SERIAL_USE_UART1 || defined(__DOXYGEN__)
static void notify2(GenericQueue *qp) {
(void)qp;
preload(&SD2);
}
#endif
/**
* @brief Driver SD3 output notification.
*/
#if LPC17xx_SERIAL_USE_UART2 || defined(__DOXYGEN__)
static void notify3(GenericQueue *qp) {
(void)qp;
preload(&SD3);
}
#endif
/**
* @brief Driver SD4 output notification.
*/
#if LPC17xx_SERIAL_USE_UART3 || defined(__DOXYGEN__)
static void notify4(GenericQueue *qp) {
(void)qp;
preload(&SD4);
}
#endif
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief UART0 IRQ handler.
*
* @isr
*/
#if LPC17xx_SERIAL_USE_UART0 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(Vector54) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD1);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART1 IRQ handler.
*
* @isr
*/
#if LPC17xx_SERIAL_USE_UART1 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(Vector58) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD2);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART2 IRQ handler.
*
* @isr
*/
#if LPC17xx_SERIAL_USE_UART2 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(Vector5C) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD3);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART3 IRQ handler.
*
* @isr
*/
#if LPC17xx_SERIAL_USE_UART3 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(Vector60) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD4);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level serial driver initialization.
*
* @notapi
*/
void sd_lld_init(void) {
#if LPC17xx_SERIAL_USE_UART0
sdObjectInit(&SD1, NULL, notify1);
SD1.uart = (LPC_UART_TypeDef*) LPC_UART0;
#endif
#if LPC17xx_SERIAL_USE_UART1
sdObjectInit(&SD2, NULL, notify2);
SD2.uart = (LPC_UART_TypeDef*) LPC_UART1;
#endif
#if LPC17xx_SERIAL_USE_UART2
sdObjectInit(&SD3, NULL, notify3);
SD3.uart = (LPC_UART_TypeDef*) LPC_UART2;
#endif
#if LPC17xx_SERIAL_USE_UART3
sdObjectInit(&SD4, NULL, notify4);
SD4.uart = (LPC_UART_TypeDef*) LPC_UART3;
#endif
}
/**
* @brief Low level serial driver configuration and (re)start.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] config the architecture-dependent serial driver configuration.
* If this parameter is set to @p NULL then a default
* configuration is used.
*
* @notapi
*/
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
if (config == NULL)
config = &default_config;
if (sdp->state == SD_STOP) {
#if LPC17xx_SERIAL_USE_UART0
if (&SD1 == sdp) {
LPC_SC->PCONP |= (1 << 3);
nvicEnableVector(UART0_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART0_IRQ_PRIORITY));
}
#endif
#if LPC17xx_SERIAL_USE_UART1
if (&SD2 == sdp) {
LPC_SC->PCONP |= (1 << 4);
nvicEnableVector(UART1_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART1_IRQ_PRIORITY));
}
#endif
#if LPC17xx_SERIAL_USE_UART2
if (&SD3 == sdp) {
LPC_SC->PCONP |= (1 << 24);
nvicEnableVector(UART2_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART2_IRQ_PRIORITY));
}
#endif
#if LPC17xx_SERIAL_USE_UART3
if (&SD4 == sdp) {
LPC_SC->PCONP |= (1 << 25);
nvicEnableVector(UART3_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SERIAL_UART3_IRQ_PRIORITY));
}
#endif
}
uart_init(sdp, config);
}
/**
* @brief Low level serial driver stop.
* @details De-initializes the UART, stops the associated clock, resets the
* interrupt vector.
*
* @param[in] sdp pointer to a @p SerialDriver object
*
* @notapi
*/
void sd_lld_stop(SerialDriver *sdp) {
if (sdp->state == SD_READY) {
uart_deinit(sdp->uart);
#if LPC17xx_SERIAL_USE_UART0
if (&SD1 == sdp) {
LPC_SC->PCONP &= ~(1 << 3);
nvicDisableVector(UART0_IRQn);
return;
}
#endif
#if LPC17xx_SERIAL_USE_UART1
if (&SD2 == sdp) {
LPC_SC->PCONP &= ~(1 << 4);
nvicDisableVector(UART1_IRQn);
return;
}
#endif
#if LPC17xx_SERIAL_USE_UART2
if (&SD3 == sdp) {
LPC_SC->PCONP &= ~(1 << 24);
nvicDisableVector(UART2_IRQn);
return;
}
#endif
#if LPC17xx_SERIAL_USE_UART3
if (&SD4 == sdp) {
LPC_SC->PCONP &= ~(1 << 25);
nvicDisableVector(UART3_IRQn);
return;
}
#endif
}
}
#endif /* HAL_USE_SERIAL */
/** @} */

View File

@ -1,268 +1,268 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/serial_lld.h
* @brief LPC17xx low level serial driver header.
*
* @addtogroup SERIAL
* @{
*/
#ifndef _SERIAL_LLD_H_
#define _SERIAL_LLD_H_
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define IIR_SRC_MASK 0x0F
#define IIR_SRC_NONE 0x01
#define IIR_SRC_MODEM 0x00
#define IIR_SRC_TX 0x02
#define IIR_SRC_RX 0x04
#define IIR_SRC_ERROR 0x06
#define IIR_SRC_TIMEOUT 0x0C
#define IER_RBR 1
#define IER_THRE 2
#define IER_STATUS 4
#define LCR_WL5 0
#define LCR_WL6 1
#define LCR_WL7 2
#define LCR_WL8 3
#define LCR_STOP1 0
#define LCR_STOP2 4
#define LCR_NOPARITY 0
#define LCR_PARITYODD 0x08
#define LCR_PARITYEVEN 0x18
#define LCR_PARITYONE 0x28
#define LCR_PARITYZERO 0x38
#define LCR_BREAK_ON 0x40
#define LCR_DLAB 0x80
#define FCR_ENABLE 1
#define FCR_RXRESET 2
#define FCR_TXRESET 4
#define FCR_TRIGGER0 0
#define FCR_TRIGGER1 0x40
#define FCR_TRIGGER2 0x80
#define FCR_TRIGGER3 0xC0
#define LSR_RBR_FULL 1
#define LSR_OVERRUN 2
#define LSR_PARITY 4
#define LSR_FRAMING 8
#define LSR_BREAK 0x10
#define LSR_THRE 0x20
#define LSR_TEMT 0x40
#define LSR_RXFE 0x80
#define TER_ENABLE 0x80
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief UART0 driver enable switch.
* @details If set to @p TRUE the support for UART0 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC17xx_SERIAL_USE_UART0) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_USE_UART0 TRUE
#endif
/**
* @brief UART1 driver enable switch.
* @details If set to @p TRUE the support for UART1 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC17xx_SERIAL_USE_UART1) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_USE_UART1 TRUE
#endif
/**
* @brief UART2 driver enable switch.
* @details If set to @p TRUE the support for UART2 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC17xx_SERIAL_USE_UART2) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_USE_UART2 TRUE
#endif
/**
* @brief UART3 driver enable switch.
* @details If set to @p TRUE the support for UART3 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC17xx_SERIAL_USE_UART3) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_USE_UART3 TRUE
#endif
/**
* @brief FIFO preload parameter.
* @details Configuration parameter, this values defines how many bytes are
* preloaded in the HW transmit FIFO for each interrupt, the maximum
* value is 16 the minimum is 1.
* @note An high value reduces the number of interrupts generated but can
* also increase the worst case interrupt response time because the
* preload loops.
*/
#if !defined(LPC17xx_SERIAL_FIFO_PRELOAD) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_FIFO_PRELOAD 16
#endif
/**
* @brief UART0 interrupt priority level setting.
*/
#if !defined(LPC17xx_SERIAL_UART0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_UART0_IRQ_PRIORITY 3
#endif
/**
* @brief UART1 interrupt priority level setting.
*/
#if !defined(LPC17xx_SERIAL_UART1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_UART1_IRQ_PRIORITY 3
#endif
/**
* @brief UART2 interrupt priority level setting.
*/
#if !defined(LPC17xx_SERIAL_UART2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_UART2_IRQ_PRIORITY 3
#endif
/**
* @brief UART3 interrupt priority level setting.
*/
#if !defined(LPC17xx_SERIAL_UART3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_UART0_IRQ_PRIORITY 3
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if (LPC17xx_SERIAL_FIFO_PRELOAD < 1) || (LPC17xx_SERIAL_FIFO_PRELOAD > 16)
#error "invalid LPC17xx_SERIAL_FIFO_PRELOAD setting"
#endif
/**
* @brief UART0 clock.
*/
#define LPC17xx_SERIAL_UART0_PCLK LPC17xx_PCLK
/**
* @brief UART1 clock.
*/
#define LPC17xx_SERIAL_UART1_PCLK LPC17xx_PCLK
/**
* @brief UART2 clock.
*/
#define LPC17xx_SERIAL_UART2_PCLK LPC17xx_PCLK
/**
* @brief UART3 clock.
*/
#define LPC17xx_SERIAL_UART3_PCLK LPC17xx_PCLK
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief LPC17xx Serial Driver configuration structure.
* @details An instance of this structure must be passed to @p sdStart()
* in order to configure and start a serial driver operations.
*/
typedef struct {
/**
* @brief Bit rate.
*/
uint32_t sc_speed;
/**
* @brief Initialization value for the LCR register.
*/
uint32_t sc_lcr;
/**
* @brief Initialization value for the FCR register.
*/
uint32_t sc_fcr;
} SerialConfig;
/**
* @brief @p SerialDriver specific data.
*/
#define _serial_driver_data \
_base_asynchronous_channel_data \
/* Driver state.*/ \
sdstate_t state; \
/* Input queue.*/ \
InputQueue iqueue; \
/* Output queue.*/ \
OutputQueue oqueue; \
/* Input circular buffer.*/ \
uint8_t ib[SERIAL_BUFFERS_SIZE]; \
/* Output circular buffer.*/ \
uint8_t ob[SERIAL_BUFFERS_SIZE]; \
/* End of the mandatory fields.*/ \
/* Pointer to the USART registers block.*/ \
LPC_UART_TypeDef *uart;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC17xx_SERIAL_USE_UART0 && !defined(__DOXYGEN__)
extern SerialDriver SD1;
#endif
#if LPC17xx_SERIAL_USE_UART1 && !defined(__DOXYGEN__)
extern SerialDriver SD2;
#endif
#if LPC17xx_SERIAL_USE_UART2 && !defined(__DOXYGEN__)
extern SerialDriver SD3;
#endif
#if LPC17xx_SERIAL_USE_UART3 && !defined(__DOXYGEN__)
extern SerialDriver SD4;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void sd_lld_init(void);
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
void sd_lld_stop(SerialDriver *sdp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SERIAL */
#endif /* _SERIAL_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/serial_lld.h
* @brief LPC17xx low level serial driver header.
*
* @addtogroup SERIAL
* @{
*/
#ifndef _SERIAL_LLD_H_
#define _SERIAL_LLD_H_
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define IIR_SRC_MASK 0x0F
#define IIR_SRC_NONE 0x01
#define IIR_SRC_MODEM 0x00
#define IIR_SRC_TX 0x02
#define IIR_SRC_RX 0x04
#define IIR_SRC_ERROR 0x06
#define IIR_SRC_TIMEOUT 0x0C
#define IER_RBR 1
#define IER_THRE 2
#define IER_STATUS 4
#define LCR_WL5 0
#define LCR_WL6 1
#define LCR_WL7 2
#define LCR_WL8 3
#define LCR_STOP1 0
#define LCR_STOP2 4
#define LCR_NOPARITY 0
#define LCR_PARITYODD 0x08
#define LCR_PARITYEVEN 0x18
#define LCR_PARITYONE 0x28
#define LCR_PARITYZERO 0x38
#define LCR_BREAK_ON 0x40
#define LCR_DLAB 0x80
#define FCR_ENABLE 1
#define FCR_RXRESET 2
#define FCR_TXRESET 4
#define FCR_TRIGGER0 0
#define FCR_TRIGGER1 0x40
#define FCR_TRIGGER2 0x80
#define FCR_TRIGGER3 0xC0
#define LSR_RBR_FULL 1
#define LSR_OVERRUN 2
#define LSR_PARITY 4
#define LSR_FRAMING 8
#define LSR_BREAK 0x10
#define LSR_THRE 0x20
#define LSR_TEMT 0x40
#define LSR_RXFE 0x80
#define TER_ENABLE 0x80
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief UART0 driver enable switch.
* @details If set to @p TRUE the support for UART0 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC17xx_SERIAL_USE_UART0) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_USE_UART0 TRUE
#endif
/**
* @brief UART1 driver enable switch.
* @details If set to @p TRUE the support for UART1 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC17xx_SERIAL_USE_UART1) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_USE_UART1 TRUE
#endif
/**
* @brief UART2 driver enable switch.
* @details If set to @p TRUE the support for UART2 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC17xx_SERIAL_USE_UART2) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_USE_UART2 TRUE
#endif
/**
* @brief UART3 driver enable switch.
* @details If set to @p TRUE the support for UART3 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC17xx_SERIAL_USE_UART3) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_USE_UART3 TRUE
#endif
/**
* @brief FIFO preload parameter.
* @details Configuration parameter, this values defines how many bytes are
* preloaded in the HW transmit FIFO for each interrupt, the maximum
* value is 16 the minimum is 1.
* @note An high value reduces the number of interrupts generated but can
* also increase the worst case interrupt response time because the
* preload loops.
*/
#if !defined(LPC17xx_SERIAL_FIFO_PRELOAD) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_FIFO_PRELOAD 16
#endif
/**
* @brief UART0 interrupt priority level setting.
*/
#if !defined(LPC17xx_SERIAL_UART0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_UART0_IRQ_PRIORITY 3
#endif
/**
* @brief UART1 interrupt priority level setting.
*/
#if !defined(LPC17xx_SERIAL_UART1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_UART1_IRQ_PRIORITY 3
#endif
/**
* @brief UART2 interrupt priority level setting.
*/
#if !defined(LPC17xx_SERIAL_UART2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_UART2_IRQ_PRIORITY 3
#endif
/**
* @brief UART3 interrupt priority level setting.
*/
#if !defined(LPC17xx_SERIAL_UART3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SERIAL_UART0_IRQ_PRIORITY 3
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if (LPC17xx_SERIAL_FIFO_PRELOAD < 1) || (LPC17xx_SERIAL_FIFO_PRELOAD > 16)
#error "invalid LPC17xx_SERIAL_FIFO_PRELOAD setting"
#endif
/**
* @brief UART0 clock.
*/
#define LPC17xx_SERIAL_UART0_PCLK LPC17xx_PCLK
/**
* @brief UART1 clock.
*/
#define LPC17xx_SERIAL_UART1_PCLK LPC17xx_PCLK
/**
* @brief UART2 clock.
*/
#define LPC17xx_SERIAL_UART2_PCLK LPC17xx_PCLK
/**
* @brief UART3 clock.
*/
#define LPC17xx_SERIAL_UART3_PCLK LPC17xx_PCLK
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief LPC17xx Serial Driver configuration structure.
* @details An instance of this structure must be passed to @p sdStart()
* in order to configure and start a serial driver operations.
*/
typedef struct {
/**
* @brief Bit rate.
*/
uint32_t sc_speed;
/**
* @brief Initialization value for the LCR register.
*/
uint32_t sc_lcr;
/**
* @brief Initialization value for the FCR register.
*/
uint32_t sc_fcr;
} SerialConfig;
/**
* @brief @p SerialDriver specific data.
*/
#define _serial_driver_data \
_base_asynchronous_channel_data \
/* Driver state.*/ \
sdstate_t state; \
/* Input queue.*/ \
InputQueue iqueue; \
/* Output queue.*/ \
OutputQueue oqueue; \
/* Input circular buffer.*/ \
uint8_t ib[SERIAL_BUFFERS_SIZE]; \
/* Output circular buffer.*/ \
uint8_t ob[SERIAL_BUFFERS_SIZE]; \
/* End of the mandatory fields.*/ \
/* Pointer to the USART registers block.*/ \
LPC_UART_TypeDef *uart;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC17xx_SERIAL_USE_UART0 && !defined(__DOXYGEN__)
extern SerialDriver SD1;
#endif
#if LPC17xx_SERIAL_USE_UART1 && !defined(__DOXYGEN__)
extern SerialDriver SD2;
#endif
#if LPC17xx_SERIAL_USE_UART2 && !defined(__DOXYGEN__)
extern SerialDriver SD3;
#endif
#if LPC17xx_SERIAL_USE_UART3 && !defined(__DOXYGEN__)
extern SerialDriver SD4;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void sd_lld_init(void);
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
void sd_lld_stop(SerialDriver *sdp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SERIAL */
#endif /* _SERIAL_LLD_H_ */
/** @} */

View File

@ -1,387 +1,387 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/spi_lld.c
* @brief LPC17xx low level SPI driver code.
*
* @addtogroup SPI
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
#if LPC17xx_SPI_USE_SSP0 || defined(__DOXYGEN__)
/** @brief SPI1 driver identifier.*/
SPIDriver SPID1;
#endif
#if LPC17xx_SPI_USE_SSP1 || defined(__DOXYGEN__)
/** @brief SPI2 driver identifier.*/
SPIDriver SPID2;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Preloads the transmit FIFO.
*
* @param[in] spip pointer to the @p SPIDriver object
*/
static void ssp_fifo_preload(SPIDriver *spip) {
LPC_SSP_TypeDef *ssp = spip->ssp;
uint32_t n = spip->txcnt > LPC17xx_SSP_FIFO_DEPTH ?
LPC17xx_SSP_FIFO_DEPTH : spip->txcnt;
while(((ssp->SR & SR_TNF) != 0) && (n > 0)) {
if (spip->txptr != NULL) {
if ((ssp->CR0 & CR0_DSSMASK) > CR0_DSS8BIT) {
const uint16_t *p = spip->txptr;
ssp->DR = *p++;
spip->txptr = p;
}
else {
const uint8_t *p = spip->txptr;
ssp->DR = *p++;
spip->txptr = p;
}
}
else
ssp->DR = 0xFFFFFFFF;
n--;
spip->txcnt--;
}
}
/**
* @brief Common IRQ handler.
*
* @param[in] spip pointer to the @p SPIDriver object
*/
static void spi_serve_interrupt(SPIDriver *spip) {
LPC_SSP_TypeDef *ssp = spip->ssp;
if ((ssp->MIS & MIS_ROR) != 0) {
/* The overflow condition should never happen because priority is given
to receive but a hook macro is provided anyway...*/
LPC17xx_SPI_SSP_ERROR_HOOK(spip);
}
ssp->ICR = ICR_RT | ICR_ROR;
while ((ssp->SR & SR_RNE) != 0) {
if (spip->rxptr != NULL) {
if ((ssp->CR0 & CR0_DSSMASK) > CR0_DSS8BIT) {
uint16_t *p = spip->rxptr;
*p++ = ssp->DR;
spip->rxptr = p;
}
else {
uint8_t *p = spip->rxptr;
*p++ = ssp->DR;
spip->rxptr = p;
}
}
else
(void)ssp->DR;
if (--spip->rxcnt == 0) {
chDbgAssert(spip->txcnt == 0,
"spi_serve_interrupt(), #1", "counter out of synch");
/* Stops the IRQ sources.*/
ssp->IMSC = 0;
/* Portable SPI ISR code defined in the high level driver, note, it is
a macro.*/
_spi_isr_code(spip);
return;
}
}
ssp_fifo_preload(spip);
if (spip->txcnt == 0)
ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_RX;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if LPC17xx_SPI_USE_SSP0 || defined(__DOXYGEN__)
/**
* @brief SSP0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector78) {
CH_IRQ_PROLOGUE();
spi_serve_interrupt(&SPID1);
CH_IRQ_EPILOGUE();
}
#endif
#if LPC17xx_SPI_USE_SSP1 || defined(__DOXYGEN__)
/**
* @brief SSP1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector7C) {
CH_IRQ_PROLOGUE();
spi_serve_interrupt(&SPID2);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level SPI driver initialization.
*
* @notapi
*/
void spi_lld_init(void) {
#if LPC17xx_SPI_USE_SSP0
spiObjectInit(&SPID1);
SPID1.ssp = LPC_SSP0;
#endif /* LPC17xx_SPI_USE_SSP0 */
#if LPC17xx_SPI_USE_SSP1
spiObjectInit(&SPID2);
SPID2.ssp = LPC_SSP1;
#endif /* LPC17xx_SPI_USE_SSP0 */
}
/**
* @brief Configures and activates the SPI peripheral.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_start(SPIDriver *spip) {
if (spip->state == SPI_STOP) {
/* Clock activation.*/
#if LPC17xx_SPI_USE_SSP0
if (&SPID1 == spip) {
LPC_SC->PCONP |= (1UL << 21);
LPC_SC->PCLKSEL0 &= (PCLKSEL_MASK << 20);
LPC_SC->PCLKSEL0 |= (LPC17xx_SPI_SSP0_PCLKSEL << 20);
nvicEnableVector(SSP0_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SPI_SSP0_IRQ_PRIORITY));
}
#endif
#if LPC17xx_SPI_USE_SSP1
if (&SPID2 == spip) {
LPC_SC->PCONP |= (1UL << 10);
LPC_SC->PCLKSEL1 &= (PCLKSEL_MASK << 10);
LPC_SC->PCLKSEL1 |= (LPC17xx_SPI_SSP0_PCLKSEL << 10);
nvicEnableVector(SSP1_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SPI_SSP1_IRQ_PRIORITY));
}
#endif
}
/* Configuration.*/
spip->ssp->CR1 = 0;
spip->ssp->ICR = ICR_RT | ICR_ROR;
spip->ssp->CR0 = spip->config->cr0;
spip->ssp->CPSR = spip->config->cpsr;
spip->ssp->CR1 = CR1_SSE;
}
/**
* @brief Deactivates the SPI peripheral.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_stop(SPIDriver *spip) {
if (spip->state != SPI_STOP) {
spip->ssp->CR1 = 0;
spip->ssp->CR0 = 0;
spip->ssp->CPSR = 0;
#if LPC17xx_SPI_USE_SSP0
if (&SPID1 == spip) {
LPC_SC->PCONP &= ~(1UL << 21);
nvicDisableVector(SSP0_IRQn);
}
#endif
#if LPC17xx_SPI_USE_SSP1
if (&SPID2 == spip) {
LPC_SC->PCONP &= ~(1UL << 10);
nvicDisableVector(SSP1_IRQn);
}
#endif
}
}
/**
* @brief Asserts the slave select signal and prepares for transfers.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_select(SPIDriver *spip) {
palClearPad(spip->config->ssport, spip->config->sspad);
}
/**
* @brief Deasserts the slave select signal.
* @details The previously selected peripheral is unselected.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_unselect(SPIDriver *spip) {
palSetPad(spip->config->ssport, spip->config->sspad);
}
/**
* @brief Ignores data on the SPI bus.
* @details This function transmits a series of idle words on the SPI bus and
* ignores the received data. This function can be invoked even
* when a slave select signal has not been yet asserted.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be ignored
*
* @notapi
*/
void spi_lld_ignore(SPIDriver *spip, size_t n) {
spip->rxptr = NULL;
spip->txptr = NULL;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Exchanges data on the SPI bus.
* @details This asynchronous function starts a simultaneous transmit/receive
* operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be exchanged
* @param[in] txbuf the pointer to the transmit buffer
* @param[out] rxbuf the pointer to the receive buffer
*
* @notapi
*/
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
spip->rxptr = rxbuf;
spip->txptr = txbuf;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Sends data over the SPI bus.
* @details This asynchronous function starts a transmit operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @notapi
*/
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
spip->rxptr = NULL;
spip->txptr = txbuf;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Receives data from the SPI bus.
* @details This asynchronous function starts a receive operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to receive
* @param[out] rxbuf the pointer to the receive buffer
*
* @notapi
*/
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
spip->rxptr = rxbuf;
spip->txptr = NULL;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Exchanges one frame using a polled wait.
* @details This synchronous function exchanges one frame using a polled
* synchronization method. This function is useful when exchanging
* small amount of data on high speed channels, usually in this
* situation is much more efficient just wait for completion using
* polling than suspending the thread waiting for an interrupt.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] frame the data frame to send over the SPI bus
* @return The received data frame from the SPI bus.
*/
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
spip->ssp->DR = (uint32_t)frame;
while ((spip->ssp->SR & SR_RNE) == 0)
;
return (uint16_t)spip->ssp->DR;
}
#endif /* HAL_USE_SPI */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/spi_lld.c
* @brief LPC17xx low level SPI driver code.
*
* @addtogroup SPI
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
#if LPC17xx_SPI_USE_SSP0 || defined(__DOXYGEN__)
/** @brief SPI1 driver identifier.*/
SPIDriver SPID1;
#endif
#if LPC17xx_SPI_USE_SSP1 || defined(__DOXYGEN__)
/** @brief SPI2 driver identifier.*/
SPIDriver SPID2;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Preloads the transmit FIFO.
*
* @param[in] spip pointer to the @p SPIDriver object
*/
static void ssp_fifo_preload(SPIDriver *spip) {
LPC_SSP_TypeDef *ssp = spip->ssp;
uint32_t n = spip->txcnt > LPC17xx_SSP_FIFO_DEPTH ?
LPC17xx_SSP_FIFO_DEPTH : spip->txcnt;
while(((ssp->SR & SR_TNF) != 0) && (n > 0)) {
if (spip->txptr != NULL) {
if ((ssp->CR0 & CR0_DSSMASK) > CR0_DSS8BIT) {
const uint16_t *p = spip->txptr;
ssp->DR = *p++;
spip->txptr = p;
}
else {
const uint8_t *p = spip->txptr;
ssp->DR = *p++;
spip->txptr = p;
}
}
else
ssp->DR = 0xFFFFFFFF;
n--;
spip->txcnt--;
}
}
/**
* @brief Common IRQ handler.
*
* @param[in] spip pointer to the @p SPIDriver object
*/
static void spi_serve_interrupt(SPIDriver *spip) {
LPC_SSP_TypeDef *ssp = spip->ssp;
if ((ssp->MIS & MIS_ROR) != 0) {
/* The overflow condition should never happen because priority is given
to receive but a hook macro is provided anyway...*/
LPC17xx_SPI_SSP_ERROR_HOOK(spip);
}
ssp->ICR = ICR_RT | ICR_ROR;
while ((ssp->SR & SR_RNE) != 0) {
if (spip->rxptr != NULL) {
if ((ssp->CR0 & CR0_DSSMASK) > CR0_DSS8BIT) {
uint16_t *p = spip->rxptr;
*p++ = ssp->DR;
spip->rxptr = p;
}
else {
uint8_t *p = spip->rxptr;
*p++ = ssp->DR;
spip->rxptr = p;
}
}
else
(void)ssp->DR;
if (--spip->rxcnt == 0) {
chDbgAssert(spip->txcnt == 0,
"spi_serve_interrupt(), #1", "counter out of synch");
/* Stops the IRQ sources.*/
ssp->IMSC = 0;
/* Portable SPI ISR code defined in the high level driver, note, it is
a macro.*/
_spi_isr_code(spip);
return;
}
}
ssp_fifo_preload(spip);
if (spip->txcnt == 0)
ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_RX;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if LPC17xx_SPI_USE_SSP0 || defined(__DOXYGEN__)
/**
* @brief SSP0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector78) {
CH_IRQ_PROLOGUE();
spi_serve_interrupt(&SPID1);
CH_IRQ_EPILOGUE();
}
#endif
#if LPC17xx_SPI_USE_SSP1 || defined(__DOXYGEN__)
/**
* @brief SSP1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector7C) {
CH_IRQ_PROLOGUE();
spi_serve_interrupt(&SPID2);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level SPI driver initialization.
*
* @notapi
*/
void spi_lld_init(void) {
#if LPC17xx_SPI_USE_SSP0
spiObjectInit(&SPID1);
SPID1.ssp = LPC_SSP0;
#endif /* LPC17xx_SPI_USE_SSP0 */
#if LPC17xx_SPI_USE_SSP1
spiObjectInit(&SPID2);
SPID2.ssp = LPC_SSP1;
#endif /* LPC17xx_SPI_USE_SSP0 */
}
/**
* @brief Configures and activates the SPI peripheral.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_start(SPIDriver *spip) {
if (spip->state == SPI_STOP) {
/* Clock activation.*/
#if LPC17xx_SPI_USE_SSP0
if (&SPID1 == spip) {
LPC_SC->PCONP |= (1UL << 21);
LPC_SC->PCLKSEL0 &= (PCLKSEL_MASK << 20);
LPC_SC->PCLKSEL0 |= (LPC17xx_SPI_SSP0_PCLKSEL << 20);
nvicEnableVector(SSP0_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SPI_SSP0_IRQ_PRIORITY));
}
#endif
#if LPC17xx_SPI_USE_SSP1
if (&SPID2 == spip) {
LPC_SC->PCONP |= (1UL << 10);
LPC_SC->PCLKSEL1 &= (PCLKSEL_MASK << 10);
LPC_SC->PCLKSEL1 |= (LPC17xx_SPI_SSP0_PCLKSEL << 10);
nvicEnableVector(SSP1_IRQn,
CORTEX_PRIORITY_MASK(LPC17xx_SPI_SSP1_IRQ_PRIORITY));
}
#endif
}
/* Configuration.*/
spip->ssp->CR1 = 0;
spip->ssp->ICR = ICR_RT | ICR_ROR;
spip->ssp->CR0 = spip->config->cr0;
spip->ssp->CPSR = spip->config->cpsr;
spip->ssp->CR1 = CR1_SSE;
}
/**
* @brief Deactivates the SPI peripheral.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_stop(SPIDriver *spip) {
if (spip->state != SPI_STOP) {
spip->ssp->CR1 = 0;
spip->ssp->CR0 = 0;
spip->ssp->CPSR = 0;
#if LPC17xx_SPI_USE_SSP0
if (&SPID1 == spip) {
LPC_SC->PCONP &= ~(1UL << 21);
nvicDisableVector(SSP0_IRQn);
}
#endif
#if LPC17xx_SPI_USE_SSP1
if (&SPID2 == spip) {
LPC_SC->PCONP &= ~(1UL << 10);
nvicDisableVector(SSP1_IRQn);
}
#endif
}
}
/**
* @brief Asserts the slave select signal and prepares for transfers.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_select(SPIDriver *spip) {
palClearPad(spip->config->ssport, spip->config->sspad);
}
/**
* @brief Deasserts the slave select signal.
* @details The previously selected peripheral is unselected.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_unselect(SPIDriver *spip) {
palSetPad(spip->config->ssport, spip->config->sspad);
}
/**
* @brief Ignores data on the SPI bus.
* @details This function transmits a series of idle words on the SPI bus and
* ignores the received data. This function can be invoked even
* when a slave select signal has not been yet asserted.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be ignored
*
* @notapi
*/
void spi_lld_ignore(SPIDriver *spip, size_t n) {
spip->rxptr = NULL;
spip->txptr = NULL;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Exchanges data on the SPI bus.
* @details This asynchronous function starts a simultaneous transmit/receive
* operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be exchanged
* @param[in] txbuf the pointer to the transmit buffer
* @param[out] rxbuf the pointer to the receive buffer
*
* @notapi
*/
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
spip->rxptr = rxbuf;
spip->txptr = txbuf;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Sends data over the SPI bus.
* @details This asynchronous function starts a transmit operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @notapi
*/
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
spip->rxptr = NULL;
spip->txptr = txbuf;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Receives data from the SPI bus.
* @details This asynchronous function starts a receive operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to receive
* @param[out] rxbuf the pointer to the receive buffer
*
* @notapi
*/
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
spip->rxptr = rxbuf;
spip->txptr = NULL;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Exchanges one frame using a polled wait.
* @details This synchronous function exchanges one frame using a polled
* synchronization method. This function is useful when exchanging
* small amount of data on high speed channels, usually in this
* situation is much more efficient just wait for completion using
* polling than suspending the thread waiting for an interrupt.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] frame the data frame to send over the SPI bus
* @return The received data frame from the SPI bus.
*/
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
spip->ssp->DR = (uint32_t)frame;
while ((spip->ssp->SR & SR_RNE) == 0)
;
return (uint16_t)spip->ssp->DR;
}
#endif /* HAL_USE_SPI */
/** @} */

View File

@ -1,337 +1,337 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/spi_lld.h
* @brief LPC17xx low level SPI driver header.
*
* @addtogroup SPI
* @{
*/
#ifndef _SPI_LLD_H_
#define _SPI_LLD_H_
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Hardware FIFO depth.
*/
#define LPC17xx_SSP_FIFO_DEPTH 8
#define CR0_DSSMASK 0x0F
#define CR0_DSS4BIT 3
#define CR0_DSS5BIT 4
#define CR0_DSS6BIT 5
#define CR0_DSS7BIT 6
#define CR0_DSS8BIT 7
#define CR0_DSS9BIT 8
#define CR0_DSS10BIT 9
#define CR0_DSS11BIT 0xA
#define CR0_DSS12BIT 0xB
#define CR0_DSS13BIT 0xC
#define CR0_DSS14BIT 0xD
#define CR0_DSS15BIT 0xE
#define CR0_DSS16BIT 0xF
#define CR0_FRFSPI 0
#define CR0_FRFSSI 0x10
#define CR0_FRFMW 0x20
#define CR0_CPOL 0x40
#define CR0_CPHA 0x80
#define CR0_CLOCKRATE(n) ((n) << 8)
#define CR1_LBM 1
#define CR1_SSE 2
#define CR1_MS 4
#define CR1_SOD 8
#define SR_TFE 1
#define SR_TNF 2
#define SR_RNE 4
#define SR_RFF 8
#define SR_BSY 16
#define IMSC_ROR 1
#define IMSC_RT 2
#define IMSC_RX 4
#define IMSC_TX 8
#define RIS_ROR 1
#define RIS_RT 2
#define RIS_RX 4
#define RIS_TX 8
#define MIS_ROR 1
#define MIS_RT 2
#define MIS_RX 4
#define MIS_TX 8
#define ICR_ROR 1
#define ICR_RT 2
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief SPI1 driver enable switch.
* @details If set to @p TRUE the support for device SSP0 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_SPI_USE_SSP0) || defined(__DOXYGEN__)
#define LPC17xx_SPI_USE_SSP0 TRUE
#endif
/**
* @brief SPI2 driver enable switch.
* @details If set to @p TRUE the support for device SSP1 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_SPI_USE_SSP1) || defined(__DOXYGEN__)
#define LPC17xx_SPI_USE_SSP1 FALSE
#endif
/**
* @brief SSP0 PCLK divider.
*/
#if !defined(LPC17xx_SPI_SSP0CLKDIV) || defined(__DOXYGEN__)
#define LPC17xx_SPI_SSP0CLKDIV 1
#endif
/**
* @brief SSP1 PCLK divider.
*/
#if !defined(LPC17xx_SPI_SSP1CLKDIV) || defined(__DOXYGEN__)
#define LPC17xx_SPI_SSP1CLKDIV 1
#endif
/**
* @brief SPI0 interrupt priority level setting.
*/
#if !defined(LPC17xx_SPI_SSP0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SPI_SSP0_IRQ_PRIORITY 5
#endif
/**
* @brief SPI1 interrupt priority level setting.
*/
#if !defined(LPC17xx_SPI_SSP1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SPI_SSP1_IRQ_PRIORITY 5
#endif
/**
* @brief Overflow error hook.
* @details The default action is to stop the system.
*/
#if !defined(LPC17xx_SPI_SSP_ERROR_HOOK) || defined(__DOXYGEN__)
#define LPC17xx_SPI_SSP_ERROR_HOOK(spip) chSysHalt()
#endif
#if LPC17xx_SPI_SSP0CLKDIV == 1
#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK
#elif LPC17xx_SPI_SSP0CLKDIV == 2
#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK_DIV_2
#elif LPC17xx_SPI_SSP0CLKDIV == 4
#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK_DIV_4
#elif LPC17xx_SPI_SSP0CLKDIV == 8
#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK_DIV_8
#else
#error "Invalid LPC17xx_SPI_SSP0CLKDIV setting (1, 2, 4 or 8 accepted)"
#endif
#if LPC17xx_SPI_SSP1CLKDIV == 1
#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK
#elif LPC17xx_SPI_SSP1CLKDIV == 2
#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK_DIV_2
#elif LPC17xx_SPI_SSP1CLKDIV == 4
#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK_DIV_4
#elif LPC17xx_SPI_SSP1CLKDIV == 8
#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK_DIV_8
#else
#error "Invalid LPC17xx_SPI_SSP1CLKDIV setting (1, 2, 4 or 8 accepted)"
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if (LPC17xx_SPI_SSP0CLKDIV != 1) && (LPC17xx_SPI_SSP0CLKDIV != 2) && \
(LPC17xx_SPI_SSP0CLKDIV != 4) && (LPC17xx_SPI_SSP0CLKDIV != 8)
#error "Invalid LPC17xx_SPI_SSP0CLKDIV setting (1, 2, 4 or 8 accepted)"
#endif
#if (LPC17xx_SPI_SSP1CLKDIV != 1) && (LPC17xx_SPI_SSP1CLKDIV != 2) && \
(LPC17xx_SPI_SSP1CLKDIV != 4) && (LPC17xx_SPI_SSP1CLKDIV != 8)
#error "invalid LPC17xx_SPI_SSP1CLKDIV setting (1, 2, 4 or 8 accepted)"
#endif
#if !LPC17xx_SPI_USE_SSP0 && !LPC17xx_SPI_USE_SSP1
#error "SPI driver activated but no SPI peripheral assigned"
#endif
/**
* @brief SSP0 clock.
*/
#define LPC17xx_SPI_SSP0_PCLK \
(LPC17xx_CCLK / LPC17xx_SPI_SSP0CLKDIV)
/**
* @brief SSP1 clock.
*/
#define LPC17xx_SPI_SSP1_PCLK \
(LPC17xx_CCLK / LPC17xx_SPI_SSP1CLKDIV)
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an SPI driver.
*/
typedef struct SPIDriver SPIDriver;
/**
* @brief SPI notification callback type.
*
* @param[in] spip pointer to the @p SPIDriver object triggering the
* callback
*/
typedef void (*spicallback_t)(SPIDriver *spip);
/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
* @brief Operation complete callback or @p NULL.
*/
spicallback_t end_cb;
/* End of the mandatory fields.*/
/**
* @brief The chip select line port.
*/
ioportid_t ssport;
/**
* @brief The chip select line pad number.
*/
uint16_t sspad;
/**
* @brief SSP CR0 initialization data.
*/
uint16_t cr0;
/**
* @brief SSP CPSR initialization data.
*/
uint32_t cpsr;
} SPIConfig;
/**
* @brief Structure representing a SPI driver.
*/
struct SPIDriver {
/**
* @brief Driver state.
*/
spistate_t state;
/**
* @brief Current configuration data.
*/
const SPIConfig *config;
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif /* SPI_USE_WAIT */
#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* SPI_USE_MUTUAL_EXCLUSION */
#if defined(SPI_DRIVER_EXT_FIELDS)
SPI_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the SSP registers block.
*/
LPC_SSP_TypeDef *ssp;
/**
* @brief Number of bytes yet to be received.
*/
uint32_t rxcnt;
/**
* @brief Receive pointer or @p NULL.
*/
void *rxptr;
/**
* @brief Number of bytes yet to be transmitted.
*/
uint32_t txcnt;
/**
* @brief Transmit pointer or @p NULL.
*/
const void *txptr;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC17xx_SPI_USE_SSP0 && !defined(__DOXYGEN__)
extern SPIDriver SPID1;
#endif
#if LPC17xx_SPI_USE_SSP1 && !defined(__DOXYGEN__)
extern SPIDriver SPID2;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void spi_lld_init(void);
void spi_lld_start(SPIDriver *spip);
void spi_lld_stop(SPIDriver *spip);
void spi_lld_select(SPIDriver *spip);
void spi_lld_unselect(SPIDriver *spip);
void spi_lld_ignore(SPIDriver *spip, size_t n);
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf);
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SPI */
#endif /* _SPI_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC17xx/spi_lld.h
* @brief LPC17xx low level SPI driver header.
*
* @addtogroup SPI
* @{
*/
#ifndef _SPI_LLD_H_
#define _SPI_LLD_H_
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Hardware FIFO depth.
*/
#define LPC17xx_SSP_FIFO_DEPTH 8
#define CR0_DSSMASK 0x0F
#define CR0_DSS4BIT 3
#define CR0_DSS5BIT 4
#define CR0_DSS6BIT 5
#define CR0_DSS7BIT 6
#define CR0_DSS8BIT 7
#define CR0_DSS9BIT 8
#define CR0_DSS10BIT 9
#define CR0_DSS11BIT 0xA
#define CR0_DSS12BIT 0xB
#define CR0_DSS13BIT 0xC
#define CR0_DSS14BIT 0xD
#define CR0_DSS15BIT 0xE
#define CR0_DSS16BIT 0xF
#define CR0_FRFSPI 0
#define CR0_FRFSSI 0x10
#define CR0_FRFMW 0x20
#define CR0_CPOL 0x40
#define CR0_CPHA 0x80
#define CR0_CLOCKRATE(n) ((n) << 8)
#define CR1_LBM 1
#define CR1_SSE 2
#define CR1_MS 4
#define CR1_SOD 8
#define SR_TFE 1
#define SR_TNF 2
#define SR_RNE 4
#define SR_RFF 8
#define SR_BSY 16
#define IMSC_ROR 1
#define IMSC_RT 2
#define IMSC_RX 4
#define IMSC_TX 8
#define RIS_ROR 1
#define RIS_RT 2
#define RIS_RX 4
#define RIS_TX 8
#define MIS_ROR 1
#define MIS_RT 2
#define MIS_RX 4
#define MIS_TX 8
#define ICR_ROR 1
#define ICR_RT 2
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief SPI1 driver enable switch.
* @details If set to @p TRUE the support for device SSP0 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_SPI_USE_SSP0) || defined(__DOXYGEN__)
#define LPC17xx_SPI_USE_SSP0 TRUE
#endif
/**
* @brief SPI2 driver enable switch.
* @details If set to @p TRUE the support for device SSP1 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC17xx_SPI_USE_SSP1) || defined(__DOXYGEN__)
#define LPC17xx_SPI_USE_SSP1 FALSE
#endif
/**
* @brief SSP0 PCLK divider.
*/
#if !defined(LPC17xx_SPI_SSP0CLKDIV) || defined(__DOXYGEN__)
#define LPC17xx_SPI_SSP0CLKDIV 1
#endif
/**
* @brief SSP1 PCLK divider.
*/
#if !defined(LPC17xx_SPI_SSP1CLKDIV) || defined(__DOXYGEN__)
#define LPC17xx_SPI_SSP1CLKDIV 1
#endif
/**
* @brief SPI0 interrupt priority level setting.
*/
#if !defined(LPC17xx_SPI_SSP0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SPI_SSP0_IRQ_PRIORITY 5
#endif
/**
* @brief SPI1 interrupt priority level setting.
*/
#if !defined(LPC17xx_SPI_SSP1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC17xx_SPI_SSP1_IRQ_PRIORITY 5
#endif
/**
* @brief Overflow error hook.
* @details The default action is to stop the system.
*/
#if !defined(LPC17xx_SPI_SSP_ERROR_HOOK) || defined(__DOXYGEN__)
#define LPC17xx_SPI_SSP_ERROR_HOOK(spip) chSysHalt()
#endif
#if LPC17xx_SPI_SSP0CLKDIV == 1
#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK
#elif LPC17xx_SPI_SSP0CLKDIV == 2
#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK_DIV_2
#elif LPC17xx_SPI_SSP0CLKDIV == 4
#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK_DIV_4
#elif LPC17xx_SPI_SSP0CLKDIV == 8
#define LPC17xx_SPI_SSP0_PCLKSEL PCLKSEL_CCLK_DIV_8
#else
#error "Invalid LPC17xx_SPI_SSP0CLKDIV setting (1, 2, 4 or 8 accepted)"
#endif
#if LPC17xx_SPI_SSP1CLKDIV == 1
#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK
#elif LPC17xx_SPI_SSP1CLKDIV == 2
#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK_DIV_2
#elif LPC17xx_SPI_SSP1CLKDIV == 4
#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK_DIV_4
#elif LPC17xx_SPI_SSP1CLKDIV == 8
#define LPC17xx_SPI_SSP1_PCLKSEL PCLKSEL_CCLK_DIV_8
#else
#error "Invalid LPC17xx_SPI_SSP1CLKDIV setting (1, 2, 4 or 8 accepted)"
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if (LPC17xx_SPI_SSP0CLKDIV != 1) && (LPC17xx_SPI_SSP0CLKDIV != 2) && \
(LPC17xx_SPI_SSP0CLKDIV != 4) && (LPC17xx_SPI_SSP0CLKDIV != 8)
#error "Invalid LPC17xx_SPI_SSP0CLKDIV setting (1, 2, 4 or 8 accepted)"
#endif
#if (LPC17xx_SPI_SSP1CLKDIV != 1) && (LPC17xx_SPI_SSP1CLKDIV != 2) && \
(LPC17xx_SPI_SSP1CLKDIV != 4) && (LPC17xx_SPI_SSP1CLKDIV != 8)
#error "invalid LPC17xx_SPI_SSP1CLKDIV setting (1, 2, 4 or 8 accepted)"
#endif
#if !LPC17xx_SPI_USE_SSP0 && !LPC17xx_SPI_USE_SSP1
#error "SPI driver activated but no SPI peripheral assigned"
#endif
/**
* @brief SSP0 clock.
*/
#define LPC17xx_SPI_SSP0_PCLK \
(LPC17xx_CCLK / LPC17xx_SPI_SSP0CLKDIV)
/**
* @brief SSP1 clock.
*/
#define LPC17xx_SPI_SSP1_PCLK \
(LPC17xx_CCLK / LPC17xx_SPI_SSP1CLKDIV)
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an SPI driver.
*/
typedef struct SPIDriver SPIDriver;
/**
* @brief SPI notification callback type.
*
* @param[in] spip pointer to the @p SPIDriver object triggering the
* callback
*/
typedef void (*spicallback_t)(SPIDriver *spip);
/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
* @brief Operation complete callback or @p NULL.
*/
spicallback_t end_cb;
/* End of the mandatory fields.*/
/**
* @brief The chip select line port.
*/
ioportid_t ssport;
/**
* @brief The chip select line pad number.
*/
uint16_t sspad;
/**
* @brief SSP CR0 initialization data.
*/
uint16_t cr0;
/**
* @brief SSP CPSR initialization data.
*/
uint32_t cpsr;
} SPIConfig;
/**
* @brief Structure representing a SPI driver.
*/
struct SPIDriver {
/**
* @brief Driver state.
*/
spistate_t state;
/**
* @brief Current configuration data.
*/
const SPIConfig *config;
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif /* SPI_USE_WAIT */
#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* SPI_USE_MUTUAL_EXCLUSION */
#if defined(SPI_DRIVER_EXT_FIELDS)
SPI_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the SSP registers block.
*/
LPC_SSP_TypeDef *ssp;
/**
* @brief Number of bytes yet to be received.
*/
uint32_t rxcnt;
/**
* @brief Receive pointer or @p NULL.
*/
void *rxptr;
/**
* @brief Number of bytes yet to be transmitted.
*/
uint32_t txcnt;
/**
* @brief Transmit pointer or @p NULL.
*/
const void *txptr;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC17xx_SPI_USE_SSP0 && !defined(__DOXYGEN__)
extern SPIDriver SPID1;
#endif
#if LPC17xx_SPI_USE_SSP1 && !defined(__DOXYGEN__)
extern SPIDriver SPID2;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void spi_lld_init(void);
void spi_lld_start(SPIDriver *spip);
void spi_lld_stop(SPIDriver *spip);
void spi_lld_select(SPIDriver *spip);
void spi_lld_unselect(SPIDriver *spip);
void spi_lld_ignore(SPIDriver *spip, size_t n);
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf);
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SPI */
#endif /* _SPI_LLD_H_ */
/** @} */

View File

@ -1,64 +1,64 @@
/**************************************************************************//**
* @file system_LPC17xx.h
* @brief CMSIS Cortex-M3 Device Peripheral Access Layer Header File
* for the NXP LPC17xx Device Series
* @version V1.02
* @date 08. September 2009
*
* @note
* Copyright (C) 2009 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#ifndef __SYSTEM_LPC17xx_H
#define __SYSTEM_LPC17xx_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
/**
* Initialize the system
*
* @param none
* @return none
*
* @brief Setup the microcontroller system.
* Initialize the System and update the SystemCoreClock variable.
*/
extern void SystemInit (void);
/**
* Update SystemCoreClock variable
*
* @param none
* @return none
*
* @brief Updates the SystemCoreClock with current core Clock
* retrieved from cpu registers.
*/
extern void SystemCoreClockUpdate (void);
#ifdef __cplusplus
}
#endif
#endif /* __SYSTEM_LPC17xx_H */
/**************************************************************************//**
* @file system_LPC17xx.h
* @brief CMSIS Cortex-M3 Device Peripheral Access Layer Header File
* for the NXP LPC17xx Device Series
* @version V1.02
* @date 08. September 2009
*
* @note
* Copyright (C) 2009 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#ifndef __SYSTEM_LPC17xx_H
#define __SYSTEM_LPC17xx_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
/**
* Initialize the system
*
* @param none
* @return none
*
* @brief Setup the microcontroller system.
* Initialize the System and update the SystemCoreClock variable.
*/
extern void SystemInit (void);
/**
* Update SystemCoreClock variable
*
* @param none
* @return none
*
* @brief Updates the SystemCoreClock with current core Clock
* retrieved from cpu registers.
*/
extern void SystemCoreClockUpdate (void);
#ifdef __cplusplus
}
#endif
#endif /* __SYSTEM_LPC17xx_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,212 +1,212 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC43xx DAC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/dac_lld.c
* @brief LPC43xx DAC subsystem low level driver source.
*
* @addtogroup DAC
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_DAC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief CHN1 driver identifier.*/
DACDriver DACD1;
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
static lpc_dma_lli_config_t lpc_dac_lli[2] __attribute__((aligned(0x10)));
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Shared end/half-of-tx service routine.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] flags pre-shifted content of the ISR register
*/
static void dac_serve_dma_interrupt(DACDriver *dacp, uint32_t flags) {
if ((flags & (1 << LPC_DAC_DMA_CHANNEL)) != 0) {
_dac_isr_error_code(dacp, flags); /* DMA errors handling.*/
}
else {
if (dacp->half_buffer == false) {
_dac_isr_half_code(dacp);
dacp->half_buffer = true;
}
else {
_dac_isr_full_code(dacp);
dacp->half_buffer = false;
}
}
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level DAC driver initialization.
*
* @notapi
*/
void dac_lld_init(void) {
dacObjectInit(&DACD1);
}
/**
* @brief Configures and activates the DAC peripheral.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
void dac_lld_start(DACDriver *dacp) {
if (dacp->state == DAC_STOP) {
LPC_CCU1->CLK_APB3_DAC_CFG = 1; /* Enable clock. */
LPC_DAC->CR = 0;
LPC_DAC->CTRL = 0;
LPC_DAC->CNTVAL = LPC_BASE_APB3_CLK/dacp->config->frequency;
dmaMuxSet(PERIPHERAL15, 0);
dmaChannelAllocate(LPC_DAC_DMA_CHANNEL, \
(lpc_dmaisr_t)dac_serve_dma_interrupt, \
(void *)dacp);
}
}
/**
* @brief Deactivates the DAC peripheral.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
void dac_lld_stop(DACDriver *dacp) {
/* If in ready state then disables the DAC clock.*/
if (dacp->state == DAC_READY) {
/* DMA disable.*/
dmaChannelDisable(LPC_DAC_DMA_CHANNEL);
dmaChannelRelease(LPC_DAC_DMA_CHANNEL);
LPC_DAC->CTRL = 0; /* Disable DAC */
LPC_CCU1->CLK_APB3_DAC_CFG = 0; /* Disable clock. */
}
}
/**
* @brief Sends data over the DAC bus.
* @details This asynchronous function starts a transmit operation.
* @post At the end of the operation the configured callback is invoked.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @notapi
*/
void dac_lld_start_conversion(DACDriver *dacp) {
dacp->half_buffer = false;
uint32_t dma_ch_config;
/* DMA configuration */
lpc_dac_lli[0].srcaddr = (uint32_t) &dacp->samples[0];
lpc_dac_lli[0].dstaddr = (uint32_t)&LPC_DAC->CR;
lpc_dac_lli[0].lli = (uint32_t) &lpc_dac_lli[1];
lpc_dac_lli[0].control =
DMA_CTRL_TRANSFER_SIZE(dacp->depth/2) |
DMA_CTRL_SRC_BSIZE_1 |
DMA_CTRL_DST_BSIZE_1 |
DMA_CTRL_SRC_WIDTH_WORD |
DMA_CTRL_DST_WIDTH_WORD |
DMA_CTRL_SRC_AHBM0 |
DMA_CTRL_DST_AHBM1 |
DMA_CTRL_SRC_INC |
DMA_CTRL_DST_NOINC |
DMA_CTRL_PROT1_USER |
DMA_CTRL_PROT2_NONBUFF |
DMA_CTRL_PROT3_NONCACHE |
DMA_CTRL_INT;
lpc_dac_lli[1].srcaddr = (uint32_t) &dacp->samples[dacp->depth/2];
lpc_dac_lli[1].dstaddr = lpc_dac_lli[0].dstaddr;
lpc_dac_lli[1].control = lpc_dac_lli[0].control;
if (dacp->grpp->circular == true) {
lpc_dac_lli[1].lli = (uint32_t) &lpc_dac_lli[0];
}
else {
lpc_dac_lli[1].lli = 0;
}
dma_ch_config =
DMA_CFG_CH_ENABLE |
DMA_CFG_DST_PERIPH(PERIPHERAL15) |
DMA_CFG_FCTRL_M2P |
DMA_CFG_IE |
DMA_CFG_ITC;
dmaChannelSrcAddr(LPC_DAC_DMA_CHANNEL, lpc_dac_lli[0].srcaddr);
dmaChannelDstAddr(LPC_DAC_DMA_CHANNEL, lpc_dac_lli[0].dstaddr);
dmaChannelLinkedList(LPC_DAC_DMA_CHANNEL, lpc_dac_lli[0].lli, DMA_LLI_AHBM0);
dmaChannelControl(LPC_DAC_DMA_CHANNEL, lpc_dac_lli[0].control);
dmaChannelConfig(LPC_DAC_DMA_CHANNEL, dma_ch_config);
LPC_DAC->CTRL = DACCTRL_DMA_ENA | DACCTRL_CNT_ENA | DACCTRL_DBLBUF_ENA;
}
void dac_lld_stop_conversion(DACDriver *dacp) {
/* If in active state then disables the DAC.*/
if (dacp->state == DAC_ACTIVE) {
/* DMA disable.*/
dmaChannelDisable(LPC_DAC_DMA_CHANNEL);
}
};
#endif /* HAL_USE_DAC */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC43xx DAC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/dac_lld.c
* @brief LPC43xx DAC subsystem low level driver source.
*
* @addtogroup DAC
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_DAC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief CHN1 driver identifier.*/
DACDriver DACD1;
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
static lpc_dma_lli_config_t lpc_dac_lli[2] __attribute__((aligned(0x10)));
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Shared end/half-of-tx service routine.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] flags pre-shifted content of the ISR register
*/
static void dac_serve_dma_interrupt(DACDriver *dacp, uint32_t flags) {
if ((flags & (1 << LPC_DAC_DMA_CHANNEL)) != 0) {
_dac_isr_error_code(dacp, flags); /* DMA errors handling.*/
}
else {
if (dacp->half_buffer == false) {
_dac_isr_half_code(dacp);
dacp->half_buffer = true;
}
else {
_dac_isr_full_code(dacp);
dacp->half_buffer = false;
}
}
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level DAC driver initialization.
*
* @notapi
*/
void dac_lld_init(void) {
dacObjectInit(&DACD1);
}
/**
* @brief Configures and activates the DAC peripheral.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
void dac_lld_start(DACDriver *dacp) {
if (dacp->state == DAC_STOP) {
LPC_CCU1->CLK_APB3_DAC_CFG = 1; /* Enable clock. */
LPC_DAC->CR = 0;
LPC_DAC->CTRL = 0;
LPC_DAC->CNTVAL = LPC_BASE_APB3_CLK/dacp->config->frequency;
dmaMuxSet(PERIPHERAL15, 0);
dmaChannelAllocate(LPC_DAC_DMA_CHANNEL, \
(lpc_dmaisr_t)dac_serve_dma_interrupt, \
(void *)dacp);
}
}
/**
* @brief Deactivates the DAC peripheral.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
void dac_lld_stop(DACDriver *dacp) {
/* If in ready state then disables the DAC clock.*/
if (dacp->state == DAC_READY) {
/* DMA disable.*/
dmaChannelDisable(LPC_DAC_DMA_CHANNEL);
dmaChannelRelease(LPC_DAC_DMA_CHANNEL);
LPC_DAC->CTRL = 0; /* Disable DAC */
LPC_CCU1->CLK_APB3_DAC_CFG = 0; /* Disable clock. */
}
}
/**
* @brief Sends data over the DAC bus.
* @details This asynchronous function starts a transmit operation.
* @post At the end of the operation the configured callback is invoked.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @notapi
*/
void dac_lld_start_conversion(DACDriver *dacp) {
dacp->half_buffer = false;
uint32_t dma_ch_config;
/* DMA configuration */
lpc_dac_lli[0].srcaddr = (uint32_t) &dacp->samples[0];
lpc_dac_lli[0].dstaddr = (uint32_t)&LPC_DAC->CR;
lpc_dac_lli[0].lli = (uint32_t) &lpc_dac_lli[1];
lpc_dac_lli[0].control =
DMA_CTRL_TRANSFER_SIZE(dacp->depth/2) |
DMA_CTRL_SRC_BSIZE_1 |
DMA_CTRL_DST_BSIZE_1 |
DMA_CTRL_SRC_WIDTH_WORD |
DMA_CTRL_DST_WIDTH_WORD |
DMA_CTRL_SRC_AHBM0 |
DMA_CTRL_DST_AHBM1 |
DMA_CTRL_SRC_INC |
DMA_CTRL_DST_NOINC |
DMA_CTRL_PROT1_USER |
DMA_CTRL_PROT2_NONBUFF |
DMA_CTRL_PROT3_NONCACHE |
DMA_CTRL_INT;
lpc_dac_lli[1].srcaddr = (uint32_t) &dacp->samples[dacp->depth/2];
lpc_dac_lli[1].dstaddr = lpc_dac_lli[0].dstaddr;
lpc_dac_lli[1].control = lpc_dac_lli[0].control;
if (dacp->grpp->circular == true) {
lpc_dac_lli[1].lli = (uint32_t) &lpc_dac_lli[0];
}
else {
lpc_dac_lli[1].lli = 0;
}
dma_ch_config =
DMA_CFG_CH_ENABLE |
DMA_CFG_DST_PERIPH(PERIPHERAL15) |
DMA_CFG_FCTRL_M2P |
DMA_CFG_IE |
DMA_CFG_ITC;
dmaChannelSrcAddr(LPC_DAC_DMA_CHANNEL, lpc_dac_lli[0].srcaddr);
dmaChannelDstAddr(LPC_DAC_DMA_CHANNEL, lpc_dac_lli[0].dstaddr);
dmaChannelLinkedList(LPC_DAC_DMA_CHANNEL, lpc_dac_lli[0].lli, DMA_LLI_AHBM0);
dmaChannelControl(LPC_DAC_DMA_CHANNEL, lpc_dac_lli[0].control);
dmaChannelConfig(LPC_DAC_DMA_CHANNEL, dma_ch_config);
LPC_DAC->CTRL = DACCTRL_DMA_ENA | DACCTRL_CNT_ENA | DACCTRL_DBLBUF_ENA;
}
void dac_lld_stop_conversion(DACDriver *dacp) {
/* If in active state then disables the DAC.*/
if (dacp->state == DAC_ACTIVE) {
/* DMA disable.*/
dmaChannelDisable(LPC_DAC_DMA_CHANNEL);
}
};
#endif /* HAL_USE_DAC */
/** @} */

View File

@ -1,207 +1,207 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC43xx DAC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/dac_lld.h
* @brief LPC43xx DAC subsystem low level driver header.
*
* @addtogroup DAC
* @{
*/
#ifndef _DAC_LLD_H_
#define _DAC_LLD_H_
#if HAL_USE_DAC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define DACR_BIAS (1UL << 16)
#define DACCTRL_INT_DMA_REQ (1UL << 0)
#define DACCTRL_DBLBUF_ENA (1UL << 1)
#define DACCTRL_CNT_ENA (1UL << 2)
#define DACCTRL_DMA_ENA (1UL << 3)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief DMA stream used for DAC CHN1 TX operations.
* @note This option is only available on platforms with enhanced DMA.
*/
#if !defined(LPC_DAC_DMA_CHANNEL) || defined(__DOXYGEN__)
#define LPC_DAC_DMA_CHANNEL DMA_CHANNEL5
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !defined(LPC_DMA_REQUIRED)
#define LPC_DMA_REQUIRED
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an DAC driver.
*/
typedef struct DACDriver DACDriver;
/**
* @brief Type representing a DAC sample.
*/
typedef uint32_t dacsample_t;
/**
* @brief DAC notification callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
* callback
*/
typedef void (*dacendcallback_t)(DACDriver *dacp, const dacsample_t * samples, size_t pos);
/**
* @brief DAC notification callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
* callback
*/
typedef void (*dacerrcallback_t)(DACDriver *dacp, uint32_t flags);
/**
* @brief DAC Conversion group structure.
*/
typedef struct {
/**
* @brief Number of DAC channels.
*/
uint16_t num_channels;
/**
* @brief Operation complete callback or @p NULL.
*/
dacendcallback_t end_cb;
/**
* @brief Error handling callback or @p NULL.
*/
dacerrcallback_t error_cb;
/**
* @brief Error handling callback or @p NULL.
*/
bool circular;
} DACConversionGroup;
/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
* @brief Timer frequency in Hz.
*/
uint32_t frequency;
/* End of the mandatory fields.*/
} DACConfig;
/**
* @brief Structure representing a DAC driver.
*/
struct DACDriver {
/**
* @brief Driver state.
*/
dacstate_t state;
/**
* @brief Conversion group.
*/
const DACConversionGroup *grpp;
/**
* @brief Samples buffer pointer.
*/
const dacsample_t *samples;
/**
* @brief Samples buffer size.
*/
uint16_t depth;
/**
* @brief Current configuration data.
*/
const DACConfig *config;
#if DAC_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif /* DAC_USE_WAIT */
#if DAC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* DAC_USE_MUTUAL_EXCLUSION */
#if defined(DAC_DRIVER_EXT_FIELDS)
DAC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Half buffer indicator.
*/
bool_t half_buffer;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
extern DACDriver DACD1;
#ifdef __cplusplus
extern "C" {
#endif
void dac_lld_init(void);
void dac_lld_start(DACDriver *dacp);
void dac_lld_stop(DACDriver *dacp);
void dac_lld_start_conversion(DACDriver *dacp);
void dac_lld_stop_conversion(DACDriver *dacp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_DAC */
#endif /* _DAC_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC43xx DAC driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/dac_lld.h
* @brief LPC43xx DAC subsystem low level driver header.
*
* @addtogroup DAC
* @{
*/
#ifndef _DAC_LLD_H_
#define _DAC_LLD_H_
#if HAL_USE_DAC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define DACR_BIAS (1UL << 16)
#define DACCTRL_INT_DMA_REQ (1UL << 0)
#define DACCTRL_DBLBUF_ENA (1UL << 1)
#define DACCTRL_CNT_ENA (1UL << 2)
#define DACCTRL_DMA_ENA (1UL << 3)
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief DMA stream used for DAC CHN1 TX operations.
* @note This option is only available on platforms with enhanced DMA.
*/
#if !defined(LPC_DAC_DMA_CHANNEL) || defined(__DOXYGEN__)
#define LPC_DAC_DMA_CHANNEL DMA_CHANNEL5
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !defined(LPC_DMA_REQUIRED)
#define LPC_DMA_REQUIRED
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an DAC driver.
*/
typedef struct DACDriver DACDriver;
/**
* @brief Type representing a DAC sample.
*/
typedef uint32_t dacsample_t;
/**
* @brief DAC notification callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
* callback
*/
typedef void (*dacendcallback_t)(DACDriver *dacp, const dacsample_t * samples, size_t pos);
/**
* @brief DAC notification callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
* callback
*/
typedef void (*dacerrcallback_t)(DACDriver *dacp, uint32_t flags);
/**
* @brief DAC Conversion group structure.
*/
typedef struct {
/**
* @brief Number of DAC channels.
*/
uint16_t num_channels;
/**
* @brief Operation complete callback or @p NULL.
*/
dacendcallback_t end_cb;
/**
* @brief Error handling callback or @p NULL.
*/
dacerrcallback_t error_cb;
/**
* @brief Error handling callback or @p NULL.
*/
bool circular;
} DACConversionGroup;
/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
* @brief Timer frequency in Hz.
*/
uint32_t frequency;
/* End of the mandatory fields.*/
} DACConfig;
/**
* @brief Structure representing a DAC driver.
*/
struct DACDriver {
/**
* @brief Driver state.
*/
dacstate_t state;
/**
* @brief Conversion group.
*/
const DACConversionGroup *grpp;
/**
* @brief Samples buffer pointer.
*/
const dacsample_t *samples;
/**
* @brief Samples buffer size.
*/
uint16_t depth;
/**
* @brief Current configuration data.
*/
const DACConfig *config;
#if DAC_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif /* DAC_USE_WAIT */
#if DAC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* DAC_USE_MUTUAL_EXCLUSION */
#if defined(DAC_DRIVER_EXT_FIELDS)
DAC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Half buffer indicator.
*/
bool_t half_buffer;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
extern DACDriver DACD1;
#ifdef __cplusplus
extern "C" {
#endif
void dac_lld_init(void);
void dac_lld_start(DACDriver *dacp);
void dac_lld_stop(DACDriver *dacp);
void dac_lld_start_conversion(DACDriver *dacp);
void dac_lld_stop_conversion(DACDriver *dacp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_DAC */
#endif /* _DAC_LLD_H_ */
/** @} */

View File

@ -1,338 +1,338 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/gpt_lld.c
* @brief LPC43xx GPT subsystem low level driver source.
*
* @addtogroup GPT
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief GPT1 driver identifier.
* @note The driver GPT1 allocates the complex timer TIM0 when enabled.
*/
#if LPC_GPT_USE_TIM0 || defined(__DOXYGEN__)
GPTDriver GPTD1;
#endif
/**
* @brief GPT2 driver identifier.
* @note The driver GPT2 allocates the timer TIM1 when enabled.
*/
#if LPC_GPT_USE_TIM1 || defined(__DOXYGEN__)
GPTDriver GPTD2;
#endif
/**
* @brief GPT3 driver identifier.
* @note The driver GPT3 allocates the timer TIM2 when enabled.
*/
#if LPC_GPT_USE_TIM2 || defined(__DOXYGEN__)
GPTDriver GPTD3;
#endif
/**
* @brief GPT4 driver identifier.
* @note The driver GPT4 allocates the timer TIM3 when enabled.
*/
#if LPC_GPT_USE_TIM3 || defined(__DOXYGEN__)
GPTDriver GPTD4;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Shared IRQ handler.
*
* @param[in] gptp pointer to a @p GPTDriver object
*/
static void gpt_lld_serve_interrupt(GPTDriver *gptp) {
gptp->tmr->IR = 1; /* Clear interrupt on match MR0.*/
if (gptp->state == GPT_ONESHOT) {
gptp->state = GPT_READY; /* Back in GPT_READY state. */
gpt_lld_stop_timer(gptp); /* Timer automatically stopped. */
}
gptp->config->callback(gptp);
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if LPC_GPT_USE_TIM0
/**
* @brief TIM0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector70) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD1);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_TIM0 */
#if LPC_GPT_USE_TIM1
/**
* @brief TIM1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector74) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD2);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_TIM0 */
#if LPC_GPT_USE_TIM2
/**
* @brief TIM2 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector78) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD3);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_TIM2 */
#if LPC_GPT_USE_TIM3
/**
* @brief TIM3 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector7C) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD4);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_TIM3 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level GPT driver initialization.
*
* @notapi
*/
void gpt_lld_init(void) {
#if LPC_GPT_USE_TIM0
/* Driver initialization.*/
GPTD1.tmr = LPC_TIMER0;
gptObjectInit(&GPTD1);
#endif
#if LPC_GPT_USE_TIM1
/* Driver initialization.*/
GPTD2.tmr = LPC_TIMER1;
gptObjectInit(&GPTD2);
#endif
#if LPC_GPT_USE_TIM2
/* Driver initialization.*/
GPTD3.tmr = LPC_TIMER2;
gptObjectInit(&GPTD3);
#endif
#if LPC_GPT_USE_TIM3
/* Driver initialization.*/
GPTD4.tmr = LPC_TIMER3;
gptObjectInit(&GPTD4);
#endif
}
/**
* @brief Configures and activates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_start(GPTDriver *gptp) {
uint32_t pr;
if (gptp->state == GPT_STOP) {
/* Clock activation.*/
#if LPC_GPT_USE_TIM0
if (&GPTD1 == gptp) {
LPC_CCU1->CLK_M4_TIMER0_CFG = 1;
nvicEnableVector(TIMER0_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
#if LPC_GPT_USE_TIM1
if (&GPTD2 == gptp) {
LPC_CCU1->CLK_M4_TIMER1_CFG = 1;
nvicEnableVector(TIMER1_IRQn, CORTEX_PRIORITY_MASK(3));
}
#endif
#if LPC_GPT_USE_TIM2
if (&GPTD3 == gptp) {
LPC_CCU1->CLK_M4_TIMER2_CFG = 1;
nvicEnableVector(TIMER2_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
#if LPC_GPT_USE_TIM3
if (&GPTD4 == gptp) {
LPC_CCU1->CLK_M4_TIMER3_CFG = 1;
nvicEnableVector(TIMER3_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
}
/* Prescaler value calculation.*/
pr = (uint16_t)((LPC_BASE_M4_CLK/ gptp->config->frequency) - 1);
chDbgAssert(((uint32_t)(pr + 1) * gptp->config->frequency) == LPC_BASE_M4_CLK,
"gpt_lld_start(), #1", "invalid frequency");
/* Timer configuration.*/
gptp->tmr->PR = pr;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
}
/**
* @brief Deactivates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop(GPTDriver *gptp) {
if (gptp->state == GPT_READY) {
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
#if LPC_GPT_USE_TIM0
if (&GPTD1 == gptp) {
nvicDisableVector(TIMER0_IRQn);
LPC_CCU1->CLK_M4_TIMER0_CFG = 0;
}
#endif
#if LPC_GPT_USE_TIM1
if (&GPTD2 == gptp) {
nvicDisableVector(TIMER1_IRQn);
LPC_CCU1->CLK_M4_TIMER1_CFG = 0;
}
#endif
#if LPC_GPT_USE_TIM2
if (&GPTD3 == gptp) {
nvicDisableVector(TIMER2_IRQn);
LPC_CCU1->CLK_M4_TIMER2_CFG = 0;
}
#endif
#if LPC_GPT_USE_TIM3
if (&GPTD4 == gptp) {
nvicDisableVector(TIMER3_IRQn);
LPC_CCU1->CLK_M4_TIMER3_CFG = 0;
}
#endif
}
}
/**
* @brief Starts the timer in continuous mode.
*
* @param[in] gptp pointer to the @p GPTDriver object
* @param[in] interval period in ticks
*
* @notapi
*/
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) {
gptp->tmr->MR[0] = interval - 1;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 3; /* IRQ and clr TC on match MR0. */
gptp->tmr->TCR = 2; /* Reset counter and prescaler. */
gptp->tmr->TCR = 1; /* Timer enabled. */
}
/**
* @brief Stops the timer.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop_timer(GPTDriver *gptp) {
gptp->tmr->IR = 1;
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
}
/**
* @brief Starts the timer in one shot mode and waits for completion.
* @details This function specifically polls the timer waiting for completion
* in order to not have extra delays caused by interrupt servicing,
* this function is only recommended for short delays.
*
* @param[in] gptp pointer to the @p GPTDriver object
* @param[in] interval time interval in ticks
*
* @notapi
*/
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) {
gptp->tmr->MR[0] = interval - 1;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 4; /* Stop TC on match MR0. */
gptp->tmr->TCR = 2; /* Reset counter and prescaler. */
gptp->tmr->TCR = 1; /* Timer enabled. */
while (gptp->tmr->TCR & 1)
;
}
#endif /* HAL_USE_GPT */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/gpt_lld.c
* @brief LPC43xx GPT subsystem low level driver source.
*
* @addtogroup GPT
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief GPT1 driver identifier.
* @note The driver GPT1 allocates the complex timer TIM0 when enabled.
*/
#if LPC_GPT_USE_TIM0 || defined(__DOXYGEN__)
GPTDriver GPTD1;
#endif
/**
* @brief GPT2 driver identifier.
* @note The driver GPT2 allocates the timer TIM1 when enabled.
*/
#if LPC_GPT_USE_TIM1 || defined(__DOXYGEN__)
GPTDriver GPTD2;
#endif
/**
* @brief GPT3 driver identifier.
* @note The driver GPT3 allocates the timer TIM2 when enabled.
*/
#if LPC_GPT_USE_TIM2 || defined(__DOXYGEN__)
GPTDriver GPTD3;
#endif
/**
* @brief GPT4 driver identifier.
* @note The driver GPT4 allocates the timer TIM3 when enabled.
*/
#if LPC_GPT_USE_TIM3 || defined(__DOXYGEN__)
GPTDriver GPTD4;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Shared IRQ handler.
*
* @param[in] gptp pointer to a @p GPTDriver object
*/
static void gpt_lld_serve_interrupt(GPTDriver *gptp) {
gptp->tmr->IR = 1; /* Clear interrupt on match MR0.*/
if (gptp->state == GPT_ONESHOT) {
gptp->state = GPT_READY; /* Back in GPT_READY state. */
gpt_lld_stop_timer(gptp); /* Timer automatically stopped. */
}
gptp->config->callback(gptp);
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if LPC_GPT_USE_TIM0
/**
* @brief TIM0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector70) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD1);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_TIM0 */
#if LPC_GPT_USE_TIM1
/**
* @brief TIM1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector74) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD2);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_TIM0 */
#if LPC_GPT_USE_TIM2
/**
* @brief TIM2 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector78) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD3);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_TIM2 */
#if LPC_GPT_USE_TIM3
/**
* @brief TIM3 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector7C) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD4);
CH_IRQ_EPILOGUE();
}
#endif /* LPC_GPT_USE_TIM3 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level GPT driver initialization.
*
* @notapi
*/
void gpt_lld_init(void) {
#if LPC_GPT_USE_TIM0
/* Driver initialization.*/
GPTD1.tmr = LPC_TIMER0;
gptObjectInit(&GPTD1);
#endif
#if LPC_GPT_USE_TIM1
/* Driver initialization.*/
GPTD2.tmr = LPC_TIMER1;
gptObjectInit(&GPTD2);
#endif
#if LPC_GPT_USE_TIM2
/* Driver initialization.*/
GPTD3.tmr = LPC_TIMER2;
gptObjectInit(&GPTD3);
#endif
#if LPC_GPT_USE_TIM3
/* Driver initialization.*/
GPTD4.tmr = LPC_TIMER3;
gptObjectInit(&GPTD4);
#endif
}
/**
* @brief Configures and activates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_start(GPTDriver *gptp) {
uint32_t pr;
if (gptp->state == GPT_STOP) {
/* Clock activation.*/
#if LPC_GPT_USE_TIM0
if (&GPTD1 == gptp) {
LPC_CCU1->CLK_M4_TIMER0_CFG = 1;
nvicEnableVector(TIMER0_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
#if LPC_GPT_USE_TIM1
if (&GPTD2 == gptp) {
LPC_CCU1->CLK_M4_TIMER1_CFG = 1;
nvicEnableVector(TIMER1_IRQn, CORTEX_PRIORITY_MASK(3));
}
#endif
#if LPC_GPT_USE_TIM2
if (&GPTD3 == gptp) {
LPC_CCU1->CLK_M4_TIMER2_CFG = 1;
nvicEnableVector(TIMER2_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
#if LPC_GPT_USE_TIM3
if (&GPTD4 == gptp) {
LPC_CCU1->CLK_M4_TIMER3_CFG = 1;
nvicEnableVector(TIMER3_IRQn, CORTEX_PRIORITY_MASK(2));
}
#endif
}
/* Prescaler value calculation.*/
pr = (uint16_t)((LPC_BASE_M4_CLK/ gptp->config->frequency) - 1);
chDbgAssert(((uint32_t)(pr + 1) * gptp->config->frequency) == LPC_BASE_M4_CLK,
"gpt_lld_start(), #1", "invalid frequency");
/* Timer configuration.*/
gptp->tmr->PR = pr;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
}
/**
* @brief Deactivates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop(GPTDriver *gptp) {
if (gptp->state == GPT_READY) {
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
#if LPC_GPT_USE_TIM0
if (&GPTD1 == gptp) {
nvicDisableVector(TIMER0_IRQn);
LPC_CCU1->CLK_M4_TIMER0_CFG = 0;
}
#endif
#if LPC_GPT_USE_TIM1
if (&GPTD2 == gptp) {
nvicDisableVector(TIMER1_IRQn);
LPC_CCU1->CLK_M4_TIMER1_CFG = 0;
}
#endif
#if LPC_GPT_USE_TIM2
if (&GPTD3 == gptp) {
nvicDisableVector(TIMER2_IRQn);
LPC_CCU1->CLK_M4_TIMER2_CFG = 0;
}
#endif
#if LPC_GPT_USE_TIM3
if (&GPTD4 == gptp) {
nvicDisableVector(TIMER3_IRQn);
LPC_CCU1->CLK_M4_TIMER3_CFG = 0;
}
#endif
}
}
/**
* @brief Starts the timer in continuous mode.
*
* @param[in] gptp pointer to the @p GPTDriver object
* @param[in] interval period in ticks
*
* @notapi
*/
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) {
gptp->tmr->MR[0] = interval - 1;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 3; /* IRQ and clr TC on match MR0. */
gptp->tmr->TCR = 2; /* Reset counter and prescaler. */
gptp->tmr->TCR = 1; /* Timer enabled. */
}
/**
* @brief Stops the timer.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop_timer(GPTDriver *gptp) {
gptp->tmr->IR = 1;
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
}
/**
* @brief Starts the timer in one shot mode and waits for completion.
* @details This function specifically polls the timer waiting for completion
* in order to not have extra delays caused by interrupt servicing,
* this function is only recommended for short delays.
*
* @param[in] gptp pointer to the @p GPTDriver object
* @param[in] interval time interval in ticks
*
* @notapi
*/
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) {
gptp->tmr->MR[0] = interval - 1;
gptp->tmr->IR = 1;
gptp->tmr->MCR = 4; /* Stop TC on match MR0. */
gptp->tmr->TCR = 2; /* Reset counter and prescaler. */
gptp->tmr->TCR = 1; /* Timer enabled. */
while (gptp->tmr->TCR & 1)
;
}
#endif /* HAL_USE_GPT */
/** @} */

View File

@ -1,208 +1,208 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/gpt_lld.h
* @brief LPC43xx GPT subsystem low level driver header.
*
* @addtogroup GPT
* @{
*/
#ifndef _GPT_LLD_H_
#define _GPT_LLD_H_
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief GPT1 driver enable switch.
* @details If set to @p TRUE the support for GPT1 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_GPT_USE_TIM0) || defined(__DOXYGEN__)
#define LPC_GPT_USE_TIM0 TRUE
#endif
/**
* @brief GPT2 driver enable switch.
* @details If set to @p TRUE the support for GPT2 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_GPT_USE_TIM1) || defined(__DOXYGEN__)
#define LPC_GPT_USE_TIM1 TRUE
#endif
/**
* @brief GPT3 driver enable switch.
* @details If set to @p TRUE the support for GPT3 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_GPT_USE_TIM2) || defined(__DOXYGEN__)
#define LPC_GPT_USE_TIM2 TRUE
#endif
/**
* @brief GPT4 driver enable switch.
* @details If set to @p TRUE the support for GPT4 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_GPT_USE_TIM3) || defined(__DOXYGEN__)
#define LPC_GPT_USE_TIM3 TRUE
#endif
/**
* @brief GPT1 interrupt priority level setting.
*/
#if !defined(LPC_GPT_TIM0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_GPT_TIM0_IRQ_PRIORITY 2
#endif
/**
* @brief GPT2 interrupt priority level setting.
*/
#if !defined(LPC_GPT_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_GPT_TIM1_IRQ_PRIORITY 2
#endif
/**
* @brief GPT3 interrupt priority level setting.
*/
#if !defined(LPC_GPT_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_GPT_TIM2_IRQ_PRIORITY 2
#endif
/**
* @brief GPT4 interrupt priority level setting.
*/
#if !defined(LPC_GPT_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_GPT_TIM3_IRQ_PRIORITY 2
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !LPC_GPT_USE_TIM0 && !LPC_GPT_USE_TIM1 && \
!LPC_GPT_USE_TIM2 && !LPC_GPT_USE_TIM3
#error "GPT driver activated but no CT peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief GPT frequency type.
*/
typedef uint32_t gptfreq_t;
/**
* @brief GPT counter type.
*/
typedef uint32_t gptcnt_t;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
gptfreq_t frequency;
/**
* @brief Timer callback pointer.
* @note This callback is invoked on GPT counter events.
*/
gptcallback_t callback;
/* End of the mandatory fields.*/
} GPTConfig;
/**
* @brief Structure representing a GPT driver.
*/
struct GPTDriver {
/**
* @brief Driver state.
*/
gptstate_t state;
/**
* @brief Current configuration data.
*/
const GPTConfig *config;
/* End of the mandatory fields.*/
/**
* @brief Timer base clock.
*/
uint32_t clock;
/**
* @brief Pointer to the LPC_TIMERx registers block.
*/
LPC_TIMERn_Type *tmr;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC_GPT_USE_TIM0 && !defined(__DOXYGEN__)
extern GPTDriver GPTD1;
#endif
#if LPC_GPT_USE_TIM1 && !defined(__DOXYGEN__)
extern GPTDriver GPTD2;
#endif
#if LPC_GPT_USE_TIM2 && !defined(__DOXYGEN__)
extern GPTDriver GPTD3;
#endif
#if LPC_GPT_USE_TIM3 && !defined(__DOXYGEN__)
extern GPTDriver GPTD4;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void gpt_lld_init(void);
void gpt_lld_start(GPTDriver *gptp);
void gpt_lld_stop(GPTDriver *gptp);
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period);
void gpt_lld_stop_timer(GPTDriver *gptp);
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_GPT */
#endif /* _GPT_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/gpt_lld.h
* @brief LPC43xx GPT subsystem low level driver header.
*
* @addtogroup GPT
* @{
*/
#ifndef _GPT_LLD_H_
#define _GPT_LLD_H_
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief GPT1 driver enable switch.
* @details If set to @p TRUE the support for GPT1 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_GPT_USE_TIM0) || defined(__DOXYGEN__)
#define LPC_GPT_USE_TIM0 TRUE
#endif
/**
* @brief GPT2 driver enable switch.
* @details If set to @p TRUE the support for GPT2 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_GPT_USE_TIM1) || defined(__DOXYGEN__)
#define LPC_GPT_USE_TIM1 TRUE
#endif
/**
* @brief GPT3 driver enable switch.
* @details If set to @p TRUE the support for GPT3 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_GPT_USE_TIM2) || defined(__DOXYGEN__)
#define LPC_GPT_USE_TIM2 TRUE
#endif
/**
* @brief GPT4 driver enable switch.
* @details If set to @p TRUE the support for GPT4 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_GPT_USE_TIM3) || defined(__DOXYGEN__)
#define LPC_GPT_USE_TIM3 TRUE
#endif
/**
* @brief GPT1 interrupt priority level setting.
*/
#if !defined(LPC_GPT_TIM0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_GPT_TIM0_IRQ_PRIORITY 2
#endif
/**
* @brief GPT2 interrupt priority level setting.
*/
#if !defined(LPC_GPT_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_GPT_TIM1_IRQ_PRIORITY 2
#endif
/**
* @brief GPT3 interrupt priority level setting.
*/
#if !defined(LPC_GPT_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_GPT_TIM2_IRQ_PRIORITY 2
#endif
/**
* @brief GPT4 interrupt priority level setting.
*/
#if !defined(LPC_GPT_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_GPT_TIM3_IRQ_PRIORITY 2
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !LPC_GPT_USE_TIM0 && !LPC_GPT_USE_TIM1 && \
!LPC_GPT_USE_TIM2 && !LPC_GPT_USE_TIM3
#error "GPT driver activated but no CT peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief GPT frequency type.
*/
typedef uint32_t gptfreq_t;
/**
* @brief GPT counter type.
*/
typedef uint32_t gptcnt_t;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
gptfreq_t frequency;
/**
* @brief Timer callback pointer.
* @note This callback is invoked on GPT counter events.
*/
gptcallback_t callback;
/* End of the mandatory fields.*/
} GPTConfig;
/**
* @brief Structure representing a GPT driver.
*/
struct GPTDriver {
/**
* @brief Driver state.
*/
gptstate_t state;
/**
* @brief Current configuration data.
*/
const GPTConfig *config;
/* End of the mandatory fields.*/
/**
* @brief Timer base clock.
*/
uint32_t clock;
/**
* @brief Pointer to the LPC_TIMERx registers block.
*/
LPC_TIMERn_Type *tmr;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC_GPT_USE_TIM0 && !defined(__DOXYGEN__)
extern GPTDriver GPTD1;
#endif
#if LPC_GPT_USE_TIM1 && !defined(__DOXYGEN__)
extern GPTDriver GPTD2;
#endif
#if LPC_GPT_USE_TIM2 && !defined(__DOXYGEN__)
extern GPTDriver GPTD3;
#endif
#if LPC_GPT_USE_TIM3 && !defined(__DOXYGEN__)
extern GPTDriver GPTD4;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void gpt_lld_init(void);
void gpt_lld_start(GPTDriver *gptp);
void gpt_lld_stop(GPTDriver *gptp);
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period);
void gpt_lld_stop_timer(GPTDriver *gptp);
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_GPT */
#endif /* _GPT_LLD_H_ */
/** @} */

View File

@ -1,194 +1,194 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC43xx HAL driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/hal_lld.c
* @brief LPC43xx HAL subsystem low level driver source.
*
* @addtogroup HAL
* @{
*/
#include "ch.h"
#include "hal.h"
/**
* @brief Register missing in NXP header file.
*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
#define LPC_IDIV_ARRAY_NUM 5
#define LPC_BASE_CLK_ARRAY_NUM 27
const uint32_t lpc_idiv[LPC_IDIV_ARRAY_NUM] = {
(((uint32_t)LPC_IDIVA_SRC) << 24) | (LPC_IDIVA_DIV << 2) | (!LPC_IDIVA_ENABLE),
(((uint32_t)LPC_IDIVB_SRC) << 24) | (LPC_IDIVB_DIV << 2) | (!LPC_IDIVB_ENABLE),
(((uint32_t)LPC_IDIVC_SRC) << 24) | (LPC_IDIVC_DIV << 2) | (!LPC_IDIVC_ENABLE),
(((uint32_t)LPC_IDIVD_SRC) << 24) | (LPC_IDIVD_DIV << 2) | (!LPC_IDIVD_ENABLE),
(((uint32_t)LPC_IDIVE_SRC) << 24) | (LPC_IDIVE_DIV << 2) | (!LPC_IDIVE_ENABLE)
};
const uint32_t lpc_base_clk[LPC_BASE_CLK_ARRAY_NUM] = {
(CLK_SEL_PLL0USB << 24) | (!LPC_BASE_USB0_CLK_ENABLE),
(((uint32_t)LPC_BASE_PERIPH_CLK_SRC) << 24) | (!LPC_BASE_PERIPH_CLK_ENABLE),
(((uint32_t)LPC_BASE_USB1_CLK_SRC) << 24) | (!LPC_BASE_USB1_CLK_ENABLE),
(((uint32_t)LPC_BASE_M4_CLK_SRC) << 24) | (!LPC_BASE_M4_CLK_ENABLE),
(((uint32_t)LPC_BASE_SPIFI_CLK_SRC) << 24) | (!LPC_BASE_SPIFI_CLK_ENABLE),
(((uint32_t)LPC_BASE_SPI_CLK_SRC) << 24) | (!LPC_BASE_SPI_CLK_ENABLE),
(((uint32_t)LPC_BASE_PHY_RX_CLK_SRC) << 24) | (!LPC_BASE_PHY_RX_CLK_ENABLE),
(((uint32_t)LPC_BASE_PHY_TX_CLK_SRC) << 24) | (!LPC_BASE_PHY_TX_CLK_ENABLE),
(((uint32_t)LPC_BASE_APB1_CLK_SRC) << 24) | (!LPC_BASE_APB1_CLK_ENABLE),
(((uint32_t)LPC_BASE_APB3_CLK_SRC) << 24) | (!LPC_BASE_APB3_CLK_ENABLE),
(((uint32_t)LPC_BASE_LCD_CLK_SRC) << 24) | (!LPC_BASE_LCD_CLK_ENABLE),
0,
(((uint32_t)LPC_BASE_SDIO_CLK_SRC) << 24) | (!LPC_BASE_SDIO_CLK_ENABLE),
(((uint32_t)LPC_BASE_SSP0_CLK_SRC) << 24) | (!LPC_BASE_SSP0_CLK_ENABLE),
(((uint32_t)LPC_BASE_SSP1_CLK_SRC) << 24) | (!LPC_BASE_SSP1_CLK_ENABLE),
(((uint32_t)LPC_BASE_UART0_CLK_SRC) << 24) | (!LPC_BASE_UART0_CLK_ENABLE),
(((uint32_t)LPC_BASE_UART1_CLK_SRC) << 24) | (!LPC_BASE_UART1_CLK_ENABLE),
(((uint32_t)LPC_BASE_UART2_CLK_SRC) << 24) | (!LPC_BASE_UART2_CLK_ENABLE),
(((uint32_t)LPC_BASE_UART3_CLK_SRC) << 24) | (!LPC_BASE_UART3_CLK_ENABLE),
(((uint32_t)LPC_BASE_OUT_CLK_SRC) << 24) | (!LPC_BASE_OUT_CLK_ENABLE),
0,
0,
0,
0,
(((uint32_t)LPC_BASE_APLL_CLK_SRC) << 24) | (!LPC_BASE_APLL_CLK_ENABLE),
(((uint32_t)LPC_BASE_CGU_OUT0_CLK_SRC) << 24) | (!LPC_BASE_CGU_OUT0_CLK_ENABLE),
(((uint32_t)LPC_BASE_CGU_OUT1_CLK_SRC) << 24) | (!LPC_BASE_CGU_OUT1_CLK_ENABLE)
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level HAL driver initialization.
*
* @notapi
*/
void hal_lld_init(void) {
/* SysTick initialization using the system clock.*/
nvicSetSystemHandlerPriority(HANDLER_SYSTICK, CORTEX_PRIORITY_SYSTICK);
SysTick->LOAD = LPC_BASE_M4_CLK / CH_FREQUENCY - 1;
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_ENABLE_Msk |
SysTick_CTRL_TICKINT_Msk;
/* DWT cycle counter enable.*/
SCS_DEMCR |= SCS_DEMCR_TRCENA;
DWT_CTRL |= DWT_CTRL_CYCCNTENA;
#if defined(LPC_DMA_REQUIRED)
dmaInit();
#endif
}
/**
* @brief LPC43xx clocks and PLL initialization.
* @note All the involved constants come from the file @p board.h.
* @note This function must be invoked only after the system reset.
*
* @special
*/
void lpc_clock_init(void) {
uint32_t i;
volatile uint32_t * preg;
#if !LPC_FLASHLESS
/* Flash wait states setting.*/
preg = (volatile uint32_t *) 0x40043120; /* FLASHCFGA */
*preg = (1UL<< 31) | (LPC_FLASHCFG_FLASHTIM << 12) | 0x3A;
*(preg + 1)= (1UL<< 31) | (LPC_FLASHCFG_FLASHTIM << 12) | 0x3A; /* FLASHCFGB 0x40043124 */
#endif
/* System oscillator initialization if required.*/
#if LPC_XTAL_ENABLE
LPC_CGU->XTAL_OSC_CTRL = (LPC_OSCRANGE << 2); /* Enable Main oscillator */
for(i = 0; i < 1000000; i++)
; /* Wait for main oscillator to be ready */
LPC_CGU->BASE_M4_CLK = (CLK_SEL_XTAL << 24); /* Select the crystal oscillator */
/* as clock source for BASE_M4_CLK */
#else
LPC_CGU->BASE_M4_CLK = (CLK_SEL_IRC << 24); /* Select IRC as clock source for BASE_M4_CLK */
#endif
LPC_CGU->PLL1_CTRL = 0; /* Power-down PLL1 enabled by Boot ROM */
#if LPC_PLL1_ENABLE /* PLL1 works in direct or non-integer mode. */
/* Set PLL1 to FCLKOUT/2 */
LPC_CGU->PLL1_CTRL = (1UL << 24) | (LPC_PLL1_CTRL_MSEL << 16) |
(LPC_PLL1_CTRL_NSEL << 12);
while (!(LPC_CGU->PLL1_STAT & 0x01))
; /* Wait for PLL1 locked */
LPC_CGU->BASE_M4_CLK = (CLK_SEL_PLL1 << 24); /* Select PPL1 clock as source for BASE_M4_CLK. */
for(i = 0; i < 200000; i++)
; /* Wait */
#if LPC_PLL1_POSTDIV_ENABLE
LPC_CGU->PLL1_CTRL |= (LPC_PLL1_CTRL_PSEL << 8);
#else
LPC_CGU->PLL1_CTRL |= (1UL << 7); /* Set PLL1 to FCLKOUT > 156 MHz*/
#endif
#endif /* LPC_PLL1_ENABLE == TRUE */
/* Config integer dividers. */
preg = &LPC_CGU->IDIVA_CTRL;
for (i = 0; i < LPC_IDIV_ARRAY_NUM; i++) {
*preg = lpc_idiv[i];
preg++;
}
/* Config base clocks. */
preg = &LPC_CGU->BASE_USB0_CLK;
for (i = 0; i < LPC_BASE_CLK_ARRAY_NUM; i++) {
*preg = lpc_base_clk[i];
preg++;
}
#if LPC_PLL0USB0_ENABLE
#error "PPL0USB0 not supported."
#endif /* LPC_PLL0USB_ENABLE == TRUE */
#if LPC_PLL0AUDIO_ENABLE
#error "PLL0AUDIO not supported."
#endif /* LPC_PLL0AUDIO == TRUE */
}
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC43xx HAL driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/hal_lld.c
* @brief LPC43xx HAL subsystem low level driver source.
*
* @addtogroup HAL
* @{
*/
#include "ch.h"
#include "hal.h"
/**
* @brief Register missing in NXP header file.
*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
#define LPC_IDIV_ARRAY_NUM 5
#define LPC_BASE_CLK_ARRAY_NUM 27
const uint32_t lpc_idiv[LPC_IDIV_ARRAY_NUM] = {
(((uint32_t)LPC_IDIVA_SRC) << 24) | (LPC_IDIVA_DIV << 2) | (!LPC_IDIVA_ENABLE),
(((uint32_t)LPC_IDIVB_SRC) << 24) | (LPC_IDIVB_DIV << 2) | (!LPC_IDIVB_ENABLE),
(((uint32_t)LPC_IDIVC_SRC) << 24) | (LPC_IDIVC_DIV << 2) | (!LPC_IDIVC_ENABLE),
(((uint32_t)LPC_IDIVD_SRC) << 24) | (LPC_IDIVD_DIV << 2) | (!LPC_IDIVD_ENABLE),
(((uint32_t)LPC_IDIVE_SRC) << 24) | (LPC_IDIVE_DIV << 2) | (!LPC_IDIVE_ENABLE)
};
const uint32_t lpc_base_clk[LPC_BASE_CLK_ARRAY_NUM] = {
(CLK_SEL_PLL0USB << 24) | (!LPC_BASE_USB0_CLK_ENABLE),
(((uint32_t)LPC_BASE_PERIPH_CLK_SRC) << 24) | (!LPC_BASE_PERIPH_CLK_ENABLE),
(((uint32_t)LPC_BASE_USB1_CLK_SRC) << 24) | (!LPC_BASE_USB1_CLK_ENABLE),
(((uint32_t)LPC_BASE_M4_CLK_SRC) << 24) | (!LPC_BASE_M4_CLK_ENABLE),
(((uint32_t)LPC_BASE_SPIFI_CLK_SRC) << 24) | (!LPC_BASE_SPIFI_CLK_ENABLE),
(((uint32_t)LPC_BASE_SPI_CLK_SRC) << 24) | (!LPC_BASE_SPI_CLK_ENABLE),
(((uint32_t)LPC_BASE_PHY_RX_CLK_SRC) << 24) | (!LPC_BASE_PHY_RX_CLK_ENABLE),
(((uint32_t)LPC_BASE_PHY_TX_CLK_SRC) << 24) | (!LPC_BASE_PHY_TX_CLK_ENABLE),
(((uint32_t)LPC_BASE_APB1_CLK_SRC) << 24) | (!LPC_BASE_APB1_CLK_ENABLE),
(((uint32_t)LPC_BASE_APB3_CLK_SRC) << 24) | (!LPC_BASE_APB3_CLK_ENABLE),
(((uint32_t)LPC_BASE_LCD_CLK_SRC) << 24) | (!LPC_BASE_LCD_CLK_ENABLE),
0,
(((uint32_t)LPC_BASE_SDIO_CLK_SRC) << 24) | (!LPC_BASE_SDIO_CLK_ENABLE),
(((uint32_t)LPC_BASE_SSP0_CLK_SRC) << 24) | (!LPC_BASE_SSP0_CLK_ENABLE),
(((uint32_t)LPC_BASE_SSP1_CLK_SRC) << 24) | (!LPC_BASE_SSP1_CLK_ENABLE),
(((uint32_t)LPC_BASE_UART0_CLK_SRC) << 24) | (!LPC_BASE_UART0_CLK_ENABLE),
(((uint32_t)LPC_BASE_UART1_CLK_SRC) << 24) | (!LPC_BASE_UART1_CLK_ENABLE),
(((uint32_t)LPC_BASE_UART2_CLK_SRC) << 24) | (!LPC_BASE_UART2_CLK_ENABLE),
(((uint32_t)LPC_BASE_UART3_CLK_SRC) << 24) | (!LPC_BASE_UART3_CLK_ENABLE),
(((uint32_t)LPC_BASE_OUT_CLK_SRC) << 24) | (!LPC_BASE_OUT_CLK_ENABLE),
0,
0,
0,
0,
(((uint32_t)LPC_BASE_APLL_CLK_SRC) << 24) | (!LPC_BASE_APLL_CLK_ENABLE),
(((uint32_t)LPC_BASE_CGU_OUT0_CLK_SRC) << 24) | (!LPC_BASE_CGU_OUT0_CLK_ENABLE),
(((uint32_t)LPC_BASE_CGU_OUT1_CLK_SRC) << 24) | (!LPC_BASE_CGU_OUT1_CLK_ENABLE)
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level HAL driver initialization.
*
* @notapi
*/
void hal_lld_init(void) {
/* SysTick initialization using the system clock.*/
nvicSetSystemHandlerPriority(HANDLER_SYSTICK, CORTEX_PRIORITY_SYSTICK);
SysTick->LOAD = LPC_BASE_M4_CLK / CH_FREQUENCY - 1;
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_ENABLE_Msk |
SysTick_CTRL_TICKINT_Msk;
/* DWT cycle counter enable.*/
SCS_DEMCR |= SCS_DEMCR_TRCENA;
DWT_CTRL |= DWT_CTRL_CYCCNTENA;
#if defined(LPC_DMA_REQUIRED)
dmaInit();
#endif
}
/**
* @brief LPC43xx clocks and PLL initialization.
* @note All the involved constants come from the file @p board.h.
* @note This function must be invoked only after the system reset.
*
* @special
*/
void lpc_clock_init(void) {
uint32_t i;
volatile uint32_t * preg;
#if !LPC_FLASHLESS
/* Flash wait states setting.*/
preg = (volatile uint32_t *) 0x40043120; /* FLASHCFGA */
*preg = (1UL<< 31) | (LPC_FLASHCFG_FLASHTIM << 12) | 0x3A;
*(preg + 1)= (1UL<< 31) | (LPC_FLASHCFG_FLASHTIM << 12) | 0x3A; /* FLASHCFGB 0x40043124 */
#endif
/* System oscillator initialization if required.*/
#if LPC_XTAL_ENABLE
LPC_CGU->XTAL_OSC_CTRL = (LPC_OSCRANGE << 2); /* Enable Main oscillator */
for(i = 0; i < 1000000; i++)
; /* Wait for main oscillator to be ready */
LPC_CGU->BASE_M4_CLK = (CLK_SEL_XTAL << 24); /* Select the crystal oscillator */
/* as clock source for BASE_M4_CLK */
#else
LPC_CGU->BASE_M4_CLK = (CLK_SEL_IRC << 24); /* Select IRC as clock source for BASE_M4_CLK */
#endif
LPC_CGU->PLL1_CTRL = 0; /* Power-down PLL1 enabled by Boot ROM */
#if LPC_PLL1_ENABLE /* PLL1 works in direct or non-integer mode. */
/* Set PLL1 to FCLKOUT/2 */
LPC_CGU->PLL1_CTRL = (1UL << 24) | (LPC_PLL1_CTRL_MSEL << 16) |
(LPC_PLL1_CTRL_NSEL << 12);
while (!(LPC_CGU->PLL1_STAT & 0x01))
; /* Wait for PLL1 locked */
LPC_CGU->BASE_M4_CLK = (CLK_SEL_PLL1 << 24); /* Select PPL1 clock as source for BASE_M4_CLK. */
for(i = 0; i < 200000; i++)
; /* Wait */
#if LPC_PLL1_POSTDIV_ENABLE
LPC_CGU->PLL1_CTRL |= (LPC_PLL1_CTRL_PSEL << 8);
#else
LPC_CGU->PLL1_CTRL |= (1UL << 7); /* Set PLL1 to FCLKOUT > 156 MHz*/
#endif
#endif /* LPC_PLL1_ENABLE == TRUE */
/* Config integer dividers. */
preg = &LPC_CGU->IDIVA_CTRL;
for (i = 0; i < LPC_IDIV_ARRAY_NUM; i++) {
*preg = lpc_idiv[i];
preg++;
}
/* Config base clocks. */
preg = &LPC_CGU->BASE_USB0_CLK;
for (i = 0; i < LPC_BASE_CLK_ARRAY_NUM; i++) {
*preg = lpc_base_clk[i];
preg++;
}
#if LPC_PLL0USB0_ENABLE
#error "PPL0USB0 not supported."
#endif /* LPC_PLL0USB_ENABLE == TRUE */
#if LPC_PLL0AUDIO_ENABLE
#error "PLL0AUDIO not supported."
#endif /* LPC_PLL0AUDIO == TRUE */
}
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -1,201 +1,201 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC43xx DMA driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/LPC43xx_dma.c
* @brief DMA driver code.
*
* @addtogroup LPC43xx_DMA
* @details DMA sharing helper driver. In the LPC43xx the DMA streams are a
* shared resource, this driver allows to allocate and free DMA
* streams at runtime in order to allow all the other device
* drivers to coordinate the access to the resource.
* @note The DMA ISR handlers are all declared into this module because
* sharing, the various device drivers can associate a callback to
* ISRs when allocating streams.
* @{
*/
#include "ch.h"
#include "hal.h"
/* The following macro is only defined if some driver requiring DMA services
has been enabled.*/
#if defined(LPC_DMA_REQUIRED) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
lpc_dma_channel_config_t * \
_lpc_dma_channel_config[LPC_DMA_CHANNELS] = {
LPC_GPDMACH0, LPC_GPDMACH1, LPC_GPDMACH2, LPC_GPDMACH3, LPC_GPDMACH4,
LPC_GPDMACH5, LPC_GPDMACH6, LPC_GPDMACH7 };
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief DMA ISR redirector type.
*/
typedef struct {
lpc_dmaisr_t dma_func; /**< @brief DMA callback function. */
void *dma_param; /**< @brief DMA callback parameter. */
} dma_isr_redir_t;
/**
* @brief Mask of the allocated streams.
*/
static uint32_t dma_streams_mask;
/**
* @brief DMA IRQ redirectors.
*/
static dma_isr_redir_t dma_isr_redir[LPC_DMA_CHANNELS];
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief DMA interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector48) {
uint32_t irq_status;
uint32_t err_status;
uint8_t i;
CH_IRQ_PROLOGUE();
irq_status = LPC_GPDMA->INTTCSTAT;
LPC_GPDMA->INTTCCLEAR = irq_status; /* Clear DMA interrupt flag. */
err_status = LPC_GPDMA->INTERRSTAT;
LPC_GPDMA->INTERRCLR = err_status; /* Clear DMA error flag if any. */
for (i = 0; i < LPC_DMA_CHANNELS; i++) {
if (irq_status & (1UL << i)) {
if (dma_isr_redir[i].dma_func)
dma_isr_redir[i].dma_func(dma_isr_redir[i].dma_param, err_status);
}
}
CH_IRQ_EPILOGUE();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief LPC43xx DMA initialization.
*
* @init
*/
void dmaInit(void) {
uint8_t i;
/* Disable all channels */
for (i = 0; i < LPC_DMA_CHANNELS; i++)
_lpc_dma_channel_config[i]->config = 0;
LPC_GPDMA->INTTCCLEAR = 0xFF;
LPC_GPDMA->INTERRCLR = 0xFF;
LPC_GPDMA->CONFIG = DMACCONFIG_E; /* Enable DMA Controller, little-endian mode */
while((LPC_GPDMA->CONFIG & DMACCONFIG_E) != 0x01)
;
nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY));
}
/**
* @brief Allocates a DMA channel.
* @details The channel is allocated.
* @pre The channel must not be already in use or an error is returned.
* @post The channel is allocated and the default ISR handler redirected
* to the specified function.
* @post The channel must be freed using @p dmaChannelRelease() before it can
* be reused with another peripheral.
* @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmach DMA channel number
* @param[in] func handling function pointer, can be @p NULL
* @param[in] param a parameter to be passed to the handling function
* @return The operation status.
* @retval FALSE no error, stream taken.
* @retval TRUE error, stream already taken.
*
* @special
*/
bool_t dmaChannelAllocate(lpc_dma_channel_t dmach,
lpc_dmaisr_t func,
void *param) {
uint32_t channel;
channel = (1UL << dmach);
/* Checks if the channel is already taken.*/
if ((dma_streams_mask & channel) != 0)
return TRUE;
/* Marks the stream as allocated.*/
dma_isr_redir[dmach].dma_func = func;
dma_isr_redir[dmach].dma_param = param;
dma_streams_mask |= channel;
return FALSE;
}
/**
* @brief Releases a DMA channel.
* @details The channel is freed.
* Trying to release a unallocated channel is an illegal operation
* and is trapped if assertions are enabled.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post The channel is again available.
* @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmach DMA channel number
*
* @special
*/
void dmaChannelRelease(lpc_dma_channel_t dmach) {
uint32_t channel;
channel = (1UL << dmach);
/* Check if the streams is not taken.*/
chDbgAssert((dma_streams_mask & channel) != 0,
"dmaStreamRelease(), #1", "not allocated");
dma_streams_mask &= ~channel; /* Marks the stream as not allocated.*/
}
#endif /* LPC_DMA_REQUIRED */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC43xx DMA driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/LPC43xx_dma.c
* @brief DMA driver code.
*
* @addtogroup LPC43xx_DMA
* @details DMA sharing helper driver. In the LPC43xx the DMA streams are a
* shared resource, this driver allows to allocate and free DMA
* streams at runtime in order to allow all the other device
* drivers to coordinate the access to the resource.
* @note The DMA ISR handlers are all declared into this module because
* sharing, the various device drivers can associate a callback to
* ISRs when allocating streams.
* @{
*/
#include "ch.h"
#include "hal.h"
/* The following macro is only defined if some driver requiring DMA services
has been enabled.*/
#if defined(LPC_DMA_REQUIRED) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
lpc_dma_channel_config_t * \
_lpc_dma_channel_config[LPC_DMA_CHANNELS] = {
LPC_GPDMACH0, LPC_GPDMACH1, LPC_GPDMACH2, LPC_GPDMACH3, LPC_GPDMACH4,
LPC_GPDMACH5, LPC_GPDMACH6, LPC_GPDMACH7 };
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief DMA ISR redirector type.
*/
typedef struct {
lpc_dmaisr_t dma_func; /**< @brief DMA callback function. */
void *dma_param; /**< @brief DMA callback parameter. */
} dma_isr_redir_t;
/**
* @brief Mask of the allocated streams.
*/
static uint32_t dma_streams_mask;
/**
* @brief DMA IRQ redirectors.
*/
static dma_isr_redir_t dma_isr_redir[LPC_DMA_CHANNELS];
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief DMA interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector48) {
uint32_t irq_status;
uint32_t err_status;
uint8_t i;
CH_IRQ_PROLOGUE();
irq_status = LPC_GPDMA->INTTCSTAT;
LPC_GPDMA->INTTCCLEAR = irq_status; /* Clear DMA interrupt flag. */
err_status = LPC_GPDMA->INTERRSTAT;
LPC_GPDMA->INTERRCLR = err_status; /* Clear DMA error flag if any. */
for (i = 0; i < LPC_DMA_CHANNELS; i++) {
if (irq_status & (1UL << i)) {
if (dma_isr_redir[i].dma_func)
dma_isr_redir[i].dma_func(dma_isr_redir[i].dma_param, err_status);
}
}
CH_IRQ_EPILOGUE();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief LPC43xx DMA initialization.
*
* @init
*/
void dmaInit(void) {
uint8_t i;
/* Disable all channels */
for (i = 0; i < LPC_DMA_CHANNELS; i++)
_lpc_dma_channel_config[i]->config = 0;
LPC_GPDMA->INTTCCLEAR = 0xFF;
LPC_GPDMA->INTERRCLR = 0xFF;
LPC_GPDMA->CONFIG = DMACCONFIG_E; /* Enable DMA Controller, little-endian mode */
while((LPC_GPDMA->CONFIG & DMACCONFIG_E) != 0x01)
;
nvicEnableVector(DMA_IRQn, CORTEX_PRIORITY_MASK(LPC_DMA_IRQ_PRIORITY));
}
/**
* @brief Allocates a DMA channel.
* @details The channel is allocated.
* @pre The channel must not be already in use or an error is returned.
* @post The channel is allocated and the default ISR handler redirected
* to the specified function.
* @post The channel must be freed using @p dmaChannelRelease() before it can
* be reused with another peripheral.
* @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmach DMA channel number
* @param[in] func handling function pointer, can be @p NULL
* @param[in] param a parameter to be passed to the handling function
* @return The operation status.
* @retval FALSE no error, stream taken.
* @retval TRUE error, stream already taken.
*
* @special
*/
bool_t dmaChannelAllocate(lpc_dma_channel_t dmach,
lpc_dmaisr_t func,
void *param) {
uint32_t channel;
channel = (1UL << dmach);
/* Checks if the channel is already taken.*/
if ((dma_streams_mask & channel) != 0)
return TRUE;
/* Marks the stream as allocated.*/
dma_isr_redir[dmach].dma_func = func;
dma_isr_redir[dmach].dma_param = param;
dma_streams_mask |= channel;
return FALSE;
}
/**
* @brief Releases a DMA channel.
* @details The channel is freed.
* Trying to release a unallocated channel is an illegal operation
* and is trapped if assertions are enabled.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post The channel is again available.
* @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmach DMA channel number
*
* @special
*/
void dmaChannelRelease(lpc_dma_channel_t dmach) {
uint32_t channel;
channel = (1UL << dmach);
/* Check if the streams is not taken.*/
chDbgAssert((dma_streams_mask & channel) != 0,
"dmaStreamRelease(), #1", "not allocated");
dma_streams_mask &= ~channel; /* Marks the stream as not allocated.*/
}
#endif /* LPC_DMA_REQUIRED */
/** @} */

View File

@ -1,472 +1,472 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC43xx DMA driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/LPC43xx_dma.h
* @brief DMA driver header.
*
* @addtogroup LPC43xx_DMA
* @{
*/
#ifndef _LPC43xx_DMA_H_
#define _LPC43xx_DMA_H_
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define LPC_GPDMACH0 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x100))
#define LPC_GPDMACH1 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x120))
#define LPC_GPDMACH2 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x140))
#define LPC_GPDMACH3 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x160))
#define LPC_GPDMACH4 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x180))
#define LPC_GPDMACH5 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x1A0))
#define LPC_GPDMACH6 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x1C0))
#define LPC_GPDMACH7 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x1E0))
#define DMACCONFIG_E (1UL << 0)
#define DMACCONFIG_M (1UL << 1)
/**
* @brief Total number of DMA streams.
* @note This is the total number of streams among all the DMA units.
*/
#define LPC_DMA_CHANNELS 8
/**
* @name DMA control data configuration
* @{
*/
/**
* @brief DMA transfer size.
*
* @param[in] n DMA transfer size
*/
#define DMA_CTRL_TRANSFER_SIZE(n) (n)
/**
* @brief DMA source burst size.
*/
#define DMA_CTRL_SRC_BSIZE_1 (0 << 12)
#define DMA_CTRL_SRC_BSIZE_4 (1UL << 12)
#define DMA_CTRL_SRC_BSIZE_8 (2UL << 12)
#define DMA_CTRL_SRC_BSIZE_16 (3UL << 12)
#define DMA_CTRL_SRC_BSIZE_32 (4UL << 12)
#define DMA_CTRL_SRC_BSIZE_64 (5UL << 12)
#define DMA_CTRL_SRC_BSIZE_128 (6UL << 12)
#define DMA_CTRL_SRC_BSIZE_256 (7UL << 12)
/**
* @brief DMA destination burst size.
* @{
*/
#define DMA_CTRL_DST_BSIZE_1 (0 << 15)
#define DMA_CTRL_DST_BSIZE_4 (1UL << 15)
#define DMA_CTRL_DST_BSIZE_8 (2UL << 15)
#define DMA_CTRL_DST_BSIZE_16 (3UL << 15)
#define DMA_CTRL_DST_BSIZE_32 (4UL << 15)
#define DMA_CTRL_DST_BSIZE_64 (5UL << 15)
#define DMA_CTRL_DST_BSIZE_128 (6UL << 15)
#define DMA_CTRL_DST_BSIZE_256 (7UL << 15)
/** @} */
/**
* @name DMA source transfer width.
* @{
*/
#define DMA_CTRL_SRC_WIDTH_BYTE (0 << 18)
#define DMA_CTRL_SRC_WIDTH_HWORD (1UL << 18)
#define DMA_CTRL_SRC_WIDTH_WORD (2UL << 18)
/** @} */
/**
* @name DMA destination transfer width.
* @{
*/
#define DMA_CTRL_DST_WIDTH_BYTE (0 << 21)
#define DMA_CTRL_DST_WIDTH_HWORD (1UL << 21)
#define DMA_CTRL_DST_WIDTH_WORD (2UL << 21)
/**
* @name DMA source, source AHB master select.
* @{
*/
#define DMA_CTRL_SRC_AHBM0 (0 << 24)
#define DMA_CTRL_SRC_AHBM1 (1 << 24)
/** @} */
/**
* @name DMA destination AHB master select.
* @{
*/
#define DMA_CTRL_DST_AHBM0 (0 << 25)
#define DMA_CTRL_DST_AHBM1 (1 << 25)
/** @} */
/**
* @name DMA source increment after each transfer.
* @{
*/
#define DMA_CTRL_SRC_NOINC (0UL << 26)
#define DMA_CTRL_SRC_INC (1UL << 26)
/**
* @name DMA destination increment after each transfer.
* @{
*/
#define DMA_CTRL_DST_NOINC (0UL << 27)
#define DMA_CTRL_DST_INC (1UL << 27)
/**
* @name DMA bus access bits.
* @{
*/
#define DMA_CTRL_PROT1_USER (0 << 28)
#define DMA_CTRL_PROT1_PRIV (1UL << 28)
#define DMA_CTRL_PROT2_NONBUFF (0 << 29)
#define DMA_CTRL_PROT2_BUFF (1UL << 29)
#define DMA_CTRL_PROT3_NONCACHE (0 << 30)
#define DMA_CTRL_PROT3_CACHE (1UL << 30)
/** @} */
/**
* @name DMA terminal count interrupt enable.
* @{
*/
#define DMA_CTRL_INT (1UL << 31)
/** @} */
/**
* @name DMA channel enable.
* @{
*/
#define DMA_CFG_CH_ENABLE (1UL << 0)
/**
* @brief Source peripheral.
*
* @param[in] source source peripheral
*/
#define DMA_CFG_SRC_PERIPH(src) ((src) << 1)
/**
* @brief Destination peripheral.
*
* @param[in] destination destination peripheral
*/
#define DMA_CFG_DST_PERIPH(dst) ((dst) << 6)
/**
* @name Flow control and transfer type.
* @{
*/
#define DMA_CFG_FCTRL_M2M (0UL << 11)
#define DMA_CFG_FCTRL_M2P (1UL << 11)
#define DMA_CFG_FCTRL_P2M (2UL << 11)
#define DMA_CFG_FCTRL_P2P_DMA_CTRL (3UL << 11)
#define DMA_CFG_FCTRL_P2P_DST_CTRL (4UL << 11)
#define DMA_CFG_FCTRL_M2P_PER_CTRL (5UL << 11)
#define DMA_CFG_FCTRL_P2M_PER_CTRL (6UL << 11)
#define DMA_CFG_FCTRL_P2P_SRC_CTRL (7UL << 11)
/** @} */
/**
* @name Interrupt error mask.
* @{
*/
#define DMA_CFG_IE (1UL << 14)
/** @} */
/**
* @name Terminal count interrupt mask.
* @{
*/
#define DMA_CFG_ITC (1UL << 15)
/** @} */
/**
* @name Active.
* @note Read only
* @{
*/
#define DMA_CFG_ACTIVE (1UL << 17)
/** @} */
/**
* @name Halt.
* @{
*/
#define DMA_CFG_HALT (1UL << 18)
/** @} */
/** @} */
/**
* @name AHB master select for loading the next LLI.
* @{
*/
#define DMA_LLI_AHBM0 0
#define DMA_LLI_AHBM1 1
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief DMA interrupt priority level setting.
*/
#if !defined(LPC_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_DMA_IRQ_PRIORITY 3
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
typedef struct {
volatile uint32_t srcaddr; /**< @brief Source address. */
volatile uint32_t dstaddr; /**< @brief Destination address. */
volatile uint32_t lli; /**< @brief Linked List Item. */
volatile uint32_t control; /**< @brief Control. */
volatile uint32_t config; /**< @brief Configuration. */
} lpc_dma_channel_config_t;
typedef struct {
volatile uint32_t srcaddr; /**< @brief Source address. */
volatile uint32_t dstaddr; /**< @brief Destination address. */
volatile uint32_t lli; /**< @brief Linked List Item. */
volatile uint32_t control; /**< @brief Control. */
} lpc_dma_lli_config_t;
/**
* @brief DMA channel number.
*/
typedef enum {
DMA_CHANNEL0 = 0,
DMA_CHANNEL1 = 1,
DMA_CHANNEL2 = 2,
DMA_CHANNEL3 = 3,
DMA_CHANNEL4 = 4,
DMA_CHANNEL5 = 5,
DMA_CHANNEL6 = 6,
DMA_CHANNEL7 = 7
} lpc_dma_channel_t;
/**
* @brief DMA source or destination type.
*/
typedef enum {
PERIPHERAL0 = 0,
PERIPHERAL1 = 1,
PERIPHERAL2 = 2,
PERIPHERAL3 = 3,
PERIPHERAL4 = 4,
PERIPHERAL5 = 5,
PERIPHERAL6 = 6,
PERIPHERAL7 = 7,
PERIPHERAL8 = 8,
PERIPHERAL9 = 9,
PERIPHERAL10 = 10,
PERIPHERAL11 = 11,
PERIPHERAL12 = 12,
PERIPHERAL13 = 13,
PERIPHERAL14 = 14,
PERIPHERAL15 = 15
} lpc_dma_src_dst_t;
/**
* @brief LPC DMA ISR function type.
*
* @param[in] p parameter for the registered function
* @param[in] flags pre-shifted content of the xISR register, the bits
* are aligned to bit zero
*/
typedef void (*lpc_dmaisr_t)(void *p, uint32_t flags);
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Set dma peripheral connection.
*
* @param[in] periphn dma peripheral connection number
* @param[in] select selected peripheral
*
* @special
*/
#define dmaMuxSet(periphn, select) \
LPC_CREG->DMAMUX &= ~(3UL << ((periphn) * 2)); \
LPC_CREG->DMAMUX |= (select) << ((periphn) * 2)
/**
* @brief Associates a memory source to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a source address
*
* @special
*/
#define dmaChannelSrcAddr(dmach, addr) \
_lpc_dma_channel_config[dmach]->srcaddr = (uint32_t)(addr)
/**
* @brief Associates a memory destination to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a destination address
*
* @special
*/
#define dmaChannelDstAddr(dmach, addr) \
_lpc_dma_channel_config[dmach]->dstaddr = (uint32_t)(addr)
/**
* @brief Associates a linked list item address to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a linked list item
* @param[in] master AHB master select for loading next LLI, 0 or 1
*
* @special
*/
#define dmaChannelLinkedList(dmach, addr, master) \
_lpc_dma_channel_config[dmach]->lli = (((uint32_t)(addr)) | master)
/**
* @brief Set control configuration to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] ctrl control configuration value
*
* @special
*/
#define dmaChannelControl(dmach, ctrl) \
_lpc_dma_channel_config[dmach]->control = (ctrl)
/**
* @brief Set configuration to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaStreamAllocate().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmach DMA channel number
* @param[in] config dma channel configuration value
*
* @special
*/
#define dmaChannelConfig(dmach, cfg) \
_lpc_dma_channel_config[dmach]->config = (cfg)
/**
* @brief Trigger DMA software burst transfer request.
*
* @param[in] src peripheral source request
*
* @special
*/
#define dmaSoftBurstRequest(src) \
LPC_GPDMA->SOFTBREQ = (1UL << (src))
/**
* @brief Trigger DMA software single transfer request.
*
* @param[in] src peripheral source request
*
* @special
*/
#define dmaSoftSingleRequest(src) \
LPC_GPDMA->SOFTSREQ = (1UL << (src))
/**
* @brief DMA channel enable.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
*
* @special
*/
#define dmaChannelEnable(dmach) \
_lpc_dma_channel_config[dmach]->config |= (DMA_CFG_CH_ENABLE)
/**
* @brief DMA channel disable.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
*
* @special
*/
#define dmaChannelDisable(dmach) \
_lpc_dma_channel_config[dmach]->config &= ~(DMA_CFG_CH_ENABLE)
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
extern lpc_dma_channel_config_t * _lpc_dma_channel_config[];
#endif
#ifdef __cplusplus
extern "C" {
#endif
void dmaInit(void);
bool_t dmaChannelAllocate(lpc_dma_channel_t dmach,
lpc_dmaisr_t func,
void *param);
void dmaChannelRelease(lpc_dma_channel_t dmach);
#ifdef __cplusplus
}
#endif
#endif /* _LPC43xx_DMA_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
LPC43xx DMA driver - Copyright (C) 2013 Marcin Jokel
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/LPC43xx_dma.h
* @brief DMA driver header.
*
* @addtogroup LPC43xx_DMA
* @{
*/
#ifndef _LPC43xx_DMA_H_
#define _LPC43xx_DMA_H_
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define LPC_GPDMACH0 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x100))
#define LPC_GPDMACH1 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x120))
#define LPC_GPDMACH2 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x140))
#define LPC_GPDMACH3 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x160))
#define LPC_GPDMACH4 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x180))
#define LPC_GPDMACH5 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x1A0))
#define LPC_GPDMACH6 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x1C0))
#define LPC_GPDMACH7 ((lpc_dma_channel_config_t *) (LPC_GPDMA_BASE + 0x1E0))
#define DMACCONFIG_E (1UL << 0)
#define DMACCONFIG_M (1UL << 1)
/**
* @brief Total number of DMA streams.
* @note This is the total number of streams among all the DMA units.
*/
#define LPC_DMA_CHANNELS 8
/**
* @name DMA control data configuration
* @{
*/
/**
* @brief DMA transfer size.
*
* @param[in] n DMA transfer size
*/
#define DMA_CTRL_TRANSFER_SIZE(n) (n)
/**
* @brief DMA source burst size.
*/
#define DMA_CTRL_SRC_BSIZE_1 (0 << 12)
#define DMA_CTRL_SRC_BSIZE_4 (1UL << 12)
#define DMA_CTRL_SRC_BSIZE_8 (2UL << 12)
#define DMA_CTRL_SRC_BSIZE_16 (3UL << 12)
#define DMA_CTRL_SRC_BSIZE_32 (4UL << 12)
#define DMA_CTRL_SRC_BSIZE_64 (5UL << 12)
#define DMA_CTRL_SRC_BSIZE_128 (6UL << 12)
#define DMA_CTRL_SRC_BSIZE_256 (7UL << 12)
/**
* @brief DMA destination burst size.
* @{
*/
#define DMA_CTRL_DST_BSIZE_1 (0 << 15)
#define DMA_CTRL_DST_BSIZE_4 (1UL << 15)
#define DMA_CTRL_DST_BSIZE_8 (2UL << 15)
#define DMA_CTRL_DST_BSIZE_16 (3UL << 15)
#define DMA_CTRL_DST_BSIZE_32 (4UL << 15)
#define DMA_CTRL_DST_BSIZE_64 (5UL << 15)
#define DMA_CTRL_DST_BSIZE_128 (6UL << 15)
#define DMA_CTRL_DST_BSIZE_256 (7UL << 15)
/** @} */
/**
* @name DMA source transfer width.
* @{
*/
#define DMA_CTRL_SRC_WIDTH_BYTE (0 << 18)
#define DMA_CTRL_SRC_WIDTH_HWORD (1UL << 18)
#define DMA_CTRL_SRC_WIDTH_WORD (2UL << 18)
/** @} */
/**
* @name DMA destination transfer width.
* @{
*/
#define DMA_CTRL_DST_WIDTH_BYTE (0 << 21)
#define DMA_CTRL_DST_WIDTH_HWORD (1UL << 21)
#define DMA_CTRL_DST_WIDTH_WORD (2UL << 21)
/**
* @name DMA source, source AHB master select.
* @{
*/
#define DMA_CTRL_SRC_AHBM0 (0 << 24)
#define DMA_CTRL_SRC_AHBM1 (1 << 24)
/** @} */
/**
* @name DMA destination AHB master select.
* @{
*/
#define DMA_CTRL_DST_AHBM0 (0 << 25)
#define DMA_CTRL_DST_AHBM1 (1 << 25)
/** @} */
/**
* @name DMA source increment after each transfer.
* @{
*/
#define DMA_CTRL_SRC_NOINC (0UL << 26)
#define DMA_CTRL_SRC_INC (1UL << 26)
/**
* @name DMA destination increment after each transfer.
* @{
*/
#define DMA_CTRL_DST_NOINC (0UL << 27)
#define DMA_CTRL_DST_INC (1UL << 27)
/**
* @name DMA bus access bits.
* @{
*/
#define DMA_CTRL_PROT1_USER (0 << 28)
#define DMA_CTRL_PROT1_PRIV (1UL << 28)
#define DMA_CTRL_PROT2_NONBUFF (0 << 29)
#define DMA_CTRL_PROT2_BUFF (1UL << 29)
#define DMA_CTRL_PROT3_NONCACHE (0 << 30)
#define DMA_CTRL_PROT3_CACHE (1UL << 30)
/** @} */
/**
* @name DMA terminal count interrupt enable.
* @{
*/
#define DMA_CTRL_INT (1UL << 31)
/** @} */
/**
* @name DMA channel enable.
* @{
*/
#define DMA_CFG_CH_ENABLE (1UL << 0)
/**
* @brief Source peripheral.
*
* @param[in] source source peripheral
*/
#define DMA_CFG_SRC_PERIPH(src) ((src) << 1)
/**
* @brief Destination peripheral.
*
* @param[in] destination destination peripheral
*/
#define DMA_CFG_DST_PERIPH(dst) ((dst) << 6)
/**
* @name Flow control and transfer type.
* @{
*/
#define DMA_CFG_FCTRL_M2M (0UL << 11)
#define DMA_CFG_FCTRL_M2P (1UL << 11)
#define DMA_CFG_FCTRL_P2M (2UL << 11)
#define DMA_CFG_FCTRL_P2P_DMA_CTRL (3UL << 11)
#define DMA_CFG_FCTRL_P2P_DST_CTRL (4UL << 11)
#define DMA_CFG_FCTRL_M2P_PER_CTRL (5UL << 11)
#define DMA_CFG_FCTRL_P2M_PER_CTRL (6UL << 11)
#define DMA_CFG_FCTRL_P2P_SRC_CTRL (7UL << 11)
/** @} */
/**
* @name Interrupt error mask.
* @{
*/
#define DMA_CFG_IE (1UL << 14)
/** @} */
/**
* @name Terminal count interrupt mask.
* @{
*/
#define DMA_CFG_ITC (1UL << 15)
/** @} */
/**
* @name Active.
* @note Read only
* @{
*/
#define DMA_CFG_ACTIVE (1UL << 17)
/** @} */
/**
* @name Halt.
* @{
*/
#define DMA_CFG_HALT (1UL << 18)
/** @} */
/** @} */
/**
* @name AHB master select for loading the next LLI.
* @{
*/
#define DMA_LLI_AHBM0 0
#define DMA_LLI_AHBM1 1
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief DMA interrupt priority level setting.
*/
#if !defined(LPC_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_DMA_IRQ_PRIORITY 3
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
typedef struct {
volatile uint32_t srcaddr; /**< @brief Source address. */
volatile uint32_t dstaddr; /**< @brief Destination address. */
volatile uint32_t lli; /**< @brief Linked List Item. */
volatile uint32_t control; /**< @brief Control. */
volatile uint32_t config; /**< @brief Configuration. */
} lpc_dma_channel_config_t;
typedef struct {
volatile uint32_t srcaddr; /**< @brief Source address. */
volatile uint32_t dstaddr; /**< @brief Destination address. */
volatile uint32_t lli; /**< @brief Linked List Item. */
volatile uint32_t control; /**< @brief Control. */
} lpc_dma_lli_config_t;
/**
* @brief DMA channel number.
*/
typedef enum {
DMA_CHANNEL0 = 0,
DMA_CHANNEL1 = 1,
DMA_CHANNEL2 = 2,
DMA_CHANNEL3 = 3,
DMA_CHANNEL4 = 4,
DMA_CHANNEL5 = 5,
DMA_CHANNEL6 = 6,
DMA_CHANNEL7 = 7
} lpc_dma_channel_t;
/**
* @brief DMA source or destination type.
*/
typedef enum {
PERIPHERAL0 = 0,
PERIPHERAL1 = 1,
PERIPHERAL2 = 2,
PERIPHERAL3 = 3,
PERIPHERAL4 = 4,
PERIPHERAL5 = 5,
PERIPHERAL6 = 6,
PERIPHERAL7 = 7,
PERIPHERAL8 = 8,
PERIPHERAL9 = 9,
PERIPHERAL10 = 10,
PERIPHERAL11 = 11,
PERIPHERAL12 = 12,
PERIPHERAL13 = 13,
PERIPHERAL14 = 14,
PERIPHERAL15 = 15
} lpc_dma_src_dst_t;
/**
* @brief LPC DMA ISR function type.
*
* @param[in] p parameter for the registered function
* @param[in] flags pre-shifted content of the xISR register, the bits
* are aligned to bit zero
*/
typedef void (*lpc_dmaisr_t)(void *p, uint32_t flags);
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Set dma peripheral connection.
*
* @param[in] periphn dma peripheral connection number
* @param[in] select selected peripheral
*
* @special
*/
#define dmaMuxSet(periphn, select) \
LPC_CREG->DMAMUX &= ~(3UL << ((periphn) * 2)); \
LPC_CREG->DMAMUX |= (select) << ((periphn) * 2)
/**
* @brief Associates a memory source to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a source address
*
* @special
*/
#define dmaChannelSrcAddr(dmach, addr) \
_lpc_dma_channel_config[dmach]->srcaddr = (uint32_t)(addr)
/**
* @brief Associates a memory destination to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a destination address
*
* @special
*/
#define dmaChannelDstAddr(dmach, addr) \
_lpc_dma_channel_config[dmach]->dstaddr = (uint32_t)(addr)
/**
* @brief Associates a linked list item address to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] addr pointer to a linked list item
* @param[in] master AHB master select for loading next LLI, 0 or 1
*
* @special
*/
#define dmaChannelLinkedList(dmach, addr, master) \
_lpc_dma_channel_config[dmach]->lli = (((uint32_t)(addr)) | master)
/**
* @brief Set control configuration to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
* @param[in] ctrl control configuration value
*
* @special
*/
#define dmaChannelControl(dmach, ctrl) \
_lpc_dma_channel_config[dmach]->control = (ctrl)
/**
* @brief Set configuration to a DMA channel.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaStreamAllocate().
* @post After use the channel can be released using @p dmaStreamRelease().
*
* @param[in] dmach DMA channel number
* @param[in] config dma channel configuration value
*
* @special
*/
#define dmaChannelConfig(dmach, cfg) \
_lpc_dma_channel_config[dmach]->config = (cfg)
/**
* @brief Trigger DMA software burst transfer request.
*
* @param[in] src peripheral source request
*
* @special
*/
#define dmaSoftBurstRequest(src) \
LPC_GPDMA->SOFTBREQ = (1UL << (src))
/**
* @brief Trigger DMA software single transfer request.
*
* @param[in] src peripheral source request
*
* @special
*/
#define dmaSoftSingleRequest(src) \
LPC_GPDMA->SOFTSREQ = (1UL << (src))
/**
* @brief DMA channel enable.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
*
* @special
*/
#define dmaChannelEnable(dmach) \
_lpc_dma_channel_config[dmach]->config |= (DMA_CFG_CH_ENABLE)
/**
* @brief DMA channel disable.
* @note This function can be invoked in both ISR or thread context.
* @pre The channel must have been allocated using @p dmaChannelAllocate().
* @post After use the channel can be released using @p dmaChannelRelease().
*
* @param[in] dmach DMA channel number
*
* @special
*/
#define dmaChannelDisable(dmach) \
_lpc_dma_channel_config[dmach]->config &= ~(DMA_CFG_CH_ENABLE)
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
extern lpc_dma_channel_config_t * _lpc_dma_channel_config[];
#endif
#ifdef __cplusplus
extern "C" {
#endif
void dmaInit(void);
bool_t dmaChannelAllocate(lpc_dma_channel_t dmach,
lpc_dmaisr_t func,
void *param);
void dmaChannelRelease(lpc_dma_channel_t dmach);
#ifdef __cplusplus
}
#endif
#endif /* _LPC43xx_DMA_H_ */
/** @} */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,171 +1,171 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
This file has been contributed by:
Marcin Jokel.
*/
/**
* @file LPC43xx/pal_lld.c
* @brief LPC43xx GPIO low level driver code.
*
* @addtogroup PAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static void initgpio(ioportid_t port, const lpc_gpio_setup_t *config) {
LPC_GPIO_PORT->DIR[port] = config->dir;
LPC_GPIO_PORT->MASK[port] = 0;
LPC_GPIO_PORT->PIN[port] = config->data;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief LPC43xx I/O ports configuration.
* @details GPIO unit registers initialization.
*
* @param[in] config the LPC43xx ports configuration
*
* @notapi
*/
void _pal_lld_init(const PALConfig *config) {
initgpio(GPIO0, &config->P0);
initgpio(GPIO1, &config->P1);
initgpio(GPIO2, &config->P2);
initgpio(GPIO3, &config->P3);
#if LPC_HAS_GPIO4
initgpio(GPIO4, &config->P4);
#endif
initgpio(GPIO5, &config->P5);
#if LPC_HAS_GPIO6
initgpio(GPIO6, &config->P6);
#endif
#if LPC_HAS_GPIO7
initgpio(GPIO7, &config->P7);
#endif
}
/**
* @brief Reads a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @return The group logical states.
*
* @notapi
*/
uint32_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset) {
uint32_t p;
LPC_GPIO_PORT->MASK[port] = ~((mask) << offset);
p = LPC_GPIO_PORT->MPIN[port];
LPC_GPIO_PORT->MASK[port] = 0;
return p;
}
/**
* @brief Writes a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] bits bits to be written. Values exceeding the group width
* are masked.
*
* @notapi
*/
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset,
uint32_t bits) {
LPC_GPIO_PORT->MASK[port] = ~((mask) << offset);
LPC_GPIO_PORT->MPIN[port] = bits;
LPC_GPIO_PORT->MASK[port] = 0;
}
/**
* @brief Pads mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with
* high state.
* @note This function does not alter the @p PINSELx registers. Alternate
* functions setup must be handled by device-specific code.
*
* @param[in] port the port identifier
* @param[in] mask the group mask
* @param[in] mode the mode
*
* @notapi
*/
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode) {
switch (mode) {
case PAL_MODE_RESET:
case PAL_MODE_INPUT:
LPC_GPIO_PORT->DIR[port] &= ~mask;
break;
case PAL_MODE_UNCONNECTED:
palSetPort(port, PAL_WHOLE_PORT);
case PAL_MODE_OUTPUT_PUSHPULL:
LPC_GPIO_PORT->DIR[port] |= mask;
break;
}
}
#endif /* HAL_USE_PAL */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
This file has been contributed by:
Marcin Jokel.
*/
/**
* @file LPC43xx/pal_lld.c
* @brief LPC43xx GPIO low level driver code.
*
* @addtogroup PAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static void initgpio(ioportid_t port, const lpc_gpio_setup_t *config) {
LPC_GPIO_PORT->DIR[port] = config->dir;
LPC_GPIO_PORT->MASK[port] = 0;
LPC_GPIO_PORT->PIN[port] = config->data;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief LPC43xx I/O ports configuration.
* @details GPIO unit registers initialization.
*
* @param[in] config the LPC43xx ports configuration
*
* @notapi
*/
void _pal_lld_init(const PALConfig *config) {
initgpio(GPIO0, &config->P0);
initgpio(GPIO1, &config->P1);
initgpio(GPIO2, &config->P2);
initgpio(GPIO3, &config->P3);
#if LPC_HAS_GPIO4
initgpio(GPIO4, &config->P4);
#endif
initgpio(GPIO5, &config->P5);
#if LPC_HAS_GPIO6
initgpio(GPIO6, &config->P6);
#endif
#if LPC_HAS_GPIO7
initgpio(GPIO7, &config->P7);
#endif
}
/**
* @brief Reads a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @return The group logical states.
*
* @notapi
*/
uint32_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset) {
uint32_t p;
LPC_GPIO_PORT->MASK[port] = ~((mask) << offset);
p = LPC_GPIO_PORT->MPIN[port];
LPC_GPIO_PORT->MASK[port] = 0;
return p;
}
/**
* @brief Writes a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] bits bits to be written. Values exceeding the group width
* are masked.
*
* @notapi
*/
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset,
uint32_t bits) {
LPC_GPIO_PORT->MASK[port] = ~((mask) << offset);
LPC_GPIO_PORT->MPIN[port] = bits;
LPC_GPIO_PORT->MASK[port] = 0;
}
/**
* @brief Pads mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with
* high state.
* @note This function does not alter the @p PINSELx registers. Alternate
* functions setup must be handled by device-specific code.
*
* @param[in] port the port identifier
* @param[in] mask the group mask
* @param[in] mode the mode
*
* @notapi
*/
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode) {
switch (mode) {
case PAL_MODE_RESET:
case PAL_MODE_INPUT:
LPC_GPIO_PORT->DIR[port] &= ~mask;
break;
case PAL_MODE_UNCONNECTED:
palSetPort(port, PAL_WHOLE_PORT);
case PAL_MODE_OUTPUT_PUSHPULL:
LPC_GPIO_PORT->DIR[port] |= mask;
break;
}
}
#endif /* HAL_USE_PAL */
/** @} */

View File

@ -1,381 +1,381 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
This file has been contributed by:
Marcin Jokel.
*/
/**
* @file LPC43xx/pal_lld.h
* @brief LPC43xx GPIO low level driver header.
*
* @addtogroup PAL
* @{
*/
#ifndef _PAL_LLD_H_
#define _PAL_LLD_H_
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Unsupported modes and specific modes */
/*===========================================================================*/
#undef PAL_MODE_INPUT_PULLUP
#undef PAL_MODE_INPUT_PULLDOWN
#undef PAL_MODE_INPUT_ANALOG
#undef PAL_MODE_OUTPUT_OPENDRAIN
/*===========================================================================*/
/* I/O Ports Types and constants. */
/*===========================================================================*/
/**
* @brief GPIO port setup info.
*/
typedef struct {
/** Initial value for PIN register.*/
uint32_t data;
/** Initial value for DIR register.*/
uint32_t dir;
} lpc_gpio_setup_t;
/**
* @brief GPIO static initializer.
* @details An instance of this structure must be passed to @p palInit() at
* system startup time in order to initialized the digital I/O
* subsystem. This represents only the initial setup, specific pads
* or whole ports can be reprogrammed at later time.
* @note The @p IOCON block is not configured, initially all pins have
* enabled pullups and are programmed as GPIO. It is responsibility
* of the various drivers to reprogram the pins in the proper mode.
* Pins that are not handled by any driver may be programmed in
* @p board.c.
*/
typedef struct {
/** @brief GPIO 0 setup data.*/
lpc_gpio_setup_t P0;
/** @brief GPIO 1 setup data.*/
lpc_gpio_setup_t P1;
/** @brief GPIO 2 setup data.*/
lpc_gpio_setup_t P2;
/** @brief GPIO 3 setup data.*/
lpc_gpio_setup_t P3;
#if LPC_HAS_GPIO4
/** @brief GPIO 4 setup data.*/
lpc_gpio_setup_t P4;
#endif
/** @brief GPIO 5 setup data.*/
lpc_gpio_setup_t P5;
#if LPC_HAS_GPIO6
/** @brief GPIO 6 setup data.*/
lpc_gpio_setup_t P6;
#endif
#if LPC_HAS_GPIO7
/** @brief GPIO 7 setup data.*/
lpc_gpio_setup_t P7;
#endif
} PALConfig;
/**
* @brief Width, in bits, of an I/O port.
*/
#define PAL_IOPORTS_WIDTH 32
/**
* @brief Whole port mask.
* @brief This macro specifies all the valid bits into a port.
*/
#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFFFFF)
/**
* @brief Digital I/O port sized unsigned type.
*/
typedef uint32_t ioportmask_t;
/**
* @brief Digital I/O modes.
*/
typedef uint32_t iomode_t;
/**
* @brief Port Identifier.
*/
typedef uint32_t ioportid_t;
/*===========================================================================*/
/* I/O Ports Identifiers. */
/*===========================================================================*/
/**
* @brief GPIO0 port identifier.
*/
#define IOPORT1 0
#define GPIO0 0
/**
* @brief GPIO1 port identifier.
*/
#define IOPORT2 1
#define GPIO1 1
/**
* @brief GPIO2 port identifier.
*/
#define IOPORT3 2
#define GPIO2 2
/**
* @brief GPIO3 port identifier.
*/
#define IOPORT4 3
#define GPIO3 3
/**
* @brief GPIO4 port identifier.
*/
#define IOPORT5 4
#define GPIO4 4
/**
* @brief GPIO5 port identifier.
*/
#define IOPORT6 5
#define GPIO5 5
/**
* @brief GPIO6 port identifier.
*/
#define IOPORT7 6
#define GPIO6 6
/**
* @brief GPIO7 port identifier.
*/
#define IOPORT8 7
#define GPIO7 7
/*===========================================================================*/
/* Implementation, some of the following macros could be implemented as */
/* functions, if so please put them in pal_lld.c. */
/*===========================================================================*/
/**
* @brief Low level PAL subsystem initialization.
*
* @param[in] config architecture-dependent ports configuration
*
* @notapi
*/
#define pal_lld_init(config) _pal_lld_init(config)
/**
* @brief Reads the physical I/O port states.
*
* @param[in] port port identifier
* @return The port bits.
*
* @notapi
*/
#define pal_lld_readport(port) (LPC_GPIO_PORT->PIN[port])
/**
* @brief Reads the output latch.
* @details The purpose of this function is to read back the latched output
* value.
*
* @param[in] port port identifier
* @return The latched logical states.
*
* @notapi
*/
#define pal_lld_readlatch(port) (LPC_GPIO_PORT->PIN[port])
/**
* @brief Writes a bits mask on a I/O port.
*
* @param[in] port port identifier
* @param[in] bits bits to be written on the specified port
*
* @notapi
*/
#define pal_lld_writeport(port, bits) (LPC_GPIO_PORT->PIN[port] = (bits))
/**
* @brief Sets a bits mask on a I/O port.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] bits bits to be ORed on the specified port
*
* @notapi
*/
#define pal_lld_setport(port, bits) (LPC_GPIO_PORT->SET[port] = (bits))
/**
* @brief Clears a bits mask on a I/O port.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] bits bits to be cleared on the specified port
*
* @notapi
*/
#define pal_lld_clearport(port, bits) (LPC_GPIO_PORT->CLR[port] = (bits))
/**
* @brief Reads a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @return The group logical states.
*
* @notapi
*/
#define pal_lld_readgroup(port, mask, offset) \
_pal_lld_readgroup(port, mask, offset)
/**
* @brief Writes a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] bits bits to be written. Values exceeding the group width
* are masked.
*
* @notapi
*/
#define pal_lld_writegroup(port, mask, offset, bits) \
_pal_lld_writegroup(port, mask, offset, bits)
/**
* @brief Pads group mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
* @note Programming an unknown or unsupported mode is silently ignored.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] mode group mode
*
* @notapi
*/
#define pal_lld_setgroupmode(port, mask, offset, mode) \
_pal_lld_setgroupmode(port, mask << offset, mode)
/**
* @brief Writes a logical state on an output pad.
* @note This function is not meant to be invoked directly by the
* application code.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @param[in] bit logical value, the value must be @p PAL_LOW or
* @p PAL_HIGH
*
* @notapi
*/
#define pal_lld_writepad(port, pad, bit) \
((bit) == PAL_LOW) ? pal_lld_clearpad(port, pad) : \
pal_lld_setpad(port, pad)
/**
* @brief Sets a pad logical state to @p PAL_HIGH.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_setpad(port, pad) \
(LPC_GPIO_PORT->SET[port] = 1UL << (pad))
/**
* @brief Clears a pad logical state to @p PAL_LOW.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_clearpad(port, pad) \
(LPC_GPIO_PORT->CLR[port] = 1UL << (pad))
/**
* @brief Toggles a pad logical state.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_togglepad(port, pad) \
(LPC_GPIO_PORT->NOT[port] = 1UL << (pad))
#if !defined(__DOXYGEN__)
extern const PALConfig pal_default_config;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void _pal_lld_init(const PALConfig *config);
uint32_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset);
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset,
uint32_t bits);
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PAL */
#endif /* _PAL_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
This file has been contributed by:
Marcin Jokel.
*/
/**
* @file LPC43xx/pal_lld.h
* @brief LPC43xx GPIO low level driver header.
*
* @addtogroup PAL
* @{
*/
#ifndef _PAL_LLD_H_
#define _PAL_LLD_H_
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Unsupported modes and specific modes */
/*===========================================================================*/
#undef PAL_MODE_INPUT_PULLUP
#undef PAL_MODE_INPUT_PULLDOWN
#undef PAL_MODE_INPUT_ANALOG
#undef PAL_MODE_OUTPUT_OPENDRAIN
/*===========================================================================*/
/* I/O Ports Types and constants. */
/*===========================================================================*/
/**
* @brief GPIO port setup info.
*/
typedef struct {
/** Initial value for PIN register.*/
uint32_t data;
/** Initial value for DIR register.*/
uint32_t dir;
} lpc_gpio_setup_t;
/**
* @brief GPIO static initializer.
* @details An instance of this structure must be passed to @p palInit() at
* system startup time in order to initialized the digital I/O
* subsystem. This represents only the initial setup, specific pads
* or whole ports can be reprogrammed at later time.
* @note The @p IOCON block is not configured, initially all pins have
* enabled pullups and are programmed as GPIO. It is responsibility
* of the various drivers to reprogram the pins in the proper mode.
* Pins that are not handled by any driver may be programmed in
* @p board.c.
*/
typedef struct {
/** @brief GPIO 0 setup data.*/
lpc_gpio_setup_t P0;
/** @brief GPIO 1 setup data.*/
lpc_gpio_setup_t P1;
/** @brief GPIO 2 setup data.*/
lpc_gpio_setup_t P2;
/** @brief GPIO 3 setup data.*/
lpc_gpio_setup_t P3;
#if LPC_HAS_GPIO4
/** @brief GPIO 4 setup data.*/
lpc_gpio_setup_t P4;
#endif
/** @brief GPIO 5 setup data.*/
lpc_gpio_setup_t P5;
#if LPC_HAS_GPIO6
/** @brief GPIO 6 setup data.*/
lpc_gpio_setup_t P6;
#endif
#if LPC_HAS_GPIO7
/** @brief GPIO 7 setup data.*/
lpc_gpio_setup_t P7;
#endif
} PALConfig;
/**
* @brief Width, in bits, of an I/O port.
*/
#define PAL_IOPORTS_WIDTH 32
/**
* @brief Whole port mask.
* @brief This macro specifies all the valid bits into a port.
*/
#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFFFFF)
/**
* @brief Digital I/O port sized unsigned type.
*/
typedef uint32_t ioportmask_t;
/**
* @brief Digital I/O modes.
*/
typedef uint32_t iomode_t;
/**
* @brief Port Identifier.
*/
typedef uint32_t ioportid_t;
/*===========================================================================*/
/* I/O Ports Identifiers. */
/*===========================================================================*/
/**
* @brief GPIO0 port identifier.
*/
#define IOPORT1 0
#define GPIO0 0
/**
* @brief GPIO1 port identifier.
*/
#define IOPORT2 1
#define GPIO1 1
/**
* @brief GPIO2 port identifier.
*/
#define IOPORT3 2
#define GPIO2 2
/**
* @brief GPIO3 port identifier.
*/
#define IOPORT4 3
#define GPIO3 3
/**
* @brief GPIO4 port identifier.
*/
#define IOPORT5 4
#define GPIO4 4
/**
* @brief GPIO5 port identifier.
*/
#define IOPORT6 5
#define GPIO5 5
/**
* @brief GPIO6 port identifier.
*/
#define IOPORT7 6
#define GPIO6 6
/**
* @brief GPIO7 port identifier.
*/
#define IOPORT8 7
#define GPIO7 7
/*===========================================================================*/
/* Implementation, some of the following macros could be implemented as */
/* functions, if so please put them in pal_lld.c. */
/*===========================================================================*/
/**
* @brief Low level PAL subsystem initialization.
*
* @param[in] config architecture-dependent ports configuration
*
* @notapi
*/
#define pal_lld_init(config) _pal_lld_init(config)
/**
* @brief Reads the physical I/O port states.
*
* @param[in] port port identifier
* @return The port bits.
*
* @notapi
*/
#define pal_lld_readport(port) (LPC_GPIO_PORT->PIN[port])
/**
* @brief Reads the output latch.
* @details The purpose of this function is to read back the latched output
* value.
*
* @param[in] port port identifier
* @return The latched logical states.
*
* @notapi
*/
#define pal_lld_readlatch(port) (LPC_GPIO_PORT->PIN[port])
/**
* @brief Writes a bits mask on a I/O port.
*
* @param[in] port port identifier
* @param[in] bits bits to be written on the specified port
*
* @notapi
*/
#define pal_lld_writeport(port, bits) (LPC_GPIO_PORT->PIN[port] = (bits))
/**
* @brief Sets a bits mask on a I/O port.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] bits bits to be ORed on the specified port
*
* @notapi
*/
#define pal_lld_setport(port, bits) (LPC_GPIO_PORT->SET[port] = (bits))
/**
* @brief Clears a bits mask on a I/O port.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] bits bits to be cleared on the specified port
*
* @notapi
*/
#define pal_lld_clearport(port, bits) (LPC_GPIO_PORT->CLR[port] = (bits))
/**
* @brief Reads a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @return The group logical states.
*
* @notapi
*/
#define pal_lld_readgroup(port, mask, offset) \
_pal_lld_readgroup(port, mask, offset)
/**
* @brief Writes a group of bits.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] bits bits to be written. Values exceeding the group width
* are masked.
*
* @notapi
*/
#define pal_lld_writegroup(port, mask, offset, bits) \
_pal_lld_writegroup(port, mask, offset, bits)
/**
* @brief Pads group mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
* @note Programming an unknown or unsupported mode is silently ignored.
*
* @param[in] port port identifier
* @param[in] mask group mask
* @param[in] offset group bit offset within the port
* @param[in] mode group mode
*
* @notapi
*/
#define pal_lld_setgroupmode(port, mask, offset, mode) \
_pal_lld_setgroupmode(port, mask << offset, mode)
/**
* @brief Writes a logical state on an output pad.
* @note This function is not meant to be invoked directly by the
* application code.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @param[in] bit logical value, the value must be @p PAL_LOW or
* @p PAL_HIGH
*
* @notapi
*/
#define pal_lld_writepad(port, pad, bit) \
((bit) == PAL_LOW) ? pal_lld_clearpad(port, pad) : \
pal_lld_setpad(port, pad)
/**
* @brief Sets a pad logical state to @p PAL_HIGH.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_setpad(port, pad) \
(LPC_GPIO_PORT->SET[port] = 1UL << (pad))
/**
* @brief Clears a pad logical state to @p PAL_LOW.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_clearpad(port, pad) \
(LPC_GPIO_PORT->CLR[port] = 1UL << (pad))
/**
* @brief Toggles a pad logical state.
* @note The @ref PAL provides a default software implementation of this
* functionality, implement this function if can optimize it by using
* special hardware functionalities or special coding.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
*
* @notapi
*/
#define pal_lld_togglepad(port, pad) \
(LPC_GPIO_PORT->NOT[port] = 1UL << (pad))
#if !defined(__DOXYGEN__)
extern const PALConfig pal_default_config;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void _pal_lld_init(const PALConfig *config);
uint32_t _pal_lld_readgroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset);
void _pal_lld_writegroup(ioportid_t port,
ioportmask_t mask,
uint32_t offset,
uint32_t bits);
void _pal_lld_setgroupmode(ioportid_t port,
ioportmask_t mask,
iomode_t mode);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PAL */
#endif /* _PAL_LLD_H_ */
/** @} */

View File

@ -1,12 +1,12 @@
# List of all the LPC43xx platform files.
PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/LPC43xx/hal_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/pal_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/serial_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/gpt_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/spi_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/lpc43xx_dma.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/mac_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/dac_lld.c
# Required include directories
PLATFORMINC = ${CHIBIOS}/os/hal/platforms/LPC43xx
# List of all the LPC43xx platform files.
PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/LPC43xx/hal_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/pal_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/serial_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/gpt_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/spi_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/lpc43xx_dma.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/mac_lld.c \
${CHIBIOS}/os/hal/platforms/LPC43xx/dac_lld.c
# Required include directories
PLATFORMINC = ${CHIBIOS}/os/hal/platforms/LPC43xx

View File

@ -1,476 +1,476 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/serial_lld.c
* @brief LPC43xx low level serial driver code.
*
* @addtogroup SERIAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
#if LPC_SERIAL_USE_UART0 || defined(__DOXYGEN__)
/** @brief UART0 serial driver identifier.*/
SerialDriver SD1;
#endif
#if LPC_SERIAL_USE_UART1 || defined(__DOXYGEN__)
/** @brief UART1 serial driver identifier.*/
SerialDriver SD2;
#endif
#if LPC_SERIAL_USE_UART2 || defined(__DOXYGEN__)
/** @brief UART2 serial driver identifier.*/
SerialDriver SD3;
#endif
#if LPC_SERIAL_USE_UART3 || defined(__DOXYGEN__)
/** @brief UART3 serial driver identifier.*/
SerialDriver SD4;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/** @brief Driver default configuration.*/
static const SerialConfig default_config = {
SERIAL_DEFAULT_BITRATE,
LCR_WL8 | LCR_STOP1 | LCR_NOPARITY,
FCR_TRIGGER0
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief UART initialization.
*
* @param[in] sdp communication channel associated to the UART
* @param[in] config the architecture-dependent serial driver configuration
*/
static void uart_init(SerialDriver *sdp, const SerialConfig *config) {
LPC_USARTn_Type *u = sdp->uart;
uint32_t div = 0;
#if LPC_SERIAL_USE_UART0
if (&SD1 == sdp) {
div = LPC_SERIAL_UART0_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC_SERIAL_USE_UART1
if (&SD2 == sdp) {
div = LPC_SERIAL_UART1_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC_SERIAL_USE_UART2
if (&SD3 == sdp) {
div = LPC_SERIAL_UART2_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC_SERIAL_USE_UART3
if (&SD4 == sdp) {
div = LPC_SERIAL_UART3_PCLK / (config->sc_speed << 4);
}
#endif
u->LCR = config->sc_lcr | LCR_DLAB;
u->DLL = div;
u->DLM = div >> 8;
u->LCR = config->sc_lcr;
u->FCR = FCR_ENABLE | FCR_RXRESET | FCR_TXRESET | config->sc_fcr;
u->ACR = 0;
u->FDR = 0x10;
u->TER = TER_ENABLE;
u->IER = IER_RBR | IER_STATUS;
}
/**
* @brief UART de-initialization.
*
* @param[in] u pointer to an UART I/O block
*/
static void uart_deinit(LPC_USARTn_Type *u) {
u->LCR = LCR_DLAB;
u->DLL = 1;
u->DLM = 0;
u->LCR = 0;
u->FDR = 0x10;
u->IER = 0;
u->FCR = FCR_RXRESET | FCR_TXRESET;
u->ACR = 0;
u->TER = TER_ENABLE;
}
/**
* @brief Error handling routine.
*
* @param[in] sdp communication channel associated to the UART
* @param[in] err UART LSR register value
*/
static void set_error(SerialDriver *sdp, IOREG32 err) {
flagsmask_t sts = 0;
if (err & LSR_OVERRUN)
sts |= SD_OVERRUN_ERROR;
if (err & LSR_PARITY)
sts |= SD_PARITY_ERROR;
if (err & LSR_FRAMING)
sts |= SD_FRAMING_ERROR;
if (err & LSR_BREAK)
sts |= SD_BREAK_DETECTED;
chSysLockFromIsr();
chnAddFlagsI(sdp, sts);
chSysUnlockFromIsr();
}
/**
* @brief Common IRQ handler.
* @note Tries hard to clear all the pending interrupt sources, we don't
* want to go through the whole ISR and have another interrupt soon
* after.
*
* @param[in] u pointer to an UART I/O block
* @param[in] sdp communication channel associated to the UART
*/
static void serve_interrupt(SerialDriver *sdp) {
LPC_USARTn_Type *u = sdp->uart;
while (TRUE) {
switch (u->IIR & IIR_SRC_MASK) {
case IIR_SRC_NONE:
return;
case IIR_SRC_ERROR:
set_error(sdp, u->LSR);
break;
case IIR_SRC_TIMEOUT:
case IIR_SRC_RX:
chSysLockFromIsr();
if (chIQIsEmptyI(&sdp->iqueue))
chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE);
chSysUnlockFromIsr();
while (u->LSR & LSR_RBR_FULL) {
chSysLockFromIsr();
if (chIQPutI(&sdp->iqueue, u->RBR) < Q_OK)
chnAddFlagsI(sdp, SD_OVERRUN_ERROR);
chSysUnlockFromIsr();
}
break;
case IIR_SRC_TX:
{
int i = LPC_SERIAL_FIFO_PRELOAD;
do {
msg_t b;
chSysLockFromIsr();
b = chOQGetI(&sdp->oqueue);
chSysUnlockFromIsr();
if (b < Q_OK) {
u->IER &= ~IER_THRE;
chSysLockFromIsr();
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
chSysUnlockFromIsr();
break;
}
u->THR = b;
} while (--i);
}
break;
default:
(void) u->THR;
(void) u->RBR;
}
}
}
/**
* @brief Attempts a TX FIFO preload.
*/
static void preload(SerialDriver *sdp) {
LPC_USARTn_Type *u = sdp->uart;
if (u->LSR & LSR_THRE) {
int i = LPC_SERIAL_FIFO_PRELOAD;
do {
msg_t b = chOQGetI(&sdp->oqueue);
if (b < Q_OK) {
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
return;
}
u->THR = b;
} while (--i);
}
u->IER |= IER_THRE;
}
/**
* @brief Driver SD1 output notification.
*/
#if LPC_SERIAL_USE_UART0 || defined(__DOXYGEN__)
static void notify1(GenericQueue *qp) {
(void)qp;
preload(&SD1);
}
#endif
/**
* @brief Driver SD2 output notification.
*/
#if LPC_SERIAL_USE_UART1 || defined(__DOXYGEN__)
static void notify2(GenericQueue *qp) {
(void)qp;
preload(&SD2);
}
#endif
/**
* @brief Driver SD3 output notification.
*/
#if LPC_SERIAL_USE_UART2 || defined(__DOXYGEN__)
static void notify3(GenericQueue *qp) {
(void)qp;
preload(&SD3);
}
#endif
/**
* @brief Driver SD4 output notification.
*/
#if LPC_SERIAL_USE_UART3 || defined(__DOXYGEN__)
static void notify4(GenericQueue *qp) {
(void)qp;
preload(&SD4);
}
#endif
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief UART0 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_UART0 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(VectorA0) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD1);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART1 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_UART1 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(VectorA4) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD2);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART2 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_UART2 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(VectorA8) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD3);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART3 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_UART3 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(VectorAC) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD4);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level serial driver initialization.
*
* @notapi
*/
void sd_lld_init(void) {
#if LPC_SERIAL_USE_UART0
sdObjectInit(&SD1, NULL, notify1);
SD1.uart = ( LPC_USARTn_Type*) LPC_USART0;
#endif
#if LPC_SERIAL_USE_UART1
sdObjectInit(&SD2, NULL, notify2);
SD2.uart = ( LPC_USARTn_Type*) LPC_UART1;
#endif
#if LPC_SERIAL_USE_UART2
sdObjectInit(&SD3, NULL, notify3);
SD3.uart = ( LPC_USARTn_Type*) LPC_USART2;
#endif
#if LPC_SERIAL_USE_UART3
sdObjectInit(&SD4, NULL, notify4);
SD4.uart = ( LPC_USARTn_Type*) LPC_USART3;
#endif
}
/**
* @brief Low level serial driver configuration and (re)start.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] config the architecture-dependent serial driver configuration.
* If this parameter is set to @p NULL then a default
* configuration is used.
*
* @notapi
*/
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
if (config == NULL)
config = &default_config;
if (sdp->state == SD_STOP) {
#if LPC_SERIAL_USE_UART0
if (&SD1 == sdp) {
LPC_CCU2->CLK_APB0_USART0_CFG = 1;
nvicEnableVector(USART0_IRQn,
CORTEX_PRIORITY_MASK(LPC_SERIAL_UART0_IRQ_PRIORITY));
}
#endif
#if LPC_SERIAL_USE_UART1
if (&SD2 == sdp) {
LPC_CCU2->CLK_APB0_UART1_CFG = 1;
nvicEnableVector(UART1_IRQn,
CORTEX_PRIORITY_MASK(LPC_SERIAL_UART1_IRQ_PRIORITY));
}
#endif
#if LPC_SERIAL_USE_UART2
if (&SD3 == sdp) {
LPC_CCU2->CLK_APB2_USART2_CFG = 1;
nvicEnableVector(USART2_IRQn,
CORTEX_PRIORITY_MASK(LPC_SERIAL_UART2_IRQ_PRIORITY));
}
#endif
#if LPC_SERIAL_USE_UART3
if (&SD4 == sdp) {
LPC_CCU2->CLK_APB2_USART3_CFG = 1;
nvicEnableVector(USART3_IRQn,
CORTEX_PRIORITY_MASK(LPC_SERIAL_UART3_IRQ_PRIORITY));
}
#endif
}
uart_init(sdp, config);
}
/**
* @brief Low level serial driver stop.
* @details De-initializes the UART, stops the associated clock, resets the
* interrupt vector.
*
* @param[in] sdp pointer to a @p SerialDriver object
*
* @notapi
*/
void sd_lld_stop(SerialDriver *sdp) {
if (sdp->state == SD_READY) {
uart_deinit(sdp->uart);
#if LPC_SERIAL_USE_UART0
if (&SD1 == sdp) {
LPC_CCU2->CLK_APB0_USART0_CFG = 0;
nvicDisableVector(USART0_IRQn);
return;
}
#endif
#if LPC_SERIAL_USE_UART1
if (&SD2 == sdp) {
LPC_CCU2->CLK_APB0_UART1_CFG = 0;
nvicDisableVector(UART1_IRQn);
return;
}
#endif
#if LPC_SERIAL_USE_UART2
if (&SD3 == sdp) {
LPC_CCU2->CLK_APB2_USART2_CFG = 0;
nvicDisableVector(USART2_IRQn);
return;
}
#endif
#if LPC_SERIAL_USE_UART3
if (&SD4 == sdp) {
LPC_CCU2->CLK_APB2_USART3_CFG = 0;
nvicDisableVector(USART3_IRQn);
return;
}
#endif
}
}
#endif /* HAL_USE_SERIAL */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/serial_lld.c
* @brief LPC43xx low level serial driver code.
*
* @addtogroup SERIAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
#if LPC_SERIAL_USE_UART0 || defined(__DOXYGEN__)
/** @brief UART0 serial driver identifier.*/
SerialDriver SD1;
#endif
#if LPC_SERIAL_USE_UART1 || defined(__DOXYGEN__)
/** @brief UART1 serial driver identifier.*/
SerialDriver SD2;
#endif
#if LPC_SERIAL_USE_UART2 || defined(__DOXYGEN__)
/** @brief UART2 serial driver identifier.*/
SerialDriver SD3;
#endif
#if LPC_SERIAL_USE_UART3 || defined(__DOXYGEN__)
/** @brief UART3 serial driver identifier.*/
SerialDriver SD4;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/** @brief Driver default configuration.*/
static const SerialConfig default_config = {
SERIAL_DEFAULT_BITRATE,
LCR_WL8 | LCR_STOP1 | LCR_NOPARITY,
FCR_TRIGGER0
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief UART initialization.
*
* @param[in] sdp communication channel associated to the UART
* @param[in] config the architecture-dependent serial driver configuration
*/
static void uart_init(SerialDriver *sdp, const SerialConfig *config) {
LPC_USARTn_Type *u = sdp->uart;
uint32_t div = 0;
#if LPC_SERIAL_USE_UART0
if (&SD1 == sdp) {
div = LPC_SERIAL_UART0_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC_SERIAL_USE_UART1
if (&SD2 == sdp) {
div = LPC_SERIAL_UART1_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC_SERIAL_USE_UART2
if (&SD3 == sdp) {
div = LPC_SERIAL_UART2_PCLK / (config->sc_speed << 4);
}
#endif
#if LPC_SERIAL_USE_UART3
if (&SD4 == sdp) {
div = LPC_SERIAL_UART3_PCLK / (config->sc_speed << 4);
}
#endif
u->LCR = config->sc_lcr | LCR_DLAB;
u->DLL = div;
u->DLM = div >> 8;
u->LCR = config->sc_lcr;
u->FCR = FCR_ENABLE | FCR_RXRESET | FCR_TXRESET | config->sc_fcr;
u->ACR = 0;
u->FDR = 0x10;
u->TER = TER_ENABLE;
u->IER = IER_RBR | IER_STATUS;
}
/**
* @brief UART de-initialization.
*
* @param[in] u pointer to an UART I/O block
*/
static void uart_deinit(LPC_USARTn_Type *u) {
u->LCR = LCR_DLAB;
u->DLL = 1;
u->DLM = 0;
u->LCR = 0;
u->FDR = 0x10;
u->IER = 0;
u->FCR = FCR_RXRESET | FCR_TXRESET;
u->ACR = 0;
u->TER = TER_ENABLE;
}
/**
* @brief Error handling routine.
*
* @param[in] sdp communication channel associated to the UART
* @param[in] err UART LSR register value
*/
static void set_error(SerialDriver *sdp, IOREG32 err) {
flagsmask_t sts = 0;
if (err & LSR_OVERRUN)
sts |= SD_OVERRUN_ERROR;
if (err & LSR_PARITY)
sts |= SD_PARITY_ERROR;
if (err & LSR_FRAMING)
sts |= SD_FRAMING_ERROR;
if (err & LSR_BREAK)
sts |= SD_BREAK_DETECTED;
chSysLockFromIsr();
chnAddFlagsI(sdp, sts);
chSysUnlockFromIsr();
}
/**
* @brief Common IRQ handler.
* @note Tries hard to clear all the pending interrupt sources, we don't
* want to go through the whole ISR and have another interrupt soon
* after.
*
* @param[in] u pointer to an UART I/O block
* @param[in] sdp communication channel associated to the UART
*/
static void serve_interrupt(SerialDriver *sdp) {
LPC_USARTn_Type *u = sdp->uart;
while (TRUE) {
switch (u->IIR & IIR_SRC_MASK) {
case IIR_SRC_NONE:
return;
case IIR_SRC_ERROR:
set_error(sdp, u->LSR);
break;
case IIR_SRC_TIMEOUT:
case IIR_SRC_RX:
chSysLockFromIsr();
if (chIQIsEmptyI(&sdp->iqueue))
chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE);
chSysUnlockFromIsr();
while (u->LSR & LSR_RBR_FULL) {
chSysLockFromIsr();
if (chIQPutI(&sdp->iqueue, u->RBR) < Q_OK)
chnAddFlagsI(sdp, SD_OVERRUN_ERROR);
chSysUnlockFromIsr();
}
break;
case IIR_SRC_TX:
{
int i = LPC_SERIAL_FIFO_PRELOAD;
do {
msg_t b;
chSysLockFromIsr();
b = chOQGetI(&sdp->oqueue);
chSysUnlockFromIsr();
if (b < Q_OK) {
u->IER &= ~IER_THRE;
chSysLockFromIsr();
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
chSysUnlockFromIsr();
break;
}
u->THR = b;
} while (--i);
}
break;
default:
(void) u->THR;
(void) u->RBR;
}
}
}
/**
* @brief Attempts a TX FIFO preload.
*/
static void preload(SerialDriver *sdp) {
LPC_USARTn_Type *u = sdp->uart;
if (u->LSR & LSR_THRE) {
int i = LPC_SERIAL_FIFO_PRELOAD;
do {
msg_t b = chOQGetI(&sdp->oqueue);
if (b < Q_OK) {
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
return;
}
u->THR = b;
} while (--i);
}
u->IER |= IER_THRE;
}
/**
* @brief Driver SD1 output notification.
*/
#if LPC_SERIAL_USE_UART0 || defined(__DOXYGEN__)
static void notify1(GenericQueue *qp) {
(void)qp;
preload(&SD1);
}
#endif
/**
* @brief Driver SD2 output notification.
*/
#if LPC_SERIAL_USE_UART1 || defined(__DOXYGEN__)
static void notify2(GenericQueue *qp) {
(void)qp;
preload(&SD2);
}
#endif
/**
* @brief Driver SD3 output notification.
*/
#if LPC_SERIAL_USE_UART2 || defined(__DOXYGEN__)
static void notify3(GenericQueue *qp) {
(void)qp;
preload(&SD3);
}
#endif
/**
* @brief Driver SD4 output notification.
*/
#if LPC_SERIAL_USE_UART3 || defined(__DOXYGEN__)
static void notify4(GenericQueue *qp) {
(void)qp;
preload(&SD4);
}
#endif
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief UART0 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_UART0 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(VectorA0) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD1);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART1 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_UART1 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(VectorA4) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD2);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART2 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_UART2 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(VectorA8) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD3);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART3 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_UART3 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(VectorAC) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD4);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level serial driver initialization.
*
* @notapi
*/
void sd_lld_init(void) {
#if LPC_SERIAL_USE_UART0
sdObjectInit(&SD1, NULL, notify1);
SD1.uart = ( LPC_USARTn_Type*) LPC_USART0;
#endif
#if LPC_SERIAL_USE_UART1
sdObjectInit(&SD2, NULL, notify2);
SD2.uart = ( LPC_USARTn_Type*) LPC_UART1;
#endif
#if LPC_SERIAL_USE_UART2
sdObjectInit(&SD3, NULL, notify3);
SD3.uart = ( LPC_USARTn_Type*) LPC_USART2;
#endif
#if LPC_SERIAL_USE_UART3
sdObjectInit(&SD4, NULL, notify4);
SD4.uart = ( LPC_USARTn_Type*) LPC_USART3;
#endif
}
/**
* @brief Low level serial driver configuration and (re)start.
*
* @param[in] sdp pointer to a @p SerialDriver object
* @param[in] config the architecture-dependent serial driver configuration.
* If this parameter is set to @p NULL then a default
* configuration is used.
*
* @notapi
*/
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
if (config == NULL)
config = &default_config;
if (sdp->state == SD_STOP) {
#if LPC_SERIAL_USE_UART0
if (&SD1 == sdp) {
LPC_CCU2->CLK_APB0_USART0_CFG = 1;
nvicEnableVector(USART0_IRQn,
CORTEX_PRIORITY_MASK(LPC_SERIAL_UART0_IRQ_PRIORITY));
}
#endif
#if LPC_SERIAL_USE_UART1
if (&SD2 == sdp) {
LPC_CCU2->CLK_APB0_UART1_CFG = 1;
nvicEnableVector(UART1_IRQn,
CORTEX_PRIORITY_MASK(LPC_SERIAL_UART1_IRQ_PRIORITY));
}
#endif
#if LPC_SERIAL_USE_UART2
if (&SD3 == sdp) {
LPC_CCU2->CLK_APB2_USART2_CFG = 1;
nvicEnableVector(USART2_IRQn,
CORTEX_PRIORITY_MASK(LPC_SERIAL_UART2_IRQ_PRIORITY));
}
#endif
#if LPC_SERIAL_USE_UART3
if (&SD4 == sdp) {
LPC_CCU2->CLK_APB2_USART3_CFG = 1;
nvicEnableVector(USART3_IRQn,
CORTEX_PRIORITY_MASK(LPC_SERIAL_UART3_IRQ_PRIORITY));
}
#endif
}
uart_init(sdp, config);
}
/**
* @brief Low level serial driver stop.
* @details De-initializes the UART, stops the associated clock, resets the
* interrupt vector.
*
* @param[in] sdp pointer to a @p SerialDriver object
*
* @notapi
*/
void sd_lld_stop(SerialDriver *sdp) {
if (sdp->state == SD_READY) {
uart_deinit(sdp->uart);
#if LPC_SERIAL_USE_UART0
if (&SD1 == sdp) {
LPC_CCU2->CLK_APB0_USART0_CFG = 0;
nvicDisableVector(USART0_IRQn);
return;
}
#endif
#if LPC_SERIAL_USE_UART1
if (&SD2 == sdp) {
LPC_CCU2->CLK_APB0_UART1_CFG = 0;
nvicDisableVector(UART1_IRQn);
return;
}
#endif
#if LPC_SERIAL_USE_UART2
if (&SD3 == sdp) {
LPC_CCU2->CLK_APB2_USART2_CFG = 0;
nvicDisableVector(USART2_IRQn);
return;
}
#endif
#if LPC_SERIAL_USE_UART3
if (&SD4 == sdp) {
LPC_CCU2->CLK_APB2_USART3_CFG = 0;
nvicDisableVector(USART3_IRQn);
return;
}
#endif
}
}
#endif /* HAL_USE_SERIAL */
/** @} */

View File

@ -1,268 +1,268 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/serial_lld.h
* @brief LPC43xx low level serial driver header.
*
* @addtogroup SERIAL
* @{
*/
#ifndef _SERIAL_LLD_H_
#define _SERIAL_LLD_H_
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define IIR_SRC_MASK 0x0F
#define IIR_SRC_NONE 0x01
#define IIR_SRC_MODEM 0x00
#define IIR_SRC_TX 0x02
#define IIR_SRC_RX 0x04
#define IIR_SRC_ERROR 0x06
#define IIR_SRC_TIMEOUT 0x0C
#define IER_RBR 1
#define IER_THRE 2
#define IER_STATUS 4
#define LCR_WL5 0
#define LCR_WL6 1
#define LCR_WL7 2
#define LCR_WL8 3
#define LCR_STOP1 0
#define LCR_STOP2 4
#define LCR_NOPARITY 0
#define LCR_PARITYODD 0x08
#define LCR_PARITYEVEN 0x18
#define LCR_PARITYONE 0x28
#define LCR_PARITYZERO 0x38
#define LCR_BREAK_ON 0x40
#define LCR_DLAB 0x80
#define FCR_ENABLE 1
#define FCR_RXRESET 2
#define FCR_TXRESET 4
#define FCR_TRIGGER0 0
#define FCR_TRIGGER1 0x40
#define FCR_TRIGGER2 0x80
#define FCR_TRIGGER3 0xC0
#define LSR_RBR_FULL 1
#define LSR_OVERRUN 2
#define LSR_PARITY 4
#define LSR_FRAMING 8
#define LSR_BREAK 0x10
#define LSR_THRE 0x20
#define LSR_TEMT 0x40
#define LSR_RXFE 0x80
#define TER_ENABLE 0x01
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief UART0 driver enable switch.
* @details If set to @p TRUE the support for UART0 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC_SERIAL_USE_UART0) || defined(__DOXYGEN__)
#define LPC_SERIAL_USE_UART0 TRUE
#endif
/**
* @brief UART1 driver enable switch.
* @details If set to @p TRUE the support for UART1 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC_SERIAL_USE_UART1) || defined(__DOXYGEN__)
#define LPC_SERIAL_USE_UART1 TRUE
#endif
/**
* @brief UART2 driver enable switch.
* @details If set to @p TRUE the support for UART2 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC_SERIAL_USE_UART2) || defined(__DOXYGEN__)
#define LPC_SERIAL_USE_UART2 TRUE
#endif
/**
* @brief UART3 driver enable switch.
* @details If set to @p TRUE the support for UART3 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC_SERIAL_USE_UART3) || defined(__DOXYGEN__)
#define LPC_SERIAL_USE_UART3 TRUE
#endif
/**
* @brief FIFO preload parameter.
* @details Configuration parameter, this values defines how many bytes are
* preloaded in the HW transmit FIFO for each interrupt, the maximum
* value is 16 the minimum is 1.
* @note An high value reduces the number of interrupts generated but can
* also increase the worst case interrupt response time because the
* preload loops.
*/
#if !defined(LPC_SERIAL_FIFO_PRELOAD) || defined(__DOXYGEN__)
#define LPC_SERIAL_FIFO_PRELOAD 16
#endif
/**
* @brief UART0 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_UART0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SERIAL_UART0_IRQ_PRIORITY 3
#endif
/**
* @brief UART1 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_UART1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SERIAL_UART1_IRQ_PRIORITY 3
#endif
/**
* @brief UART2 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_UART2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SERIAL_UART2_IRQ_PRIORITY 3
#endif
/**
* @brief UART3 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_UART3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SERIAL_UART3_IRQ_PRIORITY 3
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if (LPC_SERIAL_FIFO_PRELOAD < 1) || (LPC_SERIAL_FIFO_PRELOAD > 16)
#error "invalid LPC_SERIAL_FIFO_PRELOAD setting"
#endif
/**
* @brief UART0 clock.
*/
#define LPC_SERIAL_UART0_PCLK LPC_BASE_UART0_CLK
/**
* @brief UART1 clock.
*/
#define LPC_SERIAL_UART1_PCLK LPC_BASE_UART1_CLK
/**
* @brief UART2 clock.
*/
#define LPC_SERIAL_UART2_PCLK LPC_BASE_UART2_CLK
/**
* @brief UART3 clock.
*/
#define LPC_SERIAL_UART3_PCLK LPC_BASE_UART3_CLK
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief LPC17xx Serial Driver configuration structure.
* @details An instance of this structure must be passed to @p sdStart()
* in order to configure and start a serial driver operations.
*/
typedef struct {
/**
* @brief Bit rate.
*/
uint32_t sc_speed;
/**
* @brief Initialization value for the LCR register.
*/
uint32_t sc_lcr;
/**
* @brief Initialization value for the FCR register.
*/
uint32_t sc_fcr;
} SerialConfig;
/**
* @brief @p SerialDriver specific data.
*/
#define _serial_driver_data \
_base_asynchronous_channel_data \
/* Driver state.*/ \
sdstate_t state; \
/* Input queue.*/ \
InputQueue iqueue; \
/* Output queue.*/ \
OutputQueue oqueue; \
/* Input circular buffer.*/ \
uint8_t ib[SERIAL_BUFFERS_SIZE]; \
/* Output circular buffer.*/ \
uint8_t ob[SERIAL_BUFFERS_SIZE]; \
/* End of the mandatory fields.*/ \
/* Pointer to the USART registers block.*/ \
LPC_USARTn_Type *uart;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC_SERIAL_USE_UART0 && !defined(__DOXYGEN__)
extern SerialDriver SD1;
#endif
#if LPC_SERIAL_USE_UART1 && !defined(__DOXYGEN__)
extern SerialDriver SD2;
#endif
#if LPC_SERIAL_USE_UART2 && !defined(__DOXYGEN__)
extern SerialDriver SD3;
#endif
#if LPC_SERIAL_USE_UART3 && !defined(__DOXYGEN__)
extern SerialDriver SD4;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void sd_lld_init(void);
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
void sd_lld_stop(SerialDriver *sdp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SERIAL */
#endif /* _SERIAL_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/serial_lld.h
* @brief LPC43xx low level serial driver header.
*
* @addtogroup SERIAL
* @{
*/
#ifndef _SERIAL_LLD_H_
#define _SERIAL_LLD_H_
#if HAL_USE_SERIAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define IIR_SRC_MASK 0x0F
#define IIR_SRC_NONE 0x01
#define IIR_SRC_MODEM 0x00
#define IIR_SRC_TX 0x02
#define IIR_SRC_RX 0x04
#define IIR_SRC_ERROR 0x06
#define IIR_SRC_TIMEOUT 0x0C
#define IER_RBR 1
#define IER_THRE 2
#define IER_STATUS 4
#define LCR_WL5 0
#define LCR_WL6 1
#define LCR_WL7 2
#define LCR_WL8 3
#define LCR_STOP1 0
#define LCR_STOP2 4
#define LCR_NOPARITY 0
#define LCR_PARITYODD 0x08
#define LCR_PARITYEVEN 0x18
#define LCR_PARITYONE 0x28
#define LCR_PARITYZERO 0x38
#define LCR_BREAK_ON 0x40
#define LCR_DLAB 0x80
#define FCR_ENABLE 1
#define FCR_RXRESET 2
#define FCR_TXRESET 4
#define FCR_TRIGGER0 0
#define FCR_TRIGGER1 0x40
#define FCR_TRIGGER2 0x80
#define FCR_TRIGGER3 0xC0
#define LSR_RBR_FULL 1
#define LSR_OVERRUN 2
#define LSR_PARITY 4
#define LSR_FRAMING 8
#define LSR_BREAK 0x10
#define LSR_THRE 0x20
#define LSR_TEMT 0x40
#define LSR_RXFE 0x80
#define TER_ENABLE 0x01
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief UART0 driver enable switch.
* @details If set to @p TRUE the support for UART0 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC_SERIAL_USE_UART0) || defined(__DOXYGEN__)
#define LPC_SERIAL_USE_UART0 TRUE
#endif
/**
* @brief UART1 driver enable switch.
* @details If set to @p TRUE the support for UART1 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC_SERIAL_USE_UART1) || defined(__DOXYGEN__)
#define LPC_SERIAL_USE_UART1 TRUE
#endif
/**
* @brief UART2 driver enable switch.
* @details If set to @p TRUE the support for UART2 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC_SERIAL_USE_UART2) || defined(__DOXYGEN__)
#define LPC_SERIAL_USE_UART2 TRUE
#endif
/**
* @brief UART3 driver enable switch.
* @details If set to @p TRUE the support for UART3 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC_SERIAL_USE_UART3) || defined(__DOXYGEN__)
#define LPC_SERIAL_USE_UART3 TRUE
#endif
/**
* @brief FIFO preload parameter.
* @details Configuration parameter, this values defines how many bytes are
* preloaded in the HW transmit FIFO for each interrupt, the maximum
* value is 16 the minimum is 1.
* @note An high value reduces the number of interrupts generated but can
* also increase the worst case interrupt response time because the
* preload loops.
*/
#if !defined(LPC_SERIAL_FIFO_PRELOAD) || defined(__DOXYGEN__)
#define LPC_SERIAL_FIFO_PRELOAD 16
#endif
/**
* @brief UART0 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_UART0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SERIAL_UART0_IRQ_PRIORITY 3
#endif
/**
* @brief UART1 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_UART1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SERIAL_UART1_IRQ_PRIORITY 3
#endif
/**
* @brief UART2 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_UART2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SERIAL_UART2_IRQ_PRIORITY 3
#endif
/**
* @brief UART3 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_UART3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SERIAL_UART3_IRQ_PRIORITY 3
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if (LPC_SERIAL_FIFO_PRELOAD < 1) || (LPC_SERIAL_FIFO_PRELOAD > 16)
#error "invalid LPC_SERIAL_FIFO_PRELOAD setting"
#endif
/**
* @brief UART0 clock.
*/
#define LPC_SERIAL_UART0_PCLK LPC_BASE_UART0_CLK
/**
* @brief UART1 clock.
*/
#define LPC_SERIAL_UART1_PCLK LPC_BASE_UART1_CLK
/**
* @brief UART2 clock.
*/
#define LPC_SERIAL_UART2_PCLK LPC_BASE_UART2_CLK
/**
* @brief UART3 clock.
*/
#define LPC_SERIAL_UART3_PCLK LPC_BASE_UART3_CLK
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief LPC17xx Serial Driver configuration structure.
* @details An instance of this structure must be passed to @p sdStart()
* in order to configure and start a serial driver operations.
*/
typedef struct {
/**
* @brief Bit rate.
*/
uint32_t sc_speed;
/**
* @brief Initialization value for the LCR register.
*/
uint32_t sc_lcr;
/**
* @brief Initialization value for the FCR register.
*/
uint32_t sc_fcr;
} SerialConfig;
/**
* @brief @p SerialDriver specific data.
*/
#define _serial_driver_data \
_base_asynchronous_channel_data \
/* Driver state.*/ \
sdstate_t state; \
/* Input queue.*/ \
InputQueue iqueue; \
/* Output queue.*/ \
OutputQueue oqueue; \
/* Input circular buffer.*/ \
uint8_t ib[SERIAL_BUFFERS_SIZE]; \
/* Output circular buffer.*/ \
uint8_t ob[SERIAL_BUFFERS_SIZE]; \
/* End of the mandatory fields.*/ \
/* Pointer to the USART registers block.*/ \
LPC_USARTn_Type *uart;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC_SERIAL_USE_UART0 && !defined(__DOXYGEN__)
extern SerialDriver SD1;
#endif
#if LPC_SERIAL_USE_UART1 && !defined(__DOXYGEN__)
extern SerialDriver SD2;
#endif
#if LPC_SERIAL_USE_UART2 && !defined(__DOXYGEN__)
extern SerialDriver SD3;
#endif
#if LPC_SERIAL_USE_UART3 && !defined(__DOXYGEN__)
extern SerialDriver SD4;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void sd_lld_init(void);
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
void sd_lld_stop(SerialDriver *sdp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SERIAL */
#endif /* _SERIAL_LLD_H_ */
/** @} */

View File

@ -1,383 +1,383 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/spi_lld.c
* @brief LPC43xx low level SPI driver code.
*
* @addtogroup SPI
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
#if LPC_SPI_USE_SSP0 || defined(__DOXYGEN__)
/** @brief SPI1 driver identifier.*/
SPIDriver SPID1;
#endif
#if LPC_SPI_USE_SSP1 || defined(__DOXYGEN__)
/** @brief SPI2 driver identifier.*/
SPIDriver SPID2;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Preloads the transmit FIFO.
*
* @param[in] spip pointer to the @p SPIDriver object
*/
static void ssp_fifo_preload(SPIDriver *spip) {
LPC_SSPn_Type *ssp = spip->ssp;
uint32_t n = spip->txcnt > LPC_SSP_FIFO_DEPTH ?
LPC_SSP_FIFO_DEPTH : spip->txcnt;
while(((ssp->SR & SR_TNF) != 0) && (n > 0)) {
if (spip->txptr != NULL) {
if ((ssp->CR0 & CR0_DSSMASK) > CR0_DSS8BIT) {
const uint16_t *p = spip->txptr;
ssp->DR = *p++;
spip->txptr = p;
}
else {
const uint8_t *p = spip->txptr;
ssp->DR = *p++;
spip->txptr = p;
}
}
else
ssp->DR = 0xFFFFFFFF;
n--;
spip->txcnt--;
}
}
/**
* @brief Common IRQ handler.
*
* @param[in] spip pointer to the @p SPIDriver object
*/
static void spi_serve_interrupt(SPIDriver *spip) {
LPC_SSPn_Type *ssp = spip->ssp;
if ((ssp->MIS & MIS_ROR) != 0) {
/* The overflow condition should never happen because priority is given
to receive but a hook macro is provided anyway...*/
LPC_SPI_SSP_ERROR_HOOK(spip);
}
ssp->ICR = ICR_RT | ICR_ROR;
while ((ssp->SR & SR_RNE) != 0) {
if (spip->rxptr != NULL) {
if ((ssp->CR0 & CR0_DSSMASK) > CR0_DSS8BIT) {
uint16_t *p = spip->rxptr;
*p++ = ssp->DR;
spip->rxptr = p;
}
else {
uint8_t *p = spip->rxptr;
*p++ = ssp->DR;
spip->rxptr = p;
}
}
else
(void)ssp->DR;
if (--spip->rxcnt == 0) {
chDbgAssert(spip->txcnt == 0,
"spi_serve_interrupt(), #1", "counter out of synch");
/* Stops the IRQ sources.*/
ssp->IMSC = 0;
/* Portable SPI ISR code defined in the high level driver, note, it is
a macro.*/
_spi_isr_code(spip);
return;
}
}
ssp_fifo_preload(spip);
if (spip->txcnt == 0)
ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_RX;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if LPC_SPI_USE_SSP0 || defined(__DOXYGEN__)
/**
* @brief SSP0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector98) {
CH_IRQ_PROLOGUE();
spi_serve_interrupt(&SPID1);
CH_IRQ_EPILOGUE();
}
#endif
#if LPC_SPI_USE_SSP1 || defined(__DOXYGEN__)
/**
* @brief SSP1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector9C) {
CH_IRQ_PROLOGUE();
spi_serve_interrupt(&SPID2);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level SPI driver initialization.
*
* @notapi
*/
void spi_lld_init(void) {
#if LPC_SPI_USE_SSP0
spiObjectInit(&SPID1);
SPID1.ssp = LPC_SSP0;
#endif /* LPC_SPI_USE_SSP0 */
#if LPC_SPI_USE_SSP1
spiObjectInit(&SPID2);
SPID2.ssp = LPC_SSP1;
#endif /* LPC_SPI_USE_SSP0 */
}
/**
* @brief Configures and activates the SPI peripheral.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_start(SPIDriver *spip) {
if (spip->state == SPI_STOP) {
/* Clock activation.*/
#if LPC_SPI_USE_SSP0
if (&SPID1 == spip) {
LPC_CCU2->CLK_APB0_SSP0_CFG = 1;
nvicEnableVector(SSP0_IRQn,
CORTEX_PRIORITY_MASK(LPC_SPI_SSP0_IRQ_PRIORITY));
}
#endif
#if LPC_SPI_USE_SSP1
if (&SPID2 == spip) {
LPC_CCU2->CLK_APB2_SSP1_CFG= 1;
nvicEnableVector(SSP1_IRQn,
CORTEX_PRIORITY_MASK(LPC_SPI_SSP1_IRQ_PRIORITY));
}
#endif
}
/* Configuration.*/
spip->ssp->CR1 = 0;
spip->ssp->ICR = ICR_RT | ICR_ROR;
spip->ssp->CR0 = spip->config->cr0;
spip->ssp->CPSR = spip->config->cpsr;
spip->ssp->CR1 = CR1_SSE;
}
/**
* @brief Deactivates the SPI peripheral.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_stop(SPIDriver *spip) {
if (spip->state != SPI_STOP) {
spip->ssp->CR1 = 0;
spip->ssp->CR0 = 0;
spip->ssp->CPSR = 0;
#if LPC_SPI_USE_SSP0
if (&SPID1 == spip) {
LPC_CCU2->CLK_APB0_SSP0_CFG = 0;
nvicDisableVector(SSP0_IRQn);
}
#endif
#if LPC_SPI_USE_SSP1
if (&SPID2 == spip) {
LPC_CCU2->CLK_APB2_SSP1_CFG= 0;
nvicDisableVector(SSP1_IRQn);
}
#endif
}
}
/**
* @brief Asserts the slave select signal and prepares for transfers.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_select(SPIDriver *spip) {
palClearPad(spip->config->ssport, spip->config->sspad);
}
/**
* @brief Deasserts the slave select signal.
* @details The previously selected peripheral is unselected.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_unselect(SPIDriver *spip) {
palSetPad(spip->config->ssport, spip->config->sspad);
}
/**
* @brief Ignores data on the SPI bus.
* @details This function transmits a series of idle words on the SPI bus and
* ignores the received data. This function can be invoked even
* when a slave select signal has not been yet asserted.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be ignored
*
* @notapi
*/
void spi_lld_ignore(SPIDriver *spip, size_t n) {
spip->rxptr = NULL;
spip->txptr = NULL;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Exchanges data on the SPI bus.
* @details This asynchronous function starts a simultaneous transmit/receive
* operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be exchanged
* @param[in] txbuf the pointer to the transmit buffer
* @param[out] rxbuf the pointer to the receive buffer
*
* @notapi
*/
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
spip->rxptr = rxbuf;
spip->txptr = txbuf;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Sends data over the SPI bus.
* @details This asynchronous function starts a transmit operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @notapi
*/
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
spip->rxptr = NULL;
spip->txptr = txbuf;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Receives data from the SPI bus.
* @details This asynchronous function starts a receive operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to receive
* @param[out] rxbuf the pointer to the receive buffer
*
* @notapi
*/
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
spip->rxptr = rxbuf;
spip->txptr = NULL;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Exchanges one frame using a polled wait.
* @details This synchronous function exchanges one frame using a polled
* synchronization method. This function is useful when exchanging
* small amount of data on high speed channels, usually in this
* situation is much more efficient just wait for completion using
* polling than suspending the thread waiting for an interrupt.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] frame the data frame to send over the SPI bus
* @return The received data frame from the SPI bus.
*/
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
spip->ssp->DR = (uint32_t)frame;
while ((spip->ssp->SR & SR_RNE) == 0)
;
return (uint16_t)spip->ssp->DR;
}
#endif /* HAL_USE_SPI */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/spi_lld.c
* @brief LPC43xx low level SPI driver code.
*
* @addtogroup SPI
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
#if LPC_SPI_USE_SSP0 || defined(__DOXYGEN__)
/** @brief SPI1 driver identifier.*/
SPIDriver SPID1;
#endif
#if LPC_SPI_USE_SSP1 || defined(__DOXYGEN__)
/** @brief SPI2 driver identifier.*/
SPIDriver SPID2;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Preloads the transmit FIFO.
*
* @param[in] spip pointer to the @p SPIDriver object
*/
static void ssp_fifo_preload(SPIDriver *spip) {
LPC_SSPn_Type *ssp = spip->ssp;
uint32_t n = spip->txcnt > LPC_SSP_FIFO_DEPTH ?
LPC_SSP_FIFO_DEPTH : spip->txcnt;
while(((ssp->SR & SR_TNF) != 0) && (n > 0)) {
if (spip->txptr != NULL) {
if ((ssp->CR0 & CR0_DSSMASK) > CR0_DSS8BIT) {
const uint16_t *p = spip->txptr;
ssp->DR = *p++;
spip->txptr = p;
}
else {
const uint8_t *p = spip->txptr;
ssp->DR = *p++;
spip->txptr = p;
}
}
else
ssp->DR = 0xFFFFFFFF;
n--;
spip->txcnt--;
}
}
/**
* @brief Common IRQ handler.
*
* @param[in] spip pointer to the @p SPIDriver object
*/
static void spi_serve_interrupt(SPIDriver *spip) {
LPC_SSPn_Type *ssp = spip->ssp;
if ((ssp->MIS & MIS_ROR) != 0) {
/* The overflow condition should never happen because priority is given
to receive but a hook macro is provided anyway...*/
LPC_SPI_SSP_ERROR_HOOK(spip);
}
ssp->ICR = ICR_RT | ICR_ROR;
while ((ssp->SR & SR_RNE) != 0) {
if (spip->rxptr != NULL) {
if ((ssp->CR0 & CR0_DSSMASK) > CR0_DSS8BIT) {
uint16_t *p = spip->rxptr;
*p++ = ssp->DR;
spip->rxptr = p;
}
else {
uint8_t *p = spip->rxptr;
*p++ = ssp->DR;
spip->rxptr = p;
}
}
else
(void)ssp->DR;
if (--spip->rxcnt == 0) {
chDbgAssert(spip->txcnt == 0,
"spi_serve_interrupt(), #1", "counter out of synch");
/* Stops the IRQ sources.*/
ssp->IMSC = 0;
/* Portable SPI ISR code defined in the high level driver, note, it is
a macro.*/
_spi_isr_code(spip);
return;
}
}
ssp_fifo_preload(spip);
if (spip->txcnt == 0)
ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_RX;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if LPC_SPI_USE_SSP0 || defined(__DOXYGEN__)
/**
* @brief SSP0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector98) {
CH_IRQ_PROLOGUE();
spi_serve_interrupt(&SPID1);
CH_IRQ_EPILOGUE();
}
#endif
#if LPC_SPI_USE_SSP1 || defined(__DOXYGEN__)
/**
* @brief SSP1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Vector9C) {
CH_IRQ_PROLOGUE();
spi_serve_interrupt(&SPID2);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level SPI driver initialization.
*
* @notapi
*/
void spi_lld_init(void) {
#if LPC_SPI_USE_SSP0
spiObjectInit(&SPID1);
SPID1.ssp = LPC_SSP0;
#endif /* LPC_SPI_USE_SSP0 */
#if LPC_SPI_USE_SSP1
spiObjectInit(&SPID2);
SPID2.ssp = LPC_SSP1;
#endif /* LPC_SPI_USE_SSP0 */
}
/**
* @brief Configures and activates the SPI peripheral.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_start(SPIDriver *spip) {
if (spip->state == SPI_STOP) {
/* Clock activation.*/
#if LPC_SPI_USE_SSP0
if (&SPID1 == spip) {
LPC_CCU2->CLK_APB0_SSP0_CFG = 1;
nvicEnableVector(SSP0_IRQn,
CORTEX_PRIORITY_MASK(LPC_SPI_SSP0_IRQ_PRIORITY));
}
#endif
#if LPC_SPI_USE_SSP1
if (&SPID2 == spip) {
LPC_CCU2->CLK_APB2_SSP1_CFG= 1;
nvicEnableVector(SSP1_IRQn,
CORTEX_PRIORITY_MASK(LPC_SPI_SSP1_IRQ_PRIORITY));
}
#endif
}
/* Configuration.*/
spip->ssp->CR1 = 0;
spip->ssp->ICR = ICR_RT | ICR_ROR;
spip->ssp->CR0 = spip->config->cr0;
spip->ssp->CPSR = spip->config->cpsr;
spip->ssp->CR1 = CR1_SSE;
}
/**
* @brief Deactivates the SPI peripheral.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_stop(SPIDriver *spip) {
if (spip->state != SPI_STOP) {
spip->ssp->CR1 = 0;
spip->ssp->CR0 = 0;
spip->ssp->CPSR = 0;
#if LPC_SPI_USE_SSP0
if (&SPID1 == spip) {
LPC_CCU2->CLK_APB0_SSP0_CFG = 0;
nvicDisableVector(SSP0_IRQn);
}
#endif
#if LPC_SPI_USE_SSP1
if (&SPID2 == spip) {
LPC_CCU2->CLK_APB2_SSP1_CFG= 0;
nvicDisableVector(SSP1_IRQn);
}
#endif
}
}
/**
* @brief Asserts the slave select signal and prepares for transfers.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_select(SPIDriver *spip) {
palClearPad(spip->config->ssport, spip->config->sspad);
}
/**
* @brief Deasserts the slave select signal.
* @details The previously selected peripheral is unselected.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_unselect(SPIDriver *spip) {
palSetPad(spip->config->ssport, spip->config->sspad);
}
/**
* @brief Ignores data on the SPI bus.
* @details This function transmits a series of idle words on the SPI bus and
* ignores the received data. This function can be invoked even
* when a slave select signal has not been yet asserted.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be ignored
*
* @notapi
*/
void spi_lld_ignore(SPIDriver *spip, size_t n) {
spip->rxptr = NULL;
spip->txptr = NULL;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Exchanges data on the SPI bus.
* @details This asynchronous function starts a simultaneous transmit/receive
* operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be exchanged
* @param[in] txbuf the pointer to the transmit buffer
* @param[out] rxbuf the pointer to the receive buffer
*
* @notapi
*/
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
spip->rxptr = rxbuf;
spip->txptr = txbuf;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Sends data over the SPI bus.
* @details This asynchronous function starts a transmit operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @notapi
*/
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
spip->rxptr = NULL;
spip->txptr = txbuf;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Receives data from the SPI bus.
* @details This asynchronous function starts a receive operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to receive
* @param[out] rxbuf the pointer to the receive buffer
*
* @notapi
*/
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
spip->rxptr = rxbuf;
spip->txptr = NULL;
spip->rxcnt = spip->txcnt = n;
ssp_fifo_preload(spip);
spip->ssp->IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Exchanges one frame using a polled wait.
* @details This synchronous function exchanges one frame using a polled
* synchronization method. This function is useful when exchanging
* small amount of data on high speed channels, usually in this
* situation is much more efficient just wait for completion using
* polling than suspending the thread waiting for an interrupt.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] frame the data frame to send over the SPI bus
* @return The received data frame from the SPI bus.
*/
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
spip->ssp->DR = (uint32_t)frame;
while ((spip->ssp->SR & SR_RNE) == 0)
;
return (uint16_t)spip->ssp->DR;
}
#endif /* HAL_USE_SPI */
/** @} */

View File

@ -1,301 +1,301 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/spi_lld.h
* @brief LPC43xx low level SPI driver header.
*
* @addtogroup SPI
* @{
*/
#ifndef _SPI_LLD_H_
#define _SPI_LLD_H_
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Hardware FIFO depth.
*/
#define LPC_SSP_FIFO_DEPTH 8
#define CR0_DSSMASK 0x0F
#define CR0_DSS4BIT 3
#define CR0_DSS5BIT 4
#define CR0_DSS6BIT 5
#define CR0_DSS7BIT 6
#define CR0_DSS8BIT 7
#define CR0_DSS9BIT 8
#define CR0_DSS10BIT 9
#define CR0_DSS11BIT 0xA
#define CR0_DSS12BIT 0xB
#define CR0_DSS13BIT 0xC
#define CR0_DSS14BIT 0xD
#define CR0_DSS15BIT 0xE
#define CR0_DSS16BIT 0xF
#define CR0_FRFSPI 0
#define CR0_FRFSSI 0x10
#define CR0_FRFMW 0x20
#define CR0_CPOL 0x40
#define CR0_CPHA 0x80
#define CR0_CLOCKRATE(n) ((n) << 8)
#define CR1_LBM 1
#define CR1_SSE 2
#define CR1_MS 4
#define CR1_SOD 8
#define SR_TFE 1
#define SR_TNF 2
#define SR_RNE 4
#define SR_RFF 8
#define SR_BSY 16
#define IMSC_ROR 1
#define IMSC_RT 2
#define IMSC_RX 4
#define IMSC_TX 8
#define RIS_ROR 1
#define RIS_RT 2
#define RIS_RX 4
#define RIS_TX 8
#define MIS_ROR 1
#define MIS_RT 2
#define MIS_RX 4
#define MIS_TX 8
#define ICR_ROR 1
#define ICR_RT 2
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief SPI1 driver enable switch.
* @details If set to @p TRUE the support for device SSP0 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_SPI_USE_SSP0) || defined(__DOXYGEN__)
#define LPC_SPI_USE_SSP0 TRUE
#endif
/**
* @brief SPI2 driver enable switch.
* @details If set to @p TRUE the support for device SSP1 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_SPI_USE_SSP1) || defined(__DOXYGEN__)
#define LPC_SPI_USE_SSP1 FALSE
#endif
/**
* @brief SSP0 PCLK divider.
*/
#if !defined(LPC_SPI_SSP0CLKDIV) || defined(__DOXYGEN__)
#define LPC_SPI_SSP0CLKDIV 1
#endif
/**
* @brief SSP1 PCLK divider.
*/
#if !defined(LPC_SPI_SSP1CLKDIV) || defined(__DOXYGEN__)
#define LPC_SPI_SSP1CLKDIV 1
#endif
/**
* @brief SPI0 interrupt priority level setting.
*/
#if !defined(LPC_SPI_SSP0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SPI_SSP0_IRQ_PRIORITY 5
#endif
/**
* @brief SPI1 interrupt priority level setting.
*/
#if !defined(LPC_SPI_SSP1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SPI_SSP1_IRQ_PRIORITY 5
#endif
/**
* @brief Overflow error hook.
* @details The default action is to stop the system.
*/
#if !defined(LPC_SPI_SSP_ERROR_HOOK) || defined(__DOXYGEN__)
#define LPC_SPI_SSP_ERROR_HOOK(spip) chSysHalt()
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !LPC_SPI_USE_SSP0 && !LPC_SPI_USE_SSP1
#error "SPI driver activated but no SPI peripheral assigned"
#endif
/**
* @brief SSP0 clock.
*/
#define LPC_SPI_SSP0_PCLK LPC_BASE_SSP0_CLK
/**
* @brief SSP1 clock.
*/
#define LPC_SPI_SSP1_PCLK LPC_BASE_SSP1_CLK
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an SPI driver.
*/
typedef struct SPIDriver SPIDriver;
/**
* @brief SPI notification callback type.
*
* @param[in] spip pointer to the @p SPIDriver object triggering the
* callback
*/
typedef void (*spicallback_t)(SPIDriver *spip);
/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
* @brief Operation complete callback or @p NULL.
*/
spicallback_t end_cb;
/* End of the mandatory fields.*/
/**
* @brief The chip select line port.
*/
ioportid_t ssport;
/**
* @brief The chip select line pad number.
*/
uint16_t sspad;
/**
* @brief SSP CR0 initialization data.
*/
uint16_t cr0;
/**
* @brief SSP CPSR initialization data.
*/
uint32_t cpsr;
} SPIConfig;
/**
* @brief Structure representing a SPI driver.
*/
struct SPIDriver {
/**
* @brief Driver state.
*/
spistate_t state;
/**
* @brief Current configuration data.
*/
const SPIConfig *config;
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif /* SPI_USE_WAIT */
#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* SPI_USE_MUTUAL_EXCLUSION */
#if defined(SPI_DRIVER_EXT_FIELDS)
SPI_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the SSP registers block.
*/
LPC_SSPn_Type *ssp;
/**
* @brief Number of bytes yet to be received.
*/
uint32_t rxcnt;
/**
* @brief Receive pointer or @p NULL.
*/
void *rxptr;
/**
* @brief Number of bytes yet to be transmitted.
*/
uint32_t txcnt;
/**
* @brief Transmit pointer or @p NULL.
*/
const void *txptr;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC_SPI_USE_SSP0 && !defined(__DOXYGEN__)
extern SPIDriver SPID1;
#endif
#if LPC_SPI_USE_SSP1 && !defined(__DOXYGEN__)
extern SPIDriver SPID2;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void spi_lld_init(void);
void spi_lld_start(SPIDriver *spip);
void spi_lld_stop(SPIDriver *spip);
void spi_lld_select(SPIDriver *spip);
void spi_lld_unselect(SPIDriver *spip);
void spi_lld_ignore(SPIDriver *spip, size_t n);
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf);
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SPI */
#endif /* _SPI_LLD_H_ */
/** @} */
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file LPC43xx/spi_lld.h
* @brief LPC43xx low level SPI driver header.
*
* @addtogroup SPI
* @{
*/
#ifndef _SPI_LLD_H_
#define _SPI_LLD_H_
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Hardware FIFO depth.
*/
#define LPC_SSP_FIFO_DEPTH 8
#define CR0_DSSMASK 0x0F
#define CR0_DSS4BIT 3
#define CR0_DSS5BIT 4
#define CR0_DSS6BIT 5
#define CR0_DSS7BIT 6
#define CR0_DSS8BIT 7
#define CR0_DSS9BIT 8
#define CR0_DSS10BIT 9
#define CR0_DSS11BIT 0xA
#define CR0_DSS12BIT 0xB
#define CR0_DSS13BIT 0xC
#define CR0_DSS14BIT 0xD
#define CR0_DSS15BIT 0xE
#define CR0_DSS16BIT 0xF
#define CR0_FRFSPI 0
#define CR0_FRFSSI 0x10
#define CR0_FRFMW 0x20
#define CR0_CPOL 0x40
#define CR0_CPHA 0x80
#define CR0_CLOCKRATE(n) ((n) << 8)
#define CR1_LBM 1
#define CR1_SSE 2
#define CR1_MS 4
#define CR1_SOD 8
#define SR_TFE 1
#define SR_TNF 2
#define SR_RNE 4
#define SR_RFF 8
#define SR_BSY 16
#define IMSC_ROR 1
#define IMSC_RT 2
#define IMSC_RX 4
#define IMSC_TX 8
#define RIS_ROR 1
#define RIS_RT 2
#define RIS_RX 4
#define RIS_TX 8
#define MIS_ROR 1
#define MIS_RT 2
#define MIS_RX 4
#define MIS_TX 8
#define ICR_ROR 1
#define ICR_RT 2
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief SPI1 driver enable switch.
* @details If set to @p TRUE the support for device SSP0 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_SPI_USE_SSP0) || defined(__DOXYGEN__)
#define LPC_SPI_USE_SSP0 TRUE
#endif
/**
* @brief SPI2 driver enable switch.
* @details If set to @p TRUE the support for device SSP1 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC_SPI_USE_SSP1) || defined(__DOXYGEN__)
#define LPC_SPI_USE_SSP1 FALSE
#endif
/**
* @brief SSP0 PCLK divider.
*/
#if !defined(LPC_SPI_SSP0CLKDIV) || defined(__DOXYGEN__)
#define LPC_SPI_SSP0CLKDIV 1
#endif
/**
* @brief SSP1 PCLK divider.
*/
#if !defined(LPC_SPI_SSP1CLKDIV) || defined(__DOXYGEN__)
#define LPC_SPI_SSP1CLKDIV 1
#endif
/**
* @brief SPI0 interrupt priority level setting.
*/
#if !defined(LPC_SPI_SSP0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SPI_SSP0_IRQ_PRIORITY 5
#endif
/**
* @brief SPI1 interrupt priority level setting.
*/
#if !defined(LPC_SPI_SSP1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SPI_SSP1_IRQ_PRIORITY 5
#endif
/**
* @brief Overflow error hook.
* @details The default action is to stop the system.
*/
#if !defined(LPC_SPI_SSP_ERROR_HOOK) || defined(__DOXYGEN__)
#define LPC_SPI_SSP_ERROR_HOOK(spip) chSysHalt()
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !LPC_SPI_USE_SSP0 && !LPC_SPI_USE_SSP1
#error "SPI driver activated but no SPI peripheral assigned"
#endif
/**
* @brief SSP0 clock.
*/
#define LPC_SPI_SSP0_PCLK LPC_BASE_SSP0_CLK
/**
* @brief SSP1 clock.
*/
#define LPC_SPI_SSP1_PCLK LPC_BASE_SSP1_CLK
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an SPI driver.
*/
typedef struct SPIDriver SPIDriver;
/**
* @brief SPI notification callback type.
*
* @param[in] spip pointer to the @p SPIDriver object triggering the
* callback
*/
typedef void (*spicallback_t)(SPIDriver *spip);
/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
* @brief Operation complete callback or @p NULL.
*/
spicallback_t end_cb;
/* End of the mandatory fields.*/
/**
* @brief The chip select line port.
*/
ioportid_t ssport;
/**
* @brief The chip select line pad number.
*/
uint16_t sspad;
/**
* @brief SSP CR0 initialization data.
*/
uint16_t cr0;
/**
* @brief SSP CPSR initialization data.
*/
uint32_t cpsr;
} SPIConfig;
/**
* @brief Structure representing a SPI driver.
*/
struct SPIDriver {
/**
* @brief Driver state.
*/
spistate_t state;
/**
* @brief Current configuration data.
*/
const SPIConfig *config;
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif /* SPI_USE_WAIT */
#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* SPI_USE_MUTUAL_EXCLUSION */
#if defined(SPI_DRIVER_EXT_FIELDS)
SPI_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the SSP registers block.
*/
LPC_SSPn_Type *ssp;
/**
* @brief Number of bytes yet to be received.
*/
uint32_t rxcnt;
/**
* @brief Receive pointer or @p NULL.
*/
void *rxptr;
/**
* @brief Number of bytes yet to be transmitted.
*/
uint32_t txcnt;
/**
* @brief Transmit pointer or @p NULL.
*/
const void *txptr;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC_SPI_USE_SSP0 && !defined(__DOXYGEN__)
extern SPIDriver SPID1;
#endif
#if LPC_SPI_USE_SSP1 && !defined(__DOXYGEN__)
extern SPIDriver SPID2;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void spi_lld_init(void);
void spi_lld_start(SPIDriver *spip);
void spi_lld_stop(SPIDriver *spip);
void spi_lld_select(SPIDriver *spip);
void spi_lld_unselect(SPIDriver *spip);
void spi_lld_ignore(SPIDriver *spip, size_t n);
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf);
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SPI */
#endif /* _SPI_LLD_H_ */
/** @} */

View File

@ -1,50 +1,50 @@
/**********************************************************************
* $Id$ system_lpc43xx.h 2011-06-02
*//**
* @file system_lpc43xx.h
* @brief Cortex-M3 Device System Header File for NXP lpc43xx Series.
* @version 1.0
* @date 02. June. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#ifndef __SYSTEM_lpc43xx_H
#define __SYSTEM_lpc43xx_H
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
/**
* Initialize the system
*
* @param none
* @return none
*
* @brief Setup the microcontroller system.
* Initialize the System and update the SystemCoreClock variable.
*/
extern void SystemInit (void);
#ifdef __cplusplus
}
#endif
#endif /* __SYSTEM_lpc43xx_H */
/**********************************************************************
* $Id$ system_lpc43xx.h 2011-06-02
*//**
* @file system_lpc43xx.h
* @brief Cortex-M3 Device System Header File for NXP lpc43xx Series.
* @version 1.0
* @date 02. June. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#ifndef __SYSTEM_lpc43xx_H
#define __SYSTEM_lpc43xx_H
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
/**
* Initialize the system
*
* @param none
* @return none
*
* @brief Setup the microcontroller system.
* Initialize the System and update the SystemCoreClock variable.
*/
extern void SystemInit (void);
#ifdef __cplusplus
}
#endif
#endif /* __SYSTEM_lpc43xx_H */