Add support for new microcontroller NXP LPC43xx.

Drivers for hal, pal, gpt, serial, mac, dac, spi, dma.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@6740 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
theshed 2014-03-01 21:29:32 +00:00
parent ba0368ae0b
commit 5b02bc9fc4
23 changed files with 42195 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +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 */
/** @} */

View File

@ -0,0 +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_ */
/** @} */

View File

@ -0,0 +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 */
/** @} */

View File

@ -0,0 +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_ */
/** @} */

View File

@ -0,0 +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 */
}
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +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 */
/** @} */

View File

@ -0,0 +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_ */
/** @} */

View File

@ -0,0 +1,748 @@
/*
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.
Ported from ChibiOS STM32 mac_lld driver.
*/
/**
* @file LPC43xx/mac_lld.c
* @brief LPC43xx low level MAC driver code.
*
* @addtogroup MAC
* @{
*/
#include <string.h>
#include "ch.h"
#include "hal.h"
#include "mii.h"
#if HAL_USE_MAC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define BUFFER_SIZE ((((LPC_MAC_BUFFERS_SIZE - 1) | 3) + 1) / 4)
/* MII divider optimal value.*/
#if (LPC_CLK_M4_ETHERNET >= 150000000)
#define MAC_MII_ADDR_CR ETH_MAC_MII_ADDR_CR_DIV_102
#elif (LPC_CLK_M4_ETHERNET >= 100000000)
#define MAC_MII_ADDR_CR ETH_MAC_MII_ADDR_CR_DIV_62
#elif (LPC_CLK_M4_ETHERNET >= 60000000)
#define MAC_MII_ADDR_CR ETH_MAC_MII_ADDR_CR_DIV_42
#elif (LPC_CLK_M4_ETHERNET >= 35000000)
#define MAC_MII_ADDR_CR ETH_MAC_MII_ADDR_CR_DIV_26
#elif (LPC_CLK_M4_ETHERNET >= 20000000)
#define MAC_MII_ADDR_CR ETH_MAC_MII_ADDR_CR_DIV_16
#else
#error "LPC_CLK_M4_ETHERNET below minimum frequency for ETH operations (20MHz)"
#endif
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief Ethernet driver 1.
*/
MACDriver ETHD1;
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
static const uint8_t default_mac_address[] = {0xAA, 0x55, 0x13,
0x37, 0x01, 0x10};
static lpc_eth_rx_descriptor_t rd[LPC_MAC_RECEIVE_BUFFERS];
static lpc_eth_tx_descriptor_t td[LPC_MAC_TRANSMIT_BUFFERS];
static uint32_t rb[LPC_MAC_RECEIVE_BUFFERS][BUFFER_SIZE];
static uint32_t tb[LPC_MAC_TRANSMIT_BUFFERS][BUFFER_SIZE];
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Enable MAC clock.
*/
static void mac_clk_enable(void) {
LPC_CGU->BASE_PHY_RX_CLK &= ~(1UL << 0);
LPC_CGU->BASE_PHY_TX_CLK &= ~(1UL << 0);
LPC_CCU1->CLK_M4_ETHERNET_CFG = 1;
}
/**
* @brief Disable MAC clock.
*/
static void mac_clk_disable(void) {
LPC_CGU->BASE_PHY_RX_CLK |= (1UL << 0);
LPC_CGU->BASE_PHY_TX_CLK |= (1UL << 0);
LPC_CCU1->CLK_M4_ETHERNET_CFG = 0;
}
/**
* @brief Writes a PHY register.
*
* @param[in] macp pointer to the @p MACDriver object
* @param[in] reg register number
* @param[in] value new register value
*/
static void mii_write(MACDriver *macp, uint32_t reg, uint32_t value) { // OK
LPC_ETHERNET->MAC_MII_DATA = value;
LPC_ETHERNET->MAC_MII_ADDR = macp->phyaddr | (reg << 6) | MAC_MII_ADDR_CR |
ETH_MAC_MII_ADDR_W | ETH_MAC_MII_ADDR_GB;
while ((LPC_ETHERNET->MAC_MII_ADDR & ETH_MAC_MII_ADDR_GB) != 0)
;
}
/**
* @brief Reads a PHY register.
*
* @param[in] macp pointer to the @p MACDriver object
* @param[in] reg register number
*
* @return The PHY register content.
*/
static uint32_t mii_read(MACDriver *macp, uint32_t reg) { // OK
LPC_ETHERNET->MAC_MII_ADDR = macp->phyaddr | (reg << 6) | MAC_MII_ADDR_CR | ETH_MAC_MII_ADDR_GB;
while ((LPC_ETHERNET->MAC_MII_ADDR & ETH_MAC_MII_ADDR_GB) != 0)
;
return LPC_ETHERNET->MAC_MII_DATA;
}
#if !defined(BOARD_PHY_ADDRESS)
/**
* @brief PHY address detection.
*
* @param[in] macp pointer to the @p MACDriver object
*/
static void mii_find_phy(MACDriver *macp) { // OK
uint32_t i;
#if LPC_MAC_PHY_TIMEOUT > 0
halrtcnt_t start = halGetCounterValue();
halrtcnt_t timeout = start + MS2RTT(LPC_MAC_PHY_TIMEOUT);
while (halIsCounterWithin(start, timeout)) {
#endif
for (i = 0; i < 31; i++) {
macp->phyaddr = i << 11;
LPC_ETHERNET->MAC_MII_DATA = (i << 6) | MAC_MII_ADDR_CR;
if ((mii_read(macp, MII_PHYSID1) == (BOARD_PHY_ID >> 16)) &&
((mii_read(macp, MII_PHYSID2) & 0xFFF0) == (BOARD_PHY_ID & 0xFFF0))) {
return;
}
}
#if LPC_MAC_PHY_TIMEOUT > 0
}
#endif
/* Wrong or defective board.*/
chSysHalt();
}
#endif
/**
* @brief MAC address setup.
*
* @param[in] p pointer to a six bytes buffer containing the MAC
* address
*/
static void mac_lld_set_address(const uint8_t *p) { // OK
/* MAC address configuration, only a single address comparator is used,
hash table not used.*/
LPC_ETHERNET->MAC_ADDR0_HIGH = ((uint32_t)p[5] << 8) |
((uint32_t)p[4] << 0);
LPC_ETHERNET->MAC_ADDR0_LOW = ((uint32_t)p[3] << 24) |
((uint32_t)p[2] << 16) |
((uint32_t)p[1] << 8) |
((uint32_t)p[0] << 0);
LPC_ETHERNET->MAC_HASHTABLE_HIGH = 0;
LPC_ETHERNET->MAC_HASHTABLE_LOW = 0;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
CH_IRQ_HANDLER(Vector54) { // OK
uint32_t dmasr;
CH_IRQ_PROLOGUE();
dmasr = LPC_ETHERNET->DMA_STAT;
LPC_ETHERNET->DMA_STAT = dmasr; /* Clear status bits.*/
if (dmasr & ETH_DMA_STAT_RI) {
/* Data Received.*/
chSysLockFromIsr();
chSemResetI(&ETHD1.rdsem, 0);
#if MAC_USE_EVENTS
chEvtBroadcastI(&ETHD1.rdevent);
#endif
chSysUnlockFromIsr();
}
if (dmasr & ETH_DMA_STAT_TI) {
/* Data Transmitted.*/
chSysLockFromIsr();
chSemResetI(&ETHD1.tdsem, 0);
chSysUnlockFromIsr();
}
CH_IRQ_EPILOGUE();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level MAC initialization.
*
* @notapi
*/
void mac_lld_init(void) {
unsigned i;
macObjectInit(&ETHD1);
ETHD1.link_up = FALSE;
/* Descriptor tables are initialized in chained mode, note that the first
word is not initialized here but in mac_lld_start().*/
for (i = 0; i < LPC_MAC_RECEIVE_BUFFERS; i++) {
rd[i].rdes1 = LPC_RDES1_RCH | LPC_MAC_BUFFERS_SIZE;
rd[i].rdes2 = (uint32_t)rb[i];
rd[i].rdes3 = (uint32_t)&rd[(i + 1) % LPC_MAC_RECEIVE_BUFFERS];
}
for (i = 0; i < LPC_MAC_TRANSMIT_BUFFERS; i++) {
td[i].tdes1 = 0;
td[i].tdes2 = (uint32_t)tb[i];
td[i].tdes3 = (uint32_t)&td[(i + 1) % LPC_MAC_TRANSMIT_BUFFERS];
}
/* Selection of the RMII or MII mode based on info exported by board.h.*/
#if defined(BOARD_PHY_RMII)
LPC_CREG->CREG6 |= (4UL << 0);
#else
LPC_CREG->CREG6 &= ~(7UL << 0);
#endif
/* Reset of the MAC core.*/
LPC_RGU->RESET_CTRL0 = (1UL << 22);
for (i = 0; i < (LPC_BASE_M4_CLK/IRCOSCCLK + 1); i++)
__NOP(); /* Wait. */
/* MAC clocks temporary activation.*/
mac_clk_enable();
/* PHY address setup.*/
#if defined(BOARD_PHY_ADDRESS)
ETHD1.phyaddr = BOARD_PHY_ADDRESS << 11;
#else
mii_find_phy(&ETHD1);
#endif
#if defined(BOARD_PHY_RESET)
/* PHY board-specific reset procedure.*/
BOARD_PHY_RESET();
#else
/* PHY soft reset procedure.*/
mii_write(&ETHD1, MII_BMCR, BMCR_RESET);
#if defined(BOARD_PHY_RESET_DELAY)
halPolledDelay(BOARD_PHY_RESET_DELAY);
#endif
while (mii_read(&ETHD1, MII_BMCR) & BMCR_RESET)
;
#endif
#if LPC_MAC_ETH1_CHANGE_PHY_STATE
/* PHY in power down mode until the driver will be started.*/
mii_write(&ETHD1, MII_BMCR, mii_read(&ETHD1, MII_BMCR) | BMCR_PDOWN);
#endif
/* MAC clocks stopped again.*/
mac_clk_disable();
}
/**
* @brief Configures and activates the MAC peripheral.
*
* @param[in] macp pointer to the @p MACDriver object
*
* @notapi
*/
void mac_lld_start(MACDriver *macp) {
unsigned i;
/* Resets the state of all descriptors.*/
for (i = 0; i < LPC_MAC_RECEIVE_BUFFERS; i++)
rd[i].rdes0 = LPC_RDES0_OWN;
macp->rxptr = (lpc_eth_rx_descriptor_t *)rd;
for (i = 0; i < LPC_MAC_TRANSMIT_BUFFERS; i++)
td[i].tdes0 = LPC_TDES0_TCH;
macp->txptr = (lpc_eth_tx_descriptor_t *)td;
/* MAC clocks activation and commanded reset procedure.*/
mac_clk_enable();
/* PHY in power up mode.*/
mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) & ~BMCR_PDOWN);
LPC_ETHERNET->DMA_BUS_MODE |= ETH_DMA_BUS_MODE_SWR; /* Software reset. */
while(LPC_ETHERNET->DMA_BUS_MODE & ETH_DMA_BUS_MODE_SWR)
;
/* ISR vector enabled.*/
nvicEnableVector(ETHERNET_IRQn,
CORTEX_PRIORITY_MASK(LPC_MAC_ETH1_IRQ_PRIORITY));
/* MAC configuration.*/
LPC_ETHERNET->MAC_FRAME_FILTER = 0;
LPC_ETHERNET->MAC_FLOW_CTRL = 0;
LPC_ETHERNET->MAC_VLAN_TAG = 0;
/* MAC address setup.*/
if (macp->config->mac_address == NULL)
mac_lld_set_address(default_mac_address);
else
mac_lld_set_address(macp->config->mac_address);
/* Transmitter and receiver enabled.
Note that the complete setup of the MAC is performed when the link
status is detected.*/
LPC_ETHERNET->MAC_CONFIG = ETH_MAC_CONFIG_RE | ETH_MAC_CONFIG_TE;
/* DMA configuration:
Descriptor chains pointers.*/
LPC_ETHERNET->DMA_REC_DES_ADDR = (uint32_t)rd;
LPC_ETHERNET->DMA_TRANS_DES_ADDR = (uint32_t)td;
/* Enabling required interrupt sources.*/
LPC_ETHERNET->DMA_STAT = LPC_ETHERNET->DMA_STAT;
LPC_ETHERNET->DMA_INT_EN = ETH_DMA_INT_EN_NIE | ETH_DMA_INT_EN_RIE | ETH_DMA_INT_EN_TIE;
/* DMA general settings.*/
LPC_ETHERNET->DMA_BUS_MODE = ETH_DMA_BUS_MODE_AAL | ETH_DMA_BUS_MODE_RPBL(1UL) |
ETH_DMA_BUS_MODE_PBL(1UL);
/* Transmit FIFO flush.*/
LPC_ETHERNET->DMA_OP_MODE = ETH_DMA_OP_MODE_FTF;
while (LPC_ETHERNET->DMA_OP_MODE & ETH_DMA_OP_MODE_FTF)
;
/* DMA final configuration and start.*/
LPC_ETHERNET->DMA_OP_MODE = ETH_DMA_OP_MODE_TTC_256 | ETH_DMA_OP_MODE_ST |
ETH_DMA_OP_MODE_RTC_128 | ETH_DMA_OP_MODE_SR;
}
/**
* @brief Deactivates the MAC peripheral.
*
* @param[in] macp pointer to the @p MACDriver object
*
* @notapi
*/
void mac_lld_stop(MACDriver *macp) {
if (macp->state != MAC_STOP) {
/* MAC and DMA stopped.*/
LPC_ETHERNET->MAC_CONFIG = 0;
LPC_ETHERNET->DMA_OP_MODE = 0;
LPC_ETHERNET->DMA_INT_EN = 0;
LPC_ETHERNET->DMA_STAT = LPC_ETHERNET->DMA_STAT;
/* PHY in power down mode until the driver will be restarted.*/
mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) | BMCR_PDOWN);
/* MAC clocks stopped.*/
mac_clk_disable();
/* ISR vector disabled.*/
nvicDisableVector(ETHERNET_IRQn);
}
}
/**
* @brief Returns a transmission descriptor.
* @details One of the available transmission descriptors is locked and
* returned.
*
* @param[in] macp pointer to the @p MACDriver object
* @param[out] tdp pointer to a @p MACTransmitDescriptor structure
* @return The operation status.
* @retval RDY_OK the descriptor has been obtained.
* @retval RDY_TIMEOUT descriptor not available.
*
* @notapi
*/
msg_t mac_lld_get_transmit_descriptor(MACDriver *macp,
MACTransmitDescriptor *tdp) {
lpc_eth_tx_descriptor_t *tdes;
if (!macp->link_up)
return RDY_TIMEOUT;
chSysLock();
/* Get Current TX descriptor.*/
tdes = macp->txptr;
/* Ensure that descriptor isn't owned by the Ethernet DMA or locked by
another thread.*/
if (tdes->tdes0 & (LPC_TDES0_OWN | LPC_TDES0_LOCKED)) {
chSysUnlock();
return RDY_TIMEOUT;
}
/* Marks the current descriptor as locked using a reserved bit.*/
tdes->tdes0 |= LPC_TDES0_LOCKED;
/* Next TX descriptor to use.*/
macp->txptr = (lpc_eth_tx_descriptor_t *)tdes->tdes3;
chSysUnlock();
/* Set the buffer size and configuration.*/
tdp->offset = 0;
tdp->size = LPC_MAC_BUFFERS_SIZE;
tdp->physdesc = tdes;
return RDY_OK;
}
/**
* @brief Releases a transmit descriptor and starts the transmission of the
* enqueued data as a single frame.
*
* @param[in] tdp the pointer to the @p MACTransmitDescriptor structure
*
* @notapi
*/
void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp) {
chDbgAssert(!(tdp->physdesc->tdes0 & LPC_TDES0_OWN),
"mac_lld_release_transmit_descriptor(), #1",
"attempt to release descriptor already owned by DMA");
chSysLock();
/* Unlocks the descriptor and returns it to the DMA engine.*/
tdp->physdesc->tdes1 = tdp->offset;
tdp->physdesc->tdes0 = LPC_TDES0_CIC(LPC_MAC_IP_CHECKSUM_OFFLOAD) |
LPC_TDES0_IC | LPC_TDES0_LS | LPC_TDES0_FS |
LPC_TDES0_TCH | LPC_TDES0_OWN;
/* If the DMA engine is stalled then a restart request is issued.*/
if ((LPC_ETHERNET->DMA_STAT & ETH_DMA_STAT_TS) == ETH_DMA_STAT_TS_SUSPEND) {
LPC_ETHERNET->DMA_STAT = ETH_DMA_STAT_TU;
LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = ETH_DMA_STAT_TU; /* Any value is OK.*/
}
chSysUnlock();
}
/**
* @brief Returns a receive descriptor.
*
* @param[in] macp pointer to the @p MACDriver object
* @param[out] rdp pointer to a @p MACReceiveDescriptor structure
* @return The operation status.
* @retval RDY_OK the descriptor has been obtained.
* @retval RDY_TIMEOUT descriptor not available.
*
* @notapi
*/
msg_t mac_lld_get_receive_descriptor(MACDriver *macp,
MACReceiveDescriptor *rdp) {
lpc_eth_rx_descriptor_t *rdes;
chSysLock();
/* Get Current RX descriptor.*/
rdes = macp->rxptr;
/* Iterates through received frames until a valid one is found, invalid
frames are discarded.*/
while (!(rdes->rdes0 & LPC_RDES0_OWN)) {
if (!(rdes->rdes0 & (LPC_RDES0_AFM | LPC_RDES0_ES))
#if LPC_MAC_IP_CHECKSUM_OFFLOAD
&& (rdes->rdes0 & LPC_RDES0_FT)
&& !(rdes->rdes0 & (LPC_RDES0_IPHCE | LPC_RDES0_PCE))
#endif
&& (rdes->rdes0 & LPC_RDES0_FS) && (rdes->rdes0 & LPC_RDES0_LS)) {
/* Found a valid one.*/
rdp->offset = 0;
rdp->size = ((rdes->rdes0 & LPC_RDES0_FL_MASK) >> 16) - 4;
rdp->physdesc = rdes;
macp->rxptr = (lpc_eth_rx_descriptor_t *)rdes->rdes3;
chSysUnlock();
return RDY_OK;
}
/* Invalid frame found, purging.*/
rdes->rdes0 = LPC_RDES0_OWN;
rdes = (lpc_eth_rx_descriptor_t *)rdes->rdes3;
}
/* Next descriptor to check.*/
macp->rxptr = rdes;
chSysUnlock();
return RDY_TIMEOUT;
}
/**
* @brief Releases a receive descriptor.
* @details The descriptor and its buffer are made available for more incoming
* frames.
*
* @param[in] rdp the pointer to the @p MACReceiveDescriptor structure
*
* @notapi
*/
void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp) {
chDbgAssert(!(rdp->physdesc->rdes0 & LPC_RDES0_OWN),
"mac_lld_release_receive_descriptor(), #1",
"attempt to release descriptor already owned by DMA");
chSysLock();
/* Give buffer back to the Ethernet DMA.*/
rdp->physdesc->rdes0 = LPC_RDES0_OWN;
/* If the DMA engine is stalled then a restart request is issued.*/
if ((LPC_ETHERNET->DMA_STAT & ETH_DMA_STAT_RS) == ETH_DMA_STAT_RS_SUSPEND) {
LPC_ETHERNET->DMA_STAT = ETH_DMA_STAT_RU;
LPC_ETHERNET->DMA_REC_POLL_DEMAND = ETH_DMA_STAT_RU; /* Any value is OK.*/
}
chSysUnlock();
}
/**
* @brief Updates and returns the link status.
*
* @param[in] macp pointer to the @p MACDriver object
* @return The link status.
* @retval TRUE if the link is active.
* @retval FALSE if the link is down.
*
* @notapi
*/
bool_t mac_lld_poll_link_status(MACDriver *macp) {
uint32_t maccr, bmsr, bmcr;
maccr = LPC_ETHERNET->MAC_CONFIG;
/* PHY CR and SR registers read.*/
(void)mii_read(macp, MII_BMSR);
bmsr = mii_read(macp, MII_BMSR);
bmcr = mii_read(macp, MII_BMCR);
/* Check on auto-negotiation mode.*/
if (bmcr & BMCR_ANENABLE) {
uint32_t lpa;
/* Auto-negotiation must be finished without faults and link established.*/
if ((bmsr & (BMSR_LSTATUS | BMSR_RFAULT | BMSR_ANEGCOMPLETE)) !=
(BMSR_LSTATUS | BMSR_ANEGCOMPLETE))
return macp->link_up = FALSE;
/* Auto-negotiation enabled, checks the LPA register.*/
lpa = mii_read(macp, MII_LPA);
/* Check on link speed.*/
if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4))
maccr |= ETH_MAC_CONFIG_FES;
else
maccr &= ~ETH_MAC_CONFIG_FES;
/* Check on link mode.*/
if (lpa & (LPA_10FULL | LPA_100FULL))
maccr |= ETH_MAC_CONFIG_DM;
else
maccr &= ~ETH_MAC_CONFIG_DM;
}
else {
/* Link must be established.*/
if (!(bmsr & BMSR_LSTATUS))
return macp->link_up = FALSE;
/* Check on link speed.*/
if (bmcr & BMCR_SPEED100)
maccr |= ETH_MAC_CONFIG_FES;
else
maccr &= ~ETH_MAC_CONFIG_FES;
/* Check on link mode.*/
if (bmcr & BMCR_FULLDPLX)
maccr |= ETH_MAC_CONFIG_DM;
else
maccr &= ~ETH_MAC_CONFIG_DM;
}
/* Changes the mode in the MAC.*/
LPC_ETHERNET->MAC_CONFIG = maccr;
/* Returns the link status.*/
return macp->link_up = TRUE;
}
/**
* @brief Writes to a transmit descriptor's stream.
*
* @param[in] tdp pointer to a @p MACTransmitDescriptor structure
* @param[in] buf pointer to the buffer containing the data to be
* written
* @param[in] size number of bytes to be written
* @return The number of bytes written into the descriptor's
* stream, this value can be less than the amount
* specified in the parameter @p size if the maximum
* frame size is reached.
*
* @notapi
*/
size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
uint8_t *buf,
size_t size) {
chDbgAssert(!(tdp->physdesc->tdes0 & LPC_TDES0_OWN),
"mac_lld_write_transmit_descriptor(), #1",
"attempt to write descriptor already owned by DMA");
if (size > tdp->size - tdp->offset)
size = tdp->size - tdp->offset;
if (size > 0) {
memcpy((uint8_t *)(tdp->physdesc->tdes2) + tdp->offset, buf, size);
tdp->offset += size;
}
return size;
}
/**
* @brief Reads from a receive descriptor's stream.
*
* @param[in] rdp pointer to a @p MACReceiveDescriptor structure
* @param[in] buf pointer to the buffer that will receive the read data
* @param[in] size number of bytes to be read
* @return The number of bytes read from the descriptor's
* stream, this value can be less than the amount
* specified in the parameter @p size if there are
* no more bytes to read.
*
* @notapi
*/
size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
uint8_t *buf,
size_t size) {
chDbgAssert(!(rdp->physdesc->rdes0 & LPC_RDES0_OWN),
"mac_lld_read_receive_descriptor(), #1",
"attempt to read descriptor already owned by DMA");
if (size > rdp->size - rdp->offset)
size = rdp->size - rdp->offset;
if (size > 0) {
memcpy(buf, (uint8_t *)(rdp->physdesc->rdes2) + rdp->offset, size);
rdp->offset += size;
}
return size;
}
#if MAC_USE_ZERO_COPY || defined(__DOXYGEN__)
/**
* @brief Returns a pointer to the next transmit buffer in the descriptor
* chain.
* @note The API guarantees that enough buffers can be requested to fill
* a whole frame.
*
* @param[in] tdp pointer to a @p MACTransmitDescriptor structure
* @param[in] size size of the requested buffer. Specify the frame size
* on the first call then scale the value down subtracting
* the amount of data already copied into the previous
* buffers.
* @param[out] sizep pointer to variable receiving the buffer size, it is
* zero when the last buffer has already been returned.
* Note that a returned size lower than the amount
* requested means that more buffers must be requested
* in order to fill the frame data entirely.
* @return Pointer to the returned buffer.
* @retval NULL if the buffer chain has been entirely scanned.
*
* @notapi
*/
uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp,
size_t size,
size_t *sizep) {
if (tdp->offset == 0) {
*sizep = tdp->size;
tdp->offset = size;
return (uint8_t *)tdp->physdesc->tdes2;
}
*sizep = 0;
return NULL;
}
/**
* @brief Returns a pointer to the next receive buffer in the descriptor
* chain.
* @note The API guarantees that the descriptor chain contains a whole
* frame.
*
* @param[in] rdp pointer to a @p MACReceiveDescriptor structure
* @param[out] sizep pointer to variable receiving the buffer size, it is
* zero when the last buffer has already been returned.
* @return Pointer to the returned buffer.
* @retval NULL if the buffer chain has been entirely scanned.
*
* @notapi
*/
const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp,
size_t *sizep) {
if (rdp->size > 0) {
*sizep = rdp->size;
rdp->offset = rdp->size;
rdp->size = 0;
return (uint8_t *)rdp->physdesc->rdes2;
}
*sizep = 0;
return NULL;
}
#endif /* MAC_USE_ZERO_COPY */
#endif /* HAL_USE_MAC */
/** @} */

View File

@ -0,0 +1,687 @@
/*
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.
Ported from ChibiOS STM32 mac_lld driver.
*/
/**
* @file LPC43xx/mac_lld.h
* @brief LPC43xx low level MAC driver header.
*
* @addtogroup MAC
* @{
*/
#ifndef _MAC_LLD_H_
#define _MAC_LLD_H_
#if HAL_USE_MAC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief This implementation supports the zero-copy mode API.
*/
#define MAC_SUPPORTS_ZERO_COPY TRUE
/**
* @name MAC Configuration register bits
* @{
*/
#define ETH_MAC_CONFIG_RE (1UL << 2)
#define ETH_MAC_CONFIG_TE (1UL << 3)
#define ETH_MAC_CONFIG_DF (1UL << 4)
#define ETH_MAC_CONFIG_BL_MIN_N_10 (0UL << 5)
#define ETH_MAC_CONFIG_BL_MIN_N_8 (1UL << 5)
#define ETH_MAC_CONFIG_BL_MIN_N_4 (2UL << 5)
#define ETH_MAC_CONFIG_BL_MIN_N_1 (3UL << 5)
#define ETH_MAC_CONFIG_ACS (1UL << 7)
#define ETH_MAC_CONFIG_DR (1UL << 9)
#define ETH_MAC_CONFIG_DM (1UL << 11)
#define ETH_MAC_CONFIG_LM (1UL << 12)
#define ETH_MAC_CONFIG_DO (1UL << 13)
#define ETH_MAC_CONFIG_FES (1UL << 14)
#define ETH_MAC_CONFIG_PS (1UL << 15)
#define ETH_MAC_CONFIG_DCRS (1UL << 16)
#define ETH_MAC_CONFIG_IFG_96 (0UL << 17)
#define ETH_MAC_CONFIG_IFG_88 (1UL << 17)
#define ETH_MAC_CONFIG_IFG_80 (2UL << 17)
#define ETH_MAC_CONFIG_IFG_72 (3UL << 17)
#define ETH_MAC_CONFIG_IFG_64 (4UL << 17)
#define ETH_MAC_CONFIG_IFG_56 (5UL << 17)
#define ETH_MAC_CONFIG_IFG_48 (6UL << 17)
#define ETH_MAC_CONFIG_IFG_40 (7UL << 17)
#define ETH_MAC_CONFIG_JE (1UL << 20)
#define ETH_MAC_CONFIG_JD (1UL << 22)
#define ETH_MAC_CONFIG_WD (1UL << 23)
/** @} */
/**
* @name MAC Frame filter register bits
* @{
*/
#define ETH_MAC_FRAME_FILTER_PR (1UL << 0)
#define ETH_MAC_FRAME_FILTER_HUC (1UL << 1)
#define ETH_MAC_FRAME_FILTER_HMC (1UL << 2)
#define ETH_MAC_FRAME_FILTER_DAIF (1UL << 3)
#define ETH_MAC_FRAME_FILTER_PM (1UL << 4)
#define ETH_MAC_FRAME_FILTER_DBF (1UL << 5)
#define ETH_MAC_FRAME_FILTER_PCF_FILTER_ALL (1UL << 6)
#define ETH_MAC_FRAME_FILTER_PCF_FOR_ALL (1UL << 6)
#define ETH_MAC_FRAME_FILTER_PCF_FOR_FAIL_ADDR (1UL << 6)
#define ETH_MAC_FRAME_FILTER_PCF_FOR_PASS_ADDR (1UL << 6)
#define ETH_MAC_FRAME_FILTER_HPF (1UL << 10)
#define ETH_MAC_FRAME_FILTER_RA (1UL << 31)
/** @} */
/**
* @name MAC MII Address register bits
* @{
*/
#define ETH_MAC_MII_ADDR_GB (1UL << 0)
#define ETH_MAC_MII_ADDR_W (1UL << 1)
#define ETH_MAC_MII_ADDR_CR_DIV_42 (0UL << 2)
#define ETH_MAC_MII_ADDR_CR_DIV_62 (1UL << 2)
#define ETH_MAC_MII_ADDR_CR_DIV_16 (2UL << 2)
#define ETH_MAC_MII_ADDR_CR_DIV_26 (3UL << 2)
#define ETH_MAC_MII_ADDR_CR_DIV_102 (4UL << 2)
#define ETH_MAC_MII_ADDR_CR_DIV_124 (5UL << 2)
#define ETH_MAC_MII_ADDR_GR(reg) ((reg) << 6)
#define ETH_MAC_MII_ADDR_PA(addr) ((addr) << 11)
/** @} */
/**
* @name MAC Flow control register bits
* @{
*/
#define ETH_MAC_FLOW_CTRL_FCB (1UL << 0)
#define ETH_MAC_FLOW_CTRL_TFE (1UL << 1)
#define ETH_MAC_FLOW_CTRL_RFE (1UL << 2)
#define ETH_MAC_FLOW_CTRL_UP (1UL << 3)
#define ETH_MAC_FLOW_CTRL_PLT(t) ((t) << 4)
#define ETH_MAC_FLOW_CTRL_DZPQ (1UL << 7)
#define ETH_MAC_FLOW_CTRL_PT(t) ((t) << 16)
/** @} */
/**
* @name MAC VLAN tag register bits
* @{
*/
#define ETH_MAC_VLAN_TAG_VL(t) ((t) << 0)
#define ETH_MAC_FLOW_CTRL_ETV (1UL << 16)
/** @} */
/**
* @name MAC Debug register bits
* @{
*/
#define ETH_MAC_DEBUG_RXIDLESTAT (1UL << 0)
#define ETH_MAC_DEBUG_FIFOSTAT0 (1UL << 1)
#define ETH_MAC_DEBUG_RXFIFOSTAT1 (1UL << 4)
#define ETH_MAC_DEBUG_RXFIFOSTAT (3UL << 5)
#define ETH_MAC_DEBUG_RXFIFOSTAT_IDLE (0UL << 5)
#define ETH_MAC_DEBUG_RXFIFOSTAT_RD_D (1UL << 5)
#define ETH_MAC_DEBUG_RXFIFOSTAT_RD_ST (2UL << 5)
#define ETH_MAC_DEBUG_RXFIFOSTAT_FLUSH (3UL << 5)
#define ETH_MAC_DEBUG_RXFIFOLVL (3UL << 8)
#define ETH_MAC_DEBUG_RXFIFOLVL_EMPTY (0UL << 8)
#define ETH_MAC_DEBUG_RXFIFOLVL_BELOW (1UL << 8)
#define ETH_MAC_DEBUG_RXFIFOLVL_ABOVE (2UL << 8)
#define ETH_MAC_DEBUG_RXFIFOLVL_FULL (3UL << 8)
#define ETH_MAC_DEBUG_TXIDLESTAT (1UL << 16)
#define ETH_MAC_DEBUG_TXSTAT (3UL << 17)
#define ETH_MAC_DEBUG_TXSTAT_IDLE (0UL << 17)
#define ETH_MAC_DEBUG_TXSTAT_WAIT (1UL << 17)
#define ETH_MAC_DEBUG_TXSTAT_GEN (2UL << 17)
#define ETH_MAC_DEBUG_TXSTAT_TRAN (3UL << 17)
#define ETH_MAC_DEBUG_PAUSE (1UL << 19)
#define ETH_MAC_DEBUG_TXFIFOSTAT (3UL << 20)
#define ETH_MAC_DEBUG_TXFIFOSTAT_IDLE (0UL << 20)
#define ETH_MAC_DEBUG_TXFIFOSTAT_READ (1UL << 20)
#define ETH_MAC_DEBUG_TXFIFOSTAT_WAIT (1UL << 20)
#define ETH_MAC_DEBUG_TXFIFOSTAT_WRITE (1UL << 20)
#define ETH_MAC_DEBUG_TXFIFOSTAT1 (1UL << 22)
#define ETH_MAC_DEBUG_TXFIFOLVL (1UL << 24)
#define ETH_MAC_DEBUG_TXFIFOFULL (1UL << 25)
/** @} */
/**
* @name MAC PMT control and status register bits
* @{
*/
#define ETH_MAC_PMT_CTRL_STAT_PD (1UL << 0)
#define ETH_MAC_PMT_CTRL_STAT_MPE (1UL << 1)
#define ETH_MAC_PMT_CTRL_STAT_WFE (1UL << 2)
#define ETH_MAC_PMT_CTRL_STAT_MPR (1UL << 5)
#define ETH_MAC_PMT_CTRL_STAT_WFR (1UL << 6)
#define ETH_MAC_PMT_CTRL_STAT_GU (1UL << 9)
#define ETH_MAC_PMT_CTRL_STAT_WFFRPR (1UL << 31)
/** @} */
/**
* @name MAC Interrupt status register bits
* @{
*/
#define ETH_MAC_INTR_PMT (1UL << 3)
#define ETH_MAC_INTR_TS (1UL << 9)
/** @} */
/**
* @name MAC Interrupt mask register bits
* @{
*/
#define ETH_MAC_INTR_MASK_PMTIM (1UL << 3)
#define ETH_MAC_INTR_MASK_TSIM (1UL << 9)
/** @} */
/**
* @name MAC IEEE1588 time stamp control register bits
* @{
*/
#define ETH_MAC_TIMESTP_CTRL_TSENA (1UL << 0)
#define ETH_MAC_TIMESTP_CTRL_TSCFUPDT (1UL << 1)
#define ETH_MAC_TIMESTP_CTRL_TSINIT (1UL << 2)
#define ETH_MAC_TIMESTP_CTRL_TSUPDT (1UL << 3)
#define ETH_MAC_TIMESTP_CTRL_TSTRIG (1UL << 4)
#define ETH_MAC_TIMESTP_CTRL_TSADDREG (1UL << 5)
#define ETH_MAC_TIMESTP_CTRL_TSENALL (1UL << 8)
#define ETH_MAC_TIMESTP_CTRL_TSCTRLSSR (1UL << 9)
#define ETH_MAC_TIMESTP_CTRL_TSVER2ENA (1UL << 10)
#define ETH_MAC_TIMESTP_CTRL_TSIPENA (1UL << 11)
#define ETH_MAC_TIMESTP_CTRL_TSIPV6ENA (1UL << 12)
#define ETH_MAC_TIMESTP_CTRL_TSIPV4ENA (1UL << 13)
#define ETH_MAC_TIMESTP_CTRL_TSEVNTENA (1UL << 14)
#define ETH_MAC_TIMESTP_CTRL_TSMSTRENA (1UL << 15)
#define ETH_MAC_TIMESTP_CTRL_TSCLKTYPE (3UL << 16)
#define ETH_MAC_TIMESTP_CTRL_TSCLKTYPE_OCLK (0UL << 16)
#define ETH_MAC_TIMESTP_CTRL_TSCLKTYPE_BCLK (1UL << 16)
#define ETH_MAC_TIMESTP_CTRL_TSCLKTYPE_ETETCLK (2UL << 16)
#define ETH_MAC_TIMESTP_CTRL_TSCLKTYPE_PTPTCLK (3UL << 16)
#define ETH_MAC_TIMESTP_CTRL_TSENMACADDR (1UL << 18)
/** @} */
/**
* @name System time nanoseconds register bits
* @{
*/
#define ETH_NANOSECONDS_PSNT (1UL << 31)
/** @} */
/**
* @name System time nanoseconds update register bits
* @{
*/
#define ETH_NANOSECONDSUPDATE_ADDSUB (1UL << 31)
/** @} */
/**
* @name Time stamp status register bits
* @{
*/
#define ETH_TIMESTAMPSTAT_TSSOVF (1UL << 0)
#define ETH_TIMESTAMPSTAT_TSTARGT (1UL << 1)
/** @} */
/**
* @name DMA Bus mode register bits
* @{
*/
#define ETH_DMA_BUS_MODE_SWR (1UL << 0)
#define ETH_DMA_BUS_MODE_DA (1UL << 1)
#define ETH_DMA_BUS_MODE_DSL(len) ((len) << 2)
#define ETH_DMA_BUS_MODE_ATDS (1UL << 7)
#define ETH_DMA_BUS_MODE_PBL(len) ((len) << 8)
#define ETH_DMA_BUS_MODE_PR (3UL << 14)
#define ETH_DMA_BUS_MODE_PR_1T1 (0UL << 14)
#define ETH_DMA_BUS_MODE_PR_2T1 (1UL << 14)
#define ETH_DMA_BUS_MODE_PR_3T1 (2UL << 14)
#define ETH_DMA_BUS_MODE_PR_4T1 (3UL << 14)
#define ETH_DMA_BUS_MODE_FB (1UL << 16)
#define ETH_DMA_BUS_MODE_RPBL(n) ((n) << 17)
#define ETH_DMA_BUS_MODE_USP (1UL << 23)
#define ETH_DMA_BUS_MODE_PBL8X (1UL << 24)
#define ETH_DMA_BUS_MODE_AAL (1UL << 25)
#define ETH_DMA_BUS_MODE_MB (1UL << 26)
#define ETH_DMA_BUS_MODE_TXPR (1UL << 27)
/** @} */
/**
* @name DMA Status register bits
* @{
*/
#define ETH_DMA_STAT_TI (1UL << 0)
#define ETH_DMA_STAT_TPS (1UL << 1)
#define ETH_DMA_STAT_TU (1UL << 2)
#define ETH_DMA_STAT_TJT (1UL << 3)
#define ETH_DMA_STAT_OVF (1UL << 4)
#define ETH_DMA_STAT_UNF (1UL << 5)
#define ETH_DMA_STAT_RI (1UL << 6)
#define ETH_DMA_STAT_RU (1UL << 7)
#define ETH_DMA_STAT_RPS (1UL << 8)
#define ETH_DMA_STAT_RWT (1UL << 9)
#define ETH_DMA_STAT_ETI (1UL << 10)
#define ETH_DMA_STAT_FBI (1UL << 13)
#define ETH_DMA_STAT_ERI (1UL << 14)
#define ETH_DMA_STAT_AIE (1UL << 15)
#define ETH_DMA_STAT_NIS (1UL << 16)
#define ETH_DMA_STAT_RS (7UL << 17)
#define ETH_DMA_STAT_RS_STOP (0UL << 17)
#define ETH_DMA_STAT_RS_RUN_FETCH (1UL << 17)
#define ETH_DMA_STAT_RS_RUN_WAIT (3UL << 17)
#define ETH_DMA_STAT_RS_SUSPEND (4UL << 17)
#define ETH_DMA_STAT_RS_RUN_CLOSE (5UL << 17)
#define ETH_DMA_STAT_RS_TIME_STAMP (6UL << 17)
#define ETH_DMA_STAT_RS_RUN_TRANSFER (7UL << 17)
#define ETH_DMA_STAT_TS (7UL << 20)
#define ETH_DMA_STAT_TS_STOP (0UL << 20)
#define ETH_DMA_STAT_TS_RUN_FETCH (1UL << 20)
#define ETH_DMA_STAT_TS_RUN_WAIT (2UL << 20)
#define ETH_DMA_STAT_TS_RUN_READ (3UL << 20)
#define ETH_DMA_STAT_TS_TIME_STAMP (4UL << 20)
#define ETH_DMA_STAT_TS_SUSPEND (6UL << 20)
#define ETH_DMA_STAT_TS_RUN_CLOSE (7UL << 20)
#define ETH_DMA_STAT_EB1 (1UL << 23)
#define ETH_DMA_STAT_EB2 (1UL << 24)
#define ETH_DMA_STAT_EB3 (1UL << 25)
/** @} */
/**
* @name DMA Operation mode register bits
* @{
*/
#define ETH_DMA_OP_MODE_SR (1UL << 1)
#define ETH_DMA_OP_MODE_OSF (1UL << 2)
#define ETH_DMA_OP_MODE_RTC (3UL << 3)
#define ETH_DMA_OP_MODE_RTC_64 (0UL << 3)
#define ETH_DMA_OP_MODE_RTC_32 (1UL << 3)
#define ETH_DMA_OP_MODE_RTC_96 (2UL << 3)
#define ETH_DMA_OP_MODE_RTC_128 (3UL << 3)
#define ETH_DMA_OP_MODE_FUF (1UL << 6)
#define ETH_DMA_OP_MODE_FEF (1UL << 7)
#define ETH_DMA_OP_MODE_ST (1UL << 13)
#define ETH_DMA_OP_MODE_TTC (7UL << 14)
#define ETH_DMA_OP_MODE_TTC_64 (0UL << 14)
#define ETH_DMA_OP_MODE_TTC_128 (1UL << 14)
#define ETH_DMA_OP_MODE_TTC_192 (2UL << 14)
#define ETH_DMA_OP_MODE_TTC_256 (3UL << 14)
#define ETH_DMA_OP_MODE_TTC_40 (4UL << 14)
#define ETH_DMA_OP_MODE_TTC_32 (5UL << 14)
#define ETH_DMA_OP_MODE_TTC_24 (6UL << 14)
#define ETH_DMA_OP_MODE_TTC_16 (7UL << 14)
#define ETH_DMA_OP_MODE_FTF (1UL << 20)
#define ETH_DMA_OP_MODE_DFF (1UL << 24)
/** @} */
/**
* @name DMA Interrupt enable register bits
* @{
*/
#define ETH_DMA_INT_EN_TIE (1UL << 0)
#define ETH_DMA_INT_EN_TSE (1UL << 1)
#define ETH_DMA_INT_EN_TUE (1UL << 2)
#define ETH_DMA_INT_EN_TJE (1UL << 3)
#define ETH_DMA_INT_EN_OVE (1UL << 4)
#define ETH_DMA_INT_EN_UNE (1UL << 5)
#define ETH_DMA_INT_EN_RIE (1UL << 6)
#define ETH_DMA_INT_EN_RUE (1UL << 7)
#define ETH_DMA_INT_EN_RSE (1UL << 8)
#define ETH_DMA_INT_EN_RWE (1UL << 9)
#define ETH_DMA_INT_EN_ETE (1UL << 10)
#define ETH_DMA_INT_EN_FBE (1UL << 13)
#define ETH_DMA_INT_EN_ERE (1UL << 14)
#define ETH_DMA_INT_EN_AIE (1UL << 15)
#define ETH_DMA_INT_EN_NIE (1UL << 16)
/** @} */
/**
* @name DMA Missed frame and buffer overflow counter register bits
* @{
*/
#define ETH_DMA_MFRM_BUFOF_FMC 0x0000FFFF
#define ETH_DMA_MFRM_BUFOF_OC (1UL << 16)
#define ETH_DMA_MFRM_BUFOF_FMA 0x0FFE0000
#define ETH_DMA_MFRM_BUFOF_OF (1UL << 28)
/** @} */
/**
* @name RDES0 constants
* @{
*/
#define LPC_RDES0_OWN 0x80000000
#define LPC_RDES0_AFM 0x40000000
#define LPC_RDES0_FL_MASK 0x3FFF0000
#define LPC_RDES0_ES 0x00008000
#define LPC_RDES0_DESERR 0x00004000
#define LPC_RDES0_SAF 0x00002000
#define LPC_RDES0_LE 0x00001000
#define LPC_RDES0_OE 0x00000800
#define LPC_RDES0_VLAN 0x00000400
#define LPC_RDES0_FS 0x00000200
#define LPC_RDES0_LS 0x00000100
#define LPC_RDES0_IPHCE 0x00000080
#define LPC_RDES0_LCO 0x00000040
#define LPC_RDES0_FT 0x00000020
#define LPC_RDES0_RWT 0x00000010
#define LPC_RDES0_RE 0x00000008
#define LPC_RDES0_DE 0x00000004
#define LPC_RDES0_CE 0x00000002
#define LPC_RDES0_PCE 0x00000001
/** @} */
/**
* @name RDES1 constants
* @{
*/
#define LPC_RDES1_DIC 0x80000000
#define LPC_RDES1_RBS2_MASK 0x1FFF0000
#define LPC_RDES1_RER 0x00008000
#define LPC_RDES1_RCH 0x00004000
#define LPC_RDES1_RBS1_MASK 0x00001FFF
/** @} */
/**
* @name TDES0 constants
* @{
*/
#define LPC_TDES0_OWN 0x80000000
#define LPC_TDES0_IC 0x40000000
#define LPC_TDES0_LS 0x20000000
#define LPC_TDES0_FS 0x10000000
#define LPC_TDES0_DC 0x08000000
#define LPC_TDES0_DP 0x04000000
#define LPC_TDES0_TTSE 0x02000000
#define LPC_TDES0_LOCKED 0x01000000 /* NOTE: Pseudo flag. */
#define LPC_TDES0_CIC_MASK 0x00C00000
#define LPC_TDES0_CIC(n) ((n) << 22)
#define LPC_TDES0_TER 0x00200000
#define LPC_TDES0_TCH 0x00100000
#define LPC_TDES0_TTSS 0x00020000
#define LPC_TDES0_IHE 0x00010000
#define LPC_TDES0_ES 0x00008000
#define LPC_TDES0_JT 0x00004000
#define LPC_TDES0_FF 0x00002000
#define LPC_TDES0_IPE 0x00001000
#define LPC_TDES0_LCA 0x00000800
#define LPC_TDES0_NC 0x00000400
#define LPC_TDES0_LCO 0x00000200
#define LPC_TDES0_EC 0x00000100
#define LPC_TDES0_VF 0x00000080
#define LPC_TDES0_CC_MASK 0x00000078
#define LPC_TDES0_ED 0x00000004
#define LPC_TDES0_UF 0x00000002
#define LPC_TDES0_DB 0x00000001
/** @} */
/**
* @name TDES1 constants
* @{
*/
#define LPC_TDES1_TBS2_MASK 0x1FFF0000
#define LPC_TDES1_TBS1_MASK 0x00001FFF
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief Number of available transmit buffers.
*/
#if !defined(LPC_MAC_TRANSMIT_BUFFERS) || defined(__DOXYGEN__)
#define LPC_MAC_TRANSMIT_BUFFERS 2
#endif
/**
* @brief Number of available receive buffers.
*/
#if !defined(LPC_MAC_RECEIVE_BUFFERS) || defined(__DOXYGEN__)
#define LPC_MAC_RECEIVE_BUFFERS 4
#endif
/**
* @brief Maximum supported frame size.
*/
#if !defined(LPC_MAC_BUFFERS_SIZE) || defined(__DOXYGEN__)
#define LPC_MAC_BUFFERS_SIZE 1522
#endif
/**
* @brief PHY detection timeout.
* @details Timeout, in milliseconds, for PHY address detection, if a PHY
* is not detected within the timeout then the driver halts during
* initialization. This setting applies only if the PHY address is
* not explicitly set in the board header file using
* @p BOARD_PHY_ADDRESS. A zero value disables the timeout and a
* single search path is performed.
*/
#if !defined(LPC_MAC_PHY_TIMEOUT) || defined(__DOXYGEN__)
#define LPC_MAC_PHY_TIMEOUT 100
#endif
/**
* @brief Change the PHY power state inside the driver.
*/
#if !defined(LPC_MAC_ETH1_CHANGE_PHY_STATE) || defined(__DOXYGEN__)
#define LPC_MAC_ETH1_CHANGE_PHY_STATE TRUE
#endif
/**
* @brief ETHD1 interrupt priority level setting.
*/
#if !defined(LPC_MAC_ETH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_MAC_ETH1_IRQ_PRIORITY 13
#endif
/**
* @brief IP checksum offload.
* @details The following modes are available:
* - 0 Function disabled.
* - 1 Only IP header checksum calculation and insertion are enabled.
* - 2 IP header checksum and payload checksum calculation and
* insertion are enabled, but pseudo-header checksum is not
* calculated in hardware.
* - 3 IP Header checksum and payload checksum calculation and
* insertion are enabled, and pseudo-header checksum is
* calculated in hardware.
* .
*/
#if !defined(LPC_MAC_IP_CHECKSUM_OFFLOAD) || defined(__DOXYGEN__)
#define LPC_MAC_IP_CHECKSUM_OFFLOAD 0
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if (LPC_MAC_PHY_TIMEOUT > 0) && !HAL_IMPLEMENTS_COUNTERS
#error "LPC_MAC_PHY_TIMEOUT requires the realtime counter service"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of an LPC Ethernet receive descriptor.
*/
typedef struct {
volatile uint32_t rdes0;
volatile uint32_t rdes1;
volatile uint32_t rdes2;
volatile uint32_t rdes3;
} lpc_eth_rx_descriptor_t;
/**
* @brief Type of an LPC Ethernet transmit descriptor.
*/
typedef struct {
volatile uint32_t tdes0;
volatile uint32_t tdes1;
volatile uint32_t tdes2;
volatile uint32_t tdes3;
} lpc_eth_tx_descriptor_t;
/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
* @brief MAC address.
*/
uint8_t *mac_address;
/* End of the mandatory fields.*/
} MACConfig;
/**
* @brief Structure representing a MAC driver.
*/
struct MACDriver {
/**
* @brief Driver state.
*/
macstate_t state;
/**
* @brief Current configuration data.
*/
const MACConfig *config;
/**
* @brief Transmit semaphore.
*/
Semaphore tdsem;
/**
* @brief Receive semaphore.
*/
Semaphore rdsem;
#if MAC_USE_EVENTS || defined(__DOXYGEN__)
/**
* @brief Receive event.
*/
EventSource rdevent;
#endif
/* End of the mandatory fields.*/
/**
* @brief Link status flag.
*/
bool_t link_up;
/**
* @brief PHY address (pre shifted).
*/
uint32_t phyaddr;
/**
* @brief Receive next frame pointer.
*/
lpc_eth_rx_descriptor_t *rxptr;
/**
* @brief Transmit next frame pointer.
*/
lpc_eth_tx_descriptor_t *txptr;
};
/**
* @brief Structure representing a transmit descriptor.
*/
typedef struct {
/**
* @brief Current write offset.
*/
size_t offset;
/**
* @brief Available space size.
*/
size_t size;
/* End of the mandatory fields.*/
/**
* @brief Pointer to the physical descriptor.
*/
lpc_eth_tx_descriptor_t *physdesc;
} MACTransmitDescriptor;
/**
* @brief Structure representing a receive descriptor.
*/
typedef struct {
/**
* @brief Current read offset.
*/
size_t offset;
/**
* @brief Available data size.
*/
size_t size;
/* End of the mandatory fields.*/
/**
* @brief Pointer to the physical descriptor.
*/
lpc_eth_rx_descriptor_t *physdesc;
} MACReceiveDescriptor;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
extern MACDriver ETHD1;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void mac_lld_init(void);
void mac_lld_start(MACDriver *macp);
void mac_lld_stop(MACDriver *macp);
msg_t mac_lld_get_transmit_descriptor(MACDriver *macp,
MACTransmitDescriptor *tdp);
void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp);
msg_t mac_lld_get_receive_descriptor(MACDriver *macp,
MACReceiveDescriptor *rdp);
void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp);
bool_t mac_lld_poll_link_status(MACDriver *macp);
size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
uint8_t *buf,
size_t size);
size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
uint8_t *buf,
size_t size);
#if MAC_USE_ZERO_COPY
uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp,
size_t size,
size_t *sizep);
const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp,
size_t *sizep);
#endif /* MAC_USE_ZERO_COPY */
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_MAC */
#endif /* _MAC_LLD_H_ */
/** @} */

View File

@ -0,0 +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 */
/** @} */

View File

@ -0,0 +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_ */
/** @} */

View File

@ -0,0 +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

View File

@ -0,0 +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 */
/** @} */

View File

@ -0,0 +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_ */
/** @} */

View File

@ -0,0 +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 */
/** @} */

View File

@ -0,0 +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_ */
/** @} */

View File

@ -0,0 +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 */

View File

@ -0,0 +1,62 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file GCC/ARMCMx/LPC43xx/cmparams.h
* @brief ARM Cortex-M4 LPC43xx Specific Parameters.
*
* @defgroup ARMCMx_LPC43xx LPC43xx Specific Parameters
* @ingroup ARMCMx_SPECIFIC
* @details This file contains the Cortex-M4 specific parameters for the
* LPC43xx platform.
* @{
*/
#ifndef _CMPARAMS_H_
#define _CMPARAMS_H_
/**
* @brief Cortex core model.
*/
#define CORTEX_MODEL CORTEX_M4
/**
* @brief Systick unit presence.
*/
#define CORTEX_HAS_ST TRUE
/**
* @brief Memory Protection unit presence.
*/
#define CORTEX_HAS_MPU TRUE
/**
* @brief Floating Point unit presence.
*/
#define CORTEX_HAS_FPU TRUE
/**
* @brief Number of bits in priority masks.
*/
#define CORTEX_PRIORITY_BITS 4
#endif /* _CMPARAMS_H_ */
/** @} */

View File

@ -0,0 +1,157 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* LPC4330 ROMless memory setup.
* Code runs from ram.
*/
__main_stack_size__ = 0x0800;
__process_stack_size__ = 0x0800;
MEMORY
{
ram : org = 0x10000000, len = 128k
ram2 : org = 0x10080000, len = 72k
ramahb : org = 0x20000000, len = 32k
ramahb2 : org = 0x20008000, len = 16k
ramahb3 : org = 0x2000C000, len = 16k
}
__ram_start__ = ORIGIN(ram2);
__ram_size__ = LENGTH(ram2);
__ram_end__ = __ram_start__ + __ram_size__;
ENTRY(ResetHandler)
SECTIONS
{
. = 0;
_text = .;
startup : ALIGN(16) SUBALIGN(16)
{
__vectors_start = .;
KEEP(*(vectors))
} > ram
constructors : ALIGN(4) SUBALIGN(4)
{
PROVIDE(__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE(__init_array_end = .);
} > ram
destructors : ALIGN(4) SUBALIGN(4)
{
PROVIDE(__fini_array_start = .);
KEEP(*(.fini_array))
KEEP(*(SORT(.fini_array.*)))
PROVIDE(__fini_array_end = .);
} > ram
.text : ALIGN(16) SUBALIGN(16)
{
*(.text.startup.*)
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.*)
*(.glue_7t)
*(.glue_7)
*(.gcc*)
} > ram
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > ram
.ARM.exidx : {
PROVIDE(__exidx_start = .);
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
PROVIDE(__exidx_end = .);
} > ram
.eh_frame_hdr :
{
*(.eh_frame_hdr)
} > ram
.eh_frame : ONLY_IF_RO
{
*(.eh_frame)
} > ram
.textalign : ONLY_IF_RO
{
. = ALIGN(8);
} > ram
_etext = .;
_textdata = _etext;
.stacks :
{
. = ALIGN(8);
__main_stack_base__ = .;
. += __main_stack_size__;
. = ALIGN(8);
__main_stack_end__ = .;
__process_stack_base__ = .;
__main_thread_stack_base__ = .;
. += __process_stack_size__;
. = ALIGN(8);
__process_stack_end__ = .;
__main_thread_stack_end__ = .;
} > ram2
.data :
{
. = ALIGN(4);
PROVIDE(_data = .);
*(.data)
. = ALIGN(4);
*(.data.*)
. = ALIGN(4);
*(.ramtext)
. = ALIGN(4);
PROVIDE(_edata = .);
} > ram2 AT > ram
.bss :
{
. = ALIGN(4);
PROVIDE(_bss_start = .);
*(.bss)
. = ALIGN(4);
*(.bss.*)
. = ALIGN(4);
*(COMMON)
. = ALIGN(4);
PROVIDE(_bss_end = .);
} > ram2
}
PROVIDE(end = .);
_end = .;
__heap_base__ = _end;
__heap_end__ = __ram_end__;

View File

@ -0,0 +1,15 @@
# List of the ChibiOS/RT Cortex-M4 LPC43xx port files.
PORTSRC = $(CHIBIOS)/os/ports/GCC/ARMCMx/crt0.c \
$(CHIBIOS)/os/ports/GCC/ARMCMx/LPC43xx/vectors.c \
${CHIBIOS}/os/ports/GCC/ARMCMx/chcore.c \
${CHIBIOS}/os/ports/GCC/ARMCMx/chcore_v7m.c \
${CHIBIOS}/os/ports/common/ARMCMx/nvic.c
PORTASM =
PORTINC = ${CHIBIOS}/os/ports/common/ARMCMx/CMSIS/include \
${CHIBIOS}/os/ports/common/ARMCMx \
${CHIBIOS}/os/ports/GCC/ARMCMx \
${CHIBIOS}/os/ports/GCC/ARMCMx/LPC43xx
PORTLD = ${CHIBIOS}/os/ports/GCC/ARMCMx/LPC43xx/ld

View File

@ -0,0 +1,246 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file GCC/ARMCMx/LPC43xx/vectors.c
* @brief Interrupt vectors for the LPC43xx family.
*
* @defgroup ARMCMx_LPC43xx_VECTORS LPC43xx Interrupt Vectors
* @ingroup ARMCMx_SPECIFIC
* @details Interrupt vectors for the LPC43xx family.
* @{
*/
#include "ch.h"
/**
* @brief Type of an IRQ vector.
*/
typedef void (*irq_vector_t)(void);
/**
* @brief Type of a structure representing the whole vectors table.
*/
typedef struct {
uint32_t *init_stack;
irq_vector_t reset_vector;
irq_vector_t nmi_vector;
irq_vector_t hardfault_vector;
irq_vector_t memmanage_vector;
irq_vector_t busfault_vector;
irq_vector_t usagefault_vector;
irq_vector_t vector1c;
irq_vector_t vector20;
irq_vector_t vector24;
irq_vector_t vector28;
irq_vector_t svcall_vector;
irq_vector_t debugmonitor_vector;
irq_vector_t vector34;
irq_vector_t pendsv_vector;
irq_vector_t systick_vector;
irq_vector_t vectors[49];
} vectors_t;
#if !defined(__DOXYGEN__)
extern uint32_t __main_stack_end__;
extern void ResetHandler(void);
extern void NMIVector(void);
extern void HardFaultVector(void);
extern void MemManageVector(void);
extern void BusFaultVector(void);
extern void UsageFaultVector(void);
extern void Vector1C(void);
extern void Vector20(void);
extern void Vector24(void);
extern void Vector28(void);
extern void SVCallVector(void);
extern void DebugMonitorVector(void);
extern void Vector34(void);
extern void PendSVVector(void);
extern void SysTickVector(void);
extern void Vector40(void);
extern void Vector44(void);
extern void Vector48(void);
extern void Vector4C(void);
extern void Vector50(void);
extern void Vector54(void);
extern void Vector58(void);
extern void Vector5C(void);
extern void Vector60(void);
extern void Vector64(void);
extern void Vector68(void);
extern void Vector6C(void);
extern void Vector70(void);
extern void Vector74(void);
extern void Vector78(void);
extern void Vector7C(void);
extern void Vector80(void);
extern void Vector84(void);
extern void Vector88(void);
extern void Vector8C(void);
extern void Vector90(void);
extern void Vector94(void);
extern void Vector98(void);
extern void Vector9C(void);
extern void VectorA0(void);
extern void VectorA4(void);
extern void VectorA8(void);
extern void VectorAC(void);
extern void VectorB0(void);
extern void VectorB4(void);
extern void VectorB8(void);
extern void VectorBC(void);
extern void VectorC0(void);
extern void VectorC4(void);
extern void VectorC8(void);
extern void VectorCC(void);
extern void VectorD0(void);
extern void VectorD4(void);
extern void VectorD8(void);
extern void VectorDC(void);
extern void VectorE0(void);
extern void VectorE4(void);
extern void VectorE8(void);
extern void VectorEC(void);
extern void VectorF0(void);
extern void VectorF4(void);
extern void VectorF8(void);
extern void VectorFC(void);
extern void Vector100(void);
extern void Vector104(void);
extern void Vector108(void);
extern void Vector10C(void);
extern void Vector110(void);
#endif
/**
* @brief LPC17xx vectors table.
*/
#if !defined(__DOXYGEN__)
__attribute__ ((section("vectors")))
#endif
vectors_t _vectors = {
&__main_stack_end__,ResetHandler, NMIVector, HardFaultVector,
MemManageVector, BusFaultVector, UsageFaultVector, Vector1C,
Vector20, Vector24, Vector28, SVCallVector,
DebugMonitorVector, Vector34, PendSVVector, SysTickVector,
{
Vector40, Vector44, Vector48, Vector4C,
Vector50, Vector54, Vector58, Vector5C,
Vector60, Vector64, Vector68, Vector6C,
Vector70, Vector74, Vector78, Vector7C,
Vector80, Vector84, Vector88, Vector8C,
Vector90, Vector94, Vector98, Vector9C,
VectorA0, VectorA4, VectorA8, VectorAC,
VectorB0, VectorB4, VectorB8, VectorBC,
VectorC0, VectorC4, VectorC8, VectorCC,
VectorE0, VectorE4, VectorE8, VectorEC,
VectorF0, VectorF4, VectorF8, VectorFC,
Vector100, Vector104, Vector108, Vector10C,
Vector110
}
};
/**
* @brief Unhandled exceptions handler.
* @details Any undefined exception vector points to this function by default.
* This function simply stops the system into an infinite loop.
*
* @notapi
*/
#if !defined(__DOXYGEN__)
__attribute__ ((naked))
#endif
void _unhandled_exception(void) {
while (TRUE)
;
}
void NMIVector(void) __attribute__((weak, alias("_unhandled_exception")));
void HardFaultVector(void) __attribute__((weak, alias("_unhandled_exception")));
void MemManageVector(void) __attribute__((weak, alias("_unhandled_exception")));
void BusFaultVector(void) __attribute__((weak, alias("_unhandled_exception")));
void UsageFaultVector(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector1C(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector20(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector24(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector28(void) __attribute__((weak, alias("_unhandled_exception")));
void SVCallVector(void) __attribute__((weak, alias("_unhandled_exception")));
void DebugMonitorVector(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector34(void) __attribute__((weak, alias("_unhandled_exception")));
void PendSVVector(void) __attribute__((weak, alias("_unhandled_exception")));
void SysTickVector(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector40(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector44(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector48(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector4C(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector50(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector54(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector58(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector5C(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector60(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector64(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector68(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector6C(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector70(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector74(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector78(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector7C(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector80(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector84(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector88(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector8C(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector90(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector94(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector98(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector9C(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorA0(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorA4(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorA8(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorAC(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorB0(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorB4(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorB8(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorBC(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorC0(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorC4(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorC8(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorCC(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorD0(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorD4(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorD8(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorDC(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorE0(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorE4(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorE8(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorEC(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorF0(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorF4(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorF8(void) __attribute__((weak, alias("_unhandled_exception")));
void VectorFC(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector100(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector104(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector108(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector10C(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector110(void) __attribute__((weak, alias("_unhandled_exception")));
/** @} */